more multithreading, trying to get arrow key nav working

This commit is contained in:
Nyeguds 2022-10-02 12:40:55 +02:00
parent ab1a00a4ad
commit 21217de0ad
19 changed files with 675 additions and 657 deletions

View File

@ -229,12 +229,6 @@
<Compile Include="Controls\PlayerSettings.Designer.cs">
<DependentUpon>PlayerSettings.cs</DependentUpon>
</Compile>
<Compile Include="Controls\TypeComboBox.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Controls\TypeComboBox.Designer.cs">
<DependentUpon>TypeComboBox.cs</DependentUpon>
</Compile>
<Compile Include="Controls\TypeListBox.cs">
<SubType>Component</SubType>
</Compile>

View File

@ -108,19 +108,35 @@ namespace MobiusEditor.Controls
get => zoom;
set
{
var newZoom = Math.Max(MinZoom, Math.Min(MaxZoom, value));
if (zoom != newZoom)
{
zoom = newZoom;
var clientPosition = PointToClient(MousePosition);
referencePositions = (ClientToMap(clientPosition), new SizeF(clientPosition.X / (float)ClientSize.Width, clientPosition.Y / (float)ClientSize.Height));
UpdateCamera();
}
AdjustZoom(value, true);
}
}
private void AdjustZoom(double value, bool fromMousePos)
{
var newZoom = Math.Max(MinZoom, Math.Min(MaxZoom, value));
if (zoom != newZoom)
{
zoom = newZoom;
var clientPosition = fromMousePos ? PointToClient(MousePosition) : new Point(ClientRectangle.Width / 2, ClientRectangle.Height / 2);
referencePositions = (ClientToMap(clientPosition), new SizeF(clientPosition.X / (float)ClientSize.Width, clientPosition.Y / (float)ClientSize.Height));
UpdateCamera();
}
}
public void IncreaseZoomStep()
{
AdjustZoom(zoom + (zoom * zoomStep), false);
}
public void DecreaseZoomStep()
{
AdjustZoom(zoom - (zoom * zoomStep), false);
}
private bool smoothScale = Globals.MapSmoothScale;
public bool SmoothScale
{
@ -351,7 +367,7 @@ namespace MobiusEditor.Controls
var invalidPen = new Pen(Color.DarkRed);
foreach (var cell in invalidateCells)
{
pe.Graphics.DrawRectangle(invalidPen, new Rectangle(cell.X * Globals.TileWidth, cell.Y * Globals.TileHeight, Globals.TileWidth, Globals.TileHeight));
pe.Graphics.DrawRectangle(invalidPen, new Rectangle(cell.X * Globals.MapTileWidth, cell.Y * Globals.MapTileHeight, Globals.MapTileWidth, Globals.MapTileHeight));
}
}
#endif

View File

@ -1,37 +0,0 @@
//
// 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
namespace MobiusEditor.Controls
{
partial class TypeComboBox
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@ -1,137 +0,0 @@
//
// 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.Interface;
using MobiusEditor.Model;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace MobiusEditor.Controls
{
public partial class TypeComboBox : ComboBox
{
[Category("Behavior")]
public Image MissingThumbnail { get; set; } = SystemIcons.Error.ToBitmap();
public IEnumerable<IBrowsableType> Types
{
get => Items.Cast<TypeItem<IBrowsableType>>().Select(t => t.Type);
set
{
DataSource = value.Select(t => new TypeItem<IBrowsableType>(t.DisplayName, t)).ToArray();
DropDownHeight = Math.Max(DropDownHeight, value.Max(t => (t.Thumbnail?.Height ?? MissingThumbnail.Height) * 3));
Invalidate();
}
}
public IBrowsableType SelectedType => SelectedValue as IBrowsableType;
public TypeComboBox()
{
InitializeComponent();
DisplayMember = "Name";
ValueMember = "Type";
}
protected override void OnMeasureItem(MeasureItemEventArgs e)
{
base.OnMeasureItem(e);
var typeItem = this.Items[e.Index] as TypeItem<IBrowsableType>;
if (typeItem?.Type != null)
{
e.ItemHeight = (int)((typeItem.Type.Thumbnail?.Height ?? MissingThumbnail.Height) *
Properties.Settings.Default.ObjectToolItemSizeMultiplier);
}
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
base.OnDrawItem(e);
e.DrawBackground();
e.DrawFocusRectangle();
if ((e.Index >= 0) && (e.Index < Items.Count))
{
var typeItem = Items[e.Index] as TypeItem<IBrowsableType>;
if (typeItem?.Type != null)
{
StringFormat stringFormat = new StringFormat
{
LineAlignment = StringAlignment.Center
};
var textColor = ((e.State & DrawItemState.Selected) == DrawItemState.Selected) ? SystemBrushes.HighlightText : SystemBrushes.WindowText;
var textSize = e.Graphics.MeasureString(typeItem.Name, Font, e.Bounds.Width, stringFormat);
e.Graphics.DrawString(typeItem.Name, Font, textColor, e.Bounds, stringFormat);
if ((e.State & DrawItemState.ComboBoxEdit) == DrawItemState.None)
{
var thumbnail = typeItem.Type.Thumbnail ?? MissingThumbnail;
var thumbnailWidth = (int)Math.Min((e.Bounds.Width - textSize.Width),
thumbnail.Width);
int thumbnailHeight = (int)Math.Min(e.Bounds.Height, Math.Max(textSize.Height, thumbnail.Height));
double widthRatio = (e.Bounds.Width - textSize.Width) / (double)thumbnail.Width;
double heightRatio = e.Bounds.Height / (double)thumbnail.Height;
if (heightRatio < widthRatio)
{
thumbnailWidth = (int)(thumbnail.Width * heightRatio);
}
else
{
thumbnailHeight = (int)(thumbnail.Height * widthRatio);
}
var thumbnailSize = new Size(thumbnailWidth, thumbnailHeight);
var thumbnailBounds = new Rectangle(new Point(e.Bounds.Right - thumbnailSize.Width, e.Bounds.Top), thumbnailSize);
e.Graphics.DrawImage(thumbnail, thumbnailBounds);
}
}
}
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
if (MissingThumbnail != null)
{
try
{
MissingThumbnail.Dispose();
}
catch
{
// Ignore.
}
MissingThumbnail = null;
}
}
base.Dispose(disposing);
}
}
}

View File

@ -38,10 +38,10 @@
this.txtPath = new System.Windows.Forms.TextBox();
this.btnPickFile = new System.Windows.Forms.Button();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.btnExport = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.btnExport = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
@ -70,7 +70,7 @@
this.txtScale.Location = new System.Drawing.Point(67, 9);
this.txtScale.Name = "txtScale";
this.txtScale.Size = new System.Drawing.Size(100, 20);
this.txtScale.TabIndex = 1;
this.txtScale.TabIndex = 2;
this.txtScale.Text = "0.5";
this.txtScale.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
this.txtScale.TextChanged += new System.EventHandler(this.txtScale_TextChanged);
@ -101,7 +101,7 @@
this.chkSmooth.Location = new System.Drawing.Point(67, 35);
this.chkSmooth.Name = "chkSmooth";
this.chkSmooth.Size = new System.Drawing.Size(98, 17);
this.chkSmooth.TabIndex = 4;
this.chkSmooth.TabIndex = 2;
this.chkSmooth.Text = "Smooth scaling";
this.chkSmooth.UseVisualStyleBackColor = true;
//
@ -123,7 +123,7 @@
this.txtPath.Name = "txtPath";
this.txtPath.ReadOnly = true;
this.txtPath.Size = new System.Drawing.Size(304, 20);
this.txtPath.TabIndex = 3;
this.txtPath.TabIndex = 4;
//
// btnPickFile
//
@ -155,28 +155,7 @@
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(346, 190);
this.tableLayoutPanel1.TabIndex = 6;
//
// btnExport
//
this.btnExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnExport.Location = new System.Drawing.Point(184, 301);
this.btnExport.Name = "btnExport";
this.btnExport.Size = new System.Drawing.Size(84, 23);
this.btnExport.TabIndex = 5;
this.btnExport.Text = "Export";
this.btnExport.UseVisualStyleBackColor = true;
this.btnExport.Click += new System.EventHandler(this.btnExport_Click);
//
// btnCancel
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.Location = new System.Drawing.Point(274, 301);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(84, 23);
this.btnCancel.TabIndex = 5;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.tableLayoutPanel1.TabIndex = 3;
//
// label2
//
@ -200,6 +179,28 @@
this.label3.Text = "Indicators:";
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// btnExport
//
this.btnExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnExport.Location = new System.Drawing.Point(184, 301);
this.btnExport.Name = "btnExport";
this.btnExport.Size = new System.Drawing.Size(84, 23);
this.btnExport.TabIndex = 0;
this.btnExport.Text = "Export";
this.btnExport.UseVisualStyleBackColor = true;
this.btnExport.Click += new System.EventHandler(this.btnExport_Click);
//
// btnCancel
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(274, 301);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(84, 23);
this.btnCancel.TabIndex = 1;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
//
// ImageExportDialog
//
this.AcceptButton = this.btnExport;

View File

