- changed a lot around the actions

- no more mousebutton-specific code in the editing modes (now all bound by actions)
- some progress on the drawing editing mode
This commit is contained in:
codeimp 2008-04-27 12:07:26 +00:00
parent 175f645e5e
commit 4ae985d630
30 changed files with 1468 additions and 767 deletions

BIN
Resources/Icons/Pencil.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

View file

@ -59,6 +59,8 @@
<Compile Include="Config\UniversalFieldInfo.cs" />
<Compile Include="Config\UniversalFieldType.cs" />
<Compile Include="Controls\ActionAttribute.cs" />
<Compile Include="Controls\BeginActionAttribute.cs" />
<Compile Include="Controls\EndActionAttribute.cs" />
<Compile Include="Controls\KeyControl.cs" />
<Compile Include="Controls\MouseInput.cs" />
<Compile Include="Data\DirectoryReader.cs" />

View file

@ -299,26 +299,21 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
}
}
// When edit button is released
protected override void EndEdit()
{
// Just return to base mode, Disengage will be called automatically.
General.Map.ChangeMode(basemode);
base.EndEdit();
}
// Mouse moving
public override void MouseMove(MouseEventArgs e)
{
base.MouseMove(e);
Update();
}
// Mouse button released
public override void MouseUp(MouseEventArgs e)
{
base.MouseUp(e);
// Is the editing button released?
if(e.Button == EditMode.EDIT_BUTTON)
{
// Just return to vertices mode, geometry will be merged on disengage.
General.Map.ChangeMode(basemode);
}
}
// When a key is released
public override void KeyUp(KeyEventArgs e)
{

View file

@ -334,6 +334,15 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
}
}
// When edit button is released
protected override void EndEdit()
{
// Just return to vertices mode, geometry will be merged on disengage.
General.Map.ChangeMode(basemode);
base.EndEdit();
}
// Mouse moving
public override void MouseMove(MouseEventArgs e)
{
@ -341,19 +350,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
Update();
}
// Mouse button released
public override void MouseUp(MouseEventArgs e)
{
base.MouseUp(e);
// Is the editing button released?
if(e.Button == EditMode.EDIT_BUTTON)
{
// Just return to vertices mode, geometry will be merged on disengage.
General.Map.ChangeMode(basemode);
}
}
// When a key is released
public override void KeyUp(KeyEventArgs e)
{

View file

@ -31,20 +31,20 @@ using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Geometry;
using System.Drawing;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Controls;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes.Editing
{
[EditMode(SwitchAction = "drawlinesmode", // Action name used to switch to this mode
ButtonDesc = "Draw Lines Mode", // Description on the button in toolbar/menu
ButtonImage = "LinesMode.png", // Image resource name for the button
ButtonOrder = int.MinValue + 1)] // Position of the button (lower is more to the left)
[EditMode(SwitchAction = "drawlinesmode")]
public class DrawGeometryMode : ClassicMode
{
#region ================== Constants
private const float LINE_THICKNESS = 0.6f;
#endregion
#region ================== Variables
@ -110,6 +110,8 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
base.Cancel();
// Return to original mode
Type t = basemode.GetType();
basemode = (EditMode)Activator.CreateInstance(t);
General.Map.ChangeMode(basemode);
}
@ -119,12 +121,14 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
base.Disengage();
Cursor.Current = Cursors.AppStarting;
// When not cancelled
if(!cancelled)
// When not cancelled and points have been drawn
if(!cancelled && (points.Count > 0))
{
// Make undo for the draw
General.Map.UndoRedo.CreateUndo("line draw", UndoGroup.None, 0);
// Update cached values
General.Map.Map.Update();
@ -143,7 +147,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
protected bool CheckViewChanged()
{
bool viewchanged = false;
// View changed?
if(renderer.OffsetX != lastoffsetx) viewchanged = true;
if(renderer.OffsetY != lastoffsety) viewchanged = true;
@ -187,10 +191,36 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
snaptonearest = General.Interface.CtrlState;
Vector2D lastp = new Vector2D(0, 0);
Vector2D curp = GetCurrentPosition();
float vsize = ((float)renderer.VertexSize + 1.0f) / renderer.Scale;
// Render drawing lines
if(renderer.StartOverlay(true))
{
RenderSelection();
// Go for all points to draw lines
if(points.Count > 0)
{
// Render lines
lastp = points[0];
for(int i = 1; i < points.Count; i++)
{
renderer.RenderLine(lastp, points[i], LINE_THICKNESS, General.Colors.Selection, true);
lastp = points[i];
}
// Render line to cursor
renderer.RenderLine(lastp, curp, LINE_THICKNESS, General.Colors.Highlight, true);
// Render vertices
for(int i = 0; i < points.Count; i++)
renderer.RenderRectangleFilled(new RectangleF(points[i].x - vsize, points[i].y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.Selection, true);
}
// Render vertex at cursor
renderer.RenderRectangleFilled(new RectangleF(curp.x - vsize, curp.y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.Highlight, true);
// Done
renderer.Finish();
}
@ -198,6 +228,57 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
renderer.Present();
}
// This gets the aligned and snapped draw position
private Vector2D GetCurrentPosition()
{
// Snap to nearest?
if(snaptonearest)
{
float vrange = VerticesMode.VERTEX_HIGHLIGHT_RANGE / renderer.Scale;
// Go for all drawn points
foreach(Vector2D v in points)
{
Vector2D delta = mousemappos - v;
if(delta.GetLengthSq() < (vrange * vrange)) return v;
}
// Try the nearest vertex
Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange);
if(nv != null) return nv.Position;
// Try the nearest linedef
Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, LinedefsMode.LINEDEF_HIGHLIGHT_RANGE / renderer.Scale);
if(nl != null)
{
// Snap to grid?
if(snaptogrid)
{
// Aligned to line and grid
// TODO: Find nearest horzontal and vertical grid intersections and align there
return nl.NearestOnLine(mousemappos);
}
else
{
// Aligned to line
return nl.NearestOnLine(mousemappos);
}
}
}
// Snap to grid?
if(snaptogrid)
{
// Aligned to grid
return General.Map.Grid.SnappedToGrid(mousemappos);
}
else
{
// Normal position
return mousemappos;
}
}
// Mouse moving
public override void MouseMove(MouseEventArgs e)
{
@ -205,26 +286,46 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
Update();
}
// Mouse button released
public override void MouseUp(MouseEventArgs e)
// Drawing a point
[BeginAction("drawpoint")]
public void DrawPoint()
{
base.MouseUp(e);
// Mouse inside window?
if(General.Interface.MouseInDisplay)
{
points.Add(GetCurrentPosition());
Update();
}
}
// Remove a point
[BeginAction("removepoint")]
public void RemovePoint()
{
if(points.Count > 0) points.RemoveAt(points.Count - 1);
Update();
}
// Finish drawing
[BeginAction("finishdraw")]
public void FinishDraw()
{
// Just return to base mode, Disengage will be called automatically.
General.Map.ChangeMode(basemode);
}
// When a key is released
public override void KeyUp(KeyEventArgs e)
{
base.KeyUp(e);
if(snaptogrid != General.Interface.ShiftState ^ General.Interface.SnapToGrid) Update();
if(snaptonearest != General.Interface.CtrlState) Update();
Update();
}
// When a key is pressed
public override void KeyDown(KeyEventArgs e)
{
base.KeyDown(e);
if(snaptogrid != General.Interface.ShiftState ^ General.Interface.SnapToGrid) Update();
if(snaptonearest != General.Interface.CtrlState) Update();
Update();
}
#endregion

View file

@ -44,7 +44,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
{
#region ================== Constants
protected const float LINEDEF_HIGHLIGHT_RANGE = 20f;
public const float LINEDEF_HIGHLIGHT_RANGE = 20f;
#endregion
@ -150,7 +150,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Render selection
if(renderer.StartOverlay(true))
{
RenderSelection();
RenderMultiSelection();
renderer.Finish();
}
}
@ -195,39 +195,108 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
General.Interface.HideInfo();
}
// This is called wheh selection ends
protected override void EndSelection()
// Selection
protected override void Select()
{
// Go for all lines
foreach(Linedef l in General.Map.Map.Linedefs)
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
l.Selected = ((l.Start.Position.x >= selectionrect.Left) &&
(l.Start.Position.y >= selectionrect.Top) &&
(l.Start.Position.x <= selectionrect.Right) &&
(l.Start.Position.y <= selectionrect.Bottom) &&
(l.End.Position.x >= selectionrect.Left) &&
(l.End.Position.y >= selectionrect.Top) &&
(l.End.Position.x <= selectionrect.Right) &&
(l.End.Position.y <= selectionrect.Bottom));
// Flip selection
highlighted.Selected = !highlighted.Selected;
// Update display
if(renderer.StartPlotter(false))
{
// Redraw highlight to show selection
renderer.PlotLinedef(highlighted, renderer.DetermineLinedefColor(highlighted));
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
renderer.Finish();
renderer.Present();
}
}
base.EndSelection();
if(renderer.StartOverlay(true)) renderer.Finish();
General.Interface.RedrawDisplay();
else
{
// Start rectangular selection
StartMultiSelection();
}
base.Select();
}
// This is called when the selection is updated
protected override void UpdateSelection()
// End selection
protected override void EndSelect()
{
base.UpdateSelection();
// Render selection
if(renderer.StartOverlay(true))
// Not stopping from multiselection?
if(!selecting)
{
RenderSelection();
renderer.Finish();
renderer.Present();
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Update display
if(renderer.StartPlotter(false))
{
// Render highlighted item
renderer.PlotLinedef(highlighted, General.Colors.Highlight);
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
renderer.Finish();
renderer.Present();
}
}
}
base.EndSelect();
}
// Start editing
protected override void Edit()
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Highlighted item not selected?
if(!highlighted.Selected)
{
// Make this the only selection
General.Map.Map.ClearSelectedLinedefs();
highlighted.Selected = true;
General.Interface.RedrawDisplay();
}
// Update display
if(renderer.StartPlotter(false))
{
// Redraw highlight to show selection
renderer.PlotLinedef(highlighted, renderer.DetermineLinedefColor(highlighted));
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
renderer.Finish();
renderer.Present();
}
}
base.Edit();
}
// Done editing
protected override void EndEdit()
{
// Anything selected?
ICollection<Linedef> selected = General.Map.Map.GetLinedefsSelection(true);
if(selected.Count > 0)
{
// Show line edit dialog
General.Interface.ShowEditLinedefs(selected);
// When a single line was selected, deselect it now
if(selected.Count == 1) General.Map.Map.ClearSelectedLinedefs();
// Update entire display
General.Interface.RedrawDisplay();
}
base.EndEdit();
}
// Mouse moves
@ -255,114 +324,13 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
Highlight(null);
}
// Mouse button pressed
public override void MouseDown(MouseEventArgs e)
{
base.MouseDown(e);
// Select button?
if(e.Button == EditMode.SELECT_BUTTON)
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Flip selection
highlighted.Selected = !highlighted.Selected;
// Update display
if(renderer.StartPlotter(false))
{
// Redraw highlight to show selection
renderer.PlotLinedef(highlighted, renderer.DetermineLinedefColor(highlighted));
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
renderer.Finish();
renderer.Present();
}
}
else
{
// Start making a selection
StartSelection();
}
}
// Edit button?
else if(e.Button == EditMode.EDIT_BUTTON)
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Highlighted item not selected?
if(!highlighted.Selected)
{
// Make this the only selection
General.Map.Map.ClearSelectedLinedefs();
highlighted.Selected = true;
General.Interface.RedrawDisplay();
}
// Update display
if(renderer.StartPlotter(false))
{
// Redraw highlight to show selection
renderer.PlotLinedef(highlighted, renderer.DetermineLinedefColor(highlighted));
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
renderer.Finish();
renderer.Present();
}
}
}
}
// Mouse released
public override void MouseUp(MouseEventArgs e)
{
ICollection<Linedef> selected;
base.MouseUp(e);
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Update display
if(renderer.StartPlotter(false))
{
// Render highlighted item
renderer.PlotLinedef(highlighted, General.Colors.Highlight);
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
renderer.Finish();
renderer.Present();
}
// Edit button?
if(e.Button == EditMode.EDIT_BUTTON)
{
// Anything selected?
selected = General.Map.Map.GetLinedefsSelection(true);
if(selected.Count > 0)
{
// Show line edit dialog
General.Interface.ShowEditLinedefs(selected);
// When a single line was selected, deselect it now
if(selected.Count == 1) General.Map.Map.ClearSelectedLinedefs();
// Update entire display
General.Interface.RedrawDisplay();
}
}
}
}
// Mouse wants to drag
protected override void DragStart(MouseEventArgs e)
{
base.DragStart(e);
// Edit button used?
if(e.Button == EditMode.EDIT_BUTTON)
if(General.Interface.CheckActionActive(null, "classicedit"))
{
// Anything highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
@ -380,6 +348,45 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
}
}
}
// This is called wheh selection ends
protected override void EndMultiSelection()
{
// Go for all lines
foreach(Linedef l in General.Map.Map.Linedefs)
{
l.Selected = ((l.Start.Position.x >= selectionrect.Left) &&
(l.Start.Position.y >= selectionrect.Top) &&
(l.Start.Position.x <= selectionrect.Right) &&
(l.Start.Position.y <= selectionrect.Bottom) &&
(l.End.Position.x >= selectionrect.Left) &&
(l.End.Position.y >= selectionrect.Top) &&
(l.End.Position.x <= selectionrect.Right) &&
(l.End.Position.y <= selectionrect.Bottom));
}
base.EndMultiSelection();
// Clear overlay
if(renderer.StartOverlay(true)) renderer.Finish();
// Redraw
General.Interface.RedrawDisplay();
}
// This is called when the selection is updated
protected override void UpdateMultiSelection()
{
base.UpdateMultiSelection();
// Render selection
if(renderer.StartOverlay(true))
{
RenderMultiSelection();
renderer.Finish();
renderer.Present();
}
}
#endregion
}

