UltimateZoneBuilder/Source/Core/Controls/DockersControl.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

456 lines
12 KiB
C#

#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 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.Drawing;
using System.Windows.Forms;
#endregion
namespace CodeImp.DoomBuilder.Controls
{
internal partial class DockersControl : UserControl
{
#region ================== Constants
#endregion
#region ================== Delegates
public event EventHandler MouseContainerEnter;
public event EventHandler MouseContainerLeave;
public event EventHandler Collapsed;
public event EventHandler Expanded;
public event EventHandler UserResize;
#endregion
#region ================== Variables
// Behaviour
private bool rightalign;
private bool iscollapsed;
// Collapsing
private int expandedwidth; // width when expanded
private int expandedtab; // selected tab index when expanded
// Splitting
private int splitstartoffset;
// Selection
private string currentselected;
private string previousselected;
private bool controlledselection;
#endregion
#region ================== Properties
public bool IsCollpased { get { return iscollapsed; } }
// This returns true when the focus is here, but not in some special cases
public bool IsFocused
{
get
{
Control ac = FindActiveControl();
// We have focus when we need the keyboard for input
// Otherwise we don't want the focus and the docker may collapse
return (ac is TextBox) || (ac is RichTextBox) || (ac is NumericUpDown) || (ac is ComboBox);
}
}
#endregion
#region ================== Constructor
// Constructor
public DockersControl()
{
InitializeComponent();
expandedwidth = (int)(this.Width * (this.CurrentAutoScaleDimensions.Width / this.AutoScaleDimensions.Width));
tabs.TabsOffsetTop = buttonTogglePinning.Bottom + 2; //mxd
if(General.Settings != null)
buttonTogglePinning.Image = General.Settings.CollapseDockers ? Properties.Resources.Unpin : Properties.Resources.Pin; //mxd
}
#endregion
#region ================== Methods
// This returns the active child control
private Control FindActiveControl()
{
Control c = this.ActiveControl;
while(c is IContainerControl)
{
IContainerControl cc = (c as IContainerControl);
if(cc.ActiveControl != null)
c = cc.ActiveControl;
else
break;
}
return c;
}
// This sets up the controls for left or right alignment
public void Setup(bool right)
{
rightalign = right;
if(rightalign)
{
splitter.Dock = DockStyle.Left;
tabs.Alignment = TabAlignment.Right;
tabs.Location = new Point(0, 0);
buttonTogglePinning.Location = new Point(this.ClientRectangle.Width - buttonTogglePinning.Width - 2, buttonTogglePinning.Top); //mxd
buttonTogglePinning.Anchor = AnchorStyles.Right | AnchorStyles.Top; //mxd
tabs.Size = new Size(this.ClientRectangle.Width + 2, this.ClientRectangle.Height);
}
else
{
splitter.Dock = DockStyle.Right;
tabs.Alignment = TabAlignment.Left;
tabs.Location = new Point(-2, 0);
buttonTogglePinning.Location = new Point(2, buttonTogglePinning.Top); //mxd
buttonTogglePinning.Anchor = AnchorStyles.Left | AnchorStyles.Top; //mxd
tabs.Size = new Size(this.ClientRectangle.Width + 2, this.ClientRectangle.Height);
}
tabs.SendToBack();
}
// This collapses the docker
public void Collapse()
{
if(iscollapsed) return;
controlledselection = true;
splitter.Enabled = false;
splitter.BackColor = SystemColors.Control;
splitter.Width = (int)(2.0f * (this.CurrentAutoScaleDimensions.Width / this.AutoScaleDimensions.Width));
expandedtab = tabs.SelectedIndex;
expandedwidth = this.Width;
tabs.SelectedIndex = -1;
General.MainWindow.LockUpdate();
if(rightalign) this.Left = this.Right - GetCollapsedWidth();
this.Width = GetCollapsedWidth();
General.MainWindow.UnlockUpdate();
this.Invalidate(true);
controlledselection = false;
iscollapsed = true;
if(Collapsed != null) Collapsed(this, EventArgs.Empty);
}
// This expands the docker
public void Expand()
{
if(!iscollapsed) return;
controlledselection = true;
splitter.Enabled = true;
splitter.BackColor = Color.Transparent;
splitter.Width = (int)(4.0f * (this.CurrentAutoScaleDimensions.Width / this.AutoScaleDimensions.Width));
General.MainWindow.LockUpdate();
if(rightalign) this.Left = this.Right - expandedwidth;
this.Width = expandedwidth;
General.MainWindow.UnlockUpdate();
tabs.SelectedIndex = expandedtab;
tabs.Invalidate(true);
controlledselection = false;
iscollapsed = false;
if(Expanded != null) Expanded(this, EventArgs.Empty);
}
// This calculates the collapsed width
public int GetCollapsedWidth()
{
Rectangle r;
if(tabs.TabPages.Count > 0)
r = tabs.GetTabRect(0);
else
r = new Rectangle(0, 0, 26, 26);
return r.Width + (int)(1.0f * (this.CurrentAutoScaleDimensions.Width / this.AutoScaleDimensions.Width));
}
// This adds a docker
public void Add(Docker d)
{
// Set up page
TabPage page = new TabPage(d.Title);
page.SuspendLayout();
page.Font = this.Font;
page.Tag = d;
page.UseVisualStyleBackColor = false;
page.Controls.Add(d.Control);
d.Control.Dock = DockStyle.Fill;
tabs.TabPages.Add(page);
page.ResumeLayout(true);
if(iscollapsed) tabs.SelectedIndex = -1;
// Go for all controls to add events
Queue<Control> todo = new Queue<Control>();
todo.Enqueue(d.Control);
while(todo.Count > 0)
{
Control c = todo.Dequeue();
c.MouseEnter += RaiseMouseContainerEnter;
c.MouseLeave += RaiseMouseContainerLeave;
foreach(Control cc in c.Controls)
todo.Enqueue(cc);
}
}
// This removes a docker
public bool Remove(Docker d)
{
foreach(TabPage page in tabs.TabPages)
{
if((page.Tag as Docker) == d)
{
// Go for all controls to remove events
Queue<Control> todo = new Queue<Control>();
todo.Enqueue(d.Control);
while(todo.Count > 0)
{
Control c = todo.Dequeue();
c.MouseEnter -= RaiseMouseContainerEnter;
c.MouseLeave -= RaiseMouseContainerLeave;
foreach(Control cc in c.Controls)
todo.Enqueue(cc);
}
// Take down that page
if(page == tabs.SelectedTab) SelectPrevious();
page.Controls.Clear();
tabs.TabPages.Remove(page);
return true;
}
}
return false;
}
//mxd. This checks if given docker exists in this control
public bool Contains(Docker d) {
foreach (TabPage page in tabs.TabPages) {
if ((page.Tag as Docker) == d) return true;
}
return false;
}
// This selects a docker
public bool SelectDocker(Docker d)
{
int index = 0;
foreach(TabPage page in tabs.TabPages)
{
if((page.Tag as Docker) == d)
{
if(iscollapsed)
{
previousselected = currentselected;
expandedtab = index;
}
else
tabs.SelectedTab = page;
return true;
}
index++;
}
return false;
}
// This selectes the previous docker
public void SelectPrevious()
{
if(!string.IsNullOrEmpty(previousselected))
{
int index = 0;
foreach(TabPage page in tabs.TabPages)
{
if((page.Tag as Docker).FullName == previousselected)
{
if(iscollapsed)
{
previousselected = currentselected;
expandedtab = index;
}
else
tabs.SelectedTab = page;
break;
}
index++;
}
}
}
// This sorts tabs by their full name
public void SortTabs(IEnumerable<string> fullnames)
{
Dictionary<string, TabPage> pages = new Dictionary<string, TabPage>(tabs.TabPages.Count, StringComparer.Ordinal);
foreach(TabPage p in tabs.TabPages) pages.Add((p.Tag as Docker).FullName, p);
tabs.TabPages.Clear();
// Add tabs in order as in fullnames
foreach(string name in fullnames)
{
if(pages.ContainsKey(name))
{
tabs.TabPages.Add(pages[name]);
pages.Remove(name);
}
}
// Add remaining tabs
foreach(KeyValuePair<string, TabPage> p in pages)
tabs.TabPages.Add(p.Value);
}
#endregion
#region ================== Events
// This raises the MouseContainerEnter event
private void RaiseMouseContainerEnter(object sender, EventArgs e)
{
if(MouseContainerEnter != null)
MouseContainerEnter(sender, e);
}
// This raises the MouseContainerLeave event
private void RaiseMouseContainerLeave(object sender, EventArgs e)
{
if(MouseContainerLeave != null)
MouseContainerLeave(sender, e);
}
// We don't want the focus
private void tabs_Enter(object sender, EventArgs e) { General.MainWindow.FocusDisplay(); }
private void tabs_MouseUp(object sender, MouseEventArgs e) { General.MainWindow.FocusDisplay(); }
private void tabs_Selected(object sender, TabControlEventArgs e) { General.MainWindow.FocusDisplay(); }
// Tab selected
private void tabs_SelectedIndexChanged(object sender, EventArgs e)
{
if(!controlledselection)
{
// Keep track of previous selected tab
previousselected = currentselected;
if(tabs.SelectedTab != null)
{
Docker d = (tabs.SelectedTab.Tag as Docker);
currentselected = d.FullName;
}
else
{
currentselected = null;
}
}
General.MainWindow.FocusDisplay();
}
// Splitting begins
private void splitter_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Left)
{
splitstartoffset = e.X;
splitter.BackColor = SystemColors.Highlight;
}
}
// Splitting ends
private void splitter_MouseUp(object sender, MouseEventArgs e)
{
splitter.BackColor = Color.Transparent;
tabs.Invalidate(true);
this.Update();
General.MainWindow.RedrawDisplay();
General.MainWindow.Update();
}
// Splitting dragged
private void splitter_MouseMove(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Left)
{
General.MainWindow.LockUpdate();
// Resize the control
int delta = e.X - splitstartoffset;
int collapsedwidth = GetCollapsedWidth();
if(rightalign)
{
if((this.Width > collapsedwidth) || (delta < 0))
{
this.Left += delta;
this.Width -= delta;
if(this.Width < collapsedwidth)
{
this.Left -= collapsedwidth - this.Width;
this.Width = collapsedwidth;
}
}
}
else
{
if((this.Width > collapsedwidth) || (delta > 0))
{
this.Width += delta;
if(this.Width < collapsedwidth)
this.Width = collapsedwidth;
}
}
General.MainWindow.UnlockUpdate();
this.Update();
General.MainWindow.RedrawDisplay();
General.MainWindow.Update();
// Raise event
if(UserResize != null)
UserResize(this, EventArgs.Empty);
}
}
//mxd
private void buttonTogglePinning_Click(object sender, EventArgs e) {
General.Settings.CollapseDockers = !General.Settings.CollapseDockers;
General.MainWindow.SetupInterface();
buttonTogglePinning.Image = General.Settings.CollapseDockers ? Properties.Resources.Unpin : Properties.Resources.Pin;
}
#endregion
}
}