@ -15,8 +15,6 @@ namespace MobiusEditor.Dialogs
{
public partial class ImageExportDialog : Form, IHasStatusLabel
{
public delegate void InvokeDelegateEnableControls(Boolean enabled, String processingLabel);
public delegate DialogResult InvokeDelegateMessageBox(String message, MessageBoxButtons buttons, MessageBoxIcon icon);
private SimpleMultiThreading<ImageExportDialog> multiThreader;
private Label m_BusyStatusLabel;
@ -84,6 +82,7 @@ namespace MobiusEditor.Dialogs
// Could make this at the moment of the call, too, but it also has a
// system to ignore further calls if the running one isn't finished.
multiThreader = SimpleMultiThreading.Make(this);
multiThreader.ProcessingLabelBorder = BorderStyle.Fixed3D;
}
private void SetSizeLabel()
@ -191,6 +190,33 @@ namespace MobiusEditor.Dialogs
}
private void btnPickFile_Click(Object sender, EventArgs e)
{
SelectPath();
}
private void btnExport_Click(Object sender, EventArgs e)
{
if (String.IsNullOrEmpty(txtPath.Text))
{
//MessageBox.Show("Please select a filename to export to.", "Error");
if (!SelectPath())
{
return;
}
}
if (!Double.TryParse(txtScale.Text, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out double scale))
{
MessageBox.Show("Could not parse scale factor!", "Error");
return;
}
MapLayerFlag layers = GetLayers() | MapLayerFlag.Template;
bool smooth = chkSmooth.Checked;
string path = txtPath.Text;
Func<String> saveOperation = () => SaveImage(gamePlugin, layers, scale, smooth, path);
multiThreader.ExecuteThreaded(saveOperation, ShowResult, true, EnableControls, "Exporting image");
}
private bool SelectPath()
{
using (SaveFileDialog sfd = new SaveFileDialog())
{
@ -209,29 +235,12 @@ namespace MobiusEditor.Dialogs
if (sfd.ShowDialog(this) == DialogResult.OK)
{
txtPath.Text = sfd.FileName;
return true;
}
return false;
}
}
private void btnExport_Click(Object sender, EventArgs e)
{
if (String.IsNullOrEmpty(txtPath.Text))
{
MessageBox.Show("Please select a filename to export to.", "Error");
return;
}
if (!Double.TryParse(txtScale.Text, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out double scale))
{
MessageBox.Show("Could not parse scale factor!", "Error");
return;
}
MapLayerFlag layers = GetLayers() | MapLayerFlag.Template;
bool smooth = chkSmooth.Checked;
string path = txtPath.Text;
Func<String> saveOperation = () => SaveImage(gamePlugin, layers, scale, smooth, path);
multiThreader.ExecuteThreaded(saveOperation, ShowResult, true, EnableControls, "Exporting image");
}
private static String SaveImage(IGamePlugin gamePlugin, MapLayerFlag layers, double scale, bool smooth, string outputPath)
{
int tileWidth = Math.Max(1, (int)(Globals.OriginalTileWidth * scale));
@ -250,6 +259,10 @@ namespace MobiusEditor.Dialogs
private void ShowResult(String path)
{
if (path == null)
{
MessageBox.Show("Image saving failed!", "Image Export", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
using (ImageExportedDialog imexd = new ImageExportedDialog(path))
{
imexd.ShowDialog(this);

View File

@ -84,7 +84,7 @@ namespace MobiusEditor
public const int MaxTeamClasses = 5;
public const int MaxTeamMissions = 20;
public const long MaxMapSize = 131072;
public const long MaxMapSize = 0x20000;
public static MegafileManager TheMegafileManager;
public static TextureManager TheTextureManager;

View File

@ -48,13 +48,15 @@ namespace MobiusEditor.Interface
Image MapImage { get; }
IFeedBackHandler FeedBackHandler { get; set; }
bool Dirty { get; set; }
string ExtraIniText { get; set; }
void New(string theater);
IEnumerable<string> Load(string path, FileType fileType, out bool modified);
IEnumerable<string> Load(string path, FileType fileType);
bool Save(string path, FileType fileType);

View File

@ -72,7 +72,7 @@ namespace MobiusEditor
this.toolsRandomizeTilesMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolsExportImageMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewMapEnableAllMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewMapDisableAllMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewMapBuildingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@ -82,22 +82,22 @@ namespace MobiusEditor
this.viewMapOverlayMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewMapSmudgeMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewMapWaypointsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewLabelsEnableAllMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsEnableAllMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsDisableAllMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsBoundariesMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsWaypointsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsFootballAreaMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsCellTriggersMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsObjectTriggersMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsBuildingRebuildLabelsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsBuildingFakeLabelsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewIndicatorsFootballAreaMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.developerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.developerGenerateMapPreviewMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.developerGenerateMapPreviewDirectoryMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.developerGoToINIMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
this.debugToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.developerDebugToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.developerDebugShowOverlapCellsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mainStatusStrip = new System.Windows.Forms.StatusStrip();
this.toolStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
@ -105,6 +105,7 @@ namespace MobiusEditor
this.copyrightStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.mouseToolTip = new System.Windows.Forms.ToolTip(this.components);
this.mainToolStrip = new System.Windows.Forms.ToolStrip();
this.mapPanel = new MobiusEditor.Controls.MapPanel();
this.mapToolStripButton = new MobiusEditor.Controls.ViewToolStripButton();
this.smudgeToolStripButton = new MobiusEditor.Controls.ViewToolStripButton();
this.overlayToolStripButton = new MobiusEditor.Controls.ViewToolStripButton();
@ -117,7 +118,6 @@ namespace MobiusEditor
this.waypointsToolStripButton = new MobiusEditor.Controls.ViewToolStripButton();
this.cellTriggersToolStripButton = new MobiusEditor.Controls.ViewToolStripButton();
this.selectToolStripButton = new MobiusEditor.Controls.ViewToolStripButton();
this.mapPanel = new MobiusEditor.Controls.MapPanel();
this.mainMenuStrip.SuspendLayout();
this.mainStatusStrip.SuspendLayout();
this.mainToolStrip.SuspendLayout();
@ -345,15 +345,15 @@ namespace MobiusEditor
// viewToolStripMenuItem
//
this.viewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mapToolStripMenuItem,
this.viewLabelsEnableAllMenuItem});
this.viewMapToolStripMenuItem,
this.viewIndicatorsToolStripMenuItem});
this.viewToolStripMenuItem.Name = "viewToolStripMenuItem";
this.viewToolStripMenuItem.Size = new System.Drawing.Size(44, 20);
this.viewToolStripMenuItem.Text = "&View";
//
// mapToolStripMenuItem
// viewMapToolStripMenuItem
//
this.mapToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.viewMapToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.viewMapEnableAllMenuItem,
this.viewMapDisableAllMenuItem,
this.viewMapBuildingsMenuItem,
@ -363,21 +363,21 @@ namespace MobiusEditor
this.viewMapOverlayMenuItem,
this.viewMapSmudgeMenuItem,
this.viewMapWaypointsMenuItem});
this.mapToolStripMenuItem.Name = "mapToolStripMenuItem";
this.mapToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.mapToolStripMenuItem.Text = "&Map";
this.viewMapToolStripMenuItem.Name = "viewMapToolStripMenuItem";
this.viewMapToolStripMenuItem.Size = new System.Drawing.Size(126, 22);
this.viewMapToolStripMenuItem.Text = "&Map";
//
// viewMapEnableAllMenuItem
//
this.viewMapEnableAllMenuItem.Name = "viewMapEnableAllMenuItem";
this.viewMapEnableAllMenuItem.Size = new System.Drawing.Size(180, 22);
this.viewMapEnableAllMenuItem.Size = new System.Drawing.Size(130, 22);
this.viewMapEnableAllMenuItem.Text = "Enable all";
this.viewMapEnableAllMenuItem.Click += new System.EventHandler(this.ViewMapEnableAllMenuItem_Click);
//
// viewMapDisableAllMenuItem
//
this.viewMapDisableAllMenuItem.Name = "viewMapDisableAllMenuItem";
this.viewMapDisableAllMenuItem.Size = new System.Drawing.Size(180, 22);
this.viewMapDisableAllMenuItem.Size = new System.Drawing.Size(130, 22);
this.viewMapDisableAllMenuItem.Text = "Disable all";
this.viewMapDisableAllMenuItem.Click += new System.EventHandler(this.ViewMapDisableAllMenuItem_Click);
//
@ -387,7 +387,7 @@ namespace MobiusEditor
this.viewMapBuildingsMenuItem.CheckOnClick = true;
this.viewMapBuildingsMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.viewMapBuildingsMenuItem.Name = "viewMapBuildingsMenuItem";
this.viewMapBuildingsMenuItem.Size = new System.Drawing.Size(180, 22);
this.viewMapBuildingsMenuItem.Size = new System.Drawing.Size(130, 22);
this.viewMapBuildingsMenuItem.Text = "&Buildings";
this.viewMapBuildingsMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
@ -397,7 +397,7 @@ namespace MobiusEditor
this.viewMapInfantryMenuItem.CheckOnClick = true;
this.viewMapInfantryMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.viewMapInfantryMenuItem.Name = "viewMapInfantryMenuItem";
this.viewMapInfantryMenuItem.Size = new System.Drawing.Size(180, 22);
this.viewMapInfantryMenuItem.Size = new System.Drawing.Size(130, 22);
this.viewMapInfantryMenuItem.Text = "&Infantry";
this.viewMapInfantryMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
@ -407,7 +407,7 @@ namespace MobiusEditor
this.viewMapUnitsMenuItem.CheckOnClick = true;
this.viewMapUnitsMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.viewMapUnitsMenuItem.Name = "viewMapUnitsMenuItem";
this.viewMapUnitsMenuItem.Size = new System.Drawing.Size(180, 22);
this.viewMapUnitsMenuItem.Size = new System.Drawing.Size(130, 22);
this.viewMapUnitsMenuItem.Text = "&Units";
this.viewMapUnitsMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
@ -417,7 +417,7 @@ namespace MobiusEditor
this.viewMapTerrainMenuItem.CheckOnClick = true;
this.viewMapTerrainMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.viewMapTerrainMenuItem.Name = "viewMapTerrainMenuItem";
this.viewMapTerrainMenuItem.Size = new System.Drawing.Size(180, 22);
this.viewMapTerrainMenuItem.Size = new System.Drawing.Size(130, 22);
this.viewMapTerrainMenuItem.Text = "&Terrain";
this.viewMapTerrainMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
@ -427,7 +427,7 @@ namespace MobiusEditor
this.viewMapOverlayMenuItem.CheckOnClick = true;
this.viewMapOverlayMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.viewMapOverlayMenuItem.Name = "viewMapOverlayMenuItem";
this.viewMapOverlayMenuItem.Size = new System.Drawing.Size(180, 22);
this.viewMapOverlayMenuItem.Size = new System.Drawing.Size(130, 22);
this.viewMapOverlayMenuItem.Text = "&Overlay";
this.viewMapOverlayMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
@ -437,7 +437,7 @@ namespace MobiusEditor
this.viewMapSmudgeMenuItem.CheckOnClick = true;
this.viewMapSmudgeMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.viewMapSmudgeMenuItem.Name = "viewMapSmudgeMenuItem";
this.viewMapSmudgeMenuItem.Size = new System.Drawing.Size(180, 22);
this.viewMapSmudgeMenuItem.Size = new System.Drawing.Size(130, 22);
this.viewMapSmudgeMenuItem.Text = "&Smudge";
this.viewMapSmudgeMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
@ -447,13 +447,13 @@ namespace MobiusEditor
this.viewMapWaypointsMenuItem.CheckOnClick = true;
this.viewMapWaypointsMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.viewMapWaypointsMenuItem.Name = "viewMapWaypointsMenuItem";
this.viewMapWaypointsMenuItem.Size = new System.Drawing.Size(180, 22);
this.viewMapWaypointsMenuItem.Size = new System.Drawing.Size(130, 22);
this.viewMapWaypointsMenuItem.Text = "&Waypoints";
this.viewMapWaypointsMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
// viewLabelsEnableAllMenuItem
// viewIndicatorsToolStripMenuItem
//
this.viewLabelsEnableAllMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.viewIndicatorsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.viewIndicatorsEnableAllMenuItem,
this.viewIndicatorsDisableAllMenuItem,
this.viewIndicatorsBoundariesMenuItem,
@ -463,9 +463,9 @@ namespace MobiusEditor
this.viewIndicatorsObjectTriggersMenuItem,
this.viewIndicatorsBuildingRebuildLabelsMenuItem,
this.viewIndicatorsBuildingFakeLabelsMenuItem});
this.viewLabelsEnableAllMenuItem.Name = "viewLabelsEnableAllMenuItem";
this.viewLabelsEnableAllMenuItem.Size = new System.Drawing.Size(180, 22);
this.viewLabelsEnableAllMenuItem.Text = "&Indicators";
this.viewIndicatorsToolStripMenuItem.Name = "viewIndicatorsToolStripMenuItem";
this.viewIndicatorsToolStripMenuItem.Size = new System.Drawing.Size(126, 22);
this.viewIndicatorsToolStripMenuItem.Text = "&Indicators";
//
// viewIndicatorsEnableAllMenuItem
//
@ -501,6 +501,16 @@ namespace MobiusEditor
this.viewIndicatorsWaypointsMenuItem.Text = "&Waypoint labels";
this.viewIndicatorsWaypointsMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
// viewIndicatorsFootballAreaMenuItem
//
this.viewIndicatorsFootballAreaMenuItem.Checked = true;
this.viewIndicatorsFootballAreaMenuItem.CheckOnClick = true;
this.viewIndicatorsFootballAreaMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.viewIndicatorsFootballAreaMenuItem.Name = "viewIndicatorsFootballAreaMenuItem";
this.viewIndicatorsFootballAreaMenuItem.Size = new System.Drawing.Size(207, 22);
this.viewIndicatorsFootballAreaMenuItem.Text = "Football goal areas";
this.viewIndicatorsFootballAreaMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
// viewIndicatorsCellTriggersMenuItem
//
this.viewIndicatorsCellTriggersMenuItem.Checked = true;
@ -541,23 +551,13 @@ namespace MobiusEditor
this.viewIndicatorsBuildingFakeLabelsMenuItem.Text = "Building \'&fake\' Labels";
this.viewIndicatorsBuildingFakeLabelsMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
// viewIndicatorsFootballAreaMenuItem
//
this.viewIndicatorsFootballAreaMenuItem.Checked = true;
this.viewIndicatorsFootballAreaMenuItem.CheckOnClick = true;
this.viewIndicatorsFootballAreaMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.viewIndicatorsFootballAreaMenuItem.Name = "viewIndicatorsFootballAreaMenuItem";
this.viewIndicatorsFootballAreaMenuItem.Size = new System.Drawing.Size(207, 22);
this.viewIndicatorsFootballAreaMenuItem.Text = "Football goal areas";
this.viewIndicatorsFootballAreaMenuItem.CheckedChanged += new System.EventHandler(this.ViewMenuItem_CheckedChanged);
//
// developerToolStripMenuItem
//
this.developerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.developerGenerateMapPreviewMenuItem,
this.developerGoToINIMenuItem,
this.toolStripMenuItem2,
this.debugToolStripMenuItem});
this.developerDebugToolStripMenuItem});
this.developerToolStripMenuItem.Name = "developerToolStripMenuItem";
this.developerToolStripMenuItem.Size = new System.Drawing.Size(72, 20);
this.developerToolStripMenuItem.Text = "&Developer";
@ -569,7 +569,6 @@ namespace MobiusEditor
this.developerGenerateMapPreviewMenuItem.Name = "developerGenerateMapPreviewMenuItem";
this.developerGenerateMapPreviewMenuItem.Size = new System.Drawing.Size(192, 22);
this.developerGenerateMapPreviewMenuItem.Text = "&Generate map preview";
this.developerGenerateMapPreviewMenuItem.Click += new System.EventHandler(this.developerGenerateMapPreviewMenuItem_Click);
//
// developerGenerateMapPreviewDirectoryMenuItem
//
@ -590,13 +589,13 @@ namespace MobiusEditor
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
this.toolStripMenuItem2.Size = new System.Drawing.Size(189, 6);
//
// debugToolStripMenuItem
// developerDebugToolStripMenuItem
//
this.debugToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.developerDebugToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.developerDebugShowOverlapCellsMenuItem});
this.debugToolStripMenuItem.Name = "debugToolStripMenuItem";
this.debugToolStripMenuItem.Size = new System.Drawing.Size(192, 22);
this.debugToolStripMenuItem.Text = "&Debug";
this.developerDebugToolStripMenuItem.Name = "developerDebugToolStripMenuItem";
this.developerDebugToolStripMenuItem.Size = new System.Drawing.Size(192, 22);
this.developerDebugToolStripMenuItem.Text = "&Debug";
//
// developerDebugShowOverlapCellsMenuItem
//
@ -664,6 +663,26 @@ namespace MobiusEditor
this.mainToolStrip.Text = "toolStrip1";
this.mainToolStrip.MouseMove += new System.Windows.Forms.MouseEventHandler(this.mainToolStrip_MouseMove);
//
// mapPanel
//
this.mapPanel.AllowDrop = true;
this.mapPanel.BackColor = System.Drawing.Color.Black;
this.mapPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.mapPanel.FocusOnMouseEnter = true;
this.mapPanel.Location = new System.Drawing.Point(0, 55);
this.mapPanel.MapImage = null;
this.mapPanel.MaxZoom = 8D;
this.mapPanel.MinZoom = 1D;
this.mapPanel.Name = "mapPanel";
this.mapPanel.Size = new System.Drawing.Size(1008, 484);
this.mapPanel.SmoothScale = false;
this.mapPanel.TabIndex = 4;
this.mapPanel.Zoom = 1D;
this.mapPanel.ZoomStep = 1D;
this.mapPanel.DragDrop += new System.Windows.Forms.DragEventHandler(this.MapPanel_DragDrop);
this.mapPanel.DragEnter += new System.Windows.Forms.DragEventHandler(this.MapPanel_DragEnter);
this.mapPanel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.MapPanel_MouseMove);
//
// mapToolStripButton
//
this.mapToolStripButton.Image = ((System.Drawing.Image)(resources.GetObject("mapToolStripButton.Image")));
@ -783,26 +802,7 @@ namespace MobiusEditor
this.selectToolStripButton.Text = "Select";
this.selectToolStripButton.ToolType = MobiusEditor.Interface.ToolType.Select;
this.selectToolStripButton.Visible = false;
//
// mapPanel
//
this.mapPanel.AllowDrop = true;
this.mapPanel.BackColor = System.Drawing.Color.Black;
this.mapPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.mapPanel.FocusOnMouseEnter = true;
this.mapPanel.Location = new System.Drawing.Point(0, 55);
this.mapPanel.MapImage = null;
this.mapPanel.MaxZoom = 8D;
this.mapPanel.MinZoom = 1D;
this.mapPanel.Name = "mapPanel";
this.mapPanel.Size = new System.Drawing.Size(1008, 484);
this.mapPanel.SmoothScale = false;
this.mapPanel.TabIndex = 4;
this.mapPanel.Zoom = 1D;
this.mapPanel.ZoomStep = 1D;
this.mapPanel.DragDrop += new System.Windows.Forms.DragEventHandler(this.MapPanel_DragDrop);
this.mapPanel.DragEnter += new System.Windows.Forms.DragEventHandler(this.MapPanel_DragEnter);
this.mapPanel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.MapPanel_MouseMove);
this.selectToolStripButton.Click += new System.EventHandler(this.mainToolStripButton_Click);
//
// MainForm
//
@ -853,7 +853,7 @@ namespace MobiusEditor
private System.Windows.Forms.ToolStripMenuItem editUndoMenuItem;
private System.Windows.Forms.ToolStripMenuItem editRedoMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2;
private System.Windows.Forms.ToolStripMenuItem debugToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem developerDebugToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem developerDebugShowOverlapCellsMenuItem;
private System.Windows.Forms.ToolStripMenuItem filePublishMenuItem;
private System.Windows.Forms.ToolTip mouseToolTip;
@ -877,7 +877,7 @@ namespace MobiusEditor
private MobiusEditor.Controls.ViewToolStripButton cellTriggersToolStripButton;
private System.Windows.Forms.ToolStripMenuItem settingsTeamTypesMenuItem;
private System.Windows.Forms.ToolStripMenuItem settingsTriggersMenuItem;
private System.Windows.Forms.ToolStripMenuItem mapToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewMapToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewMapTerrainMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewMapOverlayMenuItem;
private System.Windows.Forms.ToolStripStatusLabel toolStatusLabel;
@ -891,7 +891,7 @@ namespace MobiusEditor
private System.Windows.Forms.ToolStripMenuItem viewMapSmudgeMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewMapWaypointsMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewMapEnableAllMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewLabelsEnableAllMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewIndicatorsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewIndicatorsEnableAllMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewIndicatorsDisableAllMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewIndicatorsBoundariesMenuItem;

