lots of stuff (including half decent copy/paste)

This commit is contained in:
codeimp 2008-09-22 18:27:50 +00:00
parent fccba768f0
commit b1ccdbbc7f
29 changed files with 1692 additions and 1325 deletions

View file

@ -27,3 +27,5 @@
- Make Plugin Development Kit
- Add proper XML comments to classes, properties and methods
- Contact AlysiumX (AlysiumX@gmail.com) for official video tutorials
(see http://www.youtube.com/view_play_list?p=6FDD1F9F674419E8)

View file

@ -33,6 +33,7 @@
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Compile Include="ClassicModes\BaseClassicMode.cs" />
<Compile Include="ClassicModes\BrightnessMode.cs" />
<Compile Include="ClassicModes\EditSelectionMode.cs" />
<Compile Include="ClassicModes\CurveLinedefsMode.cs" />

View file

@ -0,0 +1,107 @@
#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;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using CodeImp.DoomBuilder.Windows;
using CodeImp.DoomBuilder.IO;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.Types;
using CodeImp.DoomBuilder.Config;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
public abstract class BaseClassicMode : ClassicMode
{
#region ================== Constants
#endregion
#region ================== Variables
#endregion
#region ================== Properties
#endregion
#region ================== Constructor / Disposer
// Constructor
public BaseClassicMode()
{
// Initialize
// We have no destructor
GC.SuppressFinalize(this);
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Done
base.Dispose();
}
}
#endregion
#region ================== Methods
// This occurs when the user presses Copy. All selected geometry must be marked for copying!
public override bool OnCopyBegin()
{
General.Map.Map.MarkAllSelectedGeometry(true);
// Return true when anything is selected so that the copy continues
// We only have to check vertices for the geometry, because without selected
// vertices, no complete structure can exist.
return (General.Map.Map.GetMarkedVertices(true).Count > 0) ||
(General.Map.Map.GetMarkedThings(true).Count > 0);
}
// This is called when something is pasted.
public override void OnPasteEnd()
{
General.Map.Map.ClearAllSelected();
General.Map.Map.SelectMarkedGeometry(true, true);
// Switch to EditSelectionMode
General.Map.ChangeMode("EditSelectionMode");
}
#endregion
}
}

View file

