From f204a172986982647e0b354592362ce48f896315 Mon Sep 17 00:00:00 2001 From: biwa <6475593+biwa@users.noreply.github.com> Date: Thu, 16 Jul 2020 22:01:37 +0200 Subject: [PATCH] Improved associations (#440) Improved associations and event lines. Refactorings to make the whole thing more sensible (hopefully). Options to display labels on event lines (can be configured in Preferences -> Editing). --- Source/Plugins/3DFloorMode/ThreeDFloorMode.cs | 8 +- .../BuilderModes/ClassicModes/LinedefsMode.cs | 71 +- .../BuilderModes/ClassicModes/SectorsMode.cs | 17 +- .../BuilderModes/ClassicModes/ThingsMode.cs | 58 +- .../BuilderModes/General/Association.cs | 755 ++++++++++++++++-- .../BuilderModes/General/BuilderPlug.cs | 183 +---- .../Interface/PreferencesForm.Designer.cs | 113 ++- .../BuilderModes/Interface/PreferencesForm.cs | 4 + 8 files changed, 834 insertions(+), 375 deletions(-) diff --git a/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs b/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs index e8f99fcf..cf7cd4ad 100644 --- a/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs +++ b/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs @@ -70,7 +70,7 @@ namespace CodeImp.DoomBuilder.ThreeDFloorMode // Highlighted item protected Sector highlighted; protected ThreeDFloor highlighted3dfloor; - private Association highlightasso = new Association(); + private Association highlightasso; private FlatVertex[] overlayGeometry; private FlatVertex[] overlaygeometry3dfloors; private FlatVertex[] overlaygeometry3dfloors_highlighted; @@ -110,6 +110,7 @@ namespace CodeImp.DoomBuilder.ThreeDFloorMode public ThreeDFloorHelperMode() { threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + highlightasso = new Association(renderer); withdrawduplicateundo = false; @@ -123,7 +124,6 @@ namespace CodeImp.DoomBuilder.ThreeDFloorMode { withdrawduplicateundo = true; } - } // Disposer @@ -437,10 +437,10 @@ namespace CodeImp.DoomBuilder.ThreeDFloorMode if (s != null) { Vector2D center = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); - highlightasso.Set(center, s.Tag, UniversalType.SectorTag); + highlightasso.Set(s); } else - highlightasso.Set(new Vector2D(), 0, 0); + highlightasso.Clear(); // New association highlights something? if((s != null) && (s.Tag > 0)) completeredraw = true; diff --git a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs index 44b8a5b5..2737b604 100755 --- a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs @@ -56,8 +56,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Highlighted item private Linedef highlighted; - private readonly Association[] association = new Association[Linedef.NUM_ARGS]; - private readonly Association highlightasso = new Association(); + private readonly Association highlightasso; private Vector2D insertpreview = new Vector2D(float.NaN, float.NaN); //mxd //mxd. Text labels @@ -82,7 +81,7 @@ namespace CodeImp.DoomBuilder.BuilderModes public LinedefsMode() { //mxd. Associations now requre initializing... - for(int i = 0; i < association.Length; i++) association[i] = new Association(); + highlightasso = new Association(renderer); } //mxd @@ -125,9 +124,9 @@ namespace CodeImp.DoomBuilder.BuilderModes labels[highlighted].Color = General.Colors.Highlight; completeredraw = true; } - + // Previous association highlights something? - if(highlighted.Tag != 0) completeredraw = true; + if (!highlightasso.IsEmpty) completeredraw = true; } // Set highlight association @@ -141,57 +140,18 @@ namespace CodeImp.DoomBuilder.BuilderModes } // 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; - } + highlightasso.Set(l); + + // Only need a complete redraw if the association contains elements + if (!highlightasso.IsEmpty) completeredraw = true; } else { - highlightasso.Set(new Vector2D(), 0, 0); + // Only need a complete redraw if the old association wasn't empty + if (!highlightasso.IsEmpty) completeredraw = true; + highlightasso.Clear(); } - // 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); - else - association[0].Set(new Vector2D(), 0, 0); - } - else - { - 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); - else - association[i].Set(new Vector2D(), 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) @@ -599,11 +559,11 @@ namespace CodeImp.DoomBuilder.BuilderModes 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); + //BuilderPlug.PlotReverseAssociations(renderer, highlightasso, eventlines); + highlightasso.Plot(); renderer.PlotLinedef(highlighted, General.Colors.Highlight); } renderer.PlotVerticesSet(General.Map.Map.Vertices); @@ -623,8 +583,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(!selecting) //mxd { - 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 + if ((highlighted != null) && !highlighted.IsDisposed) highlightasso.Render(); //mxd } else { @@ -640,8 +599,6 @@ namespace CodeImp.DoomBuilder.BuilderModes 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) { diff --git a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs index 2d6f93ac..884bba27 100755 --- a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs @@ -54,7 +54,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Highlighted item private Sector highlighted; - private readonly Association highlightasso = new Association(); + private readonly Association highlightasso; // Interface new private bool editpressed; @@ -87,6 +87,8 @@ namespace CodeImp.DoomBuilder.BuilderModes // Constructor public SectorsMode() { + highlightasso = new Association(renderer); + //mxd effects = new Dictionary(); foreach(SectorEffectInfo info in General.Map.Config.SortedSectorEffects) @@ -413,12 +415,11 @@ namespace CodeImp.DoomBuilder.BuilderModes // Set highlight association if(s != null && s.Tag != 0) { - Vector2D center = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); - highlightasso.Set(center, s.Tags, UniversalType.SectorTag); + highlightasso.Set(s); } else { - highlightasso.Set(new Vector2D(), 0, 0); + highlightasso.Clear(); } // New association highlights something? @@ -843,7 +844,7 @@ namespace CodeImp.DoomBuilder.BuilderModes if((highlighted != null) && !highlighted.IsDisposed) { renderer.PlotSector(highlighted, General.Colors.Highlight); - BuilderPlug.PlotReverseAssociations(renderer, highlightasso, eventlines); + highlightasso.Plot(); } renderer.Finish(); } @@ -862,9 +863,9 @@ namespace CodeImp.DoomBuilder.BuilderModes // Render selection if(renderer.StartOverlay(false)) { - if(highlighted != null && !highlighted.IsDisposed) BuilderPlug.RenderReverseAssociations(renderer, highlightasso, eventlines); //mxd - if(selecting) RenderMultiSelection(); - renderer.RenderArrows(eventlines); //mxd + if (highlighted != null && !highlighted.IsDisposed) highlightasso.Render(); + if (selecting) RenderMultiSelection(); + renderer.Finish(); } diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs index 8735d38f..dba140bc 100755 --- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs @@ -56,9 +56,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Highlighted item private Thing highlighted; - private readonly Association[] association = new Association[Thing.NUM_ARGS]; - private readonly Association directasso = new Association(); - private readonly Association highlightasso = new Association(); + private readonly Association highlightasso; // Interface new private bool editpressed; @@ -89,8 +87,7 @@ namespace CodeImp.DoomBuilder.BuilderModes public ThingsMode() { //mxd. Associations now requre initializing... - for(int i = 0; i < association.Length; i++) association[i] = new Association(); - directasso = new Association(); + highlightasso = new Association(renderer); } //mxd @@ -234,8 +231,7 @@ namespace CodeImp.DoomBuilder.BuilderModes renderer.PlotLinedefSet(General.Map.Map.Linedefs); renderer.PlotVerticesSet(General.Map.Map.Vertices); - for(int i = 0; i < Thing.NUM_ARGS; i++) BuilderPlug.PlotAssociations(renderer, association[i], eventlines); - if(highlighted != null && !highlighted.IsDisposed) BuilderPlug.PlotReverseAssociations(renderer, highlightasso, eventlines); + if (highlighted != null && !highlighted.IsDisposed) highlightasso.Plot(); renderer.Finish(); } @@ -246,13 +242,11 @@ namespace CodeImp.DoomBuilder.BuilderModes float alpha = (General.Settings.FixedThingsScale ? Presentation.THINGS_ALPHA : General.Settings.ActiveThingsAlpha); //mxd renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, General.Settings.HiddenThingsAlpha); renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, alpha); - for(int i = 0; i < Thing.NUM_ARGS; i++) BuilderPlug.RenderAssociations(renderer, association[i], eventlines); - BuilderPlug.RenderAssociations(renderer, directasso, eventlines); if(highlighted != null && !highlighted.IsDisposed) { renderer.RenderThing(highlighted, General.Colors.Highlight, alpha); - BuilderPlug.RenderReverseAssociations(renderer, highlightasso, eventlines); //mxd + highlightasso.Render(); } //mxd. Event lines @@ -364,11 +358,11 @@ namespace CodeImp.DoomBuilder.BuilderModes linktype = ti.ThingLink; // New association highlights something? - if(t.Tag != 0) highlightasso.Set(t.Position, t.Tag, UniversalType.ThingTag, linktype); + highlightasso.Set(t); } else { - highlightasso.Set(new Vector2D(), 0, 0); + highlightasso.Clear(); } if(highlighted != null) //mxd @@ -379,46 +373,6 @@ namespace CodeImp.DoomBuilder.BuilderModes highlighted.Highlighted = false; } - //mxd. Determine thing associations - bool clearassociations = true; //mxd - if(t != null) - { - t.Highlighted = true; //mxd - - // Check if we can find the linedefs action - if((t.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(t.Action)) - { - clearassociations = false; - LinedefActionInfo action = General.Map.Config.LinedefActions[t.Action]; - for(int i = 0; i < Thing.NUM_ARGS; i++) - association[i].Set(t.Position, t.Args[i], action.Args[i].Type); - - //Some things, such as Patrol and Interpolation specials, are associated via a shared tag rather than an argument - ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); - if (ti != null && ti.ThingLink < 0) - directasso.Set(t.Position, t.Tag, (int)UniversalType.ThingTag); - } - //mxd. Check if we can use thing arguments - else if(t.Action == 0) - { - ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); - if(ti != null) - { - clearassociations = false; - for(int i = 0; i < Thing.NUM_ARGS; i++) - association[i].Set(t.Position, t.Args[i], ti.Args[i].Type); - } - } - } - - // mxd. Clear associations? - if(clearassociations) - { - for (int i = 0; i < Thing.NUM_ARGS; i++) - association[i].Set(new Vector2D(), 0, 0); - directasso.Set(new Vector2D(), 0, 0); - } - // Set new highlight and redraw display highlighted = t; General.Interface.RedrawDisplay(); diff --git a/Source/Plugins/BuilderModes/General/Association.cs b/Source/Plugins/BuilderModes/General/Association.cs index 7b6e4809..432e034f 100755 --- a/Source/Plugins/BuilderModes/General/Association.cs +++ b/Source/Plugins/BuilderModes/General/Association.cs @@ -16,9 +16,16 @@ #region ================== Namespaces +using System; using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Windows; #endregion @@ -30,97 +37,747 @@ namespace CodeImp.DoomBuilder.BuilderModes private Vector2D center; private UniversalType type; private int directlinktype; + private Dictionary> eventlines; + private IRenderer2D renderer; + private SelectableElement element; + private List distinctcolors; + private Font font; + private Dictionary textwidths; + private Dictionary> textlabels; + + // Map elements that are associated + private List things; + private List sectors; + private List linedefs; public HashSet Tags { get { return tags; } } public Vector2D Center { get { return center; } } public UniversalType Type { get { return type; } } public int DirectLinkType { get { return directlinktype; } } + public List Things { get { return things; } } + public List Sectors { get { return sectors; } } + public List Linedefs { get { return linedefs; } } + public bool IsEmpty { get { return things.Count == 0 && sectors.Count == 0 && linedefs.Count == 0; } } //mxd. This sets up the association - public Association() + public Association(IRenderer2D renderer) { this.tags = new HashSet { 0 }; + this.renderer = renderer; + + things = new List(); + sectors = new List(); + linedefs = new List(); + eventlines = new Dictionary>(); + + font = new Font(new FontFamily(General.Settings.TextLabelFontName), General.Settings.TextLabelFontSize, (General.Settings.TextLabelFontBold ? FontStyle.Bold : FontStyle.Regular)); + + distinctcolors = new List + { + General.Colors.InfoLine, + PixelColor.FromInt(0x84d5a4).WithAlpha(255), + PixelColor.FromInt(0xc059cb).WithAlpha(255), + PixelColor.FromInt(0xd0533d).WithAlpha(255), + // PixelColor.FromInt(0x415354).WithAlpha(255), // too dark + PixelColor.FromInt(0xcea953).WithAlpha(255), + PixelColor.FromInt(0x91d44b).WithAlpha(255), + PixelColor.FromInt(0xcd5b89).WithAlpha(255), + PixelColor.FromInt(0xa8b6c0).WithAlpha(255), + PixelColor.FromInt(0x797ecb).WithAlpha(255), + // PixelColor.FromInt(0x567539).WithAlpha(255), // too dark + // PixelColor.FromInt(0x72422f).WithAlpha(255), // too dark + // PixelColor.FromInt(0x5d3762).WithAlpha(255), // too dark + PixelColor.FromInt(0xffed6f).WithAlpha(255), + PixelColor.FromInt(0xccebc5).WithAlpha(255), + PixelColor.FromInt(0xbc80bd).WithAlpha(255), + // PixelColor.FromInt(0xd9d9d9).WithAlpha(255), // too gray + PixelColor.FromInt(0xfccde5).WithAlpha(255), + PixelColor.FromInt(0x80b1d3).WithAlpha(255), + PixelColor.FromInt(0xfdb462).WithAlpha(255), + PixelColor.FromInt(0xb3de69).WithAlpha(255), + PixelColor.FromInt(0xfb8072).WithAlpha(255), + PixelColor.FromInt(0xbebada).WithAlpha(255), // too blue/gray? + PixelColor.FromInt(0xffffb3).WithAlpha(255), + PixelColor.FromInt(0x8dd3c7).WithAlpha(255), + }; } - // This sets up the association - public Association(Vector2D center, int tag, int type) + /// + /// Sets the association to a map element. Only works with an instance of Thing, Sector, or Linedef. + /// Also gets the forward and reverse associations + /// + /// An instance of Thing, Sector, or Linedef + public void Set(SelectableElement element) { - this.tags = new HashSet { tag }; //mxd - this.type = (UniversalType)type; - this.center = center; + this.element = element; + things = new List(); + sectors = new List(); + linedefs = new List(); + eventlines = new Dictionary>(); + + if (element is Sector) + { + Sector s = element as Sector; + center = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); + + type = UniversalType.SectorTag; + tags = new HashSet(s.Tags); + } + else if(element is Linedef) + { + Linedef ld = element as Linedef; + center = ld.GetCenterPoint(); + + type = UniversalType.LinedefTag; + tags = new HashSet(ld.Tags); + } + else if(element is Thing) + { + Thing t = element as Thing; + center = t.Position; + + ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); + directlinktype = ti.ThingLink; + + type = UniversalType.ThingTag; + tags = new HashSet(new int[] { t.Tag }); + } + + // Remove the tag 0, because nothing sensible will come from it + tags.Remove(0); + + // Get forward and reverse associations + GetAssociations(); + + // Cache width of label text and generate the labels + textwidths = new Dictionary(eventlines.Count); + textlabels = new Dictionary>(eventlines.Count); + + foreach(KeyValuePair> kvp in eventlines) + { + SizeF size = General.Interface.MeasureString(kvp.Key, font); + textwidths[kvp.Key] = new Vector2D(size.Width, size.Height); + + // Create one label for each line. We might not need them all, but better + // to have them all at the beginning than to generate them later + textlabels[kvp.Key] = new List(kvp.Value.Count); + + for (int i = 0; i < kvp.Value.Count; i++) + { + // We don't need to set the position here, since it'll be done on the fly later + TextLabel l = new TextLabel(); + l.AlignX = TextAlignmentX.Center; + l.AlignY = TextAlignmentY.Middle; + l.TransformCoords = true; + l.Text = kvp.Key; + + textlabels[kvp.Key].Add(l); + } + + textwidths[kvp.Key] = new Vector2D(textlabels[kvp.Key][0].TextSize.Width, textlabels[kvp.Key][0].TextSize.Height); + } + + SetEventLineColors(); } - // This sets up the association - public Association(Vector2D center, int tag, UniversalType type) + /// + /// Clears out all lists so that the association appears empty + /// + public void Clear() { - this.tags = new HashSet { tag }; //mxd - this.type = type; - this.center = center; + tags = new HashSet(); + things = new List(); + sectors = new List(); + linedefs = new List(); + eventlines = new Dictionary>(); } - //mxd. This also sets up the association - public Association(Vector2D center, IEnumerable tags, int type) + /// + /// Get the forward and reverse associations between the element and other map elements + /// + private void GetAssociations() { - this.tags = new HashSet(tags); //mxd - this.type = (UniversalType)type; - this.center = center; + Dictionary> actiontags = new Dictionary>(); + bool showforwardlabel = BuilderPlug.Me.EventLineLabelVisibility == 1 || BuilderPlug.Me.EventLineLabelVisibility == 3; + bool showreverselabel = BuilderPlug.Me.EventLineLabelVisibility == 2 || BuilderPlug.Me.EventLineLabelVisibility == 3; + + // Special handling for Doom format maps where there the linedef's tag references sectors + if (General.Map.Config.LineTagIndicatesSectors) + { + if (tags.Count == 0) + return; + + // Forward association from linedef to sector + if (element is Linedef) + { + foreach (Sector s in General.Map.Map.Sectors) + { + if (tags.Contains(s.Tag)) + { + Vector2D sectorcenter = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); + + sectors.Add(s); + + AddLineToAction(showforwardlabel ? GetActionDescription(element) : string.Empty, center, sectorcenter); + } + } + } + else if(element is Sector) + { + foreach(Linedef ld in General.Map.Map.Linedefs) + { + if(tags.Contains(ld.Tag)) + { + linedefs.Add(ld); + + AddLineToAction(showreverselabel ? GetActionDescription(ld) : string.Empty, ld.GetCenterPoint(), center); + } + } + } + + return; + } + + // Get tags of map elements the element is referencing. This is used for the forward associations + if (element is Linedef || element is Thing) + actiontags = GetTagsByType(); + + // Store presence of different types once, so that we don't have to do a lookup for each map element + bool hassectortags = actiontags.ContainsKey((int)UniversalType.SectorTag); + bool haslinedeftags = actiontags.ContainsKey((int)UniversalType.LinedefTag); + bool hasthingtag = actiontags.ContainsKey((int)UniversalType.ThingTag); + + // Process all sectors in the map + foreach (Sector s in General.Map.Map.Sectors) + { + bool addforward = false; + bool addreverse = false; + + // Check for forward association (from the element to the sector) + if (hassectortags && actiontags[(int)UniversalType.SectorTag].Overlaps(s.Tags)) + addforward = true; + + // Check the reverse association (from the sector to the element) + // Nothing here yet + + if (addforward || addreverse) + { + Vector2D sectorcenter = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); + + sectors.Add(s); + + if (addforward) + AddLineToAction(showforwardlabel ? GetActionDescription(element) : string.Empty, center, sectorcenter); + + if (addreverse) + AddLineToAction(showreverselabel ? GetActionDescription(element) : string.Empty, sectorcenter, center); + } + } + + // Process all linedefs in the map + foreach(Linedef ld in General.Map.Map.Linedefs) + { + bool addforward = false; + bool addreverse = false; + + // Check the forward association (from the element to the linedef) + if (haslinedeftags && actiontags[(int)UniversalType.LinedefTag].Overlaps(ld.Tags)) + addforward = true; + + // Check the reverse association (from the linedef to the element) + if (IsAssociatedToLinedef(ld)) + addreverse = true; + + if (addforward || addreverse) + { + linedefs.Add(ld); + + if (addforward) + AddLineToAction(showforwardlabel ? GetActionDescription(element) : string.Empty, center, ld.GetCenterPoint()); + + if (addreverse) + AddLineToAction(showreverselabel ? GetActionDescription(ld) : string.Empty, ld.GetCenterPoint(), center); + } + } + + // Doom format only knows associations between linedefs and sectors, but not thing, so stop here + if (General.Map.DOOM) + return; + + // Process all things in the map + foreach(Thing t in General.Map.Map.Things) + { + bool addforward = false; + bool addreverse = false; + + // Check the forward association (from the element to the thing) + if (hasthingtag && actiontags[(int)UniversalType.ThingTag].Contains(t.Tag)) + addforward = true; + + // Check the reverse association (from the thing to the element). Only works for Hexen and UDMF, + // as Doom format doesn't have any way to reference other map elements + if (IsAssociatedToThing(t)) + addreverse = true; + + if (addforward || addreverse) + { + things.Add(t); + + if (addforward) + AddLineToAction(showforwardlabel ? GetActionDescription(element) : string.Empty, center, t.Position); + + if (addreverse) + AddLineToAction(showreverselabel ? GetActionDescription(t) : string.Empty, t.Position, center); + } + } } - //mxd. This also sets up the association - public Association(Vector2D center, IEnumerable tags, UniversalType type) + /// + /// Gets a dictionary of sector tags, linedef tags, and thing tags, grouped by their type, that the map element is referencing + /// + /// Dictionary of sector tags, linedef tags, and thing tags that the map element is referencing + private Dictionary> GetTagsByType() { - this.tags = new HashSet(tags); //mxd - this.type = type; - this.center = center; + LinedefActionInfo action = null; + int[] actionargs = new int[5]; + Dictionary> actiontags = new Dictionary>(); + + // Get the action and its arguments from a linedef or a thing, if they have them + if (element is Linedef) + { + Linedef ld = element as Linedef; + + if (ld.Action > 0 && General.Map.Config.LinedefActions.ContainsKey(ld.Action)) + action = General.Map.Config.LinedefActions[ld.Action]; + + actionargs = ld.Args; + } + else if (element is Thing) + { + Thing t = element as Thing; + + if (t.Action > 0 && General.Map.Config.LinedefActions.ContainsKey(t.Action)) + action = General.Map.Config.LinedefActions[t.Action]; + + actionargs = t.Args; + } + else // element is a Sector + { + return actiontags; + } + + if (action != null) + { + // Collect what map element the action arguments are referencing. Ignore the argument if it's 0, so that they + // are not associated to everything untagged + for (int i = 0; i < Linedef.NUM_ARGS; i++) + { + if ((action.Args[i].Type == (int)UniversalType.SectorTag || + action.Args[i].Type == (int)UniversalType.LinedefTag || + action.Args[i].Type == (int)UniversalType.ThingTag) && + actionargs[i] > 0) + { + if (!actiontags.ContainsKey(action.Args[i].Type)) + actiontags[action.Args[i].Type] = new HashSet(); + + actiontags[action.Args[i].Type].Add(actionargs[i]); + } + } + } + else if (element is Thing && directlinktype >= 0 && Math.Abs(directlinktype) != ((Thing)element).Type) + { + // The direct link shenanigans if the thing doesn't have an action, but still reference something through + // the action parameters + Thing t = element as Thing; + ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); + + if (ti != null && directlinktype >= 0 && Math.Abs(directlinktype) != t.Type) + { + for (int i = 0; i < Linedef.NUM_ARGS; i++) + { + if ((ti.Args[i].Type == (int)UniversalType.SectorTag || + ti.Args[i].Type == (int)UniversalType.LinedefTag || + ti.Args[i].Type == (int)UniversalType.ThingTag)) + { + if (!actiontags.ContainsKey(ti.Args[i].Type)) + actiontags[ti.Args[i].Type] = new HashSet(); + + actiontags[ti.Args[i].Type].Add(actionargs[i]); + } + + } + } + } + + return actiontags; } - // This sets up the association - public void Set(Vector2D center, int tag, int type) + /// + /// Checks if there's an association between the element and a Linedef + /// + /// Linedef to check the association against + /// true if the Linedef and the element are associated, false if not + private bool IsAssociatedToLinedef(Linedef linedef) { - this.Set(center, tag, type, 0); + // Doom style reference from linedef to sector? + if (General.Map.Config.LineTagIndicatesSectors && element is Sector) + { + if (linedef.Action > 0 && tags.Overlaps(linedef.Tags)) + return true; + } + + // Known action on this line? + if ((linedef.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(linedef.Action)) + { + LinedefActionInfo action = General.Map.Config.LinedefActions[linedef.Action]; + if (((action.Args[0].Type == (int)type) && (linedef.Args[0] != 0) && (tags.Contains(linedef.Args[0]))) || + ((action.Args[1].Type == (int)type) && (linedef.Args[1] != 0) && (tags.Contains(linedef.Args[1]))) || + ((action.Args[2].Type == (int)type) && (linedef.Args[2] != 0) && (tags.Contains(linedef.Args[2]))) || + ((action.Args[3].Type == (int)type) && (linedef.Args[3] != 0) && (tags.Contains(linedef.Args[3]))) || + ((action.Args[4].Type == (int)type) && (linedef.Args[4] != 0) && (tags.Contains(linedef.Args[4])))) + { + return true; + } + } + + return false; } - public void Set(Vector2D center, int tag, int type, int directlinktype) + /// + /// Checks if there's an association between the element and a Thing + /// + /// Thing to check the association against + /// true if the Thing and the element are associated, false if not + private bool IsAssociatedToThing(Thing thing) { - this.tags = new HashSet { tag }; //mxd - this.type = (UniversalType)type; - this.center = center; - this.directlinktype = directlinktype; + // Get the thing type info + ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(thing.Type); + + // Known action on this thing? + if ((thing.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(thing.Action)) + { + //Do not draw the association if this is a child link. + // This prevents a reverse link to a thing via an argument, when it should be a direct tag-to-tag link instead. + if (ti != null && directlinktype < 0 && directlinktype != -thing.Type) + return false; + + LinedefActionInfo action = General.Map.Config.LinedefActions[thing.Action]; + if (((action.Args[0].Type == (int)type) && (tags.Contains(thing.Args[0]))) || + ((action.Args[1].Type == (int)type) && (tags.Contains(thing.Args[1]))) || + ((action.Args[2].Type == (int)type) && (tags.Contains(thing.Args[2]))) || + ((action.Args[3].Type == (int)type) && (tags.Contains(thing.Args[3]))) || + ((action.Args[4].Type == (int)type) && (tags.Contains(thing.Args[4])))) + { + return true; + } + + //If there is a link setup on this thing, and it matches the association, then draw a direct link to any matching tag + if (ti != null && directlinktype == thing.Type && tags.Contains(thing.Tag)) + { + return true; + } + } + //mxd. Thing action on this thing? + else if (thing.Action == 0) + { + // Gets the association, unless it is a child link. + // This prevents a reverse link to a thing via an argument, when it should be a direct tag-to-tag link instead. + if (ti != null && directlinktype >= 0 && Math.Abs(directlinktype) != thing.Type) + { + if (((ti.Args[0].Type == (int)type) && (tags.Contains(thing.Args[0]))) || + ((ti.Args[1].Type == (int)type) && (tags.Contains(thing.Args[1]))) || + ((ti.Args[2].Type == (int)type) && (tags.Contains(thing.Args[2]))) || + ((ti.Args[3].Type == (int)type) && (tags.Contains(thing.Args[3]))) || + ((ti.Args[4].Type == (int)type) && (tags.Contains(thing.Args[4])))) + { + return true; + } + } + } + + return false; } - // This sets up the association - public void Set(Vector2D center, int tag, UniversalType type) + /// + /// Returns a string that contains the description of the action and its arguments, based on the given Linedef or Thing + /// + /// An instance of Thing or Linedef + /// String that contains the description of the action and its arguments for a given Linedef or Thing + private string GetActionDescription(SelectableElement se) { - this.Set(center, tag, type, 0); + int action = 0; + int[] actionargs = new int[5]; + + if (se is Thing) + { + action = ((Thing)se).Action; + actionargs = ((Thing)se).Args; + } + else if(se is Linedef) + { + action = ((Linedef)se).Action; + actionargs = ((Linedef)se).Args; + } + + if (action > 0) + { + LinedefActionInfo lai = General.Map.Config.GetLinedefActionInfo(action); + List argdescription = new List(); + + string description = lai.Index + ": " + lai.Title; + + // Label style: only action, or if the element can't have any parameters + if (BuilderPlug.Me.EventLineLabelStyle == 0 || General.Map.Config.LineTagIndicatesSectors) + return description; + + for (int i=0; i < 5; i++) + { + if(lai.Args[i].Used) + { + string argstring = ""; + + if(BuilderPlug.Me.EventLineLabelStyle == 2) // Label style: full arguments + argstring = lai.Args[i].Title + ": "; + + EnumItem ei = lai.Args[i].Enum.GetByEnumIndex(actionargs[i].ToString()); + + if (ei != null && BuilderPlug.Me.EventLineLabelStyle == 2) // Label style: full arguments + argstring += ei.ToString(); + else // Argument has no EnumItem or label style: short arguments + argstring += actionargs[i].ToString(); + + argdescription.Add(argstring); + } + } + + description += " (" + string.Join(", ", argdescription) + ")"; + + return description; + } + + return null; } - public void Set(Vector2D center, int tag, UniversalType type, int directlinktype) + /// + /// Sets a different color for each event + /// + private void SetEventLineColors() { - this.tags = new HashSet { tag }; //mxd - this.type = type; - this.center = center; - this.directlinktype = directlinktype; + int colorindex = 0; + + foreach(KeyValuePair> kvp in textlabels) + { + foreach (Line3D l in eventlines[kvp.Key]) + l.Color = distinctcolors[colorindex]; + + foreach (TextLabel l in kvp.Value) + l.Color = distinctcolors[colorindex]; + + if(BuilderPlug.Me.EventLineDistinctColors) + if (++colorindex >= distinctcolors.Count) + colorindex = 0; + } } - //mxd. This also sets up the association - public void Set(Vector2D center, IEnumerable tags, int type) + /// + /// Adds a line to an action + /// + /// Name of the action + /// Start of the line + /// End of the line + private void AddLineToAction(string action, Vector2D start, Vector2D end) { - this.Set(center, tags, (UniversalType)type, 0); + if (action == null) + return; + + if (!eventlines.ContainsKey(action)) + eventlines[action] = new List(); + + eventlines[action].Add(new Line3D(start, end, true)); } - //mxd. This also sets up the association - public void Set(Vector2D center, IEnumerable tags, UniversalType type) + /// + /// Generates a label position given a start and end point of a line. Taken (with modifications) from LineLengthLabel.Move() + /// + /// Start of the line + /// End of the line + /// + private Vector2D GetLabelPosition(Vector2D start, Vector2D end) { - this.Set(center, tags, type, 0); + // Check if start/end point is on screen... + Vector2D lt = General.Map.Renderer2D.DisplayToMap(new Vector2D(0.0, General.Interface.Display.Size.Height)); + Vector2D rb = General.Map.Renderer2D.DisplayToMap(new Vector2D(General.Interface.Display.Size.Width, 0.0)); + RectangleF viewport = new RectangleF((float)lt.x, (float)lt.y, (float)(rb.x - lt.x), (float)(rb.y - lt.y)); + bool startvisible = viewport.Contains((float)start.x, (float)start.y); + bool endvisible = viewport.Contains((float)end.x, (float)end.y); + + // Do this only when one point is visible, an the other isn't + if ((!startvisible && endvisible) || (startvisible && !endvisible)) + { + Line2D drawnline = new Line2D(start, end); + Line2D[] viewportsides = new[] { + new Line2D(lt, rb.x, lt.y), // top + new Line2D(lt.x, rb.y, rb.x, rb.y), // bottom + new Line2D(lt, lt.x, rb.y), // left + new Line2D(rb.x, lt.y, rb.x, rb.y), // right + }; + + foreach (Line2D side in viewportsides) + { + // Modify the start point so it stays on screen + double u; + if (!startvisible && side.GetIntersection(drawnline, out u)) + { + start = drawnline.GetCoordinatesAt(u); + break; + } + + // Modify the end point so it stays on screen + if (!endvisible && side.GetIntersection(drawnline, out u)) + { + end = drawnline.GetCoordinatesAt(u); + break; + } + } + } + + // Create position + Vector2D delta = end - start; + return new Vector2D(start.x + delta.x * 0.5, start.y + delta.y * 0.5); } - //mxd. This also sets up the association - public void Set(Vector2D center, IEnumerable tags, UniversalType type, int directlinktype) + /// + /// Merges label positions based on a merge distance + /// + /// Positions to merge + /// Distance to merge positions at + /// List of new positions + List MergePositions(List positions, Vector2D distance) { - this.tags = new HashSet(tags); //mxd - this.type = type; - this.center = center; - this.directlinktype = directlinktype; + List allpositions = positions.OrderBy(o => o.x).ToList(); + List newpositions = new List(positions.Count); + Vector2D mergedistance = distance / renderer.Scale * 1.5; + + // Keep going while we have positions me might want to merge + while (allpositions.Count > 0) + { + Vector2D curposition = allpositions[0]; + allpositions.RemoveAt(0); + + bool hasclosepositions = true; + + // Keep merging as long as there are close positions nearby + while(hasclosepositions) + { + // Get all positions that are close to the current position + List closepositions = allpositions.Where(o => Math.Abs(curposition.x - o.x) < mergedistance.x && Math.Abs(curposition.y - o.y) < mergedistance.y).ToList(); + + if (closepositions.Count > 0) + { + Vector2D tl = curposition; + Vector2D br = curposition; + + // Get the max dimensions of the positions... + foreach (Vector2D v in closepositions) + { + if (v.x < tl.x) tl.x = v.x; + if (v.x > br.x) br.x = v.x; + if (v.y > tl.y) tl.y = v.y; + if (v.y < br.y) br.y = v.y; + + // Remove the position from the list so that it doesn't get checked again + allpositions.Remove(v); + } + + // ... and set the current position to the center of that + curposition.x = tl.x + (br.x - tl.x) / 2.0; + curposition.y = tl.y + (br.y - tl.y) / 2.0; + } + else + { + // The current position is a new final position + newpositions.Add(curposition); + hasclosepositions = false; + allpositions.Reverse(); + } + } + } + + return newpositions; + } + + + /// + /// Renders associated things and sectors in the indication color. + /// Also renders event lines, if that option is enabled + /// + public void Render() + { + bool showlabels = BuilderPlug.Me.EventLineLabelVisibility > 0; // Show labels at all? + + foreach (Thing t in things) + renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); + + // There must be a better way to do this + foreach(Sector s in sectors) + { + int highlightedColor = General.Colors.Highlight.WithAlpha(128).ToInt(); + FlatVertex[] verts = new FlatVertex[s.FlatVertices.Length]; + s.FlatVertices.CopyTo(verts, 0); + for (int i = 0; i < verts.Length; i++) verts[i].c = highlightedColor; + renderer.RenderGeometry(verts, null, true); + } + + if (General.Settings.GZShowEventLines) + { + List lines = new List(eventlines.Count); + List labels = new List(eventlines.Count); + + foreach(KeyValuePair> kvp in eventlines) + { + bool emptylabel = string.IsNullOrEmpty(kvp.Key); // Can be true if only either forward or reverse labels are shown + List allpositions = new List(kvp.Value.Count); + + foreach (Line3D line in kvp.Value) + { + if (showlabels && !emptylabel) + allpositions.Add(GetLabelPosition(line.Start, line.End)); + + lines.Add(line); + } + + if (showlabels && !emptylabel) + { + List positions = MergePositions(allpositions, textwidths[kvp.Key]); + int labelcounter = 0; + + // Set the position of the pre-generated labels. Only add the labels that are needed + foreach (Vector2D pos in positions) + { + textlabels[kvp.Key][labelcounter].Location = pos; + labels.Add(textlabels[kvp.Key][labelcounter]); + labelcounter++; + } + } + } + + renderer.RenderArrows(lines); + + if (showlabels) + renderer.RenderText(labels); + } + } + + /// + /// Plots associated linedefs and sectors + /// + public void Plot() + { + foreach(Linedef ld in linedefs) + renderer.PlotLinedef(ld, General.Colors.Indication); + + foreach (Sector s in sectors) + renderer.PlotSector(s, General.Colors.Indication); } // This compares an association diff --git a/Source/Plugins/BuilderModes/General/BuilderPlug.cs b/Source/Plugins/BuilderModes/General/BuilderPlug.cs index ec9d59aa..7713cf2d 100755 --- a/Source/Plugins/BuilderModes/General/BuilderPlug.cs +++ b/Source/Plugins/BuilderModes/General/BuilderPlug.cs @@ -138,11 +138,14 @@ namespace CodeImp.DoomBuilder.BuilderModes private bool showlightradii; //mxd private bool showsoundradii; //mxd private int scaletexturesonslopes; // 0 = base scale of 1, 1 = use current scale as base, 2 = don't scale - + private int eventlinelabelvisibility; // 0 = never show, 1 = forward only, 2 = reverse only, 3 = forward + reverse + private int eventlinelabelstyle; // 0 = Action only, 1 = Action + short arguments, 2 = action + full arguments + private bool eventlinedistinctcolors; + #endregion #region ================== Properties - + public override string Name { get { return "Ultimate Doom Builder"; } } //mxd public static BuilderPlug Me { get { return me; } } @@ -193,6 +196,9 @@ namespace CodeImp.DoomBuilder.BuilderModes public bool ShowLightRadii { get { return showlightradii; } internal set { showlightradii = value; } } //mxd public bool ShowSoundRadii { get { return showsoundradii; } internal set { showsoundradii = value; } } //mxd public int ScaleTexturesOnSlopes { get { return scaletexturesonslopes; } internal set { scaletexturesonslopes = value; } } + public int EventLineLabelVisibility { get { return eventlinelabelvisibility; } internal set { eventlinelabelvisibility = value; } } + public int EventLineLabelStyle { get { return eventlinelabelstyle; } internal set { eventlinelabelstyle = value; } } + public bool EventLineDistinctColors { get { return eventlinedistinctcolors; } internal set { eventlinedistinctcolors = value; } } //mxd. "Make Door" action persistent settings internal MakeDoorSettings MakeDoor; @@ -297,6 +303,9 @@ namespace CodeImp.DoomBuilder.BuilderModes dontMoveGeometryOutsideMapBoundary = General.Settings.ReadPluginSetting("dontmovegeometryoutsidemapboundary", false); //mxd syncSelection = General.Settings.ReadPluginSetting("syncselection", false); //mxd scaletexturesonslopes = General.Settings.ReadPluginSetting("scaletexturesonslopes", 0); + eventlinelabelvisibility = General.Settings.ReadPluginSetting("eventlinelabelvisibility", 3); + eventlinelabelstyle = General.Settings.ReadPluginSetting("eventlinelabelstyle", 2); + eventlinedistinctcolors = General.Settings.ReadPluginSetting("eventlinedistinctcolors", true); } //mxd. Load settings, which can be changed via UI @@ -619,176 +628,6 @@ namespace CodeImp.DoomBuilder.BuilderModes // Return list return found.ToArray(); } - - // This renders the associated sectors/linedefs with the indication color - public static void PlotAssociations(IRenderer2D renderer, Association asso, List eventlines) - { - // Tag must be above zero - if(General.GetByIndex(asso.Tags, 0) < 1) return; - - // Sectors? - switch(asso.Type) - { - case UniversalType.SectorTag: { - foreach(Sector s in General.Map.Map.Sectors) - { - if(!asso.Tags.Overlaps(s.Tags))continue; - renderer.PlotSector(s, General.Colors.Indication); - - if(!General.Settings.GZShowEventLines) continue; - Vector2D end = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); - eventlines.Add(new Line3D(asso.Center, end)); //mxd - } - break; - } - - case UniversalType.LinedefTag: { - foreach(Linedef l in General.Map.Map.Linedefs) - { - if(!asso.Tags.Overlaps(l.Tags)) continue; - renderer.PlotLinedef(l, General.Colors.Indication); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(asso.Center, l.GetCenterPoint())); //mxd - } - break; - } - } - } - - // This renders the associated things with the indication color - public static void RenderAssociations(IRenderer2D renderer, Association asso, List eventlines) - { - // Tag must be above zero - if(General.GetByIndex(asso.Tags, 0) < 1) return; - - // Things? - switch(asso.Type) - { - case UniversalType.ThingTag: - foreach(Thing t in General.Map.Map.Things) - { - if(!asso.Tags.Contains(t.Tag)) continue; - - //Do not draw the association if the user is hovering over a child link - ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); - if (ti != null && ti.ThingLink < 0) - continue; - - renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(asso.Center, t.Position)); //mxd - } - break; - - case UniversalType.SectorTag: - foreach(Sector s in General.Map.Map.Sectors) - { - if(!asso.Tags.Overlaps(s.Tags)) continue; - int highlightedColor = General.Colors.Highlight.WithAlpha(128).ToInt(); - FlatVertex[] verts = new FlatVertex[s.FlatVertices.Length]; - s.FlatVertices.CopyTo(verts, 0); - for(int i = 0; i < verts.Length; i++) verts[i].c = highlightedColor; - renderer.RenderGeometry(verts, null, true); - } - break; - } - } - - // This renders the associated sectors/linedefs with the indication color - public static void PlotReverseAssociations(IRenderer2D renderer, Association asso, List eventlines) - { - // Tag must be above zero - if(General.GetByIndex(asso.Tags, 0) < 1) return; - - // Doom style referencing to sectors? - if(General.Map.Config.LineTagIndicatesSectors && (asso.Type == UniversalType.SectorTag)) - { - // Linedefs - foreach(Linedef l in General.Map.Map.Linedefs) - { - // Any action on this line? - if(l.Action <= 0 || !asso.Tags.Overlaps(l.Tags)) continue; - renderer.PlotLinedef(l, General.Colors.Indication); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(l.GetCenterPoint(), asso.Center)); //mxd - } - } - - // Linedefs - foreach(Linedef l in General.Map.Map.Linedefs) - { - // Known action on this line? - if((l.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(l.Action)) - { - LinedefActionInfo action = General.Map.Config.LinedefActions[l.Action]; - if( ((action.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[0]))) || - ((action.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[1]))) || - ((action.Args[2].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[2]))) || - ((action.Args[3].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[3]))) || - ((action.Args[4].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[4])))) - { - renderer.PlotLinedef(l, General.Colors.Indication); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(l.GetCenterPoint(), asso.Center)); //mxd - } - } - } - } - - // This renders the associated things with the indication color - public static void RenderReverseAssociations(IRenderer2D renderer, Association asso, List eventlines) - { - // Tag must be above zero - if(General.GetByIndex(asso.Tags, 0) < 1) return; - - // Things - foreach(Thing t in General.Map.Map.Things) - { - // Get the thing type info - ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); - - // Known action on this thing? - if((t.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(t.Action)) - { - //Do not draw the association if this is a child link. - // This prevents a reverse link to a thing via an argument, when it should be a direct tag-to-tag link instead. - if(ti != null && asso.DirectLinkType < 0 && asso.DirectLinkType != -t.Type) - continue; - - LinedefActionInfo action = General.Map.Config.LinedefActions[t.Action]; - if( ((action.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[0]))) || - ((action.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[1]))) || - ((action.Args[2].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[2]))) || - ((action.Args[3].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[3]))) || - ((action.Args[4].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[4])))) - { - renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(t.Position, asso.Center)); //mxd - } - - //If there is a link setup on this thing, and it matches the association, then draw a direct link to any matching tag - if(ti != null && asso.DirectLinkType == t.Type && asso.Tags.Contains(t.Tag)) - { - renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); - if (General.Settings.GZShowEventLines) eventlines.Add(new Line3D(t.Position, asso.Center)); - } - } - //mxd. Thing action on this thing? - else if(t.Action == 0) - { - //Draw the association, unless it is a child link. - // This prevents a reverse link to a thing via an argument, when it should be a direct tag-to-tag link instead. - if(ti != null && asso.DirectLinkType >= 0 && Math.Abs(asso.DirectLinkType) != t.Type) - { - if( ((ti.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[0]))) || - ((ti.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[1]))) || - ((ti.Args[2].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[2]))) || - ((ti.Args[3].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[3]))) || - ((ti.Args[4].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[4])))) - { - renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(t.Position, asso.Center)); - } - } - } - } - } #endregion diff --git a/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs b/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs index 1db5dac6..92deef96 100755 --- a/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs +++ b/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs @@ -69,18 +69,22 @@ namespace CodeImp.DoomBuilder.BuilderModes this.label4 = new System.Windows.Forms.Label(); this.label7 = new System.Windows.Forms.Label(); this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.scaletexturesonslopes = new System.Windows.Forms.ComboBox(); + this.label18 = new System.Windows.Forms.Label(); this.splitbehavior = new System.Windows.Forms.ComboBox(); this.label10 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label(); this.heightbysidedef = new System.Windows.Forms.ComboBox(); - this.label18 = new System.Windows.Forms.Label(); - this.scaletexturesonslopes = new System.Windows.Forms.ComboBox(); + this.groupBox5 = new System.Windows.Forms.GroupBox(); + this.eventlinelabelvisibility = new System.Windows.Forms.ComboBox(); + this.eventlinelabelstyle = new System.Windows.Forms.ComboBox(); this.tabs.SuspendLayout(); this.taboptions.SuspendLayout(); this.groupBox4.SuspendLayout(); this.groupBox3.SuspendLayout(); this.groupBox2.SuspendLayout(); this.groupBox1.SuspendLayout(); + this.groupBox5.SuspendLayout(); this.SuspendLayout(); // // tabs @@ -99,6 +103,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // // taboptions // + this.taboptions.Controls.Add(this.groupBox5); this.taboptions.Controls.Add(this.groupBox4); this.taboptions.Controls.Add(this.groupBox3); this.taboptions.Controls.Add(this.groupBox2); @@ -122,9 +127,9 @@ namespace CodeImp.DoomBuilder.BuilderModes this.groupBox4.Controls.Add(this.label12); this.groupBox4.Controls.Add(this.defaultbrightness); this.groupBox4.Controls.Add(this.label11); - this.groupBox4.Location = new System.Drawing.Point(6, 335); + this.groupBox4.Location = new System.Drawing.Point(6, 320); this.groupBox4.Name = "groupBox4"; - this.groupBox4.Size = new System.Drawing.Size(272, 136); + this.groupBox4.Size = new System.Drawing.Size(272, 119); this.groupBox4.TabIndex = 2; this.groupBox4.TabStop = false; this.groupBox4.Text = " Default sector settings"; @@ -132,7 +137,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // label15 // this.label15.AutoSize = true; - this.label15.Location = new System.Drawing.Point(218, 37); + this.label15.Location = new System.Drawing.Point(218, 27); this.label15.Name = "label15"; this.label15.Size = new System.Drawing.Size(27, 13); this.label15.TabIndex = 26; @@ -141,7 +146,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // label14 // this.label14.AutoSize = true; - this.label14.Location = new System.Drawing.Point(218, 67); + this.label14.Location = new System.Drawing.Point(218, 57); this.label14.Name = "label14"; this.label14.Size = new System.Drawing.Size(27, 13); this.label14.TabIndex = 20; @@ -159,7 +164,7 @@ namespace CodeImp.DoomBuilder.BuilderModes this.defaultfloorheight.ButtonStepSmall = 0.1F; this.defaultfloorheight.ButtonStepsUseModifierKeys = false; this.defaultfloorheight.ButtonStepsWrapAround = false; - this.defaultfloorheight.Location = new System.Drawing.Point(153, 32); + this.defaultfloorheight.Location = new System.Drawing.Point(153, 22); this.defaultfloorheight.Name = "defaultfloorheight"; this.defaultfloorheight.Size = new System.Drawing.Size(59, 24); this.defaultfloorheight.StepValues = null; @@ -167,7 +172,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // // label13 // - this.label13.Location = new System.Drawing.Point(38, 37); + this.label13.Location = new System.Drawing.Point(38, 27); this.label13.Name = "label13"; this.label13.Size = new System.Drawing.Size(110, 14); this.label13.TabIndex = 24; @@ -186,7 +191,7 @@ namespace CodeImp.DoomBuilder.BuilderModes this.defaultceilheight.ButtonStepSmall = 0.1F; this.defaultceilheight.ButtonStepsUseModifierKeys = false; this.defaultceilheight.ButtonStepsWrapAround = false; - this.defaultceilheight.Location = new System.Drawing.Point(153, 62); + this.defaultceilheight.Location = new System.Drawing.Point(153, 52); this.defaultceilheight.Name = "defaultceilheight"; this.defaultceilheight.Size = new System.Drawing.Size(59, 24); this.defaultceilheight.StepValues = null; @@ -194,7 +199,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // // label12 // - this.label12.Location = new System.Drawing.Point(38, 67); + this.label12.Location = new System.Drawing.Point(38, 57); this.label12.Name = "label12"; this.label12.Size = new System.Drawing.Size(110, 14); this.label12.TabIndex = 22; @@ -213,7 +218,7 @@ namespace CodeImp.DoomBuilder.BuilderModes this.defaultbrightness.ButtonStepSmall = 0.1F; this.defaultbrightness.ButtonStepsUseModifierKeys = false; this.defaultbrightness.ButtonStepsWrapAround = false; - this.defaultbrightness.Location = new System.Drawing.Point(153, 92); + this.defaultbrightness.Location = new System.Drawing.Point(153, 82); this.defaultbrightness.Name = "defaultbrightness"; this.defaultbrightness.Size = new System.Drawing.Size(59, 24); this.defaultbrightness.StepValues = null; @@ -221,7 +226,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // // label11 // - this.label11.Location = new System.Drawing.Point(38, 97); + this.label11.Location = new System.Drawing.Point(38, 87); this.label11.Name = "label11"; this.label11.Size = new System.Drawing.Size(110, 14); this.label11.TabIndex = 20; @@ -244,7 +249,7 @@ namespace CodeImp.DoomBuilder.BuilderModes this.groupBox3.Controls.Add(this.additiveselect); this.groupBox3.Location = new System.Drawing.Point(284, 139); this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(379, 332); + this.groupBox3.Size = new System.Drawing.Size(379, 360); this.groupBox3.TabIndex = 3; this.groupBox3.TabStop = false; this.groupBox3.Text = " Options "; @@ -389,7 +394,7 @@ namespace CodeImp.DoomBuilder.BuilderModes this.groupBox2.Controls.Add(this.label7); this.groupBox2.Location = new System.Drawing.Point(6, 139); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(272, 190); + this.groupBox2.Size = new System.Drawing.Size(272, 175); this.groupBox2.TabIndex = 1; this.groupBox2.TabStop = false; this.groupBox2.Text = " Ranges "; @@ -594,6 +599,29 @@ namespace CodeImp.DoomBuilder.BuilderModes this.groupBox1.TabStop = false; this.groupBox1.Text = " Behavior "; // + // scaletexturesonslopes + // + this.scaletexturesonslopes.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.scaletexturesonslopes.FormattingEnabled = true; + this.scaletexturesonslopes.Items.AddRange(new object[] { + "Use a scale of 1 as base", + "Use current scale as base", + "Don\'t scale"}); + this.scaletexturesonslopes.Location = new System.Drawing.Point(342, 91); + this.scaletexturesonslopes.Name = "scaletexturesonslopes"; + this.scaletexturesonslopes.Size = new System.Drawing.Size(309, 21); + this.scaletexturesonslopes.TabIndex = 3; + // + // label18 + // + this.label18.AutoSize = true; + this.label18.Location = new System.Drawing.Point(133, 94); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(190, 13); + this.label18.TabIndex = 2; + this.label18.Text = "When auto-aligning textures on slopes:"; + this.label18.TextAlign = System.Drawing.ContentAlignment.TopRight; + // // splitbehavior // this.splitbehavior.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; @@ -642,28 +670,43 @@ namespace CodeImp.DoomBuilder.BuilderModes this.heightbysidedef.Size = new System.Drawing.Size(309, 21); this.heightbysidedef.TabIndex = 0; // - // label18 + // groupBox5 // - this.label18.AutoSize = true; - this.label18.Location = new System.Drawing.Point(133, 94); - this.label18.Name = "label18"; - this.label18.Size = new System.Drawing.Size(190, 13); - this.label18.TabIndex = 2; - this.label18.Text = "When auto-aligning textures on slopes:"; - this.label18.TextAlign = System.Drawing.ContentAlignment.TopRight; + this.groupBox5.Controls.Add(this.eventlinelabelstyle); + this.groupBox5.Controls.Add(this.eventlinelabelvisibility); + this.groupBox5.Location = new System.Drawing.Point(6, 445); + this.groupBox5.Name = "groupBox5"; + this.groupBox5.Size = new System.Drawing.Size(272, 54); + this.groupBox5.TabIndex = 4; + this.groupBox5.TabStop = false; + this.groupBox5.Text = "Event line labels"; // - // scaletexturesonslopes + // eventlinelabelvisibility // - this.scaletexturesonslopes.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.scaletexturesonslopes.FormattingEnabled = true; - this.scaletexturesonslopes.Items.AddRange(new object[] { - "Use a scale of 1 as base", - "Use current scale as base", - "Don\'t scale"}); - this.scaletexturesonslopes.Location = new System.Drawing.Point(342, 91); - this.scaletexturesonslopes.Name = "scaletexturesonslopes"; - this.scaletexturesonslopes.Size = new System.Drawing.Size(309, 21); - this.scaletexturesonslopes.TabIndex = 3; + this.eventlinelabelvisibility.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.eventlinelabelvisibility.FormattingEnabled = true; + this.eventlinelabelvisibility.Items.AddRange(new object[] { + "Never show", + "Forward only", + "Reverse only", + "Forward + Reverse"}); + this.eventlinelabelvisibility.Location = new System.Drawing.Point(6, 19); + this.eventlinelabelvisibility.Name = "eventlinelabelvisibility"; + this.eventlinelabelvisibility.Size = new System.Drawing.Size(121, 21); + this.eventlinelabelvisibility.TabIndex = 0; + // + // eventlinelabelstyle + // + this.eventlinelabelstyle.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.eventlinelabelstyle.FormattingEnabled = true; + this.eventlinelabelstyle.Items.AddRange(new object[] { + "Action only", + "Action + short arguments", + "Action + full arguments"}); + this.eventlinelabelstyle.Location = new System.Drawing.Point(133, 19); + this.eventlinelabelstyle.Name = "eventlinelabelstyle"; + this.eventlinelabelstyle.Size = new System.Drawing.Size(133, 21); + this.eventlinelabelstyle.TabIndex = 1; // // PreferencesForm // @@ -686,6 +729,7 @@ namespace CodeImp.DoomBuilder.BuilderModes this.groupBox2.PerformLayout(); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); + this.groupBox5.ResumeLayout(false); this.ResumeLayout(false); } @@ -739,5 +783,8 @@ namespace CodeImp.DoomBuilder.BuilderModes private System.Windows.Forms.CheckBox additivepaintselect; private System.Windows.Forms.ComboBox scaletexturesonslopes; private System.Windows.Forms.Label label18; + private System.Windows.Forms.GroupBox groupBox5; + private System.Windows.Forms.ComboBox eventlinelabelvisibility; + private System.Windows.Forms.ComboBox eventlinelabelstyle; } } \ No newline at end of file diff --git a/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs b/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs index 38ff83de..42cea092 100755 --- a/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs +++ b/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs @@ -65,6 +65,8 @@ namespace CodeImp.DoomBuilder.BuilderModes defaultceilheight.Text = General.Settings.DefaultCeilingHeight.ToString();//mxd defaultfloorheight.Text = General.Settings.DefaultFloorHeight.ToString(); //mxd scaletexturesonslopes.SelectedIndex = General.Settings.ReadPluginSetting("scaletexturesonslopes", 0); + eventlinelabelvisibility.SelectedIndex = General.Settings.ReadPluginSetting("eventlinelabelvisibility", 3); + eventlinelabelstyle.SelectedIndex = General.Settings.ReadPluginSetting("eventlinelabelstyle", 2); } #endregion @@ -93,6 +95,8 @@ namespace CodeImp.DoomBuilder.BuilderModes General.Settings.WritePluginSetting("dontmovegeometryoutsidemapboundary", dontMoveGeometryOutsideBounds.Checked);//mxd General.Settings.WritePluginSetting("syncselection", syncSelection.Checked);//mxd General.Settings.WritePluginSetting("scaletexturesonslopes", scaletexturesonslopes.SelectedIndex); + General.Settings.WritePluginSetting("eventlinelabelvisibility", eventlinelabelvisibility.SelectedIndex); + General.Settings.WritePluginSetting("eventlinelabelstyle", eventlinelabelstyle.SelectedIndex); General.Settings.SwitchViewModes = switchviewmodes.Checked; //mxd General.Settings.SplitLineBehavior = (SplitLineBehavior)splitbehavior.SelectedIndex;//mxd