- 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:
codeimp 2008-05-08 16:39:14 +00:00
parent 33d2af5417
commit 6f255e1866
15 changed files with 228 additions and 40 deletions

View file

@ -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

View file

@ -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
{

View file

@ -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
{

View file

@ -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
{

View file

@ -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();
}
}
}
}

View file

@ -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!");
}
}
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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);

View file

@ -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)
{

View file

@ -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)

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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)

View file

@ -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;