CnC_Remastered_Collection/CnCTDRAMapEditor/Tools/TemplateTool.cs
PG-SteveT e37e174be1 C&C Remastered Map Editor
Initial commit of C&C Remastered Map Editor code
2020-09-10 11:12:58 -07:00

1009 lines
37 KiB
C#

//
// Copyright 2020 Electronic Arts Inc.
//
// The Command & Conquer Map Editor and corresponding source code is free
// software: you can redistribute it and/or modify it under the terms of
// the GNU General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
// The Command & Conquer Map Editor and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
using MobiusEditor.Controls;
using MobiusEditor.Event;
using MobiusEditor.Interface;
using MobiusEditor.Model;
using MobiusEditor.Utility;
using MobiusEditor.Widgets;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace MobiusEditor.Tools
{
public class TemplateTool : ViewTool
{
private static readonly Regex CategoryRegex = new Regex(@"^([a-z]*)", RegexOptions.Compiled);
private readonly ListView templateTypeListView;
private readonly MapPanel templateTypeMapPanel;
private readonly ToolTip mouseTooltip;
private readonly Dictionary<int, Template> undoTemplates = new Dictionary<int, Template>();
private readonly Dictionary<int, Template> redoTemplates = new Dictionary<int, Template>();
private Map previewMap;
protected override Map RenderMap => previewMap;
private bool placementMode;
private bool boundsMode;
private Rectangle dragBounds;
private int dragEdge = -1;
private TemplateType selectedTemplateType;
private TemplateType SelectedTemplateType
{
get => selectedTemplateType;
set
{
if (selectedTemplateType != value)
{
if (placementMode && (selectedTemplateType != null))
{
for (var y = 0; y < selectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < selectedTemplateType.IconWidth; ++x)
{
mapPanel.Invalidate(map, new Point(navigationWidget.MouseCell.X + x, navigationWidget.MouseCell.Y + y));
}
}
}
selectedTemplateType = value;
templateTypeListView.BeginUpdate();
templateTypeListView.SelectedIndexChanged -= TemplateTypeListView_SelectedIndexChanged;
foreach (ListViewItem item in templateTypeListView.Items)
{
item.Selected = item.Tag == selectedTemplateType;
}
if (templateTypeListView.SelectedIndices.Count > 0)
{
templateTypeListView.EnsureVisible(templateTypeListView.SelectedIndices[0]);
}
templateTypeListView.SelectedIndexChanged += TemplateTypeListView_SelectedIndexChanged;
templateTypeListView.EndUpdate();
if (placementMode && (selectedTemplateType != null))
{
for (var y = 0; y < selectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < selectedTemplateType.IconWidth; ++x)
{
mapPanel.Invalidate(map, new Point(navigationWidget.MouseCell.X + x, navigationWidget.MouseCell.Y + y));
}
}
}
RefreshMapPanel();
}
}
}
private Point? selectedIcon;
private Point? SelectedIcon
{
get => selectedIcon;
set
{
if (selectedIcon != value)
{
selectedIcon = value;
templateTypeMapPanel.Invalidate();
if (placementMode && (SelectedTemplateType != null))
{
for (var y = 0; y < SelectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < SelectedTemplateType.IconWidth; ++x)
{
mapPanel.Invalidate(map, new Point(navigationWidget.MouseCell.X + x, navigationWidget.MouseCell.Y + y));
}
}
}
}
}
}
private NavigationWidget templateTypeNavigationWidget;
public TemplateTool(MapPanel mapPanel, MapLayerFlag layers, ToolStripStatusLabel statusLbl, ListView templateTypeListView, MapPanel templateTypeMapPanel, ToolTip mouseTooltip, IGamePlugin plugin, UndoRedoList<UndoRedoEventArgs> url)
: base(mapPanel, layers, statusLbl, plugin, url)
{
previewMap = map;
this.mapPanel.MouseDown += MapPanel_MouseDown;
this.mapPanel.MouseUp += MapPanel_MouseUp;
this.mapPanel.MouseMove += MapPanel_MouseMove;
(this.mapPanel as Control).KeyDown += TemplateTool_KeyDown;
(this.mapPanel as Control).KeyUp += TemplateTool_KeyUp;
this.templateTypeListView = templateTypeListView;
this.templateTypeListView.SelectedIndexChanged += TemplateTypeListView_SelectedIndexChanged;
string templateCategory(TemplateType template)
{
var m = CategoryRegex.Match(template.Name);
return m.Success ? m.Groups[1].Value : string.Empty;
}
var templateTypes = plugin.Map.TemplateTypes
.Where(t =>
(t.Thumbnail != null) &&
t.Theaters.Contains(plugin.Map.Theater) &&
((t.Flag & TemplateTypeFlag.Clear) == TemplateTypeFlag.None))
.GroupBy(t => templateCategory(t)).OrderBy(g => g.Key);
var templateTypeImages = templateTypes.SelectMany(g => g).Select(t => t.Thumbnail);
var maxWidth = templateTypeImages.Max(t => t.Width);
var maxHeight = templateTypeImages.Max(t => t.Height);
var imageList = new ImageList();
imageList.Images.AddRange(templateTypeImages.ToArray());
imageList.ImageSize = new Size(maxWidth, maxHeight);
imageList.ColorDepth = ColorDepth.Depth24Bit;
this.templateTypeListView.BeginUpdate();
this.templateTypeListView.LargeImageList = imageList;
var imageIndex = 0;
foreach (var templateTypeGroup in templateTypes)
{
var group = new ListViewGroup(templateTypeGroup.Key);
this.templateTypeListView.Groups.Add(group);
foreach (var templateType in templateTypeGroup)
{
var item = new ListViewItem(templateType.DisplayName, imageIndex++)
{
Group = group,
Tag = templateType
};
this.templateTypeListView.Items.Add(item);
}
}
this.templateTypeListView.EndUpdate();
this.templateTypeMapPanel = templateTypeMapPanel;
this.templateTypeMapPanel.MouseDown += TemplateTypeMapPanel_MouseDown;
this.templateTypeMapPanel.PostRender += TemplateTypeMapPanel_PostRender;
this.templateTypeMapPanel.BackColor = Color.Black;
this.templateTypeMapPanel.MaxZoom = 1;
this.mouseTooltip = mouseTooltip;
navigationWidget.MouseCellChanged += MouseoverWidget_MouseCellChanged;
url.Undone += Url_Undone;
url.Redone += Url_Redone;
SelectedTemplateType = templateTypes.First().First();
UpdateStatus();
}
private void Url_Redone(object sender, EventArgs e)
{
if (boundsMode && (map.Bounds != dragBounds))
{
dragBounds = map.Bounds;
dragEdge = -1;
UpdateTooltip();
mapPanel.Invalidate();
}
}
private void Url_Undone(object sender, EventArgs e)
{
if (boundsMode && (map.Bounds != dragBounds))
{
dragBounds = map.Bounds;
dragEdge = -1;
UpdateTooltip();
mapPanel.Invalidate();
}
}
private void TemplateTypeMapPanel_MouseDown(object sender, MouseEventArgs e)
{
if ((SelectedTemplateType == null) || ((SelectedTemplateType.IconWidth * SelectedTemplateType.IconHeight) == 1))
{
SelectedIcon = null;
}
else
{
if (e.Button == MouseButtons.Left)
{
var templateTypeMouseCell = templateTypeNavigationWidget.MouseCell;
if ((templateTypeMouseCell.X >= 0) && (templateTypeMouseCell.X < SelectedTemplateType.IconWidth))
{
if ((templateTypeMouseCell.Y >= 0) && (templateTypeMouseCell.Y < SelectedTemplateType.IconHeight))
{
if (SelectedTemplateType.IconMask[templateTypeMouseCell.X, templateTypeMouseCell.Y])
{
SelectedIcon = templateTypeMouseCell;
}
}
}
}
else if (e.Button == MouseButtons.Right)
{
SelectedIcon = null;
}
}
}
private void TemplateTypeMapPanel_PostRender(object sender, RenderEventArgs e)
{
if (SelectedIcon.HasValue)
{
var selectedIconPen = new Pen(Color.Yellow, 2);
var cellSize = new Size(Globals.OriginalTileWidth / 4, Globals.OriginalTileHeight / 4);
var rect = new Rectangle(new Point(SelectedIcon.Value.X * cellSize.Width, SelectedIcon.Value.Y * cellSize.Height), cellSize);
e.Graphics.DrawRectangle(selectedIconPen, rect);
}
if (SelectedTemplateType != null)
{
var sizeStringFormat = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
var sizeBackgroundBrush = new SolidBrush(Color.FromArgb(128, Color.Black));
var sizeTextBrush = new SolidBrush(Color.White);
var text = string.Format("{0} ({1}x{2})", SelectedTemplateType.DisplayName, SelectedTemplateType.IconWidth, SelectedTemplateType.IconHeight);
var textSize = e.Graphics.MeasureString(text, SystemFonts.CaptionFont) + new SizeF(6.0f, 6.0f);
var textBounds = new RectangleF(new PointF(0, 0), textSize);
e.Graphics.Transform = new Matrix();
e.Graphics.FillRectangle(sizeBackgroundBrush, textBounds);
e.Graphics.DrawString(text, SystemFonts.CaptionFont, sizeTextBrush, textBounds, sizeStringFormat);
}
}
private void TemplateTool_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.ShiftKey)
{
EnterPlacementMode();
}
else if (e.KeyCode == Keys.ControlKey)
{
EnterBoundsMode();
}
}
private void TemplateTool_KeyUp(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.ShiftKey) || (e.KeyCode == Keys.ControlKey))
{
ExitAllModes();
}
}
private void TemplateTypeListView_SelectedIndexChanged(object sender, EventArgs e)
{
SelectedTemplateType = (templateTypeListView.SelectedItems.Count > 0) ? (templateTypeListView.SelectedItems[0].Tag as TemplateType) : null;
SelectedIcon = null;
}
private void MapPanel_MouseDown(object sender, MouseEventArgs e)
{
if (boundsMode)
{
dragEdge = DetectDragEdge();
UpdateStatus();
}
else if (placementMode)
{
if (e.Button == MouseButtons.Left)
{
SetTemplate(navigationWidget.MouseCell);
}
else if (e.Button == MouseButtons.Right)
{
RemoveTemplate(navigationWidget.MouseCell);
}
}
else if ((e.Button == MouseButtons.Left) || (e.Button == MouseButtons.Right))
{
PickTemplate(navigationWidget.MouseCell, e.Button == MouseButtons.Left);
}
}
private void MapPanel_MouseUp(object sender, MouseEventArgs e)
{
if (boundsMode)
{
if (dragBounds != map.Bounds)
{
var oldBounds = map.Bounds;
void undoAction(UndoRedoEventArgs ure)
{
ure.Map.Bounds = oldBounds;
ure.MapPanel.Invalidate();
}
void redoAction(UndoRedoEventArgs ure)
{
ure.Map.Bounds = dragBounds;
ure.MapPanel.Invalidate();
}
map.Bounds = dragBounds;
url.Track(undoAction, redoAction);
mapPanel.Invalidate();
}
dragEdge = -1;
UpdateStatus();
}
else
{
if ((undoTemplates.Count > 0) || (redoTemplates.Count > 0))
{
CommitChange();
}
}
}
private void MapPanel_MouseMove(object sender, MouseEventArgs e)
{
if (!placementMode && (Control.ModifierKeys == Keys.Shift))
{
EnterPlacementMode();
}
else if (!boundsMode && (Control.ModifierKeys == Keys.Control))
{
EnterBoundsMode();
}
else if ((placementMode || boundsMode) && (Control.ModifierKeys == Keys.None))
{
ExitAllModes();
}
var cursor = Cursors.Default;
if (boundsMode)
{
switch ((dragEdge >= 0) ? dragEdge : DetectDragEdge())
{
case 0:
case 4:
cursor = Cursors.SizeNS;
break;
case 2:
case 6:
cursor = Cursors.SizeWE;
break;
case 1:
case 5:
cursor = Cursors.SizeNESW;
break;
case 3:
case 7:
cursor = Cursors.SizeNWSE;
break;
}
}
Cursor.Current = cursor;
UpdateTooltip();
}
private void MouseoverWidget_MouseCellChanged(object sender, MouseCellChangedEventArgs e)
{
if (dragEdge >= 0)
{
var endDrag = navigationWidget.MouseCell;
map.Metrics.Clip(ref endDrag, new Size(1, 1), Size.Empty);
switch (dragEdge)
{
case 0:
case 1:
case 7:
if (endDrag.Y < dragBounds.Bottom)
{
dragBounds.Height = dragBounds.Bottom - endDrag.Y;
dragBounds.Y = endDrag.Y;
}
break;
}
switch (dragEdge)
{
case 5:
case 6:
case 7:
if (endDrag.X < dragBounds.Right)
{
dragBounds.Width = dragBounds.Right - endDrag.X;
dragBounds.X = endDrag.X;
}
break;
}
switch (dragEdge)
{
case 3:
case 4:
case 5:
if (endDrag.Y > dragBounds.Top)
{
dragBounds.Height = endDrag.Y - dragBounds.Top;
}
break;
}
switch (dragEdge)
{
case 1:
case 2:
case 3:
if (endDrag.X > dragBounds.Left)
{
dragBounds.Width = endDrag.X - dragBounds.Left;
}
break;
}
mapPanel.Invalidate();
}
else if (placementMode)
{
if (Control.MouseButtons == MouseButtons.Right)
{
RemoveTemplate(navigationWidget.MouseCell);
}
if (SelectedTemplateType != null)
{
foreach (var location in new Point[] { e.OldCell, e.NewCell })
{
for (var y = 0; y < SelectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < SelectedTemplateType.IconWidth; ++x)
{
mapPanel.Invalidate(map, new Point(location.X + x, location.Y + y));
}
}
}
}
}
else if((Control.MouseButtons == MouseButtons.Left) || (Control.MouseButtons == MouseButtons.Right))
{
PickTemplate(navigationWidget.MouseCell, Control.MouseButtons == MouseButtons.Left);
}
}
private void RefreshMapPanel()
{
if (templateTypeNavigationWidget != null)
{
templateTypeNavigationWidget.Dispose();
templateTypeNavigationWidget = null;
}
if (SelectedTemplateType != null)
{
templateTypeMapPanel.MapImage = SelectedTemplateType.Thumbnail;
var templateTypeMetrics = new CellMetrics(SelectedTemplateType.IconWidth, SelectedTemplateType.IconHeight);
templateTypeNavigationWidget = new NavigationWidget(templateTypeMapPanel, templateTypeMetrics,
new Size(Globals.OriginalTileWidth / 4, Globals.OriginalTileHeight / 4));
templateTypeNavigationWidget.MouseoverSize = Size.Empty;
}
else
{
templateTypeMapPanel.MapImage = null;
}
}
private void SetTemplate(Point location)
{
if (SelectedTemplateType != null)
{
if (SelectedIcon.HasValue)
{
if (map.Metrics.GetCell(location, out int cell))
{
if (!undoTemplates.ContainsKey(cell))
{
undoTemplates[cell] = map.Templates[location];
}
var icon = (SelectedIcon.Value.Y * SelectedTemplateType.IconWidth) + SelectedIcon.Value.X;
var template = new Template { Type = SelectedTemplateType, Icon = icon };
map.Templates[cell] = template;
redoTemplates[cell] = template;
mapPanel.Invalidate(map, cell);
plugin.Dirty = true;
}
}
else
{
for (int y = 0, icon = 0; y < SelectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < SelectedTemplateType.IconWidth; ++x, ++icon)
{
var subLocation = new Point(location.X + x, location.Y + y);
if (map.Metrics.GetCell(subLocation, out int cell))
{
if (!undoTemplates.ContainsKey(cell))
{
undoTemplates[cell] = map.Templates[subLocation];
}
}
}
}
for (int y = 0, icon = 0; y < SelectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < SelectedTemplateType.IconWidth; ++x, ++icon)
{
if (!SelectedTemplateType.IconMask[x, y])
{
continue;
}
var subLocation = new Point(location.X + x, location.Y + y);
if (map.Metrics.GetCell(subLocation, out int cell))
{
var template = new Template { Type = SelectedTemplateType, Icon = icon };
map.Templates[cell] = template;
redoTemplates[cell] = template;
mapPanel.Invalidate(map, cell);
plugin.Dirty = true;
}
}
}
}
}
}
private void RemoveTemplate(Point location)
{
if (SelectedTemplateType != null)
{
if (SelectedIcon.HasValue)
{
if (map.Metrics.GetCell(location, out int cell))
{
if (!undoTemplates.ContainsKey(cell))
{
undoTemplates[cell] = map.Templates[location];
}
map.Templates[cell] = null;
redoTemplates[cell] = null;
mapPanel.Invalidate(map, cell);
plugin.Dirty = true;
}
}
else
{
for (int y = 0, icon = 0; y < SelectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < SelectedTemplateType.IconWidth; ++x, ++icon)
{
var subLocation = new Point(location.X + x, location.Y + y);
if (map.Metrics.GetCell(subLocation, out int cell))
{
if (!undoTemplates.ContainsKey(cell))
{
undoTemplates[cell] = map.Templates[subLocation];
}
}
}
}
for (int y = 0, icon = 0; y < SelectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < SelectedTemplateType.IconWidth; ++x, ++icon)
{
var subLocation = new Point(location.X + x, location.Y + y);
if (map.Metrics.GetCell(subLocation, out int cell))
{
map.Templates[cell] = null;
redoTemplates[cell] = null;
mapPanel.Invalidate(map, cell);
plugin.Dirty = true;
}
}
}
}
}
}
private void EnterPlacementMode()
{
if (placementMode || boundsMode)
{
return;
}
placementMode = true;
navigationWidget.MouseoverSize = Size.Empty;
if (SelectedTemplateType != null)
{
for (var y = 0; y < SelectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < SelectedTemplateType.IconWidth; ++x)
{
mapPanel.Invalidate(map, new Point(navigationWidget.MouseCell.X + x, navigationWidget.MouseCell.Y + y));
}
}
}
UpdateStatus();
}
private void EnterBoundsMode()
{
if (boundsMode || placementMode)
{
return;
}
boundsMode = true;
dragBounds = map.Bounds;
navigationWidget.MouseoverSize = Size.Empty;
if (SelectedTemplateType != null)
{
for (var y = 0; y < SelectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < SelectedTemplateType.IconWidth; ++x)
{
mapPanel.Invalidate(map, new Point(navigationWidget.MouseCell.X + x, navigationWidget.MouseCell.Y + y));
}
}
}
UpdateTooltip();
UpdateStatus();
}
private void ExitAllModes()
{
if (!placementMode && !boundsMode)
{
return;
}
boundsMode = false;
dragEdge = -1;
dragBounds = Rectangle.Empty;
placementMode = false;
navigationWidget.MouseoverSize = new Size(1, 1);
if (SelectedTemplateType != null)
{
for (var y = 0; y < SelectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < SelectedTemplateType.IconWidth; ++x)
{
mapPanel.Invalidate(map, new Point(navigationWidget.MouseCell.X + x, navigationWidget.MouseCell.Y + y));
}
}
}
UpdateTooltip();
UpdateStatus();
}
private void UpdateTooltip()
{
if (boundsMode)
{
var tooltip = string.Format("X = {0}\nY = {1}\nWidth = {2}\nHeight = {3}", dragBounds.Left, dragBounds.Top, dragBounds.Width, dragBounds.Height);
var textSize = TextRenderer.MeasureText(tooltip, SystemFonts.CaptionFont);
var tooltipSize = new Size(textSize.Width + 6, textSize.Height + 6);
var tooltipPosition = mapPanel.PointToClient(Control.MousePosition);
switch (dragEdge)
{
case -1:
case 0:
case 1:
case 7:
tooltipPosition.Y -= tooltipSize.Height;
break;
}
switch (dragEdge)
{
case -1:
case 5:
case 6:
case 7:
tooltipPosition.X -= tooltipSize.Width;
break;
}
var screenPosition = mapPanel.PointToScreen(tooltipPosition);
var screen = Screen.FromControl(mapPanel);
screenPosition.X = Math.Max(0, Math.Min(screen.WorkingArea.Width - tooltipSize.Width, screenPosition.X));
screenPosition.Y = Math.Max(0, Math.Min(screen.WorkingArea.Height - tooltipSize.Height, screenPosition.Y));
tooltipPosition = mapPanel.PointToClient(screenPosition);
mouseTooltip.Show(tooltip, mapPanel, tooltipPosition.X, tooltipPosition.Y);
}
else
{
mouseTooltip.Hide(mapPanel);
}
}
private void PickTemplate(Point location, bool wholeTemplate)
{
if (map.Metrics.GetCell(location, out int cell))
{
var template = map.Templates[cell];
if (template != null)
{
SelectedTemplateType = template.Type;
}
else
{
SelectedTemplateType = map.TemplateTypes.Where(t => t.Equals("clear1")).FirstOrDefault();
}
if (!wholeTemplate && ((SelectedTemplateType.IconWidth * SelectedTemplateType.IconHeight) > 1))
{
var icon = template?.Icon ?? 0;
SelectedIcon = new Point(icon % SelectedTemplateType.IconWidth, icon / SelectedTemplateType.IconWidth);
}
else
{
SelectedIcon = null;
}
}
}
private int DetectDragEdge()
{
var mouseCell = navigationWidget.MouseCell;
var mousePixel = navigationWidget.MouseSubPixel;
var topEdge =
((mouseCell.Y == dragBounds.Top) && (mousePixel.Y <= (Globals.PixelHeight / 4))) ||
((mouseCell.Y == dragBounds.Top - 1) && (mousePixel.Y >= (3 * Globals.PixelHeight / 4)));
var bottomEdge =
((mouseCell.Y == dragBounds.Bottom) && (mousePixel.Y <= (Globals.PixelHeight / 4))) ||
((mouseCell.Y == dragBounds.Bottom - 1) && (mousePixel.Y >= (3 * Globals.PixelHeight / 4)));
var leftEdge =
((mouseCell.X == dragBounds.Left) && (mousePixel.X <= (Globals.PixelWidth / 4))) ||
((mouseCell.X == dragBounds.Left - 1) && (mousePixel.X >= (3 * Globals.PixelWidth / 4)));
var rightEdge =
((mouseCell.X == dragBounds.Right) && (mousePixel.X <= (Globals.PixelHeight / 4))) ||
((mouseCell.X == dragBounds.Right - 1) && (mousePixel.X >= (3 * Globals.PixelHeight / 4)));
if (topEdge)
{
if (rightEdge)
{
return 1;
}
else if (leftEdge)
{
return 7;
}
else
{
return 0;
}
}
else if (bottomEdge)
{
if (rightEdge)
{
return 3;
}
else if (leftEdge)
{
return 5;
}
else
{
return 4;
}
}
else if (rightEdge)
{
return 2;
}
else if (leftEdge)
{
return 6;
}
else
{
return -1;
}
}
private void CommitChange()
{
var undoTemplates2 = new Dictionary<int, Template>(undoTemplates);
void undoAction(UndoRedoEventArgs e)
{
foreach (var kv in undoTemplates2)
{
e.Map.Templates[kv.Key] = kv.Value;
}
e.MapPanel.Invalidate(e.Map, undoTemplates2.Keys);
}
var redoTemplates2 = new Dictionary<int, Template>(redoTemplates);
void redoAction(UndoRedoEventArgs e)
{
foreach (var kv in redoTemplates2)
{
e.Map.Templates[kv.Key] = kv.Value;
}
e.MapPanel.Invalidate(e.Map, redoTemplates2.Keys);
}
undoTemplates.Clear();
redoTemplates.Clear();
url.Track(undoAction, redoAction);
}
private void UpdateStatus()
{
if (placementMode)
{
statusLbl.Text = "Left-Click to place template, Right-Click to clear template";
}
else if (boundsMode)
{
if (dragEdge >= 0)
{
statusLbl.Text = "Release left button to end dragging map bounds edge";
}
else
{
statusLbl.Text = "Left-Click a map bounds edge to start dragging";
}
}
else
{
statusLbl.Text = "Shift to enter placement mode, Ctrl to enter map bounds mode, Left-Click to pick whole template, Right-Click to pick individual template tile";
}
}
protected override void PreRenderMap()
{
base.PreRenderMap();
previewMap = map.Clone();
if (placementMode)
{
var location = navigationWidget.MouseCell;
if (SelectedTemplateType != null)
{
if (SelectedIcon.HasValue)
{
if (previewMap.Metrics.GetCell(location, out int cell))
{
var icon = (SelectedIcon.Value.Y * SelectedTemplateType.IconWidth) + SelectedIcon.Value.X;
previewMap.Templates[cell] = new Template { Type = SelectedTemplateType, Icon = icon };
}
}
else
{
int icon = 0;
for (var y = 0; y < SelectedTemplateType.IconHeight; ++y)
{
for (var x = 0; x < SelectedTemplateType.IconWidth; ++x, ++icon)
{
if (!SelectedTemplateType.IconMask[x, y])
{
continue;
}
var subLocation = new Point(location.X + x, location.Y + y);
if (previewMap.Metrics.GetCell(subLocation, out int cell))
{
previewMap.Templates[cell] = new Template { Type = SelectedTemplateType, Icon = icon };
}
}
}
}
}
}
}
protected override void PostRenderMap(Graphics graphics)
{
base.PostRenderMap(graphics);
if (boundsMode)
{
var bounds = Rectangle.FromLTRB(
dragBounds.Left * Globals.TileWidth,
dragBounds.Top * Globals.TileHeight,
dragBounds.Right * Globals.TileWidth,
dragBounds.Bottom * Globals.TileHeight
);
var boundsPen = new Pen(Color.Red, 8.0f);
graphics.DrawRectangle(boundsPen, bounds);
}
else if (placementMode)
{
var location = navigationWidget.MouseCell;
if (SelectedTemplateType != null)
{
var previewPen = new Pen(Color.Green, 4.0f);
var previewBounds = new Rectangle(
location.X * Globals.TileWidth,
location.Y * Globals.TileHeight,
(SelectedIcon.HasValue ? 1 : SelectedTemplateType.IconWidth) * Globals.TileWidth,
(SelectedIcon.HasValue ? 1 : SelectedTemplateType.IconHeight) * Globals.TileHeight
);
graphics.DrawRectangle(previewPen, previewBounds);
}
}
}
#region IDisposable Support
private bool disposedValue = false;
protected override void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
mapPanel.MouseDown -= MapPanel_MouseDown;
mapPanel.MouseUp -= MapPanel_MouseUp;
mapPanel.MouseMove -= MapPanel_MouseMove;
(mapPanel as Control).KeyDown -= TemplateTool_KeyDown;
(mapPanel as Control).KeyUp -= TemplateTool_KeyUp;
templateTypeListView.SelectedIndexChanged -= TemplateTypeListView_SelectedIndexChanged;
templateTypeMapPanel.MouseDown -= TemplateTypeMapPanel_MouseDown;
templateTypeMapPanel.PostRender -= TemplateTypeMapPanel_PostRender;
navigationWidget.MouseCellChanged -= MouseoverWidget_MouseCellChanged;
url.Undone -= Url_Undone;
url.Redone -= Url_Redone;
}
disposedValue = true;
}
base.Dispose(disposing);
}
#endregion
}
}