View File

@ -25,7 +25,6 @@ using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
@ -34,7 +33,7 @@ using System.Windows.Forms;
namespace MobiusEditor
{
public partial class MainForm : Form, IFeedBackHandler
public partial class MainForm : Form, IFeedBackHandler, IHasStatusLabel
{
public Dictionary<GameType, string[]> ModPaths { get; set; }
@ -108,6 +107,14 @@ namespace MobiusEditor
private readonly Timer steamUpdateTimer = new Timer();
private SimpleMultiThreading<MainForm> multiThreader;
Label busyStatusLabel;
public Label StatusLabel
{
get { return busyStatusLabel; }
set { busyStatusLabel = value; }
}
static MainForm()
{
toolTypes = ((IEnumerable<ToolType>)Enum.GetValues(typeof(ToolType))).Where(t => t != ToolType.None).ToArray();
@ -153,6 +160,8 @@ namespace MobiusEditor
UpdateUndoRedo();
steamUpdateTimer.Interval = 500;
steamUpdateTimer.Tick += SteamUpdateTimer_Tick;
multiThreader = SimpleMultiThreading.Make(this);
multiThreader.ProcessingLabelBorder = BorderStyle.Fixed3D;
}
private void SetTitle()
@ -197,7 +206,7 @@ namespace MobiusEditor
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
RefreshAvailableTools();
RefreshUI();
UpdateVisibleLayers();
//filePublishMenuItem.Enabled = SteamworksUGC.IsInit;
steamUpdateTimer.Start();
@ -253,6 +262,18 @@ namespace MobiusEditor
case OemScanCode.H:
selectToolStripButton.PerformClick();
return true;
case OemScanCode.NumPadPlus:
if (plugin != null && mapPanel.MapImage != null)
{
mapPanel.IncreaseZoomStep();
}
return true;
case OemScanCode.NumPadMinus:
if (plugin != null && mapPanel.MapImage != null)
{
mapPanel.DecreaseZoomStep();
}
return true;
}
}
else if (keyData == (Keys.Control | Keys.Z))
@ -292,61 +313,7 @@ namespace MobiusEditor
{
return;
}
using (NewMapDialog nmd = new NewMapDialog())
{
if (nmd.ShowDialog() != DialogResult.OK)
{
return;
}
if (plugin != null)
{
plugin.Dispose();
}
plugin = null;
string[] modPaths = null;
if (ModPaths != null)
{
ModPaths.TryGetValue(nmd.GameType, out modPaths);
}
Globals.TheTextureManager.ExpandModPaths = modPaths;
Globals.TheTextureManager.Reset();
Globals.TheTilesetManager.ExpandModPaths = modPaths;
Globals.TheTilesetManager.Reset();
Globals.TheTeamColorManager.ExpandModPaths = modPaths;
if (nmd.GameType == GameType.TiberianDawn)
{
Globals.TheTeamColorManager.Reset();
Globals.TheTeamColorManager.Load(@"DATA\XML\CNCTDTEAMCOLORS.XML");
plugin = new TiberianDawn.GamePlugin(nmd.MegaMap, this);
plugin.New(nmd.TheaterName);
}
else if (nmd.GameType == GameType.RedAlert)
{
Globals.TheTeamColorManager.Reset();
Globals.TheTeamColorManager.Load(@"DATA\XML\CNCRATEAMCOLORS.XML");
plugin = new RedAlert.GamePlugin(this);
plugin.New(nmd.TheaterName);
}
else if (nmd.GameType == GameType.SoleSurvivor)
{
Globals.TheTeamColorManager.Reset();
Globals.TheTeamColorManager.Load(@"DATA\XML\CNCTDTEAMCOLORS.XML");
plugin = new SoleSurvivor.GamePlugin(this);
plugin.New(nmd.TheaterName);
}
if (SteamworksUGC.IsInit)
{
plugin.Map.BasicSection.Author = SteamFriends.GetPersonaName();
}
LoadIcons(plugin);
mapPanel.MapImage = plugin.MapImage;
filename = null;
SetTitle();
url.Clear();
ClearAllTools();
RefreshAvailableTools();
RefreshActiveTool();
}
NewFile();
}
private void FileOpenMenuItem_Click(object sender, EventArgs e)
@ -503,7 +470,7 @@ namespace MobiusEditor
{
sfd.AutoUpgradeEnabled = false;
sfd.RestoreDirectory = true;
sfd.Filter = "MEG files (*.meg)|*.meg";
if (sfd.ShowDialog(this) == DialogResult.OK)
{
@ -655,7 +622,7 @@ namespace MobiusEditor
{
plugin.Dirty = true;
plugin.Map.Triggers = reordered;
RefreshAvailableTools();
RefreshUI();
}
}
}
@ -730,7 +697,7 @@ namespace MobiusEditor
var sb = new StringBuilder();
sb.AppendFormat("X = {0}, Y = {1}, Cell = {2}", location.X, location.Y, cell);
var template = plugin.Map.Templates[cell];
var templateType = template?.Type;
var templateType = template?.Type;
if (templateType != null)
{
sb.AppendFormat(", Template = {0} ({1})", templateType.DisplayName, template.Icon);
@ -787,6 +754,34 @@ namespace MobiusEditor
}
}
private void NewFile()
{
if (!PromptSaveMap())
{
return;
}
GameType gameType = GameType.None;
string theater = null;
bool isTdMegaMap = false;
using (NewMapDialog nmd = new NewMapDialog())
{
if (nmd.ShowDialog() != DialogResult.OK)
{
return;
}
gameType = nmd.GameType;
isTdMegaMap = nmd.MegaMap;
theater = nmd.TheaterName;
}
string[] modPaths = null;
if (ModPaths != null)
{
ModPaths.TryGetValue(gameType, out modPaths);
}
Unload();
multiThreader.ExecuteThreaded(() => NewFile(gameType, theater, isTdMegaMap, modPaths), PostLoad, true, LoadUnloadUi, "Loading new map");
}
private void OpenFile(String fileName, bool askSave)
{
if (askSave && !PromptSaveMap())
@ -794,19 +789,203 @@ namespace MobiusEditor
return;
}
var fileInfo = new FileInfo(fileName);
if (LoadFile(fileInfo.FullName))
String name = fileInfo.FullName;
if (!GetPluginOptions(name, out FileType fileType, out GameType gameType, out bool isTdMegaMap))
{
mru.Add(fileInfo);
return;
}
string[] modPaths = null;
if (ModPaths != null)
{
ModPaths.TryGetValue(gameType, out modPaths);
}
multiThreader.ExecuteThreaded(() => LoadFile(name, fileType, gameType, isTdMegaMap, modPaths), PostLoad, true, LoadUnloadUi, "Loading map");
}
/// <summary>
/// WARNING: this EnableUI function is meant for map load, meaning it unloads the current plugin in addition to disabling all controls!
/// </summary>
/// <param name="enableUI"></param>
/// <param name="label"></param>
private void LoadUnloadUi(bool enableUI, string label)
{
fileNewMenuItem.Enabled = enableUI;
fileOpenMenuItem.Enabled = enableUI;
fileRecentFilesMenuItem.Enabled = enableUI;
viewMapToolStripMenuItem.Enabled = enableUI;
viewIndicatorsToolStripMenuItem.Enabled = enableUI;
if (enableUI)
{
multiThreader.RemoveBusyLabel();
}
else
{
mru.Remove(fileInfo);
MessageBox.Show(string.Format("Error loading {0}.", fileName), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Unload();
multiThreader.CreateBusyLabel(label);
}
}
private bool LoadFile(string loadFilename)
/// <summary>
/// The 'lighter' enable/disable UI function, for map saving.
/// </summary>
/// <param name="enableUI"></param>
/// <param name="label"></param>
private void EnableDisableUi(bool enableUI, string label)
{
EnableDisableMenuItems(enableUI);
if (enableUI)
{
multiThreader.RemoveBusyLabel();
}
else
{
Unload();
multiThreader.CreateBusyLabel(label);
}
}
private static IGamePlugin LoadNewPlugin(GameType gameType, bool isTdMegaMap, string[] modPaths)
{
return LoadNewPlugin(gameType, isTdMegaMap, modPaths, false);
}
private static IGamePlugin LoadNewPlugin(GameType gameType, bool isTdMegaMap, string[] modPaths, bool noImage)
{
Globals.TheTextureManager.ExpandModPaths = modPaths;
Globals.TheTextureManager.Reset();
Globals.TheTilesetManager.ExpandModPaths = modPaths;
Globals.TheTilesetManager.Reset();
Globals.TheTeamColorManager.ExpandModPaths = modPaths;
IGamePlugin plugin = null;
if (gameType == GameType.TiberianDawn)
{
Globals.TheTeamColorManager.Reset();
Globals.TheTeamColorManager.Load(@"DATA\XML\CNCTDTEAMCOLORS.XML");
plugin = new TiberianDawn.GamePlugin(!noImage, isTdMegaMap);
}
else if (gameType == GameType.RedAlert)
{
Globals.TheTeamColorManager.Reset();
Globals.TheTeamColorManager.Load(@"DATA\XML\CNCRATEAMCOLORS.XML");
plugin = new RedAlert.GamePlugin(!noImage);
}
else if (gameType == GameType.SoleSurvivor)
{
Globals.TheTeamColorManager.Reset();
Globals.TheTeamColorManager.Load(@"DATA\XML\CNCTDTEAMCOLORS.XML");
plugin = new SoleSurvivor.GamePlugin(!noImage);
}
return plugin;
}
/// <summary>
/// The separate-threaded part for making a new map.
/// </summary>
/// <param name="gameType"></param>
/// <param name="theater"></param>
/// <param name="isTdMegaMap"></param>
/// <param name="modPaths"></param>
/// <returns></returns>
private static (string FileName, FileType FileType, IGamePlugin Plugin, string[] Errors) NewFile(GameType gameType, string theater, bool isTdMegaMap, string[] modPaths)
{
try
{
IGamePlugin plugin = LoadNewPlugin(gameType, isTdMegaMap, modPaths);
plugin.New(theater);
if (SteamworksUGC.IsInit)
{
plugin.Map.BasicSection.Author = SteamFriends.GetPersonaName();
}
return (null, FileType.None, plugin, null);
}
catch (Exception ex)
{
List<string> errorMessage = new List<string>();
errorMessage.Add("Error loading map: " + ex.Message);
#if DEBUG
errorMessage.Add(ex.StackTrace);
#endif
return (null, FileType.None, null, errorMessage.ToArray());
}
}
/// <summary>
/// The separate-threaded part for loading a map.
/// </summary>
/// <param name="loadFilename"></param>
/// <param name="fileType"></param>
/// <param name="gameType"></param>
/// <param name="isTdMegaMap"></param>
/// <param name="modPaths"></param>
/// <returns></returns>
private static (string, FileType, IGamePlugin, string[]) LoadFile(string loadFilename, FileType fileType, GameType gameType, bool isTdMegaMap, string[] modPaths)
{
try
{
IGamePlugin plugin = LoadNewPlugin(gameType, isTdMegaMap, modPaths);
// Simply being flagged as single play no longer flags maps as "modified by the loading process",
// to make it simpler to open classic maps and examine them without getting a save prompt on close.
string[] errors = plugin.Load(loadFilename, fileType).ToArray();
return (loadFilename, fileType, plugin, errors);
}
catch (Exception ex)
{
List<string> errorMessage = new List<string>();
errorMessage.Add("Error loading map: " + ex.Message);
#if DEBUG
errorMessage.Add(ex.StackTrace);
#endif
return (loadFilename, fileType, null, errorMessage.ToArray());
}
}
private void PostLoad((string FileName, FileType FileType, IGamePlugin Plugin, string[] Errors) loadInfo)
{
string[] errors = loadInfo.Errors ?? new string[0];
if (loadInfo.Plugin == null)
{
if (loadInfo.FileName != null)
{
var fileInfo = new FileInfo(loadInfo.FileName);
mru.Remove(fileInfo);
}
MessageBox.Show(string.Format("Error loading {0}: {1}", loadInfo.FileName ?? "new map", String.Join("\n", errors)), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
this.plugin = loadInfo.Plugin;
LoadIcons(plugin);
if (errors.Length > 0)
{
using (ErrorMessageBox emb = new ErrorMessageBox())
{
emb.Errors = errors;
emb.StartPosition = FormStartPosition.CenterParent;
emb.ShowDialog(this);
}
}
mapPanel.MapImage = plugin.MapImage;
filename = loadInfo.FileName;
loadedFileType = loadInfo.FileType;
url.Clear();
DisableAllTools();
RefreshUI();
RefreshActiveTool();
SetTitle();
if (loadInfo.FileName != null)
{
var fileInfo = new FileInfo(loadInfo.FileName);
mru.Add(fileInfo);
}
}
}
private Boolean GetPluginOptions(String loadFilename, out FileType fileType, out GameType gameType, out bool isTdMegaMap)
{
fileType = FileType.None;
gameType = GameType.None;
isTdMegaMap = false;
try
{
if (!File.Exists(loadFilename))
@ -818,7 +997,6 @@ namespace MobiusEditor
{
return false;
}
FileType fileType = FileType.None;
switch (Path.GetExtension(loadFilename).ToLower())
{
case ".ini":
@ -861,49 +1039,54 @@ namespace MobiusEditor
}
}
}
GameType gameType = GameType.None;
string iniFile = fileType != FileType.BIN ? loadFilename : Path.ChangeExtension(loadFilename, ".ini");
INI iniContents = GeneralUtils.GetIniContents(iniFile, fileType);
if (iniContents == null)
{
return false;
}
switch (fileType)
{
case FileType.INI:
{
gameType = RedAlert.GamePlugin.CheckForRAMap(loadFilename, fileType) ? GameType.RedAlert : GameType.TiberianDawn;
gameType = RedAlert.GamePlugin.CheckForRAMap(iniContents) ? GameType.RedAlert : GameType.TiberianDawn;
break;
}
case FileType.BIN:
{
gameType = File.Exists(Path.ChangeExtension(loadFilename, ".ini")) ? GameType.TiberianDawn : GameType.None;
gameType = File.Exists(iniFile) ? GameType.TiberianDawn : GameType.None;
break;
}
#if DEVELOPER
case FileType.PGM:
{
try
{
using (var megafile = new Megafile(loadFilename))
try
{
if (megafile.Any(f => Path.GetExtension(f).ToLower() == ".mpr"))
using (var megafile = new Megafile(loadFilename))
{
gameType = GameType.RedAlert;
}
else
{
gameType = GameType.TiberianDawn;
if (megafile.Any(f => Path.GetExtension(f).ToLower() == ".mpr"))
{
gameType = GameType.RedAlert;
}
else
{
gameType = GameType.TiberianDawn;
}
}
}
catch (FileNotFoundException)
{
return false;
}
break;
}
catch (FileNotFoundException)
{
return false;
}
break;
}
#endif
}
bool isTdMegaMap = false;
if (gameType == GameType.TiberianDawn)
{
isTdMegaMap = TiberianDawn.GamePlugin.CheckForMegamap(loadFilename, fileType);
if (isTdMegaMap && SoleSurvivor.GamePlugin.CheckForSSmap(loadFilename, fileType))
isTdMegaMap = TiberianDawn.GamePlugin.CheckForMegamap(iniContents);
if (isTdMegaMap && SoleSurvivor.GamePlugin.CheckForSSmap(iniContents))
{
gameType = GameType.SoleSurvivor;
}
@ -912,82 +1095,6 @@ namespace MobiusEditor
{
return false;
}
Unload();
if (plugin != null)
{
plugin.Dispose();
}
plugin = null;
string[] modPaths = null;
if (ModPaths != null)
{
ModPaths.TryGetValue(gameType, out modPaths);
}
Globals.TheTextureManager.ExpandModPaths = modPaths;
Globals.TheTextureManager.Reset();
Globals.TheTilesetManager.ExpandModPaths = modPaths;
Globals.TheTilesetManager.Reset();
Globals.TheTeamColorManager.ExpandModPaths = modPaths;
switch (gameType)
{
case GameType.TiberianDawn:
Globals.TheTeamColorManager.Reset();
Globals.TheTeamColorManager.Load(@"DATA\XML\CNCTDTEAMCOLORS.XML");
plugin = new TiberianDawn.GamePlugin(isTdMegaMap, this);
break;
case GameType.RedAlert:
Globals.TheTeamColorManager.Reset();
Globals.TheTeamColorManager.Load(@"DATA\XML\CNCRATEAMCOLORS.XML");
plugin = new RedAlert.GamePlugin(this);
break;
case GameType.SoleSurvivor:
Globals.TheTeamColorManager.Reset();
Globals.TheTeamColorManager.Load(@"DATA\XML\CNCTDTEAMCOLORS.XML");
plugin = new SoleSurvivor.GamePlugin(this);
break;
}
string[] errors;
bool modifiedByLoad;
try
{
// Simply being flagged as single play no longer flags maps as "modified by the loading process",
// to make it simpler to open classic maps and examine them without getting a save prompt on close.
errors = plugin.Load(loadFilename, fileType, out modifiedByLoad).ToArray();
LoadIcons(plugin);
if (errors.Length > 0)
{
using (ErrorMessageBox emb = new ErrorMessageBox())
{
emb.Errors = errors;
emb.StartPosition = FormStartPosition.CenterParent;
emb.ShowDialog(this);
}
}
}
catch (Exception ex)
{
String errorMessage = "Error loading map: " + ex.Message;
#if DEBUG
errorMessage += "\n\n" + ex.StackTrace;
#endif
MessageBox.Show(errorMessage, this.GetProgramVersionTitle(), MessageBoxButtons.OK, MessageBoxIcon.Error);
this.Unload();
#if DEVELOPER
throw;
#else
return false;
#endif
}
mapPanel.MapImage = plugin.MapImage;
filename = loadFilename;
loadedFileType = fileType;
plugin.Dirty = modifiedByLoad;
url.Clear();
ClearAllTools();
RefreshAvailableTools();
RefreshActiveTool();
SetTitle();
return true;
}
@ -1000,15 +1107,16 @@ namespace MobiusEditor
{
url.Clear();
// Disable all tools
ActiveToolType = ToolType.None;
ActiveToolType = ToolType.None; // Always re-defaults to map anyway, so nicer if nothing is selected during load.
this.ActiveControl = null;
ClearAllTools();
DisableAllTools();
// Unlink plugin
IGamePlugin pl = plugin;
plugin = null;
// Remove tools
RefreshAvailableTools();
// Clear UI
// Refresh UI to plugin-less state
RefreshUI();
// Reset map panel. Looks odd if the zoom/position is preserved, so zoom out first.
mapPanel.Zoom = 1.0;
mapPanel.MapImage = null;
mapPanel.Invalidate();
// Dispose plugin
@ -1048,7 +1156,8 @@ namespace MobiusEditor
{
if (inputNameType == FileType.None)
{
return false;
// Just default to ini
fileType = FileType.INI;
}
else
{
@ -1074,33 +1183,10 @@ namespace MobiusEditor
return true;
}
private void RefreshAvailableTools()
private void RefreshUI()
{
// Menu items
if (plugin != null)
{
fileSaveMenuItem.Enabled = true;
fileSaveAsMenuItem.Enabled = true;
filePublishMenuItem.Enabled = true;
fileExportMenuItem.Enabled = true;
editUndoMenuItem.Enabled = url.CanUndo;
editRedoMenuItem.Enabled = url.CanRedo;
editClearUndoRedoMenuItem.Enabled = url.CanUndo || url.CanRedo;
settingsMapSettingsMenuItem.Enabled = true;
settingsTeamTypesMenuItem.Enabled = true;
settingsTriggersMenuItem.Enabled = true;
toolsPowerMenuItem.Enabled = true;
toolsExportImageMenuItem.Enabled = true;
developerGoToINIMenuItem.Enabled = true;
developerDebugShowOverlapCellsMenuItem.Enabled = true;
developerGenerateMapPreviewDirectoryMenuItem.Enabled = true;
viewMapBuildingsMenuItem.Visible = plugin.GameType != GameType.SoleSurvivor;
viewIndicatorsFootballAreaMenuItem.Visible = plugin.GameType == GameType.SoleSurvivor;
viewIndicatorsBuildingFakeLabelsMenuItem.Visible = plugin.GameType == GameType.RedAlert;
viewIndicatorsBuildingRebuildLabelsMenuItem.Visible = plugin.GameType != GameType.SoleSurvivor;
}
// Special rules per game.
EnableDisableMenuItems(true);
// Tools
availableToolTypes = ToolType.None;
if (plugin != null)
@ -1118,6 +1204,7 @@ namespace MobiusEditor
if (plugin.Map.OverlayTypes.Any(t => t.IsWall && (!Globals.FilterTheaterObjects || t.Theaters == null || t.Theaters.Contains(th)))) availableToolTypes |= ToolType.Wall;
// Always allow celltrigger tool, even if triggers list is empty; it contains a tooltip saying which triggers are eligible.
availableToolTypes |= ToolType.CellTrigger;
// TODO - Select tool will always be enabled
availableToolTypes |= ToolType.Select;
}
foreach (var toolStripButton in viewToolStripButtons)
@ -1127,30 +1214,40 @@ namespace MobiusEditor
ActiveToolType = activeToolType;
}
private void ClearAllTools()
private void EnableDisableMenuItems(bool enable)
{
// Menu items
fileSaveMenuItem.Enabled = false;
fileSaveAsMenuItem.Enabled = false;
filePublishMenuItem.Enabled = false;
fileExportMenuItem.Enabled = false;
editUndoMenuItem.Enabled = false;
editRedoMenuItem.Enabled = false;
editClearUndoRedoMenuItem.Enabled = false;
settingsMapSettingsMenuItem.Enabled = false;
settingsTeamTypesMenuItem.Enabled = false;
settingsTriggersMenuItem.Enabled = false;
toolsPowerMenuItem.Enabled = false;
toolsExportImageMenuItem.Enabled = false;
developerGoToINIMenuItem.Enabled = false;
developerDebugShowOverlapCellsMenuItem.Enabled = false;
developerGenerateMapPreviewDirectoryMenuItem.Enabled = false;
bool hasPlugin = plugin != null;
fileSaveMenuItem.Enabled = enable && hasPlugin;
fileSaveAsMenuItem.Enabled = enable && hasPlugin;
filePublishMenuItem.Enabled = enable && hasPlugin;
fileExportMenuItem.Enabled = enable && hasPlugin;
editUndoMenuItem.Enabled = enable && hasPlugin && url.CanUndo;
editRedoMenuItem.Enabled = enable && hasPlugin && url.CanRedo;
editClearUndoRedoMenuItem.Enabled = enable && hasPlugin && url.CanUndo || url.CanRedo;
settingsMapSettingsMenuItem.Enabled = enable && hasPlugin;
settingsTeamTypesMenuItem.Enabled = enable && hasPlugin;
settingsTriggersMenuItem.Enabled = enable && hasPlugin;
toolsPowerMenuItem.Enabled = enable && hasPlugin;
toolsStorageMenuItem.Enabled = enable && hasPlugin;
toolsRandomizeTilesMenuItem.Enabled = enable && hasPlugin;
toolsExportImageMenuItem.Enabled = enable && hasPlugin;
developerGoToINIMenuItem.Enabled = enable && hasPlugin;
developerDebugToolStripMenuItem.Enabled = enable && hasPlugin;
developerGenerateMapPreviewDirectoryMenuItem.Enabled = enable && hasPlugin;
viewMapBuildingsMenuItem.Visible = plugin == null || plugin.GameType != GameType.SoleSurvivor;
viewIndicatorsBuildingFakeLabelsMenuItem.Visible = plugin == null || plugin.GameType == GameType.RedAlert;
viewIndicatorsBuildingRebuildLabelsMenuItem.Visible = plugin == null || plugin.GameType != GameType.SoleSurvivor;
viewIndicatorsFootballAreaMenuItem.Visible = plugin == null || plugin.GameType == GameType.SoleSurvivor;
viewMapToolStripMenuItem.Enabled = enable;
viewIndicatorsToolStripMenuItem.Enabled = enable;
// Special rules per game.
viewMapBuildingsMenuItem.Visible = !hasPlugin || plugin.GameType != GameType.SoleSurvivor;
viewIndicatorsBuildingFakeLabelsMenuItem.Visible = !hasPlugin || plugin.GameType == GameType.RedAlert;
viewIndicatorsBuildingRebuildLabelsMenuItem.Visible = !hasPlugin || plugin.GameType != GameType.SoleSurvivor;
viewIndicatorsFootballAreaMenuItem.Visible = !hasPlugin || plugin.GameType == GameType.SoleSurvivor;
}
private void DisableAllTools()
{
// Tools
ClearActiveTool();
foreach (var kvp in toolForms)
@ -1246,6 +1343,7 @@ namespace MobiusEditor
break;
case ToolType.Select:
{
// TODO: select/copy/paste function
toolDialog = null; // new SelectToolDialog(this);
}
break;
@ -1358,7 +1456,7 @@ namespace MobiusEditor
e.Effect = DragDropEffects.Copy;
}
}
private void MapPanel_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
String[] files = (String[])e.Data.GetData(DataFormats.FileDrop);
@ -1554,13 +1652,7 @@ namespace MobiusEditor
private void developerGenerateMapPreviewMenuItem_Click(object sender, EventArgs e)
{
#if DEVELOPER
if ((plugin == null) || string.IsNullOrEmpty(filename))
{
return;
}
plugin.Map.GenerateMapPreview().Save(Path.ChangeExtension(filename, ".tga"));
#endif
}
private void developerGoToINIMenuItem_Click(object sender, EventArgs e)
@ -1594,41 +1686,18 @@ namespace MobiusEditor
{
ShowNewFolderButton = false
};
if (fbd.ShowDialog() == DialogResult.OK)
if (fbd.ShowDialog() != DialogResult.OK)
{
var extensions = new string[] { ".ini", ".mpr" };
foreach (var file in Directory.EnumerateFiles(fbd.SelectedPath).Where(file => extensions.Contains(Path.GetExtension(file).ToLower())))
{
GameType gameType = GameType.None;
var ini = new INI();
using (var reader = new StreamReader(file))
{
ini.Parse(reader);
}
gameType = ini.Sections.Contains("MapPack") ? GameType.RedAlert : GameType.TiberianDawn;
if (gameType == GameType.None)
{
continue;
}
IGamePlugin plugin = null;
switch (gameType)
{
case GameType.TiberianDawn:
{
plugin = new TiberianDawn.GamePlugin(false);
}
break;
case GameType.RedAlert:
{
plugin = new RedAlert.GamePlugin(false);
}
break;
}
plugin.Load(file, FileType.INI);
plugin.Map.GenerateMapPreview().Save(Path.ChangeExtension(file, ".tga"));
plugin.Dispose();
}
return;
}
var extensions = new string[] { ".ini", ".mpr" };
foreach (var file in Directory.EnumerateFiles(fbd.SelectedPath).Where(file => extensions.Contains(Path.GetExtension(file).ToLower())))
{
bool valid = GetPluginOptions(file, out FileType fileType, out GameType gameType, out bool isTdMegaMap);
IGamePlugin plugin = LoadNewPlugin(gameType, isTdMegaMap, null, true);
plugin.Load(file, fileType);
plugin.Map.GenerateMapPreview(gameType, true).Save(Path.ChangeExtension(file, ".tga"));
plugin.Dispose();
}
#endif
}
@ -1695,8 +1764,8 @@ namespace MobiusEditor
private void MainForm_Shown(object sender, System.EventArgs e)
{
ClearAllTools();
RefreshAvailableTools();
DisableAllTools();
RefreshUI();
UpdateUndoRedo();
if (filename != null)
this.OpenFile(filename, false);
@ -1709,6 +1778,11 @@ namespace MobiusEditor
{
return;
}
// If loading, abort. Wait for confirmation of abort before continuing the unloading.
if (multiThreader != null)
{
multiThreader.AbortThreadedOperation(5000);
}
// Restore default icons, then dispose custom ones.
// Form dispose should take care of the default ones.
LoadNewIcon(mapToolStripButton, null, null, 0);
@ -1793,13 +1867,14 @@ namespace MobiusEditor
&& (sm.Theaters == null || sm.Theaters.Contains(plugin.Map.Theater))).OrderBy(sm => sm.ID).FirstOrDefault();
OverlayType overlay = plugin.Map.OverlayTypes.Where(ov => (ov.Flag & OverlayTypeFlag.Crate) == OverlayTypeFlag.Crate
&& (ov.Theaters == null || ov.Theaters.Contains(plugin.Map.Theater))).OrderBy(ov => ov.ID).FirstOrDefault();
if (overlay == null) {
if (overlay == null)
{
overlay = plugin.Map.OverlayTypes.Where(ov => (ov.Flag & OverlayTypeFlag.Flag) == OverlayTypeFlag.Flag
&& (ov.Theaters == null || ov.Theaters.Contains(plugin.Map.Theater))).OrderBy(ov => ov.ID).FirstOrDefault();
}
Tile overlayTile = null;
if (overlay != null) Globals.TheTilesetManager.GetTileData(plugin.Map.Theater.Tilesets, overlay.Name, 0, out overlayTile, false, true);
TerrainType terrain = plugin.Map.TerrainTypes.Where(tr => tr.Theaters == null || tr.Theaters.Contains(plugin.Map.Theater)).OrderBy(tr => tr.ID).FirstOrDefault();;
TerrainType terrain = plugin.Map.TerrainTypes.Where(tr => tr.Theaters == null || tr.Theaters.Contains(plugin.Map.Theater)).OrderBy(tr => tr.ID).FirstOrDefault(); ;
InfantryType infantry = plugin.Map.InfantryTypes.FirstOrDefault();
UnitType unit = plugin.Map.UnitTypes.FirstOrDefault();
BuildingType building = plugin.Map.BuildingTypes.Where(bl => bl.Size.Width == 2 && bl.Size.Height == 2

View File

@ -261,7 +261,12 @@ namespace MobiusEditor.RedAlert
public Image MapImage { get; private set; }
IFeedBackHandler feedBackHandler;
private IFeedBackHandler feedBackHandler;
public IFeedBackHandler FeedBackHandler
{
get { return feedBackHandler; }
set { feedBackHandler = value; }
}
bool isDirty;
public bool Dirty
@ -331,9 +336,9 @@ namespace MobiusEditor.RedAlert
UpdateBuildingRules(ini, this.Map);
}
}
public static bool CheckForRAMap(String path, FileType fileType)
public static bool CheckForRAMap(INI contents)
{
return GeneralUtils.CheckForIniInfo(path, fileType, "MapPack", null, null);
return GeneralUtils.CheckForIniInfo(contents, "MapPack", null, null);
}
static GamePlugin()
@ -341,14 +346,13 @@ namespace MobiusEditor.RedAlert
fullTechnoTypes = InfantryTypes.GetTypes().Cast<ITechnoType>().Concat(UnitTypes.GetTypes(false).Cast<ITechnoType>());
}
public GamePlugin(IFeedBackHandler feedBackHandler)
: this(true, feedBackHandler)
public GamePlugin()
: this(true)
{
}
public GamePlugin(bool mapImage, IFeedBackHandler feedBackHandler)
public GamePlugin(bool mapImage)
{
this.feedBackHandler = feedBackHandler;
var playerWaypoints = Enumerable.Range(0, multiStartPoints).Select(i => new Waypoint(string.Format("P{0}", i), Waypoint.GetFlagForMpId(i)));
var generalWaypoints = Enumerable.Range(multiStartPoints, 98 - multiStartPoints).Select(i => new Waypoint(i.ToString()));
var specialWaypoints = new Waypoint[] { new Waypoint("Home", WaypointFlag.Home), new Waypoint("Reinf.", WaypointFlag.Reinforce), new Waypoint("Special", WaypointFlag.Special) };
@ -441,13 +445,14 @@ namespace MobiusEditor.RedAlert
}
}
public IEnumerable<string> Load(string path, FileType fileType, out bool modified)
public IEnumerable<string> Load(string path, FileType fileType)
{
bool modified = false;
try
{
isLoading = true;
var errors = new List<string>();
modified = false;
bool forceSingle = false;
switch (fileType)
{
@ -485,6 +490,10 @@ namespace MobiusEditor.RedAlert
default:
throw new NotSupportedException("Unsupported filetype.");
}
if (modified)
{
this.Dirty = true;
}
return errors;
}
finally

View File

@ -21,24 +21,23 @@ namespace MobiusEditor.SoleSurvivor
public override GameType GameType => GameType.SoleSurvivor;
public override bool IsMegaMap => true;
public GamePlugin(IFeedBackHandler feedBackHandler)
: this(true, feedBackHandler)
public static bool CheckForSSmap(INI iniContents)
{
}
public static bool CheckForSSmap(string path, FileType fileType)
{
return GeneralUtils.CheckForIniInfo(path, fileType, "Crates", null, null);
return GeneralUtils.CheckForIniInfo(iniContents, "Crates", null, null);
}
protected CratesSection cratesSection;
public CratesSection CratesSection => cratesSection;
public GamePlugin(bool mapImage, IFeedBackHandler feedBackHandler)
public GamePlugin()
: this(true)
{
}
public GamePlugin(bool mapImage)
: base()
{
this.isMegaMap = true;
this.feedBackHandler = feedBackHandler;
var crateWaypoints = Enumerable.Range(0, cratePoints).Select(i => new Waypoint(string.Format("CR{0}", i), WaypointFlag.CrateSpawn));
var teamWaypoints = Enumerable.Range(cratePoints, teamStartPoints).Select(i => new Waypoint(string.Format("TM{0}", i - cratePoints), Waypoint.GetFlagForMpId(i - cratePoints)));
var generalWaypoints = Enumerable.Range(cratePoints + teamStartPoints, 25 - cratePoints - teamStartPoints).Select(i => new Waypoint(i.ToString()));
@ -126,9 +125,9 @@ namespace MobiusEditor.SoleSurvivor
}
}
public override IEnumerable<string> Load(string path, FileType fileType, out bool modified)
public override IEnumerable<string> Load(string path, FileType fileType)
{
return Load(path, fileType, true, out modified);
return Load(path, fileType, true);
}
protected override List<string> LoadINI(INI ini, bool forceSoloMission, ref bool modified)