View file

@ -165,7 +165,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Render selection
if(renderer.StartOverlay(true))
{
RenderSelection();
RenderMultiSelection();
renderer.Finish();
}
}
@ -216,61 +216,107 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
General.Interface.HideInfo();
}
// This is called wheh selection ends
protected override void EndSelection()
// Selection
protected override void Select()
{
// Go for all lines
foreach(Linedef l in General.Map.Map.Linedefs)
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
l.Selected = ((l.Start.Position.x >= selectionrect.Left) &&
(l.Start.Position.y >= selectionrect.Top) &&
(l.Start.Position.x <= selectionrect.Right) &&
(l.Start.Position.y <= selectionrect.Bottom) &&
(l.End.Position.x >= selectionrect.Left) &&
(l.End.Position.y >= selectionrect.Top) &&
(l.End.Position.x <= selectionrect.Right) &&
(l.End.Position.y <= selectionrect.Bottom));
}
// Flip selection
SelectSector(highlighted, !highlighted.Selected);
// Go for all sectors
foreach(Sector s in General.Map.Map.Sectors)
{
// Go for all sidedefs
bool allselected = true;
foreach(Sidedef sd in s.Sidedefs)
// Update display
if(renderer.StartPlotter(false))
{
if(!sd.Line.Selected)
{
allselected = false;
break;
}
// Redraw highlight to show selection
renderer.PlotSector(highlighted);
renderer.Finish();
renderer.Present();
}
// Sector completely selected?
s.Selected = allselected;
}
else
{
// Start making a selection
StartMultiSelection();
}
// Make sure all linedefs reflect selected sectors
foreach(Sector s in General.Map.Map.Sectors)
SelectSector(s, s.Selected);
base.EndSelection();
if(renderer.StartOverlay(true)) renderer.Finish();
General.Interface.RedrawDisplay();
base.Select();
}
// This is called when the selection is updated
protected override void UpdateSelection()
// End selection
protected override void EndSelect()
{
base.UpdateSelection();
// Render selection
if(renderer.StartOverlay(true))
// Not stopping from multiselection?
if(!selecting)
{
RenderSelection();
renderer.Finish();
renderer.Present();
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Update display
if(renderer.StartPlotter(false))
{
// Render highlighted item
renderer.PlotSector(highlighted, General.Colors.Highlight);
renderer.Finish();
renderer.Present();
}
}
}
base.EndSelect();
}
// Start editing
protected override void Edit()
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Highlighted item not selected?
if(!highlighted.Selected)
{
// Make this the only selection
General.Map.Map.ClearSelectedSectors();
General.Map.Map.ClearSelectedLinedefs();
SelectSector(highlighted, true);
General.Interface.RedrawDisplay();
}
// Update display
if(renderer.StartPlotter(false))
{
// Redraw highlight to show selection
renderer.PlotSector(highlighted);
renderer.Finish();
renderer.Present();
}
}
base.Edit();
}
// Done editing
protected override void EndEdit()
{
// Anything selected?
ICollection<Sector> selected = General.Map.Map.GetSectorsSelection(true);
if(selected.Count > 0)
{
// Show sector edit dialog
General.Interface.ShowEditSectors(selected);
// When a single sector was selected, deselect it now
if(selected.Count == 1)
{
General.Map.Map.ClearSelectedSectors();
General.Map.Map.ClearSelectedLinedefs();
}
// Update entire display
General.Interface.RedrawDisplay();
}
base.EndEdit();
}
// Mouse moves
@ -326,113 +372,13 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
Highlight(null);
}
// Mouse button pressed
public override void MouseDown(MouseEventArgs e)
{
base.MouseDown(e);
// Select button?
if(e.Button == EditMode.SELECT_BUTTON)
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Flip selection
SelectSector(highlighted, !highlighted.Selected);
// Update display
if(renderer.StartPlotter(false))
{
// Redraw highlight to show selection
renderer.PlotSector(highlighted);
renderer.Finish();
renderer.Present();
}
}
else
{
// Start making a selection
StartSelection();
}
}
// Edit button?
else if(e.Button == EditMode.EDIT_BUTTON)
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Highlighted item not selected?
if(!highlighted.Selected)
{
// Make this the only selection
General.Map.Map.ClearSelectedSectors();
General.Map.Map.ClearSelectedLinedefs();
SelectSector(highlighted, true);
General.Interface.RedrawDisplay();
}
// Update display
if(renderer.StartPlotter(false))
{
// Redraw highlight to show selection
renderer.PlotSector(highlighted);
renderer.Finish();
renderer.Present();
}
}
}
}
// Mouse released
public override void MouseUp(MouseEventArgs e)
{
ICollection<Sector> selected;
base.MouseUp(e);
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Update display
if(renderer.StartPlotter(false))
{
// Render highlighted item
renderer.PlotSector(highlighted, General.Colors.Highlight);
renderer.Finish();
renderer.Present();
}
// Edit button?
if(e.Button == EditMode.EDIT_BUTTON)
{
// Anything selected?
selected = General.Map.Map.GetSectorsSelection(true);
if(selected.Count > 0)
{
// Show sector edit dialog
General.Interface.ShowEditSectors(selected);
// When a single sector was selected, deselect it now
if(selected.Count == 1)
{
General.Map.Map.ClearSelectedSectors();
General.Map.Map.ClearSelectedLinedefs();
}
// Update entire display
General.Interface.RedrawDisplay();
}
}
}
}
// Mouse wants to drag
protected override void DragStart(MouseEventArgs e)
{
base.DragStart(e);
// Edit button used?
if(e.Button == EditMode.EDIT_BUTTON)
if(General.Interface.CheckActionActive(null, "classicedit"))
{
// Anything highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
@ -450,6 +396,63 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
}
}
}
// This is called wheh selection ends
protected override void EndMultiSelection()
{
// Go for all lines
foreach(Linedef l in General.Map.Map.Linedefs)
{
l.Selected = ((l.Start.Position.x >= selectionrect.Left) &&
(l.Start.Position.y >= selectionrect.Top) &&
(l.Start.Position.x <= selectionrect.Right) &&
(l.Start.Position.y <= selectionrect.Bottom) &&
(l.End.Position.x >= selectionrect.Left) &&
(l.End.Position.y >= selectionrect.Top) &&
(l.End.Position.x <= selectionrect.Right) &&
(l.End.Position.y <= selectionrect.Bottom));
}
// Go for all sectors
foreach(Sector s in General.Map.Map.Sectors)
{
// Go for all sidedefs
bool allselected = true;
foreach(Sidedef sd in s.Sidedefs)
{
if(!sd.Line.Selected)
{
allselected = false;
break;
}
}
// Sector completely selected?
s.Selected = allselected;
}
// Make sure all linedefs reflect selected sectors
foreach(Sector s in General.Map.Map.Sectors)
SelectSector(s, s.Selected);
base.EndMultiSelection();
if(renderer.StartOverlay(true)) renderer.Finish();
General.Interface.RedrawDisplay();
}
// This is called when the selection is updated
protected override void UpdateMultiSelection()
{
base.UpdateMultiSelection();
// Render selection
if(renderer.StartOverlay(true))
{
RenderMultiSelection();
renderer.Finish();
renderer.Present();
}
}
#endregion
}

