You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1278 lines
36 KiB
C#
1278 lines
36 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Windows.Forms;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Permissions;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
namespace Mesnac.Docking
|
|
{
|
|
[ToolboxItem(false)]
|
|
public partial class DockPane : UserControl, IDockDragSource
|
|
{
|
|
public enum AppearanceStyle
|
|
{
|
|
ToolWindow,
|
|
Document
|
|
}
|
|
|
|
private enum HitTestArea
|
|
{
|
|
Caption,
|
|
TabStrip,
|
|
Content,
|
|
None
|
|
}
|
|
|
|
private struct HitTestResult
|
|
{
|
|
public HitTestArea HitArea;
|
|
public int Index;
|
|
|
|
public HitTestResult(HitTestArea hitTestArea, int index)
|
|
{
|
|
HitArea = hitTestArea;
|
|
Index = index;
|
|
}
|
|
}
|
|
|
|
private DockPaneCaptionBase m_captionControl;
|
|
private DockPaneCaptionBase CaptionControl
|
|
{
|
|
get { return m_captionControl; }
|
|
}
|
|
|
|
private DockPaneStripBase m_tabStripControl;
|
|
internal DockPaneStripBase TabStripControl
|
|
{
|
|
get { return m_tabStripControl; }
|
|
}
|
|
|
|
internal protected DockPane(IDockContent content, DockState visibleState, bool show)
|
|
{
|
|
InternalConstruct(content, visibleState, false, Rectangle.Empty, null, DockAlignment.Right, 0.5, show);
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")]
|
|
internal protected DockPane(IDockContent content, FloatWindow floatWindow, bool show)
|
|
{
|
|
if (floatWindow == null)
|
|
throw new ArgumentNullException("floatWindow");
|
|
|
|
InternalConstruct(content, DockState.Float, false, Rectangle.Empty, floatWindow.NestedPanes.GetDefaultPreviousPane(this), DockAlignment.Right, 0.5, show);
|
|
}
|
|
|
|
internal protected DockPane(IDockContent content, DockPane previousPane, DockAlignment alignment, double proportion, bool show)
|
|
{
|
|
if (previousPane == null)
|
|
throw(new ArgumentNullException("previousPane"));
|
|
InternalConstruct(content, previousPane.DockState, false, Rectangle.Empty, previousPane, alignment, proportion, show);
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")]
|
|
internal protected DockPane(IDockContent content, Rectangle floatWindowBounds, bool show)
|
|
{
|
|
InternalConstruct(content, DockState.Float, true, floatWindowBounds, null, DockAlignment.Right, 0.5, show);
|
|
}
|
|
|
|
private void InternalConstruct(IDockContent content, DockState dockState, bool flagBounds, Rectangle floatWindowBounds, DockPane prevPane, DockAlignment alignment, double proportion, bool show)
|
|
{
|
|
if (dockState == DockState.Hidden || dockState == DockState.Unknown)
|
|
throw new ArgumentException(Strings.DockPane_SetDockState_InvalidState);
|
|
|
|
if (content == null)
|
|
throw new ArgumentNullException(Strings.DockPane_Constructor_NullContent);
|
|
|
|
if (content.DockHandler.DockPanel == null)
|
|
throw new ArgumentException(Strings.DockPane_Constructor_NullDockPanel);
|
|
|
|
|
|
SuspendLayout();
|
|
SetStyle(ControlStyles.Selectable, false);
|
|
|
|
m_isFloat = (dockState == DockState.Float);
|
|
|
|
m_contents = new DockContentCollection();
|
|
m_displayingContents = new DockContentCollection(this);
|
|
m_dockPanel = content.DockHandler.DockPanel;
|
|
m_dockPanel.AddPane(this);
|
|
|
|
m_splitter = new SplitterControl(this);
|
|
|
|
m_nestedDockingStatus = new NestedDockingStatus(this);
|
|
|
|
m_captionControl = DockPanel.DockPaneCaptionFactory.CreateDockPaneCaption(this);
|
|
m_tabStripControl = DockPanel.DockPaneStripFactory.CreateDockPaneStrip(this);
|
|
Controls.AddRange(new Control[] { m_captionControl, m_tabStripControl });
|
|
|
|
DockPanel.SuspendLayout(true);
|
|
if (flagBounds)
|
|
FloatWindow = DockPanel.FloatWindowFactory.CreateFloatWindow(DockPanel, this, floatWindowBounds);
|
|
else if (prevPane != null)
|
|
DockTo(prevPane.NestedPanesContainer, prevPane, alignment, proportion);
|
|
|
|
SetDockState(dockState);
|
|
if (show)
|
|
content.DockHandler.Pane = this;
|
|
else if (this.IsFloat)
|
|
content.DockHandler.FloatPane = this;
|
|
else
|
|
content.DockHandler.PanelPane = this;
|
|
|
|
ResumeLayout();
|
|
DockPanel.ResumeLayout(true, true);
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
m_dockState = DockState.Unknown;
|
|
|
|
if (NestedPanesContainer != null)
|
|
NestedPanesContainer.NestedPanes.Remove(this);
|
|
|
|
if (DockPanel != null)
|
|
{
|
|
DockPanel.RemovePane(this);
|
|
m_dockPanel = null;
|
|
}
|
|
|
|
Splitter.Dispose();
|
|
if (m_autoHidePane != null)
|
|
m_autoHidePane.Dispose();
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
private IDockContent m_activeContent = null;
|
|
public virtual IDockContent ActiveContent
|
|
{
|
|
get { return m_activeContent; }
|
|
set
|
|
{
|
|
if (ActiveContent == value)
|
|
return;
|
|
|
|
if (value != null)
|
|
{
|
|
if (!DisplayingContents.Contains(value))
|
|
throw(new InvalidOperationException(Strings.DockPane_ActiveContent_InvalidValue));
|
|
}
|
|
else
|
|
{
|
|
if (DisplayingContents.Count != 0)
|
|
throw(new InvalidOperationException(Strings.DockPane_ActiveContent_InvalidValue));
|
|
}
|
|
|
|
IDockContent oldValue = m_activeContent;
|
|
|
|
if (DockPanel.ActiveAutoHideContent == oldValue)
|
|
DockPanel.ActiveAutoHideContent = null;
|
|
|
|
m_activeContent = value;
|
|
|
|
if (DockPanel.DocumentStyle == DocumentStyle.DockingMdi && DockState == DockState.Document)
|
|
{
|
|
if (m_activeContent != null)
|
|
m_activeContent.DockHandler.Form.BringToFront();
|
|
}
|
|
else
|
|
{
|
|
if (m_activeContent != null)
|
|
m_activeContent.DockHandler.SetVisible();
|
|
if (oldValue != null && DisplayingContents.Contains(oldValue))
|
|
oldValue.DockHandler.SetVisible();
|
|
if (IsActivated && m_activeContent != null)
|
|
m_activeContent.DockHandler.Activate();
|
|
}
|
|
|
|
if (FloatWindow != null)
|
|
FloatWindow.SetText();
|
|
|
|
if (DockPanel.DocumentStyle == DocumentStyle.DockingMdi &&
|
|
DockState == DockState.Document)
|
|
RefreshChanges(false); // delayed layout to reduce screen flicker
|
|
else
|
|
RefreshChanges();
|
|
|
|
if (m_activeContent != null)
|
|
TabStripControl.EnsureTabVisible(m_activeContent);
|
|
}
|
|
}
|
|
|
|
private bool m_allowDockDragAndDrop = true;
|
|
public virtual bool AllowDockDragAndDrop
|
|
{
|
|
get { return m_allowDockDragAndDrop; }
|
|
set { m_allowDockDragAndDrop = value; }
|
|
}
|
|
|
|
private IDisposable m_autoHidePane = null;
|
|
internal IDisposable AutoHidePane
|
|
{
|
|
get { return m_autoHidePane; }
|
|
set { m_autoHidePane = value; }
|
|
}
|
|
|
|
private object m_autoHideTabs = null;
|
|
internal object AutoHideTabs
|
|
{
|
|
get { return m_autoHideTabs; }
|
|
set { m_autoHideTabs = value; }
|
|
}
|
|
|
|
private object TabPageContextMenu
|
|
{
|
|
get
|
|
{
|
|
IDockContent content = ActiveContent;
|
|
|
|
if (content == null)
|
|
return null;
|
|
|
|
if (content.DockHandler.TabPageContextMenuStrip != null)
|
|
return content.DockHandler.TabPageContextMenuStrip;
|
|
else if (content.DockHandler.TabPageContextMenu != null)
|
|
return content.DockHandler.TabPageContextMenu;
|
|
else
|
|
return null;
|
|
}
|
|
}
|
|
|
|
internal bool HasTabPageContextMenu
|
|
{
|
|
get { return TabPageContextMenu != null; }
|
|
}
|
|
|
|
internal void ShowTabPageContextMenu(Control control, Point position)
|
|
{
|
|
object menu = TabPageContextMenu;
|
|
|
|
if (menu == null)
|
|
return;
|
|
|
|
ContextMenuStrip contextMenuStrip = menu as ContextMenuStrip;
|
|
if (contextMenuStrip != null)
|
|
{
|
|
contextMenuStrip.Show(control, position);
|
|
return;
|
|
}
|
|
|
|
ContextMenu contextMenu = menu as ContextMenu;
|
|
if (contextMenu != null)
|
|
contextMenu.Show(this, position);
|
|
}
|
|
|
|
private Rectangle CaptionRectangle
|
|
{
|
|
get
|
|
{
|
|
if (!HasCaption)
|
|
return Rectangle.Empty;
|
|
|
|
Rectangle rectWindow = DisplayingRectangle;
|
|
int x, y, width;
|
|
x = rectWindow.X;
|
|
y = rectWindow.Y;
|
|
width = rectWindow.Width;
|
|
int height = CaptionControl.MeasureHeight();
|
|
|
|
return new Rectangle(x, y, width, height);
|
|
}
|
|
}
|
|
|
|
internal Rectangle ContentRectangle
|
|
{
|
|
get
|
|
{
|
|
Rectangle rectWindow = DisplayingRectangle;
|
|
Rectangle rectCaption = CaptionRectangle;
|
|
Rectangle rectTabStrip = TabStripRectangle;
|
|
|
|
int x = rectWindow.X;
|
|
int y = rectWindow.Y + (rectCaption.IsEmpty ? 0 : rectCaption.Height) +
|
|
(DockState == DockState.Document ? rectTabStrip.Height : 0);
|
|
int width = rectWindow.Width;
|
|
int height = rectWindow.Height - rectCaption.Height - rectTabStrip.Height;
|
|
|
|
return new Rectangle(x, y, width, height);
|
|
}
|
|
}
|
|
|
|
internal Rectangle TabStripRectangle
|
|
{
|
|
get
|
|
{
|
|
if (Appearance == AppearanceStyle.ToolWindow)
|
|
return TabStripRectangle_ToolWindow;
|
|
else
|
|
return TabStripRectangle_Document;
|
|
}
|
|
}
|
|
|
|
private Rectangle TabStripRectangle_ToolWindow
|
|
{
|
|
get
|
|
{
|
|
if (DisplayingContents.Count <= 1 || IsAutoHide)
|
|
return Rectangle.Empty;
|
|
|
|
Rectangle rectWindow = DisplayingRectangle;
|
|
|
|
int width = rectWindow.Width;
|
|
int height = TabStripControl.MeasureHeight();
|
|
int x = rectWindow.X;
|
|
int y = rectWindow.Bottom - height;
|
|
Rectangle rectCaption = CaptionRectangle;
|
|
if (rectCaption.Contains(x, y))
|
|
y = rectCaption.Y + rectCaption.Height;
|
|
|
|
return new Rectangle(x, y, width, height);
|
|
}
|
|
}
|
|
|
|
private Rectangle TabStripRectangle_Document
|
|
{
|
|
get
|
|
{
|
|
if (DisplayingContents.Count == 0)
|
|
return Rectangle.Empty;
|
|
|
|
if (DisplayingContents.Count == 1 && DockPanel.DocumentStyle == DocumentStyle.DockingSdi)
|
|
return Rectangle.Empty;
|
|
|
|
Rectangle rectWindow = DisplayingRectangle;
|
|
int x = rectWindow.X;
|
|
int y = rectWindow.Y;
|
|
int width = rectWindow.Width;
|
|
int height = TabStripControl.MeasureHeight();
|
|
|
|
return new Rectangle(x, y, width, height);
|
|
}
|
|
}
|
|
|
|
public virtual string CaptionText
|
|
{
|
|
get { return ActiveContent == null ? string.Empty : ActiveContent.DockHandler.TabText; }
|
|
}
|
|
|
|
private DockContentCollection m_contents;
|
|
public DockContentCollection Contents
|
|
{
|
|
get { return m_contents; }
|
|
}
|
|
|
|
private DockContentCollection m_displayingContents;
|
|
public DockContentCollection DisplayingContents
|
|
{
|
|
get { return m_displayingContents; }
|
|
}
|
|
|
|
private DockPanel m_dockPanel;
|
|
public DockPanel DockPanel
|
|
{
|
|
get { return m_dockPanel; }
|
|
}
|
|
|
|
private bool HasCaption
|
|
{
|
|
get
|
|
{
|
|
if (DockState == DockState.Document ||
|
|
DockState == DockState.Hidden ||
|
|
DockState == DockState.Unknown ||
|
|
(DockState == DockState.Float && FloatWindow.VisibleNestedPanes.Count <= 1))
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private bool m_isActivated = false;
|
|
public bool IsActivated
|
|
{
|
|
get { return m_isActivated; }
|
|
}
|
|
internal void SetIsActivated(bool value)
|
|
{
|
|
if (m_isActivated == value)
|
|
return;
|
|
|
|
m_isActivated = value;
|
|
if (DockState != DockState.Document)
|
|
RefreshChanges(false);
|
|
OnIsActivatedChanged(EventArgs.Empty);
|
|
}
|
|
|
|
private bool m_isActiveDocumentPane = false;
|
|
public bool IsActiveDocumentPane
|
|
{
|
|
get { return m_isActiveDocumentPane; }
|
|
}
|
|
internal void SetIsActiveDocumentPane(bool value)
|
|
{
|
|
if (m_isActiveDocumentPane == value)
|
|
return;
|
|
|
|
m_isActiveDocumentPane = value;
|
|
if (DockState == DockState.Document)
|
|
RefreshChanges();
|
|
OnIsActiveDocumentPaneChanged(EventArgs.Empty);
|
|
}
|
|
|
|
public bool IsDockStateValid(DockState dockState)
|
|
{
|
|
foreach (IDockContent content in Contents)
|
|
if (!content.DockHandler.IsDockStateValid(dockState))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool IsAutoHide
|
|
{
|
|
get { return DockHelper.IsDockStateAutoHide(DockState); }
|
|
}
|
|
|
|
public AppearanceStyle Appearance
|
|
{
|
|
get { return (DockState == DockState.Document) ? AppearanceStyle.Document : AppearanceStyle.ToolWindow; }
|
|
}
|
|
|
|
internal Rectangle DisplayingRectangle
|
|
{
|
|
get { return ClientRectangle; }
|
|
}
|
|
|
|
public void Activate()
|
|
{
|
|
if (DockHelper.IsDockStateAutoHide(DockState) && DockPanel.ActiveAutoHideContent != ActiveContent)
|
|
DockPanel.ActiveAutoHideContent = ActiveContent;
|
|
else if (!IsActivated && ActiveContent != null)
|
|
ActiveContent.DockHandler.Activate();
|
|
}
|
|
|
|
internal void AddContent(IDockContent content)
|
|
{
|
|
if (Contents.Contains(content))
|
|
return;
|
|
|
|
Contents.Add(content);
|
|
}
|
|
|
|
internal void Close()
|
|
{
|
|
Dispose();
|
|
}
|
|
|
|
public void CloseActiveContent()
|
|
{
|
|
CloseContent(ActiveContent);
|
|
}
|
|
|
|
internal void CloseContent(IDockContent content)
|
|
{
|
|
DockPanel dockPanel = DockPanel;
|
|
dockPanel.SuspendLayout(true);
|
|
|
|
if (content == null)
|
|
return;
|
|
|
|
if (!content.DockHandler.CloseButton)
|
|
return;
|
|
|
|
if (content.DockHandler.HideOnClose)
|
|
content.DockHandler.Hide();
|
|
else
|
|
content.DockHandler.Close();
|
|
|
|
dockPanel.ResumeLayout(true, true);
|
|
}
|
|
|
|
private HitTestResult GetHitTest(Point ptMouse)
|
|
{
|
|
Point ptMouseClient = PointToClient(ptMouse);
|
|
|
|
Rectangle rectCaption = CaptionRectangle;
|
|
if (rectCaption.Contains(ptMouseClient))
|
|
return new HitTestResult(HitTestArea.Caption, -1);
|
|
|
|
Rectangle rectContent = ContentRectangle;
|
|
if (rectContent.Contains(ptMouseClient))
|
|
return new HitTestResult(HitTestArea.Content, -1);
|
|
|
|
Rectangle rectTabStrip = TabStripRectangle;
|
|
if (rectTabStrip.Contains(ptMouseClient))
|
|
return new HitTestResult(HitTestArea.TabStrip, TabStripControl.HitTest(TabStripControl.PointToClient(ptMouse)));
|
|
|
|
return new HitTestResult(HitTestArea.None, -1);
|
|
}
|
|
|
|
private bool m_isHidden = true;
|
|
public bool IsHidden
|
|
{
|
|
get { return m_isHidden; }
|
|
}
|
|
private void SetIsHidden(bool value)
|
|
{
|
|
if (m_isHidden == value)
|
|
return;
|
|
|
|
m_isHidden = value;
|
|
if (DockHelper.IsDockStateAutoHide(DockState))
|
|
{
|
|
DockPanel.RefreshAutoHideStrip();
|
|
DockPanel.PerformLayout();
|
|
}
|
|
else if (NestedPanesContainer != null)
|
|
((Control)NestedPanesContainer).PerformLayout();
|
|
}
|
|
|
|
protected override void OnLayout(LayoutEventArgs levent)
|
|
{
|
|
SetIsHidden(DisplayingContents.Count == 0);
|
|
if (!IsHidden)
|
|
{
|
|
CaptionControl.Bounds = CaptionRectangle;
|
|
TabStripControl.Bounds = TabStripRectangle;
|
|
|
|
SetContentBounds();
|
|
|
|
foreach (IDockContent content in Contents)
|
|
{
|
|
if (DisplayingContents.Contains(content))
|
|
if (content.DockHandler.FlagClipWindow && content.DockHandler.Form.Visible)
|
|
content.DockHandler.FlagClipWindow = false;
|
|
}
|
|
}
|
|
|
|
base.OnLayout(levent);
|
|
}
|
|
|
|
internal void SetContentBounds()
|
|
{
|
|
Rectangle rectContent = ContentRectangle;
|
|
if (DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.DockingMdi)
|
|
rectContent = DockPanel.RectangleToMdiClient(RectangleToScreen(rectContent));
|
|
|
|
Rectangle rectInactive = new Rectangle(-rectContent.Width, rectContent.Y, rectContent.Width, rectContent.Height);
|
|
foreach (IDockContent content in Contents)
|
|
if (content.DockHandler.Pane == this)
|
|
{
|
|
if (content == ActiveContent)
|
|
content.DockHandler.Form.Bounds = rectContent;
|
|
else
|
|
content.DockHandler.Form.Bounds = rectInactive;
|
|
}
|
|
}
|
|
|
|
internal void RefreshChanges()
|
|
{
|
|
RefreshChanges(true);
|
|
}
|
|
|
|
private void RefreshChanges(bool performLayout)
|
|
{
|
|
if (IsDisposed)
|
|
return;
|
|
|
|
CaptionControl.RefreshChanges();
|
|
TabStripControl.RefreshChanges();
|
|
if (DockState == DockState.Float)
|
|
FloatWindow.RefreshChanges();
|
|
if (DockHelper.IsDockStateAutoHide(DockState) && DockPanel != null)
|
|
{
|
|
DockPanel.RefreshAutoHideStrip();
|
|
DockPanel.PerformLayout();
|
|
}
|
|
|
|
if (performLayout)
|
|
PerformLayout();
|
|
}
|
|
|
|
internal void RemoveContent(IDockContent content)
|
|
{
|
|
if (!Contents.Contains(content))
|
|
return;
|
|
|
|
Contents.Remove(content);
|
|
}
|
|
|
|
public void SetContentIndex(IDockContent content, int index)
|
|
{
|
|
int oldIndex = Contents.IndexOf(content);
|
|
if (oldIndex == -1)
|
|
throw(new ArgumentException(Strings.DockPane_SetContentIndex_InvalidContent));
|
|
|
|
if (index < 0 || index > Contents.Count - 1)
|
|
if (index != -1)
|
|
throw(new ArgumentOutOfRangeException(Strings.DockPane_SetContentIndex_InvalidIndex));
|
|
|
|
if (oldIndex == index)
|
|
return;
|
|
if (oldIndex == Contents.Count - 1 && index == -1)
|
|
return;
|
|
|
|
Contents.Remove(content);
|
|
if (index == -1)
|
|
Contents.Add(content);
|
|
else if (oldIndex < index)
|
|
Contents.AddAt(content, index - 1);
|
|
else
|
|
Contents.AddAt(content, index);
|
|
|
|
RefreshChanges();
|
|
}
|
|
|
|
private void SetParent()
|
|
{
|
|
if (DockState == DockState.Unknown || DockState == DockState.Hidden)
|
|
{
|
|
SetParent(null);
|
|
Splitter.Parent = null;
|
|
}
|
|
else if (DockState == DockState.Float)
|
|
{
|
|
SetParent(FloatWindow);
|
|
Splitter.Parent = FloatWindow;
|
|
}
|
|
else if (DockHelper.IsDockStateAutoHide(DockState))
|
|
{
|
|
SetParent(DockPanel.AutoHideControl);
|
|
Splitter.Parent = null;
|
|
}
|
|
else
|
|
{
|
|
SetParent(DockPanel.DockWindows[DockState]);
|
|
Splitter.Parent = Parent;
|
|
}
|
|
}
|
|
|
|
private void SetParent(Control value)
|
|
{
|
|
if (Parent == value)
|
|
return;
|
|
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// Workaround of .Net Framework bug:
|
|
// Change the parent of a control with focus may result in the first
|
|
// MDI child form get activated.
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
IDockContent contentFocused = GetFocusedContent();
|
|
if (contentFocused != null)
|
|
DockPanel.SaveFocus();
|
|
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
Parent = value;
|
|
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// Workaround of .Net Framework bug:
|
|
// Change the parent of a control with focus may result in the first
|
|
// MDI child form get activated.
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
if (contentFocused != null)
|
|
contentFocused.DockHandler.Activate();
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
}
|
|
|
|
public new void Show()
|
|
{
|
|
Activate();
|
|
}
|
|
|
|
internal void TestDrop(IDockDragSource dragSource, DockOutlineBase dockOutline)
|
|
{
|
|
if (!dragSource.CanDockTo(this))
|
|
return;
|
|
|
|
Point ptMouse = Control.MousePosition;
|
|
|
|
HitTestResult hitTestResult = GetHitTest(ptMouse);
|
|
if (hitTestResult.HitArea == HitTestArea.Caption)
|
|
dockOutline.Show(this, -1);
|
|
else if (hitTestResult.HitArea == HitTestArea.TabStrip && hitTestResult.Index != -1)
|
|
dockOutline.Show(this, hitTestResult.Index);
|
|
}
|
|
|
|
internal void ValidateActiveContent()
|
|
{
|
|
if (ActiveContent == null)
|
|
{
|
|
if (DisplayingContents.Count != 0)
|
|
ActiveContent = DisplayingContents[0];
|
|
return;
|
|
}
|
|
|
|
if (DisplayingContents.IndexOf(ActiveContent) >= 0)
|
|
return;
|
|
|
|
IDockContent prevVisible = null;
|
|
for (int i=Contents.IndexOf(ActiveContent)-1; i>=0; i--)
|
|
if (Contents[i].DockHandler.DockState == DockState)
|
|
{
|
|
prevVisible = Contents[i];
|
|
break;
|
|
}
|
|
|
|
IDockContent nextVisible = null;
|
|
for (int i=Contents.IndexOf(ActiveContent)+1; i<Contents.Count; i++)
|
|
if (Contents[i].DockHandler.DockState == DockState)
|
|
{
|
|
nextVisible = Contents[i];
|
|
break;
|
|
}
|
|
|
|
if (prevVisible != null)
|
|
ActiveContent = prevVisible;
|
|
else if (nextVisible != null)
|
|
ActiveContent = nextVisible;
|
|
else
|
|
ActiveContent = null;
|
|
}
|
|
|
|
private static readonly object DockStateChangedEvent = new object();
|
|
public event EventHandler DockStateChanged
|
|
{
|
|
add { Events.AddHandler(DockStateChangedEvent, value); }
|
|
remove { Events.RemoveHandler(DockStateChangedEvent, value); }
|
|
}
|
|
protected virtual void OnDockStateChanged(EventArgs e)
|
|
{
|
|
EventHandler handler = (EventHandler)Events[DockStateChangedEvent];
|
|
if (handler != null)
|
|
handler(this, e);
|
|
}
|
|
|
|
private static readonly object IsActivatedChangedEvent = new object();
|
|
public event EventHandler IsActivatedChanged
|
|
{
|
|
add { Events.AddHandler(IsActivatedChangedEvent, value); }
|
|
remove { Events.RemoveHandler(IsActivatedChangedEvent, value); }
|
|
}
|
|
protected virtual void OnIsActivatedChanged(EventArgs e)
|
|
{
|
|
EventHandler handler = (EventHandler)Events[IsActivatedChangedEvent];
|
|
if (handler != null)
|
|
handler(this, e);
|
|
}
|
|
|
|
private static readonly object IsActiveDocumentPaneChangedEvent = new object();
|
|
public event EventHandler IsActiveDocumentPaneChanged
|
|
{
|
|
add { Events.AddHandler(IsActiveDocumentPaneChangedEvent, value); }
|
|
remove { Events.RemoveHandler(IsActiveDocumentPaneChangedEvent, value); }
|
|
}
|
|
protected virtual void OnIsActiveDocumentPaneChanged(EventArgs e)
|
|
{
|
|
EventHandler handler = (EventHandler)Events[IsActiveDocumentPaneChangedEvent];
|
|
if (handler != null)
|
|
handler(this, e);
|
|
}
|
|
|
|
public DockWindow DockWindow
|
|
{
|
|
get { return (m_nestedDockingStatus.NestedPanes == null) ? null : m_nestedDockingStatus.NestedPanes.Container as DockWindow; }
|
|
set
|
|
{
|
|
DockWindow oldValue = DockWindow;
|
|
if (oldValue == value)
|
|
return;
|
|
|
|
DockTo(value);
|
|
}
|
|
}
|
|
|
|
public FloatWindow FloatWindow
|
|
{
|
|
get { return (m_nestedDockingStatus.NestedPanes == null) ? null : m_nestedDockingStatus.NestedPanes.Container as FloatWindow; }
|
|
set
|
|
{
|
|
FloatWindow oldValue = FloatWindow;
|
|
if (oldValue == value)
|
|
return;
|
|
|
|
DockTo(value);
|
|
}
|
|
}
|
|
|
|
private NestedDockingStatus m_nestedDockingStatus;
|
|
public NestedDockingStatus NestedDockingStatus
|
|
{
|
|
get { return m_nestedDockingStatus; }
|
|
}
|
|
|
|
private bool m_isFloat;
|
|
public bool IsFloat
|
|
{
|
|
get { return m_isFloat; }
|
|
}
|
|
|
|
public INestedPanesContainer NestedPanesContainer
|
|
{
|
|
get
|
|
{
|
|
if (NestedDockingStatus.NestedPanes == null)
|
|
return null;
|
|
else
|
|
return NestedDockingStatus.NestedPanes.Container;
|
|
}
|
|
}
|
|
|
|
private DockState m_dockState = DockState.Unknown;
|
|
public DockState DockState
|
|
{
|
|
get { return m_dockState; }
|
|
set
|
|
{
|
|
SetDockState(value);
|
|
}
|
|
}
|
|
|
|
public DockPane SetDockState(DockState value)
|
|
{
|
|
if (value == DockState.Unknown || value == DockState.Hidden)
|
|
throw new InvalidOperationException(Strings.DockPane_SetDockState_InvalidState);
|
|
|
|
if ((value == DockState.Float) == this.IsFloat)
|
|
{
|
|
InternalSetDockState(value);
|
|
return this;
|
|
}
|
|
|
|
if (DisplayingContents.Count == 0)
|
|
return null;
|
|
|
|
IDockContent firstContent = null;
|
|
for (int i=0; i<DisplayingContents.Count; i++)
|
|
{
|
|
IDockContent content = DisplayingContents[i];
|
|
if (content.DockHandler.IsDockStateValid(value))
|
|
{
|
|
firstContent = content;
|
|
break;
|
|
}
|
|
}
|
|
if (firstContent == null)
|
|
return null;
|
|
|
|
firstContent.DockHandler.DockState = value;
|
|
DockPane pane = firstContent.DockHandler.Pane;
|
|
DockPanel.SuspendLayout(true);
|
|
for (int i=0; i<DisplayingContents.Count; i++)
|
|
{
|
|
IDockContent content = DisplayingContents[i];
|
|
if (content.DockHandler.IsDockStateValid(value))
|
|
content.DockHandler.Pane = pane;
|
|
}
|
|
DockPanel.ResumeLayout(true, true);
|
|
return pane;
|
|
}
|
|
|
|
private void InternalSetDockState(DockState value)
|
|
{
|
|
if (m_dockState == value)
|
|
return;
|
|
|
|
DockState oldDockState = m_dockState;
|
|
INestedPanesContainer oldContainer = NestedPanesContainer;
|
|
|
|
m_dockState = value;
|
|
|
|
SuspendRefreshStateChange();
|
|
|
|
IDockContent contentFocused = GetFocusedContent();
|
|
if (contentFocused != null)
|
|
DockPanel.SaveFocus();
|
|
|
|
if (!IsFloat)
|
|
DockWindow = DockPanel.DockWindows[DockState];
|
|
else if (FloatWindow == null)
|
|
FloatWindow = DockPanel.FloatWindowFactory.CreateFloatWindow(DockPanel, this);
|
|
|
|
if (contentFocused != null)
|
|
DockPanel.ContentFocusManager.Activate(contentFocused);
|
|
|
|
ResumeRefreshStateChange(oldContainer, oldDockState);
|
|
}
|
|
|
|
private int m_countRefreshStateChange = 0;
|
|
private void SuspendRefreshStateChange()
|
|
{
|
|
m_countRefreshStateChange ++;
|
|
DockPanel.SuspendLayout(true);
|
|
}
|
|
|
|
private void ResumeRefreshStateChange()
|
|
{
|
|
m_countRefreshStateChange --;
|
|
System.Diagnostics.Debug.Assert(m_countRefreshStateChange >= 0);
|
|
DockPanel.ResumeLayout(true, true);
|
|
}
|
|
|
|
private bool IsRefreshStateChangeSuspended
|
|
{
|
|
get { return m_countRefreshStateChange != 0; }
|
|
}
|
|
|
|
private void ResumeRefreshStateChange(INestedPanesContainer oldContainer, DockState oldDockState)
|
|
{
|
|
ResumeRefreshStateChange();
|
|
RefreshStateChange(oldContainer, oldDockState);
|
|
}
|
|
|
|
private void RefreshStateChange(INestedPanesContainer oldContainer, DockState oldDockState)
|
|
{
|
|
lock (this)
|
|
{
|
|
if (IsRefreshStateChangeSuspended)
|
|
return;
|
|
|
|
SuspendRefreshStateChange();
|
|
}
|
|
|
|
DockPanel.SuspendLayout(true);
|
|
|
|
IDockContent contentFocused = GetFocusedContent();
|
|
if (contentFocused != null)
|
|
DockPanel.SaveFocus();
|
|
SetParent();
|
|
|
|
if (ActiveContent != null)
|
|
ActiveContent.DockHandler.SetDockState(ActiveContent.DockHandler.IsHidden, DockState, ActiveContent.DockHandler.Pane);
|
|
foreach (IDockContent content in Contents)
|
|
{
|
|
if (content.DockHandler.Pane == this)
|
|
content.DockHandler.SetDockState(content.DockHandler.IsHidden, DockState, content.DockHandler.Pane);
|
|
}
|
|
|
|
if (oldContainer != null)
|
|
{
|
|
Control oldContainerControl = (Control)oldContainer;
|
|
if (oldContainer.DockState == oldDockState && !oldContainerControl.IsDisposed)
|
|
oldContainerControl.PerformLayout();
|
|
}
|
|
if (DockHelper.IsDockStateAutoHide(oldDockState))
|
|
DockPanel.RefreshActiveAutoHideContent();
|
|
|
|
if (NestedPanesContainer.DockState == DockState)
|
|
((Control)NestedPanesContainer).PerformLayout();
|
|
if (DockHelper.IsDockStateAutoHide(DockState))
|
|
DockPanel.RefreshActiveAutoHideContent();
|
|
|
|
if (DockHelper.IsDockStateAutoHide(oldDockState) ||
|
|
DockHelper.IsDockStateAutoHide(DockState))
|
|
{
|
|
DockPanel.RefreshAutoHideStrip();
|
|
DockPanel.PerformLayout();
|
|
}
|
|
|
|
ResumeRefreshStateChange();
|
|
|
|
if (contentFocused != null)
|
|
contentFocused.DockHandler.Activate();
|
|
|
|
DockPanel.ResumeLayout(true, true);
|
|
|
|
if (oldDockState != DockState)
|
|
OnDockStateChanged(EventArgs.Empty);
|
|
}
|
|
|
|
private IDockContent GetFocusedContent()
|
|
{
|
|
IDockContent contentFocused = null;
|
|
foreach (IDockContent content in Contents)
|
|
{
|
|
if (content.DockHandler.Form.ContainsFocus)
|
|
{
|
|
contentFocused = content;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return contentFocused;
|
|
}
|
|
|
|
public DockPane DockTo(INestedPanesContainer container)
|
|
{
|
|
if (container == null)
|
|
throw new InvalidOperationException(Strings.DockPane_DockTo_NullContainer);
|
|
|
|
DockAlignment alignment;
|
|
if (container.DockState == DockState.DockLeft || container.DockState == DockState.DockRight)
|
|
alignment = DockAlignment.Bottom;
|
|
else
|
|
alignment = DockAlignment.Right;
|
|
|
|
return DockTo(container, container.NestedPanes.GetDefaultPreviousPane(this), alignment, 0.5);
|
|
}
|
|
|
|
public DockPane DockTo(INestedPanesContainer container, DockPane previousPane, DockAlignment alignment, double proportion)
|
|
{
|
|
if (container == null)
|
|
throw new InvalidOperationException(Strings.DockPane_DockTo_NullContainer);
|
|
|
|
if (container.IsFloat == this.IsFloat)
|
|
{
|
|
InternalAddToDockList(container, previousPane, alignment, proportion);
|
|
return this;
|
|
}
|
|
|
|
IDockContent firstContent = GetFirstContent(container.DockState);
|
|
if (firstContent == null)
|
|
return null;
|
|
|
|
DockPane pane;
|
|
DockPanel.DummyContent.DockPanel = DockPanel;
|
|
if (container.IsFloat)
|
|
pane = DockPanel.DockPaneFactory.CreateDockPane(DockPanel.DummyContent, (FloatWindow)container, true);
|
|
else
|
|
pane = DockPanel.DockPaneFactory.CreateDockPane(DockPanel.DummyContent, container.DockState, true);
|
|
|
|
pane.DockTo(container, previousPane, alignment, proportion);
|
|
SetVisibleContentsToPane(pane);
|
|
DockPanel.DummyContent.DockPanel = null;
|
|
|
|
return pane;
|
|
}
|
|
|
|
private void SetVisibleContentsToPane(DockPane pane)
|
|
{
|
|
SetVisibleContentsToPane(pane, ActiveContent);
|
|
}
|
|
|
|
private void SetVisibleContentsToPane(DockPane pane, IDockContent activeContent)
|
|
{
|
|
for (int i=0; i<DisplayingContents.Count; i++)
|
|
{
|
|
IDockContent content = DisplayingContents[i];
|
|
if (content.DockHandler.IsDockStateValid(pane.DockState))
|
|
{
|
|
content.DockHandler.Pane = pane;
|
|
i--;
|
|
}
|
|
}
|
|
|
|
if (activeContent.DockHandler.Pane == pane)
|
|
pane.ActiveContent = activeContent;
|
|
}
|
|
|
|
private void InternalAddToDockList(INestedPanesContainer container, DockPane prevPane, DockAlignment alignment, double proportion)
|
|
{
|
|
if ((container.DockState == DockState.Float) != IsFloat)
|
|
throw new InvalidOperationException(Strings.DockPane_DockTo_InvalidContainer);
|
|
|
|
int count = container.NestedPanes.Count;
|
|
if (container.NestedPanes.Contains(this))
|
|
count --;
|
|
if (prevPane == null && count > 0)
|
|
throw new InvalidOperationException(Strings.DockPane_DockTo_NullPrevPane);
|
|
|
|
if (prevPane != null && !container.NestedPanes.Contains(prevPane))
|
|
throw new InvalidOperationException(Strings.DockPane_DockTo_NoPrevPane);
|
|
|
|
if (prevPane == this)
|
|
throw new InvalidOperationException(Strings.DockPane_DockTo_SelfPrevPane);
|
|
|
|
INestedPanesContainer oldContainer = NestedPanesContainer;
|
|
DockState oldDockState = DockState;
|
|
container.NestedPanes.Add(this);
|
|
NestedDockingStatus.SetStatus(container.NestedPanes, prevPane, alignment, proportion);
|
|
|
|
if (DockHelper.IsDockWindowState(DockState))
|
|
m_dockState = container.DockState;
|
|
|
|
RefreshStateChange(oldContainer, oldDockState);
|
|
}
|
|
|
|
public void SetNestedDockingProportion(double proportion)
|
|
{
|
|
NestedDockingStatus.SetStatus(NestedDockingStatus.NestedPanes, NestedDockingStatus.PreviousPane, NestedDockingStatus.Alignment, proportion);
|
|
if (NestedPanesContainer != null)
|
|
((Control)NestedPanesContainer).PerformLayout();
|
|
}
|
|
|
|
public DockPane Float()
|
|
{
|
|
DockPanel.SuspendLayout(true);
|
|
|
|
IDockContent activeContent = ActiveContent;
|
|
|
|
DockPane floatPane = GetFloatPaneFromContents();
|
|
if (floatPane == null)
|
|
{
|
|
IDockContent firstContent = GetFirstContent(DockState.Float);
|
|
if (firstContent == null)
|
|
{
|
|
DockPanel.ResumeLayout(true, true);
|
|
return null;
|
|
}
|
|
floatPane = DockPanel.DockPaneFactory.CreateDockPane(firstContent,DockState.Float, true);
|
|
}
|
|
SetVisibleContentsToPane(floatPane, activeContent);
|
|
|
|
DockPanel.ResumeLayout(true, true);
|
|
return floatPane;
|
|
}
|
|
|
|
private DockPane GetFloatPaneFromContents()
|
|
{
|
|
DockPane floatPane = null;
|
|
for (int i=0; i<DisplayingContents.Count; i++)
|
|
{
|
|
IDockContent content = DisplayingContents[i];
|
|
if (!content.DockHandler.IsDockStateValid(DockState.Float))
|
|
continue;
|
|
|
|
if (floatPane != null && content.DockHandler.FloatPane != floatPane)
|
|
return null;
|
|
else
|
|
floatPane = content.DockHandler.FloatPane;
|
|
}
|
|
|
|
return floatPane;
|
|
}
|
|
|
|
private IDockContent GetFirstContent(DockState dockState)
|
|
{
|
|
for (int i=0; i<DisplayingContents.Count; i++)
|
|
{
|
|
IDockContent content = DisplayingContents[i];
|
|
if (content.DockHandler.IsDockStateValid(dockState))
|
|
return content;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void RestoreToPanel()
|
|
{
|
|
DockPanel.SuspendLayout(true);
|
|
|
|
IDockContent activeContent = DockPanel.ActiveContent;
|
|
|
|
for (int i=DisplayingContents.Count-1; i>=0; i--)
|
|
{
|
|
IDockContent content = DisplayingContents[i];
|
|
if (content.DockHandler.CheckDockState(false) != DockState.Unknown)
|
|
content.DockHandler.IsFloat = false;
|
|
}
|
|
|
|
DockPanel.ResumeLayout(true, true);
|
|
}
|
|
|
|
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
if (m.Msg == (int)Win32.Msgs.WM_MOUSEACTIVATE)
|
|
Activate();
|
|
|
|
base.WndProc(ref m);
|
|
}
|
|
|
|
#region IDockDragSource Members
|
|
|
|
#region IDragSource Members
|
|
|
|
Control IDragSource.DragControl
|
|
{
|
|
get { return this; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
bool IDockDragSource.IsDockStateValid(DockState dockState)
|
|
{
|
|
return IsDockStateValid(dockState);
|
|
}
|
|
|
|
bool IDockDragSource.CanDockTo(DockPane pane)
|
|
{
|
|
if (!IsDockStateValid(pane.DockState))
|
|
return false;
|
|
|
|
if (pane == this)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
Rectangle IDockDragSource.BeginDrag(Point ptMouse)
|
|
{
|
|
Point location = PointToScreen(new Point(0, 0));
|
|
Size size;
|
|
|
|
DockPane floatPane = ActiveContent.DockHandler.FloatPane;
|
|
if (DockState == DockState.Float || floatPane == null || floatPane.FloatWindow.NestedPanes.Count != 1)
|
|
size = DockPanel.DefaultFloatWindowSize;
|
|
else
|
|
size = floatPane.FloatWindow.Size;
|
|
|
|
if (ptMouse.X > location.X + size.Width)
|
|
location.X += ptMouse.X - (location.X + size.Width) + Measures.SplitterSize;
|
|
|
|
return new Rectangle(location, size);
|
|
}
|
|
|
|
public void FloatAt(Rectangle floatWindowBounds)
|
|
{
|
|
if (FloatWindow == null || FloatWindow.NestedPanes.Count != 1)
|
|
FloatWindow = DockPanel.FloatWindowFactory.CreateFloatWindow(DockPanel, this, floatWindowBounds);
|
|
else
|
|
FloatWindow.Bounds = floatWindowBounds;
|
|
|
|
DockState = DockState.Float;
|
|
}
|
|
|
|
public void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex)
|
|
{
|
|
if (dockStyle == DockStyle.Fill)
|
|
{
|
|
IDockContent activeContent = ActiveContent;
|
|
for (int i = Contents.Count - 1; i >= 0; i--)
|
|
{
|
|
IDockContent c = Contents[i];
|
|
c.DockHandler.Pane = pane;
|
|
if (contentIndex != -1)
|
|
pane.SetContentIndex(c, contentIndex);
|
|
}
|
|
pane.ActiveContent = activeContent;
|
|
}
|
|
else
|
|
{
|
|
if (dockStyle == DockStyle.Left)
|
|
DockTo(pane.NestedPanesContainer, pane, DockAlignment.Left, 0.5);
|
|
else if (dockStyle == DockStyle.Right)
|
|
DockTo(pane.NestedPanesContainer, pane, DockAlignment.Right, 0.5);
|
|
else if (dockStyle == DockStyle.Top)
|
|
DockTo(pane.NestedPanesContainer, pane, DockAlignment.Top, 0.5);
|
|
else if (dockStyle == DockStyle.Bottom)
|
|
DockTo(pane.NestedPanesContainer, pane, DockAlignment.Bottom, 0.5);
|
|
|
|
DockState = pane.DockState;
|
|
}
|
|
}
|
|
|
|
public void DockTo(DockPanel panel, DockStyle dockStyle)
|
|
{
|
|
if (panel != DockPanel)
|
|
throw new ArgumentException(Strings.IDockDragSource_DockTo_InvalidPanel, "panel");
|
|
|
|
if (dockStyle == DockStyle.Top)
|
|
DockState = DockState.DockTop;
|
|
else if (dockStyle == DockStyle.Bottom)
|
|
DockState = DockState.DockBottom;
|
|
else if (dockStyle == DockStyle.Left)
|
|
DockState = DockState.DockLeft;
|
|
else if (dockStyle == DockStyle.Right)
|
|
DockState = DockState.DockRight;
|
|
else if (dockStyle == DockStyle.Fill)
|
|
DockState = DockState.Document;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|