@ -38,7 +38,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "Curve Linedefs",
Volatile = true)]
public sealed class CurveLinedefsMode : ClassicMode
public sealed class CurveLinedefsMode : BaseClassicMode
{
#region ================== Constants
@ -48,9 +48,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Variables
// Mode to return to
private EditMode basemode;
// Collections
private ICollection<Linedef> selectedlines;
private ICollection<Linedef> unselectedlines;
@ -60,9 +57,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Properties
// Just keep the base mode button checked
public override string EditModeButtonName { get { return basemode.GetType().Name; } }
internal EditMode BaseMode { get { return basemode; } }
public override string EditModeButtonName { get { return General.Map.PreviousStableMode.Name; } }
#endregion
@ -71,8 +66,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Constructor
public CurveLinedefsMode(EditMode basemode)
{
this.basemode = basemode;
// Make collections by selection
selectedlines = General.Map.Map.GetSelectedLinedefs(true);
unselectedlines = General.Map.Map.GetSelectedLinedefs(false);
@ -95,6 +88,73 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Methods
// This generates the vertices to split the line with, from start to end
private List<Vector2D> GenerateCurve(Linedef line)
{
// Fetch settings from window
int vertices = BuilderPlug.Me.CurveLinedefsForm.Vertices;
float distance = BuilderPlug.Me.CurveLinedefsForm.Distance;
float angle = BuilderPlug.Me.CurveLinedefsForm.Angle;
bool fixedcurve = BuilderPlug.Me.CurveLinedefsForm.FixedCurve;
bool backwards = BuilderPlug.Me.CurveLinedefsForm.Backwards;
// Make list
List<Vector2D> points = new List<Vector2D>(vertices);
//Added by Anders Åstrand 2008-05-18
//The formulas used are taken from http://mathworld.wolfram.com/CircularSegment.html
//c and theta are known (length of line and angle parameter). d, R and h are
//calculated from those two
//If the curve is not supposed to be a circular segment it's simply deformed to fit
//the value set for distance.
//The vertices are generated to be evenly distributed (by angle) along the curve
//and lastly they are rotated and moved to fit with the original line
//calculate some identities of a circle segment (refer to the graph in the url above)
double c = line.Length;
double theta = angle;
double d = (c / Math.Tan(theta / 2)) / 2;
double R = d / Math.Cos(theta / 2);
double h = R - d;
double yDeform = fixedcurve ? 1 : distance / h;
if(backwards)
yDeform = -yDeform;
double a, x, y;
Vector2D vertex;
for(int v = 1; v <= vertices; v++)
{
//calculate the angle for this vertex
//the curve starts at PI/2 - theta/2 and is segmented into vertices+1 segments
//this assumes the line is horisontal and on y = 0, the point is rotated and moved later
a = (Math.PI - theta) / 2 + v * (theta / (vertices + 1));
//calculate the coordinates of the point, and distort the y coordinate
//using the deform factor calculated above
x = Math.Cos(a) * R;
y = (Math.Sin(a) * R - d) * yDeform;
//rotate and transform to fit original line
vertex = new Vector2D((float)x, (float)y).GetRotated(line.Angle + Angle2D.PIHALF);
vertex = vertex.GetTransformed(line.GetCenterPoint().x, line.GetCenterPoint().y, 1, 1);
points.Add(vertex);
}
// Done
return points;
}
#endregion
#region ================== Events
// Cancelled
public override void OnCancel()
{
@ -102,7 +162,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
base.OnCancel();
// Return to base mode
General.Map.ChangeMode(basemode);
General.Map.ChangeMode(General.Map.PreviousStableMode.Name);
}
// Mode engages
@ -161,70 +221,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
General.Map.IsChanged = true;
// Return to base mode
General.Map.ChangeMode(basemode);
}
// This generates the vertices to split the line with, from start to end
private List<Vector2D> GenerateCurve(Linedef line)
{
// Fetch settings from window
int vertices = BuilderPlug.Me.CurveLinedefsForm.Vertices;
float distance = BuilderPlug.Me.CurveLinedefsForm.Distance;
float angle = BuilderPlug.Me.CurveLinedefsForm.Angle;
bool fixedcurve = BuilderPlug.Me.CurveLinedefsForm.FixedCurve;
bool backwards = BuilderPlug.Me.CurveLinedefsForm.Backwards;
// Make list
List<Vector2D> points = new List<Vector2D>(vertices);
//Added by Anders Åstrand 2008-05-18
//The formulas used are taken from http://mathworld.wolfram.com/CircularSegment.html
//c and theta are known (length of line and angle parameter). d, R and h are
//calculated from those two
//If the curve is not supposed to be a circular segment it's simply deformed to fit
//the value set for distance.
//The vertices are generated to be evenly distributed (by angle) along the curve
//and lastly they are rotated and moved to fit with the original line
//calculate some identities of a circle segment (refer to the graph in the url above)
double c = line.Length;
double theta = angle;
double d = (c / Math.Tan(theta / 2)) / 2;
double R = d / Math.Cos(theta / 2);
double h = R - d;
double yDeform = fixedcurve ? 1 : distance / h;
if (backwards)
yDeform = -yDeform;
double a, x, y;
Vector2D vertex;
for (int v = 1; v <= vertices; v++)
{
//calculate the angle for this vertex
//the curve starts at PI/2 - theta/2 and is segmented into vertices+1 segments
//this assumes the line is horisontal and on y = 0, the point is rotated and moved later
a = (Math.PI - theta)/2 + v * (theta / (vertices + 1));
//calculate the coordinates of the point, and distort the y coordinate
//using the deform factor calculated above
x = Math.Cos(a) * R;
y = (Math.Sin(a) * R - d) * yDeform;
//rotate and transform to fit original line
vertex = new Vector2D((float)x, (float)y).GetRotated(line.Angle + Angle2D.PIHALF);
vertex = vertex.GetTransformed(line.GetCenterPoint().x, line.GetCenterPoint().y, 1, 1);
points.Add(vertex);
}
// Done
return points;
General.Map.ChangeMode(General.Map.PreviousStableMode.Name);
}
// Redrawing display

View file

@ -36,16 +36,13 @@ using CodeImp.DoomBuilder.Editing;
namespace CodeImp.DoomBuilder.BuilderModes
{
public abstract class DragGeometryMode : ClassicMode
public abstract class DragGeometryMode : BaseClassicMode
{
#region ================== Constants
#endregion
#region ================== Variables
// Mode to return to
private EditMode basemode;
// Mouse position on map where dragging started
private Vector2D dragstartmappos;
@ -86,9 +83,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Properties
// Just keep the base mode button checked
public override string EditModeButtonName { get { return basemode.GetType().Name; } }
internal EditMode BaseMode { get { return basemode; } }
public override string EditModeButtonName { get { return General.Map.PreviousStableMode.Name; } }
#endregion
@ -119,9 +114,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Initialize
this.dragstartmappos = dragstartmappos;
// Create new instance of the previous mode
this.basemode = (EditMode)Assembly.GetCallingAssembly().CreateInstance(General.Map.Mode.GetType().FullName, false, BindingFlags.Default, null, null, CultureInfo.CurrentCulture, new object[0]);
Cursor.Current = Cursors.AppStarting;
// Make list of selected vertices
@ -291,7 +283,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
base.OnCancel();
// Return to vertices mode
General.Map.ChangeMode(basemode);
General.Map.ChangeMode(General.Map.PreviousStableMode.Name);
}
// Mode engages
@ -375,7 +367,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
protected override void OnEndEdit()
{
// Just return to base mode, Disengage will be called automatically.
General.Map.ChangeMode(basemode);
General.Map.ChangeMode(General.Map.PreviousStableMode.Name);
base.OnEndEdit();
}

View file

@ -68,7 +68,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public DragLinedefsMode(Vector2D dragstartmappos)
{
// Mark what we are dragging
General.Map.Map.ClearAllMarks();
General.Map.Map.ClearAllMarks(false);
General.Map.Map.MarkSelectedLinedefs(true, true);
ICollection<Vertex> verts = General.Map.Map.GetVerticesFromLinesMarks(true);
foreach(Vertex v in verts) v.Marked = true;

View file

@ -68,7 +68,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public DragSectorsMode(Vector2D dragstartmappos)
{
// Mark what we are dragging
General.Map.Map.ClearAllMarks();
General.Map.Map.ClearAllMarks(false);
General.Map.Map.MarkSelectedLinedefs(true, true);
ICollection<Vertex> verts = General.Map.Map.GetVerticesFromLinesMarks(true);
foreach(Vertex v in verts) v.Marked = true;

View file

@ -45,7 +45,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
[EditMode(DisplayName = "Things",
Volatile = true)]
public sealed class DragThingsMode : ClassicMode
public sealed class DragThingsMode : BaseClassicMode
{
#region ================== Constants
@ -104,7 +104,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
Cursor.Current = Cursors.AppStarting;
// Mark what we are dragging
General.Map.Map.ClearAllMarks();
General.Map.Map.ClearAllMarks(false);
General.Map.Map.MarkSelectedThings(true, true);
// Get selected things

View file

@ -65,7 +65,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public DragVerticesMode(Vertex dragitem, Vector2D dragstartmappos)
{
// Mark what we are dragging
General.Map.Map.ClearAllMarks();
General.Map.Map.ClearAllMarks(false);
General.Map.Map.MarkSelectedVertices(true, true);
// Initialize

View file

@ -41,7 +41,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
SwitchAction = "drawlinesmode",
Volatile = true)]
public class DrawGeometryMode : ClassicMode
public class DrawGeometryMode : BaseClassicMode
{
#region ================== Structures
@ -61,9 +61,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Variables
// Mode to return to
private EditMode basemode;
// Drawing points
private List<DrawnVertex> points;
private List<LineLengthLabel> labels;
@ -82,9 +79,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Properties
// Just keep the base mode button checked
public override string EditModeButtonName { get { return basemode.GetType().Name; } }
internal EditMode BaseMode { get { return basemode; } }
public override string EditModeButtonName { get { return General.Map.PreviousStableMode.Name; } }
#endregion
@ -94,13 +89,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
public DrawGeometryMode()
{
// Initialize
this.basemode = General.Map.Mode;
points = new List<DrawnVertex>();
labels = new List<LineLengthLabel>();
// No selection in this mode
General.Map.Map.ClearAllSelected();
General.Map.Map.ClearAllMarks();
General.Map.Map.ClearAllMarks(false);
// We have no destructor
GC.SuppressFinalize(this);
@ -125,6 +119,215 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Methods
// This checks if the view offset/zoom changed and updates the check
protected bool CheckViewChanged()
{
bool viewchanged = false;
// View changed?
if(renderer.OffsetX != lastoffsetx) viewchanged = true;
if(renderer.OffsetY != lastoffsety) viewchanged = true;
if(renderer.Scale != lastscale) viewchanged = true;
// Keep view information
lastoffsetx = renderer.OffsetX;
lastoffsety = renderer.OffsetY;
lastscale = renderer.Scale;
// Return result
return viewchanged;
}
// This updates the dragging
private void Update()
{
PixelColor stitchcolor = General.Colors.Highlight;
PixelColor losecolor = General.Colors.Selection;
PixelColor color;
snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
DrawnVertex lastp = new DrawnVertex();
DrawnVertex curp = GetCurrentPosition();
float vsize = ((float)renderer.VertexSize + 1.0f) / renderer.Scale;
float vsizeborder = ((float)renderer.VertexSize + 3.0f) / renderer.Scale;
// The last label's end must go to the mouse cursor
if(labels.Count > 0) labels[labels.Count - 1].End = curp.pos;
// Render drawing lines
if(renderer.StartOverlay(true))
{
// Go for all points to draw lines
if(points.Count > 0)
{
// Render lines
lastp = points[0];
for(int i = 1; i < points.Count; i++)
{
// Determine line color
if(lastp.stitch && points[i].stitch) color = stitchcolor;
else color = losecolor;
// Render line
renderer.RenderLine(lastp.pos, points[i].pos, LINE_THICKNESS, color, true);
lastp = points[i];
}
// Determine line color
if(lastp.stitch && snaptonearest) color = stitchcolor;
else color = losecolor;
// Render line to cursor
renderer.RenderLine(lastp.pos, curp.pos, LINE_THICKNESS, color, true);
// Render vertices
for(int i = 0; i < points.Count; i++)
{
// Determine line color
if(points[i].stitch) color = stitchcolor;
else color = losecolor;
// Render line
renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - vsize, points[i].pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true);
}
}
// Determine point color
if(snaptonearest) color = stitchcolor;
else color = losecolor;
// Render vertex at cursor
renderer.RenderRectangleFilled(new RectangleF(curp.pos.x - vsize, curp.pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true);
// Go for all labels
foreach(LineLengthLabel l in labels) renderer.RenderText(l.TextLabel);
// Done
renderer.Finish();
}
// Done
renderer.Present();
}
// This gets the aligned and snapped draw position
private DrawnVertex GetCurrentPosition()
{
DrawnVertex p = new DrawnVertex();
// Snap to nearest?
if(snaptonearest)
{
float vrange = VerticesMode.VERTEX_HIGHLIGHT_RANGE / renderer.Scale;
// Go for all drawn points
foreach(DrawnVertex v in points)
{
Vector2D delta = mousemappos - v.pos;
if(delta.GetLengthSq() < (vrange * vrange))
{
p.pos = v.pos;
p.stitch = true;
return p;
}
}
// Try the nearest vertex
Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange);
if(nv != null)
{
p.pos = nv.Position;
p.stitch = true;
return p;
}
// 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)
{
// Get grid intersection coordinates
List<Vector2D> coords = nl.GetGridIntersections();
// Find nearest grid intersection
float found_distance = float.MaxValue;
Vector2D found_coord = new Vector2D();
foreach(Vector2D v in coords)
{
Vector2D delta = mousemappos - v;
if(delta.GetLengthSq() < found_distance)
{
found_distance = delta.GetLengthSq();
found_coord = v;
}
}
// Align to the closest grid intersection
p.pos = found_coord;
p.stitch = true;
return p;
}
else
{
// Aligned to line
p.pos = nl.NearestOnLine(mousemappos);
p.stitch = true;
return p;
}
}
}
// Snap to grid?
if(snaptogrid)
{
// Aligned to grid
p.pos = General.Map.Grid.SnappedToGrid(mousemappos);
p.stitch = snaptonearest;
return p;
}
else
{
// Normal position
p.pos = mousemappos;
p.stitch = snaptonearest;
return p;
}
}
// This draws a point at a specific location
public void DrawPointAt(Vector2D pos, bool stitch)
{
DrawnVertex newpoint = new DrawnVertex();
newpoint.pos = pos;
newpoint.stitch = stitch;
points.Add(newpoint);
labels.Add(new LineLengthLabel());
labels[labels.Count - 1].Start = newpoint.pos;
if(labels.Count > 1) labels[labels.Count - 2].End = newpoint.pos;
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();
}
}
}
#endregion
#region ================== Events
// Engaging
public override void OnEngage()
{
@ -142,9 +345,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
base.OnCancel();
// Return to original mode
Type t = basemode.GetType();
basemode = (EditMode)Activator.CreateInstance(t);
General.Map.ChangeMode(basemode);
General.Map.ChangeMode(General.Map.PreviousStableMode.Name);
}
// Accepted
@ -577,28 +778,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
Cursor.Current = Cursors.Default;
// Return to original mode
Type t = basemode.GetType();
basemode = (EditMode)Activator.CreateInstance(t);
General.Map.ChangeMode(basemode);
}
// This checks if the view offset/zoom changed and updates the check
protected bool CheckViewChanged()
{
bool viewchanged = false;
// View changed?
if(renderer.OffsetX != lastoffsetx) viewchanged = true;
if(renderer.OffsetY != lastoffsety) viewchanged = true;
if(renderer.Scale != lastscale) viewchanged = true;
// Keep view information
lastoffsetx = renderer.OffsetX;
lastoffsety = renderer.OffsetY;
lastscale = renderer.Scale;
// Return result
return viewchanged;
General.Map.ChangeMode(General.Map.PreviousStableMode.Name);
}
// This redraws the display
@ -623,166 +803,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
Update();
}
// This updates the dragging
private void Update()
{
PixelColor stitchcolor = General.Colors.Highlight;
PixelColor losecolor = General.Colors.Selection;
PixelColor color;
snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
DrawnVertex lastp = new DrawnVertex();
DrawnVertex curp = GetCurrentPosition();
float vsize = ((float)renderer.VertexSize + 1.0f) / renderer.Scale;
float vsizeborder = ((float)renderer.VertexSize + 3.0f) / renderer.Scale;
// The last label's end must go to the mouse cursor
if(labels.Count > 0) labels[labels.Count - 1].End = curp.pos;
// Render drawing lines
if(renderer.StartOverlay(true))
{
// Go for all points to draw lines
if(points.Count > 0)
{
// Render lines
lastp = points[0];
for(int i = 1; i < points.Count; i++)
{
// Determine line color
if(lastp.stitch && points[i].stitch) color = stitchcolor;
else color = losecolor;
// Render line
renderer.RenderLine(lastp.pos, points[i].pos, LINE_THICKNESS, color, true);
lastp = points[i];
}
// Determine line color
if(lastp.stitch && snaptonearest) color = stitchcolor;
else color = losecolor;
// Render line to cursor
renderer.RenderLine(lastp.pos, curp.pos, LINE_THICKNESS, color, true);
// Render vertices
for(int i = 0; i < points.Count; i++)
{
// Determine line color
if(points[i].stitch) color = stitchcolor;
else color = losecolor;
// Render line
renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - vsize, points[i].pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true);
}
}
// Determine point color
if(snaptonearest) color = stitchcolor;
else color = losecolor;
// Render vertex at cursor
renderer.RenderRectangleFilled(new RectangleF(curp.pos.x - vsize, curp.pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true);
// Go for all labels
foreach(LineLengthLabel l in labels) renderer.RenderText(l.TextLabel);
// Done
renderer.Finish();
}
// Done
renderer.Present();
}
// This gets the aligned and snapped draw position
private DrawnVertex GetCurrentPosition()
{
DrawnVertex p = new DrawnVertex();
// Snap to nearest?
if(snaptonearest)
{
float vrange = VerticesMode.VERTEX_HIGHLIGHT_RANGE / renderer.Scale;
// Go for all drawn points
foreach(DrawnVertex v in points)
{
Vector2D delta = mousemappos - v.pos;
if(delta.GetLengthSq() < (vrange * vrange))
{
p.pos = v.pos;
p.stitch = true;
return p;
}
}
// Try the nearest vertex
Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange);
if(nv != null)
{
p.pos = nv.Position;
p.stitch = true;
return p;
}
// 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)
{
// Get grid intersection coordinates
List<Vector2D> coords = nl.GetGridIntersections();
// Find nearest grid intersection
float found_distance = float.MaxValue;
Vector2D found_coord = new Vector2D();
foreach(Vector2D v in coords)
{
Vector2D delta = mousemappos - v;
if(delta.GetLengthSq() < found_distance)
{
found_distance = delta.GetLengthSq();
found_coord = v;
}
}
// Align to the closest grid intersection
p.pos = found_coord;
p.stitch = true;
return p;
}
else
{
// Aligned to line
p.pos = nl.NearestOnLine(mousemappos);
p.stitch = true;
return p;
}
}
}
// Snap to grid?
if(snaptogrid)
{
// Aligned to grid
p.pos = General.Map.Grid.SnappedToGrid(mousemappos);
p.stitch = snaptonearest;
return p;
}
else
{
// Normal position
p.pos = mousemappos;
p.stitch = snaptonearest;
return p;
}
}
// Mouse moving
public override void OnMouseMove(MouseEventArgs e)
{
@ -790,31 +810,25 @@ namespace CodeImp.DoomBuilder.BuilderModes
Update();
}
// This draws a point at a specific location
public void DrawPointAt(Vector2D pos, bool stitch)
// When a key is released
public override void OnKeyUp(KeyEventArgs e)
{
DrawnVertex newpoint = new DrawnVertex();
newpoint.pos = pos;
newpoint.stitch = stitch;
points.Add(newpoint);
labels.Add(new LineLengthLabel());
labels[labels.Count - 1].Start = newpoint.pos;
if(labels.Count > 1) labels[labels.Count - 2].End = newpoint.pos;
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();
}
}
base.OnKeyUp(e);
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
}
// When a key is pressed
public override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
}
#endregion
#region ================== Actions
// Drawing a point
[BeginAction("drawpoint")]
@ -850,22 +864,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
General.Map.AcceptMode();
}
// When a key is released
public override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
}
// When a key is pressed
public override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
}
#endregion
}
}

View file

