ZoneBuilder/Source/Plugins/SoundPropagationMode/Interface/SoundEnvironmentPanel.cs
MaxED 022b0474af Fixed inability to disable bilinear filtering in Visual mode some users experienced.
Fixed occasional TreeView flickering in Edit Things window, Browse Action window and Tag Explorer panel.
Updated Thing category icons in the Edit Things window. They now have "opened" and "closed" states.
Internal: added BufferedTreeView to the core controls.
Updated ZDoom game configurations (sector crush mode).
Updated ZDoom ACC.
2023-01-09 12:41:11 +01:00

329 lines
9 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Controls;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Geometry;
namespace CodeImp.DoomBuilder.SoundPropagationMode
{
public partial class SoundEnvironmentPanel : UserControl
{
public event EventHandler OnShowWarningsOnlyChanged; //mxd
public BufferedTreeView SoundEnvironments { get { return soundenvironments; } set { soundenvironments = value; } }
private readonly int warningiconindex; //mxd
private bool treeisupdating; //mxd
private int nodewarningscount; //mxd
private const string shownodewarningstext = "Show nodes with warnings only (N)";
private delegate void UpdateCallback(); //mxd
public SoundEnvironmentPanel()
{
InitializeComponent();
soundenvironments.ImageList = new ImageList();
foreach(Bitmap icon in BuilderPlug.Me.DistinctIcons)
{
soundenvironments.ImageList.Images.Add(icon);
}
soundenvironments.ImageList.Images.Add(Properties.Resources.Warning);
warningiconindex = soundenvironments.ImageList.Images.Count - 1; //mxd
}
//mxd
public void BeginUpdate()
{
if(treeisupdating) return;
if(soundenvironments.InvokeRequired)
{
UpdateCallback d = BeginUpdate;
soundenvironments.Invoke(d);
}
else
{
soundenvironments.BeginUpdate();
nodewarningscount = 0;
}
}
//mxd
public void EndUpdate()
{
if(soundenvironments.InvokeRequired)
{
UpdateCallback d = EndUpdate;
soundenvironments.Invoke(d);
}
else
{
treeisupdating = false;
soundenvironments.Sort();
soundenvironments.EndUpdate();
// Update the checkbox
showwarningsonly.Text = shownodewarningstext.Replace("(N)", "(" + nodewarningscount + ")");
showwarningsonly.Enabled = (showwarningsonly.Checked || nodewarningscount > 0);
}
}
public void AddSoundEnvironment(SoundEnvironment se)
{
TreeNode topnode = new TreeNode(se.Name);
topnode.Tag = se; //mxd
TreeNode thingsnode = new TreeNode("Things (" + se.Things.Count + ")");
TreeNode linedefsnode = new TreeNode("Linedefs (" + se.Linedefs.Count + ")");
int notdormant = 0;
int iconindex = BuilderPlug.Me.DistinctColors.IndexOf(se.Color); //mxd
int topindex = iconindex; //mxd
bool nodehaswarnings = false; //mxd
thingsnode.ImageIndex = iconindex; //mxd
thingsnode.SelectedImageIndex = iconindex; //mxd
linedefsnode.ImageIndex = iconindex; //mxd
linedefsnode.SelectedImageIndex = iconindex; //mxd
// Add things
foreach(Thing t in se.Things)
{
TreeNode thingnode = new TreeNode("Thing " + t.Index);
thingnode.Tag = t;
thingnode.ImageIndex = iconindex; //mxd
thingnode.SelectedImageIndex = iconindex; //mxd
thingsnode.Nodes.Add(thingnode);
if(!BuilderPlug.ThingDormant(t))
{
notdormant++;
}
else
{
thingnode.Text += " (dormant)";
}
}
// Set the icon to warning sign and add the tooltip when there are more than 1 non-dormant things
if(notdormant > 1)
{
thingsnode.ImageIndex = warningiconindex;
thingsnode.SelectedImageIndex = warningiconindex;
topindex = warningiconindex;
foreach(TreeNode tn in thingsnode.Nodes)
{
if(!BuilderPlug.ThingDormant((Thing)tn.Tag))
{
tn.ImageIndex = warningiconindex;
tn.SelectedImageIndex = warningiconindex;
tn.ToolTipText = "More than one thing in this\nsound environment is set to be\nactive. Set all but one thing\nto dormant.";
nodewarningscount++; //mxd
nodehaswarnings = true; //mxd
}
}
}
// Add linedefs
foreach(Linedef ld in se.Linedefs)
{
bool showwarning = false;
TreeNode linedefnode = new TreeNode("Linedef " + ld.Index);
linedefnode.Tag = ld;
linedefnode.ImageIndex = iconindex; //mxd
linedefnode.SelectedImageIndex = iconindex; //mxd
if(ld.Back == null)
{
showwarning = true;
linedefnode.ToolTipText = "This line is single-sided, but has\nthe sound boundary flag set.";
}
else if(se.Sectors.Contains(ld.Front.Sector) && se.Sectors.Contains(ld.Back.Sector))
{
showwarning = true;
linedefnode.ToolTipText = "More than one thing in this\nThe sectors on both sides of\nthe line belong to the same\nsound environment.";
}
if(showwarning)
{
linedefnode.ImageIndex = warningiconindex;
linedefnode.SelectedImageIndex = warningiconindex;
linedefsnode.ImageIndex = warningiconindex;
linedefsnode.SelectedImageIndex = warningiconindex;
topindex = warningiconindex;
nodewarningscount++; //mxd
nodehaswarnings = true; //mxd
}
linedefsnode.Nodes.Add(linedefnode);
}
//mxd
if(!showwarningsonly.Checked || nodehaswarnings)
{
topnode.Nodes.Add(thingsnode);
topnode.Nodes.Add(linedefsnode);
topnode.Tag = se;
topnode.ImageIndex = topindex;
topnode.SelectedImageIndex = topindex;
// Sound environments will no be added in consecutive order, so we'll have to find
// out where in the tree to add the node
int insertionplace = 0;
foreach(TreeNode tn in soundenvironments.Nodes)
{
if(se.ID < ((SoundEnvironment)tn.Tag).ID) break;
insertionplace++;
}
soundenvironments.Nodes.Insert(insertionplace, topnode);
}
}
public void HighlightSoundEnvironment(SoundEnvironment se)
{
if(soundenvironments.SelectedNode != null) return; //mxd
if(!treeisupdating) soundenvironments.BeginUpdate();
soundenvironments.CollapseAll(); //mxd
foreach(TreeNode tn in soundenvironments.Nodes)
{
if(se != null && ((SoundEnvironment)tn.Tag).ID == se.ID)
{
if(tn.NodeFont == null || tn.NodeFont.Style != FontStyle.Bold)
tn.NodeFont = new Font(soundenvironments.Font.FontFamily, soundenvironments.Font.Size, FontStyle.Bold);
//mxd
tn.Expand();
if(soundenvironments.SelectedNode == null) tn.EnsureVisible();
}
else
{
if(tn.NodeFont == null || tn.NodeFont.Style != FontStyle.Regular)
tn.NodeFont = new Font(soundenvironments.Font.FontFamily, soundenvironments.Font.Size);
}
}
if(!treeisupdating) soundenvironments.EndUpdate();
}
//mxd. This (de)selects sound environment
public void SelectSoundEnvironment(SoundEnvironment se)
{
if((se == null && soundenvironments.SelectedNode != null) || (se != null && soundenvironments.SelectedNode != null && soundenvironments.SelectedNode.Tag is SoundEnvironment && ((SoundEnvironment)soundenvironments.SelectedNode.Tag).ID == se.ID))
{
soundenvironments.SelectedNode = null;
return;
}
if(se == null) return;
foreach(TreeNode tn in soundenvironments.Nodes)
{
if(((SoundEnvironment)tn.Tag).ID == se.ID)
{
soundenvironments.SelectedNode = tn;
tn.EnsureVisible();
return;
}
}
}
private static bool IsClickOnText(TreeView treeView, TreeNode node, Point location)
{
var hitTest = treeView.HitTest(location);
return hitTest.Node == node && (hitTest.Location == TreeViewHitTestLocations.Label || hitTest.Location == TreeViewHitTestLocations.Image);
}
private static void ProcessNodeClick(TreeNode node)
{
if(node == null) return;
List<Vector2D> points = new List<Vector2D>();
RectangleF area = MapSet.CreateEmptyArea();
if(node.Parent == null)
{
if(node.Tag is SoundEnvironment)
{
SoundEnvironment se = (SoundEnvironment)node.Tag;
foreach(Sector s in se.Sectors)
{
foreach(Sidedef sd in s.Sidedefs)
{
points.Add(sd.Line.Start.Position);
points.Add(sd.Line.End.Position);
}
}
}
else
{
// Don't zoom if the wrong nodes are selected
return;
}
}
else
{
if(node.Tag is Thing)
{
Thing t = (Thing)node.Tag;
// We don't want to be zoomed too closely, so add somepadding
points.Add(t.Position - 200);
points.Add(t.Position + 200);
}
else if(node.Tag is Linedef)
{
Linedef ld = (Linedef)node.Tag;
points.Add(ld.Start.Position);
points.Add(ld.End.Position);
}
else
{
// Don't zoom if the wrong nodes are selected
return;
}
}
area = MapSet.IncreaseArea(area, points);
// Add padding
area.Inflate(100f, 100f);
// Zoom to area
ClassicMode editmode = (General.Editing.Mode as ClassicMode);
editmode.CenterOnArea(area, 0.0f);
}
#region ================== Events
private void soundenvironments_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if(IsClickOnText(soundenvironments, e.Node, e.Location))
{
ProcessNodeClick(e.Node);
}
}
private void soundenvironments_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
if(e.Action != TreeViewAction.ByMouse) return;
var position = soundenvironments.PointToClient(Cursor.Position);
e.Cancel = !IsClickOnText(soundenvironments, e.Node, position);
}
//mxd
private void showwarningsonly_CheckedChanged(object sender, EventArgs e)
{
if(OnShowWarningsOnlyChanged != null) OnShowWarningsOnlyChanged(this, EventArgs.Empty);
}
#endregion
}
}