View file

@ -134,7 +134,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Render selection
if(renderer.StartOverlay(true))
{
RenderSelection();
RenderMultiSelection();
renderer.Finish();
}
}
@ -171,35 +171,102 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
General.Interface.HideInfo();
}
// This is called wheh selection ends
protected override void EndSelection()
// Selection
protected override void Select()
{
// Go for all things
foreach(Thing t in General.Map.Map.Things)
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
t.Selected = ((t.Position.x >= selectionrect.Left) &&
(t.Position.y >= selectionrect.Top) &&
(t.Position.x <= selectionrect.Right) &&
(t.Position.y <= selectionrect.Bottom));
// Flip selection
highlighted.Selected = !highlighted.Selected;
// Update display
if(renderer.StartThings(false))
{
// Redraw highlight to show selection
renderer.RenderThing(highlighted, renderer.DetermineThingColor(highlighted));
renderer.Finish();
renderer.Present();
}
}
else
{
// Start making a selection
StartMultiSelection();
}
base.EndSelection();
if(renderer.StartOverlay(true)) renderer.Finish();
General.Interface.RedrawDisplay();
base.Select();
}
// This is called when the selection is updated
protected override void UpdateSelection()
// End selection
protected override void EndSelect()
{
base.UpdateSelection();
// Render selection
if(renderer.StartOverlay(true))
// Not ending from a multi-selection?
if(!selecting)
{
RenderSelection();
renderer.Finish();
renderer.Present();
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Update display
if(renderer.StartThings(false))
{
// Render highlighted item
renderer.RenderThing(highlighted, General.Colors.Highlight);
renderer.Finish();
renderer.Present();
}
}
}
base.EndSelect();
}
// Start editing
protected override void Edit()
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Highlighted item not selected?
if(!highlighted.Selected)
{
// Make this the only selection
General.Map.Map.ClearSelectedThings();
highlighted.Selected = true;
General.Interface.RedrawDisplay();
}
// Update display
if(renderer.StartThings(false))
{
// Redraw highlight to show selection
renderer.RenderThing(highlighted, renderer.DetermineThingColor(highlighted));
renderer.Finish();
renderer.Present();
}
}
base.Edit();
}
// Done editing
protected override void EndEdit()
{
// Anything selected?
ICollection<Thing> selected = General.Map.Map.GetThingsSelection(true);
if(selected.Count > 0)
{
// Show thing edit dialog
// TODO
// When a single thing was selected, deselect it now
if(selected.Count == 1) General.Map.Map.ClearSelectedThings();
// Update entire display
General.Interface.RedrawDisplay();
}
base.EndEdit();
}
// Mouse moves
@ -227,108 +294,13 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
Highlight(null);
}
// Mouse button pressed
public override void MouseDown(MouseEventArgs e)
{
base.MouseDown(e);
// Select button?
if(e.Button == EditMode.SELECT_BUTTON)
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Flip selection
highlighted.Selected = !highlighted.Selected;
// Update display
if(renderer.StartThings(false))
{
// Redraw highlight to show selection
renderer.RenderThing(highlighted, renderer.DetermineThingColor(highlighted));
renderer.Finish();
renderer.Present();
}
}
else
{
// Start making a selection
StartSelection();
}
}
// Edit button?
else if(e.Button == EditMode.EDIT_BUTTON)
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Highlighted item not selected?
if(!highlighted.Selected)
{
// Make this the only selection
General.Map.Map.ClearSelectedThings();
highlighted.Selected = true;
General.Interface.RedrawDisplay();
}
// Update display
if(renderer.StartThings(false))
{
// Redraw highlight to show selection
renderer.RenderThing(highlighted, renderer.DetermineThingColor(highlighted));
renderer.Finish();
renderer.Present();
}
}
}
}
// Mouse released
public override void MouseUp(MouseEventArgs e)
{
ICollection<Thing> selected;
base.MouseUp(e);
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Update display
if(renderer.StartThings(false))
{
// Render highlighted item
renderer.RenderThing(highlighted, General.Colors.Highlight);
renderer.Finish();
renderer.Present();
}
// Edit button?
if(e.Button == EditMode.EDIT_BUTTON)
{
// Anything selected?
selected = General.Map.Map.GetThingsSelection(true);
if(selected.Count > 0)
{
// Show thing edit dialog
// TODO
// When a single thing was selected, deselect it now
if(selected.Count == 1) General.Map.Map.ClearSelectedThings();
// Update entire display
General.Interface.RedrawDisplay();
}
}
}
}
// Mouse wants to drag
protected override void DragStart(MouseEventArgs e)
{
base.DragStart(e);
// Edit button used?
if(e.Button == EditMode.EDIT_BUTTON)
if(General.Interface.CheckActionActive(null, "classicedit"))
{
// Anything highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
@ -346,6 +318,41 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
}
}
}
// This is called wheh selection ends
protected override void EndMultiSelection()
{
// Go for all things
foreach(Thing t in General.Map.Map.Things)
{
t.Selected = ((t.Position.x >= selectionrect.Left) &&
(t.Position.y >= selectionrect.Top) &&
(t.Position.x <= selectionrect.Right) &&
(t.Position.y <= selectionrect.Bottom));
}
base.EndMultiSelection();
// Clear overlay
if(renderer.StartOverlay(true)) renderer.Finish();
// Redraw
General.Interface.RedrawDisplay();
}
// This is called when the selection is updated
protected override void UpdateMultiSelection()
{
base.UpdateMultiSelection();
// Render selection
if(renderer.StartOverlay(true))
{
RenderMultiSelection();
renderer.Finish();
renderer.Present();
}
}
#endregion
}

View file

@ -150,7 +150,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Render selection
if(renderer.StartOverlay(true))
{
RenderSelection();
RenderMultiSelection();
renderer.Finish();
}
}
@ -186,36 +186,65 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
else
General.Interface.HideInfo();
}
// This is called wheh selection ends
protected override void EndSelection()
// Selection
protected override void Select()
{
// Go for all vertices
foreach(Vertex v in General.Map.Map.Vertices)
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
v.Selected = ((v.Position.x >= selectionrect.Left) &&
(v.Position.y >= selectionrect.Top) &&
(v.Position.x <= selectionrect.Right) &&
(v.Position.y <= selectionrect.Bottom));
// Flip selection
highlighted.Selected = !highlighted.Selected;
// Redraw highlight to show selection
if(renderer.StartPlotter(false))
{
renderer.PlotVertex(highlighted, renderer.DetermineVertexColor(highlighted));
renderer.Finish();
renderer.Present();
}
}
else
{
// Start making a selection
StartMultiSelection();
}
base.EndSelection();
if(renderer.StartOverlay(true)) renderer.Finish();
General.Interface.RedrawDisplay();
base.Select();
}
// This is called when the selection is updated
protected override void UpdateSelection()
// End selection
protected override void EndSelect()
{
base.UpdateSelection();
// Render selection
if(renderer.StartOverlay(true))
// Not stopping from multiselection?
if(!selecting)
{
RenderSelection();
renderer.Finish();
renderer.Present();
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Render highlighted item
if(renderer.StartPlotter(false))
{
renderer.PlotVertex(highlighted, ColorCollection.HIGHLIGHT);
renderer.Finish();
renderer.Present();
}
}
}
base.EndSelect();
}
// Start editing
protected override void Edit()
{
base.Edit();
}
// Done editing
protected override void EndEdit()
{
base.EndEdit();
}
// Mouse moves
@ -242,54 +271,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Highlight nothing
Highlight(null);
}
// Mouse button pressed
public override void MouseDown(MouseEventArgs e)
{
base.MouseDown(e);
// Which button is used?
if(e.Button == EditMode.SELECT_BUTTON)
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Flip selection
highlighted.Selected = !highlighted.Selected;
// Redraw highlight to show selection
if(renderer.StartPlotter(false))
{
renderer.PlotVertex(highlighted, renderer.DetermineVertexColor(highlighted));
renderer.Finish();
renderer.Present();
}
}
else
{
// Start making a selection
StartSelection();
}
}
}
// Mouse released
public override void MouseUp(MouseEventArgs e)
{
base.MouseUp(e);
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Render highlighted item
if(renderer.StartPlotter(false))
{
renderer.PlotVertex(highlighted, ColorCollection.HIGHLIGHT);
renderer.Finish();
renderer.Present();
}
}
}
// Mouse wants to drag
protected override void DragStart(MouseEventArgs e)
@ -297,7 +278,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
base.DragStart(e);
// Edit button used?
if(e.Button == EditMode.EDIT_BUTTON)
if(General.Interface.CheckActionActive(null, "classicedit"))
{
// Anything highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
@ -315,6 +296,41 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
}
}
}
// This is called wheh selection ends
protected override void EndMultiSelection()
{
// Go for all vertices
foreach(Vertex v in General.Map.Map.Vertices)
{
v.Selected = ((v.Position.x >= selectionrect.Left) &&
(v.Position.y >= selectionrect.Top) &&
(v.Position.x <= selectionrect.Right) &&
(v.Position.y <= selectionrect.Bottom));
}
base.EndMultiSelection();
// Clear overlay
if(renderer.StartOverlay(true)) renderer.Finish();
// Redraw
General.Interface.RedrawDisplay();
}
// This is called when the selection is updated
protected override void UpdateMultiSelection()
{
base.UpdateMultiSelection();
// Render selection
if(renderer.StartOverlay(true))
{
RenderMultiSelection();
renderer.Finish();
renderer.Present();
}
}
#endregion
}

View file