@ -43,7 +43,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
SwitchAction = "editselectionmode", // Action name used to switch to this mode
Volatile = true)]
public class EditSelectionMode : ClassicMode
public class EditSelectionMode : BaseClassicMode
{
#region ================== Enums
@ -83,8 +83,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Variables
// Mode to return to
private EditMode basemode;
// Mode switching
private bool modealreadyswitching = false;
// Highlighted vertex
@ -133,7 +132,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Properties
// Just keep the base mode button checked
public override string EditModeButtonName { get { return basemode.GetType().Name; } }
public override string EditModeButtonName { get { return General.Map.PreviousStableMode.Name; } }
#endregion
@ -143,11 +142,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public EditSelectionMode()
{
// Initialize
basemode = General.Map.Mode;
mode = ModifyMode.None;
// TEST:
rotation = Angle2D.PI2 * 0;// 0.02f;
}
// Disposer
@ -163,461 +158,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
#endregion
#region ================== Events
// Mode engages
public override void OnEngage()
{
base.OnEngage();
// Convert geometry selection
General.Map.Map.ClearAllMarks();
General.Map.Map.MarkSelectedVertices(true, true);
General.Map.Map.MarkSelectedThings(true, true);
General.Map.Map.MarkSelectedLinedefs(true, true);
ICollection<Vertex> verts = General.Map.Map.GetVerticesFromLinesMarks(true);
foreach(Vertex v in verts) v.Marked = true;
selectedvertices = General.Map.Map.GetMarkedVertices(true);
selectedthings = General.Map.Map.GetMarkedThings(true);
unselectedvertices = General.Map.Map.GetMarkedVertices(false);
// Make sure everything is selected so that it turns up red
foreach(Vertex v in selectedvertices) v.Selected = true;
ICollection<Linedef> markedlines = General.Map.Map.LinedefsFromMarkedVertices(false, true, false);
foreach(Linedef l in markedlines) l.Selected = true;
unselectedlines = General.Map.Map.LinedefsFromMarkedVertices(true, false, false);
// Array to keep original coordinates
vertexpos = new List<Vector2D>(selectedvertices.Count);
thingpos = new List<Vector2D>(selectedthings.Count);
// A selection must be made!
if((selectedvertices.Count > 0) || (selectedthings.Count > 0))
{
// Initialize offset and size
offset.x = float.MaxValue;
offset.y = float.MaxValue;
Vector2D right;
right.x = float.MinValue;
right.y = float.MinValue;
foreach(Vertex v in selectedvertices)
{
// Find left-top and right-bottom
if(v.Position.x < offset.x) offset.x = v.Position.x;
if(v.Position.y < offset.y) offset.y = v.Position.y;
if(v.Position.x > right.x) right.x = v.Position.x;
if(v.Position.y > right.y) right.y = v.Position.y;
// Keep original coordinates
vertexpos.Add(v.Position);
}
foreach(Thing t in selectedthings)
{
// Find left-top and right-bottom
if(t.Position.x < offset.x) offset.x = t.Position.x;
if(t.Position.y < offset.y) offset.y = t.Position.y;
if(t.Position.x > right.x) right.x = t.Position.x;
if(t.Position.y > right.y) right.y = t.Position.y;
// Keep original coordinates
thingpos.Add(t.Position);
}
// Calculate size
size = right - offset;
// If the width of a dimension is zero, add a little
if(Math.Abs(size.x) < 1.0f)
{
size.x += ZERO_SIZE_ADDITION;
offset.x -= ZERO_SIZE_ADDITION / 2;
}
if(Math.Abs(size.y) < 1.0f)
{
size.y += ZERO_SIZE_ADDITION;
offset.y -= ZERO_SIZE_ADDITION / 2;
}
basesize = size;
baseoffset = offset;
// Set presentation
if(selectedthings.Count > 0)
renderer.SetPresentation(Presentation.Things);
else
renderer.SetPresentation(Presentation.Standard);
// Update
UpdateRectangleComponents();
}
else
{
General.Interface.DisplayWarning("Please make a selection first!");
// Cancel now
General.Map.CancelMode();
}
}
// Cancel mode
public override void OnCancel()
{
base.OnCancel();
// Reset geometry in original position
int index = 0;
foreach(Vertex v in selectedvertices)
v.Move(vertexpos[index++]);
index = 0;
foreach(Thing t in selectedthings)
t.Move(thingpos[index++]);
General.Map.Map.Update(true, true);
// Return to original mode
Type mt = basemode.GetType();
basemode = (EditMode)Activator.CreateInstance(mt);
General.Map.ChangeMode(basemode);
}
// When accepted
public override void OnAccept()
{
base.OnAccept();
// Anything to do?
if((selectedthings.Count > 0) || (selectedvertices.Count > 0))
{
Cursor.Current = Cursors.AppStarting;
// Reset geometry in original position
int index = 0;
foreach(Vertex v in selectedvertices)
v.Move(vertexpos[index++]);
index = 0;
foreach(Thing t in selectedthings)
t.Move(thingpos[index++]);
// Make undo
General.Map.UndoRedo.CreateUndo("Edit selection", UndoGroup.None, 0);
// Move geometry to new position
UpdateGeometry();
General.Map.Map.Update(true, true);
// Stitch geometry
if(snaptonearest) General.Map.Map.StitchGeometry();
// Snap to map format accuracy
General.Map.Map.SnapAllToAccuracy();
// Update cached values
General.Map.Map.Update();
// Done
selectedvertices = new List<Vertex>();
selectedthings = new List<Thing>();
Cursor.Current = Cursors.Default;
General.Map.IsChanged = true;
}
if(!modealreadyswitching)
{
// Return to original mode
Type mt = basemode.GetType();
basemode = (EditMode)Activator.CreateInstance(mt);
General.Map.ChangeMode(basemode);
}
}
// Mode disengages
public override void OnDisengage()
{
base.OnDisengage();
// When not cancelled manually, we assume it is accepted
if(!cancelled)
{
modealreadyswitching = true;
this.OnAccept();
}
// Hide highlight info
General.Interface.HideInfo();
General.Interface.SetCursor(Cursors.Default);
}
// This redraws the display
public override void OnRedrawDisplay()
{
UpdateRectangleComponents();
// Render lines
if(renderer.StartPlotter(true))
{
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
renderer.PlotVerticesSet(General.Map.Map.Vertices);
if(highlighted != null) renderer.PlotVertex(highlighted, ColorCollection.HIGHLIGHT);
renderer.Finish();
}
// Render things
if(renderer.StartThings(true))
{
renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, Presentation.THINGS_HIDDEN_ALPHA);
renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, 1.0f);
renderer.Finish();
}
// Render selection
if(renderer.StartOverlay(true))
{
// Rectangle
PixelColor rectcolor = General.Colors.Highlight.WithAlpha(RECTANGLE_ALPHA);
renderer.RenderGeometry(cornerverts, null, true);
renderer.RenderLine(corners[0], corners[1], 4, rectcolor, true);
renderer.RenderLine(corners[1], corners[2], 4, rectcolor, true);
renderer.RenderLine(corners[2], corners[3], 4, rectcolor, true);
renderer.RenderLine(corners[3], corners[0], 4, rectcolor, true);
// Extension line
if(extensionline.GetLengthSq() > 0.0f)
renderer.RenderLine(extensionline.v1, extensionline.v2, 1, General.Colors.Indication.WithAlpha(EXTENSION_LINE_ALPHA), true);
// Grips
for(int i = 0; i < 4; i++)
{
renderer.RenderRectangleFilled(resizegrips[i], General.Colors.Background, true);
renderer.RenderRectangle(resizegrips[i], 2, General.Colors.Highlight, true);
renderer.RenderRectangleFilled(rotategrips[i], General.Colors.Background, true);
renderer.RenderRectangle(rotategrips[i], 2, General.Colors.Indication, true);
}
renderer.Finish();
}
renderer.Present();
}
// Mouse moves
public override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
Update();
}
// Mouse leaves the display
public override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
// Reset cursor
General.Interface.SetCursor(Cursors.Default);
}
// When edit button is pressed
protected override void OnEdit()
{
base.OnEdit();
OnSelect();
}
// When edit button is released
protected override void OnEndEdit()
{
base.OnEndEdit();
OnEndSelect();
}
// When select button is pressed
protected override void OnSelect()
{
base.OnSelect();
// Used in many cases:
Vector2D center = offset + size * 0.5f;
Vector2D delta;
// Check what grip the mouse is over
switch(CheckMouseGrip())
{
// Drag main rectangle
case Grip.Main:
// Find the original position of the highlighted vertex
if(highlighted != null)
{
int index = 0;
foreach(Vertex v in selectedvertices)
{
if(v == highlighted) highlightedpos = vertexpos[index];
index++;
}
}
dragoffset = mousemappos - offset;
mode = ModifyMode.Dragging;
break;
// Resize
case Grip.SizeN:
// The resize vector is a unit vector in the direction of the resize.
// We multiply this with the sign of the current size, because the
// corners may be reversed when the selection is flipped.
resizevector = corners[1] - corners[2];
resizevector = resizevector.GetNormal() * Math.Sign(size.y);
// The edgevector is a vector with length and direction of the edge perpendicular to the resizevector
edgevector = corners[1] - corners[0];
// Make the resize axis. This is a line with the length and direction
// of basesize used to calculate the resize percentage.
resizeaxis = new Line2D(corners[2], corners[2] + resizevector * basesize.y);
// Original axis filter
resizefilter = new Vector2D(0.0f, 1.0f);
// This is the corner that must stay in the same position
stickcorner = 2;
Highlight(null);
mode = ModifyMode.Resizing;
break;
// Resize
case Grip.SizeE:
// See description above
resizevector = corners[1] - corners[0];
resizevector = resizevector.GetNormal() * Math.Sign(size.x);
edgevector = corners[1] - corners[2];
resizeaxis = new Line2D(corners[0], corners[0] + resizevector * basesize.x);
resizefilter = new Vector2D(1.0f, 0.0f);
stickcorner = 0;
Highlight(null);
mode = ModifyMode.Resizing;
break;
// Resize
case Grip.SizeS:
// See description above
resizevector = corners[2] - corners[1];
resizevector = resizevector.GetNormal() * Math.Sign(size.y);
edgevector = corners[2] - corners[3];
resizeaxis = new Line2D(corners[1], corners[1] + resizevector * basesize.y);
resizefilter = new Vector2D(0.0f, 1.0f);
stickcorner = 0;
Highlight(null);
mode = ModifyMode.Resizing;
break;
// Resize
case Grip.SizeW:
// See description above
resizevector = corners[0] - corners[1];
resizevector = resizevector.GetNormal() * Math.Sign(size.x);
edgevector = corners[0] - corners[3];
resizeaxis = new Line2D(corners[1], corners[1] + resizevector * basesize.x);
resizefilter = new Vector2D(1.0f, 0.0f);
stickcorner = 1;
Highlight(null);
mode = ModifyMode.Resizing;
break;
// Rotate
case Grip.RotateLB:
delta = corners[3] - center;
rotategripangle = delta.GetAngle() - rotation;
Highlight(null);
mode = ModifyMode.Rotating;
break;
// Rotate
case Grip.RotateLT:
delta = corners[0] - center;
rotategripangle = delta.GetAngle() - rotation;
Highlight(null);
mode = ModifyMode.Rotating;
break;
// Rotate
case Grip.RotateRB:
delta = corners[2] - center;
rotategripangle = delta.GetAngle() - rotation;
Highlight(null);
mode = ModifyMode.Rotating;
break;
// Rotate
case Grip.RotateRT:
delta = corners[1] - center;
rotategripangle = delta.GetAngle() - rotation;
Highlight(null);
mode = ModifyMode.Rotating;
break;
// Outside the selection?
default:
// Accept and be done with it
General.Map.AcceptMode();
break;
}
}
// When selected button is released
protected override void OnEndSelect()
{
base.OnEndSelect();
// Remove extension line
extensionline = new Line2D();
// No modifying mode
mode = ModifyMode.None;
// Redraw
General.Interface.RedrawDisplay();
}
// When a key is released
public override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
}
// When a key is pressed
public override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
}
#endregion
#region ================== Methods
// This clears the selection
[BeginAction("clearselection", BaseAction = true)]
public void ClearSelection()
{
// Accept changes
General.Map.Map.ClearAllSelected();
General.Map.AcceptMode();
}
// This highlights a new vertex
protected void Highlight(Vertex v)
{
@ -1031,5 +575,456 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
#endregion
#region ================== Events
// Mode engages
public override void OnEngage()
{
base.OnEngage();
// Convert geometry selection
General.Map.Map.ClearAllMarks(false);
General.Map.Map.MarkSelectedVertices(true, true);
General.Map.Map.MarkSelectedThings(true, true);
General.Map.Map.MarkSelectedLinedefs(true, true);
ICollection<Vertex> verts = General.Map.Map.GetVerticesFromLinesMarks(true);
foreach(Vertex v in verts) v.Marked = true;
selectedvertices = General.Map.Map.GetMarkedVertices(true);
selectedthings = General.Map.Map.GetMarkedThings(true);
unselectedvertices = General.Map.Map.GetMarkedVertices(false);
// Make sure everything is selected so that it turns up red
foreach(Vertex v in selectedvertices) v.Selected = true;
ICollection<Linedef> markedlines = General.Map.Map.LinedefsFromMarkedVertices(false, true, false);
foreach(Linedef l in markedlines) l.Selected = true;
unselectedlines = General.Map.Map.LinedefsFromMarkedVertices(true, false, false);
// Array to keep original coordinates
vertexpos = new List<Vector2D>(selectedvertices.Count);
thingpos = new List<Vector2D>(selectedthings.Count);
// A selection must be made!
if((selectedvertices.Count > 0) || (selectedthings.Count > 0))
{
// Initialize offset and size
offset.x = float.MaxValue;
offset.y = float.MaxValue;
Vector2D right;
right.x = float.MinValue;
right.y = float.MinValue;
foreach(Vertex v in selectedvertices)
{
// Find left-top and right-bottom
if(v.Position.x < offset.x) offset.x = v.Position.x;
if(v.Position.y < offset.y) offset.y = v.Position.y;
if(v.Position.x > right.x) right.x = v.Position.x;
if(v.Position.y > right.y) right.y = v.Position.y;
// Keep original coordinates
vertexpos.Add(v.Position);
}
foreach(Thing t in selectedthings)
{
// Find left-top and right-bottom
if(t.Position.x < offset.x) offset.x = t.Position.x;
if(t.Position.y < offset.y) offset.y = t.Position.y;
if(t.Position.x > right.x) right.x = t.Position.x;
if(t.Position.y > right.y) right.y = t.Position.y;
// Keep original coordinates
thingpos.Add(t.Position);
}
// Calculate size
size = right - offset;
// If the width of a dimension is zero, add a little
if(Math.Abs(size.x) < 1.0f)
{
size.x += ZERO_SIZE_ADDITION;
offset.x -= ZERO_SIZE_ADDITION / 2;
}
if(Math.Abs(size.y) < 1.0f)
{
size.y += ZERO_SIZE_ADDITION;
offset.y -= ZERO_SIZE_ADDITION / 2;
}
basesize = size;
baseoffset = offset;
// Set presentation
if(selectedthings.Count > 0)
renderer.SetPresentation(Presentation.Things);
else
renderer.SetPresentation(Presentation.Standard);
// Update
UpdateRectangleComponents();
}
else
{
General.Interface.DisplayWarning("Please make a selection first!");
// Cancel now
General.Map.CancelMode();
}
}
// Cancel mode
public override void OnCancel()
{
base.OnCancel();
// Reset geometry in original position
int index = 0;
foreach(Vertex v in selectedvertices)
v.Move(vertexpos[index++]);
index = 0;
foreach(Thing t in selectedthings)
t.Move(thingpos[index++]);
General.Map.Map.Update(true, true);
// Return to previous stable mode
General.Map.ChangeMode(General.Map.PreviousStableMode.Name);
}
// When accepted
public override void OnAccept()
{
base.OnAccept();
// Anything to do?
if((selectedthings.Count > 0) || (selectedvertices.Count > 0))
{
Cursor.Current = Cursors.AppStarting;
// Reset geometry in original position
int index = 0;
foreach(Vertex v in selectedvertices)
v.Move(vertexpos[index++]);
index = 0;
foreach(Thing t in selectedthings)
t.Move(thingpos[index++]);
// Make undo
General.Map.UndoRedo.CreateUndo("Edit selection", UndoGroup.None, 0);
// Move geometry to new position
UpdateGeometry();
General.Map.Map.Update(true, true);
// Stitch geometry
if(snaptonearest) General.Map.Map.StitchGeometry();
// Snap to map format accuracy
General.Map.Map.SnapAllToAccuracy();
// Update cached values
General.Map.Map.Update();
// Done
selectedvertices = new List<Vertex>();
selectedthings = new List<Thing>();
Cursor.Current = Cursors.Default;
General.Map.IsChanged = true;
}
if(!modealreadyswitching)
{
// Return to previous stable mode
General.Map.ChangeMode(General.Map.PreviousStableMode.Name);
}
}
// Mode disengages
public override void OnDisengage()
{
base.OnDisengage();
// When not cancelled manually, we assume it is accepted
if(!cancelled)
{
modealreadyswitching = true;
this.OnAccept();
}
// Hide highlight info
General.Interface.HideInfo();
General.Interface.SetCursor(Cursors.Default);
}
// This redraws the display
public override void OnRedrawDisplay()
{
UpdateRectangleComponents();
// Render lines
if(renderer.StartPlotter(true))
{
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
renderer.PlotVerticesSet(General.Map.Map.Vertices);
if(highlighted != null) renderer.PlotVertex(highlighted, ColorCollection.HIGHLIGHT);
renderer.Finish();
}
// Render things
if(renderer.StartThings(true))
{
renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, Presentation.THINGS_HIDDEN_ALPHA);
renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, 1.0f);
renderer.Finish();
}
// Render selection
if(renderer.StartOverlay(true))
{
// Rectangle
PixelColor rectcolor = General.Colors.Highlight.WithAlpha(RECTANGLE_ALPHA);
renderer.RenderGeometry(cornerverts, null, true);
renderer.RenderLine(corners[0], corners[1], 4, rectcolor, true);
renderer.RenderLine(corners[1], corners[2], 4, rectcolor, true);
renderer.RenderLine(corners[2], corners[3], 4, rectcolor, true);
renderer.RenderLine(corners[3], corners[0], 4, rectcolor, true);
// Extension line
if(extensionline.GetLengthSq() > 0.0f)
renderer.RenderLine(extensionline.v1, extensionline.v2, 1, General.Colors.Indication.WithAlpha(EXTENSION_LINE_ALPHA), true);
// Grips
for(int i = 0; i < 4; i++)
{
renderer.RenderRectangleFilled(resizegrips[i], General.Colors.Background, true);
renderer.RenderRectangle(resizegrips[i], 2, General.Colors.Highlight, true);
renderer.RenderRectangleFilled(rotategrips[i], General.Colors.Background, true);
renderer.RenderRectangle(rotategrips[i], 2, General.Colors.Indication, true);
}
renderer.Finish();
}
renderer.Present();
}
// Mouse moves
public override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
Update();
}
// Mouse leaves the display
public override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
// Reset cursor
General.Interface.SetCursor(Cursors.Default);
}
// When edit button is pressed
protected override void OnEdit()
{
base.OnEdit();
OnSelect();
}
// When edit button is released
protected override void OnEndEdit()
{
base.OnEndEdit();
OnEndSelect();
}
// When select button is pressed
protected override void OnSelect()
{
base.OnSelect();
// Used in many cases:
Vector2D center = offset + size * 0.5f;
Vector2D delta;
// Check what grip the mouse is over
switch(CheckMouseGrip())
{
// Drag main rectangle
case Grip.Main:
// Find the original position of the highlighted vertex
if(highlighted != null)
{
int index = 0;
foreach(Vertex v in selectedvertices)
{
if(v == highlighted) highlightedpos = vertexpos[index];
index++;
}
}
dragoffset = mousemappos - offset;
mode = ModifyMode.Dragging;
break;
// Resize
case Grip.SizeN:
// The resize vector is a unit vector in the direction of the resize.
// We multiply this with the sign of the current size, because the
// corners may be reversed when the selection is flipped.
resizevector = corners[1] - corners[2];
resizevector = resizevector.GetNormal() * Math.Sign(size.y);
// The edgevector is a vector with length and direction of the edge perpendicular to the resizevector
edgevector = corners[1] - corners[0];
// Make the resize axis. This is a line with the length and direction
// of basesize used to calculate the resize percentage.
resizeaxis = new Line2D(corners[2], corners[2] + resizevector * basesize.y);
// Original axis filter
resizefilter = new Vector2D(0.0f, 1.0f);
// This is the corner that must stay in the same position
stickcorner = 2;
Highlight(null);
mode = ModifyMode.Resizing;
break;
// Resize
case Grip.SizeE:
// See description above
resizevector = corners[1] - corners[0];
resizevector = resizevector.GetNormal() * Math.Sign(size.x);
edgevector = corners[1] - corners[2];
resizeaxis = new Line2D(corners[0], corners[0] + resizevector * basesize.x);
resizefilter = new Vector2D(1.0f, 0.0f);
stickcorner = 0;
Highlight(null);
mode = ModifyMode.Resizing;
break;
// Resize
case Grip.SizeS:
// See description above
resizevector = corners[2] - corners[1];
resizevector = resizevector.GetNormal() * Math.Sign(size.y);
edgevector = corners[2] - corners[3];
resizeaxis = new Line2D(corners[1], corners[1] + resizevector * basesize.y);
resizefilter = new Vector2D(0.0f, 1.0f);
stickcorner = 0;
Highlight(null);
mode = ModifyMode.Resizing;
break;
// Resize
case Grip.SizeW:
// See description above
resizevector = corners[0] - corners[1];
resizevector = resizevector.GetNormal() * Math.Sign(size.x);
edgevector = corners[0] - corners[3];
resizeaxis = new Line2D(corners[1], corners[1] + resizevector * basesize.x);
resizefilter = new Vector2D(1.0f, 0.0f);
stickcorner = 1;
Highlight(null);
mode = ModifyMode.Resizing;
break;
// Rotate
case Grip.RotateLB:
delta = corners[3] - center;
rotategripangle = delta.GetAngle() - rotation;
Highlight(null);
mode = ModifyMode.Rotating;
break;
// Rotate
case Grip.RotateLT:
delta = corners[0] - center;
rotategripangle = delta.GetAngle() - rotation;
Highlight(null);
mode = ModifyMode.Rotating;
break;
// Rotate
case Grip.RotateRB:
delta = corners[2] - center;
rotategripangle = delta.GetAngle() - rotation;
Highlight(null);
mode = ModifyMode.Rotating;
break;
// Rotate
case Grip.RotateRT:
delta = corners[1] - center;
rotategripangle = delta.GetAngle() - rotation;
Highlight(null);
mode = ModifyMode.Rotating;
break;
// Outside the selection?
default:
// Accept and be done with it
General.Map.AcceptMode();
break;
}
}
// When selected button is released
protected override void OnEndSelect()
{
base.OnEndSelect();
// Remove extension line
extensionline = new Line2D();
// No modifying mode
mode = ModifyMode.None;
// Redraw
General.Interface.RedrawDisplay();
}
// When a key is released
public override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
}
// When a key is pressed
public override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update();
}
#endregion
#region ================== Actions
// This clears the selection
[BeginAction("clearselection", BaseAction = true)]
public void ClearSelection()
{
// Accept changes
General.Map.Map.ClearAllSelected();
General.Map.AcceptMode();
}
#endregion
}
}

