diff --git a/Source/Plugins/BuilderModes/BuilderModes.csproj b/Source/Plugins/BuilderModes/BuilderModes.csproj index ba0fad02..e0da7c05 100755 --- a/Source/Plugins/BuilderModes/BuilderModes.csproj +++ b/Source/Plugins/BuilderModes/BuilderModes.csproj @@ -145,11 +145,19 @@ + + + + + + + + diff --git a/Source/Plugins/BuilderModes/BuilderModesMono.csproj b/Source/Plugins/BuilderModes/BuilderModesMono.csproj index 22ead15e..1dc66ddc 100644 --- a/Source/Plugins/BuilderModes/BuilderModesMono.csproj +++ b/Source/Plugins/BuilderModes/BuilderModesMono.csproj @@ -143,11 +143,19 @@ + + + + + + + + diff --git a/Source/Plugins/BuilderModes/FindReplace/BaseFindMapElement.cs b/Source/Plugins/BuilderModes/FindReplace/BaseFindMapElement.cs new file mode 100644 index 00000000..edcee3a7 --- /dev/null +++ b/Source/Plugins/BuilderModes/FindReplace/BaseFindMapElement.cs @@ -0,0 +1,130 @@ +#region ================== Copyright (c) 2021 Boris Iwanski + +/* + * Copyright (c) 2021 Boris Iwanski + * 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.Collections.Generic; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + internal class BaseFindMapElement : FindReplaceType + { + #region ================== Methods + + // This is called when a specific object is selected from the list + public override void ObjectSelected(FindReplaceObject[] selection) + { + if (selection.Length == 1) + { + ZoomToSelection(selection); + + if (selection[0].Object is Linedef) + General.Interface.ShowLinedefInfo(selection[0].Linedef); + else if (selection[0].Object is Sidedef) + General.Interface.ShowLinedefInfo(selection[0].Sidedef.Line); + else if (selection[0].Object is Sector) + General.Interface.ShowSectorInfo(selection[0].Sector); + else if (selection[0].Object is Thing) + General.Interface.ShowThingInfo(selection[0].Thing); + else if (selection[0].Object is Vertex) + General.Interface.ShowVertexInfo(selection[0].Vertex); + } + else + { + General.Interface.HideInfo(); + } + + General.Map.Map.ClearAllSelected(); + foreach (FindReplaceObject obj in selection) + { + // Sidedefs can not be selected, so we have to select its Linedef + if (obj.Object is Sidedef) + obj.Sidedef.Line.Selected = true; + else + ((SelectableElement)obj.Object).Selected = true; + } + } + + // Render selection + public override void PlotSelection(IRenderer2D renderer, FindReplaceObject[] selection) + { + foreach (FindReplaceObject o in selection) + { + if (o.Object is Linedef) + renderer.PlotLinedef(o.Linedef, General.Colors.Selection); + else if (o.Object is Sidedef) + renderer.PlotLinedef(o.Sidedef.Line, General.Colors.Selection); + else if (o.Object is Sector) + { + foreach (Sidedef sd in o.Sector.Sidedefs) + renderer.PlotLinedef(sd.Line, General.Colors.Selection); + } + else if (o.Object is Thing) + renderer.RenderThing(o.Thing, General.Colors.Selection, General.Settings.ActiveThingsAlpha); + else if(o.Object is Vertex) + renderer.PlotVertex(o.Vertex, ColorCollection.SELECTION); + } + } + + // Edit objects + public override void EditObjects(FindReplaceObject[] selection) + { + HashSet linedefs = new HashSet(); + HashSet sectors = new HashSet(); + HashSet things = new HashSet(); + HashSet vertices = new HashSet(); + + foreach (FindReplaceObject o in selection) + { + if (o.Object is Linedef) + { + if (!linedefs.Contains(o.Linedef)) linedefs.Add(o.Linedef); + } + else if (o.Object is Sidedef) + { + if (!linedefs.Contains(o.Sidedef.Line)) linedefs.Add(o.Sidedef.Line); + } + else if (o.Object is Sector) + { + if (!sectors.Contains(o.Sector)) sectors.Add(o.Sector); + } + else if (o.Object is Thing) + { + if (!things.Contains(o.Thing)) things.Add(o.Thing); + } + else if (o.Object is Vertex) + if (!vertices.Contains(o.Vertex)) vertices.Add(o.Vertex); + } + + if(linedefs.Count > 0) + General.Interface.ShowEditLinedefs(linedefs); + + if (sectors.Count > 0) + General.Interface.ShowEditSectors(sectors); + + if (things.Count > 0) + General.Interface.ShowEditThings(things); + + if (vertices.Count > 0) + General.Interface.ShowEditVertices(vertices); + } + + #endregion + } +} diff --git a/Source/Plugins/BuilderModes/FindReplace/BaseFindUDMFField.cs b/Source/Plugins/BuilderModes/FindReplace/BaseFindUDMFField.cs new file mode 100644 index 00000000..86d60564 --- /dev/null +++ b/Source/Plugins/BuilderModes/FindReplace/BaseFindUDMFField.cs @@ -0,0 +1,125 @@ +#region ================== Copyright (c) 2021 Boris Iwanski + +/* + * Copyright (c) 2021 Boris Iwanski + * 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.Text.RegularExpressions; +using CodeImp.DoomBuilder.Map; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + class BaseFindUDMFField : BaseFindMapElement + { + #region ================== Properties + + public override string UsageHint + { + get + { + return "Usage: field [value]" + Environment.NewLine + + "Supported wildcards (for both field and value):" + Environment.NewLine + + "* - zero or more characters" + Environment.NewLine + + "? - one character"; + } + } + + #endregion + + #region ================== Methods + + public override bool CanReplace() + { + return false; + } + + public override bool DetermineVisiblity() + { + return General.Map.UDMF; + } + + /// + /// Gets map elements with matching fields + /// + /// Field name + /// Field value + /// List of map elements to check + /// + protected FindReplaceObject[] GetObjects(string input, ICollection list) + { + if (string.IsNullOrWhiteSpace(input)) + return new FindReplaceObject[] { }; + + List objs = new List(); + + string key; + string value; + + input = input.Trim(); + + if (input.IndexOf(' ') == -1) + { + key = input; + value = string.Empty; + } + else + { + key = input.Substring(0, input.IndexOf(' ')); + value = input.Substring(input.IndexOf(' ')).Trim(); + } + + Regex keyre = new Regex(WildCardToRegular(key)); + Regex valuere = new Regex(WildCardToRegular(value)); + + foreach(MapElement me in list) + { + foreach(KeyValuePair kvp in me.Fields) + { + if (keyre.IsMatch(kvp.Key)) + { + bool matching = true; + string fieldvalue = kvp.Value.Value.ToString(); + + if (!string.IsNullOrEmpty(value)) + { + if (!valuere.IsMatch(fieldvalue)) + matching = false; + } + + if(matching) + objs.Add(new FindReplaceObject(me, me.GetType().Name + " " + me.Index.ToString() + ". " + kvp.Key + ": " + fieldvalue)); + } + } + } + + return objs.ToArray(); + } + + /// + /// Turns a wildcard string into an regular expression. Taken from https://stackoverflow.com/a/30300521 (by user Dmitry Bychenko) + /// + /// String with wildcards + /// String of regular expression + private static string WildCardToRegular(string value) + { + return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$"; + } + + #endregion + } +} diff --git a/Source/Plugins/BuilderModes/FindReplace/FindAnyUDMFField.cs b/Source/Plugins/BuilderModes/FindReplace/FindAnyUDMFField.cs new file mode 100644 index 00000000..69494b90 --- /dev/null +++ b/Source/Plugins/BuilderModes/FindReplace/FindAnyUDMFField.cs @@ -0,0 +1,78 @@ +#region ================== Copyright (c) 2021 Boris Iwanski + +/* + * Copyright (c) 2021 Boris Iwanski + * 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.Collections.Generic; +using CodeImp.DoomBuilder.Map; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + [FindReplace("Any UDMF Field", BrowseButton = false)] + internal class FindAnyUDMFField : BaseFindUDMFField + { + #region ================== Methods + + public override bool CanReplace() + { + return false; + } + + public override bool DetermineVisiblity() + { + return General.Map.UDMF; + } + + public override FindReplaceObject[] Find(string value, bool withinselection, bool replace, string replacewith, bool keepselection) + { + if (string.IsNullOrWhiteSpace(value)) + return new FindReplaceObject[] { }; + + List list = new List(); + + if(withinselection) + { + list.AddRange(General.Map.Map.GetSelectedSectors(true)); + list.AddRange(General.Map.Map.GetSelectedLinedefs(true)); + + foreach (Linedef ld in General.Map.Map.GetSelectedLinedefs(true)) + { + if (ld.Front != null && !ld.Front.IsDisposed) + list.Add(ld.Front); + + if (ld.Back != null && !ld.Back.IsDisposed) + list.Add(ld.Back); + } + + list.AddRange(General.Map.Map.GetSelectedThings(true)); + list.AddRange(General.Map.Map.GetSelectedVertices(true)); + } + else + { + list.AddRange(General.Map.Map.Sectors); + list.AddRange(General.Map.Map.Linedefs); + list.AddRange(General.Map.Map.Sidedefs); + list.AddRange(General.Map.Map.Things); + list.AddRange(General.Map.Map.Vertices); + } + + return GetObjects(value, list); + } + + #endregion + } +} diff --git a/Source/Plugins/BuilderModes/FindReplace/FindLinedefUDMFFields.cs b/Source/Plugins/BuilderModes/FindReplace/FindLinedefUDMFFields.cs new file mode 100644 index 00000000..deed5c38 --- /dev/null +++ b/Source/Plugins/BuilderModes/FindReplace/FindLinedefUDMFFields.cs @@ -0,0 +1,52 @@ +#region ================== Copyright (c) 2021 Boris Iwanski + +/* + * Copyright (c) 2021 Boris Iwanski + * 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.Collections.Generic; +using CodeImp.DoomBuilder.Map; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + [FindReplace("Linedef UDMF Field", BrowseButton = false)] + internal class FindLinedefUDMFField : BaseFindUDMFField + { + #region ================== Methods + + public override bool CanReplace() + { + return false; + } + + public override bool DetermineVisiblity() + { + return General.Map.UDMF; + } + + public override FindReplaceObject[] Find(string value, bool withinselection, bool replace, string replacewith, bool keepselection) + { + if (string.IsNullOrWhiteSpace(value)) + return new FindReplaceObject[] { }; + + ICollection list = withinselection ? (ICollection)General.Map.Map.GetSelectedLinedefs(true) : (ICollection)General.Map.Map.Linedefs; + + return GetObjects(value, list); + } + + #endregion + } +} diff --git a/Source/Plugins/BuilderModes/FindReplace/FindSectorUDMFField.cs b/Source/Plugins/BuilderModes/FindReplace/FindSectorUDMFField.cs new file mode 100644 index 00000000..f3d0a313 --- /dev/null +++ b/Source/Plugins/BuilderModes/FindReplace/FindSectorUDMFField.cs @@ -0,0 +1,52 @@ +#region ================== Copyright (c) 2021 Boris Iwanski + +/* + * Copyright (c) 2021 Boris Iwanski + * 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.Collections.Generic; +using CodeImp.DoomBuilder.Map; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + [FindReplace("Sector UDMF Field", BrowseButton = false)] + internal class FindSectorUDMFField : BaseFindUDMFField + { + #region ================== Methods + + public override bool CanReplace() + { + return false; + } + + public override bool DetermineVisiblity() + { + return General.Map.UDMF; + } + + public override FindReplaceObject[] Find(string value, bool withinselection, bool replace, string replacewith, bool keepselection) + { + if(string.IsNullOrWhiteSpace(value)) + return new FindReplaceObject[] { }; + + ICollection list = withinselection ? (ICollection)General.Map.Map.GetSelectedSectors(true) : (ICollection)General.Map.Map.Sectors; + + return GetObjects(value, list); + } + + #endregion + } +} diff --git a/Source/Plugins/BuilderModes/FindReplace/FindSidedefUDMFField.cs b/Source/Plugins/BuilderModes/FindReplace/FindSidedefUDMFField.cs new file mode 100644 index 00000000..c0d61019 --- /dev/null +++ b/Source/Plugins/BuilderModes/FindReplace/FindSidedefUDMFField.cs @@ -0,0 +1,71 @@ +#region ================== Copyright (c) 2021 Boris Iwanski + +/* + * Copyright (c) 2021 Boris Iwanski + * 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.Collections.Generic; +using CodeImp.DoomBuilder.Map; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + [FindReplace("Sidedef UDMF Field", BrowseButton = false)] + internal class FindSidedefUDMFField : BaseFindUDMFField + { + #region ================== Methods + + public override bool CanReplace() + { + return false; + } + + public override bool DetermineVisiblity() + { + return General.Map.UDMF; + } + + public override FindReplaceObject[] Find(string value, bool withinselection, bool replace, string replacewith, bool keepselection) + { + if (string.IsNullOrWhiteSpace(value)) + return new FindReplaceObject[] { }; + + ICollection list; + + if(withinselection) + { + // Get all sidedefs of the selected linedefs + list = new List(); + + foreach(Linedef ld in General.Map.Map.GetSelectedLinedefs(true)) + { + if (ld.Front != null && !ld.Front.IsDisposed) + list.Add(ld.Front); + + if (ld.Back != null && !ld.Back.IsDisposed) + list.Add(ld.Back); + } + } + else + { + list = (ICollection)General.Map.Map.Sidedefs; + } + + return GetObjects(value, list); + } + + #endregion + } +} diff --git a/Source/Plugins/BuilderModes/FindReplace/FindThingUDMFField.cs b/Source/Plugins/BuilderModes/FindReplace/FindThingUDMFField.cs new file mode 100644 index 00000000..d9746411 --- /dev/null +++ b/Source/Plugins/BuilderModes/FindReplace/FindThingUDMFField.cs @@ -0,0 +1,52 @@ +#region ================== Copyright (c) 2021 Boris Iwanski + +/* + * Copyright (c) 2021 Boris Iwanski + * 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.Collections.Generic; +using CodeImp.DoomBuilder.Map; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + [FindReplace("Thing UDMF Field", BrowseButton = false)] + internal class FindThingUDMFField : BaseFindUDMFField + { + #region ================== Methods + + public override bool CanReplace() + { + return false; + } + + public override bool DetermineVisiblity() + { + return General.Map.UDMF; + } + + public override FindReplaceObject[] Find(string value, bool withinselection, bool replace, string replacewith, bool keepselection) + { + if (string.IsNullOrWhiteSpace(value)) + return new FindReplaceObject[] { }; + + ICollection list = withinselection ? (ICollection)General.Map.Map.GetSelectedThings(true) : (ICollection)General.Map.Map.Things; + + return GetObjects(value, list); + } + + #endregion + } +} diff --git a/Source/Plugins/BuilderModes/FindReplace/FindVertexUDMFField.cs b/Source/Plugins/BuilderModes/FindReplace/FindVertexUDMFField.cs new file mode 100644 index 00000000..4a6e1bbf --- /dev/null +++ b/Source/Plugins/BuilderModes/FindReplace/FindVertexUDMFField.cs @@ -0,0 +1,52 @@ +#region ================== Copyright (c) 2021 Boris Iwanski + +/* + * Copyright (c) 2021 Boris Iwanski + * 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.Collections.Generic; +using CodeImp.DoomBuilder.Map; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + [FindReplace("Vertex UDMF Field", BrowseButton = false)] + internal class FindVertexUDMFField : BaseFindUDMFField + { + #region ================== Methods + + public override bool CanReplace() + { + return false; + } + + public override bool DetermineVisiblity() + { + return General.Map.UDMF; + } + + public override FindReplaceObject[] Find(string value, bool withinselection, bool replace, string replacewith, bool keepselection) + { + if (string.IsNullOrWhiteSpace(value)) + return new FindReplaceObject[] { }; + + ICollection list = withinselection ? (ICollection)General.Map.Map.GetSelectedVertices(true) : (ICollection)General.Map.Map.Vertices; + + return GetObjects(value, list); + } + + #endregion + } +}