@ -2,8 +2,21 @@
Doom Builder Actions Configuration
\******************************************/
// This just defines which actions there are and what description they have
// The source code will bind to these actions with delegates (function pointers)
// This just defines which actions there are, what description they have and
// some behaviour options. The Doom Builder core will bind to these actions
// with delegates (function pointers) where you use the BeginAction and
// EndAction attributes.
// Behaviour options:
//
// allowkeys: Allows the user to bind standard keys to this action.
// allowmouse: Allows the user to bind mouse buttons to this action.
// allowscroll: Allows the user to bind the scrollwheel to this action.
// disregardshift: This action will be triggered regardless if Shift or Control are used.
// repeat: BeginAction will be called for automatic key repetition.
//
// allowkeys and allowmouse are true by default, the others are false by default.
//
verticesmode
{
@ -43,8 +56,36 @@ thingsmode
drawlinesmode
{
title = "Edit: Draw Lines";
description = "Starts drawing lines.";
title = "2D: Draw Lines";
description = "Starts drawing lines. See the Drawing category for actions available during drawing mode.";
allowkeys = true;
allowmouse = true;
allowscroll = true;
}
drawpoint
{
title = "Drawing: Draws Vertex";
description = "Draws a vertex at the mousecursor position.";
allowkeys = true;
allowmouse = true;
allowscroll = true;
disregardshift = true;
}
removepoint
{
title = "Drawing: Remove Previous Vertex";
description = "Removes the previously drawn vertex from the drawing session.";
allowkeys = true;
allowmouse = true;
allowscroll = true;
}
finishdraw
{
title = "Drawing: Finish Drawing";
description = "Finishes the drawing and creates the geometry.";
allowkeys = true;
allowmouse = true;
allowscroll = true;

View file

@ -232,8 +232,8 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
base.MouseDown(e);
bool front, back;
// Which button is used?
if(e.Button == EditMode.SELECT_BUTTON)
// Edit button is used?
if(General.Interface.CheckActionActive(null, "classicedit"))
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
@ -272,8 +272,8 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Which button is used?
if(e.Button == EditMode.SELECT_BUTTON)
// Edit button is used?
if(General.Interface.CheckActionActive(null, "classicedit"))
{
// Anything selected?
selected = General.Map.Map.GetSectorsSelection(true);

View file

@ -39,14 +39,18 @@ namespace CodeImp.DoomBuilder.Controls
// Shortcut key
private int key;
private int keymask;
// Shortcut options
private bool allowkeys;
private bool allowmouse;
private bool allowscroll;
private bool disregardshift;
private bool repeat;
// Delegate
private List<ActionDelegate> delegates;
private List<ActionDelegate> begindelegates;
private List<ActionDelegate> enddelegates;
#endregion
@ -57,9 +61,12 @@ namespace CodeImp.DoomBuilder.Controls
public string Title { get { return title; } }
public string Description { get { return description; } }
public int ShortcutKey { get { return key; } }
public int ShortcutMask { get { return keymask; } }
public bool AllowKeys { get { return allowkeys; } }
public bool AllowMouse { get { return allowmouse; } }
public bool AllowScroll { get { return allowscroll; } }
public bool DisregardShift { get { return disregardshift; } }
public bool Repeat { get { return repeat; } }
#endregion
@ -67,18 +74,32 @@ namespace CodeImp.DoomBuilder.Controls
// Constructor
public Action(string name, string shortname, string title, string description, int key,
bool allowkeys, bool allowmouse, bool allowscroll)
bool allowkeys, bool allowmouse, bool allowscroll, bool disregardshift, bool repeat)
{
// Initialize
this.name = name;
this.shortname = shortname;
this.title = title;
this.description = description;
this.delegates = new List<ActionDelegate>();
this.begindelegates = new List<ActionDelegate>();
this.enddelegates = new List<ActionDelegate>();
this.allowkeys = allowkeys;
this.allowmouse = allowmouse;
this.allowscroll = allowscroll;
this.key = key;
this.disregardshift = disregardshift;
this.repeat = repeat;
if(disregardshift)
{
keymask = (int)Keys.Shift | (int)Keys.Control;
keymask = ~keymask;
}
else
{
keymask = ~0;
}
this.key = key & keymask;
}
// Destructor
@ -166,42 +187,71 @@ namespace CodeImp.DoomBuilder.Controls
public void SetShortcutKey(int key)
{
// Make it so.
this.key = key;
this.key = key & keymask;
}
// This binds a delegate to this action
public void Bind(ActionDelegate method)
public void BindBegin(ActionDelegate method)
{
delegates.Add(method);
begindelegates.Add(method);
}
// This removes a delegate from this action
public void Unbind(ActionDelegate method)
public void UnbindBegin(ActionDelegate method)
{
delegates.Remove(method);
begindelegates.Remove(method);
}
// This binds a delegate to this action
public void BindEnd(ActionDelegate method)
{
enddelegates.Add(method);
}
// This removes a delegate from this action
public void UnbindEnd(ActionDelegate method)
{
enddelegates.Remove(method);
}
// This raises events for this action
public void Invoke()
public void Begin()
{
List<ActionDelegate> delegateslist;
// No method bound?
if(delegates.Count == 0)
{
// Ignore this since keys can also be handled through KeyDown and KeyUp in editing modes
//General.WriteLogLine("Called action '" + name + "' has no methods bound");
}
else
// Method bound?
if(begindelegates.Count > 0)
{
// Copy delegates list
delegateslist = new List<ActionDelegate>(delegates);
delegateslist = new List<ActionDelegate>(begindelegates);
// Invoke all the delegates
foreach(ActionDelegate ad in delegateslist) ad.Invoke();
}
}
// This raises events for this action
public void End()
{
List<ActionDelegate> delegateslist;
// Method bound?
if(enddelegates.Count > 0)
{
// Copy delegates list
delegateslist = new List<ActionDelegate>(enddelegates);
// Invoke all the delegates
foreach(ActionDelegate ad in delegateslist) ad.Invoke();
}
}
// This checks if the action qualifies for a key combination
public bool KeyMatches(int pressedkey)
{
return (key == (pressedkey & keymask));
}
#endregion
}
}

View file

@ -30,15 +30,15 @@ namespace CodeImp.DoomBuilder.Controls
/// <summary>
/// This binds a method to an action.
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited=true, AllowMultiple=true)]
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class ActionAttribute : Attribute
{
#region ================== Variables
// The action to bind to
private string action;
private bool baseaction;
protected string action;
protected bool baseaction;
#endregion
#region ================== Properties
@ -47,6 +47,7 @@ namespace CodeImp.DoomBuilder.Controls
/// Set to true to indicate this is a core Doom Builder action when used within a plugin.
/// </summary>
public bool BaseAction { get { return baseaction; } set { baseaction = value; } }
internal string ActionName { get { return action; } }
#endregion
@ -71,19 +72,15 @@ namespace CodeImp.DoomBuilder.Controls
public string GetFullActionName(Assembly asm)
{
string asmname;
if(baseaction)
asmname = General.ThisAssembly.GetName().Name.ToLowerInvariant();
else
asmname = asm.GetName().Name.ToLowerInvariant();
return asmname + "_" + action;
}
#endregion
#region ================== Static Methods
// This makes the proper name
public string GetFullActionName(Assembly asm, bool baseaction, string actionname)
{
@ -97,134 +94,6 @@ namespace CodeImp.DoomBuilder.Controls
return asmname + "_" + actionname;
}
// This binds all methods marked with this attribute
internal static void BindMethods(Type type)
{
// Bind static methods
BindMethods(null, type);
}
// This binds all methods marked with this attribute
internal static void BindMethods(object obj)
{
// Bind instance methods
BindMethods(obj, obj.GetType());
}
// This binds all methods marked with this attribute
private static void BindMethods(object obj, Type type)
{
MethodInfo[] methods;
ActionAttribute[] attrs;
ActionDelegate del;
string actionname;
if(obj == null)
General.WriteLogLine("Binding static action methods for class " + type.Name + "...");
else
General.WriteLogLine("Binding action methods for " + type.Name + " object...");
// Go for all methods on obj
methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
foreach(MethodInfo m in methods)
{
// Check if the method has this attribute
attrs = (ActionAttribute[])m.GetCustomAttributes(typeof(ActionAttribute), true);
// Go for all attributes
foreach(ActionAttribute a in attrs)
{
// Create a delegate for this method
del = (ActionDelegate)Delegate.CreateDelegate(typeof(ActionDelegate), obj, m);
// Make proper name
actionname = a.GetFullActionName(type.Assembly);
// Bind method to action
if(General.Actions.Exists(actionname))
General.Actions[actionname].Bind(del);
else
throw new ArgumentException("Could not bind " + m.ReflectedType.Name + "." + m.Name + " to action \"" + actionname + "\", that action does not exist! Refer to, or edit Actions.cfg for all available application actions.");
}
}
}
// This binds a delegate manually
internal static void BindDelegate(Assembly asm, ActionDelegate d, ActionAttribute a)
{
string actionname;
// Make proper name
actionname = a.GetFullActionName(asm);
// Bind delegate to action
if(General.Actions.Exists(actionname))
General.Actions[actionname].Bind(d);
else
General.WriteLogLine("WARNING: Could not bind delegate for " + d.Method.Name + " to action \"" + a.action + "\" (" + actionname + "), that action does not exist! Refer to, or edit Actions.cfg for all available application actions.");
}
// This unbinds all methods marked with this attribute
internal static void UnbindMethods(Type type)
{
// Unbind static methods
UnbindMethods(null, type);
}
// This unbinds all methods marked with this attribute
internal static void UnbindMethods(object obj)
{
// Unbind instance methods
UnbindMethods(obj, obj.GetType());
}
// This unbinds all methods marked with this attribute
private static void UnbindMethods(object obj, Type type)
{
MethodInfo[] methods;
ActionAttribute[] attrs;
ActionDelegate del;
string actionname;
if(obj == null)
General.WriteLogLine("Unbinding static action methods for class " + type.Name + "...");
else
General.WriteLogLine("Unbinding action methods for " + type.Name + " object...");
// Go for all methods on obj
methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
foreach(MethodInfo m in methods)
{
// Check if the method has this attribute
attrs = (ActionAttribute[])m.GetCustomAttributes(typeof(ActionAttribute), true);
// Go for all attributes
foreach(ActionAttribute a in attrs)
{
// Create a delegate for this method
del = (ActionDelegate)Delegate.CreateDelegate(typeof(ActionDelegate), obj, m);
// Make proper name
actionname = a.GetFullActionName(type.Assembly);
// Unbind method from action
General.Actions[actionname].Unbind(del);
}
}
}
// This unbinds a delegate manually
internal static void UnbindDelegate(Assembly asm, ActionDelegate d, ActionAttribute a)
{
string actionname;
// Make proper name
actionname = a.GetFullActionName(asm);
// Unbind delegate to action
General.Actions[actionname].Unbind(d);
}
#endregion
}
}