View file

@ -39,8 +39,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
[EditMode(DisplayName = "Find & Replace",
SwitchAction = "findmode",
Volatile = true)]
public sealed class FindReplaceMode : ClassicMode
public sealed class FindReplaceMode : BaseClassicMode
{
#region ================== Constants
@ -48,41 +48,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Variables
// Mode to return to
private EditMode basemode;
#endregion
#region ================== Properties
internal EditMode BaseMode { get { return basemode; } }
#endregion
#region ================== Constructor / Disposer
// Constructor
public FindReplaceMode()
{
this.basemode = General.Map.Mode;
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Done
base.Dispose();
}
}
#endregion
#region ================== Methods
#region ================== Events
// Cancelled
public override void OnCancel()
@ -91,7 +67,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
base.OnCancel();
// Return to base mode
General.Map.ChangeMode(basemode.GetType().Name);
General.Map.ChangeMode(General.Map.PreviousStableMode.Name);
}
// Mode engages
@ -127,7 +103,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
General.Map.IsChanged = true;
// Return to base mode
General.Map.ChangeMode(basemode);
General.Map.ChangeMode(General.Map.PreviousStableMode.Name);
}
// Redrawing display

View file

@ -44,7 +44,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
ButtonImage = "LinesMode.png", // Image resource name for the button
ButtonOrder = int.MinValue + 100)] // Position of the button (lower is more to the left)
public class LinedefsMode : ClassicMode
public class LinedefsMode : BaseClassicMode
{
#region ================== Constants
@ -70,28 +70,108 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Constructor / Disposer
// Constructor
public LinedefsMode()
{
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Dispose base
base.Dispose();
}
}
#endregion
#region ================== Methods
// This highlights a new item
protected void Highlight(Linedef l)
{
bool completeredraw = false;
LinedefActionInfo action = null;
// Often we can get away by simply undrawing the previous
// highlight and drawing the new highlight. But if associations
// are or were drawn we need to redraw the entire display.
// Previous association highlights something?
if((highlighted != null) && (highlighted.Tag > 0)) completeredraw = true;
// Set highlight association
if(l != null)
highlightasso.Set(l.Tag, UniversalType.LinedefTag);
else
highlightasso.Set(0, 0);
// New association highlights something?
if((l != null) && (l.Tag > 0)) completeredraw = true;
if(l != null)
{
// Check if we can find the linedefs action
if((l.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(l.Action))
action = General.Map.Config.LinedefActions[l.Action];
}
// Determine linedef associations
for(int i = 0; i < Linedef.NUM_ARGS; i++)
{
// Previous association highlights something?
if((association[i].type == UniversalType.SectorTag) ||
(association[i].type == UniversalType.LinedefTag) ||
(association[i].type == UniversalType.ThingTag)) completeredraw = true;
// Make new association
if(action != null)
association[i].Set(l.Args[i], action.Args[i].Type);
else
association[i].Set(0, 0);
// New association highlights something?
if((association[i].type == UniversalType.SectorTag) ||
(association[i].type == UniversalType.LinedefTag) ||
(association[i].type == UniversalType.ThingTag)) completeredraw = true;
}
// If we're changing associations, then we
// need to redraw the entire display
if(completeredraw)
{
// Set new highlight and redraw completely
highlighted = l;
General.Interface.RedrawDisplay();
}
else
{
// Update display
if(renderer.StartPlotter(false))
{
// Undraw previous highlight
if((highlighted != null) && !highlighted.IsDisposed)
{
renderer.PlotLinedef(highlighted, renderer.DetermineLinedefColor(highlighted));
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
}
// Set new highlight
highlighted = l;
// Render highlighted item
if((highlighted != null) && !highlighted.IsDisposed)
{
renderer.PlotLinedef(highlighted, General.Colors.Highlight);
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
}
// Done
renderer.Finish();
renderer.Present();
}
}
// Show highlight info
if((highlighted != null) && !highlighted.IsDisposed)
General.Interface.ShowLinedefInfo(highlighted);
else
General.Interface.HideInfo();
}
#endregion
#region ================== Events
// Cancel mode
public override void OnCancel()
{
@ -108,7 +188,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.SetPresentation(Presentation.Standard);
// Convert geometry selection to linedefs selection
General.Map.Map.ClearAllMarks();
General.Map.Map.ClearAllMarks(false);
General.Map.Map.MarkSelectedVertices(true, true);
ICollection<Linedef> lines = General.Map.Map.LinedefsFromMarkedVertices(false, true, false);
foreach(Linedef l in lines) l.Selected = true;
@ -173,100 +253,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.Present();
}
// This highlights a new item
protected void Highlight(Linedef l)
{
bool completeredraw = false;
LinedefActionInfo action = null;
// Often we can get away by simply undrawing the previous
// highlight and drawing the new highlight. But if associations
// are or were drawn we need to redraw the entire display.
// Previous association highlights something?
if((highlighted != null) && (highlighted.Tag > 0)) completeredraw = true;
// Set highlight association
if(l != null)
highlightasso.Set(l.Tag, UniversalType.LinedefTag);
else
highlightasso.Set(0, 0);
// New association highlights something?
if((l != null) && (l.Tag > 0)) completeredraw = true;
if(l != null)
{
// Check if we can find the linedefs action
if((l.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(l.Action))
action = General.Map.Config.LinedefActions[l.Action];
}
// Determine linedef associations
for(int i = 0; i < Linedef.NUM_ARGS; i++)
{
// Previous association highlights something?
if((association[i].type == UniversalType.SectorTag) ||
(association[i].type == UniversalType.LinedefTag) ||
(association[i].type == UniversalType.ThingTag)) completeredraw = true;
// Make new association
if(action != null)
association[i].Set(l.Args[i], action.Args[i].Type);
else
association[i].Set(0, 0);
// New association highlights something?
if((association[i].type == UniversalType.SectorTag) ||
(association[i].type == UniversalType.LinedefTag) ||
(association[i].type == UniversalType.ThingTag)) completeredraw = true;
}
// If we're changing associations, then we
// need to redraw the entire display
if(completeredraw)
{
// Set new highlight and redraw completely
highlighted = l;
General.Interface.RedrawDisplay();
}
else
{
// Update display
if(renderer.StartPlotter(false))
{
// Undraw previous highlight
if((highlighted != null) && !highlighted.IsDisposed)
{
renderer.PlotLinedef(highlighted, renderer.DetermineLinedefColor(highlighted));
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
}
// Set new highlight
highlighted = l;
// Render highlighted item
if((highlighted != null) && !highlighted.IsDisposed)
{
renderer.PlotLinedef(highlighted, General.Colors.Highlight);
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
}
// Done
renderer.Finish();
renderer.Present();
}
}
// Show highlight info
if((highlighted != null) && !highlighted.IsDisposed)
General.Interface.ShowLinedefInfo(highlighted);
else
General.Interface.HideInfo();
}
// Selection
protected override void OnSelect()
{
@ -474,17 +460,31 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.Present();
}
}
// When copying
public override bool OnCopyBegin()
{
return true;
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedSectors(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
highlighted.Selected = true;
}
return base.OnCopyBegin();
}
// When pasting
public override bool OnPasteBegin()
{
return true;
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedSectors(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
highlighted.Selected = true;
}
return base.OnPasteBegin();
}
#endregion

View file

@ -43,7 +43,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
ButtonImage = "NewSector2.png", // Image resource name for the button
ButtonOrder = int.MinValue + 202)] // Position of the button (lower is more to the left)
public class MakeSectorMode : ClassicMode
public class MakeSectorMode : BaseClassicMode
{
#region ================== Constants
@ -100,6 +100,111 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Methods
// This draws the geometry
private void DrawGeometry()
{
// Render lines and vertices
if(renderer.StartPlotter(true))
{
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
// Render highlight
if(alllines != null)
{
foreach(Linedef l in alllines) renderer.PlotLinedef(l, General.Colors.Highlight);
}
renderer.PlotVerticesSet(General.Map.Map.Vertices);
renderer.Finish();
}
}
// This draws the overlay
private void DrawOverlay()
{
// Redraw overlay
if(renderer.StartOverlay(true))
{
if((flashpolygon != null) && (flashintensity > 0.0f))
{
renderer.RenderGeometry(flashpolygon, null, true);
}
renderer.Finish();
}
}
// This highlights a new region
protected void Highlight(bool buttonspressed)
{
LinedefSide newnearest;
// Mouse inside?
if(mouseinside)
{
// Highlighting from a new sidedef?
Linedef nl = General.Map.Map.NearestLinedef(mousemappos);
float side = nl.SideOfLine(mousemappos);
newnearest = new LinedefSide(nl, (side <= 0.0f));
if(newnearest != nearestside)
{
// Only change when buttons are not pressed
if(!buttonspressed || (editside == newnearest))
{
// Find new sector
General.Interface.SetCursor(Cursors.AppStarting);
nearestside = newnearest;
allsides = SectorTools.FindPotentialSectorAt(mousemappos);
if(allsides != null)
{
alllines = new List<Linedef>(allsides.Count);
foreach(LinedefSide sd in allsides) alllines.Add(sd.Line);
}
else
{
alllines = null;
}
General.Interface.SetCursor(Cursors.Default);
}
else
{
// Don't highlight this one
nearestside = null;
allsides = null;
alllines = null;
}
// Redraw overlay
DrawGeometry();
renderer.Present();
}
}
else
{
// No valid region
nearestside = null;
allsides = null;
alllines = null;
// Redraw overlay
DrawGeometry();
renderer.Present();
}
}
// Start select
protected override void OnSelect()
{
// Select pressed in this mode
selectpressed = true;
editside = nearestside;
base.OnEdit();
}
#endregion
#region ================== Events
// Cancel mode
public override void OnCancel()
{
@ -171,107 +276,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.Present();
}
// This draws the geometry
private void DrawGeometry()
{
// Render lines and vertices
if(renderer.StartPlotter(true))
{
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
// Render highlight
if(alllines != null)
{
foreach(Linedef l in alllines) renderer.PlotLinedef(l, General.Colors.Highlight);
}
renderer.PlotVerticesSet(General.Map.Map.Vertices);
renderer.Finish();
}
}
// This draws the overlay
private void DrawOverlay()
{
// Redraw overlay
if(renderer.StartOverlay(true))
{
if((flashpolygon != null) && (flashintensity > 0.0f))
{
renderer.RenderGeometry(flashpolygon, null, true);
}
renderer.Finish();
}
}
// This highlights a new region
protected void Highlight(bool buttonspressed)
{
LinedefSide newnearest;
// Mouse inside?
if(mouseinside)
{
// Highlighting from a new sidedef?
Linedef nl = General.Map.Map.NearestLinedef(mousemappos);
float side = nl.SideOfLine(mousemappos);
newnearest = new LinedefSide(nl, (side <= 0.0f));
if(newnearest != nearestside)
{
// Only change when buttons are not pressed
if(!buttonspressed || (editside == newnearest))
{
// Find new sector
General.Interface.SetCursor(Cursors.AppStarting);
nearestside = newnearest;
allsides = SectorTools.FindPotentialSectorAt(mousemappos);
if(allsides != null)
{
alllines = new List<Linedef>(allsides.Count);
foreach(LinedefSide sd in allsides) alllines.Add(sd.Line);
}
else
{
alllines = null;
}
General.Interface.SetCursor(Cursors.Default);
}
else
{
// Don't highlight this one
nearestside = null;
allsides = null;
alllines = null;
}
// Redraw overlay
DrawGeometry();
renderer.Present();
}
}
else
{
// No valid region
nearestside = null;
allsides = null;
alllines = null;
// Redraw overlay
DrawGeometry();
renderer.Present();
}
}
// Start select
protected override void OnSelect()
{
// Select pressed in this mode
selectpressed = true;
editside = nearestside;
base.OnEdit();
}
// Done selecting
protected override void OnEndSelect()
{

View file

@ -44,7 +44,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
ButtonImage = "SectorsMode.png", // Image resource name for the button
ButtonOrder = int.MinValue + 200)] // Position of the button (lower is more to the left)
public class SectorsMode : ClassicMode
public class SectorsMode : BaseClassicMode
{
#region ================== Constants
@ -101,31 +101,105 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Methods
// This clears the selection
[BeginAction("clearselection", BaseAction = true)]
public void ClearSelection()
// Support function for joining and merging sectors
private void JoinMergeSectors(bool removelines)
{
// Clear selection
General.Map.Map.ClearAllSelected();
// Remove lines in betwen joining sectors?
if(removelines)
{
// Go for all selected linedefs
ICollection<Linedef> selectedlines = General.Map.Map.GetSelectedLinedefs(true);
foreach(Linedef ld in selectedlines)
{
// Front and back side?
if((ld.Front != null) && (ld.Back != null))
{
// Both a selected sector, but not the same?
if(ld.Front.Sector.Selected && ld.Back.Sector.Selected &&
(ld.Front.Sector != ld.Back.Sector))
{
// Remove this line
ld.Dispose();
}
}
}
}
// Redraw
General.Interface.RedrawDisplay();
}
// When undo is used
[EndAction("undo", BaseAction = true)]
public void Undo()
{
// Clear ordered selection
orderedselection.Clear();
// Join all selected sectors with the first
for(int i = 1; i < orderedselection.Count; i++)
orderedselection[i].Join(orderedselection[0]);
}
// When redo is used
[EndAction("redo", BaseAction = true)]
public void Redo()
// This highlights a new item
protected void Highlight(Sector s)
{
// Clear ordered selection
orderedselection.Clear();
bool completeredraw = false;
// Often we can get away by simply undrawing the previous
// highlight and drawing the new highlight. But if associations
// are or were drawn we need to redraw the entire display.
// Previous association highlights something?
if((highlighted != null) && (highlighted.Tag > 0)) completeredraw = true;
// Set highlight association
if(s != null)
highlightasso.Set(s.Tag, UniversalType.SectorTag);
else
highlightasso.Set(0, 0);
// New association highlights something?
if((s != null) && (s.Tag > 0)) completeredraw = true;
// If we're changing associations, then we
// need to redraw the entire display
if(completeredraw)
{
// Set new highlight and redraw completely
highlighted = s;
General.Interface.RedrawDisplay();
}
else
{
// Update display
if(renderer.StartPlotter(false))
{
// Undraw previous highlight
if((highlighted != null) && !highlighted.IsDisposed)
renderer.PlotSector(highlighted);
/*
// Undraw highlighted things
if(highlighted != null)
foreach(Thing t in highlighted.Things)
renderer.RenderThing(t, renderer.DetermineThingColor(t));
*/
// Set new highlight
highlighted = s;
// Render highlighted item
if((highlighted != null) && !highlighted.IsDisposed)
renderer.PlotSector(highlighted, General.Colors.Highlight);
/*
// Render highlighted things
if(highlighted != null)
foreach(Thing t in highlighted.Things)
renderer.RenderThing(t, General.Colors.Highlight);
*/
// Done
renderer.Finish();
renderer.Present();
}
}
// Show highlight info
if((highlighted != null) && !highlighted.IsDisposed)
General.Interface.ShowSectorInfo(highlighted);
else
General.Interface.HideInfo();
}
// This selectes or deselects a sector
@ -161,6 +235,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
}
#endregion
#region ================== Events
// Cancel mode
public override void OnCancel()
@ -178,7 +256,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.SetPresentation(Presentation.Standard);
// Convert geometry selection to sectors only
General.Map.Map.ClearAllMarks();
General.Map.Map.ClearAllMarks(false);
General.Map.Map.MarkSelectedVertices(true, true);
ICollection<Linedef> lines = General.Map.Map.LinedefsFromMarkedVertices(false, true, false);
foreach(Linedef l in lines) l.Selected = true;
@ -257,78 +335,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.Present();
}
// This highlights a new item
protected void Highlight(Sector s)
{
bool completeredraw = false;
// Often we can get away by simply undrawing the previous
// highlight and drawing the new highlight. But if associations
// are or were drawn we need to redraw the entire display.
// Previous association highlights something?
if((highlighted != null) && (highlighted.Tag > 0)) completeredraw = true;
// Set highlight association
if(s != null)
highlightasso.Set(s.Tag, UniversalType.SectorTag);
else
highlightasso.Set(0, 0);
// New association highlights something?
if((s != null) && (s.Tag > 0)) completeredraw = true;
// If we're changing associations, then we
// need to redraw the entire display
if(completeredraw)
{
// Set new highlight and redraw completely
highlighted = s;
General.Interface.RedrawDisplay();
}
else
{
// Update display
if(renderer.StartPlotter(false))
{
// Undraw previous highlight
if((highlighted != null) && !highlighted.IsDisposed)
renderer.PlotSector(highlighted);
/*
// Undraw highlighted things
if(highlighted != null)
foreach(Thing t in highlighted.Things)
renderer.RenderThing(t, renderer.DetermineThingColor(t));
*/
// Set new highlight
highlighted = s;
// Render highlighted item
if((highlighted != null) && !highlighted.IsDisposed)
renderer.PlotSector(highlighted, General.Colors.Highlight);
/*
// Render highlighted things
if(highlighted != null)
foreach(Thing t in highlighted.Things)
renderer.RenderThing(t, General.Colors.Highlight);
*/
// Done
renderer.Finish();
renderer.Present();
}
}
// Show highlight info
if((highlighted != null) && !highlighted.IsDisposed)
General.Interface.ShowSectorInfo(highlighted);
else
General.Interface.HideInfo();
}
// Selection
protected override void OnSelect()
{
@ -588,6 +594,50 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.Present();
}
}
// When copying
public override bool OnCopyBegin()
{
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedSectors(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
SelectSector(highlighted, true);
}
return base.OnCopyBegin();
}
// When pasting
public override bool OnPasteBegin()
{
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedSectors(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
SelectSector(highlighted, true);
}
return base.OnPasteBegin();
}
// When undo is used
public override bool OnUndoBegin()
{
// Clear ordered selection
orderedselection.Clear();
return base.OnUndoBegin();
}
// When redo is used
public override bool OnRedoBegin()
{
// Clear ordered selection
orderedselection.Clear();
return base.OnRedoBegin();
}
#endregion
@ -721,35 +771,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
// Support function for joining and merging sectors
private void JoinMergeSectors(bool removelines)
// This clears the selection
[BeginAction("clearselection", BaseAction = true)]
public void ClearSelection()
{
// Remove lines in betwen joining sectors?
if(removelines)
{
// Go for all selected linedefs
ICollection<Linedef> selectedlines = General.Map.Map.GetSelectedLinedefs(true);
foreach(Linedef ld in selectedlines)
{
// Front and back side?
if((ld.Front != null) && (ld.Back != null))
{
// Both a selected sector, but not the same?
if(ld.Front.Sector.Selected && ld.Back.Sector.Selected &&
(ld.Front.Sector != ld.Back.Sector))
{
// Remove this line
ld.Dispose();
}
}
}
}
// Join all selected sectors with the first
for(int i = 1; i < orderedselection.Count; i++)
orderedselection[i].Join(orderedselection[0]);
}
// Clear selection
General.Map.Map.ClearAllSelected();
// Redraw
General.Interface.RedrawDisplay();
}
#endregion
}
}

