mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-27 14:12:16 +00:00
fe71e53edc
Program preferences are now saved as soon as the configuration dialog is closed Recent files are now saved as soon as an existing map is loaded
4668 lines
145 KiB
C#
Executable file
4668 lines
145 KiB
C#
Executable file
|
|
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
|
|
|
/*
|
|
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
|
* This program is released under GNU General Public License
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#endregion
|
|
|
|
#region ================== Namespaces
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Forms;
|
|
|
|
using CodeImp.DoomBuilder.Actions;
|
|
using CodeImp.DoomBuilder.Config;
|
|
using CodeImp.DoomBuilder.Controls;
|
|
using CodeImp.DoomBuilder.Data;
|
|
using CodeImp.DoomBuilder.Editing;
|
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using CodeImp.DoomBuilder.IO;
|
|
using CodeImp.DoomBuilder.Map;
|
|
using CodeImp.DoomBuilder.Plugins;
|
|
using CodeImp.DoomBuilder.Properties;
|
|
using CodeImp.DoomBuilder.Rendering;
|
|
using CodeImp.DoomBuilder.VisualModes;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.Windows
|
|
{
|
|
public partial class MainForm : DelayedForm, IMainForm
|
|
{
|
|
#region ================== Constants
|
|
|
|
// Recent files
|
|
private const int MAX_RECENT_FILES_PIXELS = 250;
|
|
|
|
// Status bar
|
|
internal const int WARNING_FLASH_COUNT = 10;
|
|
internal const int WARNING_FLASH_INTERVAL = 100;
|
|
internal const int WARNING_RESET_DELAY = 5000;
|
|
internal const int INFO_RESET_DELAY = 5000;
|
|
internal const int ACTION_FLASH_COUNT = 3;
|
|
internal const int ACTION_FLASH_INTERVAL = 50;
|
|
internal const int ACTION_RESET_DELAY = 5000;
|
|
|
|
internal readonly Image[,] STATUS_IMAGES = new Image[,]
|
|
{
|
|
// Normal versions
|
|
{
|
|
Resources.Status0, Resources.Status1,
|
|
Resources.Status2, Resources.Warning
|
|
},
|
|
|
|
// Flashing versions
|
|
{
|
|
Resources.Status10, Resources.Status11,
|
|
Resources.Status12, Resources.WarningOff
|
|
}
|
|
};
|
|
|
|
#endregion
|
|
|
|
#region ================== Delegates
|
|
|
|
//private delegate void CallUpdateStatusIcon();
|
|
//private delegate void CallImageDataLoaded(ImageData img);
|
|
private delegate void CallBlink(); //mxd
|
|
|
|
#endregion
|
|
|
|
#region ================== mxd. Events
|
|
|
|
public event EventHandler OnEditFormValuesChanged; //mxd
|
|
|
|
#endregion
|
|
|
|
#region ================== Variables
|
|
|
|
// Position/size
|
|
private bool displayresized = true;
|
|
private bool windowactive;
|
|
|
|
// Mouse in display
|
|
private bool mouseinside;
|
|
|
|
// Input
|
|
private bool shift, ctrl, alt;
|
|
private MouseButtons mousebuttons;
|
|
private MouseInput mouseinput;
|
|
private bool mouseexclusive;
|
|
private int mouseexclusivebreaklevel;
|
|
|
|
// Last info on panels
|
|
private object lastinfoobject;
|
|
|
|
// Recent files
|
|
private ToolStripMenuItem[] recentitems;
|
|
|
|
// View modes
|
|
private ToolStripButton[] viewmodesbuttons;
|
|
private ToolStripMenuItem[] viewmodesitems;
|
|
|
|
//mxd. Geometry merge modes
|
|
private ToolStripButton[] geomergemodesbuttons;
|
|
private ToolStripMenuItem[] geomergemodesitems;
|
|
|
|
// Edit modes
|
|
private List<ToolStripItem> editmodeitems;
|
|
|
|
// Toolbar
|
|
private List<PluginToolbarButton> pluginbuttons;
|
|
private EventHandler buttonvisiblechangedhandler;
|
|
private bool preventupdateseperators;
|
|
private bool updatingfilters;
|
|
private bool toolbarContextMenuShiftPressed; //mxd
|
|
|
|
// Statusbar
|
|
private StatusInfo status;
|
|
private int statusflashcount;
|
|
private bool statusflashicon;
|
|
|
|
// Properties
|
|
private IntPtr windowptr;
|
|
|
|
// Processing
|
|
private int processingcount;
|
|
private long lastupdatetime;
|
|
|
|
// Updating
|
|
private int lockupdatecount;
|
|
private bool mapchanged; //mxd
|
|
|
|
//mxd. Hints
|
|
private Docker hintsDocker;
|
|
private HintsPanel hintsPanel;
|
|
|
|
//mxd
|
|
private System.Timers.Timer blinkTimer;
|
|
private bool editformopen;
|
|
|
|
//mxd. Misc drawing
|
|
private Graphics graphics;
|
|
|
|
#endregion
|
|
|
|
#region ================== Properties
|
|
|
|
public bool ShiftState { get { return shift; } }
|
|
public bool CtrlState { get { return ctrl; } }
|
|
public bool AltState { get { return alt; } }
|
|
new public MouseButtons MouseButtons { get { return mousebuttons; } }
|
|
public bool MouseInDisplay { get { return mouseinside; } }
|
|
public RenderTargetControl Display { get { return display; } }
|
|
public bool SnapToGrid { get { return buttonsnaptogrid.Checked; } }
|
|
public bool AutoMerge { get { return buttonautomerge.Checked; } }
|
|
public bool MouseExclusive { get { return mouseexclusive; } }
|
|
new public IntPtr Handle { get { return windowptr; } }
|
|
public bool IsInfoPanelExpanded { get { return (panelinfo.Height == heightpanel1.Height); } }
|
|
public string ActiveDockerTabName { get { return dockerspanel.IsCollpased ? "None" : dockerspanel.SelectedTabName; } }
|
|
public bool IsActiveWindow { get { return windowactive; } }
|
|
public StatusInfo Status { get { return status; } }
|
|
public static Size ScaledIconSize = new Size(16, 16); //mxd
|
|
public static SizeF DPIScaler = new SizeF(1.0f, 1.0f); //mxd
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
// Constructor
|
|
internal MainForm()
|
|
{
|
|
// Fetch pointer
|
|
windowptr = base.Handle;
|
|
|
|
//mxd. Graphics
|
|
graphics = Graphics.FromHwndInternal(windowptr);
|
|
|
|
//mxd. Set DPI-aware icon size
|
|
DPIScaler = new SizeF(graphics.DpiX / 96, graphics.DpiY / 96);
|
|
|
|
if(DPIScaler.Width != 1.0f || DPIScaler.Height != 1.0f)
|
|
{
|
|
ScaledIconSize.Width = (int)Math.Round(ScaledIconSize.Width * DPIScaler.Width);
|
|
ScaledIconSize.Height = (int)Math.Round(ScaledIconSize.Height * DPIScaler.Height);
|
|
}
|
|
|
|
// Setup controls
|
|
InitializeComponent();
|
|
|
|
//mxd. Resize status labels
|
|
if(DPIScaler.Width != 1.0f)
|
|
{
|
|
gridlabel.Width = (int)Math.Round(gridlabel.Width * DPIScaler.Width);
|
|
zoomlabel.Width = (int)Math.Round(zoomlabel.Width * DPIScaler.Width);
|
|
xposlabel.Width = (int)Math.Round(xposlabel.Width * DPIScaler.Width);
|
|
yposlabel.Width = (int)Math.Round(yposlabel.Width * DPIScaler.Width);
|
|
warnsLabel.Width = (int)Math.Round(warnsLabel.Width * DPIScaler.Width);
|
|
}
|
|
|
|
pluginbuttons = new List<PluginToolbarButton>();
|
|
editmodeitems = new List<ToolStripItem>();
|
|
labelcollapsedinfo.Text = "";
|
|
display.Dock = DockStyle.Fill;
|
|
|
|
// Make array for view modes
|
|
viewmodesbuttons = new ToolStripButton[Renderer2D.NUM_VIEW_MODES];
|
|
viewmodesbuttons[(int)ViewMode.Normal] = buttonviewnormal;
|
|
viewmodesbuttons[(int)ViewMode.Brightness] = buttonviewbrightness;
|
|
viewmodesbuttons[(int)ViewMode.FloorTextures] = buttonviewfloors;
|
|
viewmodesbuttons[(int)ViewMode.CeilingTextures] = buttonviewceilings;
|
|
viewmodesitems = new ToolStripMenuItem[Renderer2D.NUM_VIEW_MODES];
|
|
viewmodesitems[(int)ViewMode.Normal] = itemviewnormal;
|
|
viewmodesitems[(int)ViewMode.Brightness] = itemviewbrightness;
|
|
viewmodesitems[(int)ViewMode.FloorTextures] = itemviewfloors;
|
|
viewmodesitems[(int)ViewMode.CeilingTextures] = itemviewceilings;
|
|
|
|
//mxd. Make arrays for geometry merge modes
|
|
int numgeomodes = Enum.GetValues(typeof(MergeGeometryMode)).Length;
|
|
geomergemodesbuttons = new ToolStripButton[numgeomodes];
|
|
geomergemodesbuttons[(int)MergeGeometryMode.CLASSIC] = buttonmergegeoclassic;
|
|
geomergemodesbuttons[(int)MergeGeometryMode.MERGE] = buttonmergegeo;
|
|
geomergemodesbuttons[(int)MergeGeometryMode.REPLACE] = buttonplacegeo;
|
|
geomergemodesitems = new ToolStripMenuItem[numgeomodes];
|
|
geomergemodesitems[(int)MergeGeometryMode.CLASSIC] = itemmergegeoclassic;
|
|
geomergemodesitems[(int)MergeGeometryMode.MERGE] = itemmergegeo;
|
|
geomergemodesitems[(int)MergeGeometryMode.REPLACE] = itemreplacegeo;
|
|
|
|
// Visual Studio IDE doesn't let me set these in the designer :(
|
|
buttonzoom.Font = menufile.Font;
|
|
buttonzoom.DropDownDirection = ToolStripDropDownDirection.AboveLeft;
|
|
buttongrid.Font = menufile.Font;
|
|
buttongrid.DropDownDirection = ToolStripDropDownDirection.AboveLeft;
|
|
|
|
// Event handlers
|
|
buttonvisiblechangedhandler = ToolbarButtonVisibleChanged;
|
|
//mxd
|
|
display.OnKeyReleased += display_OnKeyReleased;
|
|
toolbarContextMenu.KeyDown += toolbarContextMenu_KeyDown;
|
|
toolbarContextMenu.KeyUp += toolbarContextMenu_KeyUp;
|
|
linedefcolorpresets.DropDown.MouseLeave += linedefcolorpresets_MouseLeave;
|
|
this.MouseCaptureChanged += MainForm_MouseCaptureChanged;
|
|
|
|
// Apply shortcut keys
|
|
ApplyShortcutKeys();
|
|
|
|
// Make recent items list
|
|
CreateRecentFiles();
|
|
|
|
// Show splash
|
|
ShowSplashDisplay();
|
|
|
|
//mxd
|
|
blinkTimer = new System.Timers.Timer {Interval = 500};
|
|
blinkTimer.Elapsed += blinkTimer_Elapsed;
|
|
|
|
//mxd. Debug Console
|
|
#if DEBUG
|
|
modename.Visible = false;
|
|
#else
|
|
console.Visible = false;
|
|
#endif
|
|
|
|
//mxd. Hints
|
|
hintsPanel = new HintsPanel();
|
|
hintsDocker = new Docker("hints", "Help", hintsPanel);
|
|
|
|
KeyPreview = true;
|
|
PreviewKeyDown += new PreviewKeyDownEventHandler(MainForm_PreviewKeyDown);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== General
|
|
|
|
// Editing mode changed!
|
|
internal void EditModeChanged()
|
|
{
|
|
// Check appropriate button on interface
|
|
// And show the mode name
|
|
if(General.Editing.Mode != null)
|
|
{
|
|
General.MainWindow.CheckEditModeButton(General.Editing.Mode.EditModeButtonName);
|
|
General.MainWindow.DisplayModeName(General.Editing.Mode.Attributes.DisplayName + (General.Editing.Mode.Attributes.IsDeprecated ? " (deprecated)" : ""));
|
|
}
|
|
else
|
|
{
|
|
General.MainWindow.CheckEditModeButton("");
|
|
General.MainWindow.DisplayModeName("");
|
|
}
|
|
|
|
// View mode only matters in classic editing modes
|
|
bool isclassicmode = (General.Editing.Mode is ClassicMode);
|
|
for(int i = 0; i < Renderer2D.NUM_VIEW_MODES; i++)
|
|
{
|
|
viewmodesitems[i].Enabled = isclassicmode;
|
|
viewmodesbuttons[i].Enabled = isclassicmode;
|
|
}
|
|
|
|
//mxd. Merge geometry mode only matters in classic editing modes
|
|
for(int i = 0; i < geomergemodesbuttons.Length; i++)
|
|
{
|
|
geomergemodesbuttons[i].Enabled = isclassicmode;
|
|
geomergemodesitems[i].Enabled = isclassicmode;
|
|
}
|
|
|
|
UpdateEditMenu();
|
|
UpdatePrefabsMenu();
|
|
}
|
|
|
|
// This makes a beep sound
|
|
public void MessageBeep(MessageBeepType type)
|
|
{
|
|
General.MessageBeep(type);
|
|
}
|
|
|
|
// This sets up the interface
|
|
internal void SetupInterface()
|
|
{
|
|
// Setup docker
|
|
if(General.Settings.DockersPosition != 2 && General.Map != null)
|
|
{
|
|
LockUpdate();
|
|
dockerspanel.Visible = true;
|
|
dockersspace.Visible = true;
|
|
|
|
// We can't place the docker easily when collapsed
|
|
dockerspanel.Expand();
|
|
|
|
// Setup docker width
|
|
if(General.Settings.DockersWidth < dockerspanel.GetCollapsedWidth())
|
|
General.Settings.DockersWidth = dockerspanel.GetCollapsedWidth();
|
|
|
|
// Determine fixed space required
|
|
if(General.Settings.CollapseDockers)
|
|
dockersspace.Width = dockerspanel.GetCollapsedWidth();
|
|
else
|
|
dockersspace.Width = General.Settings.DockersWidth;
|
|
|
|
// Setup docker
|
|
int targetindex = this.Controls.IndexOf(display) + 1; //mxd
|
|
if(General.Settings.DockersPosition == 0)
|
|
{
|
|
modestoolbar.Dock = DockStyle.Right; //mxd
|
|
dockersspace.Dock = DockStyle.Left;
|
|
AdjustDockersSpace(targetindex); //mxd
|
|
dockerspanel.Setup(false);
|
|
dockerspanel.Location = dockersspace.Location;
|
|
dockerspanel.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Bottom;
|
|
}
|
|
else
|
|
{
|
|
modestoolbar.Dock = DockStyle.Left; //mxd
|
|
dockersspace.Dock = DockStyle.Right;
|
|
AdjustDockersSpace(targetindex); //mxd
|
|
dockerspanel.Setup(true);
|
|
dockerspanel.Location = new Point(dockersspace.Right - General.Settings.DockersWidth, dockersspace.Top);
|
|
dockerspanel.Anchor = AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
|
|
}
|
|
|
|
dockerspanel.Width = General.Settings.DockersWidth;
|
|
dockerspanel.Height = dockersspace.Height;
|
|
dockerspanel.BringToFront();
|
|
|
|
if(General.Settings.CollapseDockers) dockerspanel.Collapse();
|
|
|
|
UnlockUpdate();
|
|
}
|
|
else
|
|
{
|
|
dockerspanel.Visible = false;
|
|
dockersspace.Visible = false;
|
|
modestoolbar.Dock = DockStyle.Left; //mxd
|
|
}
|
|
}
|
|
|
|
//mxd. dockersspace display index gets messed up while re-docking. This fixes it...
|
|
private void AdjustDockersSpace(int targetindex)
|
|
{
|
|
while(this.Controls.IndexOf(dockersspace) != targetindex)
|
|
{
|
|
this.Controls.SetChildIndex(dockersspace, targetindex);
|
|
}
|
|
}
|
|
|
|
// This updates all menus for the current status
|
|
internal void UpdateInterface()
|
|
{
|
|
//mxd. Update title
|
|
UpdateTitle();
|
|
|
|
// Update the status bar
|
|
UpdateStatusbar();
|
|
|
|
// Update menus and toolbar icons
|
|
UpdateFileMenu();
|
|
UpdateEditMenu();
|
|
UpdateViewMenu();
|
|
UpdateModeMenu();
|
|
UpdatePrefabsMenu();
|
|
UpdateToolsMenu();
|
|
UpdateToolbar();
|
|
UpdateSkills();
|
|
UpdateHelpMenu();
|
|
}
|
|
|
|
//mxd
|
|
private void UpdateTitle()
|
|
{
|
|
string programname = this.Text = Application.ProductName + " R" + General.ThisAssembly.GetName().Version.Revision;
|
|
if (Environment.Is64BitProcess)
|
|
programname += " (64-bit)";
|
|
else programname += " (32-bit)";
|
|
|
|
// Map opened?
|
|
if (General.Map != null)
|
|
{
|
|
// Get nice name
|
|
string maptitle = (!string.IsNullOrEmpty(General.Map.Data.MapInfo.Title) ? ": " + General.Map.Data.MapInfo.Title : "");
|
|
|
|
// Show map name and filename in caption
|
|
this.Text = (mapchanged ? "\u25CF " : "") + General.Map.FileTitle + " (" + General.Map.Options.CurrentName + maptitle + ") - " + programname;
|
|
}
|
|
else
|
|
{
|
|
// Show normal caption
|
|
this.Text = programname;
|
|
}
|
|
}
|
|
|
|
// Generic event that invokes the tagged action
|
|
public void InvokeTaggedAction(object sender, EventArgs e)
|
|
{
|
|
this.Update();
|
|
|
|
if(sender is ToolStripItem)
|
|
General.Actions.InvokeAction(((ToolStripItem)sender).Tag.ToString());
|
|
else if(sender is Control)
|
|
General.Actions.InvokeAction(((Control)sender).Tag.ToString());
|
|
else
|
|
General.Fail("InvokeTaggedAction used on an unexpected control.");
|
|
|
|
this.Update();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Window
|
|
|
|
// This locks the window for updating
|
|
internal void LockUpdate()
|
|
{
|
|
lockupdatecount++;
|
|
if(lockupdatecount == 1) General.LockWindowUpdate(this.Handle);
|
|
}
|
|
|
|
// This unlocks for updating
|
|
internal void UnlockUpdate()
|
|
{
|
|
lockupdatecount--;
|
|
if(lockupdatecount == 0) General.LockWindowUpdate(IntPtr.Zero);
|
|
if(lockupdatecount < 0) lockupdatecount = 0;
|
|
}
|
|
|
|
// This unlocks for updating
|
|
/*internal void ForceUnlockUpdate()
|
|
{
|
|
if(lockupdatecount > 0) General.LockWindowUpdate(IntPtr.Zero);
|
|
lockupdatecount = 0;
|
|
}*/
|
|
|
|
//mxd
|
|
internal void UpdateMapChangedStatus()
|
|
{
|
|
if(General.Map == null || General.Map.IsChanged == mapchanged) return;
|
|
mapchanged = General.Map.IsChanged;
|
|
UpdateTitle();
|
|
}
|
|
|
|
// This sets the focus on the display for correct key input
|
|
public bool FocusDisplay()
|
|
{
|
|
return display.Focus();
|
|
}
|
|
|
|
// Window is first shown
|
|
private void MainForm_Shown(object sender, EventArgs e)
|
|
{
|
|
// Perform auto map loading action when the window is not delayed
|
|
if(!General.DelayMainWindow) PerformAutoMapLoading();
|
|
}
|
|
|
|
// Auto map loading that must be done when the window is first shown after loading
|
|
// but also before the window is shown when the -delaywindow parameter is given
|
|
internal void PerformAutoMapLoading()
|
|
{
|
|
// Check if the command line arguments tell us to load something
|
|
if(General.AutoLoadFile != null)
|
|
{
|
|
bool showdialog = false;
|
|
MapOptions options = new MapOptions();
|
|
|
|
// Any of the options already given?
|
|
if(General.AutoLoadMap != null)
|
|
{
|
|
Configuration mapsettings;
|
|
|
|
// Try to find existing options in the settings file
|
|
string dbsfile = General.AutoLoadFile.Substring(0, General.AutoLoadFile.Length - 4) + ".dbs";
|
|
if(File.Exists(dbsfile))
|
|
try { mapsettings = new Configuration(dbsfile, true); }
|
|
catch(Exception) { mapsettings = new Configuration(true); }
|
|
else
|
|
mapsettings = new Configuration(true);
|
|
|
|
//mxd. Get proper configuration file
|
|
bool longtexturenamessupported = false;
|
|
string configfile = General.AutoLoadConfig;
|
|
if(string.IsNullOrEmpty(configfile)) configfile = mapsettings.ReadSetting("gameconfig", "");
|
|
if(configfile.Trim().Length == 0)
|
|
{
|
|
showdialog = true;
|
|
}
|
|
else
|
|
{
|
|
// Get if long texture names are supported from the game configuration
|
|
ConfigurationInfo configinfo = General.GetConfigurationInfo(configfile);
|
|
longtexturenamessupported = configinfo.Configuration.ReadSetting("longtexturenames", false);
|
|
}
|
|
|
|
// Set map name and other options
|
|
options = new MapOptions(mapsettings, General.AutoLoadMap, longtexturenamessupported);
|
|
|
|
// Set resource data locations
|
|
options.CopyResources(General.AutoLoadResources);
|
|
|
|
// Set strict patches
|
|
options.StrictPatches = General.AutoLoadStrictPatches;
|
|
|
|
// Set configuration file (constructor already does this, but we want this info from the cmd args if possible)
|
|
options.ConfigFile = configfile;
|
|
}
|
|
else
|
|
{
|
|
// No options given
|
|
showdialog = true;
|
|
}
|
|
|
|
// Show open map dialog?
|
|
if(showdialog)
|
|
{
|
|
// Show open dialog
|
|
General.OpenMapFile(General.AutoLoadFile, null);
|
|
}
|
|
else
|
|
{
|
|
// Open with options
|
|
General.OpenMapFileWithOptions(General.AutoLoadFile, options);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Window is loaded
|
|
private void MainForm_Load(object sender, EventArgs e)
|
|
{
|
|
//mxd. Enable drag and drop
|
|
this.AllowDrop = true;
|
|
this.DragEnter += OnDragEnter;
|
|
this.DragDrop += OnDragDrop;
|
|
|
|
// Info panel state?
|
|
bool expandedpanel = General.Settings.ReadSetting("windows." + configname + ".expandedinfopanel", true);
|
|
if(expandedpanel != IsInfoPanelExpanded) ToggleInfoPanel();
|
|
}
|
|
|
|
// Window receives focus
|
|
private void MainForm_Activated(object sender, EventArgs e)
|
|
{
|
|
windowactive = true;
|
|
|
|
//UpdateInterface();
|
|
ResumeExclusiveMouseInput();
|
|
ReleaseAllKeys();
|
|
FocusDisplay();
|
|
}
|
|
|
|
// Window loses focus
|
|
private void MainForm_Deactivate(object sender, EventArgs e)
|
|
{
|
|
windowactive = false;
|
|
|
|
BreakExclusiveMouseInput();
|
|
ReleaseAllKeys();
|
|
}
|
|
|
|
//mxd. Looks like in some cases StartMouseExclusive is called before app aquires the mouse
|
|
// which results in setting Cursor.Clip not taking effect.
|
|
private void MainForm_MouseCaptureChanged(object sender, EventArgs e)
|
|
{
|
|
if(mouseexclusive && windowactive && mouseinside && Cursor.Clip != display.RectangleToScreen(display.ClientRectangle))
|
|
Cursor.Clip = display.RectangleToScreen(display.ClientRectangle);
|
|
}
|
|
|
|
// Window is being closed
|
|
protected override void OnFormClosing(FormClosingEventArgs e)
|
|
{
|
|
base.OnFormClosing(e);
|
|
if(e.CloseReason == CloseReason.ApplicationExitCall) return;
|
|
|
|
// Close the map
|
|
if(General.CloseMap())
|
|
{
|
|
General.WriteLogLine("Closing main interface window...");
|
|
|
|
// Stop timers
|
|
statusflasher.Stop();
|
|
statusresetter.Stop();
|
|
blinkTimer.Stop(); //mxd
|
|
|
|
// Stop exclusive mode, if any is active
|
|
StopExclusiveMouseInput();
|
|
StopProcessing();
|
|
|
|
// Unbind methods
|
|
General.Actions.UnbindMethods(this);
|
|
|
|
// Determine window state to save
|
|
General.Settings.WriteSetting("windows." + configname + ".expandedinfopanel", IsInfoPanelExpanded);
|
|
|
|
// Save recent files
|
|
SaveRecentFiles();
|
|
|
|
// Terminate the program
|
|
General.Terminate(true);
|
|
}
|
|
else
|
|
{
|
|
// Cancel the close
|
|
e.Cancel = true;
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
private void OnDragEnter(object sender, DragEventArgs e)
|
|
{
|
|
if(e.Data.GetDataPresent(DataFormats.FileDrop))
|
|
{
|
|
e.Effect = DragDropEffects.Copy;
|
|
}
|
|
else
|
|
{
|
|
e.Effect = DragDropEffects.None;
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
private void OnDragDrop(object sender, DragEventArgs e)
|
|
{
|
|
if(e.Data.GetDataPresent(DataFormats.FileDrop))
|
|
{
|
|
string[] filepaths = (string[])e.Data.GetData(DataFormats.FileDrop);
|
|
if(filepaths.Length != 1)
|
|
{
|
|
General.Interface.DisplayStatus(StatusType.Warning, "Cannot open multiple files at once!");
|
|
return;
|
|
}
|
|
|
|
if(!File.Exists(filepaths[0]))
|
|
{
|
|
General.Interface.DisplayStatus(StatusType.Warning, "Cannot open \"" + filepaths[0] + "\": file does not exist!");
|
|
return;
|
|
}
|
|
|
|
string ext = Path.GetExtension(filepaths[0]);
|
|
if(string.IsNullOrEmpty(ext) || ext.ToLower() != ".wad")
|
|
{
|
|
General.Interface.DisplayStatus(StatusType.Warning, "Cannot open \"" + filepaths[0] + "\": only WAD files can be loaded this way!");
|
|
return;
|
|
}
|
|
|
|
// If we call General.OpenMapFile here, it will lock the source window in the waiting state untill OpenMapOptionsForm is closed.
|
|
Timer t = new Timer { Tag = filepaths[0], Interval = 10 };
|
|
t.Tick += OnDragDropTimerTick;
|
|
t.Start();
|
|
}
|
|
}
|
|
|
|
private void OnDragDropTimerTick(object sender, EventArgs e)
|
|
{
|
|
Timer t = sender as Timer;
|
|
if(t != null)
|
|
{
|
|
t.Stop();
|
|
string targetwad = t.Tag.ToString();
|
|
this.Update(); // Update main window
|
|
General.OpenMapFile(targetwad, null);
|
|
UpdateGZDoomPanel();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Statusbar
|
|
|
|
// This updates the status bar
|
|
private void UpdateStatusbar()
|
|
{
|
|
// Map open?
|
|
if(General.Map != null)
|
|
{
|
|
// Enable items
|
|
xposlabel.Enabled = true;
|
|
yposlabel.Enabled = true;
|
|
poscommalabel.Enabled = true;
|
|
zoomlabel.Enabled = true;
|
|
buttonzoom.Enabled = true;
|
|
gridlabel.Enabled = true;
|
|
itemgrid05.Visible = General.Map.UDMF; //mxd
|
|
itemgrid025.Visible = General.Map.UDMF; //mxd
|
|
itemgrid0125.Visible = General.Map.UDMF; //mxd
|
|
buttongrid.Enabled = true;
|
|
configlabel.Text = General.Map.Config.Name;
|
|
|
|
//mxd. Raise grid size to 1 if it was lower and the map isn't in UDMF
|
|
if(!General.Map.UDMF && General.Map.Grid.GridSizeF < GridSetup.MINIMUM_GRID_SIZE)
|
|
General.Map.Grid.SetGridSize(GridSetup.MINIMUM_GRID_SIZE);
|
|
}
|
|
else
|
|
{
|
|
// Disable items
|
|
xposlabel.Text = "--";
|
|
yposlabel.Text = "--";
|
|
xposlabel.Enabled = false;
|
|
yposlabel.Enabled = false;
|
|
poscommalabel.Enabled = false;
|
|
zoomlabel.Enabled = false;
|
|
buttonzoom.Enabled = false;
|
|
gridlabel.Enabled = false;
|
|
buttongrid.Enabled = false;
|
|
configlabel.Text = "";
|
|
}
|
|
|
|
UpdateStatusIcon();
|
|
}
|
|
|
|
// This flashes the status icon
|
|
private void statusflasher_Tick(object sender, EventArgs e)
|
|
{
|
|
statusflashicon = !statusflashicon;
|
|
UpdateStatusIcon();
|
|
statusflashcount--;
|
|
if(statusflashcount == 0) statusflasher.Stop();
|
|
}
|
|
|
|
// This resets the status to ready
|
|
private void statusresetter_Tick(object sender, EventArgs e)
|
|
{
|
|
DisplayReady();
|
|
}
|
|
|
|
// This changes status text
|
|
public void DisplayStatus(StatusType type, string message) { DisplayStatus(new StatusInfo(type, message)); }
|
|
public void DisplayStatus(StatusInfo newstatus)
|
|
{
|
|
// Stop timers
|
|
if(!newstatus.displayed)
|
|
{
|
|
statusresetter.Stop();
|
|
statusflasher.Stop();
|
|
statusflashicon = false;
|
|
}
|
|
|
|
// Determine what to do specifically for this status type
|
|
switch(newstatus.type)
|
|
{
|
|
// Shows information without flashing the icon.
|
|
case StatusType.Ready: //mxd
|
|
case StatusType.Selection: //mxd
|
|
case StatusType.Info:
|
|
if(!newstatus.displayed)
|
|
{
|
|
statusresetter.Interval = INFO_RESET_DELAY;
|
|
statusresetter.Start();
|
|
}
|
|
break;
|
|
|
|
// Shows action information and flashes up the status icon once.
|
|
case StatusType.Action:
|
|
if(!newstatus.displayed)
|
|
{
|
|
statusflashicon = true;
|
|
statusflasher.Interval = ACTION_FLASH_INTERVAL;
|
|
statusflashcount = ACTION_FLASH_COUNT;
|
|
statusflasher.Start();
|
|
statusresetter.Interval = ACTION_RESET_DELAY;
|
|
statusresetter.Start();
|
|
}
|
|
break;
|
|
|
|
// Shows a warning, makes a warning sound and flashes a warning icon.
|
|
case StatusType.Warning:
|
|
if(!newstatus.displayed)
|
|
{
|
|
MessageBeep(MessageBeepType.Warning);
|
|
statusflasher.Interval = WARNING_FLASH_INTERVAL;
|
|
statusflashcount = WARNING_FLASH_COUNT;
|
|
statusflasher.Start();
|
|
statusresetter.Interval = WARNING_RESET_DELAY;
|
|
statusresetter.Start();
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Update status description
|
|
status = newstatus;
|
|
status.displayed = true;
|
|
statuslabel.Text = status.ToString(); //mxd. message -> ToString()
|
|
|
|
// Update icon as well
|
|
UpdateStatusIcon();
|
|
|
|
// Refresh
|
|
statusbar.Invalidate();
|
|
//this.Update(); // ano - this is unneeded afaict and slow
|
|
}
|
|
|
|
// This changes status text to Ready
|
|
public void DisplayReady()
|
|
{
|
|
DisplayStatus(StatusType.Ready, null);
|
|
}
|
|
|
|
// This updates the status icon
|
|
private void UpdateStatusIcon()
|
|
{
|
|
int statusicon = 0;
|
|
int statusflashindex = statusflashicon ? 1 : 0;
|
|
|
|
// Loading icon?
|
|
if((General.Map != null) && (General.Map.Data != null) && General.Map.Data.IsLoading)
|
|
statusicon = 1;
|
|
|
|
// Status type
|
|
switch(status.type)
|
|
{
|
|
case StatusType.Ready:
|
|
case StatusType.Info:
|
|
case StatusType.Action:
|
|
case StatusType.Selection: //mxd
|
|
statuslabel.Image = STATUS_IMAGES[statusflashindex, statusicon];
|
|
break;
|
|
|
|
case StatusType.Busy:
|
|
statuslabel.Image = STATUS_IMAGES[statusflashindex, 2];
|
|
break;
|
|
|
|
case StatusType.Warning:
|
|
statuslabel.Image = STATUS_IMAGES[statusflashindex, 3];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// This changes coordinates display
|
|
public void UpdateCoordinates(Vector2D coords){ UpdateCoordinates(coords, false); } //mxd
|
|
public void UpdateCoordinates(Vector2D coords, bool snaptogrid)
|
|
{
|
|
//mxd
|
|
if(snaptogrid) coords = General.Map.Grid.SnappedToGrid(coords);
|
|
|
|
// X position
|
|
xposlabel.Text = (double.IsNaN(coords.x) ? "--" : coords.x.ToString("####0"));
|
|
|
|
// Y position
|
|
yposlabel.Text = (double.IsNaN(coords.y) ? "--" : coords.y.ToString("####0"));
|
|
}
|
|
|
|
// This changes zoom display
|
|
internal void UpdateZoom(float scale)
|
|
{
|
|
// Update scale label
|
|
zoomlabel.Text = (float.IsNaN(scale) ? "--" : (scale * 100).ToString("##0") + "%");
|
|
}
|
|
|
|
// Zoom to a specified level
|
|
private void itemzoomto_Click(object sender, EventArgs e)
|
|
{
|
|
// In classic mode?
|
|
if(General.Map != null && General.Editing.Mode is ClassicMode)
|
|
{
|
|
// Requested from menu?
|
|
ToolStripMenuItem item = sender as ToolStripMenuItem;
|
|
if(item != null)
|
|
{
|
|
// Get integral zoom level
|
|
int zoom = int.Parse(item.Tag.ToString(), CultureInfo.InvariantCulture);
|
|
|
|
// Zoom now
|
|
((ClassicMode)General.Editing.Mode).SetZoom(zoom / 100f);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Zoom to fit in screen
|
|
private void itemzoomfittoscreen_Click(object sender, EventArgs e)
|
|
{
|
|
// In classic mode?
|
|
if(General.Map != null && General.Editing.Mode is ClassicMode)
|
|
((ClassicMode)General.Editing.Mode).CenterInScreen();
|
|
}
|
|
|
|
// This changes grid display
|
|
internal void UpdateGrid(double gridsize)
|
|
{
|
|
// Update grid label
|
|
gridlabel.Text = (gridsize == 0 ? "--" : gridsize + " mp");
|
|
}
|
|
|
|
// Set grid to a specified size
|
|
private void itemgridsize_Click(object sender, EventArgs e)
|
|
{
|
|
if(General.Map == null) return;
|
|
|
|
// In classic mode?
|
|
if(General.Editing.Mode is ClassicMode)
|
|
{
|
|
// Requested from menu?
|
|
ToolStripMenuItem item = sender as ToolStripMenuItem;
|
|
if(item != null)
|
|
{
|
|
//mxd. Get decimal zoom level
|
|
float size = float.Parse(item.Tag.ToString(), CultureInfo.InvariantCulture);
|
|
|
|
//mxd. Disable automatic grid resizing
|
|
DisableDynamicGridResize();
|
|
|
|
// Change grid size
|
|
General.Map.Grid.SetGridSize(size);
|
|
|
|
// Redraw display
|
|
RedrawDisplay();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Show grid setup
|
|
private void itemgridcustom_Click(object sender, EventArgs e)
|
|
{
|
|
if(General.Map != null) GridSetup.ShowGridSetup();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Display
|
|
|
|
// This shows the splash screen on display
|
|
internal void ShowSplashDisplay()
|
|
{
|
|
// Change display to show splash logo
|
|
display.SetSplashLogoDisplay();
|
|
display.Cursor = Cursors.Default;
|
|
this.Update();
|
|
}
|
|
|
|
// This clears the display
|
|
internal void ClearDisplay()
|
|
{
|
|
// Clear the display
|
|
display.SetManualRendering();
|
|
this.Update();
|
|
}
|
|
|
|
// This sets the display cursor
|
|
public void SetCursor(Cursor cursor)
|
|
{
|
|
// Only when a map is open
|
|
if(General.Map != null) display.Cursor = cursor;
|
|
}
|
|
|
|
// This redraws the display on the next paint event
|
|
public void RedrawDisplay()
|
|
{
|
|
if((General.Map != null) && (General.Editing.Mode != null))
|
|
{
|
|
General.Plugins.OnEditRedrawDisplayBegin();
|
|
General.Editing.Mode.OnRedrawDisplay();
|
|
General.Plugins.OnEditRedrawDisplayEnd();
|
|
statistics.UpdateStatistics(); //mxd
|
|
}
|
|
else
|
|
{
|
|
display.Invalidate();
|
|
}
|
|
}
|
|
|
|
// This event is called when a repaint is needed
|
|
private void display_Paint(object sender, PaintEventArgs e)
|
|
{
|
|
if(General.Map != null)
|
|
{
|
|
if(General.Editing.Mode != null)
|
|
{
|
|
if(!displayresized) General.Editing.Mode.OnPresentDisplay();
|
|
}
|
|
else
|
|
{
|
|
if(General.Colors != null)
|
|
e.Graphics.Clear(Color.FromArgb(General.Colors.Background.ToInt()));
|
|
else
|
|
e.Graphics.Clear(SystemColors.ControlDarkDark);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Redraw requested
|
|
private void redrawtimer_Tick(object sender, EventArgs e)
|
|
{
|
|
// Disable timer (only redraw once)
|
|
redrawtimer.Enabled = false;
|
|
|
|
// Don't do anything when minimized (mxd)
|
|
if(this.WindowState == FormWindowState.Minimized) return;
|
|
|
|
// Resume control layouts
|
|
//if(displayresized) General.LockWindowUpdate(IntPtr.Zero);
|
|
|
|
// Map opened?
|
|
if(General.Map != null)
|
|
{
|
|
// Display was resized?
|
|
if(displayresized)
|
|
{
|
|
//mxd. Aspect ratio may've been changed
|
|
General.Map.CRenderer3D.CreateProjection();
|
|
}
|
|
|
|
// This is a dirty trick to give the display a new mousemove event with correct arguments
|
|
if(mouseinside)
|
|
{
|
|
Point mousepos = Cursor.Position;
|
|
Cursor.Position = new Point(mousepos.X + 1, mousepos.Y + 1);
|
|
Cursor.Position = mousepos;
|
|
}
|
|
|
|
// Redraw now
|
|
RedrawDisplay();
|
|
}
|
|
|
|
// Display resize is done
|
|
displayresized = false;
|
|
}
|
|
|
|
// Display size changes
|
|
private void display_Resize(object sender, EventArgs e)
|
|
{
|
|
// Resizing
|
|
//if(!displayresized) General.LockWindowUpdate(display.Handle);
|
|
displayresized = true;
|
|
|
|
//mxd. Separators may need updating
|
|
UpdateSeparators();
|
|
|
|
// Request redraw
|
|
if(!redrawtimer.Enabled) redrawtimer.Enabled = true;
|
|
}
|
|
|
|
// This requests a delayed redraw
|
|
public void DelayedRedraw()
|
|
{
|
|
// Request redraw
|
|
if(!redrawtimer.Enabled) redrawtimer.Enabled = true;
|
|
}
|
|
|
|
// Mouse click
|
|
private void display_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
if((General.Map != null) && (General.Editing.Mode != null))
|
|
{
|
|
General.Plugins.OnEditMouseClick(e);
|
|
General.Editing.Mode.OnMouseClick(e);
|
|
}
|
|
}
|
|
|
|
// Mouse doubleclick
|
|
private void display_MouseDoubleClick(object sender, MouseEventArgs e)
|
|
{
|
|
if((General.Map != null) && (General.Editing.Mode != null))
|
|
{
|
|
General.Plugins.OnEditMouseDoubleClick(e);
|
|
General.Editing.Mode.OnMouseDoubleClick(e);
|
|
}
|
|
}
|
|
|
|
// Mouse down
|
|
private void display_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
int key = 0;
|
|
|
|
LoseFocus(this, EventArgs.Empty);
|
|
|
|
int mod = 0;
|
|
if(alt) mod |= (int)Keys.Alt;
|
|
if(shift) mod |= (int)Keys.Shift;
|
|
if(ctrl) mod |= (int)Keys.Control;
|
|
|
|
// Apply button
|
|
mousebuttons |= e.Button;
|
|
|
|
// Create key
|
|
switch(e.Button)
|
|
{
|
|
case MouseButtons.Left: key = (int)Keys.LButton; break;
|
|
case MouseButtons.Middle: key = (int)Keys.MButton; break;
|
|
case MouseButtons.Right: key = (int)Keys.RButton; break;
|
|
case MouseButtons.XButton1: key = (int)Keys.XButton1; break;
|
|
case MouseButtons.XButton2: key = (int)Keys.XButton2; break;
|
|
}
|
|
|
|
// Invoke any actions associated with this key
|
|
General.Actions.KeyPressed(key | mod);
|
|
|
|
// Invoke on editing mode
|
|
if((General.Map != null) && (General.Editing.Mode != null))
|
|
{
|
|
General.Plugins.OnEditMouseDown(e);
|
|
General.Editing.Mode.OnMouseDown(e);
|
|
}
|
|
}
|
|
|
|
// Mouse enters
|
|
private void display_MouseEnter(object sender, EventArgs e)
|
|
{
|
|
mouseinside = true;
|
|
//mxd. Skip when in mouseexclusive (e.g. Visual) mode to avoid mouse disappearing when moving it
|
|
// on top of inactive editor window while Visual mode is active
|
|
if((General.Map != null) && (mouseinput == null) && (General.Editing.Mode != null) && !mouseexclusive)
|
|
{
|
|
General.Plugins.OnEditMouseEnter(e);
|
|
General.Editing.Mode.OnMouseEnter(e);
|
|
if(Application.OpenForms.Count == 1 || editformopen) display.Focus(); //mxd
|
|
}
|
|
}
|
|
|
|
// Mouse leaves
|
|
private void display_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
mouseinside = false;
|
|
if((General.Map != null) && (mouseinput == null) && (General.Editing.Mode != null))
|
|
{
|
|
General.Plugins.OnEditMouseLeave(e);
|
|
General.Editing.Mode.OnMouseLeave(e);
|
|
}
|
|
}
|
|
|
|
// Mouse moves
|
|
private void display_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
if((General.Map != null) && (mouseinput == null) && (General.Editing.Mode != null))
|
|
{
|
|
General.Plugins.OnEditMouseMove(e);
|
|
General.Editing.Mode.OnMouseMove(e);
|
|
}
|
|
}
|
|
|
|
// Mouse up
|
|
private void display_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
int key = 0;
|
|
|
|
int mod = 0;
|
|
if(alt) mod |= (int)Keys.Alt;
|
|
if(shift) mod |= (int)Keys.Shift;
|
|
if(ctrl) mod |= (int)Keys.Control;
|
|
|
|
// Apply button
|
|
mousebuttons &= ~e.Button;
|
|
|
|
// Create key
|
|
switch(e.Button)
|
|
{
|
|
case MouseButtons.Left: key = (int)Keys.LButton; break;
|
|
case MouseButtons.Middle: key = (int)Keys.MButton; break;
|
|
case MouseButtons.Right: key = (int)Keys.RButton; break;
|
|
case MouseButtons.XButton1: key = (int)Keys.XButton1; break;
|
|
case MouseButtons.XButton2: key = (int)Keys.XButton2; break;
|
|
}
|
|
|
|
// Invoke any actions associated with this key
|
|
General.Actions.KeyReleased(key | mod);
|
|
|
|
// Invoke on editing mode
|
|
if((General.Map != null) && (General.Editing.Mode != null))
|
|
{
|
|
General.Plugins.OnEditMouseUp(e);
|
|
General.Editing.Mode.OnMouseUp(e);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Input
|
|
|
|
// This is a tool to lock the mouse in exclusive mode
|
|
private void StartMouseExclusive()
|
|
{
|
|
// Not already locked?
|
|
if(mouseinput == null)
|
|
{
|
|
// Start special input device
|
|
mouseinput = new MouseInput(this);
|
|
|
|
// Lock and hide the mouse in window
|
|
Cursor.Position = display.PointToScreen(new Point(display.ClientSize.Width / 2, display.ClientSize.Height / 2)); //mxd
|
|
Cursor.Clip = display.RectangleToScreen(display.ClientRectangle);
|
|
Cursor.Hide();
|
|
|
|
#if MONO_WINFORMS
|
|
// A beautiful transparent cursor, just for you mono!
|
|
string emptycursor =
|
|
"AAACAAEAICACAAAAAAAwAQAAFgAAACgAAAAgAAAAQAAAAAEAAQAAAAAAgAAAAAAAAAAAAAAAAgAA" +
|
|
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
|
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
|
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////////////////////////////////" +
|
|
"////////////////////////////////////////////////////////////////////////////" +
|
|
"//////////////////////////////////////////////////////8=";
|
|
using (var stream = new MemoryStream(System.Convert.FromBase64String(emptycursor)))
|
|
{
|
|
var cursor = new Cursor(stream);
|
|
Cursor.Current = cursor;
|
|
display.Cursor = cursor;
|
|
}
|
|
Application.DoEvents();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// This is a tool to unlock the mouse
|
|
private void StopMouseExclusive()
|
|
{
|
|
// Locked?
|
|
if(mouseinput != null)
|
|
{
|
|
// Stop special input device
|
|
mouseinput.Dispose();
|
|
mouseinput = null;
|
|
|
|
// Release and show the mouse
|
|
Cursor.Clip = Rectangle.Empty;
|
|
Cursor.Position = display.PointToScreen(new Point(display.ClientSize.Width / 2, display.ClientSize.Height / 2));
|
|
#if MONO_WINFORMS
|
|
Cursor.Current = Cursors.Default;
|
|
display.Cursor = Cursors.Default;
|
|
Application.DoEvents();
|
|
#endif
|
|
Cursor.Show();
|
|
}
|
|
}
|
|
|
|
// This requests exclusive mouse input
|
|
public void StartExclusiveMouseInput()
|
|
{
|
|
// Only when not already in exclusive mode
|
|
if(!mouseexclusive)
|
|
{
|
|
General.WriteLogLine("Starting exclusive mouse input mode...");
|
|
|
|
// Start special input device
|
|
StartMouseExclusive();
|
|
mouseexclusive = true;
|
|
mouseexclusivebreaklevel = 0;
|
|
}
|
|
}
|
|
|
|
// This stops exclusive mouse input
|
|
public void StopExclusiveMouseInput()
|
|
{
|
|
// Only when in exclusive mode
|
|
if(mouseexclusive)
|
|
{
|
|
General.WriteLogLine("Stopping exclusive mouse input mode...");
|
|
|
|
// Stop special input device
|
|
StopMouseExclusive();
|
|
mouseexclusive = false;
|
|
mouseexclusivebreaklevel = 0;
|
|
}
|
|
}
|
|
|
|
// This temporarely breaks exclusive mode and counts the break level
|
|
public void BreakExclusiveMouseInput()
|
|
{
|
|
// Only when in exclusive mode
|
|
if(mouseexclusive)
|
|
{
|
|
// Stop special input device
|
|
StopMouseExclusive();
|
|
|
|
// Count the break level
|
|
mouseexclusivebreaklevel++;
|
|
}
|
|
}
|
|
|
|
// This resumes exclusive mode from a break when all breaks have been called to resume
|
|
public void ResumeExclusiveMouseInput()
|
|
{
|
|
// Only when in exclusive mode
|
|
if(mouseexclusive && (mouseexclusivebreaklevel > 0))
|
|
{
|
|
// Decrease break level
|
|
mouseexclusivebreaklevel--;
|
|
|
|
// All break levels resumed? Then lock the mouse again.
|
|
if(mouseexclusivebreaklevel == 0)
|
|
StartMouseExclusive();
|
|
}
|
|
}
|
|
|
|
// This releases all keys
|
|
internal void ReleaseAllKeys()
|
|
{
|
|
General.Actions.ReleaseAllKeys();
|
|
mousebuttons = MouseButtons.None;
|
|
shift = false;
|
|
ctrl = false;
|
|
alt = false;
|
|
}
|
|
|
|
// When the mouse wheel is changed
|
|
protected override void OnMouseWheel(MouseEventArgs e)
|
|
{
|
|
int mod = 0;
|
|
if(alt) mod |= (int)Keys.Alt;
|
|
if(shift) mod |= (int)Keys.Shift;
|
|
if(ctrl) mod |= (int)Keys.Control;
|
|
|
|
// Scrollwheel up?
|
|
if(e.Delta > 0)
|
|
{
|
|
// Invoke actions for scrollwheel
|
|
//for(int i = 0; i < e.Delta; i += 120)
|
|
General.Actions.KeyPressed((int)SpecialKeys.MScrollUp | mod);
|
|
General.Actions.KeyReleased((int)SpecialKeys.MScrollUp | mod);
|
|
}
|
|
// Scrollwheel down?
|
|
else if(e.Delta < 0)
|
|
{
|
|
// Invoke actions for scrollwheel
|
|
//for(int i = 0; i > e.Delta; i -= 120)
|
|
General.Actions.KeyPressed((int)SpecialKeys.MScrollDown | mod);
|
|
General.Actions.KeyReleased((int)SpecialKeys.MScrollDown | mod);
|
|
}
|
|
|
|
// Let the base know
|
|
base.OnMouseWheel(e);
|
|
}
|
|
|
|
// [ZZ]
|
|
private void OnMouseHWheel(int delta)
|
|
{
|
|
int mod = 0;
|
|
if (alt) mod |= (int)Keys.Alt;
|
|
if (shift) mod |= (int)Keys.Shift;
|
|
if (ctrl) mod |= (int)Keys.Control;
|
|
|
|
// Scrollwheel left?
|
|
if (delta < 0)
|
|
{
|
|
General.Actions.KeyPressed((int)SpecialKeys.MScrollLeft | mod);
|
|
General.Actions.KeyReleased((int)SpecialKeys.MScrollLeft | mod);
|
|
}
|
|
else if (delta > 0)
|
|
{
|
|
General.Actions.KeyPressed((int)SpecialKeys.MScrollRight | mod);
|
|
General.Actions.KeyReleased((int)SpecialKeys.MScrollRight | mod);
|
|
}
|
|
|
|
// base? what base?
|
|
}
|
|
|
|
private void MainForm_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
|
|
{
|
|
if (e.KeyCode == Keys.F10)
|
|
e.IsInputKey = true;
|
|
}
|
|
|
|
// When a key is pressed
|
|
private void MainForm_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
int mod = 0;
|
|
|
|
// Keep key modifiers
|
|
alt = e.Alt;
|
|
shift = e.Shift;
|
|
ctrl = e.Control;
|
|
if(alt) mod |= (int)Keys.Alt;
|
|
if(shift) mod |= (int)Keys.Shift;
|
|
if(ctrl) mod |= (int)Keys.Control;
|
|
|
|
// Don't process any keys when they are meant for other input controls
|
|
if((e.KeyData != Keys.None) && ((ActiveControl == null) || (ActiveControl == display)))
|
|
{
|
|
// Invoke any actions associated with this key
|
|
General.Actions.UpdateModifiers(mod);
|
|
e.Handled = General.Actions.KeyPressed((int)e.KeyData);
|
|
|
|
// Invoke on editing mode
|
|
if((General.Map != null) && (General.Editing.Mode != null))
|
|
{
|
|
General.Plugins.OnEditKeyDown(e);
|
|
General.Editing.Mode.OnKeyDown(e);
|
|
}
|
|
|
|
// Handled
|
|
if(e.Handled)
|
|
e.SuppressKeyPress = true;
|
|
}
|
|
|
|
// F1 pressed?
|
|
if((e.KeyCode == Keys.F1) && (e.Modifiers == Keys.None))
|
|
{
|
|
// No action bound to F1?
|
|
Actions.Action[] f1actions = General.Actions.GetActionsByKey((int)e.KeyData);
|
|
if(f1actions.Length == 0)
|
|
{
|
|
// If we don't have any map open, show the Main Window help
|
|
// otherwise, give the help request to the editing mode so it
|
|
// can open the appropriate help file.
|
|
if((General.Map == null) || (General.Editing.Mode == null))
|
|
{
|
|
General.ShowHelp("introduction.html");
|
|
}
|
|
else
|
|
{
|
|
General.Editing.Mode.OnHelp();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (e.KeyCode == Keys.F10)
|
|
{
|
|
Actions.Action[] f10actions = General.Actions.GetActionsByKey((int)e.KeyData);
|
|
if (f10actions.Length > 0)
|
|
{
|
|
e.SuppressKeyPress = true;
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// When a key is released
|
|
private void MainForm_KeyUp(object sender, KeyEventArgs e)
|
|
{
|
|
int mod = 0;
|
|
|
|
// Keep key modifiers
|
|
alt = e.Alt;
|
|
shift = e.Shift;
|
|
ctrl = e.Control;
|
|
if(alt) mod |= (int)Keys.Alt;
|
|
if(shift) mod |= (int)Keys.Shift;
|
|
if(ctrl) mod |= (int)Keys.Control;
|
|
|
|
// Don't process any keys when they are meant for other input controls
|
|
if((ActiveControl == null) || (ActiveControl == display))
|
|
{
|
|
// Invoke any actions associated with this key
|
|
General.Actions.UpdateModifiers(mod);
|
|
e.Handled = General.Actions.KeyReleased((int)e.KeyData);
|
|
|
|
// Invoke on editing mode
|
|
if((General.Map != null) && (General.Editing.Mode != null))
|
|
{
|
|
General.Plugins.OnEditKeyUp(e);
|
|
General.Editing.Mode.OnKeyUp(e);
|
|
}
|
|
|
|
// Handled
|
|
if(e.Handled)
|
|
e.SuppressKeyPress = true;
|
|
}
|
|
|
|
if (e.KeyCode == Keys.F10)
|
|
{
|
|
Actions.Action[] f10actions = General.Actions.GetActionsByKey((int)e.KeyData);
|
|
if (f10actions.Length > 0)
|
|
{
|
|
e.SuppressKeyPress = true;
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//mxd. Sometimes it's handeled by RenderTargetControl, not by MainForm leading to keys being "stuck"
|
|
private void display_OnKeyReleased(object sender, KeyEventArgs e)
|
|
{
|
|
MainForm_KeyUp(sender, e);
|
|
}
|
|
|
|
// These prevent focus changes by way of TAB or Arrow keys
|
|
protected override bool IsInputChar(char charCode) { return false; }
|
|
protected override bool IsInputKey(Keys keyData) { return false; }
|
|
protected override bool ProcessKeyPreview(ref Message m) { return false; }
|
|
protected override bool ProcessDialogKey(Keys keyData) { return false; }
|
|
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { return false; }
|
|
|
|
// This fixes some odd input behaviour
|
|
private void display_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
|
|
{
|
|
if((ActiveControl == null) || (ActiveControl == display))
|
|
{
|
|
LoseFocus(this, EventArgs.Empty);
|
|
KeyEventArgs ea = new KeyEventArgs(e.KeyData);
|
|
MainForm_KeyDown(sender, ea);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Toolbar
|
|
|
|
// This updates the skills list
|
|
private void UpdateSkills()
|
|
{
|
|
// Clear list
|
|
buttontest.DropDownItems.Clear();
|
|
|
|
// Map loaded?
|
|
if(General.Map != null)
|
|
{
|
|
// Make the new items list
|
|
List<ToolStripItem> items = new List<ToolStripItem>(General.Map.Config.Skills.Count * 2 + General.Map.ConfigSettings.TestEngines.Count + 2);
|
|
|
|
// Positive skills are with monsters
|
|
foreach(SkillInfo si in General.Map.Config.Skills)
|
|
{
|
|
ToolStripMenuItem menuitem = new ToolStripMenuItem(si.ToString());
|
|
menuitem.Image = Resources.Monster2;
|
|
menuitem.Click += TestSkill_Click;
|
|
menuitem.Tag = si.Index;
|
|
menuitem.Checked = (General.Settings.TestMonsters && (General.Map.ConfigSettings.TestSkill == si.Index));
|
|
items.Add(menuitem);
|
|
}
|
|
|
|
// Add seperator
|
|
items.Add(new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) });
|
|
|
|
// Negative skills are without monsters
|
|
foreach(SkillInfo si in General.Map.Config.Skills)
|
|
{
|
|
ToolStripMenuItem menuitem = new ToolStripMenuItem(si.ToString());
|
|
menuitem.Image = Resources.Monster3;
|
|
menuitem.Click += TestSkill_Click;
|
|
menuitem.Tag = -si.Index;
|
|
menuitem.Checked = (!General.Settings.TestMonsters && (General.Map.ConfigSettings.TestSkill == si.Index));
|
|
items.Add(menuitem);
|
|
}
|
|
|
|
//mxd. Add seperator
|
|
items.Add(new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) });
|
|
|
|
//mxd. Add test engines
|
|
for(int i = 0; i < General.Map.ConfigSettings.TestEngines.Count; i++)
|
|
{
|
|
if(General.Map.ConfigSettings.TestEngines[i].TestProgramName == EngineInfo.DEFAULT_ENGINE_NAME) continue;
|
|
ToolStripMenuItem menuitem = new ToolStripMenuItem(General.Map.ConfigSettings.TestEngines[i].TestProgramName);
|
|
menuitem.Image = General.Map.ConfigSettings.TestEngines[i].TestProgramIcon;
|
|
menuitem.Click += TestEngine_Click;
|
|
menuitem.Tag = i;
|
|
menuitem.Checked = (i == General.Map.ConfigSettings.CurrentEngineIndex);
|
|
items.Add(menuitem);
|
|
}
|
|
|
|
// Add to list
|
|
buttontest.DropDownItems.AddRange(items.ToArray());
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
internal void DisableDynamicGridResize()
|
|
{
|
|
if(General.Settings.DynamicGridSize)
|
|
{
|
|
General.Settings.DynamicGridSize = false;
|
|
itemdynamicgridsize.Checked = false;
|
|
buttontoggledynamicgrid.Checked = false;
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
private void TestEngine_Click(object sender, EventArgs e)
|
|
{
|
|
General.Map.ConfigSettings.CurrentEngineIndex = (int)(((ToolStripMenuItem)sender).Tag);
|
|
General.Map.ConfigSettings.Changed = true;
|
|
General.Map.Launcher.TestAtSkill(General.Map.ConfigSettings.TestSkill);
|
|
UpdateSkills();
|
|
}
|
|
|
|
// Event handler for testing at a specific skill
|
|
private void TestSkill_Click(object sender, EventArgs e)
|
|
{
|
|
int skill = (int)((sender as ToolStripMenuItem).Tag);
|
|
General.Settings.TestMonsters = (skill > 0);
|
|
General.Map.ConfigSettings.TestSkill = Math.Abs(skill);
|
|
General.Map.Launcher.TestAtSkill(Math.Abs(skill));
|
|
UpdateSkills();
|
|
}
|
|
|
|
// This loses focus
|
|
private void LoseFocus(object sender, EventArgs e)
|
|
{
|
|
// Lose focus!
|
|
try { display.Focus(); } catch(Exception) { }
|
|
this.ActiveControl = null;
|
|
}
|
|
|
|
//mxd. Things filter selected
|
|
private void thingfilters_DropDownItemClicked(object sender, EventArgs e)
|
|
{
|
|
// Only possible when a map is open
|
|
if((General.Map != null) && !updatingfilters)
|
|
{
|
|
updatingfilters = true;
|
|
ToolStripMenuItem clickeditem = sender as ToolStripMenuItem;
|
|
|
|
// Keep already selected items selected
|
|
if(!clickeditem.Checked)
|
|
{
|
|
clickeditem.Checked = true;
|
|
updatingfilters = false;
|
|
return;
|
|
}
|
|
|
|
// Change filter
|
|
ThingsFilter f = clickeditem.Tag as ThingsFilter;
|
|
General.Map.ChangeThingFilter(f);
|
|
|
|
// Deselect other items...
|
|
foreach(var item in thingfilters.DropDown.Items)
|
|
{
|
|
if(item != clickeditem) ((ToolStripMenuItem)item).Checked = false;
|
|
}
|
|
|
|
// Update button text
|
|
thingfilters.Text = f.Name;
|
|
|
|
updatingfilters = false;
|
|
}
|
|
|
|
// Lose focus
|
|
LoseFocus(sender, e);
|
|
}
|
|
|
|
//mxd. This updates the things filter on the toolbar
|
|
internal void UpdateThingsFilters()
|
|
{
|
|
// Only possible to list filters when a map is open
|
|
if(General.Map != null)
|
|
{
|
|
ThingsFilter oldfilter = null;
|
|
|
|
// Anything selected?
|
|
foreach(var item in thingfilters.DropDown.Items)
|
|
{
|
|
if(((ToolStripMenuItem)item).Checked)
|
|
{
|
|
oldfilter = ((ToolStripMenuItem)item).Tag as ThingsFilter;
|
|
break;
|
|
}
|
|
}
|
|
|
|
updatingfilters = true;
|
|
|
|
// Clear the list
|
|
thingfilters.DropDown.Items.Clear();
|
|
|
|
// Add null filter
|
|
if(General.Map.ThingsFilter is NullThingsFilter)
|
|
thingfilters.DropDown.Items.Add(CreateThingsFilterMenuItem(General.Map.ThingsFilter));
|
|
else
|
|
thingfilters.DropDown.Items.Add(CreateThingsFilterMenuItem(new NullThingsFilter()));
|
|
|
|
// Add all filters, select current one
|
|
foreach(ThingsFilter f in General.Map.ConfigSettings.ThingsFilters)
|
|
thingfilters.DropDown.Items.Add(CreateThingsFilterMenuItem(f));
|
|
|
|
updatingfilters = false;
|
|
|
|
// No filter selected?
|
|
ToolStripMenuItem selecteditem = null;
|
|
foreach(var i in thingfilters.DropDown.Items)
|
|
{
|
|
ToolStripMenuItem item = i as ToolStripMenuItem;
|
|
if(item.Checked)
|
|
{
|
|
selecteditem = item;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(selecteditem == null)
|
|
{
|
|
ToolStripMenuItem first = thingfilters.DropDown.Items[0] as ToolStripMenuItem;
|
|
first.Checked = true;
|
|
}
|
|
// Another filter got selected?
|
|
else if(selecteditem.Tag != oldfilter)
|
|
{
|
|
selecteditem.Checked = true;
|
|
}
|
|
|
|
// Update button text
|
|
if(selecteditem != null)
|
|
thingfilters.Text = ((ThingsFilter)selecteditem.Tag).Name;
|
|
}
|
|
else
|
|
{
|
|
// Clear the list
|
|
thingfilters.DropDown.Items.Clear();
|
|
thingfilters.Text = "(show all)";
|
|
}
|
|
}
|
|
|
|
// This selects the things filter based on the filter set on the map manager
|
|
internal void ReflectThingsFilter()
|
|
{
|
|
if(!updatingfilters)
|
|
{
|
|
updatingfilters = true;
|
|
|
|
// Select current filter
|
|
bool selecteditemfound = false;
|
|
foreach(var i in thingfilters.DropDown.Items)
|
|
{
|
|
ToolStripMenuItem item = i as ToolStripMenuItem;
|
|
ThingsFilter f = item.Tag as ThingsFilter;
|
|
|
|
if(f == General.Map.ThingsFilter)
|
|
{
|
|
item.Checked = true;
|
|
thingfilters.Text = f.Name;
|
|
selecteditemfound = true;
|
|
}
|
|
else
|
|
{
|
|
item.Checked = false;
|
|
}
|
|
}
|
|
|
|
// Not in the list?
|
|
if(!selecteditemfound)
|
|
{
|
|
// Select nothing
|
|
thingfilters.Text = "(show all)"; //mxd
|
|
}
|
|
|
|
updatingfilters = false;
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
private ToolStripMenuItem CreateThingsFilterMenuItem(ThingsFilter f)
|
|
{
|
|
// Make decorated name
|
|
string name = f.Name;
|
|
if(f.Invert) name = "!" + name;
|
|
switch(f.DisplayMode)
|
|
{
|
|
case ThingsFilterDisplayMode.CLASSIC_MODES_ONLY: name += " [2D]"; break;
|
|
case ThingsFilterDisplayMode.VISUAL_MODES_ONLY: name += " [3D]"; break;
|
|
}
|
|
|
|
// Create and select the item
|
|
ToolStripMenuItem item = new ToolStripMenuItem(name) { CheckOnClick = true, Tag = f };
|
|
item.CheckedChanged += thingfilters_DropDownItemClicked;
|
|
item.Checked = (f == General.Map.ThingsFilter);
|
|
|
|
// Update icon
|
|
if(!(f is NullThingsFilter) && !f.IsValid())
|
|
{
|
|
item.Image = Resources.Warning;
|
|
//item.ImageScaling = ToolStripItemImageScaling.None;
|
|
}
|
|
|
|
return item;
|
|
}
|
|
|
|
//mxd. Linedef color preset (de)selected
|
|
private void linedefcolorpresets_ItemClicked(object sender, EventArgs e)
|
|
{
|
|
ToolStripMenuItem item = sender as ToolStripMenuItem;
|
|
((LinedefColorPreset)item.Tag).Enabled = item.Checked;
|
|
|
|
List<string> enablednames = new List<string>();
|
|
foreach(LinedefColorPreset p in General.Map.ConfigSettings.LinedefColorPresets)
|
|
{
|
|
if(p.Enabled) enablednames.Add(p.Name);
|
|
}
|
|
|
|
// Update button text
|
|
UpdateColorPresetsButtonText(linedefcolorpresets, enablednames);
|
|
|
|
General.Map.Map.UpdateCustomLinedefColors();
|
|
General.Map.ConfigSettings.Changed = true;
|
|
|
|
// Update display
|
|
if(General.Editing.Mode is ClassicMode) General.Interface.RedrawDisplay();
|
|
}
|
|
|
|
//mxd. Handle Shift key...
|
|
private void linedefcolorpresets_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
|
|
{
|
|
linedefcolorpresets.DropDown.AutoClose = (ModifierKeys != Keys.Shift);
|
|
}
|
|
|
|
//mxd. Handles the mouse leaving linedefcolorpresets.DropDown and clicking on linedefcolorpresets button
|
|
private void linedefcolorpresets_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
linedefcolorpresets.DropDown.AutoClose = true;
|
|
}
|
|
|
|
//mxd. This updates linedef color presets selector on the toolbar
|
|
internal void UpdateLinedefColorPresets()
|
|
{
|
|
// Refill the list
|
|
List<string> enablednames = new List<string>();
|
|
linedefcolorpresets.DropDown.Items.Clear();
|
|
|
|
if(General.Map != null)
|
|
{
|
|
foreach(LinedefColorPreset p in General.Map.ConfigSettings.LinedefColorPresets)
|
|
{
|
|
// Create menu item
|
|
ToolStripMenuItem item = new ToolStripMenuItem(p.Name)
|
|
{
|
|
CheckOnClick = true,
|
|
Tag = p,
|
|
//ImageScaling = ToolStripItemImageScaling.None,
|
|
Checked = p.Enabled,
|
|
ToolTipText = "Hold Shift to toggle several items at once"
|
|
};
|
|
|
|
// Create icon
|
|
if(p.IsValid())
|
|
{
|
|
Bitmap icon = new Bitmap(16, 16);
|
|
using(Graphics g = Graphics.FromImage(icon))
|
|
{
|
|
g.FillRectangle(new SolidBrush(p.Color.ToColor()), 2, 3, 12, 10);
|
|
g.DrawRectangle(Pens.Black, 2, 3, 11, 9);
|
|
}
|
|
|
|
item.Image = icon;
|
|
}
|
|
// Or use the warning icon
|
|
else
|
|
{
|
|
item.Image = Resources.Warning;
|
|
}
|
|
|
|
item.CheckedChanged += linedefcolorpresets_ItemClicked;
|
|
linedefcolorpresets.DropDown.Items.Add(item);
|
|
if(p.Enabled) enablednames.Add(p.Name);
|
|
}
|
|
}
|
|
|
|
// Update button text
|
|
UpdateColorPresetsButtonText(linedefcolorpresets, enablednames);
|
|
}
|
|
|
|
//mxd
|
|
private static void UpdateColorPresetsButtonText(ToolStripItem button, List<string> names)
|
|
{
|
|
if(names.Count == 0)
|
|
{
|
|
button.Text = "No active presets";
|
|
}
|
|
else
|
|
{
|
|
string text = string.Join(", ", names.ToArray());
|
|
if(TextRenderer.MeasureText(text, button.Font).Width > button.Width)
|
|
button.Text = names.Count + (names.Count.ToString(CultureInfo.InvariantCulture).EndsWith("1") ? " preset" : " presets") + " active";
|
|
else
|
|
button.Text = text;
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
public void BeginToolbarUpdate()
|
|
{
|
|
toolbar.SuspendLayout();
|
|
modestoolbar.SuspendLayout();
|
|
modecontrolsloolbar.SuspendLayout();
|
|
}
|
|
|
|
//mxd
|
|
public void EndToolbarUpdate()
|
|
{
|
|
toolbar.ResumeLayout(true);
|
|
modestoolbar.ResumeLayout(true);
|
|
modecontrolsloolbar.ResumeLayout(true);
|
|
}
|
|
|
|
// This adds a button to the toolbar
|
|
public void AddButton(ToolStripItem button) { AddButton(button, ToolbarSection.Custom, General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly())); }
|
|
public void AddButton(ToolStripItem button, ToolbarSection section) { AddButton(button, section, General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly())); }
|
|
private void AddButton(ToolStripItem button, ToolbarSection section, Plugin plugin)
|
|
{
|
|
// Fix tags to full action names
|
|
ToolStripItemCollection items = new ToolStripItemCollection(toolbar, new ToolStripItem[0]);
|
|
items.Add(button);
|
|
RenameTagsToFullActions(items, plugin);
|
|
|
|
// Add to the list so we can update it as needed
|
|
PluginToolbarButton buttoninfo = new PluginToolbarButton();
|
|
buttoninfo.button = button;
|
|
buttoninfo.section = section;
|
|
pluginbuttons.Add(buttoninfo);
|
|
|
|
// Bind visible changed event
|
|
if(!(button is ToolStripSeparator)) button.VisibleChanged += buttonvisiblechangedhandler;
|
|
|
|
// Insert the button in the right section
|
|
switch(section)
|
|
{
|
|
case ToolbarSection.File: toolbar.Items.Insert(toolbar.Items.IndexOf(seperatorfile), button); break;
|
|
case ToolbarSection.Script: toolbar.Items.Insert(toolbar.Items.IndexOf(seperatorscript), button); break;
|
|
case ToolbarSection.UndoRedo: toolbar.Items.Insert(toolbar.Items.IndexOf(seperatorundo), button); break;
|
|
case ToolbarSection.CopyPaste: toolbar.Items.Insert(toolbar.Items.IndexOf(seperatorcopypaste), button); break;
|
|
case ToolbarSection.Prefabs: toolbar.Items.Insert(toolbar.Items.IndexOf(seperatorprefabs), button); break;
|
|
case ToolbarSection.Things: toolbar.Items.Insert(toolbar.Items.IndexOf(buttonviewnormal), button); break;
|
|
case ToolbarSection.Views: toolbar.Items.Insert(toolbar.Items.IndexOf(seperatorviews), button); break;
|
|
case ToolbarSection.Geometry: toolbar.Items.Insert(toolbar.Items.IndexOf(seperatorgeometry), button); break;
|
|
case ToolbarSection.Helpers: toolbar.Items.Insert(toolbar.Items.IndexOf(separatorgzmodes), button); break; //mxd
|
|
case ToolbarSection.Testing: toolbar.Items.Insert(toolbar.Items.IndexOf(seperatortesting), button); break;
|
|
case ToolbarSection.Modes: modestoolbar.Items.Add(button); break; //mxd
|
|
case ToolbarSection.Custom: modecontrolsloolbar.Items.Add(button); modecontrolsloolbar.Visible = true; break; //mxd
|
|
}
|
|
|
|
UpdateToolbar();
|
|
}
|
|
|
|
//mxd
|
|
public void AddModesButton(ToolStripItem button, string group)
|
|
{
|
|
// Set proper styling
|
|
button.Padding = new Padding(0, 1, 0, 1);
|
|
button.Margin = new Padding();
|
|
|
|
// Fix tags to full action names
|
|
ToolStripItemCollection items = new ToolStripItemCollection(toolbar, new ToolStripItem[0]);
|
|
items.Add(button);
|
|
RenameTagsToFullActions(items, General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly()));
|
|
|
|
// Add to the list so we can update it as needed
|
|
PluginToolbarButton buttoninfo = new PluginToolbarButton();
|
|
buttoninfo.button = button;
|
|
buttoninfo.section = ToolbarSection.Modes;
|
|
pluginbuttons.Add(buttoninfo);
|
|
|
|
button.VisibleChanged += buttonvisiblechangedhandler;
|
|
|
|
//find the separator we need
|
|
for(int i = 0; i < modestoolbar.Items.Count; i++)
|
|
{
|
|
if(modestoolbar.Items[i] is ToolStripSeparator && modestoolbar.Items[i].Text == group)
|
|
{
|
|
modestoolbar.Items.Insert(i + 1, button);
|
|
break;
|
|
}
|
|
}
|
|
|
|
UpdateToolbar();
|
|
}
|
|
|
|
// Removes a button
|
|
public void RemoveButton(ToolStripItem button)
|
|
{
|
|
// Find in the list and remove it
|
|
PluginToolbarButton buttoninfo = new PluginToolbarButton();
|
|
for(int i = 0; i < pluginbuttons.Count; i++)
|
|
{
|
|
if(pluginbuttons[i].button == button)
|
|
{
|
|
buttoninfo = pluginbuttons[i];
|
|
pluginbuttons.RemoveAt(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(buttoninfo.button != null)
|
|
{
|
|
// Unbind visible changed event
|
|
if(!(button is ToolStripSeparator)) button.VisibleChanged -= buttonvisiblechangedhandler;
|
|
|
|
//mxd. Remove button from toolbars
|
|
switch(buttoninfo.section)
|
|
{
|
|
case ToolbarSection.Modes:
|
|
modestoolbar.Items.Remove(button);
|
|
break;
|
|
case ToolbarSection.Custom:
|
|
modecontrolsloolbar.Items.Remove(button);
|
|
modecontrolsloolbar.Visible = (modecontrolsloolbar.Items.Count > 0);
|
|
break;
|
|
default:
|
|
toolbar.Items.Remove(button);
|
|
break;
|
|
}
|
|
|
|
UpdateSeparators();
|
|
}
|
|
}
|
|
|
|
// This handle visibility changes in the toolbar buttons
|
|
private void ToolbarButtonVisibleChanged(object sender, EventArgs e)
|
|
{
|
|
if(!preventupdateseperators)
|
|
{
|
|
// Update the seeprators
|
|
UpdateSeparators();
|
|
}
|
|
}
|
|
|
|
// This hides redundant separators
|
|
internal void UpdateSeparators()
|
|
{
|
|
UpdateToolStripSeparators(toolbar.Items, false);
|
|
UpdateToolStripSeparators(menumode.DropDownItems, true);
|
|
|
|
//mxd
|
|
UpdateToolStripSeparators(modestoolbar.Items, true);
|
|
UpdateToolStripSeparators(modecontrolsloolbar.Items, true);
|
|
}
|
|
|
|
// This hides redundant separators
|
|
private static void UpdateToolStripSeparators(ToolStripItemCollection items, bool defaultvisible)
|
|
{
|
|
ToolStripItem pvi = null;
|
|
foreach(ToolStripItem i in items)
|
|
{
|
|
bool separatorvisible = false;
|
|
|
|
// This is a seperator?
|
|
if(i is ToolStripSeparator)
|
|
{
|
|
// Make visible when previous item was not a seperator
|
|
separatorvisible = !(pvi is ToolStripSeparator) && (pvi != null);
|
|
i.Visible = separatorvisible;
|
|
}
|
|
|
|
// Keep as previous visible item
|
|
if(i.Visible || separatorvisible || (defaultvisible && !(i is ToolStripSeparator))) pvi = i;
|
|
}
|
|
|
|
// Hide last item if it is a seperator
|
|
if(pvi is ToolStripSeparator) pvi.Visible = false;
|
|
}
|
|
|
|
// This enables or disables all editing mode items and toolbar buttons
|
|
private void UpdateToolbar()
|
|
{
|
|
preventupdateseperators = true;
|
|
|
|
// Show/hide items based on preferences
|
|
bool maploaded = (General.Map != null); //mxd
|
|
buttonnewmap.Visible = General.Settings.ToolbarFile;
|
|
buttonopenmap.Visible = General.Settings.ToolbarFile;
|
|
buttonsavemap.Visible = General.Settings.ToolbarFile;
|
|
buttonscripteditor.Visible = General.Settings.ToolbarScript && maploaded && General.Map.Config.HasScriptLumps(); // Only show script editor if there a script lumps defined
|
|
buttonundo.Visible = General.Settings.ToolbarUndo && maploaded;
|
|
buttonredo.Visible = General.Settings.ToolbarUndo && maploaded;
|
|
buttoncut.Visible = General.Settings.ToolbarCopy && maploaded;
|
|
buttoncopy.Visible = General.Settings.ToolbarCopy && maploaded;
|
|
buttonpaste.Visible = General.Settings.ToolbarCopy && maploaded;
|
|
buttoninsertprefabfile.Visible = General.Settings.ToolbarPrefabs && maploaded;
|
|
buttoninsertpreviousprefab.Visible = General.Settings.ToolbarPrefabs && maploaded;
|
|
buttonthingsfilter.Visible = General.Settings.ToolbarFilter && maploaded;
|
|
thingfilters.Visible = General.Settings.ToolbarFilter && maploaded;
|
|
separatorlinecolors.Visible = General.Settings.ToolbarFilter && maploaded; //mxd
|
|
buttonlinededfcolors.Visible = General.Settings.ToolbarFilter && maploaded; //mxd
|
|
linedefcolorpresets.Visible = General.Settings.ToolbarFilter && maploaded; //mxd
|
|
separatorfilters.Visible = General.Settings.ToolbarViewModes && maploaded; //mxd
|
|
buttonfullbrightness.Visible = General.Settings.ToolbarViewModes && maploaded; //mxd
|
|
buttonfullbrightness.Checked = Renderer.FullBrightness; //mxd
|
|
buttontogglegrid.Visible = General.Settings.ToolbarViewModes && maploaded; //mxd
|
|
buttontogglegrid.Checked = General.Settings.RenderGrid; //mxd
|
|
buttontogglecomments.Visible = General.Settings.ToolbarViewModes && maploaded && General.Map.UDMF; //mxd
|
|
buttontogglecomments.Checked = General.Settings.RenderComments; //mxd
|
|
buttontogglefixedthingsscale.Visible = General.Settings.ToolbarViewModes && maploaded; //mxd
|
|
buttontogglefixedthingsscale.Checked = General.Settings.FixedThingsScale; //mxd
|
|
separatorfullbrightness.Visible = General.Settings.ToolbarViewModes && maploaded; //mxd
|
|
buttonviewbrightness.Visible = General.Settings.ToolbarViewModes && maploaded;
|
|
buttonviewceilings.Visible = General.Settings.ToolbarViewModes && maploaded;
|
|
buttonviewfloors.Visible = General.Settings.ToolbarViewModes && maploaded;
|
|
buttonviewnormal.Visible = General.Settings.ToolbarViewModes && maploaded;
|
|
separatorgeomergemodes.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd
|
|
buttonmergegeoclassic.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd
|
|
buttonmergegeo.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd
|
|
buttonplacegeo.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd
|
|
buttonsnaptogrid.Visible = General.Settings.ToolbarGeometry && maploaded;
|
|
buttontoggledynamicgrid.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd
|
|
buttontoggledynamicgrid.Checked = General.Settings.DynamicGridSize; //mxd
|
|
buttonautomerge.Visible = General.Settings.ToolbarGeometry && maploaded;
|
|
buttonsplitjoinedsectors.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd
|
|
buttonsplitjoinedsectors.Checked = General.Settings.SplitJoinedSectors; //mxd
|
|
buttonautoclearsidetextures.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd
|
|
buttontest.Visible = General.Settings.ToolbarTesting && maploaded;
|
|
|
|
//mxd
|
|
modelrendermode.Visible = General.Settings.GZToolbarGZDoom && maploaded;
|
|
dynamiclightmode.Visible = General.Settings.GZToolbarGZDoom && maploaded;
|
|
buttontogglefog.Visible = General.Settings.GZToolbarGZDoom && maploaded;
|
|
buttontogglesky.Visible = General.Settings.GZToolbarGZDoom && maploaded;
|
|
buttontoggleeventlines.Visible = General.Settings.GZToolbarGZDoom && maploaded;
|
|
buttontogglevisualvertices.Visible = General.Settings.GZToolbarGZDoom && maploaded && General.Map.UDMF;
|
|
separatorgzmodes.Visible = General.Settings.GZToolbarGZDoom && maploaded;
|
|
|
|
//mxd. Show/hide additional panels
|
|
modestoolbar.Visible = maploaded;
|
|
panelinfo.Visible = maploaded;
|
|
modecontrolsloolbar.Visible = (maploaded && modecontrolsloolbar.Items.Count > 0);
|
|
|
|
//mxd. modestoolbar index in Controls gets messed up when it's invisible. This fixes it.
|
|
//TODO: find out why this happens in the first place
|
|
if(modestoolbar.Visible)
|
|
{
|
|
int toolbarpos = this.Controls.IndexOf(toolbar);
|
|
if(this.Controls.IndexOf(modestoolbar) > toolbarpos)
|
|
{
|
|
this.Controls.SetChildIndex(modestoolbar, toolbarpos);
|
|
}
|
|
}
|
|
|
|
// Update plugin buttons
|
|
foreach(PluginToolbarButton p in pluginbuttons)
|
|
{
|
|
switch(p.section)
|
|
{
|
|
case ToolbarSection.File: p.button.Visible = General.Settings.ToolbarFile; break;
|
|
case ToolbarSection.Script: p.button.Visible = General.Settings.ToolbarScript; break;
|
|
case ToolbarSection.UndoRedo: p.button.Visible = General.Settings.ToolbarUndo; break;
|
|
case ToolbarSection.CopyPaste: p.button.Visible = General.Settings.ToolbarCopy; break;
|
|
case ToolbarSection.Prefabs: p.button.Visible = General.Settings.ToolbarPrefabs; break;
|
|
case ToolbarSection.Things: p.button.Visible = General.Settings.ToolbarFilter; break;
|
|
case ToolbarSection.Views: p.button.Visible = General.Settings.ToolbarViewModes; break;
|
|
case ToolbarSection.Geometry: p.button.Visible = General.Settings.ToolbarGeometry; break;
|
|
case ToolbarSection.Testing: p.button.Visible = General.Settings.ToolbarTesting; break;
|
|
}
|
|
}
|
|
|
|
preventupdateseperators = false;
|
|
|
|
UpdateSeparators();
|
|
}
|
|
|
|
// This checks one of the edit mode items (and unchecks all others)
|
|
internal void CheckEditModeButton(string modeclassname)
|
|
{
|
|
// Go for all items
|
|
//foreach(ToolStripItem item in editmodeitems)
|
|
int itemCount = editmodeitems.Count;
|
|
for(int i = 0; i < itemCount; i++)
|
|
{
|
|
ToolStripItem item = editmodeitems[i];
|
|
// Check what type it is
|
|
if(item is ToolStripMenuItem)
|
|
{
|
|
// Check if mode type matches with given name
|
|
(item as ToolStripMenuItem).Checked = ((item.Tag as EditModeInfo).Type.Name == modeclassname);
|
|
}
|
|
else if(item is ToolStripButton)
|
|
{
|
|
// Check if mode type matches with given name
|
|
(item as ToolStripButton).Checked = ((item.Tag as EditModeInfo).Type.Name == modeclassname);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This removes the config-specific editing mode buttons
|
|
internal void RemoveEditModeButtons()
|
|
{
|
|
// Go for all items
|
|
//foreach(ToolStripItem item in editmodeitems)
|
|
int itemCount = editmodeitems.Count;
|
|
for (int i = 0; i < itemCount; i++)
|
|
{
|
|
ToolStripItem item = editmodeitems[i];
|
|
// Remove it and restart
|
|
menumode.DropDownItems.Remove(item);
|
|
item.Dispose();
|
|
}
|
|
|
|
// Done
|
|
modestoolbar.Items.Clear(); //mxd
|
|
editmodeitems.Clear();
|
|
UpdateSeparators();
|
|
}
|
|
|
|
// This adds an editing mode seperator on the toolbar and menu
|
|
internal void AddEditModeSeperator(string group)
|
|
{
|
|
// Create a button
|
|
ToolStripSeparator item = new ToolStripSeparator();
|
|
item.Text = group; //mxd
|
|
item.Margin = new Padding(0, 3, 0, 3); //mxd
|
|
modestoolbar.Items.Add(item); //mxd
|
|
editmodeitems.Add(item);
|
|
|
|
// Create menu item
|
|
int index = menumode.DropDownItems.Count;
|
|
item = new ToolStripSeparator();
|
|
item.Text = group; //mxd
|
|
item.Margin = new Padding(0, 3, 0, 3);
|
|
menumode.DropDownItems.Insert(index, item);
|
|
editmodeitems.Add(item);
|
|
|
|
UpdateSeparators();
|
|
}
|
|
|
|
// This adds an editing mode button to the toolbar and edit menu
|
|
internal void AddEditModeButton(EditModeInfo modeinfo)
|
|
{
|
|
string controlname = modeinfo.ButtonDesc.Replace("&", "&&");
|
|
|
|
// Create a button
|
|
ToolStripItem item = new ToolStripButton(modeinfo.ButtonDesc, modeinfo.ButtonImage, EditModeButtonHandler);
|
|
item.DisplayStyle = ToolStripItemDisplayStyle.Image;
|
|
item.Padding = new Padding(0, 2, 0, 2);
|
|
item.Margin = new Padding();
|
|
item.Tag = modeinfo;
|
|
modestoolbar.Items.Add(item); //mxd
|
|
editmodeitems.Add(item);
|
|
|
|
// Create menu item
|
|
int index = menumode.DropDownItems.Count;
|
|
item = new ToolStripMenuItem(controlname, modeinfo.ButtonImage, EditModeButtonHandler);
|
|
item.Tag = modeinfo;
|
|
menumode.DropDownItems.Insert(index, item);
|
|
editmodeitems.Add(item);
|
|
item.Visible = true;
|
|
|
|
ApplyShortcutKeys(menumode.DropDownItems);
|
|
UpdateSeparators();
|
|
}
|
|
|
|
// This handles edit mode button clicks
|
|
private void EditModeButtonHandler(object sender, EventArgs e)
|
|
{
|
|
this.Update();
|
|
EditModeInfo modeinfo = (EditModeInfo)((sender as ToolStripItem).Tag);
|
|
General.Actions.InvokeAction(modeinfo.SwitchAction.GetFullActionName(modeinfo.Plugin.Assembly));
|
|
this.Update();
|
|
}
|
|
|
|
//mxd
|
|
public void UpdateGZDoomPanel()
|
|
{
|
|
if(General.Map != null && General.Settings.GZToolbarGZDoom)
|
|
{
|
|
foreach(ToolStripMenuItem item in modelrendermode.DropDownItems)
|
|
{
|
|
item.Checked = ((ModelRenderMode)item.Tag == General.Settings.GZDrawModelsMode);
|
|
if(item.Checked) modelrendermode.Image = item.Image;
|
|
}
|
|
|
|
foreach(ToolStripMenuItem item in dynamiclightmode.DropDownItems)
|
|
{
|
|
item.Checked = ((LightRenderMode)item.Tag == General.Settings.GZDrawLightsMode);
|
|
if(item.Checked) dynamiclightmode.Image = item.Image;
|
|
}
|
|
|
|
buttontogglefog.Checked = General.Settings.GZDrawFog;
|
|
buttontogglesky.Checked = General.Settings.GZDrawSky;
|
|
buttontoggleeventlines.Checked = General.Settings.GZShowEventLines;
|
|
buttontogglevisualvertices.Visible = General.Map.UDMF;
|
|
buttontogglevisualvertices.Checked = General.Settings.GZShowVisualVertices;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Toolbar context menu (mxd)
|
|
|
|
private void toolbarContextMenu_Opening(object sender, CancelEventArgs e)
|
|
{
|
|
if(General.Map == null)
|
|
{
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
|
|
toggleFile.Image = General.Settings.ToolbarFile ? Resources.Check : null;
|
|
toggleScript.Image = General.Settings.ToolbarScript ? Resources.Check : null;
|
|
toggleUndo.Image = General.Settings.ToolbarUndo ? Resources.Check : null;
|
|
toggleCopy.Image = General.Settings.ToolbarCopy ? Resources.Check : null;
|
|
togglePrefabs.Image = General.Settings.ToolbarPrefabs ? Resources.Check : null;
|
|
toggleFilter.Image = General.Settings.ToolbarFilter ? Resources.Check : null;
|
|
toggleViewModes.Image = General.Settings.ToolbarViewModes ? Resources.Check : null;
|
|
toggleGeometry.Image = General.Settings.ToolbarGeometry ? Resources.Check : null;
|
|
toggleTesting.Image = General.Settings.ToolbarTesting ? Resources.Check : null;
|
|
toggleRendering.Image = General.Settings.GZToolbarGZDoom ? Resources.Check : null;
|
|
}
|
|
|
|
private void toolbarContextMenu_Closing(object sender, ToolStripDropDownClosingEventArgs e)
|
|
{
|
|
e.Cancel = (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked && toolbarContextMenuShiftPressed);
|
|
}
|
|
|
|
private void toolbarContextMenu_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
toolbarContextMenuShiftPressed = (e.KeyCode == Keys.ShiftKey);
|
|
}
|
|
|
|
private void toolbarContextMenu_KeyUp(object sender, KeyEventArgs e)
|
|
{
|
|
toolbarContextMenuShiftPressed = (e.KeyCode != Keys.ShiftKey);
|
|
}
|
|
|
|
private void toggleFile_Click(object sender, EventArgs e)
|
|
{
|
|
General.Settings.ToolbarFile = !General.Settings.ToolbarFile;
|
|
UpdateToolbar();
|
|
|
|
if(toolbarContextMenuShiftPressed)
|
|
toggleFile.Image = General.Settings.ToolbarFile ? Resources.Check : null;
|
|
}
|
|
|
|
private void toggleScript_Click(object sender, EventArgs e)
|
|
{
|
|
General.Settings.ToolbarScript = !General.Settings.ToolbarScript;
|
|
UpdateToolbar();
|
|
|
|
if(toolbarContextMenuShiftPressed)
|
|
toggleScript.Image = General.Settings.ToolbarScript ? Resources.Check : null;
|
|
}
|
|
|
|
private void toggleUndo_Click(object sender, EventArgs e)
|
|
{
|
|
General.Settings.ToolbarUndo = !General.Settings.ToolbarUndo;
|
|
UpdateToolbar();
|
|
|
|
if(toolbarContextMenuShiftPressed)
|
|
toggleUndo.Image = General.Settings.ToolbarUndo ? Resources.Check : null;
|
|
}
|
|
|
|
private void toggleCopy_Click(object sender, EventArgs e)
|
|
{
|
|
General.Settings.ToolbarCopy = !General.Settings.ToolbarCopy;
|
|
UpdateToolbar();
|
|
|
|
if(toolbarContextMenuShiftPressed)
|
|
toggleCopy.Image = General.Settings.ToolbarCopy ? Resources.Check : null;
|
|
}
|
|
|
|
private void togglePrefabs_Click(object sender, EventArgs e)
|
|
{
|
|
General.Settings.ToolbarPrefabs = !General.Settings.ToolbarPrefabs;
|
|
UpdateToolbar();
|
|
|
|
if(toolbarContextMenuShiftPressed)
|
|
togglePrefabs.Image = General.Settings.ToolbarPrefabs ? Resources.Check : null;
|
|
}
|
|
|
|
private void toggleFilter_Click(object sender, EventArgs e)
|
|
{
|
|
General.Settings.ToolbarFilter = !General.Settings.ToolbarFilter;
|
|
UpdateToolbar();
|
|
|
|
if(toolbarContextMenuShiftPressed)
|
|
toggleFilter.Image = General.Settings.ToolbarFilter ? Resources.Check : null;
|
|
}
|
|
|
|
private void toggleViewModes_Click(object sender, EventArgs e)
|
|
{
|
|
General.Settings.ToolbarViewModes = !General.Settings.ToolbarViewModes;
|
|
UpdateToolbar();
|
|
|
|
if(toolbarContextMenuShiftPressed)
|
|
toggleViewModes.Image = General.Settings.ToolbarViewModes ? Resources.Check : null;
|
|
}
|
|
|
|
private void toggleGeometry_Click(object sender, EventArgs e)
|
|
{
|
|
General.Settings.ToolbarGeometry = !General.Settings.ToolbarGeometry;
|
|
UpdateToolbar();
|
|
|
|
if(toolbarContextMenuShiftPressed)
|
|
toggleGeometry.Image = General.Settings.ToolbarGeometry ? Resources.Check : null;
|
|
}
|
|
|
|
private void toggleTesting_Click(object sender, EventArgs e)
|
|
{
|
|
General.Settings.ToolbarTesting = !General.Settings.ToolbarTesting;
|
|
UpdateToolbar();
|
|
|
|
if(toolbarContextMenuShiftPressed)
|
|
toggleTesting.Image = General.Settings.ToolbarTesting ? Resources.Check : null;
|
|
}
|
|
|
|
private void toggleRendering_Click(object sender, EventArgs e)
|
|
{
|
|
General.Settings.GZToolbarGZDoom = !General.Settings.GZToolbarGZDoom;
|
|
UpdateToolbar();
|
|
|
|
if(toolbarContextMenuShiftPressed)
|
|
toggleRendering.Image = General.Settings.GZToolbarGZDoom ? Resources.Check : null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Menus
|
|
|
|
// This adds a menu to the menus bar
|
|
public void AddMenu(ToolStripItem menu) { AddMenu(menu, MenuSection.Top, General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly())); }
|
|
public void AddMenu(ToolStripItem menu, MenuSection section) { AddMenu(menu, section, General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly())); }
|
|
private void AddMenu(ToolStripItem menu, MenuSection section, Plugin plugin)
|
|
{
|
|
// Fix tags to full action names
|
|
ToolStripItemCollection items = new ToolStripItemCollection(this.menumain, new ToolStripItem[0]);
|
|
items.Add(menu);
|
|
RenameTagsToFullActions(items, plugin);
|
|
|
|
// Insert the menu in the right location
|
|
switch(section)
|
|
{
|
|
case MenuSection.FileNewOpenClose: menufile.DropDownItems.Insert(menufile.DropDownItems.IndexOf(seperatorfileopen), menu); break;
|
|
case MenuSection.FileSave: menufile.DropDownItems.Insert(menufile.DropDownItems.IndexOf(seperatorfilesave), menu); break;
|
|
case MenuSection.FileImport: itemimport.DropDownItems.Add(menu); break; //mxd
|
|
case MenuSection.FileExport: itemexport.DropDownItems.Add(menu); break; //mxd
|
|
case MenuSection.FileRecent: menufile.DropDownItems.Insert(menufile.DropDownItems.IndexOf(seperatorfilerecent), menu); break;
|
|
case MenuSection.FileExit: menufile.DropDownItems.Insert(menufile.DropDownItems.IndexOf(itemexit), menu); break;
|
|
case MenuSection.EditUndoRedo: menuedit.DropDownItems.Insert(menuedit.DropDownItems.IndexOf(seperatoreditundo), menu); break;
|
|
case MenuSection.EditCopyPaste: menuedit.DropDownItems.Insert(menuedit.DropDownItems.IndexOf(seperatoreditcopypaste), menu); break;
|
|
case MenuSection.EditGeometry: menuedit.DropDownItems.Insert(menuedit.DropDownItems.IndexOf(seperatoreditgeometry), menu); break;
|
|
case MenuSection.EditGrid: menuedit.DropDownItems.Insert(menuedit.DropDownItems.IndexOf(seperatoreditgrid), menu); break;
|
|
case MenuSection.EditMapOptions: menuedit.DropDownItems.Add(menu); break;
|
|
case MenuSection.ViewHelpers: menuview.DropDownItems.Insert(menuview.DropDownItems.IndexOf(separatorhelpers), menu); break; //mxd
|
|
case MenuSection.ViewRendering: menuview.DropDownItems.Insert(menuview.DropDownItems.IndexOf(separatorrendering), menu); break; //mxd
|
|
case MenuSection.ViewThings: menuview.DropDownItems.Insert(menuview.DropDownItems.IndexOf(seperatorviewthings), menu); break;
|
|
case MenuSection.ViewViews: menuview.DropDownItems.Insert(menuview.DropDownItems.IndexOf(seperatorviewviews), menu); break;
|
|
case MenuSection.ViewZoom: menuview.DropDownItems.Insert(menuview.DropDownItems.IndexOf(seperatorviewzoom), menu); break;
|
|
case MenuSection.ViewScriptEdit: menuview.DropDownItems.Add(menu); break;
|
|
case MenuSection.PrefabsInsert: menuprefabs.DropDownItems.Insert(menuprefabs.DropDownItems.IndexOf(seperatorprefabsinsert), menu); break;
|
|
case MenuSection.PrefabsCreate: menuprefabs.DropDownItems.Add(menu); break;
|
|
case MenuSection.ToolsResources: menutools.DropDownItems.Insert(menutools.DropDownItems.IndexOf(seperatortoolsresources), menu); break;
|
|
case MenuSection.ToolsConfiguration: menutools.DropDownItems.Insert(menutools.DropDownItems.IndexOf(seperatortoolsconfig), menu); break;
|
|
case MenuSection.ToolsTesting: menutools.DropDownItems.Add(menu); break;
|
|
case MenuSection.HelpManual: menuhelp.DropDownItems.Insert(menuhelp.DropDownItems.IndexOf(seperatorhelpmanual), menu); break;
|
|
case MenuSection.HelpAbout: menuhelp.DropDownItems.Add(menu); break;
|
|
case MenuSection.Top: menumain.Items.Insert(menumain.Items.IndexOf(menutools), menu); break;
|
|
}
|
|
|
|
ApplyShortcutKeys(items);
|
|
}
|
|
|
|
//mxd
|
|
public void AddModesMenu(ToolStripItem menu, string group)
|
|
{
|
|
// Fix tags to full action names
|
|
ToolStripItemCollection items = new ToolStripItemCollection(this.menumain, new ToolStripItem[0]);
|
|
items.Add(menu);
|
|
RenameTagsToFullActions(items, General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly()));
|
|
|
|
//find the separator we need
|
|
for(int i = 0; i < menumode.DropDownItems.Count; i++)
|
|
{
|
|
if(menumode.DropDownItems[i] is ToolStripSeparator && menumode.DropDownItems[i].Text == group)
|
|
{
|
|
menumode.DropDownItems.Insert(i + 1, menu);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ApplyShortcutKeys(items);
|
|
}
|
|
|
|
// Removes a menu
|
|
public void RemoveMenu(ToolStripItem menu)
|
|
{
|
|
// We actually have no idea in which menu this item is,
|
|
// so try removing from all menus and the top strip
|
|
menufile.DropDownItems.Remove(menu);
|
|
menuedit.DropDownItems.Remove(menu);
|
|
menumode.DropDownItems.Remove(menu); //mxd
|
|
menuview.DropDownItems.Remove(menu);
|
|
menuprefabs.DropDownItems.Remove(menu);
|
|
menutools.DropDownItems.Remove(menu);
|
|
menuhelp.DropDownItems.Remove(menu);
|
|
menumain.Items.Remove(menu);
|
|
}
|
|
|
|
// Public method to apply shortcut keys
|
|
internal void ApplyShortcutKeys()
|
|
{
|
|
// Apply shortcut keys to menus
|
|
ApplyShortcutKeys(menumain.Items);
|
|
}
|
|
|
|
// This sets the shortcut keys on menu items
|
|
private static void ApplyShortcutKeys(ToolStripItemCollection items)
|
|
{
|
|
// Go for all controls to find menu items
|
|
foreach(ToolStripItem item in items)
|
|
{
|
|
// This is a menu item?
|
|
if(item is ToolStripMenuItem)
|
|
{
|
|
// Get the item in proper type
|
|
ToolStripMenuItem menuitem = (item as ToolStripMenuItem);
|
|
|
|
// Tag set for this item?
|
|
if(menuitem.Tag is string)
|
|
{
|
|
// Action with this name available?
|
|
string actionname = menuitem.Tag.ToString();
|
|
if(General.Actions.Exists(actionname))
|
|
{
|
|
// Put the action shortcut key on the menu item
|
|
menuitem.ShortcutKeyDisplayString = Actions.Action.GetShortcutKeyDesc(General.Actions[actionname].ShortcutKey);
|
|
}
|
|
}
|
|
// Edit mode info set for this item?
|
|
else if(menuitem.Tag is EditModeInfo)
|
|
{
|
|
// Action with this name available?
|
|
EditModeInfo modeinfo = (EditModeInfo)menuitem.Tag;
|
|
string actionname = modeinfo.SwitchAction.GetFullActionName(modeinfo.Plugin.Assembly);
|
|
if(General.Actions.Exists(actionname))
|
|
{
|
|
// Put the action shortcut key on the menu item
|
|
menuitem.ShortcutKeyDisplayString = Actions.Action.GetShortcutKeyDesc(General.Actions[actionname].ShortcutKey);
|
|
}
|
|
}
|
|
|
|
// Recursively apply shortcut keys to child menu items as well
|
|
ApplyShortcutKeys(menuitem.DropDownItems);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This fixes short action names to fully qualified
|
|
// action names on menu item tags
|
|
private static void RenameTagsToFullActions(ToolStripItemCollection items, Plugin plugin)
|
|
{
|
|
// Go for all controls to find menu items
|
|
foreach(ToolStripItem item in items)
|
|
{
|
|
// Tag set for this item?
|
|
if(item.Tag is string)
|
|
{
|
|
// Check if the tag does not already begin with the assembly name
|
|
if(!((string)item.Tag).StartsWith(plugin.Name + "_", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// Change the tag to a fully qualified action name
|
|
item.Tag = plugin.Name.ToLowerInvariant() + "_" + (string)item.Tag;
|
|
}
|
|
}
|
|
|
|
// This is a menu item?
|
|
if(item is ToolStripMenuItem)
|
|
{
|
|
// Get the item in proper type
|
|
ToolStripMenuItem menuitem = (item as ToolStripMenuItem);
|
|
|
|
// Recursively perform operation on child menu items
|
|
RenameTagsToFullActions(menuitem.DropDownItems, plugin);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== File Menu
|
|
|
|
// This sets up the file menu
|
|
private void UpdateFileMenu()
|
|
{
|
|
//mxd. Show/hide items
|
|
bool show = (General.Map != null); //mxd
|
|
itemclosemap.Visible = show;
|
|
itemsavemap.Visible = show;
|
|
itemsavemapas.Visible = show;
|
|
itemsavemapinto.Visible = show;
|
|
itemopenmapincurwad.Visible = show; //mxd
|
|
itemimport.Visible = show; //mxd
|
|
itemexport.Visible = show; //mxd
|
|
seperatorfileopen.Visible = show; //mxd
|
|
seperatorfilesave.Visible = show; //mxd
|
|
|
|
// Toolbar icons
|
|
buttonsavemap.Enabled = show;
|
|
}
|
|
|
|
// This sets the recent files from configuration
|
|
private void CreateRecentFiles()
|
|
{
|
|
bool anyitems = false;
|
|
|
|
// Where to insert
|
|
int insertindex = menufile.DropDownItems.IndexOf(itemnorecent);
|
|
|
|
// Create all items
|
|
recentitems = new ToolStripMenuItem[General.Settings.MaxRecentFiles];
|
|
for(int i = 0; i < General.Settings.MaxRecentFiles; i++)
|
|
{
|
|
// Create item
|
|
recentitems[i] = new ToolStripMenuItem("");
|
|
recentitems[i].Tag = "";
|
|
recentitems[i].Click += recentitem_Click;
|
|
menufile.DropDownItems.Insert(insertindex + i, recentitems[i]);
|
|
|
|
// Get configuration setting
|
|
string filename = General.Settings.ReadSetting("recentfiles.file" + i, "");
|
|
if(!string.IsNullOrEmpty(filename) && File.Exists(filename))
|
|
{
|
|
// Set up item
|
|
int number = i + 1;
|
|
recentitems[i].Text = "&" + number + " " + GetDisplayFilename(filename);
|
|
recentitems[i].Tag = filename;
|
|
recentitems[i].Visible = true;
|
|
anyitems = true;
|
|
}
|
|
else
|
|
{
|
|
// Hide item
|
|
recentitems[i].Visible = false;
|
|
}
|
|
}
|
|
|
|
// Hide the no recent item when there are items
|
|
itemnorecent.Visible = !anyitems;
|
|
}
|
|
|
|
// This saves the recent files list
|
|
private void SaveRecentFiles()
|
|
{
|
|
// Go for all items
|
|
for(int i = 0; i < recentitems.Length; i++)
|
|
{
|
|
// Recent file set?
|
|
if(!string.IsNullOrEmpty(recentitems[i].Text))
|
|
{
|
|
// Save to configuration
|
|
General.Settings.WriteSetting("recentfiles.file" + i, recentitems[i].Tag.ToString());
|
|
}
|
|
}
|
|
|
|
// Save program configuration
|
|
General.SaveSettings();
|
|
}
|
|
|
|
// This adds a recent file to the list
|
|
internal void AddRecentFile(string filename)
|
|
{
|
|
//mxd. Recreate recent files list
|
|
if(recentitems.Length != General.Settings.MaxRecentFiles)
|
|
{
|
|
UpdateRecentItems();
|
|
}
|
|
|
|
int movedownto = General.Settings.MaxRecentFiles - 1;
|
|
|
|
// Check if this file is already in the list
|
|
for(int i = 0; i < General.Settings.MaxRecentFiles; i++)
|
|
{
|
|
// File same as this item?
|
|
if(string.Compare(filename, recentitems[i].Tag.ToString(), true) == 0)
|
|
{
|
|
// Move down to here so that this item will disappear
|
|
movedownto = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Go for all items, except the last one, backwards
|
|
for(int i = movedownto - 1; i >= 0; i--)
|
|
{
|
|
// Move recent file down the list
|
|
int number = i + 2;
|
|
recentitems[i + 1].Text = "&" + number + " " + GetDisplayFilename(recentitems[i].Tag.ToString());
|
|
recentitems[i + 1].Tag = recentitems[i].Tag.ToString();
|
|
recentitems[i + 1].Visible = !string.IsNullOrEmpty(recentitems[i].Tag.ToString());
|
|
}
|
|
|
|
// Add new file at the top
|
|
recentitems[0].Text = "&1 " + GetDisplayFilename(filename);
|
|
recentitems[0].Tag = filename;
|
|
recentitems[0].Visible = true;
|
|
|
|
// Hide the no recent item
|
|
itemnorecent.Visible = false;
|
|
|
|
SaveRecentFiles();
|
|
}
|
|
|
|
//mxd
|
|
private void UpdateRecentItems()
|
|
{
|
|
foreach(ToolStripMenuItem item in recentitems)
|
|
menufile.DropDownItems.Remove(item);
|
|
|
|
//SaveRecentFiles();
|
|
CreateRecentFiles();
|
|
}
|
|
|
|
// This returns the trimmed file/path string
|
|
private string GetDisplayFilename(string filename)
|
|
{
|
|
// String doesnt fit?
|
|
if(MeasureString(filename, this.Font).Width > MAX_RECENT_FILES_PIXELS)
|
|
{
|
|
// Start chopping off characters
|
|
for(int i = filename.Length - 6; i >= 0; i--)
|
|
{
|
|
// Does it fit now?
|
|
string newname = filename.Substring(0, 3) + "..." + filename.Substring(filename.Length - i, i);
|
|
if(MeasureString(newname, this.Font).Width <= MAX_RECENT_FILES_PIXELS) return newname;
|
|
}
|
|
|
|
// Cant find anything that fits (most unlikely!)
|
|
return "wtf?!";
|
|
}
|
|
else
|
|
{
|
|
// The whole string fits
|
|
return filename;
|
|
}
|
|
}
|
|
|
|
// Exit clicked
|
|
private void itemexit_Click(object sender, EventArgs e) { this.Close(); }
|
|
|
|
// Recent item clicked
|
|
private void recentitem_Click(object sender, EventArgs e)
|
|
{
|
|
// Get the item that was clicked
|
|
ToolStripItem item = (sender as ToolStripItem);
|
|
|
|
// Open this file
|
|
General.OpenMapFile(item.Tag.ToString(), null);
|
|
}
|
|
|
|
//mxd
|
|
private void menufile_DropDownOpening(object sender, EventArgs e)
|
|
{
|
|
UpdateRecentItems();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Edit Menu
|
|
|
|
// This sets up the edit menu
|
|
private void UpdateEditMenu()
|
|
{
|
|
// No edit menu when no map open
|
|
menuedit.Visible = (General.Map != null);
|
|
|
|
// Enable/disable items
|
|
itemundo.Enabled = (General.Map != null) && (General.Map.UndoRedo.NextUndo != null);
|
|
itemredo.Enabled = (General.Map != null) && (General.Map.UndoRedo.NextRedo != null);
|
|
itemcut.Enabled = (General.Map != null) && (General.Editing.Mode != null) && General.Editing.Mode.Attributes.AllowCopyPaste;
|
|
itemcopy.Enabled = (General.Map != null) && (General.Editing.Mode != null) && General.Editing.Mode.Attributes.AllowCopyPaste;
|
|
itempaste.Enabled = (General.Map != null) && (General.Editing.Mode != null) && General.Editing.Mode.Attributes.AllowCopyPaste;
|
|
itempastespecial.Enabled = (General.Map != null) && (General.Editing.Mode != null) && General.Editing.Mode.Attributes.AllowCopyPaste;
|
|
itemsplitjoinedsectors.Checked = General.Settings.SplitJoinedSectors; //mxd
|
|
itemautoclearsidetextures.Checked = General.Settings.AutoClearSidedefTextures; //mxd
|
|
itemdynamicgridsize.Enabled = (General.Map != null); //mxd
|
|
itemdynamicgridsize.Checked = General.Settings.DynamicGridSize; //mxd
|
|
|
|
// Determine undo description
|
|
if(itemundo.Enabled)
|
|
itemundo.Text = "Undo " + General.Map.UndoRedo.NextUndo.Description;
|
|
else
|
|
itemundo.Text = "Undo";
|
|
|
|
// Determine redo description
|
|
if(itemredo.Enabled)
|
|
itemredo.Text = "Redo " + General.Map.UndoRedo.NextRedo.Description;
|
|
else
|
|
itemredo.Text = "Redo";
|
|
|
|
// Toolbar icons
|
|
buttonundo.Enabled = itemundo.Enabled;
|
|
buttonredo.Enabled = itemredo.Enabled;
|
|
buttonundo.ToolTipText = itemundo.Text;
|
|
buttonredo.ToolTipText = itemredo.Text;
|
|
buttonautoclearsidetextures.Checked = itemautoclearsidetextures.Checked; //mxd
|
|
buttoncut.Enabled = itemcut.Enabled;
|
|
buttoncopy.Enabled = itemcopy.Enabled;
|
|
buttonpaste.Enabled = itempaste.Enabled;
|
|
|
|
//mxd. Geometry merge mode items
|
|
if(General.Map != null)
|
|
{
|
|
for(int i = 0; i < geomergemodesbuttons.Length; i++)
|
|
{
|
|
// Check the correct item
|
|
geomergemodesbuttons[i].Checked = (i == (int)General.Settings.MergeGeometryMode);
|
|
geomergemodesitems[i].Checked = (i == (int)General.Settings.MergeGeometryMode);
|
|
}
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
private void menuedit_DropDownOpening(object sender, EventArgs e)
|
|
{
|
|
if(General.Map == null)
|
|
{
|
|
selectGroup.Enabled = false;
|
|
clearGroup.Enabled = false;
|
|
addToGroup.Enabled = false;
|
|
return;
|
|
}
|
|
|
|
//get data
|
|
ToolStripItem item;
|
|
GroupInfo[] infos = new GroupInfo[10];
|
|
for(int i = 0; i < infos.Length; i++) infos[i] = General.Map.Map.GetGroupInfo(i);
|
|
|
|
//update "Add to group" menu
|
|
addToGroup.Enabled = true;
|
|
addToGroup.DropDownItems.Clear();
|
|
foreach(GroupInfo gi in infos)
|
|
{
|
|
item = addToGroup.DropDownItems.Add(gi.ToString());
|
|
item.Tag = "builder_assigngroup" + gi.Index;
|
|
item.Click += InvokeTaggedAction;
|
|
}
|
|
|
|
//update "Select group" menu
|
|
selectGroup.DropDownItems.Clear();
|
|
foreach(GroupInfo gi in infos)
|
|
{
|
|
if(gi.Empty) continue;
|
|
item = selectGroup.DropDownItems.Add(gi.ToString());
|
|
item.Tag = "builder_selectgroup" + gi.Index;
|
|
item.Click += InvokeTaggedAction;
|
|
}
|
|
|
|
//update "Clear group" menu
|
|
clearGroup.DropDownItems.Clear();
|
|
foreach(GroupInfo gi in infos)
|
|
{
|
|
if(gi.Empty) continue;
|
|
item = clearGroup.DropDownItems.Add(gi.ToString());
|
|
item.Tag = "builder_cleargroup" + gi.Index;
|
|
item.Click += InvokeTaggedAction;
|
|
}
|
|
|
|
selectGroup.Enabled = selectGroup.DropDownItems.Count > 0;
|
|
clearGroup.Enabled = clearGroup.DropDownItems.Count > 0;
|
|
}
|
|
|
|
//mxd. Action to toggle comments rendering
|
|
[BeginAction("togglecomments")]
|
|
internal void ToggleComments()
|
|
{
|
|
buttontogglecomments.Checked = !buttontogglecomments.Checked;
|
|
itemtogglecomments.Checked = buttontogglecomments.Checked;
|
|
General.Settings.RenderComments = buttontogglecomments.Checked;
|
|
DisplayStatus(StatusType.Action, "Comment icons are " + (buttontogglecomments.Checked ? "SHOWN" : "HIDDEN"));
|
|
|
|
// Redraw display to show changes
|
|
RedrawDisplay();
|
|
}
|
|
|
|
//mxd. Action to toggle fixed things scale
|
|
[BeginAction("togglefixedthingsscale")]
|
|
internal void ToggleFixedThingsScale()
|
|
{
|
|
buttontogglefixedthingsscale.Checked = !buttontogglefixedthingsscale.Checked;
|
|
itemtogglefixedthingsscale.Checked = buttontogglefixedthingsscale.Checked;
|
|
General.Settings.FixedThingsScale = buttontogglefixedthingsscale.Checked;
|
|
DisplayStatus(StatusType.Action, "Fixed things scale is " + (buttontogglefixedthingsscale.Checked ? "ENABLED" : "DISABLED"));
|
|
|
|
// Redraw display to show changes
|
|
RedrawDisplay();
|
|
}
|
|
|
|
// Action to toggle snap to grid
|
|
[BeginAction("togglesnap")]
|
|
internal void ToggleSnapToGrid()
|
|
{
|
|
buttonsnaptogrid.Checked = !buttonsnaptogrid.Checked;
|
|
itemsnaptogrid.Checked = buttonsnaptogrid.Checked;
|
|
DisplayStatus(StatusType.Action, "Snap to grid is " + (buttonsnaptogrid.Checked ? "ENABLED" : "DISABLED"));
|
|
}
|
|
|
|
// Action to toggle auto merge
|
|
[BeginAction("toggleautomerge")]
|
|
internal void ToggleAutoMerge()
|
|
{
|
|
buttonautomerge.Checked = !buttonautomerge.Checked;
|
|
itemautomerge.Checked = buttonautomerge.Checked;
|
|
DisplayStatus(StatusType.Action, "Snap to geometry is " + (buttonautomerge.Checked ? "ENABLED" : "DISABLED"));
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("togglejoinedsectorssplitting")]
|
|
internal void ToggleJoinedSectorsSplitting()
|
|
{
|
|
buttonsplitjoinedsectors.Checked = !buttonsplitjoinedsectors.Checked;
|
|
itemsplitjoinedsectors.Checked = buttonsplitjoinedsectors.Checked;
|
|
General.Settings.SplitJoinedSectors = buttonsplitjoinedsectors.Checked;
|
|
DisplayStatus(StatusType.Action, "Joined sectors splitting is " + (General.Settings.SplitJoinedSectors ? "ENABLED" : "DISABLED"));
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("togglebrightness")]
|
|
internal void ToggleBrightness()
|
|
{
|
|
Renderer.FullBrightness = !Renderer.FullBrightness;
|
|
buttonfullbrightness.Checked = Renderer.FullBrightness;
|
|
itemfullbrightness.Checked = Renderer.FullBrightness;
|
|
General.Interface.DisplayStatus(StatusType.Action, "Full Brightness is now " + (Renderer.FullBrightness ? "ON" : "OFF"));
|
|
|
|
// Redraw display to show changes
|
|
General.Interface.RedrawDisplay();
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("togglegrid")]
|
|
protected void ToggleGrid()
|
|
{
|
|
General.Settings.RenderGrid = !General.Settings.RenderGrid;
|
|
itemtogglegrid.Checked = General.Settings.RenderGrid;
|
|
buttontogglegrid.Checked = General.Settings.RenderGrid;
|
|
General.Interface.DisplayStatus(StatusType.Action, "Grid rendering is " + (General.Settings.RenderGrid ? "ENABLED" : "DISABLED"));
|
|
|
|
// Redraw display to show changes
|
|
General.Map.CRenderer2D.GridVisibilityChanged();
|
|
General.Interface.RedrawDisplay();
|
|
}
|
|
|
|
[BeginAction("aligngridtolinedef")]
|
|
protected void AlignGridToLinedef()
|
|
{
|
|
if (General.Map == null)
|
|
return;
|
|
|
|
if (General.Map.Map.SelectedLinedefsCount != 1)
|
|
{
|
|
General.Interface.DisplayStatus(StatusType.Warning, "Exactly one linedef must be selected");
|
|
General.Interface.MessageBeep(MessageBeepType.Warning);
|
|
return;
|
|
}
|
|
Linedef line = General.Map.Map.SelectedLinedefs.First.Value;
|
|
Vertex vertex = line.Start;
|
|
General.Map.Grid.SetGridRotation(line.Angle);
|
|
General.Map.Grid.SetGridOrigin(vertex.Position.x, vertex.Position.y);
|
|
General.Map.CRenderer2D.GridVisibilityChanged();
|
|
General.Interface.RedrawDisplay();
|
|
}
|
|
|
|
[BeginAction("setgridorigintovertex")]
|
|
protected void SetGridOriginToVertex()
|
|
{
|
|
if (General.Map == null)
|
|
return;
|
|
|
|
if (General.Map.Map.SelectedVerticessCount != 1)
|
|
{
|
|
General.Interface.DisplayStatus(StatusType.Warning, "Exactly one vertex must be selected");
|
|
General.Interface.MessageBeep(MessageBeepType.Warning);
|
|
return;
|
|
}
|
|
Vertex vertex = General.Map.Map.SelectedVertices.First.Value;
|
|
General.Map.Grid.SetGridOrigin(vertex.Position.x, vertex.Position.y);
|
|
General.Map.CRenderer2D.GridVisibilityChanged();
|
|
General.Interface.RedrawDisplay();
|
|
}
|
|
|
|
[BeginAction("resetgrid")]
|
|
protected void ResetGrid()
|
|
{
|
|
General.Map.Grid.SetGridRotation(0.0f);
|
|
General.Map.Grid.SetGridOrigin(0, 0);
|
|
General.Map.CRenderer2D.GridVisibilityChanged();
|
|
General.Interface.RedrawDisplay();
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("toggledynamicgrid")]
|
|
protected void ToggleDynamicGrid()
|
|
{
|
|
General.Settings.DynamicGridSize = !General.Settings.DynamicGridSize;
|
|
itemdynamicgridsize.Checked = General.Settings.DynamicGridSize;
|
|
buttontoggledynamicgrid.Checked = General.Settings.DynamicGridSize;
|
|
General.Interface.DisplayStatus(StatusType.Action, "Dynamic grid size is " + (General.Settings.DynamicGridSize ? "ENABLED" : "DISABLED"));
|
|
|
|
// Redraw display to show changes
|
|
if(General.Editing.Mode is ClassicMode) ((ClassicMode)General.Editing.Mode).MatchGridSizeToDisplayScale();
|
|
General.Interface.RedrawDisplay();
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("toggleautoclearsidetextures")]
|
|
internal void ToggleAutoClearSideTextures()
|
|
{
|
|
buttonautoclearsidetextures.Checked = !buttonautoclearsidetextures.Checked;
|
|
itemautoclearsidetextures.Checked = buttonautoclearsidetextures.Checked;
|
|
General.Settings.AutoClearSidedefTextures = buttonautoclearsidetextures.Checked;
|
|
DisplayStatus(StatusType.Action, "Auto removal of unused sidedef textures is " + (buttonautoclearsidetextures.Checked ? "ENABLED" : "DISABLED"));
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("viewusedtags")]
|
|
internal void ViewUsedTags()
|
|
{
|
|
TagStatisticsForm f = new TagStatisticsForm();
|
|
f.ShowDialog(this);
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("viewthingtypes")]
|
|
internal void ViewThingTypes()
|
|
{
|
|
ThingStatisticsForm f = new ThingStatisticsForm();
|
|
f.ShowDialog(this);
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("geomergeclassic")]
|
|
private void GeoMergeClassic()
|
|
{
|
|
General.Settings.MergeGeometryMode = MergeGeometryMode.CLASSIC;
|
|
UpdateToolbar();
|
|
UpdateEditMenu();
|
|
DisplayStatus(StatusType.Action, "\"Merge Dragged Vertices Only\" mode selected");
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("geomerge")]
|
|
private void GeoMerge()
|
|
{
|
|
General.Settings.MergeGeometryMode = MergeGeometryMode.MERGE;
|
|
UpdateToolbar();
|
|
UpdateEditMenu();
|
|
DisplayStatus(StatusType.Action, "\"Merge Dragged Geometry\" mode selected");
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("georeplace")]
|
|
private void GeoReplace()
|
|
{
|
|
General.Settings.MergeGeometryMode = MergeGeometryMode.REPLACE;
|
|
UpdateToolbar();
|
|
UpdateEditMenu();
|
|
DisplayStatus(StatusType.Action, "\"Replace with Dragged Geometry\" mode selected");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== View Menu
|
|
|
|
// This sets up the View menu
|
|
private void UpdateViewMenu()
|
|
{
|
|
menuview.Visible = (General.Map != null); //mxd
|
|
|
|
// Menu items
|
|
itemfullbrightness.Checked = Renderer.FullBrightness; //mxd
|
|
itemtogglegrid.Checked = General.Settings.RenderGrid; //mxd
|
|
itemtoggleinfo.Checked = IsInfoPanelExpanded;
|
|
itemtogglecomments.Visible = (General.Map != null && General.Map.UDMF); //mxd
|
|
itemtogglecomments.Checked = General.Settings.RenderComments; //mxd
|
|
itemtogglefixedthingsscale.Visible = (General.Map != null); //mxd
|
|
itemtogglefixedthingsscale.Checked = General.Settings.FixedThingsScale; //mxd
|
|
itemtogglefog.Checked = General.Settings.GZDrawFog;
|
|
itemtogglesky.Checked = General.Settings.GZDrawSky;
|
|
itemtoggleeventlines.Checked = General.Settings.GZShowEventLines;
|
|
itemtogglevisualverts.Visible = (General.Map != null && General.Map.UDMF);
|
|
itemtogglevisualverts.Checked = General.Settings.GZShowVisualVertices;
|
|
|
|
// Update Model Rendering Mode items...
|
|
foreach(ToolStripMenuItem item in itemmodelmodes.DropDownItems)
|
|
{
|
|
item.Checked = ((ModelRenderMode)item.Tag == General.Settings.GZDrawModelsMode);
|
|
if(item.Checked) itemmodelmodes.Image = item.Image;
|
|
}
|
|
|
|
// Update Dynamic Light Mode items...
|
|
foreach(ToolStripMenuItem item in itemdynlightmodes.DropDownItems)
|
|
{
|
|
item.Checked = ((LightRenderMode)item.Tag == General.Settings.GZDrawLightsMode);
|
|
if(item.Checked) itemdynlightmodes.Image = item.Image;
|
|
}
|
|
|
|
// View mode items
|
|
if(General.Map != null)
|
|
{
|
|
for(int i = 0; i < Renderer2D.NUM_VIEW_MODES; i++)
|
|
{
|
|
// Check the correct item
|
|
viewmodesbuttons[i].Checked = (i == (int)General.Map.CRenderer2D.ViewMode);
|
|
viewmodesitems[i].Checked = (i == (int)General.Map.CRenderer2D.ViewMode);
|
|
}
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("gztoggleenhancedrendering")]
|
|
public void ToggleEnhancedRendering()
|
|
{
|
|
General.Settings.EnhancedRenderingEffects = !General.Settings.EnhancedRenderingEffects;
|
|
|
|
General.Settings.GZDrawFog = General.Settings.EnhancedRenderingEffects;
|
|
General.Settings.GZDrawSky = General.Settings.EnhancedRenderingEffects;
|
|
General.Settings.GZDrawLightsMode = (General.Settings.EnhancedRenderingEffects ? LightRenderMode.ALL : LightRenderMode.NONE);
|
|
General.Settings.GZDrawModelsMode = (General.Settings.EnhancedRenderingEffects ? ModelRenderMode.ALL : ModelRenderMode.NONE);
|
|
|
|
UpdateGZDoomPanel();
|
|
UpdateViewMenu();
|
|
DisplayStatus(StatusType.Info, "Enhanced rendering effects are " + (General.Settings.EnhancedRenderingEffects ? "ENABLED" : "DISABLED"));
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("gztogglefog")]
|
|
internal void ToggleFog()
|
|
{
|
|
General.Settings.GZDrawFog = !General.Settings.GZDrawFog;
|
|
|
|
itemtogglefog.Checked = General.Settings.GZDrawFog;
|
|
buttontogglefog.Checked = General.Settings.GZDrawFog;
|
|
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Fog rendering is " + (General.Settings.GZDrawFog ? "ENABLED" : "DISABLED"));
|
|
General.MainWindow.RedrawDisplay();
|
|
General.MainWindow.UpdateGZDoomPanel();
|
|
}
|
|
|
|
//mxd
|
|
[BeginAction("gztogglesky")]
|
|
internal void ToggleSky()
|
|
{
|
|
General.Settings.GZDrawSky = !General.Settings.GZDrawSky;
|
|
|
|
itemtogglesky.Checked = General.Settings.GZDrawSky;
|
|
buttontogglesky.Checked = General.Settings.GZDrawSky;
|
|
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Sky rendering is " + (General.Settings.GZDrawSky ? "ENABLED" : "DISABLED"));
|
|
General.MainWindow.RedrawDisplay();
|
|
General.MainWindow.UpdateGZDoomPanel();
|
|
}
|
|
|
|
[BeginAction("gztoggleeventlines")]
|
|
internal void ToggleEventLines()
|
|
{
|
|
General.Settings.GZShowEventLines = !General.Settings.GZShowEventLines;
|
|
|
|
itemtoggleeventlines.Checked = General.Settings.GZShowEventLines;
|
|
buttontoggleeventlines.Checked = General.Settings.GZShowEventLines;
|
|
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Event lines are " + (General.Settings.GZShowEventLines ? "ENABLED" : "DISABLED"));
|
|
General.MainWindow.RedrawDisplay();
|
|
General.MainWindow.UpdateGZDoomPanel();
|
|
}
|
|
|
|
[BeginAction("gztogglevisualvertices")]
|
|
internal void ToggleVisualVertices()
|
|
{
|
|
General.Settings.GZShowVisualVertices = !General.Settings.GZShowVisualVertices;
|
|
|
|
itemtogglevisualverts.Checked = General.Settings.GZShowVisualVertices;
|
|
buttontogglevisualvertices.Checked = General.Settings.GZShowVisualVertices;
|
|
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Visual vertices are " + (General.Settings.GZShowVisualVertices ? "ENABLED" : "DISABLED"));
|
|
General.MainWindow.RedrawDisplay();
|
|
General.MainWindow.UpdateGZDoomPanel();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Mode Menu
|
|
|
|
// This sets up the modes menu
|
|
private void UpdateModeMenu()
|
|
{
|
|
menumode.Visible = (General.Map != null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Help Menu
|
|
|
|
// This sets up the help menu
|
|
private void UpdateHelpMenu()
|
|
{
|
|
itemhelpeditmode.Visible = (General.Map != null); //mxd
|
|
itemhelpeditmode.Enabled = (General.Map != null && General.Editing.Mode != null);
|
|
}
|
|
|
|
//mxd. Check updates clicked
|
|
private void itemhelpcheckupdates_Click(object sender, EventArgs e)
|
|
{
|
|
UpdateChecker.PerformCheck(true);
|
|
}
|
|
|
|
//mxd. Github issues clicked
|
|
private void itemhelpissues_Click(object sender, EventArgs e)
|
|
{
|
|
General.OpenWebsite("https://github.com/jewalky/GZDoom-Builder-Bugfix/issues");
|
|
}
|
|
|
|
// About clicked
|
|
private void itemhelpabout_Click(object sender, EventArgs e)
|
|
{
|
|
// Show about dialog
|
|
AboutForm aboutform = new AboutForm();
|
|
aboutform.ShowDialog(this);
|
|
}
|
|
|
|
// Reference Manual clicked
|
|
private void itemhelprefmanual_Click(object sender, EventArgs e)
|
|
{
|
|
General.ShowHelp("introduction.html");
|
|
}
|
|
|
|
// About this Editing Mode
|
|
private void itemhelpeditmode_Click(object sender, EventArgs e)
|
|
{
|
|
if((General.Map != null) && (General.Editing.Mode != null))
|
|
General.Editing.Mode.OnHelp();
|
|
}
|
|
|
|
//mxd
|
|
private void itemShortcutReference_Click(object sender, EventArgs e)
|
|
{
|
|
const string columnLabels = "<tr><td width=\"240px;\"><strong>Action</strong></td><td width=\"120px;\"><div align=\"center\"><strong>Shortcut</strong></div></td><td width=\"120px;\"><div align=\"center\"><strong>Modifiers</strong></div></td><td><strong>Description</strong></td></tr>";
|
|
const string categoryPadding = "<tr><td colspan=\"4\"></td></tr>";
|
|
const string categoryStart = "<tr><td colspan=\"4\" bgcolor=\"#333333\"><strong style=\"color:#FFFFFF\">";
|
|
const string categoryEnd = "</strong><div style=\"text-align:right; float:right\"><a style=\"color:#FFFFFF\" href=\"#top\">[to top]</a></div></td></tr>";
|
|
const string fileName = "GZDB Actions Reference.html";
|
|
|
|
Actions.Action[] actions = General.Actions.GetAllActions();
|
|
Dictionary<string, List<Actions.Action>> sortedActions = new Dictionary<string, List<Actions.Action>>(StringComparer.Ordinal);
|
|
|
|
foreach(Actions.Action action in actions)
|
|
{
|
|
if(!sortedActions.ContainsKey(action.Category))
|
|
sortedActions.Add(action.Category, new List<Actions.Action>());
|
|
sortedActions[action.Category].Add(action);
|
|
}
|
|
|
|
System.Text.StringBuilder html = new System.Text.StringBuilder();
|
|
|
|
//head
|
|
html.AppendLine("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" + Environment.NewLine +
|
|
"<html xmlns=\"http://www.w3.org/1999/xhtml\">" + Environment.NewLine +
|
|
"<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><title>GZDoom Builder Actions Reference</title></head>" + Environment.NewLine +
|
|
"<body bgcolor=\"#666666\">" + Environment.NewLine +
|
|
"<div style=\"padding-left:60px; padding-right:60px; padding-top:20px; padding-bottom:20px;\">" + Environment.NewLine);
|
|
|
|
//table header
|
|
html.AppendLine("<table bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" cellspacing=\"6\" cellpadding=\"6\" style=\"font-family: 'Trebuchet MS',georgia,Verdana,Sans-serif;\">" + Environment.NewLine +
|
|
"<tr><td colspan=\"4\" bgcolor=\"#333333\"><span style=\"font-size: 24px\"><a name=\"top\" id=\"top\"></a><strong style=\"color:#FFFFFF\">GZDoom Builder Actions Reference</strong></span></td></tr>");
|
|
|
|
//categories navigator
|
|
List<string> catnames = new List<string>(sortedActions.Count);
|
|
int counter = 0;
|
|
int numActions = 0;
|
|
foreach(KeyValuePair<string, List<Actions.Action>> category in sortedActions)
|
|
{
|
|
catnames.Add("<a href=\"#cat" + (counter++) + "\">" + General.Actions.Categories[category.Key] + "</a>");
|
|
numActions += category.Value.Count;
|
|
}
|
|
|
|
html.AppendLine("<tr><td colspan=\"4\"><strong>Total number of actions:</strong> " + numActions + "<br/><strong>Jump to:</strong> ");
|
|
html.AppendLine(string.Join(" | ", catnames.ToArray()));
|
|
html.AppendLine("</td></tr>" + Environment.NewLine);
|
|
|
|
//add descriptions
|
|
counter = 0;
|
|
foreach(KeyValuePair<string, List<Actions.Action>> category in sortedActions)
|
|
{
|
|
//add category title
|
|
html.AppendLine(categoryPadding);
|
|
html.AppendLine(categoryStart + "<a name=\"cat" + counter + "\" id=\"cat" + counter + "\"></a>" + General.Actions.Categories[category.Key] + categoryEnd);
|
|
html.AppendLine(columnLabels);
|
|
counter++;
|
|
|
|
Dictionary<string, Actions.Action> actionsByTitle = new Dictionary<string, Actions.Action>(StringComparer.Ordinal);
|
|
List<string> actionTitles = new List<string>();
|
|
|
|
foreach(Actions.Action action in category.Value)
|
|
{
|
|
actionsByTitle.Add(action.Title, action);
|
|
actionTitles.Add(action.Title);
|
|
}
|
|
|
|
actionTitles.Sort();
|
|
|
|
foreach(string title in actionTitles)
|
|
{
|
|
Actions.Action a = actionsByTitle[title];
|
|
List<string> modifiers = new List<string>();
|
|
|
|
html.AppendLine("<tr>");
|
|
html.AppendLine("<td>" + title + "</td>");
|
|
html.AppendLine("<td><div align=\"center\">" + Actions.Action.GetShortcutKeyDesc(a.ShortcutKey) + "</div></td>");
|
|
|
|
if(a.DisregardControl) modifiers.Add("Ctrl");
|
|
if(a.DisregardAlt) modifiers.Add("Alt");
|
|
if(a.DisregardShift) modifiers.Add("Shift");
|
|
|
|
html.AppendLine("<td><div align=\"center\">" + string.Join(", ", modifiers.ToArray()) + "</div></td>");
|
|
html.AppendLine("<td>" + a.Description + "</td>");
|
|
html.AppendLine("</tr>");
|
|
}
|
|
}
|
|
|
|
//add bottom
|
|
html.AppendLine("</table></div></body></html>");
|
|
|
|
//write
|
|
string path;
|
|
try
|
|
{
|
|
path = Path.Combine(General.AppPath, fileName);
|
|
using(StreamWriter writer = File.CreateText(path))
|
|
{
|
|
writer.Write(html.ToString());
|
|
}
|
|
}
|
|
catch(Exception)
|
|
{
|
|
//Configurtions path SHOULD be accessible and not read-only, right?
|
|
path = Path.Combine(General.SettingsPath, fileName);
|
|
using(StreamWriter writer = File.CreateText(path))
|
|
{
|
|
writer.Write(html.ToString());
|
|
}
|
|
}
|
|
|
|
//open file
|
|
DisplayStatus(StatusType.Info, "Shortcut reference saved to \"" + path + "\"");
|
|
Process.Start(path);
|
|
}
|
|
|
|
//mxd
|
|
private void itemopenconfigfolder_Click(object sender, EventArgs e)
|
|
{
|
|
if(Directory.Exists(General.SettingsPath)) Process.Start(General.SettingsPath);
|
|
else General.ShowErrorMessage("Huh? Where did Settings folder go?.." + Environment.NewLine
|
|
+ "I swear it was here: \"" + General.SettingsPath + "\"!", MessageBoxButtons.OK); // I don't think this will ever happen
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Prefabs Menu
|
|
|
|
// This sets up the prefabs menu
|
|
private void UpdatePrefabsMenu()
|
|
{
|
|
menuprefabs.Visible = (General.Map != null); //mxd
|
|
|
|
// Enable/disable items
|
|
itemcreateprefab.Enabled = (General.Map != null) && (General.Editing.Mode != null) && General.Editing.Mode.Attributes.AllowCopyPaste;
|
|
iteminsertprefabfile.Enabled = (General.Map != null) && (General.Editing.Mode != null) && General.Editing.Mode.Attributes.AllowCopyPaste;
|
|
iteminsertpreviousprefab.Enabled = (General.Map != null) && (General.Editing.Mode != null) && General.Map.CopyPaste.IsPreviousPrefabAvailable && General.Editing.Mode.Attributes.AllowCopyPaste;
|
|
|
|
// Toolbar icons
|
|
buttoninsertprefabfile.Enabled = iteminsertprefabfile.Enabled;
|
|
buttoninsertpreviousprefab.Enabled = iteminsertpreviousprefab.Enabled;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Tools Menu
|
|
|
|
// This sets up the tools menu
|
|
private void UpdateToolsMenu()
|
|
{
|
|
//mxd. Enable/disable items
|
|
bool enabled = (General.Map != null);
|
|
itemreloadresources.Visible = enabled;
|
|
seperatortoolsconfig.Visible = enabled;
|
|
itemsavescreenshot.Visible = enabled;
|
|
itemsaveeditareascreenshot.Visible = enabled;
|
|
separatortoolsscreenshots.Visible = enabled;
|
|
itemtestmap.Visible = enabled;
|
|
|
|
bool supported = (enabled && !string.IsNullOrEmpty(General.Map.Config.DecorateGames));
|
|
itemReloadGldefs.Visible = supported;
|
|
itemReloadModedef.Visible = supported;
|
|
}
|
|
|
|
// Errors and Warnings
|
|
[BeginAction("showerrors")]
|
|
internal void ShowErrors()
|
|
{
|
|
ErrorsForm errform = new ErrorsForm();
|
|
errform.ShowDialog(this);
|
|
errform.Dispose();
|
|
//mxd
|
|
SetWarningsCount(General.ErrorLogger.ErrorsCount, false);
|
|
}
|
|
|
|
// Game Configuration action
|
|
[BeginAction("configuration")]
|
|
internal void ShowConfiguration()
|
|
{
|
|
// Show configuration dialog
|
|
ShowConfigurationPage(-1);
|
|
}
|
|
|
|
// This shows the configuration on a specific page
|
|
internal void ShowConfigurationPage(int pageindex)
|
|
{
|
|
// Show configuration dialog
|
|
ConfigForm cfgform = new ConfigForm();
|
|
if(pageindex > -1) cfgform.ShowTab(pageindex);
|
|
if(cfgform.ShowDialog(this) == DialogResult.OK)
|
|
{
|
|
// Update stuff
|
|
SetupInterface();
|
|
UpdateInterface();
|
|
General.Editing.UpdateCurrentEditModes();
|
|
General.Plugins.ProgramReconfigure();
|
|
|
|
// Save program configuration
|
|
General.SaveSettings();
|
|
|
|
// Reload resources if a map is open
|
|
if ((General.Map != null) && cfgform.ReloadResources) General.Actions.InvokeAction("builder_reloadresources");
|
|
|
|
// Redraw display
|
|
RedrawDisplay();
|
|
}
|
|
|
|
// Done
|
|
cfgform.Dispose();
|
|
}
|
|
|
|
// Preferences action
|
|
[BeginAction("preferences")]
|
|
internal void ShowPreferences()
|
|
{
|
|
// Show preferences dialog
|
|
PreferencesForm prefform = new PreferencesForm();
|
|
if(prefform.ShowDialog(this) == DialogResult.OK)
|
|
{
|
|
// Update stuff
|
|
SetupInterface();
|
|
UpdateInterface();
|
|
ApplyShortcutKeys();
|
|
General.Colors.CreateCorrectionTable();
|
|
General.Plugins.ProgramReconfigure();
|
|
|
|
// Save program configuration
|
|
General.SaveSettings();
|
|
|
|
// Map opened?
|
|
if(General.Map != null)
|
|
{
|
|
// Reload resources!
|
|
if(General.Map.ScriptEditor != null) General.Map.ScriptEditor.Editor.RefreshSettings();
|
|
General.Map.Graphics.SetupSettings();
|
|
General.Map.UpdateConfiguration();
|
|
if(prefform.ReloadResources) General.Actions.InvokeAction("builder_reloadresources");
|
|
}
|
|
|
|
// Redraw display
|
|
RedrawDisplay();
|
|
}
|
|
|
|
// Done
|
|
prefform.Dispose();
|
|
}
|
|
|
|
//mxd
|
|
internal void SaveScreenshot(bool activeControlOnly)
|
|
{
|
|
//pick a valid folder
|
|
string folder = General.Settings.ScreenshotsPath;
|
|
if(!Directory.Exists(folder))
|
|
{
|
|
if(folder != General.DefaultScreenshotsPath
|
|
&& General.ShowErrorMessage("Screenshots save path \"" + folder
|
|
+ "\" does not exist!\nPress OK to save to the default folder (\""
|
|
+ General.DefaultScreenshotsPath
|
|
+ "\").\nPress Cancel to abort.", MessageBoxButtons.OKCancel) == DialogResult.Cancel) return;
|
|
|
|
|
|
folder = General.DefaultScreenshotsPath;
|
|
if(!Directory.Exists(folder)) Directory.CreateDirectory(folder);
|
|
}
|
|
|
|
// Create name and bounds
|
|
string name;
|
|
Rectangle bounds;
|
|
bool displayextrainfo = false;
|
|
string mapname = (General.Map != null ? Path.GetFileNameWithoutExtension(General.Map.FileTitle) : General.ThisAssembly.GetName().Name);
|
|
|
|
if(activeControlOnly)
|
|
{
|
|
if(Form.ActiveForm != null && Form.ActiveForm != this)
|
|
{
|
|
name = mapname + " (" + Form.ActiveForm.Text + ") at ";
|
|
bounds = (Form.ActiveForm.WindowState == FormWindowState.Maximized ?
|
|
Screen.GetWorkingArea(Form.ActiveForm) :
|
|
Form.ActiveForm.Bounds);
|
|
}
|
|
else
|
|
{
|
|
name = mapname + " (edit area) at ";
|
|
bounds = this.display.Bounds;
|
|
bounds.Offset(this.PointToScreen(new Point()));
|
|
displayextrainfo = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
name = mapname + " at ";
|
|
bounds = (this.WindowState == FormWindowState.Maximized ? Screen.GetWorkingArea(this) : this.Bounds);
|
|
}
|
|
|
|
Point cursorLocation = Point.Empty;
|
|
//dont want to render the cursor in VisualMode
|
|
if(General.Editing.Mode == null || !(General.Editing.Mode is VisualMode))
|
|
cursorLocation = Cursor.Position - new Size(bounds.Location);
|
|
|
|
//create path
|
|
string date = DateTime.Now.ToString("yyyy.MM.dd HH-mm-ss.fff");
|
|
string revision = (General.DebugBuild ? "DEVBUILD" : "R" + General.ThisAssembly.GetName().Version.MinorRevision);
|
|
string path = Path.Combine(folder, name + date + " [" + revision + "].jpg");
|
|
|
|
//save image
|
|
using(Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
|
|
{
|
|
using(Graphics g = Graphics.FromImage(bitmap))
|
|
{
|
|
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
|
|
|
|
//draw the cursor
|
|
if(!cursorLocation.IsEmpty) g.DrawImage(Resources.Cursor, cursorLocation);
|
|
|
|
//gather some info
|
|
string info;
|
|
if(displayextrainfo && General.Editing.Mode != null)
|
|
{
|
|
info = General.Map.FileTitle + " | " + General.Map.Options.CurrentName + " | ";
|
|
|
|
//get map coordinates
|
|
if(General.Editing.Mode is ClassicMode)
|
|
{
|
|
Vector2D pos = ((ClassicMode) General.Editing.Mode).MouseMapPos;
|
|
|
|
//mouse inside the view?
|
|
if(pos.IsFinite())
|
|
{
|
|
info += "X:" + Math.Round(pos.x) + " Y:" + Math.Round(pos.y);
|
|
}
|
|
else
|
|
{
|
|
info += "X:" + Math.Round(General.Map.Renderer2D.TranslateX) + " Y:" + Math.Round(General.Map.Renderer2D.TranslateY);
|
|
}
|
|
}
|
|
else
|
|
{ //should be visual mode
|
|
info += "X:" + Math.Round(General.Map.VisualCamera.Position.x) + " Y:" + Math.Round(General.Map.VisualCamera.Position.y) + " Z:" + Math.Round(General.Map.VisualCamera.Position.z);
|
|
}
|
|
|
|
//add the revision number
|
|
info += " | " + revision;
|
|
}
|
|
else
|
|
{
|
|
//just use the revision number
|
|
info = revision;
|
|
}
|
|
|
|
//draw info
|
|
Font font = new Font("Tahoma", 10);
|
|
SizeF rect = g.MeasureString(info, font);
|
|
float px = bounds.Width - rect.Width - 4;
|
|
float py = 4;
|
|
|
|
g.FillRectangle(Brushes.Black, px, py, rect.Width, rect.Height + 3);
|
|
using(SolidBrush brush = new SolidBrush(Color.White))
|
|
{
|
|
g.DrawString(info, font, brush, px + 2, py + 2);
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
ImageCodecInfo jpegCodec = null;
|
|
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
|
|
foreach(ImageCodecInfo codec in codecs)
|
|
{
|
|
if(codec.FormatID == ImageFormat.Jpeg.Guid)
|
|
{
|
|
jpegCodec = codec;
|
|
break;
|
|
}
|
|
}
|
|
|
|
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, 90L);
|
|
EncoderParameters encoderParams = new EncoderParameters(1);
|
|
encoderParams.Param[0] = qualityParam;
|
|
|
|
bitmap.Save(path, jpegCodec, encoderParams);
|
|
DisplayStatus(StatusType.Info, "Screenshot saved to \"" + path + "\"");
|
|
}
|
|
catch(ExternalException e)
|
|
{
|
|
DisplayStatus(StatusType.Warning, "Failed to save screenshot...");
|
|
General.ErrorLogger.Add(ErrorType.Error, "Failed to save screenshot: " + e.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Models and Lights mode (mxd)
|
|
|
|
private void ChangeModelRenderingMode(object sender, EventArgs e)
|
|
{
|
|
General.Settings.GZDrawModelsMode = (ModelRenderMode)((ToolStripMenuItem)sender).Tag;
|
|
|
|
switch(General.Settings.GZDrawModelsMode)
|
|
{
|
|
case ModelRenderMode.NONE:
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Models rendering mode: NONE");
|
|
break;
|
|
|
|
case ModelRenderMode.SELECTION:
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Models rendering mode: SELECTION ONLY");
|
|
break;
|
|
|
|
case ModelRenderMode.ACTIVE_THINGS_FILTER:
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Models rendering mode: ACTIVE THINGS FILTER ONLY");
|
|
break;
|
|
|
|
case ModelRenderMode.ALL:
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Models rendering mode: ALL");
|
|
break;
|
|
}
|
|
|
|
UpdateViewMenu();
|
|
UpdateGZDoomPanel();
|
|
RedrawDisplay();
|
|
}
|
|
|
|
private void ChangeLightRenderingMode(object sender, EventArgs e)
|
|
{
|
|
General.Settings.GZDrawLightsMode = (LightRenderMode)((ToolStripMenuItem)sender).Tag;
|
|
|
|
switch(General.Settings.GZDrawLightsMode)
|
|
{
|
|
case LightRenderMode.NONE:
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Dynamic lights rendering mode: NONE");
|
|
break;
|
|
|
|
case LightRenderMode.ALL:
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Models rendering mode: ALL");
|
|
break;
|
|
|
|
case LightRenderMode.ALL_ANIMATED:
|
|
General.MainWindow.DisplayStatus(StatusType.Action, "Models rendering mode: ANIMATED");
|
|
break;
|
|
}
|
|
|
|
UpdateViewMenu();
|
|
UpdateGZDoomPanel();
|
|
RedrawDisplay();
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region ================== Info Panels
|
|
|
|
// This toggles the panel expanded / collapsed
|
|
[BeginAction("toggleinfopanel")]
|
|
internal void ToggleInfoPanel()
|
|
{
|
|
if(IsInfoPanelExpanded)
|
|
{
|
|
panelinfo.Height = buttontoggleinfo.Height + buttontoggleinfo.Top;
|
|
buttontoggleinfo.Image = Resources.InfoPanelExpand; //mxd
|
|
if(linedefinfo.Visible) linedefinfo.Hide();
|
|
if(vertexinfo.Visible) vertexinfo.Hide();
|
|
if(sectorinfo.Visible) sectorinfo.Hide();
|
|
if(thinginfo.Visible) thinginfo.Hide();
|
|
modename.Visible = false;
|
|
#if DEBUG
|
|
console.Visible = false; //mxd
|
|
#endif
|
|
statistics.Visible = false; //mxd
|
|
labelcollapsedinfo.Visible = true;
|
|
itemtoggleinfo.Checked = false;
|
|
}
|
|
else
|
|
{
|
|
panelinfo.Height = heightpanel1.Height;
|
|
buttontoggleinfo.Image = Resources.InfoPanelCollapse; //mxd
|
|
labelcollapsedinfo.Visible = false;
|
|
itemtoggleinfo.Checked = true;
|
|
if(lastinfoobject is Vertex) ShowVertexInfo((Vertex)lastinfoobject);
|
|
else if(lastinfoobject is Linedef) ShowLinedefInfo((Linedef)lastinfoobject);
|
|
else if(lastinfoobject is Sector) ShowSectorInfo((Sector)lastinfoobject);
|
|
else if(lastinfoobject is Thing) ShowThingInfo((Thing)lastinfoobject);
|
|
else HideInfo();
|
|
}
|
|
|
|
dockerspanel.Height = dockersspace.Height; //mxd
|
|
FocusDisplay();
|
|
}
|
|
|
|
// Mouse released on info panel toggle button
|
|
private void buttontoggleinfo_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
dockerspanel.Height = dockersspace.Height; //mxd
|
|
FocusDisplay();
|
|
}
|
|
|
|
// This displays the current mode name
|
|
internal void DisplayModeName(string name)
|
|
{
|
|
if(lastinfoobject == null)
|
|
{
|
|
labelcollapsedinfo.Text = name;
|
|
labelcollapsedinfo.Refresh();
|
|
}
|
|
modename.Text = name;
|
|
modename.Refresh();
|
|
}
|
|
|
|
// This hides all info panels
|
|
public void HideInfo()
|
|
{
|
|
// Hide them all
|
|
// [ZZ]
|
|
panelinfo.SuspendLayout();
|
|
bool showModeName = ((General.Map != null) && IsInfoPanelExpanded); //mxd
|
|
lastinfoobject = null;
|
|
if(linedefinfo.Visible) linedefinfo.Hide();
|
|
if(vertexinfo.Visible) vertexinfo.Hide();
|
|
if(sectorinfo.Visible) sectorinfo.Hide();
|
|
if(thinginfo.Visible) thinginfo.Hide();
|
|
labelcollapsedinfo.Text = modename.Text;
|
|
labelcollapsedinfo.Refresh();
|
|
#if DEBUG
|
|
console.Visible = true;
|
|
#else
|
|
modename.Visible = showModeName;
|
|
#endif
|
|
modename.Refresh();
|
|
statistics.Visible = showModeName; //mxd
|
|
|
|
//mxd. Let the plugins know
|
|
General.Plugins.OnHighlightLost();
|
|
// [ZZ]
|
|
panelinfo.ResumeLayout();
|
|
}
|
|
|
|
// This refreshes info
|
|
public void RefreshInfo()
|
|
{
|
|
if(lastinfoobject is Vertex) ShowVertexInfo((Vertex)lastinfoobject);
|
|
else if(lastinfoobject is Linedef) ShowLinedefInfo((Linedef)lastinfoobject);
|
|
else if(lastinfoobject is Sector) ShowSectorInfo((Sector)lastinfoobject);
|
|
else if(lastinfoobject is Thing) ShowThingInfo((Thing)lastinfoobject);
|
|
|
|
//mxd. Let the plugins know
|
|
// [ZZ]
|
|
panelinfo.SuspendLayout();
|
|
General.Plugins.OnHighlightRefreshed(lastinfoobject);
|
|
panelinfo.ResumeLayout();
|
|
}
|
|
|
|
//mxd
|
|
public void ShowHints(string hintsText)
|
|
{
|
|
if(!string.IsNullOrEmpty(hintsText))
|
|
{
|
|
hintsPanel.SetHints(hintsText);
|
|
}
|
|
else
|
|
{
|
|
ClearHints();
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
public void ClearHints()
|
|
{
|
|
hintsPanel.ClearHints();
|
|
}
|
|
|
|
//mxd
|
|
internal void AddHintsDocker()
|
|
{
|
|
if(!dockerspanel.Contains(hintsDocker)) dockerspanel.Add(hintsDocker, false);
|
|
}
|
|
|
|
//mxd
|
|
internal void RemoveHintsDocker()
|
|
{
|
|
dockerspanel.Remove(hintsDocker);
|
|
}
|
|
|
|
//mxd. Show linedef info
|
|
public void ShowLinedefInfo(Linedef l)
|
|
{
|
|
ShowLinedefInfo(l, null);
|
|
}
|
|
|
|
//mxd. Show linedef info and highlight given sidedef
|
|
public void ShowLinedefInfo(Linedef l, Sidedef highlightside)
|
|
{
|
|
if(l.IsDisposed)
|
|
{
|
|
HideInfo();
|
|
return;
|
|
}
|
|
|
|
// [ZZ]
|
|
panelinfo.SuspendLayout();
|
|
lastinfoobject = l;
|
|
modename.Visible = false;
|
|
#if DEBUG
|
|
console.Visible = console.AlwaysOnTop; //mxd
|
|
#endif
|
|
statistics.Visible = false; //mxd
|
|
if(vertexinfo.Visible) vertexinfo.Hide();
|
|
if(sectorinfo.Visible) sectorinfo.Hide();
|
|
if(thinginfo.Visible) thinginfo.Hide();
|
|
if(IsInfoPanelExpanded) linedefinfo.ShowInfo(l, highlightside);
|
|
|
|
// Show info on collapsed label
|
|
if(General.Map.Config.LinedefActions.ContainsKey(l.Action))
|
|
{
|
|
LinedefActionInfo act = General.Map.Config.LinedefActions[l.Action];
|
|
labelcollapsedinfo.Text = act.ToString();
|
|
}
|
|
else if(l.Action == 0)
|
|
{
|
|
labelcollapsedinfo.Text = l.Action + " - None";
|
|
}
|
|
else
|
|
{
|
|
labelcollapsedinfo.Text = l.Action + " - Unknown";
|
|
}
|
|
labelcollapsedinfo.Refresh();
|
|
|
|
//mxd. let the plugins know
|
|
General.Plugins.OnHighlightLinedef(l);
|
|
// [ZZ]
|
|
panelinfo.ResumeLayout();
|
|
}
|
|
|
|
// Show vertex info
|
|
public void ShowVertexInfo(Vertex v)
|
|
{
|
|
if(v.IsDisposed)
|
|
{
|
|
HideInfo();
|
|
return;
|
|
}
|
|
|
|
// [ZZ]
|
|
panelinfo.SuspendLayout();
|
|
lastinfoobject = v;
|
|
modename.Visible = false;
|
|
#if DEBUG
|
|
console.Visible = console.AlwaysOnTop; //mxd
|
|
#endif
|
|
statistics.Visible = false; //mxd
|
|
if(linedefinfo.Visible) linedefinfo.Hide();
|
|
if(sectorinfo.Visible) sectorinfo.Hide();
|
|
if(thinginfo.Visible) thinginfo.Hide();
|
|
if(IsInfoPanelExpanded) vertexinfo.ShowInfo(v);
|
|
|
|
// Show info on collapsed label
|
|
labelcollapsedinfo.Text = v.Position.x.ToString("0.##") + ", " + v.Position.y.ToString("0.##");
|
|
labelcollapsedinfo.Refresh();
|
|
|
|
//mxd. let the plugins know
|
|
General.Plugins.OnHighlightVertex(v);
|
|
// [ZZ]
|
|
panelinfo.ResumeLayout();
|
|
}
|
|
|
|
//mxd. Show sector info
|
|
public void ShowSectorInfo(Sector s)
|
|
{
|
|
ShowSectorInfo(s, false, false);
|
|
}
|
|
|
|
// Show sector info
|
|
public void ShowSectorInfo(Sector s, bool highlightceiling, bool highlightfloor)
|
|
{
|
|
if(s.IsDisposed)
|
|
{
|
|
HideInfo();
|
|
return;
|
|
}
|
|
|
|
// [ZZ]
|
|
panelinfo.SuspendLayout();
|
|
lastinfoobject = s;
|
|
modename.Visible = false;
|
|
#if DEBUG
|
|
console.Visible = console.AlwaysOnTop; //mxd
|
|
#endif
|
|
statistics.Visible = false; //mxd
|
|
if(linedefinfo.Visible) linedefinfo.Hide();
|
|
if(vertexinfo.Visible) vertexinfo.Hide();
|
|
if(thinginfo.Visible) thinginfo.Hide();
|
|
if(IsInfoPanelExpanded) sectorinfo.ShowInfo(s, highlightceiling, highlightfloor); //mxd
|
|
|
|
// Show info on collapsed label
|
|
if(General.Map.Config.SectorEffects.ContainsKey(s.Effect))
|
|
labelcollapsedinfo.Text = General.Map.Config.SectorEffects[s.Effect].ToString();
|
|
else if(s.Effect == 0)
|
|
labelcollapsedinfo.Text = s.Effect + " - Normal";
|
|
else
|
|
labelcollapsedinfo.Text = s.Effect + " - Unknown";
|
|
|
|
labelcollapsedinfo.Refresh();
|
|
|
|
//mxd. let the plugins know
|
|
General.Plugins.OnHighlightSector(s);
|
|
// [ZZ]
|
|
panelinfo.ResumeLayout();
|
|
}
|
|
|
|
// Show thing info
|
|
public void ShowThingInfo(Thing t)
|
|
{
|
|
if(t.IsDisposed)
|
|
{
|
|
HideInfo();
|
|
return;
|
|
}
|
|
|
|
// [ZZ]
|
|
panelinfo.SuspendLayout();
|
|
lastinfoobject = t;
|
|
modename.Visible = false;
|
|
#if DEBUG
|
|
console.Visible = console.AlwaysOnTop; //mxd
|
|
#endif
|
|
statistics.Visible = false; //mxd
|
|
if(linedefinfo.Visible) linedefinfo.Hide();
|
|
if(vertexinfo.Visible) vertexinfo.Hide();
|
|
if(sectorinfo.Visible) sectorinfo.Hide();
|
|
if(IsInfoPanelExpanded) thinginfo.ShowInfo(t);
|
|
|
|
// Show info on collapsed label
|
|
ThingTypeInfo ti = General.Map.Data.GetThingInfo(t.Type);
|
|
labelcollapsedinfo.Text = t.Type + " - " + ti.Title;
|
|
labelcollapsedinfo.Refresh();
|
|
|
|
//mxd. let the plugins know
|
|
General.Plugins.OnHighlightThing(t);
|
|
// [ZZ]
|
|
panelinfo.ResumeLayout();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Dialogs
|
|
|
|
// This browses for a texture
|
|
// Returns the new texture name or the same texture name when cancelled
|
|
public string BrowseTexture(IWin32Window owner, string initialvalue)
|
|
{
|
|
return TextureBrowserForm.Browse(owner, initialvalue, false);//mxd
|
|
}
|
|
|
|
// This browses for a flat
|
|
// Returns the new flat name or the same flat name when cancelled
|
|
public string BrowseFlat(IWin32Window owner, string initialvalue)
|
|
{
|
|
return TextureBrowserForm.Browse(owner, initialvalue, true); //mxd. was FlatBrowserForm
|
|
}
|
|
|
|
// This browses the lindef types
|
|
// Returns the new action or the same action when cancelled
|
|
public int BrowseLinedefActions(IWin32Window owner, int initialvalue)
|
|
{
|
|
return ActionBrowserForm.BrowseAction(owner, initialvalue, false);
|
|
}
|
|
|
|
//mxd. This browses the lindef types
|
|
// Returns the new action or the same action when cancelled
|
|
public int BrowseLinedefActions(IWin32Window owner, int initialvalue, bool addanyaction)
|
|
{
|
|
return ActionBrowserForm.BrowseAction(owner, initialvalue, addanyaction);
|
|
}
|
|
|
|
// This browses sector effects
|
|
// Returns the new effect or the same effect when cancelled
|
|
public int BrowseSectorEffect(IWin32Window owner, int initialvalue)
|
|
{
|
|
return EffectBrowserForm.BrowseEffect(owner, initialvalue, false);
|
|
}
|
|
|
|
//mxd. This browses sector effects
|
|
// Returns the new effect or the same effect when cancelled
|
|
public int BrowseSectorEffect(IWin32Window owner, int initialvalue, bool addanyeffect)
|
|
{
|
|
return EffectBrowserForm.BrowseEffect(owner, initialvalue, addanyeffect);
|
|
}
|
|
|
|
// This browses thing types
|
|
// Returns the new thing type or the same thing type when cancelled
|
|
public int BrowseThingType(IWin32Window owner, int initialvalue)
|
|
{
|
|
return ThingBrowserForm.BrowseThing(owner, initialvalue);
|
|
}
|
|
|
|
//mxd
|
|
public DialogResult ShowEditVertices(ICollection<Vertex> vertices)
|
|
{
|
|
return ShowEditVertices(vertices, true);
|
|
}
|
|
|
|
//mxd. This shows the dialog to edit vertices
|
|
public DialogResult ShowEditVertices(ICollection<Vertex> vertices, bool allowPositionChange)
|
|
{
|
|
// Show sector edit dialog
|
|
VertexEditForm f = new VertexEditForm();
|
|
DisableProcessing(); //mxd
|
|
#if NO_WIN32
|
|
BreakExclusiveMouseInput();
|
|
f.Closed += (object sender, EventArgs e) => {
|
|
ResumeExclusiveMouseInput();
|
|
EnableProcessing(); //mxd
|
|
};
|
|
#endif
|
|
f.Setup(vertices, allowPositionChange);
|
|
#if !NO_WIN32
|
|
EnableProcessing(); //mxd
|
|
#endif
|
|
f.OnValuesChanged += EditForm_OnValuesChanged;
|
|
editformopen = true; //mxd
|
|
DialogResult result = f.ShowDialog(this);
|
|
editformopen = false; //mxd
|
|
f.Dispose();
|
|
|
|
return result;
|
|
}
|
|
|
|
// This shows the dialog to edit lines
|
|
public DialogResult ShowEditLinedefs(ICollection<Linedef> lines)
|
|
{
|
|
return ShowEditLinedefs(lines, false, false);
|
|
}
|
|
|
|
// This shows the dialog to edit lines
|
|
public DialogResult ShowEditLinedefs(ICollection<Linedef> lines, bool selectfront, bool selectback)
|
|
{
|
|
DialogResult result;
|
|
|
|
// Show line edit dialog
|
|
if(General.Map.UDMF) //mxd
|
|
{
|
|
LinedefEditFormUDMF f = new LinedefEditFormUDMF(selectfront, selectback);
|
|
DisableProcessing(); //mxd
|
|
#if NO_WIN32
|
|
BreakExclusiveMouseInput();
|
|
f.Closed += (object sender, EventArgs e) => {
|
|
ResumeExclusiveMouseInput();
|
|
EnableProcessing(); //mxd
|
|
};
|
|
#endif
|
|
f.Setup(lines, selectfront, selectback);
|
|
#if !NO_WIN32
|
|
EnableProcessing();
|
|
#endif
|
|
f.OnValuesChanged += EditForm_OnValuesChanged;
|
|
editformopen = true; //mxd
|
|
result = f.ShowDialog(this);
|
|
editformopen = false; //mxd
|
|
f.Dispose();
|
|
}
|
|
else
|
|
{
|
|
LinedefEditForm f = new LinedefEditForm();
|
|
DisableProcessing(); //mxd
|
|
#if NO_WIN32
|
|
BreakExclusiveMouseInput();
|
|
f.Closed += (object sender, EventArgs e) => {
|
|
ResumeExclusiveMouseInput();
|
|
EnableProcessing(); //mxd
|
|
};
|
|
#endif
|
|
f.Setup(lines);
|
|
#if !NO_WIN32
|
|
EnableProcessing();
|
|
#endif
|
|
f.OnValuesChanged += EditForm_OnValuesChanged;
|
|
editformopen = true; //mxd
|
|
result = f.ShowDialog(this);
|
|
editformopen = false; //mxd
|
|
f.Dispose();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// This shows the dialog to edit sectors
|
|
public DialogResult ShowEditSectors(ICollection<Sector> sectors)
|
|
{
|
|
DialogResult result;
|
|
|
|
// Show sector edit dialog
|
|
if(General.Map.UDMF) //mxd
|
|
{
|
|
SectorEditFormUDMF f = new SectorEditFormUDMF();
|
|
DisableProcessing(); //mxd
|
|
#if NO_WIN32
|
|
BreakExclusiveMouseInput();
|
|
f.Closed += (object sender, EventArgs e) => {
|
|
ResumeExclusiveMouseInput();
|
|
EnableProcessing(); //mxd
|
|
};
|
|
#endif
|
|
f.Setup(sectors);
|
|
#if !NO_WIN32
|
|
EnableProcessing(); //mxd
|
|
#endif
|
|
f.OnValuesChanged += EditForm_OnValuesChanged;
|
|
editformopen = true; //mxd
|
|
result = f.ShowDialog(this);
|
|
editformopen = false; //mxd
|
|
f.Dispose();
|
|
}
|
|
else
|
|
{
|
|
SectorEditForm f = new SectorEditForm();
|
|
DisableProcessing(); //mxd
|
|
#if NO_WIN32
|
|
BreakExclusiveMouseInput();
|
|
f.Closed += (object sender, EventArgs e) => {
|
|
ResumeExclusiveMouseInput();
|
|
EnableProcessing(); //mxd
|
|
};
|
|
#endif
|
|
f.Setup(sectors);
|
|
#if !NO_WIN32
|
|
EnableProcessing(); //mxd
|
|
#endif
|
|
f.OnValuesChanged += EditForm_OnValuesChanged;
|
|
editformopen = true; //mxd
|
|
result = f.ShowDialog(this);
|
|
editformopen = false; //mxd
|
|
f.Dispose();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// This shows the dialog to edit things
|
|
public DialogResult ShowEditThings(ICollection<Thing> things)
|
|
{
|
|
DialogResult result;
|
|
|
|
// Show thing edit dialog
|
|
if(General.Map.UDMF)
|
|
{
|
|
ThingEditFormUDMF f = new ThingEditFormUDMF();
|
|
DisableProcessing(); //mxd
|
|
#if NO_WIN32
|
|
BreakExclusiveMouseInput();
|
|
f.Closed += (object sender, EventArgs e) => {
|
|
ResumeExclusiveMouseInput();
|
|
EnableProcessing(); //mxd
|
|
};
|
|
#endif
|
|
f.Setup(things);
|
|
#if !NO_WIN32
|
|
EnableProcessing(); //mxd
|
|
#endif
|
|
f.OnValuesChanged += EditForm_OnValuesChanged;
|
|
editformopen = true; //mxd
|
|
result = f.ShowDialog(this);
|
|
editformopen = false; //mxd
|
|
f.Dispose();
|
|
}
|
|
else
|
|
{
|
|
ThingEditForm f = new ThingEditForm();
|
|
DisableProcessing(); //mxd
|
|
#if NO_WIN32
|
|
BreakExclusiveMouseInput();
|
|
f.Closed += (object sender, EventArgs e) => {
|
|
ResumeExclusiveMouseInput();
|
|
EnableProcessing(); //mxd
|
|
};
|
|
#endif
|
|
f.Setup(things);
|
|
#if !NO_WIN32
|
|
EnableProcessing(); //mxd
|
|
#endif
|
|
f.OnValuesChanged += EditForm_OnValuesChanged;
|
|
editformopen = true; //mxd
|
|
result = f.ShowDialog(this);
|
|
editformopen = false; //mxd
|
|
f.Dispose();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//mxd
|
|
private void EditForm_OnValuesChanged(object sender, EventArgs e)
|
|
{
|
|
if(OnEditFormValuesChanged != null)
|
|
{
|
|
OnEditFormValuesChanged(sender, e);
|
|
}
|
|
else
|
|
{
|
|
//If current mode doesn't handle this event, let's at least update the map and redraw display.
|
|
General.Map.Map.Update();
|
|
RedrawDisplay();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Threadsafe updates
|
|
|
|
object syncobject = new object();
|
|
List<System.Action> queuedActions = new List<System.Action>();
|
|
|
|
internal void ProcessQueuedUIActions()
|
|
{
|
|
List<System.Action> queue;
|
|
lock (syncobject)
|
|
{
|
|
queue = queuedActions;
|
|
queuedActions = new List<System.Action>();
|
|
}
|
|
|
|
foreach (System.Action action in queue)
|
|
{
|
|
action();
|
|
}
|
|
}
|
|
|
|
public void RunOnUIThread(System.Action action)
|
|
{
|
|
if (!InvokeRequired)
|
|
{
|
|
action();
|
|
}
|
|
else
|
|
{
|
|
bool notify;
|
|
lock (syncobject)
|
|
{
|
|
notify = queuedActions.Count == 0;
|
|
queuedActions.Add(action);
|
|
}
|
|
|
|
if (notify)
|
|
General.InvokeUIActions(this);
|
|
}
|
|
}
|
|
|
|
public void UpdateStatus()
|
|
{
|
|
RunOnUIThread(() =>
|
|
{
|
|
DisplayStatus(status);
|
|
});
|
|
}
|
|
|
|
public void ImageDataLoaded(string imagename)
|
|
{
|
|
RunOnUIThread(() =>
|
|
{
|
|
if ((General.Map != null) && (General.Map.Data != null))
|
|
{
|
|
ImageData img = General.Map.Data.GetFlatImage(imagename);
|
|
ImageDataLoaded(img);
|
|
}
|
|
});
|
|
}
|
|
|
|
public void SpriteDataLoaded(string spritename)
|
|
{
|
|
RunOnUIThread(() =>
|
|
{
|
|
if ((General.Map != null) && (General.Map.Data != null))
|
|
{
|
|
ImageData img = General.Map.Data.GetSpriteImage(spritename);
|
|
if (img != null && img.UsedInMap && !img.IsDisposed)
|
|
{
|
|
DelayedRedraw();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Message Pump
|
|
|
|
// This handles messages
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
// Notify message?
|
|
switch(m.Msg)
|
|
{
|
|
case General.WM_UIACTION:
|
|
ProcessQueuedUIActions();
|
|
break;
|
|
|
|
case General.WM_SYSCOMMAND:
|
|
// We don't want to open a menu when ALT is pressed
|
|
if(m.WParam.ToInt32() != General.SC_KEYMENU)
|
|
{
|
|
base.WndProc(ref m);
|
|
}
|
|
break;
|
|
|
|
case General.WM_MOUSEHWHEEL:
|
|
int delta = unchecked((short)(m.WParam.ToInt64() >> 16));
|
|
OnMouseHWheel(delta);
|
|
m.Result = new IntPtr(delta);
|
|
break;
|
|
|
|
default:
|
|
// Let the base handle the message
|
|
base.WndProc(ref m);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//mxd. Warnings panel
|
|
private delegate void SetWarningsCountCallback(int count, bool blink);
|
|
internal void SetWarningsCount(int count, bool blink)
|
|
{
|
|
RunOnUIThread(() =>
|
|
{
|
|
// Update icon, start annoying blinking if necessary
|
|
if (count > 0)
|
|
{
|
|
if (blink && !blinkTimer.Enabled) blinkTimer.Start();
|
|
warnsLabel.Image = Resources.Warning;
|
|
}
|
|
else
|
|
{
|
|
blinkTimer.Stop();
|
|
warnsLabel.Image = Resources.WarningOff;
|
|
warnsLabel.BackColor = SystemColors.Control;
|
|
}
|
|
|
|
// Update errors count
|
|
warnsLabel.Text = count.ToString();
|
|
});
|
|
}
|
|
|
|
//mxd. Bliks warnings indicator
|
|
private void Blink()
|
|
{
|
|
warnsLabel.BackColor = (warnsLabel.BackColor == Color.Red ? SystemColors.Control : Color.Red);
|
|
}
|
|
|
|
//mxd
|
|
private void warnsLabel_Click(object sender, EventArgs e)
|
|
{
|
|
ShowErrors();
|
|
}
|
|
|
|
//mxd
|
|
private void blinkTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
|
{
|
|
if(!blinkTimer.Enabled) return;
|
|
try
|
|
{
|
|
RunOnUIThread(() =>
|
|
{
|
|
Blink();
|
|
});
|
|
} catch(ObjectDisposedException) { } //la-la-la. We don't care.
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Processing
|
|
|
|
// This is called from the background thread when images are loaded
|
|
// but only when first loaded or when dimensions were changed
|
|
internal void ImageDataLoaded(ImageData img)
|
|
{
|
|
// Image is used in the map?
|
|
if ((img != null) && img.UsedInMap && !img.IsDisposed)
|
|
{
|
|
// Go for all setors
|
|
bool updated = false;
|
|
long imgshorthash = General.Map.Data.GetShortLongFlatName(img.LongName); //mxd. Part of long name support shennanigans
|
|
|
|
foreach(Sector s in General.Map.Map.Sectors)
|
|
{
|
|
// Update floor buffer if needed
|
|
if(s.LongFloorTexture == img.LongName || s.LongFloorTexture == imgshorthash)
|
|
{
|
|
s.UpdateFloorSurface();
|
|
updated = true;
|
|
}
|
|
|
|
// Update ceiling buffer if needed
|
|
if(s.LongCeilTexture == img.LongName || s.LongCeilTexture == imgshorthash)
|
|
{
|
|
s.UpdateCeilingSurface();
|
|
updated = true;
|
|
}
|
|
}
|
|
|
|
// If we made updates, redraw the screen
|
|
if(updated) DelayedRedraw();
|
|
}
|
|
}
|
|
|
|
public void EnableProcessing()
|
|
{
|
|
// Increase count
|
|
processingcount++;
|
|
|
|
// If not already enabled, enable processing now
|
|
if(!processor.Enabled)
|
|
{
|
|
processor.Enabled = true;
|
|
lastupdatetime = Clock.CurrentTime;
|
|
}
|
|
}
|
|
|
|
public void DisableProcessing()
|
|
{
|
|
// Increase count
|
|
processingcount--;
|
|
if(processingcount < 0) processingcount = 0;
|
|
|
|
// Turn off
|
|
if(processor.Enabled && (processingcount == 0))
|
|
processor.Enabled = false;
|
|
}
|
|
|
|
internal void StopProcessing()
|
|
{
|
|
// Turn off
|
|
processingcount = 0;
|
|
processor.Enabled = false;
|
|
}
|
|
|
|
//mxd
|
|
internal void ResetClock()
|
|
{
|
|
Clock.Reset();
|
|
lastupdatetime = 0;
|
|
|
|
// Let the mode know...
|
|
if(General.Editing.Mode != null)
|
|
General.Editing.Mode.OnClockReset();
|
|
}
|
|
|
|
// Processor event
|
|
private void processor_Tick(object sender, EventArgs e)
|
|
{
|
|
long curtime = Clock.CurrentTime;
|
|
long deltatime = curtime - lastupdatetime;
|
|
lastupdatetime = curtime;
|
|
|
|
if((General.Map != null) && (General.Editing.Mode != null))
|
|
{
|
|
// In exclusive mouse mode?
|
|
if(mouseinput != null)
|
|
{
|
|
Vector2D deltamouse = mouseinput.Process();
|
|
General.Plugins.OnEditMouseInput(deltamouse);
|
|
General.Editing.Mode.OnMouseInput(deltamouse);
|
|
}
|
|
|
|
// Process signal
|
|
General.Editing.Mode.OnProcess(deltatime);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Dockers
|
|
|
|
// This adds a docker
|
|
public void AddDocker(Docker d)
|
|
{
|
|
if(dockerspanel.Contains(d)) return; //mxd
|
|
|
|
// Make sure the full name is set with the plugin name as prefix
|
|
Plugin plugin = General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly());
|
|
d.MakeFullName(plugin.Name.ToLowerInvariant());
|
|
|
|
dockerspanel.Add(d, false);
|
|
}
|
|
|
|
//mxd. This also adds a docker
|
|
public void AddDocker(Docker d, bool notify)
|
|
{
|
|
if(dockerspanel.Contains(d)) return; //mxd
|
|
|
|
// Make sure the full name is set with the plugin name as prefix
|
|
Plugin plugin = General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly());
|
|
d.MakeFullName(plugin.Name.ToLowerInvariant());
|
|
|
|
dockerspanel.Add(d, notify);
|
|
}
|
|
|
|
// This removes a docker
|
|
public bool RemoveDocker(Docker d)
|
|
{
|
|
if(!dockerspanel.Contains(d)) return true; //mxd. Already removed/never added
|
|
|
|
// Make sure the full name is set with the plugin name as prefix
|
|
//Plugin plugin = General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly());
|
|
//d.MakeFullName(plugin.Name.ToLowerInvariant());
|
|
|
|
// We must release all keys because the focus may be stolen when
|
|
// this was the selected docker (the previous docker is automatically selected)
|
|
ReleaseAllKeys();
|
|
|
|
return dockerspanel.Remove(d);
|
|
}
|
|
|
|
// This selects a docker
|
|
public bool SelectDocker(Docker d)
|
|
{
|
|
if(!dockerspanel.Contains(d)) return false; //mxd
|
|
|
|
// Make sure the full name is set with the plugin name as prefix
|
|
Plugin plugin = General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly());
|
|
d.MakeFullName(plugin.Name.ToLowerInvariant());
|
|
|
|
// We must release all keys because the focus will be stolen
|
|
ReleaseAllKeys();
|
|
|
|
return dockerspanel.SelectDocker(d);
|
|
}
|
|
|
|
// This selects the previous selected docker
|
|
public void SelectPreviousDocker()
|
|
{
|
|
// We must release all keys because the focus will be stolen
|
|
ReleaseAllKeys();
|
|
|
|
dockerspanel.SelectPrevious();
|
|
}
|
|
|
|
// Mouse enters dockers window
|
|
private void dockerspanel_MouseContainerEnter(object sender, EventArgs e)
|
|
{
|
|
if(General.Settings.CollapseDockers)
|
|
dockerscollapser.Start();
|
|
|
|
dockerspanel.Expand();
|
|
}
|
|
|
|
// Automatic collapsing
|
|
private void dockerscollapser_Tick(object sender, EventArgs e)
|
|
{
|
|
if(General.Settings.CollapseDockers)
|
|
{
|
|
if(!dockerspanel.IsFocused)
|
|
{
|
|
Point p = this.PointToClient(Cursor.Position);
|
|
Rectangle r = new Rectangle(dockerspanel.Location, dockerspanel.Size);
|
|
if(!r.IntersectsWith(new Rectangle(p, Size.Empty)))
|
|
{
|
|
dockerspanel.Collapse();
|
|
dockerscollapser.Stop();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dockerscollapser.Stop();
|
|
}
|
|
}
|
|
|
|
// User resizes the docker
|
|
private void dockerspanel_UserResize(object sender, EventArgs e)
|
|
{
|
|
General.Settings.DockersWidth = dockerspanel.Width;
|
|
|
|
if(!General.Settings.CollapseDockers)
|
|
{
|
|
dockersspace.Width = dockerspanel.Width;
|
|
dockerspanel.Left = dockersspace.Left;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Updater (mxd)
|
|
|
|
private delegate void UpdateAvailableCallback(int remoterev, string changelog);
|
|
internal void UpdateAvailable(int remoterev, string changelog)
|
|
{
|
|
RunOnUIThread(() => {
|
|
// Show the window
|
|
UpdateForm form = new UpdateForm(remoterev, changelog);
|
|
form.FormClosing += delegate
|
|
{
|
|
// Update ignored revision number
|
|
General.Settings.IgnoredRemoteRevision = (form.IgnoreThisUpdate ? remoterev : 0);
|
|
};
|
|
form.Show(this);
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Graphics (mxd)
|
|
|
|
public SizeF MeasureString(string text, Font font)
|
|
{
|
|
SizeF length;
|
|
|
|
// Be thread safe
|
|
lock(graphics)
|
|
{
|
|
length = graphics.MeasureString(text, font);
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
public SizeF MeasureString(string text, Font font, int width, StringFormat format)
|
|
{
|
|
SizeF length;
|
|
|
|
// Be thread safe
|
|
lock (graphics)
|
|
{
|
|
|
|
length = graphics.MeasureString(text, font, width, format);
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|