View file

@ -26,6 +26,7 @@ using System.IO;
using CodeImp.DoomBuilder.IO;
using System.Collections;
using System.Reflection;
using System.Windows.Forms;
#endregion
@ -44,6 +45,13 @@ namespace CodeImp.DoomBuilder.Controls
// Actions
private Dictionary<string, Action> actions;
// Keys state
private int modifiers;
private List<int> pressedkeys;
// Begun actions
private List<Action> activeactions;
// Disposing
private bool isdisposed = false;
@ -64,7 +72,9 @@ namespace CodeImp.DoomBuilder.Controls
// Initialize
General.WriteLogLine("Starting action manager...");
actions = new Dictionary<string, Action>();
pressedkeys = new List<int>();
activeactions = new List<Action>();
// Load all actions in this assembly
LoadActions(General.ThisAssembly);
@ -96,7 +106,7 @@ namespace CodeImp.DoomBuilder.Controls
StreamReader actionsreader;
Configuration cfg;
string name, title, desc, shortname;
bool amouse, akeys, ascroll, debugonly;
bool amouse, akeys, ascroll, debugonly, noshift, repeat;
string[] resnames;
AssemblyName asmname = asm.GetName();
@ -127,16 +137,18 @@ namespace CodeImp.DoomBuilder.Controls
name = asmname.Name.ToLowerInvariant() + "_" + shortname;
title = cfg.ReadSetting(a.Key + ".title", "[" + name + "]");
desc = cfg.ReadSetting(a.Key + ".description", "");
akeys = cfg.ReadSetting(a.Key + ".allowkeys", false);
amouse = cfg.ReadSetting(a.Key + ".allowmouse", false);
akeys = cfg.ReadSetting(a.Key + ".allowkeys", true);
amouse = cfg.ReadSetting(a.Key + ".allowmouse", true);
ascroll = cfg.ReadSetting(a.Key + ".allowscroll", false);
noshift = cfg.ReadSetting(a.Key + ".disregardshift", false);
repeat = cfg.ReadSetting(a.Key + ".repeat", false);
debugonly = cfg.ReadSetting(a.Key + ".debugonly", false);
// Check if action should be included
if(General.DebugBuild || !debugonly)
{
// Create an action
CreateAction(name, shortname, title, desc, akeys, amouse, ascroll);
CreateAction(name, shortname, title, desc, akeys, amouse, ascroll, noshift, repeat);
}
}
}
@ -144,7 +156,7 @@ namespace CodeImp.DoomBuilder.Controls
}
// This manually creates an action
private void CreateAction(string name, string shortname, string title, string desc, bool allowkeys, bool allowmouse, bool allowscroll)
private void CreateAction(string name, string shortname, string title, string desc, bool allowkeys, bool allowmouse, bool allowscroll, bool disregardshift, bool repeat)
{
// Action does not exist yet?
if(!actions.ContainsKey(name))
@ -153,7 +165,7 @@ namespace CodeImp.DoomBuilder.Controls
int key = General.Settings.ReadSetting("shortcuts." + name, 0);
// Create an action
actions.Add(name, new Action(name, shortname, title, desc, key, allowkeys, allowmouse, allowscroll));
actions.Add(name, new Action(name, shortname, title, desc, key, allowkeys, allowmouse, allowscroll, disregardshift, repeat));
}
else
{
@ -161,6 +173,196 @@ namespace CodeImp.DoomBuilder.Controls
General.WriteLogLine("WARNING: Action '" + name + "' already exists. Action names must be unique!");
}
}
// This binds all methods marked with this attribute
internal void BindMethods(Type type)
{
// Bind static methods
BindMethods(null, type);
}
// This binds all methods marked with this attribute
internal void BindMethods(object obj)
{
// Bind instance methods
BindMethods(obj, obj.GetType());
}
// This binds all methods marked with this attribute
private void BindMethods(object obj, Type type)
{
MethodInfo[] methods;
ActionAttribute[] attrs;
ActionDelegate del;
string actionname;
if(obj == null)
General.WriteLogLine("Binding static action methods for class " + type.Name + "...");
else
General.WriteLogLine("Binding action methods for " + type.Name + " object...");
// Go for all methods on obj
methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
foreach(MethodInfo m in methods)
{
// Check if the method has this attribute
attrs = (ActionAttribute[])m.GetCustomAttributes(typeof(BeginActionAttribute), true);
// Go for all attributes
foreach(ActionAttribute a in attrs)
{
// Create a delegate for this method
del = (ActionDelegate)Delegate.CreateDelegate(typeof(ActionDelegate), obj, m);
// Make proper name
actionname = a.GetFullActionName(type.Assembly);
// Bind method to action
if(Exists(actionname))
actions[actionname].BindBegin(del);
else
throw new ArgumentException("Could not bind " + m.ReflectedType.Name + "." + m.Name + " to action \"" + actionname + "\", that action does not exist! Refer to, or edit Actions.cfg for all available application actions.");
}
// Check if the method has this attribute
attrs = (ActionAttribute[])m.GetCustomAttributes(typeof(EndActionAttribute), true);
// Go for all attributes
foreach(ActionAttribute a in attrs)
{
// Create a delegate for this method
del = (ActionDelegate)Delegate.CreateDelegate(typeof(ActionDelegate), obj, m);
// Make proper name
actionname = a.GetFullActionName(type.Assembly);
// Bind method to action
if(Exists(actionname))
actions[actionname].BindEnd(del);
else
throw new ArgumentException("Could not bind " + m.ReflectedType.Name + "." + m.Name + " to action \"" + actionname + "\", that action does not exist! Refer to, or edit Actions.cfg for all available application actions.");
}
}
}
// This binds a delegate manually
internal void BindBeginDelegate(Assembly asm, ActionDelegate d, BeginActionAttribute a)
{
string actionname;
// Make proper name
actionname = a.GetFullActionName(asm);
// Bind delegate to action
if(Exists(actionname))
actions[actionname].BindBegin(d);
else
General.WriteLogLine("WARNING: Could not bind delegate for " + d.Method.Name + " to action \"" + a.ActionName + "\" (" + actionname + "), that action does not exist! Refer to, or edit Actions.cfg for all available application actions.");
}
// This binds a delegate manually
internal void BindEndDelegate(Assembly asm, ActionDelegate d, EndActionAttribute a)
{
string actionname;
// Make proper name
actionname = a.GetFullActionName(asm);
// Bind delegate to action
if(Exists(actionname))
actions[actionname].BindEnd(d);
else
General.WriteLogLine("WARNING: Could not bind delegate for " + d.Method.Name + " to action \"" + a.ActionName + "\" (" + actionname + "), that action does not exist! Refer to, or edit Actions.cfg for all available application actions.");
}
// This unbinds all methods marked with this attribute
internal void UnbindMethods(Type type)
{
// Unbind static methods
UnbindMethods(null, type);
}
// This unbinds all methods marked with this attribute
internal void UnbindMethods(object obj)
{
// Unbind instance methods
UnbindMethods(obj, obj.GetType());
}
// This unbinds all methods marked with this attribute
private void UnbindMethods(object obj, Type type)
{
MethodInfo[] methods;
ActionAttribute[] attrs;
ActionDelegate del;
string actionname;
if(obj == null)
General.WriteLogLine("Unbinding static action methods for class " + type.Name + "...");
else
General.WriteLogLine("Unbinding action methods for " + type.Name + " object...");
// Go for all methods on obj
methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
foreach(MethodInfo m in methods)
{
// Check if the method has this attribute
attrs = (ActionAttribute[])m.GetCustomAttributes(typeof(BeginActionAttribute), true);
// Go for all attributes
foreach(ActionAttribute a in attrs)
{
// Create a delegate for this method
del = (ActionDelegate)Delegate.CreateDelegate(typeof(ActionDelegate), obj, m);
// Make proper name
actionname = a.GetFullActionName(type.Assembly);
// Unbind method from action
actions[actionname].UnbindBegin(del);
}
// Check if the method has this attribute
attrs = (ActionAttribute[])m.GetCustomAttributes(typeof(EndActionAttribute), true);
// Go for all attributes
foreach(ActionAttribute a in attrs)
{
// Create a delegate for this method
del = (ActionDelegate)Delegate.CreateDelegate(typeof(ActionDelegate), obj, m);
// Make proper name
actionname = a.GetFullActionName(type.Assembly);
// Unbind method from action
actions[actionname].UnbindEnd(del);
}
}
}
// This unbinds a delegate manually
internal void UnbindBeginDelegate(Assembly asm, ActionDelegate d, BeginActionAttribute a)
{
string actionname;
// Make proper name
actionname = a.GetFullActionName(asm);
// Unbind delegate to action
actions[actionname].UnbindBegin(d);
}
// This unbinds a delegate manually
internal void UnbindEndDelegate(Assembly asm, ActionDelegate d, EndActionAttribute a)
{
string actionname;
// Make proper name
actionname = a.GetFullActionName(asm);
// Unbind delegate to action
actions[actionname].UnbindEnd(d);
}
// This checks if a given action exists
public bool Exists(string action)
@ -190,7 +392,21 @@ namespace CodeImp.DoomBuilder.Controls
#endregion
#region ================== Shortcut Keys
// This checks if a given action is active
public bool CheckActionActive(Assembly asm, string actionname)
{
// Find active action
string fullname = asm.GetName().Name.ToLowerInvariant() + "_" + actionname;
foreach(Action a in activeactions)
{
if(a.Name == fullname) return true;
}
// No such active action
return false;
}
// Removes all shortcut keys
public void RemoveShortcutKeys()
{
@ -199,23 +415,95 @@ namespace CodeImp.DoomBuilder.Controls
a.Value.SetShortcutKey(0);
}
// This notifies a key has been pressed
public void KeyPressed(int key)
{
int strippedkey = key & ~((int)Keys.Alt | (int)Keys.Shift | (int)Keys.Control);
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);
}
// This notifies a key has been released
public void KeyReleased(int key)
{
int strippedkey = key & ~((int)Keys.Alt | (int)Keys.Shift | (int)Keys.Control);
List<Action> keepactions = new List<Action>();
// Update pressed keys
if(pressedkeys.Contains(strippedkey)) pressedkeys.Remove(strippedkey);
// End actions that no longer match
EndActiveActions();
}
// This updates the modifiers
public void UpdateModifiers(int mods)
{
// Update modifiers
modifiers = mods;
// End actions that no longer match
EndActiveActions();
}
// This will call the associated actions for a keypress
public void InvokeByKey(int key)
private void BeginActionByKey(int key, bool repeated)
{
// Go for all actions
foreach(KeyValuePair<string, Action> a in actions)
{
// This action is associated with this key?
if(a.Value.ShortcutKey == key)
if(a.Value.KeyMatches(key) && (a.Value.Repeat || !repeated))
{
// Invoke action
a.Value.Invoke();
a.Value.Begin();
}
}
}
// This will end active actions for which the pressed keys do not match
private void EndActiveActions()
{
List<Action> keepactions = new List<Action>();
// Go for all active actions
foreach(Action a in activeactions)
{
// Go for all pressed keys
bool stillactive = false;
foreach(int k in pressedkeys)
{
if((k == (int)Keys.ShiftKey) || (k == (int)Keys.ControlKey))
stillactive |= a.KeyMatches(k);
else
stillactive |= a.KeyMatches(k | modifiers);
}
// End the action if no longer matches any of the keys
if(!stillactive)
{
a.End();
}
else
{
keepactions.Add(a);
}
}
// Update list of activate actions
activeactions = keepactions;
}
// This returns all action names for a given key
public string[] GetActionsByKey(int key)
public string[] GetActionNamesByKey(int key)
{
List<string> actionnames = new List<string>();
@ -223,7 +511,7 @@ namespace CodeImp.DoomBuilder.Controls
foreach(KeyValuePair<string, Action> a in actions)
{
// This action is associated with this key?
if(a.Value.ShortcutKey == key)
if(a.Value.KeyMatches(key))
{
// List short name
actionnames.Add(a.Value.ShortName);
@ -233,6 +521,26 @@ namespace CodeImp.DoomBuilder.Controls
// Return result;
return actionnames.ToArray();
}
// This returns all action names for a given key
public Action[] GetActionsByKey(int key)
{
List<Action> actionnames = new List<Action>();
// Go for all actions
foreach(KeyValuePair<string, Action> a in actions)
{
// This action is associated with this key?
if(a.Value.KeyMatches(key))
{
// List short name
actionnames.Add(a.Value);
}
}
// Return result;
return actionnames.ToArray();
}
#endregion
}

View file

@ -0,0 +1,43 @@
#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.Drawing;
using System.Text;
using System.Reflection;
#endregion
namespace CodeImp.DoomBuilder.Controls
{
/// <summary>
/// This binds a method to an action which is then called when the action is started.
/// </summary>
public class BeginActionAttribute : ActionAttribute
{
/// <summary>
/// This binds a method to an action which is then called when the action is started.
/// </summary>
/// <param name="action">The action name as defined in Actions.cfg resource.</param>
public BeginActionAttribute(string action) : base(action)
{
}
}
}

View file

@ -0,0 +1,43 @@
#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.Drawing;
using System.Text;
using System.Reflection;
#endregion
namespace CodeImp.DoomBuilder.Controls
{
/// <summary>
/// This binds a method to an action which is then called when the action is stopped.
/// </summary>
public class EndActionAttribute : ActionAttribute
{
/// <summary>
/// This binds a method to an action which is then called when the action is stopped.
/// </summary>
/// <param name="action">The action name as defined in Actions.cfg resource.</param>
public EndActionAttribute(string action) : base(action)
{
}
}
}

View file

@ -109,7 +109,7 @@ namespace CodeImp.DoomBuilder.Editing
#region ================== Scroll / Zoom
// This scrolls the view north
[Action("scrollnorth", BaseAction = true)]
[BeginAction("scrollnorth", BaseAction = true)]
public virtual void ScrollNorth()
{
// Scroll
@ -117,7 +117,7 @@ namespace CodeImp.DoomBuilder.Editing
}
// This scrolls the view south
[Action("scrollsouth", BaseAction = true)]
[BeginAction("scrollsouth", BaseAction = true)]
public virtual void ScrollSouth()
{
// Scroll
@ -125,7 +125,7 @@ namespace CodeImp.DoomBuilder.Editing
}
// This scrolls the view west
[Action("scrollwest", BaseAction = true)]
[BeginAction("scrollwest", BaseAction = true)]
public virtual void ScrollWest()
{
// Scroll
@ -133,7 +133,7 @@ namespace CodeImp.DoomBuilder.Editing
}
// This scrolls the view east
[Action("scrolleast", BaseAction = true)]
[BeginAction("scrolleast", BaseAction = true)]
public virtual void ScrollEast()
{
// Scroll
@ -141,7 +141,7 @@ namespace CodeImp.DoomBuilder.Editing
}
// This zooms in
[Action("zoomin", BaseAction = true)]
[BeginAction("zoomin", BaseAction = true)]
public virtual void ZoomIn()
{
// Zoom
@ -149,7 +149,7 @@ namespace CodeImp.DoomBuilder.Editing
}
// This zooms out
[Action("zoomout", BaseAction = true)]
[BeginAction("zoomout", BaseAction = true)]
public virtual void ZoomOut()
{
// Zoom
@ -232,7 +232,7 @@ namespace CodeImp.DoomBuilder.Editing
}
// This zooms and scrolls to fit the map in the window
[Action("centerinscreen", BaseAction = true)]
[BeginAction("centerinscreen", BaseAction = true)]
public void CenterInScreen()
{
float left = float.MaxValue;
@ -318,8 +318,7 @@ namespace CodeImp.DoomBuilder.Editing
General.MainWindow.UpdateCoordinates(mousemappos);
// Holding a button?
if((e.Button == EditMode.EDIT_BUTTON) ||
(e.Button == EditMode.SELECT_BUTTON))
if(e.Button != MouseButtons.None)
{
// Not dragging?
if(mousedragging == MouseButtons.None)
@ -337,7 +336,7 @@ namespace CodeImp.DoomBuilder.Editing
}
// Selecting?
if(selecting) UpdateSelection();
if(selecting) UpdateMultiSelection();
// Let the base class know
base.MouseMove(e);
@ -364,24 +363,23 @@ namespace CodeImp.DoomBuilder.Editing
DragStop(e);
mousedragging = MouseButtons.None;
}
// Selection stops
if(selecting) EndSelection();
// Let the base class know
base.MouseUp(e);
}
// This is called when the mouse is moved enough pixels and holding one or more buttons
/// <summary>
/// Automatically called when dragging operation starts.
/// </summary>
protected virtual void DragStart(MouseEventArgs e)
{
}
// This is called when a drag is ended because the mouse buton is released
/// <summary>
/// Automatically called when dragging operation stops.
/// </summary>
protected virtual void DragStop(MouseEventArgs e)
{
}
#endregion
@ -398,23 +396,85 @@ namespace CodeImp.DoomBuilder.Editing
#region ================== Methods
// Cancelling
/// <summary>
/// Automatically called by the core when this editing mode is engaged.
/// </summary>
public override void Engage()
{
// Clear display overlay
renderer.StartOverlay(true);
renderer.Finish();
base.Engage();
}
/// <summary>
/// Called when the user requests to cancel this editing mode.
/// </summary>
public override void Cancel()
{
cancelled = true;
base.Cancel();
}
// This starts a selection
protected virtual void StartSelection()
/// <summary>
/// This is called automatically when the Edit button is pressed.
/// (in Doom Builder 1, this was always the right mousebutton)
/// </summary>
[BeginAction("classicedit", BaseAction = true)]
protected virtual void Edit()
{
}
/// <summary>
/// This is called automatically when the Edit button is released.
/// (in Doom Builder 1, this was always the right mousebutton)
/// </summary>
[EndAction("classicedit", BaseAction = true)]
protected virtual void EndEdit()
{
}
/// <summary>
/// This is called automatically when the Select button is pressed.
/// (in Doom Builder 1, this was always the left mousebutton)
/// </summary>
[BeginAction("classicselect", BaseAction = true)]
protected virtual void Select()
{
}
/// <summary>
/// This is called automatically when the Select button is released.
/// (in Doom Builder 1, this was always the left mousebutton)
/// </summary>
[EndAction("classicselect", BaseAction = true)]
protected virtual void EndSelect()
{
if(selecting) EndMultiSelection();
}
/// <summary>
/// This is called automatically when a rectangular multi-selection ends.
/// </summary>
protected virtual void EndMultiSelection()
{
selecting = false;
}
/// <summary>
/// Call this to initiate a rectangular multi-selection.
/// </summary>
protected virtual void StartMultiSelection()
{
selecting = true;
selectstart = mousemappos;
selectionrect = new RectangleF(selectstart.x, selectstart.y, 0, 0);
}
// This updates a selection
protected virtual void UpdateSelection()
/// <summary>
/// This is called automatically when a multi-selection is updated.
/// </summary>
protected virtual void UpdateMultiSelection()
{
selectionrect.X = selectstart.x;
selectionrect.Y = selectstart.y;
@ -434,15 +494,11 @@ namespace CodeImp.DoomBuilder.Editing
}
}
// This is called when a selection is released
protected virtual void EndSelection()
{
selecting = false;
}
// This draws the selection on the overlay layer
// Must call renderer.StartOverlay first!
protected virtual void RenderSelection()
/// <summary>
/// Call this to draw the selection on the overlay layer.
/// Must call renderer.StartOverlay first!
/// </summary>
protected virtual void RenderMultiSelection()
{
renderer.RenderRectangle(selectionrect, SELECTION_BORDER_SIZE,
General.Colors.Highlight.WithAlpha(SELECTION_ALPHA), true);

View file

@ -44,8 +44,6 @@ namespace CodeImp.DoomBuilder.Editing
#region ================== Constants
public const int DRAG_START_MOVE_PIXELS = 5;
public const MouseButtons EDIT_BUTTON = MouseButtons.Right;
public const MouseButtons SELECT_BUTTON = MouseButtons.Left;
#endregion
@ -133,18 +131,18 @@ namespace CodeImp.DoomBuilder.Editing
public virtual void Engage()
{
// Bind any methods
ActionAttribute.BindMethods(this);
General.Actions.BindMethods(this);
}
// Mode disengages
public virtual void Disengage()
{
// Unbind any methods
ActionAttribute.UnbindMethods(this);
General.Actions.UnbindMethods(this);
}
// This forces the mode to cancel and return to the "parent" mode
[Action("cancelmode", BaseAction = true)]
[BeginAction("cancelmode", BaseAction = true)]
public virtual void Cancel() { }
// Optional interface methods

View file

@ -46,7 +46,7 @@ namespace CodeImp.DoomBuilder.Editing
private bool configspecific;
// Mode switching
private ActionAttribute switchactionattr = null;
private BeginActionAttribute switchactionattr = null;
private ActionDelegate switchactiondel = null;
// Mode button
@ -61,7 +61,7 @@ namespace CodeImp.DoomBuilder.Editing
public Plugin Plugin { get { return plugin; } }
public Type Type { get { return type; } }
public ActionAttribute SwitchAction { get { return switchactionattr; } }
public BeginActionAttribute SwitchAction { get { return switchactionattr; } }
public Image ButtonImage { get { return buttonimage; } }
public string ButtonDesc { get { return buttondesc; } }
public bool ConfigSpecific { get { return configspecific; } }
@ -81,11 +81,11 @@ namespace CodeImp.DoomBuilder.Editing
// Make switch action info
if((attr.SwitchAction != null) && (attr.SwitchAction.Length > 0))
{
switchactionattr = new ActionAttribute(attr.SwitchAction);
switchactionattr = new BeginActionAttribute(attr.SwitchAction);
switchactiondel = new ActionDelegate(SwitchToMode);
// Bind switch action
ActionAttribute.BindDelegate(plugin.Assembly, switchactiondel, switchactionattr);
General.Actions.BindBeginDelegate(plugin.Assembly, switchactiondel, switchactionattr);
}
// Make button info
@ -108,7 +108,7 @@ namespace CodeImp.DoomBuilder.Editing
public void Dispose()
{
// Unbind switch action
if(switchactiondel != null) ActionAttribute.UnbindDelegate(plugin.Assembly, switchactiondel, switchactionattr);
if(switchactiondel != null) General.Actions.UnbindBeginDelegate(plugin.Assembly, switchactiondel, switchactionattr);
buttonimage.Dispose();
buttonimagestream.Dispose();

View file

@ -78,7 +78,7 @@ namespace CodeImp.DoomBuilder.Editing
redos = new List<UndoSnapshot>(General.Settings.UndoLevels + 1);
// Bind any methods
ActionAttribute.BindMethods(this);
General.Actions.BindMethods(this);
// We have no destructor
GC.SuppressFinalize(this);
@ -91,7 +91,7 @@ namespace CodeImp.DoomBuilder.Editing
if(!isdisposed)
{
// Unbind any methods
ActionAttribute.UnbindMethods(this);
General.Actions.UnbindMethods(this);
// Clean up
ClearUndos();
@ -199,7 +199,7 @@ namespace CodeImp.DoomBuilder.Editing
}
// This performs an undo
[Action("undo")]
[BeginAction("undo")]
public void PerformUndo()
{
UndoSnapshot u, r;
@ -235,7 +235,7 @@ namespace CodeImp.DoomBuilder.Editing
}
// This performs a redo
[Action("redo")]
[BeginAction("redo")]
public void PerformRedo()
{
UndoSnapshot u, r;

View file

@ -184,6 +184,7 @@ namespace CodeImp.DoomBuilder.Editing
base.KeyDown(e);
/* WRONG
// Get the actions for this key
actions = General.Actions.GetActionsByKey((int)e.KeyData);
foreach(string a in actions)
@ -197,6 +198,7 @@ namespace CodeImp.DoomBuilder.Editing
case "moveright": keyright = true; break;
}
}
*/
}
// Key up
@ -206,6 +208,7 @@ namespace CodeImp.DoomBuilder.Editing
base.KeyUp(e);
/* WRONG
// Get the actions for this key
actions = General.Actions.GetActionsByKey((int)e.KeyData);
foreach(string a in actions)
@ -219,6 +222,7 @@ namespace CodeImp.DoomBuilder.Editing
case "moveright": keyright = false; break;
}
}
*/
}
#endregion

View file

@ -436,7 +436,7 @@ namespace CodeImp.DoomBuilder
actions = new ActionManager();
// Bind static methods to actions
ActionAttribute.BindMethods(typeof(General));
General.Actions.BindMethods(typeof(General));
// Create main window
General.WriteLogLine("Loading main interface window...");
@ -504,7 +504,7 @@ namespace CodeImp.DoomBuilder
General.WriteLogLine("Termination requested");
// Unbind static methods from actions
ActionAttribute.UnbindMethods(typeof(General));
General.Actions.UnbindMethods(typeof(General));
// Clean up
if(map != null) map.Dispose();
@ -545,7 +545,7 @@ namespace CodeImp.DoomBuilder
#region ================== Management
// This creates a new map
[Action("newmap")]
[BeginAction("newmap")]
internal static void NewMap()
{
MapOptions newoptions = new MapOptions();
@ -594,7 +594,7 @@ namespace CodeImp.DoomBuilder
}
// This closes the current map
[Action("closemap")]
[BeginAction("closemap")]
internal static void CloseMap()
{
// Ask the user to save changes (if any)
@ -622,7 +622,7 @@ namespace CodeImp.DoomBuilder
}
// This loads a map from file
[Action("openmap")]
[BeginAction("openmap")]
internal static void OpenMap()
{
OpenFileDialog openfile;
@ -694,7 +694,7 @@ namespace CodeImp.DoomBuilder
}
// This saves the current map
[Action("savemap")]
[BeginAction("savemap")]
internal static void SaveMap()
{
// Check if a wad file is known
@ -724,7 +724,7 @@ namespace CodeImp.DoomBuilder
}
// This saves the current map as a different file
[Action("savemapas")]
[BeginAction("savemapas")]
internal static void SaveMapAs()
{
SaveFileDialog savefile;
@ -1011,7 +1011,7 @@ namespace CodeImp.DoomBuilder
#endregion
[Action("testaction")]
[BeginAction("testaction")]
internal static void TestAction()
{
TextureBrowserForm t = new TextureBrowserForm();

View file

@ -114,7 +114,7 @@ namespace CodeImp.DoomBuilder
{
// We have no destructor
GC.SuppressFinalize(this);
// Basic objects
grid = new GridSetup();
undoredo = new UndoManager();
@ -130,7 +130,7 @@ namespace CodeImp.DoomBuilder
ChangeMode((EditMode)null);
// Unbind any methods
ActionAttribute.UnbindMethods(this);
General.Actions.UnbindMethods(this);
// Dispose
if(undoredo != null) undoredo.Dispose();
@ -222,7 +222,7 @@ namespace CodeImp.DoomBuilder
data.Load(configinfo.Resources, options.Resources);
// Bind any methods
ActionAttribute.BindMethods(this);
General.Actions.BindMethods(this);
// Set default mode
ChangeMode("VerticesMode");
@ -309,7 +309,7 @@ namespace CodeImp.DoomBuilder
data.Load(configinfo.Resources, options.Resources, maplocation);
// Bind any methods
ActionAttribute.BindMethods(this);
General.Actions.BindMethods(this);
// Set default mode
ChangeMode("VerticesMode");
@ -877,7 +877,7 @@ namespace CodeImp.DoomBuilder
#region ================== Methods
// This clears the selection
[Action("clearselection")]
[BeginAction("clearselection")]
public void ClearSelection()
{
// Clear selection
@ -900,7 +900,7 @@ namespace CodeImp.DoomBuilder
}
// This reloads resources
[Action("reloadresources")]
[BeginAction("reloadresources")]
internal void ReloadResources()
{
DataLocation maplocation;
@ -946,7 +946,7 @@ namespace CodeImp.DoomBuilder
}
// Game Configuration action
[Action("mapoptions")]
[BeginAction("mapoptions")]
internal void ShowMapOptions()
{
// Show map options dialog

View file

@ -65,5 +65,6 @@ namespace CodeImp.DoomBuilder.Interface
void SetProcessorState(bool on);
void StartExclusiveMouseInput();
void StopExclusiveMouseInput();
bool CheckActionActive(Assembly assembly, string actionname);
}
}

View file

@ -30,6 +30,8 @@ using CodeImp.DoomBuilder.Editing;
using System.Collections;
using System.IO;
using CodeImp.DoomBuilder.Map;
using System.Reflection;
using CodeImp.DoomBuilder.Plugins;
#endregion
@ -102,7 +104,7 @@ namespace CodeImp.DoomBuilder.Interface
buttongrid.DropDownDirection = ToolStripDropDownDirection.AboveLeft;
// Bind any methods
ActionAttribute.BindMethods(this);
General.Actions.BindMethods(this);
// Apply shortcut keys
ApplyShortcutKeys();
@ -154,7 +156,7 @@ namespace CodeImp.DoomBuilder.Interface
this.Update();
asmname = General.ThisAssembly.GetName().Name.ToLowerInvariant();
General.Actions[asmname + "_" + (sender as ToolStripItem).Tag.ToString()].Invoke();
General.Actions[asmname + "_" + (sender as ToolStripItem).Tag.ToString()].Begin();
this.Update();
}
@ -227,7 +229,7 @@ namespace CodeImp.DoomBuilder.Interface
SetProcessorState(false);
// Unbind methods
ActionAttribute.UnbindMethods(this);
General.Actions.UnbindMethods(this);
// Determine window state to save
if(this.WindowState != FormWindowState.Minimized)
@ -467,7 +469,7 @@ namespace CodeImp.DoomBuilder.Interface
}
// This shows the grid setup dialog
[Action("gridsetup")]
[BeginAction("gridsetup")]
internal void ShowGridSetup()
{
// Only when a map is open
@ -573,7 +575,7 @@ namespace CodeImp.DoomBuilder.Interface
this.Update();
modeinfo = (EditModeInfo)((sender as ToolStripItem).Tag);
General.Actions[modeinfo.SwitchAction.GetFullActionName(modeinfo.Plugin.Assembly)].Invoke();
General.Actions[modeinfo.SwitchAction.GetFullActionName(modeinfo.Plugin.Assembly)].Begin();
this.Update();
}
@ -671,7 +673,26 @@ namespace CodeImp.DoomBuilder.Interface
private void display_MouseDoubleClick(object sender, MouseEventArgs e) { if((General.Map != null) && (General.Map.Mode != null)) General.Map.Mode.MouseDoubleClick(e); }
// Mouse down
private void display_MouseDown(object sender, MouseEventArgs e) { if((General.Map != null) && (General.Map.Mode != null)) General.Map.Mode.MouseDown(e); }
private void display_MouseDown(object sender, MouseEventArgs e)
{
int key = 0;
// 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);
// Invoke on editing mode
if((General.Map != null) && (General.Map.Mode != null)) General.Map.Mode.MouseDown(e);
}
// Mouse enters
private void display_MouseEnter(object sender, EventArgs e)
@ -694,12 +715,40 @@ namespace CodeImp.DoomBuilder.Interface
}
// Mouse up
private void display_MouseUp(object sender, MouseEventArgs e) { if((General.Map != null) && (General.Map.Mode != null)) General.Map.Mode.MouseUp(e); }
private void display_MouseUp(object sender, MouseEventArgs e)
{
int key = 0;
// 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);
// Invoke on editing mode
if((General.Map != null) && (General.Map.Mode != null)) General.Map.Mode.MouseUp(e);
}
#endregion
#region ================== Input
// This checks if a given action is active
public bool CheckActionActive(Assembly assembly, string actionname)
{
if(assembly == null)
return General.Actions.CheckActionActive(General.ThisAssembly, actionname);
else
return General.Actions.CheckActionActive(assembly, actionname);
}
// This requests exclusive mouse input
public void StartExclusiveMouseInput()
{
@ -739,26 +788,21 @@ namespace CodeImp.DoomBuilder.Interface
// When the mouse wheel is changed
protected override void OnMouseWheel(MouseEventArgs e)
{
int mod = 0;
// Create modifiers
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.InvokeByKey(mod | (int)SpecialKeys.MScrollUp);
General.Actions.KeyPressed((int)SpecialKeys.MScrollUp);
General.Actions.KeyReleased((int)SpecialKeys.MScrollUp);
}
// Scrollwheel down?
else if(e.Delta < 0)
{
// Invoke actions for scrollwheel
//for(int i = 0; i > e.Delta; i -= 120)
General.Actions.InvokeByKey(mod | (int)SpecialKeys.MScrollDown);
General.Actions.KeyPressed((int)SpecialKeys.MScrollDown);
General.Actions.KeyReleased((int)SpecialKeys.MScrollDown);
}
// Let the base know
@ -768,13 +812,19 @@ namespace CodeImp.DoomBuilder.Interface
// 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;
// Invoke any actions associated with this key
General.Actions.InvokeByKey((int)e.KeyData);
General.Actions.UpdateModifiers(mod);
General.Actions.KeyPressed((int)e.KeyData);
// Invoke on editing mode
if((General.Map != null) && (General.Map.Mode != null)) General.Map.Mode.KeyDown(e);
@ -783,10 +833,19 @@ namespace CodeImp.DoomBuilder.Interface
// 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;
// Invoke any actions associated with this key
General.Actions.UpdateModifiers(mod);
General.Actions.KeyReleased((int)e.KeyData);
// Invoke on editing mode
if((General.Map != null) && (General.Map.Mode != null)) General.Map.Mode.KeyUp(e);
@ -1035,7 +1094,7 @@ namespace CodeImp.DoomBuilder.Interface
}
// Action to toggle snap to grid
[Action("togglesnap")]
[BeginAction("togglesnap")]
internal void ToggleSnapToGrid()
{
buttonsnaptogrid.Checked = !buttonsnaptogrid.Checked;
@ -1043,7 +1102,7 @@ namespace CodeImp.DoomBuilder.Interface
}
// Action to toggle auto merge
[Action("toggleautomerge")]
[BeginAction("toggleautomerge")]
internal void ToggleAutoMerge()
{
buttonautomerge.Checked = !buttonautomerge.Checked;
@ -1078,7 +1137,7 @@ namespace CodeImp.DoomBuilder.Interface
}
// Game Configuration action
[Action("configuration")]
[BeginAction("configuration")]
internal void ShowConfiguration()
{
// Show configuration dialog
@ -1100,7 +1159,7 @@ namespace CodeImp.DoomBuilder.Interface
}
// Preferences action
[Action("preferences")]
[BeginAction("preferences")]
internal void ShowPreferences()
{
// Show preferences dialog

View file

@ -319,6 +319,14 @@ namespace CodeImp.DoomBuilder.Map
}
}
// This returns the closest coordinates ON the line
public Vector2D NearestOnLine(Vector2D pos)
{
float u = Line2D.GetNearestOnLine(start.Position, end.Position, pos);
if(u < 0f) u = 0f; else if(u > 1f) u = 1f;
return Line2D.GetCoordinatesAt(start.Position, end.Position, u);
}
// This returns the shortest distance from given coordinates to line
public float SafeDistanceToSq(Vector2D p, bool bounded)
{

View file

@ -23,6 +23,7 @@ using System.Globalization;
using System.Text;
using System.IO;
using CodeImp.DoomBuilder.Editing;
using System.Reflection;
#endregion
@ -159,6 +160,19 @@ namespace CodeImp.DoomBuilder.Plugins
}
}
// This returns a plugin by assembly, or null when plugin cannot be found
public Plugin FindPluginByAssembly(Assembly assembly)
{
// Go for all plugins the find the one with matching assembly
foreach(Plugin p in plugins)
{
if(p.Assembly == assembly) return p;
}
// Nothing found
return null;
}
#endregion
}
}