View file

@ -44,7 +44,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
ButtonImage = "ThingsMode.png", // Image resource name for the button
ButtonOrder = int.MinValue + 300)] // Position of the button (lower is more to the left)
public class ThingsMode : ClassicMode
public class ThingsMode : BaseClassicMode
{
#region ================== Constants
@ -70,24 +70,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Constructor / Disposer
// Constructor
public ThingsMode()
{
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Dispose base
base.Dispose();
}
}
#endregion
#region ================== Methods
@ -108,7 +90,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.SetPresentation(Presentation.Things);
// Convert geometry selection to linedefs selection
General.Map.Map.ClearAllMarks();
General.Map.Map.ClearAllMarks(false);
General.Map.Map.MarkSelectedVertices(true, true);
ICollection<Linedef> lines = General.Map.Map.LinedefsFromMarkedVertices(false, true, false);
foreach(Linedef l in lines) l.Selected = true;
@ -456,6 +438,32 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.Present();
}
}
// When copying
public override bool OnCopyBegin()
{
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedThings(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
highlighted.Selected = true;
}
return base.OnCopyBegin();
}
// When pasting
public override bool OnPasteBegin()
{
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedThings(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
highlighted.Selected = true;
}
return base.OnPasteBegin();
}
#endregion

View file

@ -42,7 +42,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
ButtonImage = "VerticesMode.png", // Image resource name for the button
ButtonOrder = int.MinValue + 0)] // Position of the button (lower is more to the left)
public class VerticesMode : ClassicMode
public class VerticesMode : BaseClassicMode
{
#region ================== Constants
@ -67,24 +67,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Constructor / Disposer
// Constructor
public VerticesMode()
{
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Dispose base
base.Dispose();
}
}
#endregion
#region ================== Methods
@ -107,7 +89,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.SetPresentation(Presentation.Standard);
// Convert geometry selection to vertices only
General.Map.Map.ClearAllMarks();
General.Map.Map.ClearAllMarks(false);
General.Map.Map.MarkSelectedLinedefs(true, true);
General.Map.Map.MarkSelectedSectors(true, true);
verts = General.Map.Map.GetVerticesFromLinesMarks(true);
@ -390,6 +372,32 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
// When copying
public override bool OnCopyBegin()
{
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedVertices(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
highlighted.Selected = true;
}
return base.OnCopyBegin();
}
// When pasting
public override bool OnPasteBegin()
{
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedVertices(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
highlighted.Selected = true;
}
return base.OnPasteBegin();
}
#endregion
#region ================== Actions
@ -463,7 +471,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
General.Interface.RedrawDisplay();
}
}
#endregion
}
}