View File

@ -109,6 +109,11 @@ namespace MobiusEditor.TiberianDawn
public Image MapImage { get; protected set; }
protected IFeedBackHandler feedBackHandler;
public IFeedBackHandler FeedBackHandler
{
get { return feedBackHandler; }
set { feedBackHandler = value; }
}
bool isDirty;
public bool Dirty
@ -164,9 +169,9 @@ namespace MobiusEditor.TiberianDawn
}
}
public static bool CheckForMegamap(String path, FileType fileType)
public static bool CheckForMegamap(INI iniContents)
{
return GeneralUtils.CheckForIniInfo(path, fileType, "Map", "Version", "1");
return GeneralUtils.CheckForIniInfo(iniContents, "Map", "Version", "1");
}
static GamePlugin()
@ -174,12 +179,7 @@ namespace MobiusEditor.TiberianDawn
fullTechnoTypes = InfantryTypes.GetTypes().Cast<ITechnoType>().Concat(UnitTypes.GetTypes(false).Cast<ITechnoType>());
}
public GamePlugin(bool megaMap, IFeedBackHandler feedBackHandler)
: this(true, megaMap, feedBackHandler)
{
}
public GamePlugin()
protected GamePlugin()
{
// Readonly, so I'm splitting this off
var movies = new List<string>();
@ -201,11 +201,15 @@ namespace MobiusEditor.TiberianDawn
movieTypes = movies.ToArray();
}
public GamePlugin(bool mapImage, bool megaMap, IFeedBackHandler feedBackHandler)
public GamePlugin(bool megaMap)
: this(true, megaMap)
{
}
public GamePlugin(bool mapImage, bool megaMap)
:this()
{
this.isMegaMap = megaMap;
this.feedBackHandler = feedBackHandler;
var playerWaypoints = Enumerable.Range(0, multiStartPoints).Select(i => new Waypoint(string.Format("P{0}", i), Waypoint.GetFlagForMpId(i)));
var generalWaypoints = Enumerable.Range(multiStartPoints, 25 - multiStartPoints).Select(i => new Waypoint(i.ToString()));
var specialWaypoints = new Waypoint[] { new Waypoint("Flare", WaypointFlag.Flare), new Waypoint("Home", WaypointFlag.Home), new Waypoint("Reinf.", WaypointFlag.Reinforce) };
@ -283,16 +287,16 @@ namespace MobiusEditor.TiberianDawn
UpdateBasePlayerHouse();
}
public virtual IEnumerable<string> Load(string path, FileType fileType, out bool modified)
public virtual IEnumerable<string> Load(string path, FileType fileType)
{
return Load(path, fileType, false, out modified);
return Load(path, fileType, false);
}
protected List<string> Load(string path, FileType fileType, bool forSole, out bool modified)
protected List<string> Load(string path, FileType fileType, bool forSole)
{
var ini = new INI();
var errors = new List<string>();
modified = false;
bool modified = false;
bool forceSingle = false;
switch (fileType)
{
@ -377,6 +381,10 @@ namespace MobiusEditor.TiberianDawn
default:
throw new NotSupportedException("Unsupported filetype.");
}
if (modified)
{
this.Dirty = true;
}
return errors;
}
@ -778,7 +786,6 @@ namespace MobiusEditor.TiberianDawn
}
else if (techno is Terrain terrain)
{
MessageBox.Show("overlap");
errors.Add(string.Format("Terrain '{0}' on cell {1} overlaps terrain '{2}' in cell {3}; skipping.", terrainType.Name, cell, terrain.Type.Name, reportCell));
modified = true;
}
@ -832,6 +839,13 @@ namespace MobiusEditor.TiberianDawn
modified = true;
continue;
}
if (!Map.Metrics.Contains(cell))
{
errors.Add(string.Format("Cell for overlay is not inside the map bounds. Key: '{0}', value: '{1}'; skipping.", Key, Value));
modified = true;
continue;
}
var overlayType = Map.OverlayTypes.Where(t => t.Equals(Value)).FirstOrDefault();
if (overlayType != null)
{

View File

@ -884,7 +884,7 @@ namespace MobiusEditor.Tools
}
templateTypeMapPanel.MapImage = selected.Thumbnail;
var templateTypeMetrics = new CellMetrics(selected.ThumbnailWidth, selected.ThumbnailHeight);
templateTypeNavigationWidget = new NavigationWidget(templateTypeMapPanel, templateTypeMetrics, Globals.OriginalTileSize);
templateTypeNavigationWidget = new NavigationWidget(templateTypeMapPanel, templateTypeMetrics, Globals.OriginalTileSize, false);
templateTypeNavigationWidget.MouseoverSize = Size.Empty;
templateTypeNavigationWidget.Activate();
}
@ -1153,37 +1153,37 @@ namespace MobiusEditor.Tools
var tooltipSize = new Size(textSize.Width + 6, textSize.Height + 6);
Point mouseCell = navigationWidget.MouseCell;
Point tooltipPosition = Control.MousePosition;
PointF zoomedCell = navigationWidget.ZoomedCellSize;
SizeF zoomedCell = navigationWidget.ZoomedCellSize;
// Corrects to nearest border; should match NavigationWidget.ClosestMouseCellBorder
if (showEdge != FacingType.None)
{
if (navigationWidget.ClosestMouseCellBorder.Y > mouseCell.Y)
{
tooltipPosition.Y += (int)((Globals.PixelWidth - navigationWidget.MouseSubPixel.Y) * zoomedCell.Y / Globals.PixelWidth);
tooltipPosition.Y += (int)((Globals.PixelWidth - navigationWidget.MouseSubPixel.Y) * zoomedCell.Height / Globals.PixelWidth);
}
else
{
tooltipPosition.Y -= (int)(navigationWidget.MouseSubPixel.Y * zoomedCell.Y / Globals.PixelWidth);
tooltipPosition.Y -= (int)(navigationWidget.MouseSubPixel.Y * zoomedCell.Height / Globals.PixelWidth);
}
if (navigationWidget.ClosestMouseCellBorder.X > mouseCell.X)
{
tooltipPosition.X += (int)((Globals.PixelWidth - navigationWidget.MouseSubPixel.X) * zoomedCell.X / Globals.PixelWidth);
tooltipPosition.X += (int)((Globals.PixelWidth - navigationWidget.MouseSubPixel.X) * zoomedCell.Width / Globals.PixelWidth);
}
else
{
tooltipPosition.X -= (int)(navigationWidget.MouseSubPixel.X * zoomedCell.X / Globals.PixelWidth);
tooltipPosition.X -= (int)(navigationWidget.MouseSubPixel.X * zoomedCell.Width / Globals.PixelWidth);
}
switch (showEdge)
{
case FacingType.North:
case FacingType.NorthEast:
case FacingType.NorthWest:
tooltipPosition.Y += (int)zoomedCell.Y;
tooltipPosition.Y += (int)zoomedCell.Height;
break;
case FacingType.South:
case FacingType.SouthEast:
case FacingType.SouthWest:
tooltipPosition.Y -= (int)zoomedCell.Y;
tooltipPosition.Y -= (int)zoomedCell.Height;
break;
}
switch (showEdge)
@ -1191,12 +1191,12 @@ namespace MobiusEditor.Tools
case FacingType.SouthWest:
case FacingType.West:
case FacingType.NorthWest:
tooltipPosition.X += (int)zoomedCell.X;
tooltipPosition.X += (int)zoomedCell.Width;
break;
case FacingType.SouthEast:
case FacingType.East:
case FacingType.NorthEast:
tooltipPosition.X -= (int)zoomedCell.X;
tooltipPosition.X -= (int)zoomedCell.Width;
break;
}
switch (showEdge)
@ -1213,13 +1213,13 @@ namespace MobiusEditor.Tools
// Always towards the center, one cell away from the mouse.
Point center = dragBounds.CenterPoint();
if (mouseCell.X < center.X)
tooltipPosition.X += (int)zoomedCell.X;
tooltipPosition.X += (int)zoomedCell.Width;
else
tooltipPosition.X -= (int)zoomedCell.X + tooltipSize.Width;
tooltipPosition.X -= (int)zoomedCell.Width + tooltipSize.Width;
if (mouseCell.Y < center.Y)
tooltipPosition.Y += (int)zoomedCell.Y;
tooltipPosition.Y += (int)zoomedCell.Height;
else
tooltipPosition.Y -= (int)zoomedCell.Y + tooltipSize.Height;
tooltipPosition.Y -= (int)zoomedCell.Height + tooltipSize.Height;
}
switch (showEdge)
{

View File

@ -72,7 +72,7 @@ namespace MobiusEditor.Tools
this.statusLbl = statusLbl;
map = plugin.Map;
map.BasicSection.PropertyChanged += BasicSection_PropertyChanged;
navigationWidget = new NavigationWidget(mapPanel, map.Metrics, Globals.MapTileSize);
navigationWidget = new NavigationWidget(mapPanel, map.Metrics, Globals.MapTileSize, true);
}
protected void Invalidate(bool refreshIndicatorsOnly)