View file

@ -45,7 +45,8 @@ namespace CodeImp.DoomBuilder.Rendering
float OffsetX { get; }
float OffsetY { get; }
float Scale { get; }
int VertexSize { get; }
// Color methods
PixelColor DetermineLinedefColor(Linedef l);
PixelColor DetermineThingColor(Thing t);
@ -72,6 +73,7 @@ namespace CodeImp.DoomBuilder.Rendering
void RenderThingSet(ICollection<Thing> things);
void RenderRectangle(RectangleF rect, float bordersize, PixelColor c, bool transformrect);
void RenderRectangleFilled(RectangleF rect, PixelColor c, bool transformrect);
void RenderLine(Vector2D start, Vector2D end, float thickness, PixelColor c, bool transformcoords);
void RenderText(string text, Vector2D pos, PixelColor c, bool transformpos);
void RenderTextCentered(string text, Vector2D pos, PixelColor c, bool transformpos);
}

View file

@ -61,7 +61,7 @@ namespace CodeImp.DoomBuilder.Rendering
private const byte DOUBLESIDED_LINE_ALPHA = 130;
private const float FSAA_PLOTTER_BLEND_FACTOR = 0.6f;
private const float FSAA_OVERLAY_BLEND_FACTOR = 0.2f;
private const float FSAA_OVERLAY_BLEND_FACTOR = 0.6f;
private const float THING_ARROW_SIZE = 1.5f;
private const float THING_ARROW_SHRINK = 2f;
private const float THING_CIRCLE_SIZE = 1f;
@ -137,6 +137,7 @@ namespace CodeImp.DoomBuilder.Rendering
public float OffsetX { get { return offsetx; } }
public float OffsetY { get { return offsety; } }
public float Scale { get { return scale; } }
public int VertexSize { get { return vertexsize; } }
#endregion
@ -1181,6 +1182,59 @@ namespace CodeImp.DoomBuilder.Rendering
graphics.Shaders.Color2D.End();
}
// This renders a line with given color
public void RenderLine(Vector2D start, Vector2D end, float thickness, PixelColor c, bool transformcoords)
{
FlatVertex[] verts = new FlatVertex[4];
// Calculate positions
if(transformcoords)
{
start = start.GetTransformed(translatex, translatey, scale, -scale);
end = end.GetTransformed(translatex, translatey, scale, -scale);
}
// Calculate offsets
Vector2D delta = end - start;
Vector2D dn = delta.GetNormal() * thickness;
// Make vertices
verts[0].x = start.x - dn.x + dn.y;
verts[0].y = start.y - dn.y - dn.x;
verts[0].z = 0.0f;
verts[0].w = 1.0f;
verts[0].c = c.ToInt();
verts[1].x = start.x - dn.x - dn.y;
verts[1].y = start.y - dn.y + dn.x;
verts[1].z = 0.0f;
verts[1].w = 1.0f;
verts[1].c = c.ToInt();
verts[2].x = end.x + dn.x + dn.y;
verts[2].y = end.y + dn.y - dn.x;
verts[2].z = 0.0f;
verts[2].w = 1.0f;
verts[2].c = c.ToInt();
verts[3].x = end.x + dn.x - dn.y;
verts[3].y = end.y + dn.y + dn.x;
verts[3].z = 0.0f;
verts[3].w = 1.0f;
verts[3].c = c.ToInt();
// Set renderstates for rendering
graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
graphics.Device.SetRenderState(RenderState.ZEnable, false);
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, false);
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, false);
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
// Draw
graphics.Shaders.Color2D.Begin();
graphics.Shaders.Color2D.BeginPass(0);
graphics.Device.DrawUserPrimitives<FlatVertex>(PrimitiveType.TriangleStrip, 0, 2, verts);
graphics.Shaders.Color2D.EndPass();
graphics.Shaders.Color2D.End();
}
#endregion
#region ================== Geometry