View file

@ -121,7 +121,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
#endregion
#region ================== Tools
// This renders the associated sectors/linedefs with the indication color
public void PlotAssociations(IRenderer2D renderer, Association asso)
{
@ -143,6 +143,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
}
// This renders the associated things with the indication color
public void RenderAssociations(IRenderer2D renderer, Association asso)
@ -159,6 +160,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
}
// This renders the associated sectors/linedefs with the indication color
public void PlotReverseAssociations(IRenderer2D renderer, Association asso)
@ -181,6 +183,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
}
// This renders the associated things with the indication color
public void RenderReverseAssociations(IRenderer2D renderer, Association asso)

View file

@ -117,16 +117,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
// This shows the menu for the current editing mode
public void ShowEditingModeMenu(EditMode mode)
{
Type sourcemode = typeof(object);
if(mode != null) sourcemode = mode.GetType();
// When these modes are active, then test against the base mode they will return to
if(mode is DragGeometryMode) mode = (mode as DragGeometryMode).BaseMode;
if(mode is DragThingsMode) mode = (mode as DragThingsMode).BaseMode;
if(mode is DrawGeometryMode) mode = (mode as DrawGeometryMode).BaseMode;
if(mode is CurveLinedefsMode) mode = (mode as CurveLinedefsMode).BaseMode;
if((mode is DragGeometryMode) || (mode is DragThingsMode) ||
(mode is DrawGeometryMode) || (mode is CurveLinedefsMode))
sourcemode = General.Map.PreviousStableMode;
// Final decision
if(mode is LinedefsMode) HideAllMenusExcept(linedefsmenu);
else if(mode is SectorsMode) HideAllMenusExcept(sectorsmenu);
else if(mode is ThingsMode) HideAllMenusExcept(thingsmenu);
if(sourcemode == typeof(LinedefsMode)) HideAllMenusExcept(linedefsmenu);
else if(sourcemode == typeof(SectorsMode)) HideAllMenusExcept(sectorsmenu);
else if(sourcemode == typeof(ThingsMode)) HideAllMenusExcept(thingsmenu);
else HideAllMenus();
}

View file

@ -43,6 +43,7 @@ namespace CodeImp.DoomBuilder.Config
private Configuration cfg;
// General settings
private string configname;
private string enginename;
private float defaulttexturescale;
private float defaultflatscale;
@ -102,6 +103,7 @@ namespace CodeImp.DoomBuilder.Config
#region ================== Properties
// General settings
public string Name { get { return configname; } }
public string EngineName { get { return enginename; } }
public float DefaultTextureScale { get { return defaulttexturescale; } }
public float DefaultFlatScale { get { return defaultflatscale; } }
@ -184,6 +186,7 @@ namespace CodeImp.DoomBuilder.Config
this.skills = new List<SkillInfo>();
// Read general settings
configname = cfg.ReadSetting("game", "<unnamed game>");
enginename = cfg.ReadSetting("engine", "");
defaulttexturescale = cfg.ReadSetting("defaulttexturescale", 1f);
defaultflatscale = cfg.ReadSetting("defaultflatscale", 1f);

View file

