private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            SoundEnvironment se = e.UserState as SoundEnvironment;

            General.Interface.DisplayStatus(StatusType.Busy, "Updating sound environments (" + e.ProgressPercentage + "%)");
            panel.AddSoundEnvironment(se);
            General.Interface.RedrawDisplay();
        }
        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();
            }
        }
        // This highlights a new item
        private void Highlight(Sector s)
        {
            // Set new highlight
            highlighted = s;
            highlightedsoundenvironment = null;

            if (highlighted != null)
            {
                foreach (SoundEnvironment se in BuilderPlug.Me.SoundEnvironments)
                {
                    if (se.Sectors.Contains(highlighted))
                    {
                        highlightedsoundenvironment = se;
                        break;
                    }
                }
            }

            panel.HighlightSoundEnvironment(highlightedsoundenvironment);
        }
        public void DeleteItem()
        {
            // Anything to do?
            if (highlightedthing == null)
            {
                return;
            }

            // Make undo
            General.Map.UndoRedo.CreateUndo("Delete sound environment thing");
            General.Interface.DisplayStatus(StatusType.Action, "Deleted a sound environment thing.");

            // Remove from current sound environment
            if (highlightedsoundenvironment != null && highlightedsoundenvironment.Things.Contains(highlightedthing))
            {
                lock (highlightedsoundenvironment)
                {
                    highlightedsoundenvironment.Things.Remove(highlightedthing);
                }
            }

            // Dispose highlighted thing
            General.Map.Map.BeginAddRemove();
            highlightedthing.Dispose();
            highlightedthing = null;
            General.Map.Map.EndAddRemove();

            // Update cache values
            General.Map.IsChanged = true;
            General.Map.ThingsFilter.Update();

            // Update sound environments
            UpdateData();

            // Invoke a new mousemove so that the highlighted item updates
            highlightedsoundenvironment = null;
            OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, (int)mousepos.x, (int)mousepos.y, 0));

            // Redraw screen
            General.Interface.RedrawDisplay();
        }
        //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;
                }
            }
        }
        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 || ld.Front == 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);
            }
        }
        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);
        }
        public void UpdateSoundEnvironments(object sender, DoWorkEventArgs e)
        {
            List <Sector>     sectorstocheck        = new List <Sector>();
            List <Sector>     checkedsectors        = new List <Sector>();
            List <Sector>     allsectors            = new List <Sector>();
            BackgroundWorker  worker                = sender as BackgroundWorker;
            List <FlatVertex> vertsList             = new List <FlatVertex>();
            Dictionary <Thing, PixelColor> secolor  = new Dictionary <Thing, PixelColor>();
            Dictionary <Thing, int>        senumber = new Dictionary <Thing, int>();

            soundenvironments.Clear();
            blockinglinedefs.Clear();
            SoundEnvironmentMode.SoundEnvironmentPanel.BeginUpdate();             //mxd

            // Keep track of all the sectors in the map. Sectors that belong to a sound environment
            // will be removed from the list, so in the end only sectors that don't belong to any
            // sound environment will be in this list
            foreach (Sector s in General.Map.Map.Sectors)
            {
                allsectors.Add(s);
            }

            List <Thing> soundenvironmenthings = GetSoundEnvironmentThings(General.Map.Map.Sectors.ToList());
            int          numthings             = soundenvironmenthings.Count;

            // Assign each thing a color and a number, so each sound environment will always have the same color
            // and id, no matter in what order they are discovered
            for (int i = 0; i < soundenvironmenthings.Count; i++)
            {
                //mxd. Make sure same environments use the same color
                int seid = (soundenvironmenthings[i].Args[0] << 8) + soundenvironmenthings[i].Args[1];
                secolor[soundenvironmenthings[i]] = distinctcolors[seid % distinctcolors.Count];
                senumber.Add(soundenvironmenthings[i], i + 1);
            }

            while (soundenvironmenthings.Count > 0 && !worker.CancellationPending)
            {
                // Sort things by distance to center of the screen, so that sound environments the user want to look at will (hopefully) be discovered first
                Vector2D center = General.Map.Renderer2D.DisplayToMap(new Vector2D(General.Interface.Display.Width / 2f, General.Interface.Display.Height / 2f));
                soundenvironmenthings = soundenvironmenthings.OrderBy(o => Math.Abs(Vector2D.Distance(center, o.Position))).ToList();

                Thing thing = soundenvironmenthings[0];
                if (thing.Sector == null)
                {
                    thing.DetermineSector();
                }

                // Ignore things that are outside the map
                if (thing.Sector == null)
                {
                    soundenvironmenthings.Remove(thing);
                    continue;
                }

                SoundEnvironment environment = new SoundEnvironment();

                // Add initial sector. Additional adjacant sectors will be added later
                // as they are discovered
                sectorstocheck.Add(thing.Sector);

                while (sectorstocheck.Count > 0)
                {
                    Sector sector = sectorstocheck[0];

                    if (!environment.Sectors.Contains(sector))
                    {
                        environment.Sectors.Add(sector);
                    }
                    if (!checkedsectors.Contains(sector))
                    {
                        checkedsectors.Add(sector);
                    }

                    sectorstocheck.Remove(sector);
                    allsectors.Remove(sector);

                    // Find adjacant sectors and add them to the list of sectors to check if necessary
                    foreach (Sidedef sd in sector.Sidedefs)
                    {
                        if (LinedefBlocksSoundEnvironment(sd.Line))
                        {
                            if (!environment.Linedefs.Contains(sd.Line))
                            {
                                environment.Linedefs.Add(sd.Line);
                            }
                            continue;
                        }

                        if (sd.Other == null)
                        {
                            continue;
                        }

                        Sector oppositesector = (sd.Line.Front.Sector == sector ? sd.Line.Back.Sector : sd.Line.Front.Sector);

                        if (!sectorstocheck.Contains(oppositesector) && !checkedsectors.Contains(oppositesector))
                        {
                            sectorstocheck.Add(oppositesector);
                        }
                    }
                }

                // Get all things that are in the current sound environment...
                environment.Things = GetSoundEnvironmentThings(environment.Sectors);

                // ... and remove them from the list of sound environment things to check, because we know that
                // they already belong to a sound environment
                foreach (Thing t in environment.Things)
                {
                    if (soundenvironmenthings.Contains(t))
                    {
                        soundenvironmenthings.Remove(t);
                    }
                }

                // Set color and id of the sound environment
                environment.Color = secolor[environment.Things[0]];
                environment.ID    = senumber[environment.Things[0]];

                // Create the data for the overlay geometry
                List <FlatVertex> severtslist = new List <FlatVertex>(environment.Sectors.Count * 3);               //mxd
                foreach (Sector s in environment.Sectors)
                {
                    FlatVertex[] fv = new FlatVertex[s.FlatVertices.Length];
                    s.FlatVertices.CopyTo(fv, 0);
                    for (int j = 0; j < fv.Length; j++)
                    {
                        fv[j].c = environment.Color.WithAlpha(128).ToInt();
                    }

                    vertsList.AddRange(fv);
                    severtslist.AddRange(fv);                     //mxd

                    // Get all Linedefs that will block sound environments
                    foreach (Sidedef sd in s.Sidedefs)
                    {
                        if (!LinedefBlocksSoundEnvironment(sd.Line))
                        {
                            continue;
                        }
                        lock (blockinglinedefs)
                        {
                            blockinglinedefs.Add(sd.Line);
                        }
                    }
                }

                //mxd. Store sector environment verts
                environment.SectorsGeometry = severtslist.ToArray();

                // Update the overlay geometry with the newly added sectors
                if (overlayGeometry == null)
                {
                    overlayGeometry = vertsList.ToArray();
                }
                else
                {
                    lock (overlayGeometry)
                    {
                        overlayGeometry = vertsList.ToArray();
                    }
                }

                environment.Things   = environment.Things.OrderBy(o => o.Index).ToList();
                environment.Linedefs = environment.Linedefs.OrderBy(o => o.Index).ToList();

                //mxd. Find the first non-dormant thing
                Thing activeenv = null;
                foreach (Thing t in environment.Things)
                {
                    if (!ThingDormant(t))
                    {
                        activeenv = t;
                        break;
                    }
                }

                //mxd. Update environment name
                if (activeenv != null)
                {
                    foreach (KeyValuePair <string, KeyValuePair <int, int> > group in General.Map.Data.Reverbs)
                    {
                        if (group.Value.Key == activeenv.Args[0] && group.Value.Value == activeenv.Args[1])
                        {
                            environment.Name = group.Key + " (" + activeenv.Args[0] + " " + activeenv.Args[1] + ")";
                            break;
                        }
                    }

                    //mxd. No suitable name found?..
                    if (environment.Name == SoundEnvironment.DEFAULT_NAME)
                    {
                        environment.Name += " (" + activeenv.Args[0] + " " + activeenv.Args[1] + ")";
                    }
                }

                //mxd. Still no suitable name?..
                if (environment.Name == SoundEnvironment.DEFAULT_NAME)
                {
                    environment.Name += " " + environment.ID;
                }

                lock (soundenvironments)
                {
                    soundenvironments.Add(environment);
                }

                // Tell the worker that discovering a sound environment is finished. This will update the tree view, and also
                // redraw the interface, so the sectors of this sound environment are colored
                worker.ReportProgress((int)((1.0f - (soundenvironmenthings.Count / (float)numthings)) * 100), environment);
            }

            // Create overlay geometry for sectors that don't belong to a sound environment
            foreach (Sector s in allsectors)
            {
                FlatVertex[] fv = new FlatVertex[s.FlatVertices.Length];
                s.FlatVertices.CopyTo(fv, 0);
                for (int j = 0; j < fv.Length; j++)
                {
                    fv[j].c = NoSoundColor.WithAlpha(128).ToInt();
                }
                vertsList.AddRange(fv);
            }

            if (overlayGeometry == null)
            {
                overlayGeometry = vertsList.ToArray();
            }
            else
            {
                lock (overlayGeometry)
                {
                    overlayGeometry = vertsList.ToArray();
                }
            }

            soundenvironmentisupdated = true;
            SoundEnvironmentMode.SoundEnvironmentPanel.EndUpdate();             //mxd
        }
        // Mouse moves
        public override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            // Not holding any buttons?
            if (e.Button == MouseButtons.None)
            {
                General.Interface.SetCursor(Cursors.Default);

                // Find the nearest linedef within highlight range
                Linedef l = General.Map.Map.NearestLinedef(mousemappos);
                if (l != null)
                {
                    // Check on which side of the linedef the mouse is
                    float side = l.SideOfLine(mousemappos);
                    if (side > 0)
                    {
                        // Is there a sidedef here?
                        if (l.Back != null)
                        {
                            // Highlight if not the same
                            if (l.Back.Sector != highlighted)
                            {
                                Highlight(l.Back.Sector);
                            }
                        }
                        else if (highlighted != null)
                        {
                            // Highlight nothing
                            Highlight(null);
                        }
                    }
                    else
                    {
                        // Is there a sidedef here?
                        if (l.Front != null)
                        {
                            // Highlight if not the same
                            if (l.Front.Sector != highlighted)
                            {
                                Highlight(l.Front.Sector);
                            }
                        }
                        else if (highlighted != null)
                        {
                            // Highlight nothing
                            Highlight(null);
                        }
                    }
                }
                else if (highlighted != null)
                {
                    // Highlight nothing
                    Highlight(null);
                }

                //mxd. Find the nearest linedef within default highlight range
                l = General.Map.Map.NearestLinedefRange(mousemappos, 20 / renderer.Scale);
                //mxd. We are not interested in single-sided lines, unless they have zoneboundary flag...
                if (l != null && ((l.Front == null || l.Back == null) && !l.IsFlagSet(ZoneBoundaryFlag)))
                {
                    l = null;
                }

                //mxd. Set as highlighted
                bool redrawrequired = false;
                if (highlightedline != l)
                {
                    highlightedline = l;
                    redrawrequired  = true;
                }

                //mxd. Highlighted environment changed?
                if (oldhighlightedsoundenvironment != highlightedsoundenvironment)
                {
                    oldhighlightedsoundenvironment = highlightedsoundenvironment;
                    redrawrequired = true;
                }

                //mxd. Find the nearest thing within default highlight range
                if (highlightedline == null && highlightedsoundenvironment != null)
                {
                    Thing t = MapSet.NearestThingSquareRange(highlightedsoundenvironment.Things, mousemappos, 10 / renderer.Scale);
                    if (highlightedthing != t)
                    {
                        highlightedthing = t;
                        redrawrequired   = true;
                    }
                }
                else if (highlightedthing != null)
                {
                    highlightedthing = null;
                    redrawrequired   = true;
                }

                //mxd
                if (redrawrequired)
                {
                    // Show highlight info
                    if (highlightedline != null && !highlightedline.IsDisposed)
                    {
                        General.Interface.ShowLinedefInfo(highlightedline);
                    }
                    else if (highlighted != null && !highlighted.IsDisposed)
                    {
                        General.Interface.ShowSectorInfo(highlighted);
                    }
                    else
                    {
                        General.Interface.HideInfo();
                    }

                    // Redraw display
                    General.Interface.RedrawDisplay();
                }
            }
        }