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.Config;
using CodeImp.DoomBuilder.Data;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Types;
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 readonly Association[] association = new Association[Linedef.NUM_ARGS];
private readonly Association highlightasso = new Association();
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
#endregion
#region ================== Properties
public override object HighlightedObject { get { return highlighted; } }
#endregion
#region ================== Constructor / Disposer
public LinedefsMode()
{
//mxd. Associations now requre initializing...
for(int i = 0; i < association.Length; i++) association[i] = new Association();
}
//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?
if(highlighted.Tag != 0) completeredraw = true;
}
// 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?
if(l.Tag != 0)
{
highlightasso.Set(new Vector2D((l.Start.Position + l.End.Position) / 2), l.Tags, UniversalType.LinedefTag);
completeredraw = true;
}
}
{
}
// Use the line tag to highlight sectors (Doom style)
if(General.Map.Config.LineTagIndicatesSectors)
{
if(l != null)
association[0].Set(new Vector2D((l.Start.Position + l.End.Position)/2), l.Tags, UniversalType.SectorTag);
LinedefActionInfo action = null;
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(new Vector2D((l.Start.Position + l.End.Position)/2), l.Args[i], action.Args[i].Type);
// 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
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;
}
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
//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);
}
}
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
#endregion
#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
// 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);
for(int i = 0; i < Linedef.NUM_ARGS; i++) BuilderPlug.PlotAssociations(renderer, association[i], eventlines);
if((highlighted != null) && !highlighted.IsDisposed)
{
BuilderPlug.PlotReverseAssociations(renderer, highlightasso, eventlines);
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
{
for(int i = 0; i < Linedef.NUM_ARGS; i++) BuilderPlug.RenderAssociations(renderer, association[i], eventlines);
if((highlighted != null) && !highlighted.IsDisposed) BuilderPlug.RenderReverseAssociations(renderer, highlightasso, eventlines); //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);
}
renderer.RenderArrows(eventlines); //mxd
//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
float requiredsize = (General.Interface.MeasureString(group.Value[0], l.Font).Width / 2) / renderer.Scale;
if(requiredsize > group.Key.Labels[i].radius)
{
requiredsize = (General.Interface.MeasureString(group.Value[1], l.Font).Width / 2) / renderer.Scale;
if(requiredsize > group.Key.Labels[i].radius)
l.Text = (requiredsize > group.Key.Labels[i].radius * 4 ? string.Empty : "+");
else
l.Text = group.Value[1];
}
else
{
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);
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
728
729
730
731
732
733
734
735
736
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();
MaxED
committed
// Update selection info and labels
UpdateSelectionInfo();
SetupSectorLabels();
}
//mxd
public override void OnRedoEnd()
{
base.OnRedoEnd();
MaxED
committed
// Update selection info and labels
UpdateSelectionInfo();
SetupSectorLabels();
}
// 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
{
// Find the nearest thing within highlight range
Linedef l = General.Map.Map.NearestLinedefRange(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 = General.Map.Map.NearestLinedefRange(mousemappos, BuilderPlug.Me.HighlightRange / renderer.Scale);
//mxd. Render insert vertex preview
Linedef sl = General.Map.Map.NearestLinedefRange(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>()).pos;
if(v != insertpreview)
MaxED
committed
{
insertpreview = v;
General.Interface.RedrawDisplay();
MaxED
committed
}
else if(insertpreview.IsFinite())
MaxED
committed
{
insertpreview.x = float.NaN;
General.Interface.RedrawDisplay();
// Highlight if not the same
if(l != highlighted) Highlight(l);
MaxED
committed
//mxd. Show tooltip?
MaxED
committed
if(General.Map.UDMF && General.Settings.RenderComments && mouselastpos != mousepos && highlighted != null && !highlighted.IsDisposed && highlighted.Fields.ContainsKey("comment"))
MaxED
committed
{
string comment = highlighted.Fields.GetValue("comment", string.Empty);
if(comment.Length > 2)
{
string type = comment.Substring(0, 3);
int index = Array.IndexOf(CommentType.Types, type);
if(index > 0) comment = comment.TrimStart(type.ToCharArray());
}
MaxED
committed
General.Interface.Display.ShowToolTip("Comment:", comment, (int)(mousepos.x + 32 * MainForm.DPIScaler.Width), (int)(mousepos.y + 8 * MainForm.DPIScaler.Height));
}
}
// Mouse leaves
public override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
// Highlight nothing
Highlight(null);
}
MaxED
committed
protected override void BeginViewPan()
{
// We don't want vertex preview while panning
insertpreview.x = float.NaN;
base.BeginViewPan();
}
MaxED
committed
protected override void OnPaintSelectBegin()
{
// Highlight nothing
Highlight(null);