@ -96,22 +96,25 @@ namespace CodeImp.DoomBuilder.Editing
// that need to be copied.
if(General.Map.Mode.OnCopyBegin())
{
MapSet copyset = new MapSet();
// Copy all data over
copyset = General.Map.Map.Clone();
// Get all marked elements
ICollection<Vertex> verts = General.Map.Map.GetMarkedVertices(true);
ICollection<Sidedef> sides = General.Map.Map.GetMarkedSidedefs(true);
ICollection<Sector> sectors = General.Map.Map.GetMarkedSectors(true);
ICollection<Linedef> lines = General.Map.Map.GetMarkedLinedefs(true);
ICollection<Thing> things = General.Map.Map.GetMarkedThings(true);
// Write data to stream
MemoryStream memstream = new MemoryStream();
UniversalStreamWriter writer = new UniversalStreamWriter();
writer.RememberCustomTypes = false;
writer.Write(copyset, memstream, null);
writer.Write(verts, lines, sides, sectors, things, memstream, null);
// Set on clipboard
Clipboard.SetData(CLIPBOARD_DATA_FORMAT, memstream);
// Done
memstream.Dispose();
General.Map.Mode.OnCopyEnd();
return true;
}
else
@ -124,21 +127,36 @@ namespace CodeImp.DoomBuilder.Editing
// This performs the paste. Returns false when paste was cancelled.
private bool DoPasteSelection()
{
// Ask the editing mode to prepare selection for pasting.
if(General.Map.Mode.OnPasteBegin())
// Anything to paste?
if(Clipboard.ContainsData(CLIPBOARD_DATA_FORMAT))
{
// TODO: Do the paste
if(Clipboard.ContainsData(CLIPBOARD_DATA_FORMAT))
// Ask the editing mode to prepare selection for pasting.
if(General.Map.Mode.OnPasteBegin())
{
// Read from clipboard
Stream memstream = (Stream)Clipboard.GetData(CLIPBOARD_DATA_FORMAT);
memstream.Seek(0, SeekOrigin.Begin);
StreamReader reader = new StreamReader(memstream, Encoding.ASCII);
//File.WriteAllText("C:\\Test.txt", reader.ReadToEnd());
memstream.Dispose();
}
return true;
// Mark all current geometry
General.Map.Map.ClearAllMarks(true);
// Read data stream
UniversalStreamReader reader = new UniversalStreamReader();
reader.Read(General.Map.Map, memstream);
// The new geometry is not marked, so invert the marks to get it marked
General.Map.Map.InvertAllMarks();
// Done
memstream.Dispose();
General.Map.Mode.OnPasteEnd();
return true;
}
else
{
General.MessageBeep(MessageBeepType.Warning);
return false;
}
}
else
{

View file

@ -168,9 +168,20 @@ namespace CodeImp.DoomBuilder.Editing
// The edit mode should mark all vertices, lines and sectors
// that need to be copied.
public virtual bool OnCopyBegin() { return false; }
// Called when the marked geometry has been copied.
public virtual void OnCopyEnd() { }
// Called before pasting. Return false when paste should be cancelled.
public virtual bool OnPasteBegin() { return false; }
public virtual bool OnPasteBegin() { return true; }
// Called after new geometry has been pasted in. The new geometry is marked.
public virtual void OnPasteEnd() { }
// Called when undo/redo is used
// Return false to cancel undo action
public virtual bool OnUndoBegin() { return true; }
public virtual bool OnRedoBegin() { return true; }
// Interface events
public virtual void OnMouseClick(MouseEventArgs e) { }

View file

@ -218,42 +218,46 @@ namespace CodeImp.DoomBuilder.Editing
Cursor oldcursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
// Cancel volatile mode, if any
// This returns false when mode was not volatile
if(!General.CancelVolatileMode())
// Call UndoBegin event
if(General.Map.Mode.OnUndoBegin())
{
// Anything to undo?
if(undos.Count > 0)
// Cancel volatile mode, if any
// This returns false when mode was not volatile
if(!General.CancelVolatileMode())
{
// Get undo snapshot
u = undos[0];
undos.RemoveAt(0);
// Anything to undo?
if(undos.Count > 0)
{
// Get undo snapshot
u = undos[0];
undos.RemoveAt(0);
General.WriteLogLine("Performing undo \"" + u.description + "\", Ticket ID " + u.ticketid + "...");
General.WriteLogLine("Performing undo \"" + u.description + "\", Ticket ID " + u.ticketid + "...");
// Make a snapshot for redo
r = new UndoSnapshot(u, General.Map.Map.Clone());
// Make a snapshot for redo
r = new UndoSnapshot(u, General.Map.Map.Clone());
// Put it on the stack
redos.Insert(0, r);
LimitUndoRedoLevel(redos);
// Put it on the stack
redos.Insert(0, r);
LimitUndoRedoLevel(redos);
// Reset grouping
lastgroup = UndoGroup.None;
// Reset grouping
lastgroup = UndoGroup.None;
// Remove selection
u.map.ClearAllMarks();
u.map.ClearAllSelected();
// Remove selection
u.map.ClearAllMarks(false);
u.map.ClearAllSelected();
// Change map set
General.Map.ChangeMapSet(u.map);
// Change map set
General.Map.ChangeMapSet(u.map);
// Update
General.MainWindow.RedrawDisplay();
General.MainWindow.UpdateInterface();
// Update
General.MainWindow.RedrawDisplay();
General.MainWindow.UpdateInterface();
}
}
}
Cursor.Current = oldcursor;
}
@ -265,38 +269,42 @@ namespace CodeImp.DoomBuilder.Editing
Cursor oldcursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
// Cancel volatile mode, if any
General.CancelVolatileMode();
// Anything to redo?
if(redos.Count > 0)
// Call RedoBegin event
if(General.Map.Mode.OnRedoBegin())
{
// Get redo snapshot
r = redos[0];
redos.RemoveAt(0);
// Cancel volatile mode, if any
General.CancelVolatileMode();
General.WriteLogLine("Performing redo \"" + r.description + "\", Ticket ID " + r.ticketid + "...");
// Anything to redo?
if(redos.Count > 0)
{
// Get redo snapshot
r = redos[0];
redos.RemoveAt(0);
// Make a snapshot for undo
u = new UndoSnapshot(r, General.Map.Map.Clone());
General.WriteLogLine("Performing redo \"" + r.description + "\", Ticket ID " + r.ticketid + "...");
// Put it on the stack
undos.Insert(0, u);
LimitUndoRedoLevel(undos);
// Reset grouping
lastgroup = UndoGroup.None;
// Make a snapshot for undo
u = new UndoSnapshot(r, General.Map.Map.Clone());
// Remove selection
r.map.ClearAllMarks();
r.map.ClearAllSelected();
// Put it on the stack
undos.Insert(0, u);
LimitUndoRedoLevel(undos);
// Change map set
General.Map.ChangeMapSet(r.map);
// Reset grouping
lastgroup = UndoGroup.None;
// Update
General.MainWindow.RedrawDisplay();
General.MainWindow.UpdateInterface();
// Remove selection
r.map.ClearAllMarks(false);
r.map.ClearAllSelected();
// Change map set
General.Map.ChangeMapSet(r.map);
// Update
General.MainWindow.RedrawDisplay();
General.MainWindow.UpdateInterface();
}
}
Cursor.Current = oldcursor;

View file

@ -76,6 +76,8 @@ namespace CodeImp.DoomBuilder
private DataManager data;
private EditMode mode;
private EditMode newmode;
private Type prevmode;
private Type prevstablemode;
private D3DDevice graphics;
private Renderer2D renderer2d;
private Renderer3D renderer3d;
@ -101,6 +103,8 @@ namespace CodeImp.DoomBuilder
public MapSet Map { get { return map; } }
public EditMode Mode { get { return mode; } }
public EditMode NewMode { get { return newmode; } }
public Type PreviousMode { get { return prevmode; } }
public Type PreviousStableMode { get { return prevstablemode; } }
public DataManager Data { get { return data; } }
public bool IsChanged { get { return changed; } set { changed |= value; } }
public bool IsDisposed { get { return isdisposed; } }
@ -862,7 +866,6 @@ namespace CodeImp.DoomBuilder
public void ChangeMode(EditMode nextmode)
{
EditMode oldmode = mode;
newmode = nextmode;
cancelmodechange = false;
// Log info
@ -871,6 +874,19 @@ namespace CodeImp.DoomBuilder
else
General.WriteLogLine("Stopping edit mode...");
// Remember previous mode
newmode = nextmode;
if(mode != null)
{
prevmode = mode.GetType();
if(!mode.Attributes.Volatile) prevstablemode = prevmode;
}
else
{
prevmode = null;
prevstablemode = null;
}
// Let the plugins know beforehand
General.Plugins.ModeChanges(oldmode, newmode);

View file

@ -107,6 +107,17 @@ namespace CodeImp.DoomBuilder.IO
// This writes the structures to a stream
// writenamespace may be null to omit writing the namespace to the stream
public void Write(MapSet map, Stream stream, string writenamespace)
{
Write(map.Vertices, map.Linedefs, map.Sidedefs, map.Sectors, map.Things, stream, writenamespace);
}
// This writes the structures to a stream
// NOTE: writenamespace may be null to omit writing the namespace to the stream.
// NOTE: The given structures must be complete, with the exception of the sidedefs.
// If there are missing sidedefs, their reference will be removed from the linedefs.
public void Write(ICollection<Vertex> vertices, ICollection<Linedef> linedefs,
ICollection<Sidedef> sidedefs, ICollection<Sector> sectors,
ICollection<Thing> things, Stream stream, string writenamespace)
{
UniversalParser textmap = new UniversalParser();
@ -118,24 +129,24 @@ namespace CodeImp.DoomBuilder.IO
Dictionary<Sector, int> sectorids = new Dictionary<Sector, int>();
// Index the elements in the data structures
foreach(Vertex v in map.Vertices) vertexids.Add(v, vertexids.Count);
foreach(Sidedef sd in map.Sidedefs) sidedefids.Add(sd, sidedefids.Count);
foreach(Sector s in map.Sectors) sectorids.Add(s, sectorids.Count);
foreach(Vertex v in vertices) vertexids.Add(v, vertexids.Count);
foreach(Sidedef sd in sidedefs) sidedefids.Add(sd, sidedefids.Count);
foreach(Sector s in sectors) sectorids.Add(s, sectorids.Count);
// If we write the custom field types again, then forget
// all previous field types (this gets rid of unused field types)
if(remembercustomtypes) General.Map.Options.ForgetUniversalFieldTypes();
// Write the data structures to textmap
WriteVertices(map.Vertices, textmap);
WriteLinedefs(map.Linedefs, textmap, sidedefids, vertexids);
WriteSidedefs(map.Sidedefs, textmap, sectorids);
WriteSectors(map.Sectors, textmap);
WriteThings(map.Things, textmap);
WriteVertices(vertices, textmap);
WriteLinedefs(linedefs, textmap, sidedefids, vertexids);
WriteSidedefs(sidedefs, textmap, sectorids);
WriteSectors(sectors, textmap);
WriteThings(things, textmap);
// Get the textmap as string
string textmapstr = textmap.OutputConfiguration();
// Write to stream
StreamWriter writer = new StreamWriter(stream, Encoding.ASCII);
writer.Write(textmapstr);
@ -172,8 +183,19 @@ namespace CodeImp.DoomBuilder.IO
if(l.Tag != 0) coll.Add("id", l.Tag);
coll.Add("v1", vertexids[l.Start]);
coll.Add("v2", vertexids[l.End]);
if(l.Front != null) coll.Add("sidefront", sidedefids[l.Front]); else coll.Add("sidefront", -1);
if(l.Back != null) coll.Add("sideback", sidedefids[l.Back]); else coll.Add("sideback", -1);
// Sidedef references
if((l.Front != null) && sidedefids.ContainsKey(l.Front))
coll.Add("sidefront", sidedefids[l.Front]);
else
coll.Add("sidefront", -1);
if((l.Back != null) && sidedefids.ContainsKey(l.Back))
coll.Add("sideback", sidedefids[l.Back]);
else
coll.Add("sideback", -1);
// Special
if(l.Action != 0) coll.Add("special", l.Action);
if(l.Args[0] != 0) coll.Add("arg0", l.Args[0]);
if(l.Args[1] != 0) coll.Add("arg1", l.Args[1]);
@ -199,6 +221,8 @@ namespace CodeImp.DoomBuilder.IO
// Go for all sidedefs
foreach(Sidedef s in sidedefs)
{
int sectorid = (s.Sector != null) ? sectorids[s.Sector] : -1;
// Make collection
UniversalCollection coll = new UniversalCollection();
if(s.OffsetX != 0) coll.Add("offsetx", s.OffsetX);

View file

@ -441,18 +441,51 @@ namespace CodeImp.DoomBuilder.Map
return list;
}
// This selects geometry based on the marking
public void SelectMarkedGeometry(bool mark, bool select)
{
SelectMarkedVertices(mark, select);
SelectMarkedLinedefs(mark, select);
SelectMarkedSectors(mark, select);
SelectMarkedThings(mark, select);
}
// This selects geometry based on the marking
public void SelectMarkedVertices(bool mark, bool select)
{
foreach(Vertex v in vertices) if(v.Marked == mark) v.Selected = select;
}
// This selects geometry based on the marking
public void SelectMarkedLinedefs(bool mark, bool select)
{
foreach(Linedef l in linedefs) if(l.Marked == mark) l.Selected = select;
}
// This selects geometry based on the marking
public void SelectMarkedSectors(bool mark, bool select)
{
foreach(Sector s in sectors) if(s.Marked == mark) s.Selected = select;
}
// This selects geometry based on the marking
public void SelectMarkedThings(bool mark, bool select)
{
foreach(Thing t in things) if(t.Marked == mark) t.Selected = select;
}
#endregion
#region ================== Marking
// This clears all marks
public void ClearAllMarks()
public void ClearAllMarks(bool mark)
{
ClearMarkedVertices(false);
ClearMarkedThings(false);
ClearMarkedLinedefs(false);
ClearMarkedSectors(false);
ClearMarkedSidedefs(false);
ClearMarkedVertices(mark);
ClearMarkedThings(mark);
ClearMarkedLinedefs(mark);
ClearMarkedSectors(mark);
ClearMarkedSidedefs(mark);
}
// This clears marked vertices
@ -485,6 +518,46 @@ namespace CodeImp.DoomBuilder.Map
foreach(Sector s in sectors) s.Marked = mark;
}
// This inverts all marks
public void InvertAllMarks()
{
InvertMarkedVertices();
InvertMarkedThings();
InvertMarkedLinedefs();
InvertMarkedSectors();
InvertMarkedSidedefs();
}
// This inverts marked vertices
public void InvertMarkedVertices()
{
foreach(Vertex v in vertices) v.Marked = !v.Marked;
}
// This inverts marked things
public void InvertMarkedThings()
{
foreach(Thing t in things) t.Marked = !t.Marked;
}
// This inverts marked linedefs
public void InvertMarkedLinedefs()
{
foreach(Linedef l in linedefs) l.Marked = !l.Marked;
}
// This inverts marked sidedefs
public void InvertMarkedSidedefs()
{
foreach(Sidedef s in sidedefs) s.Marked = !s.Marked;
}
// This inverts marked sectors
public void InvertMarkedSectors()
{
foreach(Sector s in sectors) s.Marked = !s.Marked;
}
// Returns a collection of vertices that match a marked state
public List<Vertex> GetMarkedVertices(bool mark)
{
@ -509,6 +582,14 @@ namespace CodeImp.DoomBuilder.Map
return list;
}
// Returns a collection of sidedefs that match a marked state
public List<Sidedef> GetMarkedSidedefs(bool mark)
{
List<Sidedef> list = new List<Sidedef>(sidedefs.Count >> 1);
foreach(Sidedef s in sidedefs) if(s.Marked == mark) list.Add(s);
return list;
}
// Returns a collection of sectors that match a marked state
public List<Sector> GetMarkedSectors(bool mark)
{
@ -556,6 +637,17 @@ namespace CodeImp.DoomBuilder.Map
}
}
/// <summary>
/// This marks the sidedefs that make up the sectors with the matching mark
/// </summary>
public void MarkSidedefsFromSectors(bool matchmark, bool setmark)
{
foreach(Sidedef sd in sidedefs)
{
if(sd.Sector.Marked == matchmark) sd.Marked = setmark;
}
}
/// <summary>
/// Returns a collection of vertices that match a marked state on the linedefs
/// </summary>
@ -620,6 +712,49 @@ namespace CodeImp.DoomBuilder.Map
}
return list;
}
// This marks all selected geometry, including sidedefs from sectors
// Returns the number of selected elements
public void MarkAllSelectedGeometry(bool mark)
{
General.Map.Map.ClearAllMarks(!mark);
// Direct vertices
General.Map.Map.MarkSelectedVertices(true, mark);
// Direct linedefs
General.Map.Map.MarkSelectedLinedefs(true, mark);
// Vertices from linedefs
ICollection<Vertex> verts = General.Map.Map.GetVerticesFromLinesMarks(mark);
foreach(Vertex v in verts) v.Marked = mark;
// Linedefs from vertices
ICollection<Linedef> lines = General.Map.Map.LinedefsFromMarkedVertices(!mark, mark, !mark);
foreach(Linedef l in lines) l.Marked = mark;
// Mark sectors from linedefs (note: this must be the first to mark
// sectors, because this clears the sector marks!)
General.Map.Map.ClearMarkedSectors(mark);
foreach(Linedef l in General.Map.Map.Linedefs)
{
if(!l.Selected)
{
if(l.Front != null) l.Front.Sector.Marked = !mark;
if(l.Back != null) l.Back.Sector.Marked = !mark;
}
}
// Direct sectors
General.Map.Map.MarkSelectedSectors(true, mark);
// Direct things
General.Map.Map.MarkSelectedThings(true, mark);
// Sidedefs from linedefs
//General.Map.Map.MarkSidedefsFromLinedefs(true, mark);
General.Map.Map.MarkSidedefsFromSectors(true, mark);
}
#endregion