View file

@ -113,6 +113,24 @@ cancelmode
allowscroll = true;
}
classicselect
{
title = "2D: Select";
description = "Selects the highlighted item. Also allows selection by drawing a rectangle.";
allowkeys = true;
allowmouse = true;
allowscroll = false;
}
classicedit
{
title = "2D: Edit";
description = "Edits the properties of the selected items or drags the selected items. Also initiates drawing or inserts new things when no selection is made.";
allowkeys = true;
allowmouse = true;
allowscroll = false;
}
scrollwest
{
title = "2D: Scroll West";
@ -120,6 +138,7 @@ scrollwest
allowkeys = true;
allowmouse = true;
allowscroll = true;
repeat = true;
}
scrolleast
@ -129,6 +148,7 @@ scrolleast
allowkeys = true;
allowmouse = true;
allowscroll = true;
repeat = true;
}
scrollnorth
@ -138,6 +158,7 @@ scrollnorth
allowkeys = true;
allowmouse = true;
allowscroll = true;
repeat = true;
}
scrollsouth
@ -147,6 +168,7 @@ scrollsouth
allowkeys = true;
allowmouse = true;
allowscroll = true;
repeat = true;
}
zoomin
@ -156,6 +178,7 @@ zoomin
allowkeys = true;
allowmouse = true;
allowscroll = true;
repeat = true;
}
zoomout
@ -165,6 +188,7 @@ zoomout
allowkeys = true;
allowmouse = true;
allowscroll = true;
repeat = true;
}
centerinscreen