UltimateZoneBuilder/Source/Plugins/CommentsPanel/CommentsDocker.cs
MaxED 0369c969d1 According to dotnetperls.com, "new Dictionary<string, [anything]>(StringComparer.Ordinal)" works 17% faster than "new Dictionary<string, [anything]>()", so let's stick that everywhere and see what happens :)
Draw Curve Mode: added settings panel.
Sectors mode: added "Make Door" button to the toolbar.
Swapped Side panel and Info panel z-order. 
Interface: split toolbar into 3 separate toolbars. All toolbar buttons are now viewable at 1024x768.
Interface: grouped stuff in "Modes" menu a bit better.
Interface: added "Draw [stuff]" buttons to modes toolbar.
Interface: reorganized main menu. Hope it makes more sense now.
API: added General.Interface.AddModesButton() and General.Interface.AddModesMenu(), which can be used to add buttons to specific group in "Modes" toolbar and menu items to specific group in "Modes" menu, so actions, which behave like an editing mode, but are not part of one can be added there.
2014-02-26 14:11:06 +00:00

629 lines
18 KiB
C#

#region ================== Copyright (c) 2010 Pascal vd Heiden
/*
* Copyright (c) 2010 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Types;
#endregion
namespace CodeImp.DoomBuilder.CommentsPanel
{
public partial class CommentsDocker : UserControl
{
#region ================== Variables
Dictionary<string, CommentInfo> v_comments = new Dictionary<string, CommentInfo>(StringComparer.Ordinal);
Dictionary<string, CommentInfo> l_comments = new Dictionary<string, CommentInfo>(StringComparer.Ordinal);
Dictionary<string, CommentInfo> s_comments = new Dictionary<string, CommentInfo>(StringComparer.Ordinal);
Dictionary<string, CommentInfo> t_comments = new Dictionary<string, CommentInfo>(StringComparer.Ordinal);
bool preventupdate;
#endregion
#region ================== Constructor
// Constructor
public CommentsDocker()
{
InitializeComponent();
filtermode.Checked = General.Settings.ReadPluginSetting("filtermode", false);
clickselects.Checked = General.Settings.ReadPluginSetting("clickselects", false);
}
// Disposer
protected override void Dispose(bool disposing)
{
General.Settings.WritePluginSetting("filtermode", filtermode.Checked);
General.Settings.WritePluginSetting("clickselects", clickselects.Checked);
if(disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
#region ================== Methods
// When attached to the docker
public void Setup()
{
if(this.ParentForm != null)
{
this.ParentForm.Activated += ParentForm_Activated;
}
grid.CurrentCell = null;
updatetimer.Start();
enabledtimer.Start();
}
// Before detached from the docker
public void Terminate()
{
if(this.ParentForm != null)
{
this.ParentForm.Activated -= ParentForm_Activated;
}
updatetimer.Stop();
enabledtimer.Stop();
}
// This sends the focus back to the display and removes grid selection
private void LoseFocus()
{
preventupdate = false;
grid.CurrentCell = null;
grid.ClearSelection();
General.Interface.FocusDisplay();
}
// This updates the list for a specific kind of group
private void UpdateGroupList(Dictionary<string, CommentInfo> newcomments, Dictionary<string, CommentInfo> comments, Image icon)
{
// Remove old comments
List<CommentInfo> commentslist = new List<CommentInfo>(comments.Values);
foreach(CommentInfo c in commentslist)
{
if(!newcomments.ContainsKey(c.Comment))
{
grid.Rows.Remove(c.Row);
comments.Remove(c.Comment);
}
}
// Update the list with comments
foreach(KeyValuePair<string, CommentInfo> c in newcomments)
{
DataGridViewRow row;
CommentInfo cc = c.Value;
if(!comments.ContainsKey(c.Key))
{
// Create grid row
int index = grid.Rows.Add();
row = grid.Rows[index];
row.Cells[0].Value = icon;
row.Cells[0].Style.Alignment = DataGridViewContentAlignment.TopCenter;
row.Cells[0].Style.Padding = new Padding(0, 5, 0, 0);
row.Cells[1].Value = cc.Comment;
row.Cells[1].Style.WrapMode = DataGridViewTriState.True;
row.Cells[1].Tag = cc;
// Add to list of comments
cc.Row = row;
comments.Add(c.Key, cc);
}
else
{
cc = comments[c.Key];
row = cc.Row;
cc.ReplaceElements(c.Value);
}
}
}
// This sets the timer to update the list very soon
public void UpdateListSoon()
{
updatetimer.Stop();
updatetimer.Interval = 100;
updatetimer.Start();
}
// This finds all comments and updates the list
public void UpdateList()
{
if(!preventupdate)
{
// Update vertices
Dictionary<string, CommentInfo> newcomments = new Dictionary<string, CommentInfo>(StringComparer.Ordinal);
if(!filtermode.Checked || (General.Editing.Mode.GetType().Name == "VerticesMode"))
{
foreach(Vertex v in General.Map.Map.Vertices) AddComments(v, newcomments);
}
UpdateGroupList(newcomments, v_comments, Properties.Resources.VerticesMode);
// Update linedefs/sidedefs
newcomments.Clear();
if(!filtermode.Checked || (General.Editing.Mode.GetType().Name == "LinedefsMode"))
{
foreach(Linedef l in General.Map.Map.Linedefs) AddComments(l, newcomments);
foreach(Sidedef sd in General.Map.Map.Sidedefs) AddComments(sd, newcomments);
}
UpdateGroupList(newcomments, l_comments, Properties.Resources.LinesMode);
// Update sectors
newcomments.Clear();
if(!filtermode.Checked || (General.Editing.Mode.GetType().Name == "SectorsMode"))
{
foreach(Sector s in General.Map.Map.Sectors) AddComments(s, newcomments);
}
UpdateGroupList(newcomments, s_comments, Properties.Resources.SectorsMode);
// Update things
newcomments.Clear();
if(!filtermode.Checked || (General.Editing.Mode.GetType().Name == "ThingsMode"))
{
foreach(Thing t in General.Map.Map.Things) AddComments(t, newcomments);
}
UpdateGroupList(newcomments, t_comments, Properties.Resources.ThingsMode);
// Sort grid
grid.Sort(grid.Columns[1], ListSortDirection.Ascending);
// Update
grid.Update();
grid.CurrentCell = null;
grid.ClearSelection();
}
}
// This adds comments from a MapElement
private void AddComments(MapElement e, Dictionary<string, CommentInfo> comments)
{
if(e.Fields.ContainsKey("comment"))
{
string c = e.Fields["comment"].Value.ToString();
if(comments.ContainsKey(c))
comments[c].AddElement(e);
else
comments[c] = new CommentInfo(c, e);
}
}
// This changes the view to see the objects of a comment
private void ViewComment(CommentInfo c)
{
List<Vector2D> points = new List<Vector2D>();
RectangleF area = MapSet.CreateEmptyArea();
// Add all points to a list
foreach(MapElement obj in c.Elements)
{
if(obj is Vertex)
{
points.Add((obj as Vertex).Position);
}
else if(obj is Linedef)
{
points.Add((obj as Linedef).Start.Position);
points.Add((obj as Linedef).End.Position);
}
else if(obj is Sidedef)
{
points.Add((obj as Sidedef).Line.Start.Position);
points.Add((obj as Sidedef).Line.End.Position);
}
else if(obj is Sector)
{
Sector s = (obj as Sector);
foreach(Sidedef sd in s.Sidedefs)
{
points.Add(sd.Line.Start.Position);
points.Add(sd.Line.End.Position);
}
}
else if(obj is Thing)
{
Thing t = (obj as Thing);
Vector2D p = t.Position;
points.Add(p);
points.Add(p + new Vector2D(t.Size * 2.0f, t.Size * 2.0f));
points.Add(p + new Vector2D(t.Size * 2.0f, -t.Size * 2.0f));
points.Add(p + new Vector2D(-t.Size * 2.0f, t.Size * 2.0f));
points.Add(p + new Vector2D(-t.Size * 2.0f, -t.Size * 2.0f));
}
else
{
General.Fail("Unknown object given to zoom in on.");
}
}
// Make a view area from the points
foreach(Vector2D p in points) area = MapSet.IncreaseArea(area, p);
// Make the area square, using the largest side
if(area.Width > area.Height)
{
float delta = area.Width - area.Height;
area.Y -= delta * 0.5f;
area.Height += delta;
}
else
{
float delta = area.Height - area.Width;
area.X -= delta * 0.5f;
area.Width += delta;
}
// Add padding
area.Inflate(100f, 100f);
// Zoom to area
ClassicMode editmode = (General.Editing.Mode as ClassicMode);
editmode.CenterOnArea(area, 0.6f);
}
// This selects the elements in a comment
private void SelectComment(CommentInfo c, bool clear)
{
//string editmode = "";
// Leave any volatile mode
General.Editing.CancelVolatileMode();
if(clear)
{
General.Map.Map.ClearAllSelected();
if(c.Elements[0] is Thing)
General.Editing.ChangeMode("ThingsMode");
else if(c.Elements[0] is Vertex)
General.Editing.ChangeMode("VerticesMode");
else if((c.Elements[0] is Linedef) || (c.Elements[0] is Sidedef))
General.Editing.ChangeMode("LinedefsMode");
else if(c.Elements[0] is Sector)
General.Editing.ChangeMode("SectorsMode");
}
else
{
if(!(c.Elements[0] is Thing))
{
// Sectors mode is a bitch because it deals with selections somewhat aggressively
// so we have to switch to linedefs to make this work right
if((General.Editing.Mode.GetType().Name == "VerticesMode") ||
(General.Editing.Mode.GetType().Name == "SectorsMode") ||
(General.Editing.Mode.GetType().Name == "MakeSectorMode"))
General.Editing.ChangeMode("LinedefsMode");
}
}
// Select the map elements
foreach(MapElement obj in c.Elements)
{
if(obj is SelectableElement)
{
(obj as SelectableElement).Selected = true;
if(obj is Sector)
{
foreach(Sidedef sd in (obj as Sector).Sidedefs)
sd.Line.Selected = true;
}
}
}
General.Interface.RedrawDisplay();
}
// This removes the comments from elements in a comment
private void RemoveComment(CommentInfo c)
{
// Create undo
if(c.Elements.Count == 1)
General.Map.UndoRedo.CreateUndo("Remove comment");
else
General.Map.UndoRedo.CreateUndo("Remove " + c.Elements.Count + " comments");
// Erase comment fields
foreach(MapElement obj in c.Elements)
{
obj.Fields.BeforeFieldsChange();
obj.Fields.Remove("comment");
}
UpdateList();
General.Interface.RedrawDisplay();
}
// This gets the currently selected comment or returns null when none is selected
private CommentInfo GetSelectedComment()
{
if(grid.SelectedCells.Count > 0)
{
foreach(DataGridViewCell c in grid.SelectedCells)
{
if((c.ValueType != typeof(Image)) && (c.Tag is CommentInfo))
return (CommentInfo)(c.Tag);
}
}
return null;
}
#endregion
#region ================== Events
// This gives a good idea when comments could have been changed
// as it is called every time a dialog window closes.
private void ParentForm_Activated(object sender, EventArgs e)
{
UpdateList();
}
// Update regulary
private void updatetimer_Tick(object sender, EventArgs e)
{
updatetimer.Stop();
updatetimer.Interval = 2000;
UpdateList();
updatetimer.Start();
}
// Mouse pressed
private void grid_MouseDown(object sender, MouseEventArgs e)
{
preventupdate = true;
if(e.Button == MouseButtons.Right)
{
DataGridView.HitTestInfo h = grid.HitTest(e.X, e.Y);
if(h.Type == DataGridViewHitTestType.Cell)
{
grid.ClearSelection();
grid.Rows[h.RowIndex].Selected = true;
}
}
}
// Mouse released
private void grid_MouseUp(object sender, MouseEventArgs e)
{
CommentInfo c = GetSelectedComment();
// Show popup menu?
if((e.Button == MouseButtons.Right) && (c != null))
{
// Determine objects type
string objname = "";
if((c.Elements[0] is Vertex) && (c.Elements.Count > 1)) objname = "Vertices";
else if((c.Elements[0] is Vertex) && (c.Elements.Count == 1)) objname = "Vertex";
else if(((c.Elements[0] is Linedef) || (c.Elements[0] is Sidedef)) && (c.Elements.Count > 1)) objname = "Linedefs";
else if(((c.Elements[0] is Linedef) || (c.Elements[0] is Sidedef)) && (c.Elements.Count == 1)) objname = "Linedef";
else if((c.Elements[0] is Sector) && (c.Elements.Count > 1)) objname = "Sectors";
else if((c.Elements[0] is Sector) && (c.Elements.Count == 1)) objname = "Sector";
else if((c.Elements[0] is Thing) && (c.Elements.Count > 1)) objname = "Things";
else if((c.Elements[0] is Thing) && (c.Elements.Count == 1)) objname = "Thing";
editobjectitem.Text = "Edit " + objname + "...";
// Show popup menu
Point screenpos = grid.PointToScreen(new Point(e.X, e.Y));
contextmenu.Tag = c;
contextmenu.Show(screenpos);
}
else
{
// View selected comment
if(c != null)
{
ViewComment(c);
if(clickselects.Checked)
SelectComment(c, true);
}
LoseFocus();
}
}
// Select
private void selectitem_Click(object sender, EventArgs e)
{
// Select comment
CommentInfo c = (CommentInfo)contextmenu.Tag;
if(c != null) SelectComment(c, true);
}
// Select additive
private void selectadditiveitem_Click(object sender, EventArgs e)
{
// Select comment
CommentInfo c = (CommentInfo)contextmenu.Tag;
if(c != null) SelectComment(c, false);
}
// Remove comments
private void removecommentsitem_Click(object sender, EventArgs e)
{
// Remove comment
CommentInfo c = (CommentInfo)contextmenu.Tag;
if(c != null) RemoveComment(c);
}
// Edit objects
private void editobjectitem_Click(object sender, EventArgs e)
{
CommentInfo c = (CommentInfo)contextmenu.Tag;
if(c != null)
{
if(c.Elements[0] is Vertex)
{
List<Vertex> vertices = new List<Vertex>();
foreach(MapElement m in c.Elements) vertices.Add((Vertex)m);
General.Interface.ShowEditVertices(vertices);
}
else if((c.Elements[0] is Linedef) || (c.Elements[0] is Sidedef))
{
List<Linedef> linedefs = new List<Linedef>();
foreach(MapElement m in c.Elements)
{
if(m is Sidedef)
linedefs.Add((m as Sidedef).Line);
else
linedefs.Add((Linedef)m);
}
General.Interface.ShowEditLinedefs(linedefs);
}
else if(c.Elements[0] is Sector)
{
List<Sector> sectors = new List<Sector>();
foreach(MapElement m in c.Elements) sectors.Add((Sector)m);
General.Interface.ShowEditSectors(sectors);
}
else if(c.Elements[0] is Thing)
{
List<Thing> things = new List<Thing>();
foreach(MapElement m in c.Elements) things.Add((Thing)m);
General.Interface.ShowEditThings(things);
}
General.Map.Map.Update();
UpdateList();
LoseFocus();
General.Interface.RedrawDisplay();
}
}
// Menu closes
private void contextmenu_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
LoseFocus();
}
// Mode filter option changed
private void filtermode_CheckedChanged(object sender, EventArgs e)
{
UpdateList();
LoseFocus();
}
// Click selects changes
private void clickselects_CheckedChanged(object sender, EventArgs e)
{
LoseFocus();
}
// This sets the comment on the current selection
private void addcomment_Click(object sender, EventArgs e)
{
List<MapElement> elements = new List<MapElement>();
if(General.Editing.Mode.GetType().Name == "VerticesMode")
{
ICollection<Vertex> vs = General.Map.Map.GetSelectedVertices(true);
foreach(Vertex v in vs) elements.Add(v);
}
if(General.Editing.Mode.GetType().Name == "LinedefsMode")
{
ICollection<Linedef> ls = General.Map.Map.GetSelectedLinedefs(true);
foreach(Linedef l in ls) elements.Add(l);
}
if(General.Editing.Mode.GetType().Name == "SectorsMode")
{
ICollection<Sector> ss = General.Map.Map.GetSelectedSectors(true);
foreach(Sector s in ss) elements.Add(s);
}
if(General.Editing.Mode.GetType().Name == "ThingsMode")
{
ICollection<Thing> ts = General.Map.Map.GetSelectedThings(true);
foreach(Thing t in ts) elements.Add(t);
}
if(elements.Count > 0)
{
// Create undo
if(elements.Count == 1)
General.Map.UndoRedo.CreateUndo("Add comment");
else
General.Map.UndoRedo.CreateUndo("Add " + elements.Count + " comments");
// Set comment on elements
foreach(MapElement el in elements)
{
el.Fields.BeforeFieldsChange();
el.Fields["comment"] = new UniValue((int)UniversalType.String, addcommenttext.Text);
}
}
addcommenttext.Text = "";
UpdateList();
LoseFocus();
General.Interface.RedrawDisplay();
}
// Text typed in add comment box
private void addcommenttext_KeyDown(object sender, KeyEventArgs e)
{
if((e.KeyCode == Keys.Enter) && (e.Modifiers == Keys.None) && addcomment.Enabled)
{
addcomment.PerformClick();
e.Handled = true;
e.SuppressKeyPress = true;
}
}
// Check if the add comment box should be enabled
private void enabledtimer_Tick(object sender, EventArgs e)
{
if(General.Editing.Mode == null) return; //mxd
if(General.Editing.Mode.GetType().Name == "VerticesMode")
addcommentgroup.Enabled = (General.Map.Map.SelectedVerticessCount > 0);
else if(General.Editing.Mode.GetType().Name == "LinedefsMode")
addcommentgroup.Enabled = (General.Map.Map.SelectedLinedefsCount > 0);
else if(General.Editing.Mode.GetType().Name == "SectorsMode")
addcommentgroup.Enabled = (General.Map.Map.SelectedSectorsCount > 0);
else if(General.Editing.Mode.GetType().Name == "ThingsMode")
addcommentgroup.Enabled = (General.Map.Map.SelectedThingsCount > 0);
}
// Focus lost
private void grid_Leave(object sender, EventArgs e)
{
preventupdate = false;
}
#endregion
}
}