Newer
Older
#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.Linq;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.BuilderModes.Interface;
using CodeImp.DoomBuilder.Data;
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 = "Linedefs Mode",
SwitchAction = "linedefsmode", // Action name used to switch to this mode
ButtonImage = "LinesMode.png", // Image resource name for the button
ButtonOrder = int.MinValue + 100, // Position of the button (lower is more to the left)
ButtonGroup = "000_editing",
UseByDefault = true,
SafeStartMode = true)]
public class LinedefsMode : BaseClassicMode
{
#region ================== Constants
private const int MAX_LINEDEF_LABELS = 256; //mxd
#endregion
#region ================== Variables
// Highlighted item
private Linedef highlighted;
private Vector2D insertpreview = new Vector2D(float.NaN, float.NaN); //mxd
//mxd. Text labels
MaxED
committed
private Dictionary<Linedef, SelectionLabel> labels;
private Dictionary<Sector, TextLabel[]> sectorlabels;
private Dictionary<Sector, string[]> sectortexts;
private bool selectionfromhighlight; //mxd
// The blockmap makes is used to make finding lines faster
BlockMap<BlockEntry> blockmap;
// Stores sizes of the text for text labels so that they only have to be computed once
private Dictionary<string, float> textlabelsizecache;
#endregion
#region ================== Properties
public override object HighlightedObject { get { return highlighted; } }
#endregion
#region ================== Constructor / Disposer
public LinedefsMode()
{
//mxd. Associations now requre initializing...
textlabelsizecache = new Dictionary<string, float>();
}
//mxd
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Dispose old labels
MaxED
committed
if(labels != null) foreach(SelectionLabel l in labels.Values) l.Dispose();
if(sectorlabels != null)
{
foreach(TextLabel[] lbl in sectorlabels.Values)
foreach(TextLabel l in lbl) l.Dispose();
}
// Dispose base
base.Dispose();
}
}
#endregion
#region ================== Methods
// This highlights a new item
MaxED
committed
private void Highlight(Linedef l)
{
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.
if(highlighted != null)
{
//mxd. Update label color?
if(labels.ContainsKey(highlighted))
{
labels[highlighted].Color = General.Colors.Highlight;
completeredraw = true;
}
// Previous association highlights something?
}
// Set highlight association
if(l != null)
{
//mxd. Update label color?
if(labels.ContainsKey(l))
{
labels[l].Color = General.Colors.Selection;
completeredraw = true;
}
// New association highlights something?
// Only need a complete redraw if the association contains elements
if (!highlightasso.IsEmpty) completeredraw = true;
// Only need a complete redraw if the old association wasn't empty
if (!highlightasso.IsEmpty) completeredraw = true;
highlightasso.Clear();
// 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
Linedef possiblecommentline = l ?? highlighted; //mxd
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 with highlight
//mxd. Update comment highlight?
if(General.Map.UDMF && General.Settings.RenderComments
&& possiblecommentline != null && !possiblecommentline.IsDisposed
&& renderer.StartOverlay(false))
{
RenderComment(possiblecommentline);
renderer.Finish();
}
renderer.Present();
}
}
// Show highlight info
if((highlighted != null) && !highlighted.IsDisposed)
MaxED
committed
{
General.Interface.ShowLinedefInfo(highlighted);
MaxED
committed
}
MaxED
committed
{
General.Interface.Display.HideToolTip(); //mxd
General.Interface.HideInfo();
MaxED
committed
}
//mxd
MaxED
committed
private void AlignTextureToLine(bool alignFloors, bool alignToFrontSide)
{
ICollection<Linedef> lines = General.Map.Map.GetSelectedLinedefs(true);
if(lines.Count == 0 && highlighted != null && !highlighted.IsDisposed)
lines.Add(highlighted);
MaxED
committed
if(lines.Count == 0)
{
General.Interface.DisplayStatus(StatusType.Warning, "This action requires a selection!");
return;
}
//Create Undo
string rest = (alignFloors ? "Floors" : "Ceilings") + " to " + (alignToFrontSide ? "Front" : "Back")+ " Side";
General.Map.UndoRedo.CreateUndo("Align " + rest);
int counter = 0;
MaxED
committed
foreach(Linedef l in lines)
{
Sector s = null;
MaxED
committed
if(alignToFrontSide)
{
if(l.Front != null && l.Front.Sector != null) s = l.Front.Sector;
MaxED
committed
}
else
{
if(l.Back != null && l.Back.Sector != null) s = l.Back.Sector;
}
if(s == null) continue;
counter++;
s.Fields.BeforeFieldsChange();
double sourceAngle = Math.Round(General.ClampAngle(alignToFrontSide ? -Angle2D.RadToDeg(l.Angle) + 90 : -Angle2D.RadToDeg(l.Angle) - 90), 1);
if(!alignToFrontSide) sourceAngle = General.ClampAngle(sourceAngle + 180);
//update angle
UniFields.SetFloat(s.Fields, (alignFloors ? "rotationfloor" : "rotationceiling"), sourceAngle, 0.0);
//update offset
Vector2D offset = (alignToFrontSide ? l.Start.Position : l.End.Position).GetRotated(Angle2D.DegToRad(sourceAngle));
ImageData texture = General.Map.Data.GetFlatImage(s.LongFloorTexture);
if((texture == null) || (texture == General.Map.Data.WhiteTexture) ||
MaxED
committed
(texture.Width <= 0) || (texture.Height <= 0) || !texture.IsImageLoaded)
{
//meh...
}
else
{
offset.x %= texture.Width / s.Fields.GetValue((alignFloors ? "xscalefloor" : "xscaleceiling"), 1.0);
offset.y %= texture.Height / s.Fields.GetValue((alignFloors ? "yscalefloor" : "yscaleceiling"), 1.0);
}
UniFields.SetFloat(s.Fields, (alignFloors ? "xpanningfloor" : "xpanningceiling"), Math.Round(-offset.x), 0.0);
UniFields.SetFloat(s.Fields, (alignFloors ? "ypanningfloor" : "ypanningceiling"), Math.Round(offset.y), 0.0);
//update
s.UpdateNeeded = true;
s.UpdateCache();
}
General.Interface.DisplayStatus(StatusType.Info, "Aligned " +counter + " " + rest);
//update
General.Map.Map.Update();
General.Interface.RedrawDisplay();
General.Interface.RefreshInfo();
General.Map.IsChanged = true;
}
//mxd
MaxED
committed
private bool IsInSelectionRect(Linedef l, List<Line2D> selectionOutline)
{
if(BuilderPlug.Me.MarqueSelectTouching)
{
bool selected = selectionrect.Contains((float)l.Start.Position.x, (float)l.Start.Position.y) || selectionrect.Contains((float)l.End.Position.x, (float)l.End.Position.y);
//check intersections with outline
MaxED
committed
if(!selected)
{
foreach(Line2D line in selectionOutline)
{
if(Line2D.GetIntersection(l.Line, line)) return true;
}
}
return selected;
}
return selectionrect.Contains((float)l.Start.Position.x, (float)l.Start.Position.y) && selectionrect.Contains((float)l.End.Position.x, (float)l.End.Position.y);
}
//mxd. Gets map elements inside of selectionoutline and sorts them by distance to targetpoint
private List<Linedef> GetOrderedSelection(Vector2D targetpoint, List<Line2D> selectionoutline)
{
// Gather affected sectors
List<Linedef> result = new List<Linedef>();
foreach(Linedef l in General.Map.Map.Linedefs)
{
if(IsInSelectionRect(l, selectionoutline)) result.Add(l);
}
if(result.Count == 0) return result;
// Sort by distance to targetpoint
result.Sort(delegate(Linedef l1, Linedef l2)
{
if(l1 == l2) return 0;
// Get closest distance from l1 to selectstart
Vector2D pos = l1.Start.Position;
if(curdistance < closest1) closest1 = curdistance;
pos = l1.End.Position;
curdistance = Vector2D.DistanceSq(pos, targetpoint);
if(curdistance < closest1) closest1 = curdistance;
// Get closest distance from l2 to selectstart
pos = l2.Start.Position;
curdistance = Vector2D.DistanceSq(pos, targetpoint);
if(curdistance < closest2) closest2 = curdistance;
pos = l2.End.Position;
curdistance = Vector2D.DistanceSq(pos, targetpoint);
if(curdistance < closest2) closest2 = curdistance;
// Return closer one
return (int)(closest1 - closest2);
});
return result;
}
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
//mxd. This sets up new labels
private void SetupSectorLabels()
{
// Dispose old labels
if(sectorlabels != null)
{
foreach(TextLabel[] larr in sectorlabels.Values)
foreach(TextLabel l in larr) l.Dispose();
}
// Make text labels for sectors
sectorlabels = new Dictionary<Sector, TextLabel[]>();
sectortexts = new Dictionary<Sector, string[]>();
foreach(Sector s in General.Map.Map.Sectors)
{
// Setup labels
if(s.Tag == 0) continue;
// Make tag text
string[] tagdescarr = new string[2];
if(s.Tags.Count > 1)
{
string[] stags = new string[s.Tags.Count];
for(int i = 0; i < s.Tags.Count; i++) stags[i] = s.Tags[i].ToString();
tagdescarr[0] = "Tags " + string.Join(", ", stags);
tagdescarr[1] = "T" + string.Join(",", stags);
}
else
{
tagdescarr[0] = "Tag " + s.Tag;
tagdescarr[1] = "T" + s.Tag;
}
// Add to collection
sectortexts.Add(s, tagdescarr);
TextLabel[] larr = new TextLabel[s.Labels.Count];
for(int i = 0; i < s.Labels.Count; i++)
{
TextLabel l = new TextLabel();
l.TransformCoords = true;
l.Location = s.Labels[i].position;
l.AlignX = TextAlignmentX.Center;
l.AlignY = TextAlignmentY.Middle;
l.Color = General.Colors.InfoLine;
l.BackColor = General.Colors.Background.WithAlpha(128);
larr[i] = l;
}
// Add to collection
sectorlabels.Add(s, larr);
}
}
//mxd. Also update labels for the selected linedefs
public override void UpdateSelectionInfo()
{
base.UpdateSelectionInfo();
if(labels != null)
{
// Dispose old labels
foreach(SelectionLabel l in labels.Values) l.Dispose();
// Don't show lables for selected-from-highlight item
if(selectionfromhighlight)
{
labels.Clear();
return;
}
}
// Make text labels for selected linedefs
ICollection<Linedef> orderedselection = General.Map.Map.GetSelectedLinedefs(true);
MaxED
committed
labels = new Dictionary<Linedef, SelectionLabel>(orderedselection.Count);
// Otherwise significant delays will occure.
// Also we probably won't care about selection ordering when selecting this many anyway
if(orderedselection.Count > MAX_LINEDEF_LABELS) return;
int index = 0;
foreach(Linedef linedef in orderedselection)
{
MaxED
committed
SelectionLabel l = new SelectionLabel();
l.OffsetPosition = true;
l.Color = (linedef == highlighted ? General.Colors.Selection : General.Colors.Highlight);
l.BackColor = General.Colors.Background.WithAlpha(192);
MaxED
committed
l.TextLabel.Text = (++index).ToString();
labels.Add(linedef, l);
}
}
/// <summary>
/// Create a blockmap containing linedefs. This is used to speed up determining the closest line
/// to the mouse cursor
/// </summary>
private void CreateBlockmap()
{
RectangleF area = MapSet.CreateArea(General.Map.Map.Vertices);
blockmap = new BlockMap<BlockEntry>(area);
blockmap.AddLinedefsSet(General.Map.Map.Linedefs);
}
#region ================== Events
public override void OnHelp()
{
General.ShowHelp("e_linedefs.html");
}
// Cancel mode
public override void OnCancel()
{
base.OnCancel();
// Return to this mode
General.Editing.ChangeMode(new LinedefsMode());
}
// Mode engages
public override void OnEngage()
{
base.OnEngage();
renderer.SetPresentation(Presentation.Standard);
// Add toolbar buttons
General.Interface.BeginToolbarUpdate(); //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.CopyProperties);
General.Interface.AddButton(BuilderPlug.Me.MenusForm.PasteProperties);
General.Interface.AddButton(BuilderPlug.Me.MenusForm.PastePropertiesOptions); //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.SeparatorCopyPaste);
General.Interface.AddButton(BuilderPlug.Me.MenusForm.ViewSelectionNumbers); //mxd
BuilderPlug.Me.MenusForm.ViewSelectionEffects.Text = "View Sector Tags"; //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.ViewSelectionEffects); //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.SeparatorSectors1); //mxd
if(General.Map.UDMF) //mxd
{
General.Interface.AddButton(BuilderPlug.Me.MenusForm.MakeGradientBrightness);
General.Interface.AddButton(BuilderPlug.Me.MenusForm.GradientInterpolationMenu);
}
General.Interface.AddButton(BuilderPlug.Me.MenusForm.CurveLinedefs);
General.Interface.AddButton(BuilderPlug.Me.MenusForm.MarqueSelectTouching); //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.SyncronizeThingEditButton); //mxd
if (General.Map.UDMF)
{
General.Interface.AddButton(BuilderPlug.Me.MenusForm.TextureOffsetLock, ToolbarSection.Geometry); //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.TextureOffset3DFloorLock, ToolbarSection.Geometry);
}
//mxd. Update the tooltip
BuilderPlug.Me.MenusForm.SyncronizeThingEditButton.ToolTipText = "Synchronized Things Editing" + Environment.NewLine + BuilderPlug.Me.MenusForm.SyncronizeThingEditLinedefsItem.ToolTipText;
General.Interface.EndToolbarUpdate(); //mxd
// Create the blockmap
CreateBlockmap();
// Convert geometry selection to linedefs selection
General.Map.Map.ConvertSelection(SelectionType.Linedefs);
UpdateSelectionInfo(); //mxd
SetupSectorLabels(); //mxd
}
// Mode disengages
public override void OnDisengage()
{
base.OnDisengage();
// Remove toolbar buttons
General.Interface.BeginToolbarUpdate(); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.CopyProperties);
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.PasteProperties);
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.PastePropertiesOptions); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.SeparatorCopyPaste);
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.ViewSelectionNumbers); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.ViewSelectionEffects); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.SeparatorSectors1); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.MakeGradientBrightness);
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.GradientInterpolationMenu);
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.CurveLinedefs);
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.MarqueSelectTouching); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.SyncronizeThingEditButton); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.TextureOffsetLock); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.TextureOffset3DFloorLock);
General.Interface.EndToolbarUpdate(); //mxd
// Going to EditSelectionMode?
EditSelectionMode mode = General.Editing.NewMode as EditSelectionMode;
if(mode != null)
codeimp
committed
// Not pasting anything?
if(!mode.Pasting)
codeimp
committed
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedLinedefs(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
highlighted.Selected = true;
}
MaxED
committed
// Hide highlight info and tooltip
General.Interface.HideInfo();
MaxED
committed
General.Interface.Display.HideToolTip(); //mxd
}
// This redraws the display
public override void OnRedrawDisplay()
{
renderer.RedrawSurface();
List<Line3D> eventlines = new List<Line3D>(); //mxd
// Render lines
if(renderer.StartPlotter(true))
{
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
if((highlighted != null) && !highlighted.IsDisposed)
{
//BuilderPlug.PlotReverseAssociations(renderer, highlightasso, eventlines);
highlightasso.Plot();
renderer.PlotLinedef(highlighted, General.Colors.Highlight);
}
renderer.PlotVerticesSet(General.Map.Map.Vertices);
renderer.Finish();
}
// Render things
if(renderer.StartThings(true))
{
renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, General.Settings.HiddenThingsAlpha);
renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, General.Settings.ActiveThingsAlpha);
renderer.Finish();
}
// Render selection
if(renderer.StartOverlay(true))
{
if(!selecting) //mxd
MaxED
committed
{
if ((highlighted != null) && !highlighted.IsDisposed) highlightasso.Render(); //mxd
}
else
{
RenderMultiSelection();
}
//mxd. Render vertex insert preview
if(insertpreview.IsFinite())
{
double dist = Math.Min(Vector2D.Distance(mousemappos, insertpreview), BuilderPlug.Me.HighlightRange);
byte alpha = (byte)(255 - (dist / BuilderPlug.Me.HighlightRange) * 128);
float vsize = (renderer.VertexSize + 1.0f) / renderer.Scale;
renderer.RenderRectangleFilled(new RectangleF((float)(insertpreview.x - vsize), (float)(insertpreview.y - vsize), vsize * 2.0f, vsize * 2.0f), General.Colors.InfoLine.WithAlpha(alpha), true);
}
//mxd. Render sector tag labels
if(BuilderPlug.Me.ViewSelectionEffects)
{
List<ITextLabel> torender = new List<ITextLabel>(sectorlabels.Count);
foreach(KeyValuePair<Sector, string[]> group in sectortexts)
{
// Pick which text variant to use
TextLabel[] labelarray = sectorlabels[group.Key];
for(int i = 0; i < group.Key.Labels.Count; i++)
{
TextLabel l = labelarray[i];
// Render only when enough space for the label to see
if (!textlabelsizecache.ContainsKey(group.Value[0]))
textlabelsizecache[group.Value[0]] = General.Interface.MeasureString(group.Value[0], l.Font).Width;
float requiredsize = textlabelsizecache[group.Value[0]] / 2 / renderer.Scale;
if (requiredsize > group.Key.Labels[i].radius)
{
if (!textlabelsizecache.ContainsKey(group.Value[1]))
textlabelsizecache[group.Value[1]] = General.Interface.MeasureString(group.Value[1], l.Font).Width;
requiredsize = textlabelsizecache[group.Value[1]] / 2 / renderer.Scale;
string newtext;
if (requiredsize > group.Key.Labels[i].radius)
newtext = (requiredsize > group.Key.Labels[i].radius * 4 ? string.Empty : "+");
newtext = group.Value[1];
if (l.Text != newtext)
l.Text = newtext;
}
else
{
if (group.Value[0] != l.Text)
l.Text = group.Value[0];
}
if(!string.IsNullOrEmpty(l.Text)) torender.Add(l);
}
}
// Render labels
renderer.RenderText(torender);
}
//mxd. Render selection labels
if(BuilderPlug.Me.ViewSelectionNumbers)
{
List<ITextLabel> torender = new List<ITextLabel>(labels.Count);
MaxED
committed
foreach(KeyValuePair<Linedef, SelectionLabel> group in labels)
{
// Render only when enough space for the label to see
MaxED
committed
group.Value.Move(group.Key.Start.Position, group.Key.End.Position);
float requiredsize = (group.Value.TextSize.Width) / renderer.Scale;
MaxED
committed
if(group.Key.Length > requiredsize)
{
torender.Add(group.Value.TextLabel);
}
}
renderer.RenderText(torender);
}
//mxd. Render comments
if(General.Map.UDMF && General.Settings.RenderComments) foreach(Linedef l in General.Map.Map.Linedefs) RenderComment(l);
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
renderer.Finish();
}
renderer.Present();
}
// Selection
protected override void OnSelectBegin()
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Update display
if(renderer.StartPlotter(false))
{
// Redraw highlight to show selection
renderer.PlotLinedef(highlighted, renderer.DetermineLinedefColor(highlighted));
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
renderer.Finish();
renderer.Present();
}
}
base.OnSelectBegin();
}
// End selection
protected override void OnSelectEnd()
{
// Not stopping from multiselection?
if(!selecting)
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
//mxd. Flip selection
highlighted.Selected = !highlighted.Selected;
UpdateSelectionInfo(); //mxd
//mxd. Full redraw when labels were changed
if(BuilderPlug.Me.ViewSelectionNumbers)
{
General.Interface.RedrawDisplay();
}
else if(renderer.StartPlotter(false))
{
// Render highlighted item
renderer.PlotLinedef(highlighted, General.Colors.Highlight);
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
renderer.Finish();
renderer.Present();
}
MaxED
committed
}
else if(BuilderPlug.Me.AutoClearSelection && General.Map.Map.SelectedLinedefsCount > 0) //mxd
{
MaxED
committed
General.Map.Map.ClearSelectedLinedefs();
UpdateSelectionInfo(); //mxd
MaxED
committed
General.Interface.RedrawDisplay();
}
}
base.OnSelectEnd();
}
// Start editing
protected override void OnEditBegin()
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Edit pressed in this mode
editpressed = true;
// Highlighted item not selected?
if(!highlighted.Selected && (BuilderPlug.Me.AutoClearSelection || (General.Map.Map.SelectedLinedefsCount == 0)))
{
// Make this the only selection
selectionfromhighlight = true; //mxd
General.Map.Map.ClearSelectedLinedefs();
highlighted.Selected = true;
UpdateSelectionInfo(); //mxd
General.Interface.RedrawDisplay();
}
// Update display
if(renderer.StartPlotter(false))
{
// Redraw highlight to show selection
renderer.PlotLinedef(highlighted, renderer.DetermineLinedefColor(highlighted));
renderer.PlotVertex(highlighted.Start, renderer.DetermineVertexColor(highlighted.Start));
renderer.PlotVertex(highlighted.End, renderer.DetermineVertexColor(highlighted.End));
renderer.Finish();
renderer.Present();
}
}
else if(!selecting && BuilderPlug.Me.AutoDrawOnEdit) //mxd. We don't want to draw while multiselecting
{
// Start drawing mode
DrawGeometryMode drawmode = new DrawGeometryMode();
bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, false, renderer, new List<DrawnVertex>());
boris_i
committed
if(drawmode.DrawPointAt(v))
boris_i
committed
General.Editing.ChangeMode(drawmode);
else
General.Interface.DisplayStatus(StatusType.Warning, "Failed to draw point: outside of map boundaries.");
}
base.OnEditBegin();
}
// Done editing
protected override void OnEditEnd()
{
// Edit pressed in this mode?
if(editpressed)
{
// Anything selected?
ICollection<Linedef> selected = General.Map.Map.GetSelectedLinedefs(true);
if(selected.Count > 0)
{
if(General.Interface.IsActiveWindow)
{
// Show line edit dialog
biwa
committed
General.Interface.OnEditFormValuesChanged += linedefEditForm_OnValuesChanged;
DialogResult result = General.Interface.ShowEditLinedefs(selected);
biwa
committed
General.Interface.OnEditFormValuesChanged -= linedefEditForm_OnValuesChanged;
General.Map.Map.Update();
// When a single line was selected, deselect it now
if(selected.Count == 1 && selectionfromhighlight)
MaxED
committed
{
General.Map.Map.ClearSelectedLinedefs();
MaxED
committed
}
else if(result == DialogResult.Cancel) //mxd. Restore selection...
{
foreach(Linedef l in selected) l.Selected = true;
// Update entire display
biwa
committed
SetupSectorLabels();
General.Map.Renderer2D.UpdateExtraFloorFlag(); //mxd
UpdateSelectionInfo(); //mxd
General.Interface.RedrawDisplay();
}
}
}
editpressed = false;
selectionfromhighlight = false; //mxd
biwa
committed
private void linedefEditForm_OnValuesChanged(object sender, EventArgs e)
{
// This does nothing. It prevents automatic OnRedrawDisplay when closing the linedef edit form
// Required to prevent crash from issue #298
}
//mxd
public override void OnUndoEnd()
{
base.OnUndoEnd();
// Recreate the blockmap to not include the potentially un-done lines anymore
CreateBlockmap();
// Select changed map elements
if (BuilderPlug.Me.SelectChangedafterUndoRedo)
{
General.Map.Map.SelectMarkedGeometry(true, true);
General.Map.Map.ConvertSelection(SelectionType.Linedefs);
}
// If something is highlighted make sure to update the association so that it contains valid data
if (highlighted != null && !highlighted.IsDisposed)
highlightasso.Set(highlighted);
MaxED
committed
// Update selection info and labels
UpdateSelectionInfo();
SetupSectorLabels();
}
//mxd
public override void OnRedoEnd()
{
base.OnRedoEnd();
// Recreate the blockmap to include the potentially re-done linedefs again
CreateBlockmap();
// Select changed map elements
if (BuilderPlug.Me.SelectChangedafterUndoRedo)
{
General.Map.Map.SelectMarkedGeometry(true, true);
General.Map.Map.ConvertSelection(SelectionType.Linedefs);
}
// If something is highlighted make sure to update the association so that it contains valid data
if (highlighted != null && !highlighted.IsDisposed)
highlightasso.Set(highlighted);
MaxED
committed
// Update selection info and labels
UpdateSelectionInfo();
SetupSectorLabels();
}
public override void OnScriptRunEnd()
{
base.OnScriptRunEnd();
// The script might have added new geometry
CreateBlockmap();
UpdateSelectionInfo();
SetupSectorLabels();
General.Interface.RedrawDisplay();
}
// Mouse moves
public override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if(panning) return; //mxd. Skip all this jazz while panning
MaxED
committed
if(selectpressed && !editpressed && !selecting)
{
// Check if moved enough pixels for multiselect
Vector2D delta = mousedownpos - mousepos;
if((Math.Abs(delta.x) > BuilderPlug.Me.MouseSelectionThreshold) ||
(Math.Abs(delta.y) > BuilderPlug.Me.MouseSelectionThreshold))
MaxED
committed
{
// Start multiselecting
StartMultiSelection();
}
}
else if(paintselectpressed && !editpressed && !selecting) //mxd. Drag-select
Linedef l = MapSet.NearestLinedefRange(blockmap, mousemappos, BuilderPlug.Me.HighlightRange / renderer.Scale);
MaxED
committed
if(l != null)
{
if(l != highlighted)
{
if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditivePaintSelect)
l.Selected = true;
else if(General.Interface.CtrlState)
l.Selected = false;
else
l.Selected = !l.Selected;
highlighted = l;
UpdateSelectionInfo(); //mxd
// Update entire display
General.Interface.RedrawDisplay();
}
MaxED
committed
}
else if(highlighted != null)
{
Highlight(null);
// Update entire display
General.Interface.RedrawDisplay();
}
}
else if(e.Button == MouseButtons.None) // Not holding any buttons?
{
// Find the nearest linedef within highlight range
Linedef l = MapSet.NearestLinedefRange(blockmap, mousemappos, BuilderPlug.Me.HighlightRange / renderer.Scale);
//mxd. Render insert vertex preview
Linedef sl = MapSet.NearestLinedefRange(blockmap, mousemappos, BuilderPlug.Me.StitchRange / renderer.Scale);
if (sl != null)
MaxED
committed
{
bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
Vector2D v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, false, renderer, new List<DrawnVertex>(), blockmap).pos;
if (v != insertpreview)
MaxED
committed
{
insertpreview = v;
// Render preview. Do not redraw the whole display for performance reasons
if(renderer.StartOverlay(true))
{
double dist = Math.Min(Vector2D.Distance(mousemappos, insertpreview), BuilderPlug.Me.HighlightRange);
byte alpha = (byte)(255 - (dist / BuilderPlug.Me.HighlightRange) * 128);
float vsize = (renderer.VertexSize + 1.0f) / renderer.Scale;
renderer.RenderRectangleFilled(new RectangleF((float)(insertpreview.x - vsize), (float)(insertpreview.y - vsize), vsize * 2.0f, vsize * 2.0f), General.Colors.InfoLine.WithAlpha(alpha), true);
renderer.Finish();
renderer.Present();
}
MaxED
committed
}
else if(insertpreview.IsFinite())