UltimateZoneBuilder/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
MaxED 5e71585c99 Added, Edit Selection mode: Added "Adjust height" setting. It can be used to adjust floor/ceiling height of selected sectors based on the sector selection was in and the sector selection was moved into.
Removed "Adjust heights to match relatively with surrounding sector" option from Preferences -> Pasting, because sector height adjustments are now handled by Edit Selection mode.
Fixed, Sector info panel: in some cases 0 deg. floor/ceiling texture rotation was triggering texture offset/scale/rotation UI parts to be shown.
Fixed even more cases when sidedefs belonging to linedefs, which were moved on top of existing linedefs, were incorrectly reassigned when applying Edit Selection and Drag Geometry modes.
Fixed, Bridge mode: in some cases calculated floor/ceiling heights were not applied to the sectors created by the mode.
Changed, internal: changed program's CurrentCulture to InvariantCulture.
2016-05-20 15:04:00 +00:00

937 lines
30 KiB
C#

#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Windows;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "Draw Lines Mode",
SwitchAction = "drawlinesmode",
ButtonImage = "DrawGeometryMode.png", //mxd
ButtonOrder = int.MinValue + 1, //mxd
ButtonGroup = "000_drawing", //mxd
AllowCopyPaste = false,
Volatile = true,
UseByDefault = true,
Optional = false)]
public class DrawGeometryMode : BaseClassicMode
{
#region ================== Constants
protected const float LINE_THICKNESS = 0.8f;
#endregion
#region ================== Variables
// Drawing points
protected List<DrawnVertex> points;
protected List<LineLengthLabel> labels;
private LineLengthLabel[] guidelabels; //mxd
// Options
protected bool snaptogrid; // SHIFT to toggle
protected bool snaptonearest; // CTRL to enable
protected bool snaptocardinaldirection; //mxd. ALT-SHIFT to enable
protected bool usefourcardinaldirections;
protected bool continuousdrawing; //mxd. Restart after finishing drawing?
protected bool autoclosedrawing; //mxd. Finish drawing when new points and existing geometry form a closed shape
protected bool drawingautoclosed; //mxd
private bool showguidelines; //mxd
//mxd. Map area bounds
private Line2D top, bottom, left, right;
//mxd. Labels display style
protected bool labelshowangle = true;
protected bool labeluseoffset = true;
//mxd. Interface
private DrawLineOptionsPanel panel;
#endregion
#region ================== Properties
#endregion
#region ================== Constructor / Disposer
// Constructor
public DrawGeometryMode()
{
// Initialize
points = new List<DrawnVertex>();
labels = new List<LineLengthLabel>();
// No selection in this mode
General.Map.Map.ClearAllSelected();
General.Map.Map.ClearAllMarks(false);
//mxd
SetupInterface();
// We have no destructor
GC.SuppressFinalize(this);
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
if(labels != null) foreach(LineLengthLabel l in labels) l.Dispose();
if(guidelabels != null) foreach(LineLengthLabel l in guidelabels) l.Dispose();
// Done
base.Dispose();
}
}
#endregion
#region ================== Methods
// This checks if the view offset/zoom changed and updates the check (never used. mxd)
/*protected bool CheckViewChanged()
{
// View changed?
bool viewchanged = (renderer.OffsetX != lastoffsetx || renderer.OffsetY != lastoffsety || renderer.Scale != lastscale);
// Keep view information
lastoffsetx = renderer.OffsetX;
lastoffsety = renderer.OffsetY;
lastscale = renderer.Scale;
// Return result
return viewchanged;
}*/
// This updates the dragging
protected virtual void Update()
{
PixelColor stitchcolor = General.Colors.Highlight;
PixelColor losecolor = General.Colors.Selection;
snaptocardinaldirection = General.Interface.ShiftState && General.Interface.AltState; //mxd
snaptogrid = (snaptocardinaldirection || General.Interface.ShiftState ^ General.Interface.SnapToGrid);
snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
DrawnVertex curp = GetCurrentPosition();
float vsize = (renderer.VertexSize + 1.0f) / renderer.Scale;
// Update label positions (mxd)
if(labels.Count > 0)
{
// Update labels for already drawn lines
for(int i = 0; i < labels.Count - 1; i++)
{
labels[i].ShowAngle = showguidelines;
labels[i].Move(points[i].pos, points[i + 1].pos);
}
// Update label for active line
labels[labels.Count - 1].ShowAngle = showguidelines;
labels[labels.Count - 1].Move(points[points.Count - 1].pos, curp.pos);
}
// Render drawing lines
if(renderer.StartOverlay(true))
{
// Go for all points to draw lines
PixelColor color;
if(points.Count > 0)
{
//mxd
bool renderguidelabels = false;
if(showguidelines)
{
Vector2D prevp = points[points.Count - 1].pos;
PixelColor c = General.Colors.InfoLine.WithAlpha(80);
if(curp.pos.x != prevp.x && curp.pos.y != prevp.y)
{
renderguidelabels = true;
Vector2D tr = new Vector2D(Math.Max(curp.pos.x, prevp.x), Math.Max(curp.pos.y, prevp.y));
Vector2D bl = new Vector2D(Math.Min(curp.pos.x, prevp.x), Math.Min(curp.pos.y, prevp.y));
// Create guidelines
Line3D[] lines = new Line3D[5];
lines[0] = new Line3D(new Vector2D(tr.x, General.Map.Config.TopBoundary), new Vector2D(tr.x, General.Map.Config.BottomBoundary), c, false);
lines[1] = new Line3D(new Vector2D(bl.x, General.Map.Config.TopBoundary), new Vector2D(bl.x, General.Map.Config.BottomBoundary), c, false);
lines[2] = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, tr.y), new Vector2D(General.Map.Config.RightBoundary, tr.y), c, false);
lines[3] = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, bl.y), new Vector2D(General.Map.Config.RightBoundary, bl.y), c, false);
// Create current line extent. Make sure v1 is to the left of v2
Line2D current = (curp.pos.x < prevp.x ? new Line2D(curp.pos, prevp) : new Line2D(prevp, curp.pos));
Vector2D extentstart, extentend;
if(current.v1.y < current.v2.y) // Start is lower
{
// Start point can hit left or bottom boundaries
extentstart = Line2D.GetIntersectionPoint(left, current, false);
if(extentstart.y < General.Map.Config.BottomBoundary) extentstart = Line2D.GetIntersectionPoint(bottom, current, false);
// End point can hit right or top boundaries
extentend = Line2D.GetIntersectionPoint(right, current, false);
if(extentend.y > General.Map.Config.TopBoundary) extentend = Line2D.GetIntersectionPoint(top, current, false);
}
else // Start is higher
{
// Start point can hit left or top boundaries
extentstart = Line2D.GetIntersectionPoint(left, current, false);
if(extentstart.y > General.Map.Config.TopBoundary) extentstart = Line2D.GetIntersectionPoint(top, current, false);
// End point can hit right or bottom boundaries
extentend = Line2D.GetIntersectionPoint(right, current, false);
if(extentend.y < General.Map.Config.BottomBoundary) extentend = Line2D.GetIntersectionPoint(bottom, current, false);
}
lines[4] = new Line3D(extentstart, extentend, c, false);
// Render them
renderer.RenderArrows(lines);
// Update horiz/vert length labels
guidelabels[0].Move(tr, new Vector2D(tr.x, bl.y));
guidelabels[1].Move(new Vector2D(bl.x, tr.y), tr);
guidelabels[2].Move(new Vector2D(tr.x, bl.y), bl);
guidelabels[3].Move(bl, new Vector2D(bl.x, tr.y));
}
// Render horizontal line
else if(curp.pos.x != prevp.x)
{
Line3D l = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, curp.pos.y), new Vector2D(General.Map.Config.RightBoundary, curp.pos.y), c, false);
renderer.RenderArrows(new List<Line3D>{ l });
}
// Render vertical line
else if(curp.pos.y != prevp.y)
{
Line3D l = new Line3D(new Vector2D(curp.pos.x, General.Map.Config.TopBoundary), new Vector2D(curp.pos.x, General.Map.Config.BottomBoundary), c, false);
renderer.RenderArrows(new List<Line3D> { l });
}
}
// Render lines
DrawnVertex lastp = points[0];
for(int i = 1; i < points.Count; i++)
{
// Determine line color
if(lastp.stitchline && points[i].stitchline) color = stitchcolor;
else color = losecolor;
// Render line
renderer.RenderLine(lastp.pos, points[i].pos, LINE_THICKNESS, color, true);
RenderLinedefDirectionIndicator(lastp.pos, points[i].pos, color); //mxd
lastp = points[i];
}
// Determine line color
color = (lastp.stitchline && snaptonearest ? stitchcolor : losecolor);
// Render line to cursor
renderer.RenderLine(lastp.pos, curp.pos, LINE_THICKNESS, color, true);
RenderLinedefDirectionIndicator(lastp.pos, curp.pos, color); //mxd
// Render vertices
for(int i = 0; i < points.Count; i++)
{
// Determine vertex color
color = points[i].stitch ? stitchcolor : losecolor;
// Render vertex
renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - vsize, points[i].pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true);
}
//mxd. Render guide labels?
if(renderguidelabels) renderer.RenderText(guidelabels);
// Render labels
renderer.RenderText(labels.ToArray());
}
// Determine point color
color = snaptonearest ? stitchcolor : 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);
// Done
renderer.Finish();
}
// Done
renderer.Present();
}
//mxd
private void RenderLinedefDirectionIndicator(Vector2D start, Vector2D end, PixelColor color)
{
Vector2D delta = end - start;
Vector2D middlePoint = new Vector2D(start.x + delta.x / 2, start.y + delta.y / 2);
Vector2D scaledPerpendicular = delta.GetPerpendicular().GetNormal().GetScaled(18f / renderer.Scale);
renderer.RenderLine(middlePoint, new Vector2D(middlePoint.x - scaledPerpendicular.x, middlePoint.y - scaledPerpendicular.y), LINE_THICKNESS, color, true);
}
// This returns the aligned and snapped draw position
public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, bool snaptocardinal, bool usefourcardinaldirections, IRenderer2D renderer, List<DrawnVertex> points)
{
DrawnVertex p = new DrawnVertex();
p.stitch = true; //mxd. Setting these to false seems to be a good way to create invalid geometry...
p.stitchline = true; //mxd
//mxd. If snap to cardinal directions is enabled and we have points, modify mouse position
Vector2D vm, gridoffset;
if(snaptocardinal && points.Count > 0)
{
Vector2D offset = mousemappos - points[points.Count - 1].pos;
float angle;
if(usefourcardinaldirections)
angle = Angle2D.DegToRad((General.ClampAngle((int)Angle2D.RadToDeg(offset.GetAngle()))) / 90 * 90 + 45);
else
angle = Angle2D.DegToRad((General.ClampAngle((int)Angle2D.RadToDeg(offset.GetAngle()) + 22)) / 45 * 45);
offset = new Vector2D(0, -offset.GetLength()).GetRotated(angle);
vm = points[points.Count - 1].pos + offset;
//mxd. We need to be snapped relative to initial position
Vector2D prev = points[points.Count - 1].pos;
gridoffset = prev - General.Map.Grid.SnappedToGrid(prev);
}
else
{
vm = mousemappos;
gridoffset = new Vector2D();
}
float vrange = BuilderPlug.Me.StitchRange / renderer.Scale;
// Snap to nearest?
if(snaptonearest)
{
// Go for all drawn points
foreach(DrawnVertex v in points)
{
if(Vector2D.DistanceSq(vm, v.pos) < (vrange * vrange))
{
p.pos = v.pos;
return p;
}
}
// Try the nearest vertex
Vertex nv = General.Map.Map.NearestVertexSquareRange(vm, vrange);
if(nv != null)
{
//mxd. Line angle must stay the same
if(snaptocardinal) //mxd
{
Line2D ourline = new Line2D(points[points.Count - 1].pos, vm);
if(Math.Round(ourline.GetSideOfLine(nv.Position), 1) == 0)
{
p.pos = nv.Position;
return p;
}
}
else
{
p.pos = nv.Position;
return p;
}
}
// Try the nearest linedef. mxd. We'll need much bigger stitch distance when snapping to cardinal directions
Linedef nl = General.Map.Map.NearestLinedefRange(vm, BuilderPlug.Me.StitchRange / renderer.Scale);
if(nl != null)
{
//mxd. Line angle must stay the same
if(snaptocardinal)
{
Line2D ourline = new Line2D(points[points.Count - 1].pos, vm);
Line2D nearestline = new Line2D(nl.Start.Position, nl.End.Position);
Vector2D intersection = Line2D.GetIntersectionPoint(nearestline, ourline, false);
if(!float.IsNaN(intersection.x))
{
// Intersection is on nearestline?
float u = Line2D.GetNearestOnLine(nearestline.v1, nearestline.v2, intersection);
if(u < 0f || u > 1f){}
else
{
p.pos = new Vector2D((float)Math.Round(intersection.x, General.Map.FormatInterface.VertexDecimals),
(float)Math.Round(intersection.y, General.Map.FormatInterface.VertexDecimals));
return p;
}
}
}
// Snap to grid?
else if(snaptogrid)
{
// Get grid intersection coordinates
List<Vector2D> coords = nl.GetGridIntersections();
// Find nearest grid intersection
bool found = false;
float found_distance = float.MaxValue;
Vector2D found_coord = new Vector2D();
foreach(Vector2D v in coords)
{
Vector2D delta = vm - v;
if(delta.GetLengthSq() < found_distance)
{
found_distance = delta.GetLengthSq();
found_coord = v;
found = true;
}
}
if(found)
{
// Align to the closest grid intersection
p.pos = found_coord;
return p;
}
}
else
{
// Aligned to line
p.pos = nl.NearestOnLine(vm);
return p;
}
}
}
else
{
// Always snap to the first drawn vertex so that the user can finish a complete sector without stitching
if(points.Count > 0)
{
if(Vector2D.DistanceSq(vm, points[0].pos) < (vrange * vrange))
{
p.pos = points[0].pos;
return p;
}
}
}
// if the mouse cursor is outside the map bondaries check if the line between the last set point and the
// mouse cursor intersect any of the boundary lines. If it does, set the position to this intersection
if(points.Count > 0 &&
(mousemappos.x < General.Map.Config.LeftBoundary || mousemappos.x > General.Map.Config.RightBoundary ||
mousemappos.y > General.Map.Config.TopBoundary || mousemappos.y < General.Map.Config.BottomBoundary))
{
Line2D dline = new Line2D(mousemappos, points[points.Count - 1].pos);
bool foundintersection = false;
float u = 0.0f;
List<Line2D> blines = new List<Line2D>();
// lines for left, top, right and bottom boundaries
blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary));
blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.TopBoundary));
blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary));
blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary));
// check for intersections with boundaries
for(int i = 0; i < blines.Count; i++)
{
if(!foundintersection)
{
// only check for intersection if the last set point is not on the
// line we are checking against
if(blines[i].GetSideOfLine(points[points.Count - 1].pos) != 0.0f)
{
foundintersection = blines[i].GetIntersection(dline, out u);
}
}
}
// if there was no intersection set the position to the last set point
if(!foundintersection)
vm = points[points.Count - 1].pos;
else
vm = dline.GetCoordinatesAt(u);
}
// Snap to grid?
if(snaptogrid)
{
// Aligned to grid
p.pos = General.Map.Grid.SnappedToGrid(vm - gridoffset) + gridoffset;
// special handling
if(p.pos.x > General.Map.Config.RightBoundary) p.pos.x = General.Map.Config.RightBoundary;
if(p.pos.y < General.Map.Config.BottomBoundary) p.pos.y = General.Map.Config.BottomBoundary;
return p;
}
else
{
// Normal position
p.pos.x = (float)Math.Round(vm.x); //mxd
p.pos.y = (float)Math.Round(vm.y); //mxd
return p;
}
}
// This gets the aligned and snapped draw position
protected DrawnVertex GetCurrentPosition()
{
return GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, snaptocardinaldirection, usefourcardinaldirections, renderer, points);
}
// This draws a point at a specific location
public bool DrawPointAt(DrawnVertex p)
{
return DrawPointAt(p.pos, p.stitch, p.stitchline);
}
// This draws a point at a specific location
public virtual bool DrawPointAt(Vector2D pos, bool stitch, bool stitchline)
{
if(pos.x < General.Map.Config.LeftBoundary || pos.x > General.Map.Config.RightBoundary ||
pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary)
return false;
DrawnVertex newpoint = new DrawnVertex();
newpoint.pos = pos;
newpoint.stitch = stitch;
newpoint.stitchline = stitchline;
points.Add(newpoint);
labels.Add(new LineLengthLabel(labelshowangle, labeluseoffset));
Update();
if(points.Count > 1)
{
// Check if point stitches with the first
if(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))
{
//mxd. Seems... logical?
if(points.Count == 2)
{
OnCancel();
return true;
}
// Finish drawing
FinishDraw();
return true;
}
}
//mxd. Points and existing geometry form a closed shape?
if(autoclosedrawing)
{
// Determive center point
float minx = float.MaxValue;
float maxx = float.MinValue;
float miny = float.MaxValue;
float maxy = float.MinValue;
foreach(DrawnVertex v in points)
{
if(v.pos.x < minx) minx = v.pos.x;
if(v.pos.x > maxx) maxx = v.pos.x;
if(v.pos.y < miny) miny = v.pos.y;
if(v.pos.y > maxy) maxy = v.pos.y;
}
Vector2D shapecenter = new Vector2D(minx + (maxx - minx) / 2, miny + (maxy - miny) / 2);
// Determine center point between start and end points
minx = Math.Min(points[0].pos.x, points[points.Count - 1].pos.x);
maxx = Math.Max(points[0].pos.x, points[points.Count - 1].pos.x);
miny = Math.Min(points[0].pos.y, points[points.Count - 1].pos.y);
maxy = Math.Max(points[0].pos.y, points[points.Count - 1].pos.y);
Vector2D startendcenter = new Vector2D(minx + (maxx - minx) / 2, miny + (maxy - miny) / 2);
// Offset the center perpendicular to the start -> end line direction...
if(shapecenter == startendcenter)
{
shapecenter -= new Line2D(points[0].pos, points[points.Count - 1].pos).GetPerpendicular().GetNormal();
}
// Do the check
if(CanFinishDrawing(points[0].pos, points[points.Count - 1].pos, shapecenter))
{
drawingautoclosed = true;
FinishDraw();
}
}
}
return true;
}
//mxd
private static bool CanFinishDrawing(Vector2D start, Vector2D end, Vector2D center)
{
Linedef startline = FindPotentialLine(start, center);
if(startline == null) return false;
Linedef endline = FindPotentialLine(end, center);
if(endline == null) return false;
// Can finish drawing if a path between startline and endline exists
return Tools.FindClosestPath(startline, startline.SideOfLine(center) < 0.0f, endline, endline.SideOfLine(center) < 0.0f, true) != null;
}
//mxd
private static Linedef FindPotentialLine(Vector2D target, Vector2D center)
{
// Target position on top of existing vertex?
Vertex v = General.Map.Map.NearestVertex(target);
if(v == null) return null;
Linedef result = null;
if(v.Position == target)
{
float mindistance = float.MaxValue;
foreach(Linedef l in v.Linedefs)
{
if(result == null)
{
result = l;
mindistance = Vector2D.DistanceSq(l.GetCenterPoint(), center);
}
else
{
float curdistance = Vector2D.DistanceSq(l.GetCenterPoint(), center);
if(curdistance < mindistance)
{
mindistance = curdistance;
result = l;
}
}
}
}
else
{
// Result position will split a line?
result = General.Map.Map.NearestLinedef(target);
if(result.SideOfLine(target) != 0) return null;
}
return result;
}
#endregion
#region ================== mxd. Settings panel
protected virtual void SetupInterface()
{
//Add options docker
panel = new DrawLineOptionsPanel();
panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged;
panel.OnAutoCloseDrawingChanged += OnAutoCloseDrawingChanged;
panel.OnShowGuidelinesChanged += OnShowGuidelinesChanged;
// Needs to be set after adding the events...
panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawlinesmode.continuousdrawing", false);
panel.AutoCloseDrawing = General.Settings.ReadPluginSetting("drawlinesmode.autoclosedrawing", false);
panel.ShowGuidelines = General.Settings.ReadPluginSetting("drawlinesmode.showguidelines", false);
// Create guide labels
guidelabels = new LineLengthLabel[4];
for(int i = 0; i < guidelabels.Length; i++)
{
guidelabels[i] = new LineLengthLabel { ShowAngle = false, Color = General.Colors.InfoLine };
}
// Create map boudary lines
Vector2D btl = new Vector2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary);
Vector2D btr = new Vector2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary);
Vector2D bbl = new Vector2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary);
Vector2D bbr = new Vector2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary);
top = new Line2D(btl, btr);
right = new Line2D(btr, bbr);
bottom = new Line2D(bbl, bbr);
left = new Line2D(btl, bbl);
}
protected virtual void AddInterface()
{
panel.Register();
}
protected virtual void RemoveInterface()
{
General.Settings.WritePluginSetting("drawlinesmode.continuousdrawing", panel.ContinuousDrawing);
General.Settings.WritePluginSetting("drawlinesmode.autoclosedrawing", panel.AutoCloseDrawing);
General.Settings.WritePluginSetting("drawlinesmode.showguidelines", panel.ShowGuidelines);
panel.Unregister();
}
#endregion
#region ================== Events
public override void OnHelp()
{
General.ShowHelp("e_drawgeometry.html");
}
// Engaging
public override void OnEngage()
{
base.OnEngage();
EnableAutoPanning();
AddInterface(); //mxd
renderer.SetPresentation(Presentation.Standard);
// Set cursor
General.Interface.SetCursor(Cursors.Cross);
}
// Disengaging
public override void OnDisengage()
{
RemoveInterface(); //mxd
base.OnDisengage();
DisableAutoPanning();
}
// Cancelled
public override void OnCancel()
{
//mxd. Cannot leave this way when continuous drawing is enabled
if(continuousdrawing)
{
drawingautoclosed = false;
return;
}
// Cancel base class
base.OnCancel();
// Return to original mode
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
}
// Accepted
public override void OnAccept()
{
Cursor.Current = Cursors.AppStarting;
General.Settings.FindDefaultDrawSettings();
// When points have been drawn
if(points.Count > 0)
{
// Make undo for the draw
General.Map.UndoRedo.CreateUndo("Line draw");
// Make an analysis and show info
string[] adjectives = new[]
{ "beautiful", "lovely", "romantic", "stylish", "cheerful", "comical",
"awesome", "accurate", "adorable", "adventurous", "attractive", "cute",
"elegant", "glamorous", "gorgeous", "handsome", "magnificent", "unusual",
"outstanding", "mysterious", "amusing", "charming", "fantastic", "jolly" };
string word = adjectives[points.Count % adjectives.Length];
word = (points.Count > adjectives.Length) ? "very " + word : word;
string a = ((word[0] == 'a') || (word[0] == 'e') || (word[0] == 'o') || (word[0] == 'u')) ? "an " : "a ";
General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " drawing.");
// Make the drawing
if(Tools.DrawLines(points, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd
{
// Snap to map format accuracy
General.Map.Map.SnapAllToAccuracy();
// Clear selection
General.Map.Map.ClearAllSelected();
// Update cached values
General.Map.Map.Update();
//mxd. Outer sectors may require some splittin...
Tools.SplitOuterSectors(General.Map.Map.GetMarkedLinedefs(true));
// Edit new sectors?
List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
General.Interface.ShowEditSectors(newsectors);
// Update the used textures
General.Map.Data.UpdateUsedTextures();
//mxd
General.Map.Renderer2D.UpdateExtraFloorFlag();
// Map is changed
General.Map.IsChanged = true;
}
else
{
// Drawing failed
// NOTE: I have to call this twice, because the first time only cancels this volatile mode
General.Map.UndoRedo.WithdrawUndo();
General.Map.UndoRedo.WithdrawUndo();
}
}
// Done
Cursor.Current = Cursors.Default;
if(continuousdrawing)
{
//mxd. Reset settings
points.Clear();
labels.Clear();
drawingautoclosed = false;
//mxd. Redraw display
General.Interface.RedrawDisplay();
}
else
{
// Return to original mode
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
}
}
// This redraws the display
public override void OnRedrawDisplay()
{
renderer.RedrawSurface();
// Render lines
if(renderer.StartPlotter(true))
{
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
renderer.PlotVerticesSet(General.Map.Map.Vertices);
renderer.Finish();
}
// Render things
if(renderer.StartThings(true))
{
renderer.RenderThingSet(General.Map.Map.Things, General.Settings.ActiveThingsAlpha);
renderer.Finish();
}
// Normal update
Update();
}
// Mouse moving
public override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if(panning) return; //mxd. Skip all this jazz while panning
Update();
}
// 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)) ||
(snaptocardinaldirection != (General.Interface.AltState && General.Interface.ShiftState))) 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)) ||
(snaptocardinaldirection != (General.Interface.AltState && General.Interface.ShiftState))) Update();
}
//mxd
protected void OnContinuousDrawingChanged(object value, EventArgs e)
{
continuousdrawing = (bool)value;
}
//mxd
protected void OnAutoCloseDrawingChanged(object value, EventArgs e)
{
autoclosedrawing = (bool)value;
}
//mxd
private void OnShowGuidelinesChanged(object value, EventArgs e)
{
showguidelines = (bool)value;
General.Interface.RedrawDisplay();
}
#endregion
#region ================== Actions
// Drawing a point
[BeginAction("drawpoint")]
public void DrawPoint()
{
// Mouse inside window?
if(General.Interface.MouseInDisplay)
{
DrawnVertex newpoint = GetCurrentPosition();
if(!DrawPointAt(newpoint)) General.Interface.DisplayStatus(StatusType.Warning, "Failed to draw point: outside of map boundaries.");
}
}
// Remove a point
[BeginAction("removepoint")]
public virtual void RemovePoint()
{
if(points.Count > 0) points.RemoveAt(points.Count - 1);
if(labels.Count > 0)
{
labels[labels.Count - 1].Dispose();
labels.RemoveAt(labels.Count - 1);
}
Update();
}
// Finish drawing
[BeginAction("finishdraw")]
public void FinishDraw()
{
// Accept the changes
General.Editing.AcceptMode();
}
#endregion
}
}