mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-18 14:31:50 +00:00
- introduced "volatile" editing modes
- automated exclusive mouse mode management - fixed bug with actions that never ended when a dialog appears
This commit is contained in:
parent
33d2af5417
commit
6f255e1866
15 changed files with 228 additions and 40 deletions
|
@ -40,8 +40,10 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
// The EditMode attribute does not have to be specified unless the
|
||||
// mode must be activated by class name rather than direct instance.
|
||||
// In that case, just specifying the attribute like this is enough:
|
||||
[EditMode]
|
||||
// [EditMode]
|
||||
|
||||
[EditMode(Volatile = true)]
|
||||
|
||||
public sealed class DragLinedefsMode : DragGeometryMode
|
||||
{
|
||||
#region ================== Constants
|
||||
|
|
|
@ -40,7 +40,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
// The EditMode attribute does not have to be specified unless the
|
||||
// mode must be activated by class name rather than direct instance.
|
||||
// In that case, just specifying the attribute like this is enough:
|
||||
[EditMode]
|
||||
// [EditMode]
|
||||
|
||||
[EditMode(Volatile = true)]
|
||||
|
||||
public sealed class DragSectorsMode : DragGeometryMode
|
||||
{
|
||||
|
|
|
@ -40,7 +40,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
// The EditMode attribute does not have to be specified unless the
|
||||
// mode must be activated by class name rather than direct instance.
|
||||
// In that case, just specifying the attribute like this is enough:
|
||||
[EditMode]
|
||||
// [EditMode]
|
||||
|
||||
[EditMode(Volatile = true)]
|
||||
|
||||
public sealed class DragThingsMode : ClassicMode
|
||||
{
|
||||
|
|
|
@ -40,7 +40,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
// The EditMode attribute does not have to be specified unless the
|
||||
// mode must be activated by class name rather than direct instance.
|
||||
// In that case, just specifying the attribute like this is enough:
|
||||
[EditMode]
|
||||
// [EditMode]
|
||||
|
||||
[EditMode(Volatile = true)]
|
||||
|
||||
public sealed class DragVerticesMode : DragGeometryMode
|
||||
{
|
||||
|
|
|
@ -37,7 +37,7 @@ using CodeImp.DoomBuilder.Controls;
|
|||
|
||||
namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
||||
{
|
||||
[EditMode(SwitchAction = "drawlinesmode")]
|
||||
[EditMode(SwitchAction = "drawlinesmode", Volatile = true)]
|
||||
|
||||
public class DrawGeometryMode : ClassicMode
|
||||
{
|
||||
|
@ -733,6 +733,19 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
|
|||
{
|
||||
points.Add(GetCurrentPosition());
|
||||
Update();
|
||||
|
||||
// Check if point stitches with the first
|
||||
if((points.Count > 1) && (points[points.Count - 1].stitch))
|
||||
{
|
||||
Vector2D p1 = points[0].pos;
|
||||
Vector2D p2 = points[points.Count - 1].pos;
|
||||
Vector2D delta = p1 - p2;
|
||||
if((Math.Abs(delta.x) <= 0.001f) && (Math.Abs(delta.y) <= 0.001f))
|
||||
{
|
||||
// Finish drawing
|
||||
FinishDraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -422,13 +422,15 @@ namespace CodeImp.DoomBuilder.Controls
|
|||
if((strippedkey == (int)Keys.ShiftKey) || (strippedkey == (int)Keys.ControlKey)) key = strippedkey;
|
||||
bool repeat = pressedkeys.Contains(strippedkey);
|
||||
|
||||
// Invoke event
|
||||
BeginActionByKey(key, repeat);
|
||||
Action[] acts = GetActionsByKey(key);
|
||||
foreach(Action a in acts) if(!activeactions.Contains(a)) activeactions.Add(a);
|
||||
|
||||
// Update pressed keys
|
||||
if(!repeat) pressedkeys.Add(strippedkey);
|
||||
|
||||
// Add action to active list
|
||||
Action[] acts = GetActionsByKey(key);
|
||||
foreach(Action a in acts) if(!activeactions.Contains(a)) activeactions.Add(a);
|
||||
|
||||
// Invoke actions
|
||||
BeginActionByKey(key, repeat);
|
||||
}
|
||||
|
||||
// This notifies a key has been released
|
||||
|
@ -443,6 +445,16 @@ namespace CodeImp.DoomBuilder.Controls
|
|||
// End actions that no longer match
|
||||
EndActiveActions();
|
||||
}
|
||||
|
||||
// This releases all pressed keys
|
||||
public void ReleaseAllKeys()
|
||||
{
|
||||
// Clear pressed keys
|
||||
pressedkeys.Clear();
|
||||
|
||||
// End actions
|
||||
EndActiveActions();
|
||||
}
|
||||
|
||||
// This updates the modifiers
|
||||
public void UpdateModifiers(int mods)
|
||||
|
@ -461,10 +473,18 @@ namespace CodeImp.DoomBuilder.Controls
|
|||
foreach(KeyValuePair<string, Action> a in actions)
|
||||
{
|
||||
// This action is associated with this key?
|
||||
if(a.Value.KeyMatches(key) && (a.Value.Repeat || !repeated))
|
||||
if(a.Value.KeyMatches(key))
|
||||
{
|
||||
// Invoke action
|
||||
a.Value.Begin();
|
||||
// Allowed to repeat?
|
||||
if(a.Value.Repeat || !repeated)
|
||||
{
|
||||
// Invoke action
|
||||
a.Value.Begin();
|
||||
}
|
||||
else
|
||||
{
|
||||
//General.WriteLogLine("Action \"" + a.Value.Name + "\" failed because it does not support repeating activation!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ namespace CodeImp.DoomBuilder.Editing
|
|||
|
||||
#region ================== Variables
|
||||
|
||||
// Attributes
|
||||
private EditModeAttribute attributes;
|
||||
|
||||
// Disposing
|
||||
protected bool isdisposed = false;
|
||||
|
||||
|
@ -58,6 +61,8 @@ namespace CodeImp.DoomBuilder.Editing
|
|||
|
||||
public bool IsDisposed { get { return isdisposed; } }
|
||||
|
||||
public EditModeAttribute Attributes { get { return attributes; } }
|
||||
|
||||
// Unless overriden, this returns the name of this mode
|
||||
// for checking the appropriate button on the toolbar.
|
||||
public virtual string EditModeButtonName { get { return GetType().Name; } }
|
||||
|
@ -71,6 +76,20 @@ namespace CodeImp.DoomBuilder.Editing
|
|||
/// </summary>
|
||||
public EditMode()
|
||||
{
|
||||
// Fetch attributes
|
||||
object[] attrs = this.GetType().GetCustomAttributes(true);
|
||||
foreach(object a in attrs)
|
||||
{
|
||||
if(a is EditModeAttribute)
|
||||
{
|
||||
attributes = (EditModeAttribute)a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No attributes found?
|
||||
if(attributes == null) throw new Exception("Editing mode \"" + this.GetType().Name + "\" is missing EditMode attributes!");
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace CodeImp.DoomBuilder.Editing
|
|||
private string buttondesc;
|
||||
private int buttonorder;
|
||||
private bool configspecific;
|
||||
private bool isvolatile;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -78,6 +79,13 @@ namespace CodeImp.DoomBuilder.Editing
|
|||
/// </summary>
|
||||
public bool ConfigSpecific { get { return configspecific; } set { configspecific = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// When set to true, this mode is cancelled when core actions like
|
||||
/// undo and save are performed. The editing mode should then return to
|
||||
/// a non-volatile mode.
|
||||
/// </summary>
|
||||
public bool Volatile { get { return isvolatile; } set { isvolatile = value; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Disposer
|
||||
|
|
|
@ -209,6 +209,9 @@ namespace CodeImp.DoomBuilder.Editing
|
|||
// Anything to undo?
|
||||
if(undos.Count > 0)
|
||||
{
|
||||
// Cancel volatile mode, if any
|
||||
General.CancelVolatileMode();
|
||||
|
||||
// Get undo snapshot
|
||||
u = undos[0];
|
||||
undos.RemoveAt(0);
|
||||
|
@ -245,6 +248,9 @@ namespace CodeImp.DoomBuilder.Editing
|
|||
// Anything to redo?
|
||||
if(redos.Count > 0)
|
||||
{
|
||||
// Cancel volatile mode, if any
|
||||
General.CancelVolatileMode();
|
||||
|
||||
// Get redo snapshot
|
||||
r = redos[0];
|
||||
redos.RemoveAt(0);
|
||||
|
|
|
@ -543,13 +543,23 @@ namespace CodeImp.DoomBuilder
|
|||
|
||||
#region ================== Management
|
||||
|
||||
// This cancels a volatile mode
|
||||
internal static void CancelVolatileMode()
|
||||
{
|
||||
if((map != null) && (map.Mode != null) && map.Mode.Attributes.Volatile)
|
||||
map.Mode.Cancel();
|
||||
}
|
||||
|
||||
// This creates a new map
|
||||
[BeginAction("newmap")]
|
||||
internal static void NewMap()
|
||||
{
|
||||
MapOptions newoptions = new MapOptions();
|
||||
MapOptionsForm optionswindow;
|
||||
|
||||
|
||||
// Cancel volatile mode, if any
|
||||
General.CancelVolatileMode();
|
||||
|
||||
// Ask the user to save changes (if any)
|
||||
if(General.AskSaveMap())
|
||||
{
|
||||
|
@ -596,6 +606,9 @@ namespace CodeImp.DoomBuilder
|
|||
[BeginAction("closemap")]
|
||||
internal static void CloseMap()
|
||||
{
|
||||
// Cancel volatile mode, if any
|
||||
General.CancelVolatileMode();
|
||||
|
||||
// Ask the user to save changes (if any)
|
||||
if(General.AskSaveMap())
|
||||
{
|
||||
|
@ -625,7 +638,10 @@ namespace CodeImp.DoomBuilder
|
|||
internal static void OpenMap()
|
||||
{
|
||||
OpenFileDialog openfile;
|
||||
|
||||
|
||||
// Cancel volatile mode, if any
|
||||
General.CancelVolatileMode();
|
||||
|
||||
// Open map file dialog
|
||||
openfile = new OpenFileDialog();
|
||||
openfile.Filter = "Doom WAD Files (*.wad)|*.wad";
|
||||
|
@ -649,6 +665,9 @@ namespace CodeImp.DoomBuilder
|
|||
{
|
||||
OpenMapOptionsForm openmapwindow;
|
||||
|
||||
// Cancel volatile mode, if any
|
||||
General.CancelVolatileMode();
|
||||
|
||||
// Ask the user to save changes (if any)
|
||||
if(General.AskSaveMap())
|
||||
{
|
||||
|
@ -693,14 +712,21 @@ namespace CodeImp.DoomBuilder
|
|||
}
|
||||
|
||||
// This saves the current map
|
||||
// Returns tre when saved, false when cancelled or failed
|
||||
[BeginAction("savemap")]
|
||||
internal static void SaveMap()
|
||||
internal static void ActionSaveMap() { SaveMap(); }
|
||||
internal static bool SaveMap()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// Cancel volatile mode, if any
|
||||
General.CancelVolatileMode();
|
||||
|
||||
// Check if a wad file is known
|
||||
if(map.FilePathName == "")
|
||||
{
|
||||
// Call to SaveMapAs
|
||||
SaveMapAs();
|
||||
result = SaveMapAs();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -713,6 +739,7 @@ namespace CodeImp.DoomBuilder
|
|||
{
|
||||
// Add recent file
|
||||
mainwindow.AddRecentFile(map.FilePathName);
|
||||
result = true;
|
||||
}
|
||||
|
||||
// All done
|
||||
|
@ -720,14 +747,23 @@ namespace CodeImp.DoomBuilder
|
|||
mainwindow.DisplayReady();
|
||||
Cursor.Current = Cursors.Default;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// This saves the current map as a different file
|
||||
// Returns tre when saved, false when cancelled or failed
|
||||
[BeginAction("savemapas")]
|
||||
internal static void SaveMapAs()
|
||||
internal static void ActionSaveMapAs() { SaveMapAs(); }
|
||||
internal static bool SaveMapAs()
|
||||
{
|
||||
SaveFileDialog savefile;
|
||||
bool result = false;
|
||||
|
||||
// Cancel volatile mode, if any
|
||||
General.CancelVolatileMode();
|
||||
|
||||
// Show save as dialog
|
||||
savefile = new SaveFileDialog();
|
||||
savefile.Filter = "Doom WAD Files (*.wad)|*.wad";
|
||||
|
@ -747,6 +783,7 @@ namespace CodeImp.DoomBuilder
|
|||
{
|
||||
// Add recent file
|
||||
mainwindow.AddRecentFile(map.FilePathName);
|
||||
result = true;
|
||||
}
|
||||
|
||||
// All done
|
||||
|
@ -754,6 +791,8 @@ namespace CodeImp.DoomBuilder
|
|||
mainwindow.DisplayReady();
|
||||
Cursor.Current = Cursors.Default;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// This asks to save the map if needed
|
||||
|
@ -769,8 +808,8 @@ namespace CodeImp.DoomBuilder
|
|||
result = MessageBox.Show(mainwindow, "Do you want to save changes to " + map.FileTitle + " (" + map.Options.CurrentName + ")?", Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
|
||||
if(result == DialogResult.Yes)
|
||||
{
|
||||
// TODO: Save map
|
||||
|
||||
// Save map and return true on success
|
||||
return SaveMap();
|
||||
}
|
||||
else if(result == DialogResult.Cancel)
|
||||
{
|
||||
|
|
|
@ -951,6 +951,9 @@ namespace CodeImp.DoomBuilder
|
|||
[BeginAction("mapoptions")]
|
||||
internal void ShowMapOptions()
|
||||
{
|
||||
// Cancel volatile mode, if any
|
||||
General.CancelVolatileMode();
|
||||
|
||||
// Show map options dialog
|
||||
MapOptionsForm optionsform = new MapOptionsForm(options);
|
||||
if(optionsform.ShowDialog(General.MainWindow) == DialogResult.OK)
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace CodeImp.DoomBuilder.Interface
|
|||
bool MouseInDisplay { get; }
|
||||
bool AutoMerge { get; }
|
||||
bool SnapToGrid { get; }
|
||||
bool MouseExclusive { get; }
|
||||
|
||||
// Methods
|
||||
void DisplayReady();
|
||||
|
@ -65,6 +66,8 @@ namespace CodeImp.DoomBuilder.Interface
|
|||
void SetProcessorState(bool on);
|
||||
void StartExclusiveMouseInput();
|
||||
void StopExclusiveMouseInput();
|
||||
void BreakExclusiveMouseInput();
|
||||
void ResumeExclusiveMouseInput();
|
||||
bool CheckActionActive(Assembly assembly, string actionname);
|
||||
}
|
||||
}
|
||||
|
|
2
Source/Interface/MainForm.Designer.cs
generated
2
Source/Interface/MainForm.Designer.cs
generated
|
@ -923,7 +923,9 @@ namespace CodeImp.DoomBuilder.Interface
|
|||
this.Name = "MainForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
||||
this.Text = "Doom Builder";
|
||||
this.Deactivate += new System.EventHandler(this.MainForm_Deactivate);
|
||||
this.Resize += new System.EventHandler(this.MainForm_Resize);
|
||||
this.Activated += new System.EventHandler(this.MainForm_Activated);
|
||||
this.Move += new System.EventHandler(this.MainForm_Move);
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
|
||||
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.MainForm_KeyUp);
|
||||
|
|
|
@ -67,6 +67,8 @@ namespace CodeImp.DoomBuilder.Interface
|
|||
private bool shift, ctrl, alt;
|
||||
private MouseInput mouseinput;
|
||||
private Rectangle originalclip;
|
||||
private bool mouseexclusive;
|
||||
private int mouseexclusivebreaklevel;
|
||||
|
||||
// Recent files
|
||||
private ToolStripMenuItem[] recentitems;
|
||||
|
@ -85,7 +87,8 @@ namespace CodeImp.DoomBuilder.Interface
|
|||
internal 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; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Disposer
|
||||
|
@ -184,6 +187,23 @@ namespace CodeImp.DoomBuilder.Interface
|
|||
lastsize = this.Size;
|
||||
}
|
||||
}
|
||||
|
||||
// Window receives focus
|
||||
private void MainForm_Activated(object sender, EventArgs e)
|
||||
{
|
||||
// Resume any exclusive mouse input
|
||||
ResumeExclusiveMouseInput();
|
||||
}
|
||||
|
||||
// Window loses focus
|
||||
private void MainForm_Deactivate(object sender, EventArgs e)
|
||||
{
|
||||
// Release all pressed keys
|
||||
General.Actions.ReleaseAllKeys();
|
||||
|
||||
// Stop exclusive mouse input
|
||||
BreakExclusiveMouseInput();
|
||||
}
|
||||
|
||||
// Window is moved
|
||||
private void MainForm_Move(object sender, EventArgs e)
|
||||
|
@ -749,14 +769,12 @@ namespace CodeImp.DoomBuilder.Interface
|
|||
return General.Actions.CheckActionActive(assembly, actionname);
|
||||
}
|
||||
|
||||
// This requests exclusive mouse input
|
||||
public void StartExclusiveMouseInput()
|
||||
// This is a tool to lock the mouse in exclusive mode
|
||||
private void StartMouseExclusive()
|
||||
{
|
||||
// Only when not already in exclusive mode
|
||||
// Not already locked?
|
||||
if(mouseinput == null)
|
||||
{
|
||||
General.WriteLogLine("Starting exclusive mouse input mode...");
|
||||
|
||||
// Start special input device
|
||||
mouseinput = new MouseInput(this);
|
||||
|
||||
|
@ -766,15 +784,13 @@ namespace CodeImp.DoomBuilder.Interface
|
|||
Cursor.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
// This stops exclusive mouse input
|
||||
public void StopExclusiveMouseInput()
|
||||
|
||||
// This is a tool to unlock the mouse
|
||||
private void StopMouseExclusive()
|
||||
{
|
||||
// Only when in exclusive mode
|
||||
// Locked?
|
||||
if(mouseinput != null)
|
||||
{
|
||||
General.WriteLogLine("Stopping exclusive mouse input mode...");
|
||||
|
||||
// Stop special input device
|
||||
mouseinput.Dispose();
|
||||
mouseinput = null;
|
||||
|
@ -784,6 +800,65 @@ namespace CodeImp.DoomBuilder.Interface
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// When the mouse wheel is changed
|
||||
protected override void OnMouseWheel(MouseEventArgs e)
|
||||
|
|
|
@ -377,14 +377,6 @@ namespace CodeImp.DoomBuilder.Map
|
|||
public List<Vector2D> GetGridIntersections()
|
||||
{
|
||||
List<Vector2D> coords = new List<Vector2D>();
|
||||
/*
|
||||
float startx = start.Position.x;
|
||||
float endx = end.Position.x;
|
||||
float starty = start.Position.y;
|
||||
float endy = end.Position.y;
|
||||
float dirx = (float)Math.Sign(endx - startx);
|
||||
float diry = (float)Math.Sign(endy - starty);
|
||||
*/
|
||||
Vector2D v = new Vector2D();
|
||||
float gx, gy, minx, maxx, miny, maxy;
|
||||
bool reversex, reversey;
|
||||
|
|
Loading…
Reference in a new issue