UltimateZoneBuilder/Source/Core/Editing/EditingManager.cs

458 lines
12 KiB
C#
Raw Normal View History

#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.Windows.Forms;
using CodeImp.DoomBuilder.Windows;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.Plugins;
using CodeImp.DoomBuilder.VisualModes;
#endregion
namespace CodeImp.DoomBuilder.Editing
{
public sealed class EditingManager
{
#region ================== Constants
#endregion
#region ================== Variables
// All editing mode groups, sorted alphabetically
private List<string> groups;
// All editing modes available
private List<EditModeInfo> allmodes;
// Editing modes selected through configuration
private List<EditModeInfo> usedmodes;
// Status
private EditMode mode;
private EditMode newmode;
private Type prevmode;
private Type prevstablemode;
private Type prevclassicmode;
private bool disengaging;
// Disposing
private bool isdisposed;
#endregion
#region ================== Properties
internal List<EditModeInfo> ModesInfo { get { return allmodes; } }
public EditMode Mode { get { return mode; } }
public EditMode NewMode { get { return newmode; } }
public Type PreviousMode { get { return prevmode; } }
public Type PreviousStableMode { get { return prevstablemode; } }
public Type PreviousClassicMode { get { return prevclassicmode; } }
public bool IsDisposed { get { return isdisposed; } }
#endregion
#region ================== Constructor / Disposer
// Constructor
internal EditingManager()
{
// Initialize
allmodes = new List<EditModeInfo>();
usedmodes = new List<EditModeInfo>();
groups = new List<string>();
// Bind any methods
General.Actions.BindMethods(this);
// Make list of all editing modes we can find
foreach(Plugin p in General.Plugins.Plugins)
{
// For all classes that inherit from EditMode
Type[] editclasses = p.FindClasses(typeof(EditMode));
foreach(Type t in editclasses)
{
// For all defined EditMode attributes
EditModeAttribute[] emattrs = (EditModeAttribute[])t.GetCustomAttributes(typeof(EditModeAttribute), false);
foreach(EditModeAttribute a in emattrs)
{
// Make edit mode information
EditModeInfo modeinfo = new EditModeInfo(p, t, a);
allmodes.Add(modeinfo);
// Add group if not added yet
if(!groups.Contains(modeinfo.Attributes.ButtonGroup))
groups.Add(modeinfo.Attributes.ButtonGroup);
}
}
}
// Sort the lists
allmodes.Sort();
groups.Sort();
// Update modes
UpdateCurrentEditModes();
// We have no destructor
GC.SuppressFinalize(this);
}
// Disposer
internal void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Unbind any methods
General.Actions.UnbindMethods(this);
// Clean up
Added, Texture Browser: added "Show textures in subdirectories" checkbox (enabled by default). When enabled, textures from current PK3/PK7/Directory resource directory and it's subdirectories will be shown. Otherwise, only textures from current directory will be shown. Removed, Texture Browser: removed "Show image sizes" checkbox. "Show texture and flat sizes in browsers" preferences setting is now used instead. Fixed, Things mode: event line between pre-last and the last PatrolPoint was not drawn. Fixed, Things mode: highlight range for sizeless things (things with "fixedsize" game configuration property) was calculated incorrectly. Fixed: fixed a crash when opening Script Editor after using "Open map in current wad" command to switch to UDMF map with SCRIPTS lump when current script configuration was not saved in the wad's .dbs file. Fixed: map closing events were not triggered when using "Open map in current wad" command, which could potentially result in plugin crashes/incorrect behavior. Fixed: Sector Drawing overrides panel could trigger an exception when closing the map during resource loading. Internal: added "Debug + Profiler" solution configuration, added 2 profiling methods to DebugConsole. Internal: rewrote MainForm.DisplayStatus() / StatusInfo to handle selection info in a more structured way. Fixed, internal: some destructors could potentially be executed more than once potentially leading to exceptions. Other destructors were not called at all. Updated ZDoom_DECORATE.cfg.
2015-09-16 12:10:43 +00:00
foreach(EditModeInfo i in allmodes) i.Dispose(); //mxd
// Done
isdisposed = true;
}
}
#endregion
#region ================== Switch Actions
// This unbinds all editing mode switch actions
private void UnbindSwitchActions()
{
foreach(EditModeInfo emi in allmodes)
{
emi.UnbindSwitchAction();
}
}
// This binds all editing mode switch actions for the available modes only
private void BindAvailableSwitchActions()
{
// In case of VisualMode, we only bind the switch action
// of the VisualMode to switch back to the previous mode
if(mode is VisualMode)
{
// Bind only the switch action for this mode
EditModeInfo info = GetEditModeInfo(mode.GetType());
info.BindSwitchAction();
}
else
{
// Bind all available mode swtich actions
foreach(EditModeInfo emi in usedmodes)
{
emi.BindSwitchAction();
}
}
}
#endregion
#region ================== Methods
// This cancels a volatile mode, as if the user presses cancel
public bool CancelVolatileMode()
{
// Volatile mode?
if((General.Map != null) & (mode != null) && mode.Attributes.Volatile && !disengaging)
{
// Cancel
disengaging = true;
General.Plugins.OnEditCancel();
mode.OnCancel();
return true;
}
else
{
// Mode is not volatile
return false;
}
}
// This disengages a volatile mode, leaving the choice to cancel or accept to the editing mode
public bool DisengageVolatileMode()
{
// Volatile mode?
if((General.Map != null) && (mode != null) && mode.Attributes.Volatile && !disengaging)
{
// Change back to normal mode
disengaging = true;
ChangeMode(prevstablemode.Name);
return true;
}
else
{
// Mode is not volatile
return false;
}
}
// This returns specific editing mode info by name
internal EditModeInfo GetEditModeInfo(string editmodename)
{
// Find the edit mode
foreach(EditModeInfo emi in usedmodes)
{
// Mode matches class name?
if(emi.Type.Name == editmodename) return emi;
}
// No such mode found
return null;
}
// This returns specific editing mode info by name
internal EditModeInfo GetEditModeInfo(Type modetype)
{
// Find the edit mode
foreach(EditModeInfo emi in usedmodes)
{
// Mode matches class name?
if(emi.Type == modetype) return emi;
}
// No such mode found
return null;
}
// This is called when the editing modes must update
internal void UpdateCurrentEditModes()
{
// Unbind editing mode switch actions
UnbindSwitchActions();
// Rebuild list of used modes
usedmodes.Clear();
if(General.Map != null)
{
foreach(EditModeInfo emi in allmodes)
{
// Include the mode if it supports current map format (mxd) and map features
// Also include the mode when it is listed and enabled or when it's not optional
if( (emi.Attributes.SupportedMapFormats == null || Array.IndexOf(emi.Attributes.SupportedMapFormats, General.Map.Config.FormatInterface) != -1) &&
(emi.Attributes.RequiredMapFeatures == null || General.Map.Config.SupportsMapFeatures(emi.Attributes.RequiredMapFeatures)) &&
((General.Map.ConfigSettings.EditModes.ContainsKey(emi.Type.FullName) &&
General.Map.ConfigSettings.EditModes[emi.Type.FullName] )
|| !emi.IsOptional) )
{
// Add the mode to be used and bind switch action
usedmodes.Add(emi);
}
}
}
// Bind switch action for used modes
BindAvailableSwitchActions();
// Remove editing mode buttons from interface
General.MainWindow.RemoveEditModeButtons();
// Go for all the editing mode groups
foreach(string grp in groups)
{
General.MainWindow.AddEditModeSeperator(grp);
// Go for all used edit modes to add buttons
foreach(EditModeInfo emi in usedmodes)
{
if((emi.ButtonImage != null) && (emi.ButtonDesc != null) &&
(emi.Attributes.ButtonGroup == grp))
General.MainWindow.AddEditModeButton(emi);
}
}
}
//
// This changes the editing mode.
// Order in which events occur for the old and new modes:
//
// - Constructor of new mode is called
// - Disengage of old mode is called
// ----- Mode switches -----
// - Engage of new mode is called
// - Dispose of old mode is called
//
// Returns false when cancelled
public bool ChangeMode(EditMode nextmode)
{
EditMode oldmode = mode;
if(nextmode != null)
{
// Verify that this mode is usable
bool allowuse = false;
foreach(EditModeInfo emi in usedmodes)
{
if(emi.Type.FullName == nextmode.GetType().FullName)
{
allowuse = true;
break;
}
}
if(!allowuse)
{
General.Interface.MessageBeep(MessageBeepType.Error);
General.WriteLogLine("Attempt to switch to an invalid edit mode " + nextmode.GetType().Name + "!");
return false;
}
else
{
General.WriteLogLine("Preparing to change editing mode to " + nextmode.GetType().Name + "...");
}
}
else
{
General.WriteLogLine("Stopping editing mode...");
}
// Remember previous mode
newmode = nextmode;
if(mode != null)
{
prevmode = mode.GetType();
if(!mode.Attributes.Volatile)
{
prevstablemode = prevmode;
if(mode is ClassicMode) prevclassicmode = prevmode;
}
}
else
{
prevmode = null;
prevstablemode = null;
prevclassicmode = null;
}
// Let the plugins know beforehand and check if not cancelled
if(General.Plugins.ModeChanges(oldmode, newmode))
{
// Disenagage old mode
disengaging = true;
if(oldmode != null)
{
General.Plugins.OnEditDisengage(oldmode, newmode);
oldmode.OnDisengage();
}
// Reset cursor
General.Interface.SetCursor(Cursors.Default);
// Apply new mode
General.WriteLogLine("Editing mode changes from " + TypeNameOrNull(oldmode) + " to " + TypeNameOrNull(nextmode));
General.WriteLogLine("Previous stable mode is " + TypeNameOrNull(prevstablemode) + ", previous classic mode is " + TypeNameOrNull(prevclassicmode));
mode = newmode;
disengaging = false;
// Engage new mode
if(newmode != null)
{
if (newmode.Attributes.IsDeprecated)
General.ErrorLogger.Add(ErrorType.Warning, "The editing mode \"" + newmode.Attributes.DisplayName + "\" is deprecated and will be removed in the future. " + newmode.Attributes.DeprecationMessage);
newmode.OnEngage();
General.Plugins.OnEditEngage(oldmode, newmode);
}
// Bind new switch actions
UnbindSwitchActions();
BindAvailableSwitchActions();
// Update the interface
General.MainWindow.EditModeChanged();
// Dispose old mode
if(oldmode != null) oldmode.Dispose();
// Done switching
General.WriteLogLine("Editing mode change complete.");
newmode = null;
// Redraw the display
General.MainWindow.RedrawDisplay();
return true;
}
else
{
// Cancelled
General.WriteLogLine("Editing mode change cancelled.");
return false;
}
}
// This changes mode by class name and optionally with arguments
public void ChangeMode(string classname, params object[] args)
{
EditModeInfo emi = GetEditModeInfo(classname);
if(emi != null) emi.SwitchToMode(args);
}
// This returns the type name as string
private static string TypeNameOrNull(Type type)
{
return (type != null) ? type.Name : "NULL";
}
// This returns the type name as string
private static string TypeNameOrNull(object obj)
{
return (obj != null) ? obj.GetType().Name : "NULL";
}
#endregion
#region ================== Actions
/// <summary>
/// This cancels the current mode.
/// </summary>
[BeginAction("cancelmode")]
public void CancelMode()
{
// Let the mode know
if(mode != null)
{
General.Plugins.OnEditCancel();
mode.OnCancel();
}
}
/// <summary>
/// This accepts the changes in the current mode.
/// </summary>
[BeginAction("acceptmode")]
public void AcceptMode()
{
// Let the mode know
if(mode != null)
{
General.Plugins.OnEditAccept();
mode.OnAccept();
}
}
#endregion
}
}