View File

@ -226,6 +226,8 @@ namespace MobiusEditor.Tools
}
else
{
const int pageJump = 1;
const int arrJump = 0;
switch (e.KeyCode)
{
case Keys.Home:
@ -235,16 +237,16 @@ namespace MobiusEditor.Tools
newVal = maxVal;
break;
case Keys.PageDown:
newVal = Math.Min(curVal + 10, maxVal);
newVal = Math.Min(curVal + pageJump, maxVal);
break;
case Keys.PageUp:
newVal = Math.Max(curVal - 10, 0);
newVal = Math.Max(curVal - pageJump, 0);
break;
case Keys.Down:
newVal = Math.Min(curVal + 1, maxVal);
newVal = Math.Min(curVal + arrJump, maxVal);
break;
case Keys.Up:
newVal = Math.Max(curVal - 1, 0);
newVal = Math.Max(curVal - arrJump, 0);
break;
case Keys.Enter:
JumpToWaypoint();

View File

@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
namespace MobiusEditor.Utility
{
@ -34,7 +35,7 @@ namespace MobiusEditor.Utility
public static class GeneralUtils
{
public static bool CheckForIniInfo(String path, FileType fileType, string section, string key, string value)
public static INI GetIniContents(String path, FileType fileType)
{
try
{
@ -52,7 +53,8 @@ namespace MobiusEditor.Utility
case FileType.PGM:
using (var megafile = new Megafile(path))
{
var testIniFile = megafile.Where(p => Path.GetExtension(p).ToLower() == ".ini").FirstOrDefault();
Regex ext = new Regex("^\\.((ini)|(mpr))$");
var testIniFile = megafile.Where(p => ext.IsMatch(Path.GetExtension(p).ToLower())).FirstOrDefault();
if (testIniFile != null)
{
using (var iniReader = new StreamReader(megafile.Open(testIniFile), enc))
@ -65,23 +67,29 @@ namespace MobiusEditor.Utility
}
if (iniContents == null)
{
return false;
return null;
}
INI checkIni = new INI();
checkIni.Parse(iniContents);
INISection iniSection = checkIni.Sections.Extract(section);
if (key == null || value == null)
{
return iniSection != null;
}
return iniSection != null && iniSection.Keys.Contains(key) && iniSection[key].Trim() == value;
return checkIni;
}
catch
{
return false;
return null;
}
}
public static bool CheckForIniInfo(INI iniContents, string section, string key, string value)
{
INISection iniSection = iniContents.Sections.Extract(section);
if (key == null || value == null)
{
return iniSection != null;
}
return iniSection != null && iniSection.Keys.Contains(key) && iniSection[key].Trim() == value;
}
public static String MakeNew4CharName(IEnumerable<string> currentList, string fallback, params string[] reservedNames)
{
string name = string.Empty;

View File

@ -23,15 +23,21 @@ namespace MobiusEditor.Utility
/// <summary>
/// Simple multithreading for heavy operations to not freeze the UI. This just needs a form with a public
/// property to get and set a "busy" state label, and the type that is produced by the heavy operation.
/// The order of operations is: controls are disabled and busy label is set, heavy operation is executed,
/// controls are enabled and busy label is removed, an optional extra function runs to process the returned result.
/// In case an error occurred, the UI is re-enabled as usual, a message box is shown with the stack trace, and the
/// result processing function is not called.
/// </summary>
/// <typeparam name="T">Form to attach the label to.</typeparam>
/// <typeparam name="U">The type produced by the heavy operation. If the operation returns the type default, then it is treated as failed, and a message box is shown.</typeparam>
public class SimpleMultiThreading<T> where T: Form, IHasStatusLabel
{
public String DefaultProcessingLabel { get; set; } = "Processing";
public BorderStyle ProcessingLabelBorder { get; set; } = BorderStyle.FixedSingle;
public delegate void InvokeDelegateEnableControls(Boolean enabled, String processingLabel);
public delegate DialogResult InvokeDelegateMessageBox(String message, MessageBoxButtons buttons, MessageBoxIcon icon);
public delegate void InvokeDelegateResult<U>(U resultObject);
private Thread m_ProcessingThread;
private Thread processingThread;
private T attachForm;
public SimpleMultiThreading(T attachForm)
@ -39,6 +45,15 @@ namespace MobiusEditor.Utility
this.attachForm = attachForm;
}
public void AbortThreadedOperation(int timeout)
{
if (this.processingThread != null && this.processingThread.IsAlive)
{
this.processingThread.Abort();
this.processingThread.Join(timeout);
}
}
/// <summary>
/// Executes a threaded operation while locking the UI.
/// </summary>
@ -47,30 +62,33 @@ namespace MobiusEditor.Utility
/// <paramref name="resultFuncIsInvoked"/>true if the result function is Invoked on the main form.</param>
/// <param name="enableFunction">Function to enable/disable UI controls. This should also include a call to <see cref="CreateBusyLabel"/> to create the busy status label. This function is Invoked on the main form.</param>
/// <param name="operationType">Label to show while the operation is busy. This will be passed on as arg to <paramref name="enableFunction"/>.</param>
/// <typeparam name="U">Type returned by <paramref name="function"/>, and passed on to <paramref name="resultFunction"/>.</typeparam>
public void ExecuteThreaded<U>(Func<U> function, Action<U> resultFunction, bool resultFuncIsInvoked, Action<bool, string> enableFunction, String operationType)
{
if (this.m_ProcessingThread != null && this.m_ProcessingThread.IsAlive)
if (this.processingThread != null && this.processingThread.IsAlive)
return;
//Arguments: func returning SupportedFileType, reset palettes, reset index, reset auto-zoom, process type indication string.
Object[] arrParams = { function, resultFunction, resultFuncIsInvoked, enableFunction, operationType };
this.m_ProcessingThread = new Thread(this.ExecuteThreadedActual<U>);
this.m_ProcessingThread.Start(arrParams);
this.processingThread = new Thread(this.ExecuteThreadedActual<U>);
this.processingThread.Start(arrParams);
}
/// <summary>
/// Executes a threaded operation while locking the UI.
/// "parameters" must be an array of Object containing 4 items:
/// Executes a threaded operation while locking the UI. "parameters" must be an array of Object containing 5 items:
/// a <see cref="Func{TResult}"/> to execute, returning <see cref="U"/>,
/// an <see cref="Action"/> taking a parameter of type <see cref="U"/> to execute after successful processing (optional, can be null),
/// a <see cref="bool"/> indicating whether the result function is Invoked on the main form.
/// an <see cref="Action"/> to enable form controls, taking a parameter of type <see cref="bool"/> (whether to enable or disable controls) and <see cref="string"/> (message to show on disabled UI),
/// a <see cref="string"/> to indicate the process type being executed (eg. "Saving").
/// </summary>
/// <param name="parameters">
/// Array of Object, containing 4 items: a <see cref="Func{TResult}"/> to execute, returning <see cref="U"/>,
/// an <see cref="Action"/> taking a parameter of type <see cref="U"/> to execute after successful processing (optional, can be null),
/// Array of Object, containing 4 items: a <see cref="Func{TResult}"/> to execute, returning an object of type U,
/// an <see cref="Action"/> taking a parameter of type U to execute after successful processing (optional, can be null),
/// a <see cref="bool"/> indicating whether the result function is Invoked on the main form.
/// an <see cref="Action"/> to enable form controls, taking a parameter of type <see cref="bool"/> (whether to enable or disable controls) and <see cref="string"/> (message to show on disabled UI),
/// and a <see cref="string"/> to indicate the process type being executed (eg. "Saving").
/// </param>
/// <typeparam name="U">Type returned by the processing function, and to be pased on to the result handling function.</typeparam>
private void ExecuteThreadedActual<U>(Object parameters)
{
Object[] arrParams = parameters as Object[];
@ -86,9 +104,8 @@ namespace MobiusEditor.Utility
return;
}
bool resActIsInvoked = (bool)arrParams[2];
String operationType = arrParams[4] as String;
String operationType = (arrParams[4] as String ?? String.Empty).Trim();
this.attachForm.Invoke(new InvokeDelegateEnableControls(enableControls), false, operationType);
operationType = String.IsNullOrEmpty(operationType) ? "Operation" : operationType.Trim();
U result = default(U);
try
{
@ -103,12 +120,18 @@ namespace MobiusEditor.Utility
{
String message = operationType + " failed:\n" + ex.Message + "\n" + ex.StackTrace;
this.attachForm.Invoke(new InvokeDelegateMessageBox(this.ShowMessageBox), message, MessageBoxButtons.OK, MessageBoxIcon.Warning);
this.attachForm.Invoke(new InvokeDelegateEnableControls(enableControls), true, null);
try
{
this.attachForm.Invoke(new InvokeDelegateEnableControls(enableControls), true, null);
}
catch (InvalidOperationException) { /* ignore */ }
return;
}
//this.attachForm.Invoke(new InvokeDelegateMessageBox(this.ShowMessageBox), "load done!", MessageBoxButtons.OK, MessageBoxIcon.Information);
try
{
this.attachForm.Invoke(new InvokeDelegateEnableControls(enableControls), true, null);
if (resAct != null && !EqualityComparer<U>.Default.Equals(result, default(U)))
if (resAct != null)
{
if (resActIsInvoked)
{
@ -149,13 +172,13 @@ namespace MobiusEditor.Utility
}
// Create busy status label.
Label busyStatusLabel = new Label();
busyStatusLabel.Text = (String.IsNullOrEmpty(processingLabel) ? "Processing" : processingLabel) + "...";
busyStatusLabel.Text = (String.IsNullOrEmpty(processingLabel) ? (DefaultProcessingLabel ?? String.Empty) : processingLabel) + "...";
busyStatusLabel.TextAlign = ContentAlignment.MiddleCenter;
busyStatusLabel.Font = new Font(busyStatusLabel.Font.FontFamily, 15F, FontStyle.Regular, GraphicsUnit.Pixel, 0);
busyStatusLabel.AutoSize = false;
busyStatusLabel.Size = new Size(300, 100);
busyStatusLabel.Anchor = AnchorStyles.None; // Always floating in the middle, even on resize.
busyStatusLabel.BorderStyle = BorderStyle.FixedSingle;
busyStatusLabel.BorderStyle = ProcessingLabelBorder;
Int32 x = (attachForm.ClientRectangle.Width - 300) / 2;
Int32 y = (attachForm.ClientRectangle.Height - 100) / 2;
busyStatusLabel.Location = new Point(x, y);

View File

@ -78,6 +78,7 @@ namespace MobiusEditor.Widgets
}
private readonly MapPanel mapPanel;
private bool includeNavigation;
public Size CellSize { get; private set; }
private Size? startScrollMouseLocation;
@ -96,26 +97,27 @@ namespace MobiusEditor.Widgets
set => mouseoverSize = !value.IsEmpty ? new Size(value.Width | 1, value.Height | 1) : Size.Empty;
}
public PointF ZoomedCellSize
public SizeF ZoomedCellSize
{
get
{
float mapScale = mapPanel.ClientSize.Width > mapPanel.ClientSize.Height
? mapPanel.ClientSize.Width / (float)mapPanel.CameraBounds.Width
: mapPanel.ClientSize.Height / (float)mapPanel.CameraBounds.Height;
return new PointF(mapScale * mapPanel.MapImage.Width / Metrics.Width, mapScale * mapPanel.MapImage.Height / Metrics.Height);
return new SizeF(mapScale * mapPanel.MapImage.Width / Metrics.Width, mapScale * mapPanel.MapImage.Height / Metrics.Height);
}
}
public event EventHandler<MouseCellChangedEventArgs> MouseCellChanged;
public event EventHandler<MouseCellChangedEventArgs> ClosestMouseCellBorderChanged;
public NavigationWidget(MapPanel mapPanel, CellMetrics metrics, Size cellSize)
public NavigationWidget(MapPanel mapPanel, CellMetrics metrics, Size cellSize, bool includeNavigation)
{
this.mapPanel = mapPanel;
Metrics = metrics;
this.CellSize = cellSize;
this.PenColor = Color.Yellow;
this.includeNavigation = includeNavigation;
}
public void Refresh()
@ -125,7 +127,7 @@ namespace MobiusEditor.Widgets
private bool IsDragging()
{
return (Control.MouseButtons & MouseButtons.Middle) != MouseButtons.None || (GetAsyncKeyState(32) & 0x8000) != 0;
return includeNavigation && ((Control.MouseButtons & MouseButtons.Middle) != MouseButtons.None || (GetAsyncKeyState(32) & 0x8000) != 0);
}
private void DisableDragging()
@ -166,7 +168,35 @@ namespace MobiusEditor.Widgets
private void MapPanel_KeyDown(Object sender, KeyEventArgs e)
{
CheckIfDragging();
System.Media.SystemSounds.Beep.Play();
if (CheckIfDragging() || startScrollMouseLocation.HasValue)
{
return;
}
Point delta = Point.Empty;
switch (e.KeyCode)
{
case Keys.Up:
delta.Y -= 1;
break;
case Keys.Down:
delta.Y += 1;
break;
case Keys.Left:
delta.X -= 1;
break;
case Keys.Right:
delta.X += 1;
break;
default:
return;
}
if (delta != Point.Empty)
{
Point curPoint = mapPanel.AutoScrollPosition;
SizeF zoomedCell = ZoomedCellSize;
mapPanel.AutoScrollPosition = new Point(-curPoint.X + (int)(delta.X * zoomedCell.Width), -curPoint.Y + (int)(delta.Y * zoomedCell.Width));
}
}
private void MapPanel_KeyUp(Object sender, KeyEventArgs e)
@ -247,16 +277,22 @@ namespace MobiusEditor.Widgets
{
this.mapPanel.MouseDown += MapPanel_MouseDown;
this.mapPanel.MouseUp += MapPanel_MouseUp;
(this.mapPanel as Control).KeyDown += this.MapPanel_KeyDown;
(this.mapPanel as Control).KeyUp += this.MapPanel_KeyUp;
if (includeNavigation)
{
(this.mapPanel as Control).KeyDown += this.MapPanel_KeyDown;
(this.mapPanel as Control).KeyUp += this.MapPanel_KeyUp;
}
this.mapPanel.MouseMove += MapPanel_MouseMove;
}
public void Deactivate()
{
this.mapPanel.MouseMove -= MapPanel_MouseMove;
(this.mapPanel as Control).KeyDown -= this.MapPanel_KeyDown;
(this.mapPanel as Control).KeyUp -= this.MapPanel_KeyUp;
if (includeNavigation)
{
(this.mapPanel as Control).KeyDown -= this.MapPanel_KeyDown;
(this.mapPanel as Control).KeyUp -= this.MapPanel_KeyUp;
}
this.mapPanel.MouseUp -= MapPanel_MouseUp;
this.mapPanel.MouseDown -= MapPanel_MouseDown;
DisableDragging();