View file

@ -43,6 +43,7 @@ namespace CodeImp.DoomBuilder.Windows
System.Windows.Forms.ToolStripSeparator toolStripMenuItem4;
System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
System.Windows.Forms.ToolStripSeparator toolStripSeparator7;
System.Windows.Forms.ToolStripSeparator toolStripSeparator12;
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.itemeditmodesseperator = new System.Windows.Forms.ToolStripSeparator();
this.buttoneditmodesseperator = new System.Windows.Forms.ToolStripSeparator();
@ -62,6 +63,10 @@ namespace CodeImp.DoomBuilder.Windows
this.menuedit = new System.Windows.Forms.ToolStripMenuItem();
this.itemundo = new System.Windows.Forms.ToolStripMenuItem();
this.itemredo = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem7 = new System.Windows.Forms.ToolStripSeparator();
this.itemcut = new System.Windows.Forms.ToolStripMenuItem();
this.itemcopy = new System.Windows.Forms.ToolStripMenuItem();
this.itempaste = new System.Windows.Forms.ToolStripMenuItem();
this.itemsnaptogrid = new System.Windows.Forms.ToolStripMenuItem();
this.itemautomerge = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator();
@ -96,6 +101,7 @@ namespace CodeImp.DoomBuilder.Windows
this.statusbar = new System.Windows.Forms.StatusStrip();
this.statuslabel = new System.Windows.Forms.ToolStripStatusLabel();
this.warninglabel = new System.Windows.Forms.ToolStripStatusLabel();
this.configlabel = new System.Windows.Forms.ToolStripStatusLabel();
this.gridlabel = new System.Windows.Forms.ToolStripStatusLabel();
this.buttongrid = new System.Windows.Forms.ToolStripDropDownButton();
this.itemgrid1024 = new System.Windows.Forms.ToolStripMenuItem();
@ -130,10 +136,6 @@ namespace CodeImp.DoomBuilder.Windows
this.processor = new System.Windows.Forms.Timer(this.components);
this.warningtimer = new System.Windows.Forms.Timer(this.components);
this.warningflasher = new System.Windows.Forms.Timer(this.components);
this.toolStripMenuItem7 = new System.Windows.Forms.ToolStripSeparator();
this.itemcut = new System.Windows.Forms.ToolStripMenuItem();
this.itemcopy = new System.Windows.Forms.ToolStripMenuItem();
this.itempaste = new System.Windows.Forms.ToolStripMenuItem();
toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
toolStripMenuItem3 = new System.Windows.Forms.ToolStripSeparator();
@ -148,6 +150,7 @@ namespace CodeImp.DoomBuilder.Windows
toolStripMenuItem4 = new System.Windows.Forms.ToolStripSeparator();
toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator();
toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator();
this.menumain.SuspendLayout();
this.toolbar.SuspendLayout();
this.statusbar.SuspendLayout();
@ -230,6 +233,12 @@ namespace CodeImp.DoomBuilder.Windows
toolStripSeparator7.Name = "toolStripSeparator7";
toolStripSeparator7.Size = new System.Drawing.Size(6, 25);
//
// toolStripSeparator12
//
toolStripSeparator12.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
toolStripSeparator12.Name = "toolStripSeparator12";
toolStripSeparator12.Size = new System.Drawing.Size(6, 23);
//
// itemeditmodesseperator
//
this.itemeditmodesseperator.Name = "itemeditmodesseperator";
@ -401,6 +410,38 @@ namespace CodeImp.DoomBuilder.Windows
this.itemredo.Text = "Redo";
this.itemredo.Click += new System.EventHandler(this.InvokeTaggedAction);
//
// toolStripMenuItem7
//
this.toolStripMenuItem7.Name = "toolStripMenuItem7";
this.toolStripMenuItem7.Size = new System.Drawing.Size(162, 6);
//
// itemcut
//
this.itemcut.Image = global::CodeImp.DoomBuilder.Properties.Resources.Cut;
this.itemcut.Name = "itemcut";
this.itemcut.Size = new System.Drawing.Size(165, 22);
this.itemcut.Tag = "builder_cutselection";
this.itemcut.Text = "Cut";
this.itemcut.Click += new System.EventHandler(this.InvokeTaggedAction);
//
// itemcopy
//
this.itemcopy.Image = global::CodeImp.DoomBuilder.Properties.Resources.Copy;
this.itemcopy.Name = "itemcopy";
this.itemcopy.Size = new System.Drawing.Size(165, 22);
this.itemcopy.Tag = "builder_copyselection";
this.itemcopy.Text = "Copy";
this.itemcopy.Click += new System.EventHandler(this.InvokeTaggedAction);
//
// itempaste
//
this.itempaste.Image = global::CodeImp.DoomBuilder.Properties.Resources.Paste;
this.itempaste.Name = "itempaste";
this.itempaste.Size = new System.Drawing.Size(165, 22);
this.itempaste.Tag = "builder_pasteselection";
this.itempaste.Text = "Paste";
this.itempaste.Click += new System.EventHandler(this.InvokeTaggedAction);
//
// itemsnaptogrid
//
this.itemsnaptogrid.Checked = true;
@ -732,6 +773,8 @@ namespace CodeImp.DoomBuilder.Windows
this.statusbar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.statuslabel,
this.warninglabel,
this.configlabel,
toolStripSeparator12,
this.gridlabel,
this.buttongrid,
toolStripSeparator1,
@ -753,7 +796,7 @@ namespace CodeImp.DoomBuilder.Windows
this.statuslabel.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.statuslabel.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
this.statuslabel.Name = "statuslabel";
this.statuslabel.Size = new System.Drawing.Size(571, 18);
this.statuslabel.Size = new System.Drawing.Size(208, 18);
this.statuslabel.Spring = true;
this.statuslabel.Text = "Initializing user interface...";
this.statuslabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
@ -770,12 +813,22 @@ namespace CodeImp.DoomBuilder.Windows
this.warninglabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.warninglabel.Visible = false;
//
// configlabel
//
this.configlabel.AutoSize = false;
this.configlabel.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.configlabel.Name = "configlabel";
this.configlabel.Size = new System.Drawing.Size(250, 18);
this.configlabel.Text = "ZDoom (Doom in Hexen Format)";
this.configlabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.configlabel.ToolTipText = "Current Game Configuration";
//
// gridlabel
//
this.gridlabel.AutoSize = false;
this.gridlabel.AutoToolTip = true;
this.gridlabel.Name = "gridlabel";
this.gridlabel.Size = new System.Drawing.Size(128, 18);
this.gridlabel.Size = new System.Drawing.Size(62, 18);
this.gridlabel.Text = "32 mp";
this.gridlabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.gridlabel.TextImageRelation = System.Windows.Forms.TextImageRelation.Overlay;
@ -1093,38 +1146,6 @@ namespace CodeImp.DoomBuilder.Windows
//
this.warningflasher.Tick += new System.EventHandler(this.warningflasher_Tick);
//
// toolStripMenuItem7
//
this.toolStripMenuItem7.Name = "toolStripMenuItem7";
this.toolStripMenuItem7.Size = new System.Drawing.Size(162, 6);
//
// itemcut
//
this.itemcut.Image = global::CodeImp.DoomBuilder.Properties.Resources.Cut;
this.itemcut.Name = "itemcut";
this.itemcut.Size = new System.Drawing.Size(165, 22);
this.itemcut.Tag = "builder_cutselection";
this.itemcut.Text = "Cut";
this.itemcut.Click += new System.EventHandler(this.InvokeTaggedAction);
//
// itemcopy
//
this.itemcopy.Image = global::CodeImp.DoomBuilder.Properties.Resources.Copy;
this.itemcopy.Name = "itemcopy";
this.itemcopy.Size = new System.Drawing.Size(165, 22);
this.itemcopy.Tag = "builder_copyselection";
this.itemcopy.Text = "Copy";
this.itemcopy.Click += new System.EventHandler(this.InvokeTaggedAction);
//
// itempaste
//
this.itempaste.Image = global::CodeImp.DoomBuilder.Properties.Resources.Paste;
this.itempaste.Name = "itempaste";
this.itempaste.Size = new System.Drawing.Size(165, 22);
this.itempaste.Tag = "builder_pasteselection";
this.itempaste.Text = "Paste";
this.itempaste.Click += new System.EventHandler(this.InvokeTaggedAction);
//
// MainForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
@ -1256,5 +1277,6 @@ namespace CodeImp.DoomBuilder.Windows
private System.Windows.Forms.ToolStripMenuItem itemcut;
private System.Windows.Forms.ToolStripMenuItem itemcopy;
private System.Windows.Forms.ToolStripMenuItem itempaste;
private System.Windows.Forms.ToolStripStatusLabel configlabel;
}
}

View file

@ -379,6 +379,7 @@ namespace CodeImp.DoomBuilder.Windows
buttonzoom.Enabled = true;
gridlabel.Enabled = true;
buttongrid.Enabled = true;
configlabel.Text = General.Map.Config.Name;
}
else
{
@ -392,6 +393,7 @@ namespace CodeImp.DoomBuilder.Windows
buttonzoom.Enabled = false;
gridlabel.Enabled = false;
buttongrid.Enabled = false;
configlabel.Text = "";
}
}

View file

@ -159,6 +159,9 @@
<metadata name="toolStripSeparator7.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="toolStripSeparator12.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="menumain.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>