From 573823c1819b3196dcc91ba1c9886610ce4ff4de Mon Sep 17 00:00:00 2001 From: thoysg Date: Mon, 2 Aug 2010 14:35:46 +0000 Subject: [PATCH] big transformation , using DockPanels now it feels good to me! -Thoys git-svn-id: https://lsleditor.svn.sourceforge.net/svnroot/lsleditor@26 3f4676ac-adda-40fd-8265-58d1435b1672 --- trunk/Browser.cs | 3 +- trunk/Docking/AutoHideStripBase.cs | 530 ++++++ trunk/Docking/DockAreasEditor.cs | 142 ++ trunk/Docking/DockContent.cs | 304 ++++ trunk/Docking/DockContentCollection.cs | 175 ++ trunk/Docking/DockContentEventArgs.cs | 19 + trunk/Docking/DockContentHandler.cs | 1063 ++++++++++++ trunk/Docking/DockOutlineBase.cs | 161 ++ trunk/Docking/DockPane.SplitterControl.cs | 157 ++ trunk/Docking/DockPane.cs | 1288 ++++++++++++++ trunk/Docking/DockPaneCaptionBase.cs | 100 ++ trunk/Docking/DockPaneCollection.cs | 47 + trunk/Docking/DockPaneStripBase.cs | 252 +++ trunk/Docking/DockPanel.AutoHideWindow.cs | 612 +++++++ trunk/Docking/DockPanel.DockDragHandler.cs | 814 +++++++++ trunk/Docking/DockPanel.DragHandler.cs | 135 ++ trunk/Docking/DockPanel.FocusManager.cs | 568 +++++++ .../Docking/DockPanel.MdiClientController.cs | 430 +++++ trunk/Docking/DockPanel.Persistor.cs | 781 +++++++++ .../Docking/DockPanel.SplitterDragHandler.cs | 165 ++ trunk/Docking/DockPanel.bmp | Bin 0 -> 822 bytes trunk/Docking/DockPanel.cs | 1028 ++++++++++++ trunk/Docking/DockPanelExtender.cs | 225 +++ trunk/Docking/DockPanelSkin.cs | 421 +++++ trunk/Docking/DockWindow.SplitterControl.cs | 28 + trunk/Docking/DockWindow.cs | 243 +++ trunk/Docking/DockWindowCollection.cs | 38 + trunk/Docking/DragForm.cs | 64 + trunk/Docking/DummyControl.cs | 13 + trunk/Docking/Enums.cs | 60 + trunk/Docking/FloatWindow.cs | 453 +++++ trunk/Docking/FloatWindowCollection.cs | 42 + trunk/Docking/Helpers/DockHelper.cs | 103 ++ trunk/Docking/Helpers/DrawHelper.cs | 88 + trunk/Docking/Helpers/ResourceHelper.cs | 29 + trunk/Docking/Helpers/Win32Helper.cs | 19 + trunk/Docking/InertButtonBase.cs | 115 ++ trunk/Docking/Interfaces.cs | 46 + trunk/Docking/Localization.cs | 46 + trunk/Docking/Measures.cs | 14 + trunk/Docking/NestedDockingStatus.cs | 108 ++ trunk/Docking/NestedPaneCollection.cs | 116 ++ trunk/Docking/Resources.Designer.cs | 225 +++ trunk/Docking/Resources.resx | 190 +++ .../Resources/DockIndicator_PaneDiamond.bmp | Bin 0 -> 23286 bytes .../DockIndicator_PaneDiamond_Bottom.bmp | Bin 0 -> 23286 bytes .../DockIndicator_PaneDiamond_Hotspot.bmp | Bin 0 -> 23286 bytes ...DockIndicator_PaneDiamond_HotspotIndex.bmp | Bin 0 -> 90 bytes .../DockIndicator_PaneDiamond_Left.bmp | Bin 0 -> 23286 bytes .../DockIndicator_PaneDiamond_Right.bmp | Bin 0 -> 23286 bytes .../DockIndicator_PaneDiamond_Top.bmp | Bin 0 -> 23286 bytes .../Resources/DockIndicator_PanelBottom.bmp | Bin 0 -> 2782 bytes .../DockIndicator_PanelBottom_Active.bmp | Bin 0 -> 2782 bytes .../Resources/DockIndicator_PanelFill.bmp | Bin 0 -> 3030 bytes .../DockIndicator_PanelFill_Active.bmp | Bin 0 -> 3030 bytes .../Resources/DockIndicator_PanelLeft.bmp | Bin 0 -> 2838 bytes .../DockIndicator_PanelLeft_Active.bmp | Bin 0 -> 2838 bytes .../Resources/DockIndicator_PanelRight.bmp | Bin 0 -> 2838 bytes .../DockIndicator_PanelRight_Active.bmp | Bin 0 -> 2838 bytes .../Resources/DockIndicator_PanelTop.bmp | Bin 0 -> 2870 bytes .../DockIndicator_PanelTop_Active.bmp | Bin 0 -> 2870 bytes trunk/Docking/Resources/DockPane_AutoHide.bmp | Bin 0 -> 774 bytes trunk/Docking/Resources/DockPane_Close.bmp | Bin 0 -> 774 bytes trunk/Docking/Resources/DockPane_Dock.bmp | Bin 0 -> 774 bytes trunk/Docking/Resources/DockPane_Option.bmp | Bin 0 -> 774 bytes .../Resources/DockPane_OptionOverflow.bmp | Bin 0 -> 774 bytes .../Dockindicator_PaneDiamond_Fill.bmp | Bin 0 -> 23286 bytes trunk/Docking/SplitterBase.cs | 70 + trunk/Docking/Strings.Designer.cs | 774 +++++++++ trunk/Docking/Strings.resx | 357 ++++ trunk/Docking/VS2005AutoHideStrip.cs | 505 ++++++ trunk/Docking/VS2005DockPaneCaption.cs | 478 ++++++ trunk/Docking/VS2005DockPaneStrip.cs | 1479 +++++++++++++++++ trunk/Docking/VisibleNestedPaneCollection.cs | 168 ++ trunk/Docking/Win32/Enums.cs | 369 ++++ trunk/Docking/Win32/NativeMethods.cs | 64 + trunk/EditForm.cs | 9 +- trunk/LSLEditorForm.Designer.cs | 471 +++--- trunk/LSLEditorForm.cs | 257 ++- trunk/Plugins/Generic.cs | 7 +- trunk/Plugins/Particles.cs | 6 +- trunk/SimulatorConsole.Designer.cs | 263 +-- trunk/SimulatorConsole.cs | 3 +- trunk/Solution/SolutionExplorer.cs | 2 +- trunk/Solution/SolutionExplorer.designer.cs | 148 +- trunk/Solution/SolutionExplorer.resx | 204 +++ trunk/SyntaxError.Designer.cs | 226 +-- trunk/SyntaxError.cs | 3 +- trunk/ToolWindow.Designer.cs | 51 + trunk/ToolWindow.cs | 19 + trunk/ToolWindow.resx | 120 ++ trunk/lsleditor.csproj | 146 +- 92 files changed, 16899 insertions(+), 760 deletions(-) create mode 100644 trunk/Docking/AutoHideStripBase.cs create mode 100644 trunk/Docking/DockAreasEditor.cs create mode 100644 trunk/Docking/DockContent.cs create mode 100644 trunk/Docking/DockContentCollection.cs create mode 100644 trunk/Docking/DockContentEventArgs.cs create mode 100644 trunk/Docking/DockContentHandler.cs create mode 100644 trunk/Docking/DockOutlineBase.cs create mode 100644 trunk/Docking/DockPane.SplitterControl.cs create mode 100644 trunk/Docking/DockPane.cs create mode 100644 trunk/Docking/DockPaneCaptionBase.cs create mode 100644 trunk/Docking/DockPaneCollection.cs create mode 100644 trunk/Docking/DockPaneStripBase.cs create mode 100644 trunk/Docking/DockPanel.AutoHideWindow.cs create mode 100644 trunk/Docking/DockPanel.DockDragHandler.cs create mode 100644 trunk/Docking/DockPanel.DragHandler.cs create mode 100644 trunk/Docking/DockPanel.FocusManager.cs create mode 100644 trunk/Docking/DockPanel.MdiClientController.cs create mode 100644 trunk/Docking/DockPanel.Persistor.cs create mode 100644 trunk/Docking/DockPanel.SplitterDragHandler.cs create mode 100644 trunk/Docking/DockPanel.bmp create mode 100644 trunk/Docking/DockPanel.cs create mode 100644 trunk/Docking/DockPanelExtender.cs create mode 100644 trunk/Docking/DockPanelSkin.cs create mode 100644 trunk/Docking/DockWindow.SplitterControl.cs create mode 100644 trunk/Docking/DockWindow.cs create mode 100644 trunk/Docking/DockWindowCollection.cs create mode 100644 trunk/Docking/DragForm.cs create mode 100644 trunk/Docking/DummyControl.cs create mode 100644 trunk/Docking/Enums.cs create mode 100644 trunk/Docking/FloatWindow.cs create mode 100644 trunk/Docking/FloatWindowCollection.cs create mode 100644 trunk/Docking/Helpers/DockHelper.cs create mode 100644 trunk/Docking/Helpers/DrawHelper.cs create mode 100644 trunk/Docking/Helpers/ResourceHelper.cs create mode 100644 trunk/Docking/Helpers/Win32Helper.cs create mode 100644 trunk/Docking/InertButtonBase.cs create mode 100644 trunk/Docking/Interfaces.cs create mode 100644 trunk/Docking/Localization.cs create mode 100644 trunk/Docking/Measures.cs create mode 100644 trunk/Docking/NestedDockingStatus.cs create mode 100644 trunk/Docking/NestedPaneCollection.cs create mode 100644 trunk/Docking/Resources.Designer.cs create mode 100644 trunk/Docking/Resources.resx create mode 100644 trunk/Docking/Resources/DockIndicator_PaneDiamond.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PaneDiamond_Bottom.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PaneDiamond_Hotspot.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PaneDiamond_HotspotIndex.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PaneDiamond_Left.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PaneDiamond_Right.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PaneDiamond_Top.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PanelBottom.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PanelBottom_Active.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PanelFill.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PanelFill_Active.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PanelLeft.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PanelLeft_Active.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PanelRight.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PanelRight_Active.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PanelTop.bmp create mode 100644 trunk/Docking/Resources/DockIndicator_PanelTop_Active.bmp create mode 100644 trunk/Docking/Resources/DockPane_AutoHide.bmp create mode 100644 trunk/Docking/Resources/DockPane_Close.bmp create mode 100644 trunk/Docking/Resources/DockPane_Dock.bmp create mode 100644 trunk/Docking/Resources/DockPane_Option.bmp create mode 100644 trunk/Docking/Resources/DockPane_OptionOverflow.bmp create mode 100644 trunk/Docking/Resources/Dockindicator_PaneDiamond_Fill.bmp create mode 100644 trunk/Docking/SplitterBase.cs create mode 100644 trunk/Docking/Strings.Designer.cs create mode 100644 trunk/Docking/Strings.resx create mode 100644 trunk/Docking/VS2005AutoHideStrip.cs create mode 100644 trunk/Docking/VS2005DockPaneCaption.cs create mode 100644 trunk/Docking/VS2005DockPaneStrip.cs create mode 100644 trunk/Docking/VisibleNestedPaneCollection.cs create mode 100644 trunk/Docking/Win32/Enums.cs create mode 100644 trunk/Docking/Win32/NativeMethods.cs create mode 100644 trunk/ToolWindow.Designer.cs create mode 100644 trunk/ToolWindow.cs create mode 100644 trunk/ToolWindow.resx diff --git a/trunk/Browser.cs b/trunk/Browser.cs index cef25f1..f4f5d30 100644 --- a/trunk/Browser.cs +++ b/trunk/Browser.cs @@ -46,10 +46,11 @@ using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; +using LSLEditor.Docking; namespace LSLEditor { - public partial class Browser : Form + public partial class Browser : DockContent { private LSLEditorForm lslEditorForm; diff --git a/trunk/Docking/AutoHideStripBase.cs b/trunk/Docking/AutoHideStripBase.cs new file mode 100644 index 0000000..5889641 --- /dev/null +++ b/trunk/Docking/AutoHideStripBase.cs @@ -0,0 +1,530 @@ +using System; +using System.Collections; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace LSLEditor.Docking +{ + public abstract partial class AutoHideStripBase : Control + { + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + protected class Tab : IDisposable + { + private IDockContent m_content; + + protected internal Tab(IDockContent content) + { + m_content = content; + } + + ~Tab() + { + Dispose(false); + } + + public IDockContent Content + { + get { return m_content; } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + protected sealed class TabCollection : IEnumerable + { + #region IEnumerable Members + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + #endregion + + internal TabCollection(DockPane pane) + { + m_dockPane = pane; + } + + private DockPane m_dockPane = null; + public DockPane DockPane + { + get { return m_dockPane; } + } + + public DockPanel DockPanel + { + get { return DockPane.DockPanel; } + } + + public int Count + { + get { return DockPane.DisplayingContents.Count; } + } + + public Tab this[int index] + { + get + { + IDockContent content = DockPane.DisplayingContents[index]; + if (content == null) + throw (new ArgumentOutOfRangeException("index")); + if (content.DockHandler.AutoHideTab == null) + content.DockHandler.AutoHideTab = (DockPanel.AutoHideStripControl.CreateTab(content)); + return content.DockHandler.AutoHideTab as Tab; + } + } + + public bool Contains(Tab tab) + { + return (IndexOf(tab) != -1); + } + + public bool Contains(IDockContent content) + { + return (IndexOf(content) != -1); + } + + public int IndexOf(Tab tab) + { + if (tab == null) + return -1; + + return IndexOf(tab.Content); + } + + public int IndexOf(IDockContent content) + { + return DockPane.DisplayingContents.IndexOf(content); + } + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + protected class Pane : IDisposable + { + private DockPane m_dockPane; + + protected internal Pane(DockPane dockPane) + { + m_dockPane = dockPane; + } + + ~Pane() + { + Dispose(false); + } + + public DockPane DockPane + { + get { return m_dockPane; } + } + + public TabCollection AutoHideTabs + { + get + { + if (DockPane.AutoHideTabs == null) + DockPane.AutoHideTabs = new TabCollection(DockPane); + return DockPane.AutoHideTabs as TabCollection; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + protected sealed class PaneCollection : IEnumerable + { + private class AutoHideState + { + public DockState m_dockState; + public bool m_selected = false; + + public AutoHideState(DockState dockState) + { + m_dockState = dockState; + } + + public DockState DockState + { + get { return m_dockState; } + } + + public bool Selected + { + get { return m_selected; } + set { m_selected = value; } + } + } + + private class AutoHideStateCollection + { + private AutoHideState[] m_states; + + public AutoHideStateCollection() + { + m_states = new AutoHideState[] { + new AutoHideState(DockState.DockTopAutoHide), + new AutoHideState(DockState.DockBottomAutoHide), + new AutoHideState(DockState.DockLeftAutoHide), + new AutoHideState(DockState.DockRightAutoHide) + }; + } + + public AutoHideState this[DockState dockState] + { + get + { + for (int i = 0; i < m_states.Length; i++) + { + if (m_states[i].DockState == dockState) + return m_states[i]; + } + throw new ArgumentOutOfRangeException("dockState"); + } + } + + public bool ContainsPane(DockPane pane) + { + if (pane.IsHidden) + return false; + + for (int i = 0; i < m_states.Length; i++) + { + if (m_states[i].DockState == pane.DockState && m_states[i].Selected) + return true; + } + return false; + } + } + + internal PaneCollection(DockPanel panel, DockState dockState) + { + m_dockPanel = panel; + m_states = new AutoHideStateCollection(); + States[DockState.DockTopAutoHide].Selected = (dockState == DockState.DockTopAutoHide); + States[DockState.DockBottomAutoHide].Selected = (dockState == DockState.DockBottomAutoHide); + States[DockState.DockLeftAutoHide].Selected = (dockState == DockState.DockLeftAutoHide); + States[DockState.DockRightAutoHide].Selected = (dockState == DockState.DockRightAutoHide); + } + + private DockPanel m_dockPanel; + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private AutoHideStateCollection m_states; + private AutoHideStateCollection States + { + get { return m_states; } + } + + public int Count + { + get + { + int count = 0; + foreach (DockPane pane in DockPanel.Panes) + { + if (States.ContainsPane(pane)) + count++; + } + + return count; + } + } + + public Pane this[int index] + { + get + { + int count = 0; + foreach (DockPane pane in DockPanel.Panes) + { + if (!States.ContainsPane(pane)) + continue; + + if (count == index) + { + if (pane.AutoHidePane == null) + pane.AutoHidePane = DockPanel.AutoHideStripControl.CreatePane(pane); + return pane.AutoHidePane as Pane; + } + + count++; + } + throw new ArgumentOutOfRangeException("index"); + } + } + + public bool Contains(Pane pane) + { + return (IndexOf(pane) != -1); + } + + public int IndexOf(Pane pane) + { + if (pane == null) + return -1; + + int index = 0; + foreach (DockPane dockPane in DockPanel.Panes) + { + if (!States.ContainsPane(pane.DockPane)) + continue; + + if (pane == dockPane.AutoHidePane) + return index; + + index++; + } + return -1; + } + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + + #endregion + } + + protected AutoHideStripBase(DockPanel panel) + { + m_dockPanel = panel; + m_panesTop = new PaneCollection(panel, DockState.DockTopAutoHide); + m_panesBottom = new PaneCollection(panel, DockState.DockBottomAutoHide); + m_panesLeft = new PaneCollection(panel, DockState.DockLeftAutoHide); + m_panesRight = new PaneCollection(panel, DockState.DockRightAutoHide); + + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + SetStyle(ControlStyles.Selectable, false); + } + + private DockPanel m_dockPanel; + protected DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private PaneCollection m_panesTop; + protected PaneCollection PanesTop + { + get { return m_panesTop; } + } + + private PaneCollection m_panesBottom; + protected PaneCollection PanesBottom + { + get { return m_panesBottom; } + } + + private PaneCollection m_panesLeft; + protected PaneCollection PanesLeft + { + get { return m_panesLeft; } + } + + private PaneCollection m_panesRight; + protected PaneCollection PanesRight + { + get { return m_panesRight; } + } + + protected PaneCollection GetPanes(DockState dockState) + { + if (dockState == DockState.DockTopAutoHide) + return PanesTop; + else if (dockState == DockState.DockBottomAutoHide) + return PanesBottom; + else if (dockState == DockState.DockLeftAutoHide) + return PanesLeft; + else if (dockState == DockState.DockRightAutoHide) + return PanesRight; + else + throw new ArgumentOutOfRangeException("dockState"); + } + + internal int GetNumberOfPanes(DockState dockState) + { + return GetPanes(dockState).Count; + } + + protected Rectangle RectangleTopLeft + { + get + { + int height = MeasureHeight(); + return PanesTop.Count > 0 && PanesLeft.Count > 0 ? new Rectangle(0, 0, height, height) : Rectangle.Empty; + } + } + + protected Rectangle RectangleTopRight + { + get + { + int height = MeasureHeight(); + return PanesTop.Count > 0 && PanesRight.Count > 0 ? new Rectangle(Width - height, 0, height, height) : Rectangle.Empty; + } + } + + protected Rectangle RectangleBottomLeft + { + get + { + int height = MeasureHeight(); + return PanesBottom.Count > 0 && PanesLeft.Count > 0 ? new Rectangle(0, Height - height, height, height) : Rectangle.Empty; + } + } + + protected Rectangle RectangleBottomRight + { + get + { + int height = MeasureHeight(); + return PanesBottom.Count > 0 && PanesRight.Count > 0 ? new Rectangle(Width - height, Height - height, height, height) : Rectangle.Empty; + } + } + + protected internal Rectangle GetTabStripRectangle(DockState dockState) + { + int height = MeasureHeight(); + if (dockState == DockState.DockTopAutoHide && PanesTop.Count > 0) + return new Rectangle(RectangleTopLeft.Width, 0, Width - RectangleTopLeft.Width - RectangleTopRight.Width, height); + else if (dockState == DockState.DockBottomAutoHide && PanesBottom.Count > 0) + return new Rectangle(RectangleBottomLeft.Width, Height - height, Width - RectangleBottomLeft.Width - RectangleBottomRight.Width, height); + else if (dockState == DockState.DockLeftAutoHide && PanesLeft.Count > 0) + return new Rectangle(0, RectangleTopLeft.Width, height, Height - RectangleTopLeft.Height - RectangleBottomLeft.Height); + else if (dockState == DockState.DockRightAutoHide && PanesRight.Count > 0) + return new Rectangle(Width - height, RectangleTopRight.Width, height, Height - RectangleTopRight.Height - RectangleBottomRight.Height); + else + return Rectangle.Empty; + } + + private GraphicsPath m_displayingArea = null; + private GraphicsPath DisplayingArea + { + get + { + if (m_displayingArea == null) + m_displayingArea = new GraphicsPath(); + + return m_displayingArea; + } + } + + private void SetRegion() + { + DisplayingArea.Reset(); + DisplayingArea.AddRectangle(RectangleTopLeft); + DisplayingArea.AddRectangle(RectangleTopRight); + DisplayingArea.AddRectangle(RectangleBottomLeft); + DisplayingArea.AddRectangle(RectangleBottomRight); + DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockTopAutoHide)); + DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockBottomAutoHide)); + DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockLeftAutoHide)); + DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockRightAutoHide)); + Region = new Region(DisplayingArea); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if (e.Button != MouseButtons.Left) + return; + + IDockContent content = HitTest(); + if (content == null) + return; + + content.DockHandler.Activate(); + } + + protected override void OnMouseHover(EventArgs e) + { + base.OnMouseHover(e); + + IDockContent content = HitTest(); + if (content != null && DockPanel.ActiveAutoHideContent != content) + DockPanel.ActiveAutoHideContent = content; + + // requires further tracking of mouse hover behavior, + ResetMouseEventArgs(); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + RefreshChanges(); + base.OnLayout (levent); + } + + internal void RefreshChanges() + { + if (IsDisposed) + return; + + SetRegion(); + OnRefreshChanges(); + } + + protected virtual void OnRefreshChanges() + { + } + + protected internal abstract int MeasureHeight(); + + private IDockContent HitTest() + { + Point ptMouse = PointToClient(Control.MousePosition); + return HitTest(ptMouse); + } + + protected virtual Tab CreateTab(IDockContent content) + { + return new Tab(content); + } + + protected virtual Pane CreatePane(DockPane dockPane) + { + return new Pane(dockPane); + } + + protected abstract IDockContent HitTest(Point point); + } +} diff --git a/trunk/Docking/DockAreasEditor.cs b/trunk/Docking/DockAreasEditor.cs new file mode 100644 index 0000000..f7e5531 --- /dev/null +++ b/trunk/Docking/DockAreasEditor.cs @@ -0,0 +1,142 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Design; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace LSLEditor.Docking +{ + internal class DockAreasEditor : UITypeEditor + { + private class DockAreasEditorControl : System.Windows.Forms.UserControl + { + private CheckBox checkBoxFloat; + private CheckBox checkBoxDockLeft; + private CheckBox checkBoxDockRight; + private CheckBox checkBoxDockTop; + private CheckBox checkBoxDockBottom; + private CheckBox checkBoxDockFill; + private DockAreas m_oldDockAreas; + + public DockAreas DockAreas + { + get + { + DockAreas dockAreas = 0; + if (checkBoxFloat.Checked) + dockAreas |= DockAreas.Float; + if (checkBoxDockLeft.Checked) + dockAreas |= DockAreas.DockLeft; + if (checkBoxDockRight.Checked) + dockAreas |= DockAreas.DockRight; + if (checkBoxDockTop.Checked) + dockAreas |= DockAreas.DockTop; + if (checkBoxDockBottom.Checked) + dockAreas |= DockAreas.DockBottom; + if (checkBoxDockFill.Checked) + dockAreas |= DockAreas.Document; + + if (dockAreas == 0) + return m_oldDockAreas; + else + return dockAreas; + } + } + + public DockAreasEditorControl() + { + checkBoxFloat = new CheckBox(); + checkBoxDockLeft = new CheckBox(); + checkBoxDockRight = new CheckBox(); + checkBoxDockTop = new CheckBox(); + checkBoxDockBottom = new CheckBox(); + checkBoxDockFill = new CheckBox(); + + SuspendLayout(); + + checkBoxFloat.Appearance = Appearance.Button; + checkBoxFloat.Dock = DockStyle.Top; + checkBoxFloat.Height = 24; + checkBoxFloat.Text = Strings.DockAreaEditor_FloatCheckBoxText; + checkBoxFloat.TextAlign = ContentAlignment.MiddleCenter; + checkBoxFloat.FlatStyle = FlatStyle.System; + + checkBoxDockLeft.Appearance = System.Windows.Forms.Appearance.Button; + checkBoxDockLeft.Dock = System.Windows.Forms.DockStyle.Left; + checkBoxDockLeft.Width = 24; + checkBoxDockLeft.FlatStyle = FlatStyle.System; + + checkBoxDockRight.Appearance = System.Windows.Forms.Appearance.Button; + checkBoxDockRight.Dock = System.Windows.Forms.DockStyle.Right; + checkBoxDockRight.Width = 24; + checkBoxDockRight.FlatStyle = FlatStyle.System; + + checkBoxDockTop.Appearance = System.Windows.Forms.Appearance.Button; + checkBoxDockTop.Dock = System.Windows.Forms.DockStyle.Top; + checkBoxDockTop.Height = 24; + checkBoxDockTop.FlatStyle = FlatStyle.System; + + checkBoxDockBottom.Appearance = System.Windows.Forms.Appearance.Button; + checkBoxDockBottom.Dock = System.Windows.Forms.DockStyle.Bottom; + checkBoxDockBottom.Height = 24; + checkBoxDockBottom.FlatStyle = FlatStyle.System; + + checkBoxDockFill.Appearance = System.Windows.Forms.Appearance.Button; + checkBoxDockFill.Dock = System.Windows.Forms.DockStyle.Fill; + checkBoxDockFill.FlatStyle = FlatStyle.System; + + this.Controls.AddRange(new Control[] { + checkBoxDockFill, + checkBoxDockBottom, + checkBoxDockTop, + checkBoxDockRight, + checkBoxDockLeft, + checkBoxFloat}); + + Size = new System.Drawing.Size(160, 144); + BackColor = SystemColors.Control; + ResumeLayout(); + } + + public void SetStates(DockAreas dockAreas) + { + m_oldDockAreas = dockAreas; + if ((dockAreas & DockAreas.DockLeft) != 0) + checkBoxDockLeft.Checked = true; + if ((dockAreas & DockAreas.DockRight) != 0) + checkBoxDockRight.Checked = true; + if ((dockAreas & DockAreas.DockTop) != 0) + checkBoxDockTop.Checked = true; + if ((dockAreas & DockAreas.DockTop) != 0) + checkBoxDockTop.Checked = true; + if ((dockAreas & DockAreas.DockBottom) != 0) + checkBoxDockBottom.Checked = true; + if ((dockAreas & DockAreas.Document) != 0) + checkBoxDockFill.Checked = true; + if ((dockAreas & DockAreas.Float) != 0) + checkBoxFloat.Checked = true; + } + } + + private DockAreasEditor.DockAreasEditorControl m_ui = null; + + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) + { + return UITypeEditorEditStyle.DropDown; + } + + public override object EditValue(ITypeDescriptorContext context, IServiceProvider sp, object value) + { + if (m_ui == null) + m_ui = new DockAreasEditor.DockAreasEditorControl(); + + m_ui.SetStates((DockAreas)value); + + IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)sp.GetService(typeof(IWindowsFormsEditorService)); + edSvc.DropDownControl(m_ui); + + return m_ui.DockAreas; + } + } +} diff --git a/trunk/Docking/DockContent.cs b/trunk/Docking/DockContent.cs new file mode 100644 index 0000000..3f109e9 --- /dev/null +++ b/trunk/Docking/DockContent.cs @@ -0,0 +1,304 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; + +namespace LSLEditor.Docking +{ + public class DockContent : Form, IDockContent + { + public DockContent() + { + m_dockHandler = new DockContentHandler(this, new GetPersistStringCallback(GetPersistString)); + m_dockHandler.DockStateChanged += new EventHandler(DockHandler_DockStateChanged); + //Suggested as a fix by bensty regarding form resize + this.ParentChanged += new EventHandler(DockContent_ParentChanged); + } + + //Suggested as a fix by bensty regarding form resize + private void DockContent_ParentChanged(object Sender, EventArgs e) + { + if (this.Parent != null) + this.Font = this.Parent.Font; + } + + private DockContentHandler m_dockHandler = null; + [Browsable(false)] + public DockContentHandler DockHandler + { + get { return m_dockHandler; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_AllowEndUserDocking_Description")] + [DefaultValue(true)] + public bool AllowEndUserDocking + { + get { return DockHandler.AllowEndUserDocking; } + set { DockHandler.AllowEndUserDocking = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_DockAreas_Description")] + [DefaultValue(DockAreas.DockLeft|DockAreas.DockRight|DockAreas.DockTop|DockAreas.DockBottom|DockAreas.Document|DockAreas.Float)] + public DockAreas DockAreas + { + get { return DockHandler.DockAreas; } + set { DockHandler.DockAreas = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_AutoHidePortion_Description")] + [DefaultValue(0.25)] + public double AutoHidePortion + { + get { return DockHandler.AutoHidePortion; } + set { DockHandler.AutoHidePortion = value; } + } + + [Localizable(true)] + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_TabText_Description")] + [DefaultValue(null)] + private string m_tabText = null; + public string TabText + { + get { return m_tabText; } + set { DockHandler.TabText = m_tabText = value; } + } + private bool ShouldSerializeTabText() + { + return (m_tabText != null); + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_CloseButton_Description")] + [DefaultValue(true)] + public bool CloseButton + { + get { return DockHandler.CloseButton; } + set { DockHandler.CloseButton = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_CloseButtonVisible_Description")] + [DefaultValue(true)] + public bool CloseButtonVisible + { + get { return DockHandler.CloseButtonVisible; } + set { DockHandler.CloseButtonVisible = value; } + } + + [Browsable(false)] + public DockPanel DockPanel + { + get { return DockHandler.DockPanel; } + set { DockHandler.DockPanel = value; } + } + + [Browsable(false)] + public DockState DockState + { + get { return DockHandler.DockState; } + set { DockHandler.DockState = value; } + } + + [Browsable(false)] + public DockPane Pane + { + get { return DockHandler.Pane; } + set { DockHandler.Pane = value; } + } + + [Browsable(false)] + public bool IsHidden + { + get { return DockHandler.IsHidden; } + set { DockHandler.IsHidden = value; } + } + + [Browsable(false)] + public DockState VisibleState + { + get { return DockHandler.VisibleState; } + set { DockHandler.VisibleState = value; } + } + + [Browsable(false)] + public bool IsFloat + { + get { return DockHandler.IsFloat; } + set { DockHandler.IsFloat = value; } + } + + [Browsable(false)] + public DockPane PanelPane + { + get { return DockHandler.PanelPane; } + set { DockHandler.PanelPane = value; } + } + + [Browsable(false)] + public DockPane FloatPane + { + get { return DockHandler.FloatPane; } + set { DockHandler.FloatPane = value; } + } + + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + protected virtual string GetPersistString() + { + return GetType().ToString(); + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_HideOnClose_Description")] + [DefaultValue(false)] + public bool HideOnClose + { + get { return DockHandler.HideOnClose; } + set { DockHandler.HideOnClose = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_ShowHint_Description")] + [DefaultValue(DockState.Unknown)] + public DockState ShowHint + { + get { return DockHandler.ShowHint; } + set { DockHandler.ShowHint = value; } + } + + [Browsable(false)] + public bool IsActivated + { + get { return DockHandler.IsActivated; } + } + + public bool IsDockStateValid(DockState dockState) + { + return DockHandler.IsDockStateValid(dockState); + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_TabPageContextMenu_Description")] + [DefaultValue(null)] + public ContextMenu TabPageContextMenu + { + get { return DockHandler.TabPageContextMenu; } + set { DockHandler.TabPageContextMenu = value; } + } + + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockContent_TabPageContextMenuStrip_Description")] + [DefaultValue(null)] + public ContextMenuStrip TabPageContextMenuStrip + { + get { return DockHandler.TabPageContextMenuStrip; } + set { DockHandler.TabPageContextMenuStrip = value; } + } + + [Localizable(true)] + [Category("Appearance")] + [LocalizedDescription("DockContent_ToolTipText_Description")] + [DefaultValue(null)] + public string ToolTipText + { + get { return DockHandler.ToolTipText; } + set { DockHandler.ToolTipText = value; } + } + + public new void Activate() + { + DockHandler.Activate(); + } + + public new void Hide() + { + DockHandler.Hide(); + } + + public new void Show() + { + DockHandler.Show(); + } + + public void Show(DockPanel dockPanel) + { + DockHandler.Show(dockPanel); + } + + public void Show(DockPanel dockPanel, DockState dockState) + { + DockHandler.Show(dockPanel, dockState); + } + + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] + public void Show(DockPanel dockPanel, Rectangle floatWindowBounds) + { + DockHandler.Show(dockPanel, floatWindowBounds); + } + + public void Show(DockPane pane, IDockContent beforeContent) + { + DockHandler.Show(pane, beforeContent); + } + + public void Show(DockPane previousPane, DockAlignment alignment, double proportion) + { + DockHandler.Show(previousPane, alignment, proportion); + } + + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] + public void FloatAt(Rectangle floatWindowBounds) + { + DockHandler.FloatAt(floatWindowBounds); + } + + public void DockTo(DockPane paneTo, DockStyle dockStyle, int contentIndex) + { + DockHandler.DockTo(paneTo, dockStyle, contentIndex); + } + + public void DockTo(DockPanel panel, DockStyle dockStyle) + { + DockHandler.DockTo(panel, dockStyle); + } + + #region IDockContent Members + void IDockContent.OnActivated(EventArgs e) + { + this.OnActivated(e); + } + + void IDockContent.OnDeactivate(EventArgs e) + { + this.OnDeactivate(e); + } + #endregion + + #region Events + private void DockHandler_DockStateChanged(object sender, EventArgs e) + { + OnDockStateChanged(e); + } + + private static readonly object DockStateChangedEvent = new object(); + [LocalizedCategory("Category_PropertyChanged")] + [LocalizedDescription("Pane_DockStateChanged_Description")] + 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); + } + #endregion + } +} diff --git a/trunk/Docking/DockContentCollection.cs b/trunk/Docking/DockContentCollection.cs new file mode 100644 index 0000000..5ff390f --- /dev/null +++ b/trunk/Docking/DockContentCollection.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace LSLEditor.Docking +{ + public class DockContentCollection : ReadOnlyCollection + { + private static List _emptyList = new List(0); + + internal DockContentCollection() + : base(new List()) + { + } + + internal DockContentCollection(DockPane pane) + : base(_emptyList) + { + m_dockPane = pane; + } + + private DockPane m_dockPane = null; + private DockPane DockPane + { + get { return m_dockPane; } + } + + public new IDockContent this[int index] + { + get + { + if (DockPane == null) + return Items[index] as IDockContent; + else + return GetVisibleContent(index); + } + } + + internal int Add(IDockContent content) + { +#if DEBUG + if (DockPane != null) + throw new InvalidOperationException(); +#endif + + if (Contains(content)) + return IndexOf(content); + + Items.Add(content); + return Count - 1; + } + + internal void AddAt(IDockContent content, int index) + { +#if DEBUG + if (DockPane != null) + throw new InvalidOperationException(); +#endif + + if (index < 0 || index > Items.Count - 1) + return; + + if (Contains(content)) + return; + + Items.Insert(index, content); + } + + public new bool Contains(IDockContent content) + { + if (DockPane == null) + return Items.Contains(content); + else + return (GetIndexOfVisibleContents(content) != -1); + } + + public new int Count + { + get + { + if (DockPane == null) + return base.Count; + else + return CountOfVisibleContents; + } + } + + public new int IndexOf(IDockContent content) + { + if (DockPane == null) + { + if (!Contains(content)) + return -1; + else + return Items.IndexOf(content); + } + else + return GetIndexOfVisibleContents(content); + } + + internal void Remove(IDockContent content) + { + if (DockPane != null) + throw new InvalidOperationException(); + + if (!Contains(content)) + return; + + Items.Remove(content); + } + + private int CountOfVisibleContents + { + get + { +#if DEBUG + if (DockPane == null) + throw new InvalidOperationException(); +#endif + + int count = 0; + foreach (IDockContent content in DockPane.Contents) + { + if (content.DockHandler.DockState == DockPane.DockState) + count++; + } + return count; + } + } + + private IDockContent GetVisibleContent(int index) + { +#if DEBUG + if (DockPane == null) + throw new InvalidOperationException(); +#endif + + int currentIndex = -1; + foreach (IDockContent content in DockPane.Contents) + { + if (content.DockHandler.DockState == DockPane.DockState) + currentIndex++; + + if (currentIndex == index) + return content; + } + throw (new ArgumentOutOfRangeException()); + } + + private int GetIndexOfVisibleContents(IDockContent content) + { +#if DEBUG + if (DockPane == null) + throw new InvalidOperationException(); +#endif + + if (content == null) + return -1; + + int index = -1; + foreach (IDockContent c in DockPane.Contents) + { + if (c.DockHandler.DockState == DockPane.DockState) + { + index++; + + if (c == content) + return index; + } + } + return -1; + } + } +} diff --git a/trunk/Docking/DockContentEventArgs.cs b/trunk/Docking/DockContentEventArgs.cs new file mode 100644 index 0000000..4dc9e92 --- /dev/null +++ b/trunk/Docking/DockContentEventArgs.cs @@ -0,0 +1,19 @@ +using System; + +namespace LSLEditor.Docking +{ + public class DockContentEventArgs : EventArgs + { + private IDockContent m_content; + + public DockContentEventArgs(IDockContent content) + { + m_content = content; + } + + public IDockContent Content + { + get { return m_content; } + } + } +} diff --git a/trunk/Docking/DockContentHandler.cs b/trunk/Docking/DockContentHandler.cs new file mode 100644 index 0000000..3076a9c --- /dev/null +++ b/trunk/Docking/DockContentHandler.cs @@ -0,0 +1,1063 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; + +namespace LSLEditor.Docking +{ + public delegate string GetPersistStringCallback(); + + public class DockContentHandler : IDisposable, IDockDragSource + { + public DockContentHandler(Form form) : this(form, null) + { + } + + public DockContentHandler(Form form, GetPersistStringCallback getPersistStringCallback) + { + if (!(form is IDockContent)) + throw new ArgumentException(Strings.DockContent_Constructor_InvalidForm, "form"); + + m_form = form; + m_getPersistStringCallback = getPersistStringCallback; + + m_events = new EventHandlerList(); + Form.Disposed +=new EventHandler(Form_Disposed); + Form.TextChanged += new EventHandler(Form_TextChanged); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if(disposing) + { + lock(this) + { + DockPanel = null; + if (m_autoHideTab != null) + m_autoHideTab.Dispose(); + if (m_tab != null) + m_tab.Dispose(); + + Form.Disposed -= new EventHandler(Form_Disposed); + Form.TextChanged -= new EventHandler(Form_TextChanged); + m_events.Dispose(); + } + } + } + + private Form m_form; + public Form Form + { + get { return m_form; } + } + + public IDockContent Content + { + get { return Form as IDockContent; } + } + + private IDockContent m_previousActive = null; + public IDockContent PreviousActive + { + get { return m_previousActive; } + internal set { m_previousActive = value; } + } + + private IDockContent m_nextActive = null; + public IDockContent NextActive + { + get { return m_nextActive; } + internal set { m_nextActive = value; } + } + + private EventHandlerList m_events; + private EventHandlerList Events + { + get { return m_events; } + } + + private bool m_allowEndUserDocking = true; + public bool AllowEndUserDocking + { + get { return m_allowEndUserDocking; } + set { m_allowEndUserDocking = value; } + } + + private double m_autoHidePortion = 0.25; + public double AutoHidePortion + { + get { return m_autoHidePortion; } + set + { + if (value <= 0) + throw(new ArgumentOutOfRangeException(Strings.DockContentHandler_AutoHidePortion_OutOfRange)); + + if (m_autoHidePortion == value) + return; + + m_autoHidePortion = value; + + if (DockPanel == null) + return; + + if (DockPanel.ActiveAutoHideContent == Content) + DockPanel.PerformLayout(); + } + } + + private bool m_closeButton = true; + public bool CloseButton + { + get { return m_closeButton; } + set + { + if (m_closeButton == value) + return; + + m_closeButton = value; + if (Pane != null) + if (Pane.ActiveContent.DockHandler == this) + Pane.RefreshChanges(); + } + } + + private bool m_closeButtonVisible = true; + /// + /// Determines whether the close button is visible on the content + /// + public bool CloseButtonVisible + { + get { return m_closeButtonVisible; } + set { m_closeButtonVisible = value; } + } + + private DockState DefaultDockState + { + get + { + if (ShowHint != DockState.Unknown && ShowHint != DockState.Hidden) + return ShowHint; + + if ((DockAreas & DockAreas.Document) != 0) + return DockState.Document; + if ((DockAreas & DockAreas.DockRight) != 0) + return DockState.DockRight; + if ((DockAreas & DockAreas.DockLeft) != 0) + return DockState.DockLeft; + if ((DockAreas & DockAreas.DockBottom) != 0) + return DockState.DockBottom; + if ((DockAreas & DockAreas.DockTop) != 0) + return DockState.DockTop; + + return DockState.Unknown; + } + } + + private DockState DefaultShowState + { + get + { + if (ShowHint != DockState.Unknown) + return ShowHint; + + if ((DockAreas & DockAreas.Document) != 0) + return DockState.Document; + if ((DockAreas & DockAreas.DockRight) != 0) + return DockState.DockRight; + if ((DockAreas & DockAreas.DockLeft) != 0) + return DockState.DockLeft; + if ((DockAreas & DockAreas.DockBottom) != 0) + return DockState.DockBottom; + if ((DockAreas & DockAreas.DockTop) != 0) + return DockState.DockTop; + if ((DockAreas & DockAreas.Float) != 0) + return DockState.Float; + + return DockState.Unknown; + } + } + + private DockAreas m_allowedAreas = DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.DockBottom | DockAreas.Document | DockAreas.Float; + public DockAreas DockAreas + { + get { return m_allowedAreas; } + set + { + if (m_allowedAreas == value) + return; + + if (!DockHelper.IsDockStateValid(DockState, value)) + throw(new InvalidOperationException(Strings.DockContentHandler_DockAreas_InvalidValue)); + + m_allowedAreas = value; + + if (!DockHelper.IsDockStateValid(ShowHint, m_allowedAreas)) + ShowHint = DockState.Unknown; + } + } + + private DockState m_dockState = DockState.Unknown; + public DockState DockState + { + get { return m_dockState; } + set + { + if (m_dockState == value) + return; + + DockPanel.SuspendLayout(true); + + if (value == DockState.Hidden) + IsHidden = true; + else + SetDockState(false, value, Pane); + + DockPanel.ResumeLayout(true, true); + } + } + + private DockPanel m_dockPanel = null; + public DockPanel DockPanel + { + get { return m_dockPanel; } + set + { + if (m_dockPanel == value) + return; + + Pane = null; + + if (m_dockPanel != null) + m_dockPanel.RemoveContent(Content); + + if (m_tab != null) + { + m_tab.Dispose(); + m_tab = null; + } + + if (m_autoHideTab != null) + { + m_autoHideTab.Dispose(); + m_autoHideTab = null; + } + + m_dockPanel = value; + + if (m_dockPanel != null) + { + m_dockPanel.AddContent(Content); + Form.TopLevel = false; + Form.FormBorderStyle = FormBorderStyle.None; + Form.ShowInTaskbar = false; + Form.WindowState = FormWindowState.Normal; + NativeMethods.SetWindowPos(Form.Handle, IntPtr.Zero, 0, 0, 0, 0, + Win32.FlagsSetWindowPos.SWP_NOACTIVATE | + Win32.FlagsSetWindowPos.SWP_NOMOVE | + Win32.FlagsSetWindowPos.SWP_NOSIZE | + Win32.FlagsSetWindowPos.SWP_NOZORDER | + Win32.FlagsSetWindowPos.SWP_NOOWNERZORDER | + Win32.FlagsSetWindowPos.SWP_FRAMECHANGED); + } + } + } + + public Icon Icon + { + get { return Form.Icon; } + } + + public DockPane Pane + { + get { return IsFloat ? FloatPane : PanelPane; } + set + { + if (Pane == value) + return; + + DockPanel.SuspendLayout(true); + + DockPane oldPane = Pane; + + SuspendSetDockState(); + FloatPane = (value == null ? null : (value.IsFloat ? value : FloatPane)); + PanelPane = (value == null ? null : (value.IsFloat ? PanelPane : value)); + ResumeSetDockState(IsHidden, value != null ? value.DockState : DockState.Unknown, oldPane); + + DockPanel.ResumeLayout(true, true); + } + } + + private bool m_isHidden = true; + public bool IsHidden + { + get { return m_isHidden; } + set + { + if (m_isHidden == value) + return; + + SetDockState(value, VisibleState, Pane); + } + } + + private string m_tabText = null; + public string TabText + { + get { return m_tabText == null || m_tabText == "" ? Form.Text : m_tabText; } + set + { + if (m_tabText == value) + return; + + m_tabText = value; + if (Pane != null) + Pane.RefreshChanges(); + } + } + + private DockState m_visibleState = DockState.Unknown; + public DockState VisibleState + { + get { return m_visibleState; } + set + { + if (m_visibleState == value) + return; + + SetDockState(IsHidden, value, Pane); + } + } + + private bool m_isFloat = false; + public bool IsFloat + { + get { return m_isFloat; } + set + { + if (m_isFloat == value) + return; + + DockState visibleState = CheckDockState(value); + + if (visibleState == DockState.Unknown) + throw new InvalidOperationException(Strings.DockContentHandler_IsFloat_InvalidValue); + + SetDockState(IsHidden, visibleState, Pane); + } + } + + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] + public DockState CheckDockState(bool isFloat) + { + DockState dockState; + + if (isFloat) + { + if (!IsDockStateValid(DockState.Float)) + dockState = DockState.Unknown; + else + dockState = DockState.Float; + } + else + { + dockState = (PanelPane != null) ? PanelPane.DockState : DefaultDockState; + if (dockState != DockState.Unknown && !IsDockStateValid(dockState)) + dockState = DockState.Unknown; + } + + return dockState; + } + + private DockPane m_panelPane = null; + public DockPane PanelPane + { + get { return m_panelPane; } + set + { + if (m_panelPane == value) + return; + + if (value != null) + { + if (value.IsFloat || value.DockPanel != DockPanel) + throw new InvalidOperationException(Strings.DockContentHandler_DockPane_InvalidValue); + } + + DockPane oldPane = Pane; + + if (m_panelPane != null) + RemoveFromPane(m_panelPane); + m_panelPane = value; + if (m_panelPane != null) + { + m_panelPane.AddContent(Content); + SetDockState(IsHidden, IsFloat ? DockState.Float : m_panelPane.DockState, oldPane); + } + else + SetDockState(IsHidden, DockState.Unknown, oldPane); + } + } + + private void RemoveFromPane(DockPane pane) + { + pane.RemoveContent(Content); + SetPane(null); + if (pane.Contents.Count == 0) + pane.Dispose(); + } + + private DockPane m_floatPane = null; + public DockPane FloatPane + { + get { return m_floatPane; } + set + { + if (m_floatPane == value) + return; + + if (value != null) + { + if (!value.IsFloat || value.DockPanel != DockPanel) + throw new InvalidOperationException(Strings.DockContentHandler_FloatPane_InvalidValue); + } + + DockPane oldPane = Pane; + + if (m_floatPane != null) + RemoveFromPane(m_floatPane); + m_floatPane = value; + if (m_floatPane != null) + { + m_floatPane.AddContent(Content); + SetDockState(IsHidden, IsFloat ? DockState.Float : VisibleState, oldPane); + } + else + SetDockState(IsHidden, DockState.Unknown, oldPane); + } + } + + private int m_countSetDockState = 0; + private void SuspendSetDockState() + { + m_countSetDockState ++; + } + + private void ResumeSetDockState() + { + m_countSetDockState --; + if (m_countSetDockState < 0) + m_countSetDockState = 0; + } + + internal bool IsSuspendSetDockState + { + get { return m_countSetDockState != 0; } + } + + private void ResumeSetDockState(bool isHidden, DockState visibleState, DockPane oldPane) + { + ResumeSetDockState(); + SetDockState(isHidden, visibleState, oldPane); + } + + internal void SetDockState(bool isHidden, DockState visibleState, DockPane oldPane) + { + if (IsSuspendSetDockState) + return; + + if (DockPanel == null && visibleState != DockState.Unknown) + throw new InvalidOperationException(Strings.DockContentHandler_SetDockState_NullPanel); + + if (visibleState == DockState.Hidden || (visibleState != DockState.Unknown && !IsDockStateValid(visibleState))) + throw new InvalidOperationException(Strings.DockContentHandler_SetDockState_InvalidState); + + DockPanel dockPanel = DockPanel; + if (dockPanel != null) + dockPanel.SuspendLayout(true); + + SuspendSetDockState(); + + DockState oldDockState = DockState; + + if (m_isHidden != isHidden || oldDockState == DockState.Unknown) + { + m_isHidden = isHidden; + } + m_visibleState = visibleState; + m_dockState = isHidden ? DockState.Hidden : visibleState; + + if (visibleState == DockState.Unknown) + Pane = null; + else + { + m_isFloat = (m_visibleState == DockState.Float); + + if (Pane == null) + Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, visibleState, true); + else if (Pane.DockState != visibleState) + { + if (Pane.Contents.Count == 1) + Pane.SetDockState(visibleState); + else + Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, visibleState, true); + } + } + + if (Form.ContainsFocus) + if (DockState == DockState.Hidden || DockState == DockState.Unknown) + DockPanel.ContentFocusManager.GiveUpFocus(Content); + + SetPaneAndVisible(Pane); + + if (oldPane != null && !oldPane.IsDisposed && oldDockState == oldPane.DockState) + RefreshDockPane(oldPane); + + if (Pane != null && DockState == Pane.DockState) + { + if ((Pane != oldPane) || + (Pane == oldPane && oldDockState != oldPane.DockState)) + // Avoid early refresh of hidden AutoHide panes + if ((Pane.DockWindow == null || Pane.DockWindow.Visible || Pane.IsHidden) && !Pane.IsAutoHide) + RefreshDockPane(Pane); + } + + if (oldDockState != DockState) + { + if (DockState == DockState.Hidden || DockState == DockState.Unknown || + DockHelper.IsDockStateAutoHide(DockState)) + DockPanel.ContentFocusManager.RemoveFromList(Content); + else + DockPanel.ContentFocusManager.AddToList(Content); + + OnDockStateChanged(EventArgs.Empty); + } + ResumeSetDockState(); + + if (dockPanel != null) + dockPanel.ResumeLayout(true, true); + } + + private static void RefreshDockPane(DockPane pane) + { + pane.RefreshChanges(); + pane.ValidateActiveContent(); + } + + internal string PersistString + { + get { return GetPersistStringCallback == null ? Form.GetType().ToString() : GetPersistStringCallback(); } + } + + private GetPersistStringCallback m_getPersistStringCallback = null; + public GetPersistStringCallback GetPersistStringCallback + { + get { return m_getPersistStringCallback; } + set { m_getPersistStringCallback = value; } + } + + + private bool m_hideOnClose = false; + public bool HideOnClose + { + get { return m_hideOnClose; } + set { m_hideOnClose = value; } + } + + private DockState m_showHint = DockState.Unknown; + public DockState ShowHint + { + get { return m_showHint; } + set + { + if (!DockHelper.IsDockStateValid(value, DockAreas)) + throw (new InvalidOperationException(Strings.DockContentHandler_ShowHint_InvalidValue)); + + if (m_showHint == value) + return; + + m_showHint = value; + } + } + + private bool m_isActivated = false; + public bool IsActivated + { + get { return m_isActivated; } + internal set + { + if (m_isActivated == value) + return; + + m_isActivated = value; + } + } + + public bool IsDockStateValid(DockState dockState) + { + if (DockPanel != null && dockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.SystemMdi) + return false; + else + return DockHelper.IsDockStateValid(dockState, DockAreas); + } + + private ContextMenu m_tabPageContextMenu = null; + public ContextMenu TabPageContextMenu + { + get { return m_tabPageContextMenu; } + set { m_tabPageContextMenu = value; } + } + + private string m_toolTipText = null; + public string ToolTipText + { + get { return m_toolTipText; } + set { m_toolTipText = value; } + } + + public void Activate() + { + if (DockPanel == null) + Form.Activate(); + else if (Pane == null) + Show(DockPanel); + else + { + IsHidden = false; + Pane.ActiveContent = Content; + if (DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.SystemMdi) + { + Form.Activate(); + return; + } + else if (DockHelper.IsDockStateAutoHide(DockState)) + DockPanel.ActiveAutoHideContent = Content; + + if (!Form.ContainsFocus) + DockPanel.ContentFocusManager.Activate(Content); + } + } + + public void GiveUpFocus() + { + DockPanel.ContentFocusManager.GiveUpFocus(Content); + } + + private IntPtr m_activeWindowHandle = IntPtr.Zero; + internal IntPtr ActiveWindowHandle + { + get { return m_activeWindowHandle; } + set { m_activeWindowHandle = value; } + } + + public void Hide() + { + IsHidden = true; + } + + internal void SetPaneAndVisible(DockPane pane) + { + SetPane(pane); + SetVisible(); + } + + private void SetPane(DockPane pane) + { + if (pane != null && pane.DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.DockingMdi) + { + if (Form.Parent is DockPane) + SetParent(null); + if (Form.MdiParent != DockPanel.ParentForm) + { + FlagClipWindow = true; + Form.MdiParent = DockPanel.ParentForm; + } + } + else + { + FlagClipWindow = true; + if (Form.MdiParent != null) + Form.MdiParent = null; + if (Form.TopLevel) + Form.TopLevel = false; + SetParent(pane); + } + } + + internal void SetVisible() + { + bool visible; + + if (IsHidden) + visible = false; + else if (Pane != null && Pane.DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.DockingMdi) + visible = true; + else if (Pane != null && Pane.ActiveContent == Content) + visible = true; + else if (Pane != null && Pane.ActiveContent != Content) + visible = false; + else + visible = Form.Visible; + + if (Form.Visible != visible) + Form.Visible = visible; + } + + private void SetParent(Control value) + { + if (Form.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. + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + bool bRestoreFocus = false; + if (Form.ContainsFocus) + { + //Suggested as a fix for a memory leak by bugreports + if (value == null && !IsFloat) + DockPanel.ContentFocusManager.GiveUpFocus(this.Content); + else + { + DockPanel.SaveFocus(); + bRestoreFocus = true; + } + } + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + Form.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 (bRestoreFocus) + Activate(); + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + } + + public void Show() + { + if (DockPanel == null) + Form.Show(); + else + Show(DockPanel); + } + + public void Show(DockPanel dockPanel) + { + if (dockPanel == null) + throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullDockPanel)); + + if (DockState == DockState.Unknown) + Show(dockPanel, DefaultShowState); + else + Activate(); + } + + public void Show(DockPanel dockPanel, DockState dockState) + { + if (dockPanel == null) + throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullDockPanel)); + + if (dockState == DockState.Unknown || dockState == DockState.Hidden) + throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidDockState)); + + dockPanel.SuspendLayout(true); + + DockPanel = dockPanel; + + if (dockState == DockState.Float && FloatPane == null) + Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.Float, true); + else if (PanelPane == null) + { + DockPane paneExisting = null; + foreach (DockPane pane in DockPanel.Panes) + if (pane.DockState == dockState) + { + paneExisting = pane; + break; + } + + if (paneExisting == null) + Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, dockState, true); + else + Pane = paneExisting; + } + + DockState = dockState; + dockPanel.ResumeLayout(true, true); //we'll resume the layout before activating to ensure that the position + Activate(); //and size of the form are finally processed before the form is shown + } + + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] + public void Show(DockPanel dockPanel, Rectangle floatWindowBounds) + { + if (dockPanel == null) + throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullDockPanel)); + + dockPanel.SuspendLayout(true); + + DockPanel = dockPanel; + if (FloatPane == null) + { + IsHidden = true; // to reduce the screen flicker + FloatPane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.Float, false); + FloatPane.FloatWindow.StartPosition = FormStartPosition.Manual; + } + + FloatPane.FloatWindow.Bounds = floatWindowBounds; + + Show(dockPanel, DockState.Float); + Activate(); + + dockPanel.ResumeLayout(true, true); + } + + public void Show(DockPane pane, IDockContent beforeContent) + { + if (pane == null) + throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullPane)); + + if (beforeContent != null && pane.Contents.IndexOf(beforeContent) == -1) + throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidBeforeContent)); + + pane.DockPanel.SuspendLayout(true); + + DockPanel = pane.DockPanel; + Pane = pane; + pane.SetContentIndex(Content, pane.Contents.IndexOf(beforeContent)); + Show(); + + pane.DockPanel.ResumeLayout(true, true); + } + + public void Show(DockPane previousPane, DockAlignment alignment, double proportion) + { + if (previousPane == null) + throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidPrevPane)); + + if (DockHelper.IsDockStateAutoHide(previousPane.DockState)) + throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidPrevPane)); + + previousPane.DockPanel.SuspendLayout(true); + + DockPanel = previousPane.DockPanel; + DockPanel.DockPaneFactory.CreateDockPane(Content, previousPane, alignment, proportion, true); + Show(); + + previousPane.DockPanel.ResumeLayout(true, true); + } + + public void Close() + { + DockPanel dockPanel = DockPanel; + if (dockPanel != null) + dockPanel.SuspendLayout(true); + Form.Close(); + if (dockPanel != null) + dockPanel.ResumeLayout(true, true); + + } + + private DockPaneStripBase.Tab m_tab = null; + internal DockPaneStripBase.Tab GetTab(DockPaneStripBase dockPaneStrip) + { + if (m_tab == null) + m_tab = dockPaneStrip.CreateTab(Content); + + return m_tab; + } + + private IDisposable m_autoHideTab = null; + internal IDisposable AutoHideTab + { + get { return m_autoHideTab; } + set { m_autoHideTab = value; } + } + + #region Events + 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); + } + #endregion + + private void Form_Disposed(object sender, EventArgs e) + { + Dispose(); + } + + private void Form_TextChanged(object sender, EventArgs e) + { + if (DockHelper.IsDockStateAutoHide(DockState)) + DockPanel.RefreshAutoHideStrip(); + else if (Pane != null) + { + if (Pane.FloatWindow != null) + Pane.FloatWindow.SetText(); + Pane.RefreshChanges(); + } + } + + private bool m_flagClipWindow = false; + internal bool FlagClipWindow + { + get { return m_flagClipWindow; } + set + { + if (m_flagClipWindow == value) + return; + + m_flagClipWindow = value; + if (m_flagClipWindow) + Form.Region = new Region(Rectangle.Empty); + else + Form.Region = null; + } + } + + private ContextMenuStrip m_tabPageContextMenuStrip = null; + public ContextMenuStrip TabPageContextMenuStrip + { + get { return m_tabPageContextMenuStrip; } + set { m_tabPageContextMenuStrip = value; } + } + + #region IDockDragSource Members + + Control IDragSource.DragControl + { + get { return Form; } + } + + bool IDockDragSource.CanDockTo(DockPane pane) + { + if (!IsDockStateValid(pane.DockState)) + return false; + + if (Pane == pane && pane.DisplayingContents.Count == 1) + return false; + + return true; + } + + Rectangle IDockDragSource.BeginDrag(Point ptMouse) + { + Size size; + DockPane floatPane = this.FloatPane; + if (DockState == DockState.Float || floatPane == null || floatPane.FloatWindow.NestedPanes.Count != 1) + size = DockPanel.DefaultFloatWindowSize; + else + size = floatPane.FloatWindow.Size; + + Point location; + Rectangle rectPane = Pane.ClientRectangle; + if (DockState == DockState.Document) + { + if (Pane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + location = new Point(rectPane.Left, rectPane.Bottom - size.Height); + else + location = new Point(rectPane.Left, rectPane.Top); + } + else + { + location = new Point(rectPane.Left, rectPane.Bottom); + location.Y -= size.Height; + } + location = Pane.PointToScreen(location); + + 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) + { + DockPane pane = DockPanel.DockPaneFactory.CreateDockPane(Content, floatWindowBounds, true); + } + + public void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex) + { + if (dockStyle == DockStyle.Fill) + { + bool samePane = (Pane == pane); + if (!samePane) + Pane = pane; + + if (contentIndex == -1 || !samePane) + pane.SetContentIndex(Content, contentIndex); + else + { + DockContentCollection contents = pane.Contents; + int oldIndex = contents.IndexOf(Content); + int newIndex = contentIndex; + if (oldIndex < newIndex) + { + newIndex += 1; + if (newIndex > contents.Count -1) + newIndex = -1; + } + pane.SetContentIndex(Content, newIndex); + } + } + else + { + DockPane paneFrom = DockPanel.DockPaneFactory.CreateDockPane(Content, pane.DockState, true); + INestedPanesContainer container = pane.NestedPanesContainer; + if (dockStyle == DockStyle.Left) + paneFrom.DockTo(container, pane, DockAlignment.Left, 0.5); + else if (dockStyle == DockStyle.Right) + paneFrom.DockTo(container, pane, DockAlignment.Right, 0.5); + else if (dockStyle == DockStyle.Top) + paneFrom.DockTo(container, pane, DockAlignment.Top, 0.5); + else if (dockStyle == DockStyle.Bottom) + paneFrom.DockTo(container, pane, DockAlignment.Bottom, 0.5); + + paneFrom.DockState = pane.DockState; + } + } + + public void DockTo(DockPanel panel, DockStyle dockStyle) + { + if (panel != DockPanel) + throw new ArgumentException(Strings.IDockDragSource_DockTo_InvalidPanel, "panel"); + + DockPane pane; + + if (dockStyle == DockStyle.Top) + pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockTop, true); + else if (dockStyle == DockStyle.Bottom) + pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockBottom, true); + else if (dockStyle == DockStyle.Left) + pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockLeft, true); + else if (dockStyle == DockStyle.Right) + pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockRight, true); + else if (dockStyle == DockStyle.Fill) + pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.Document, true); + else + return; + } + + #endregion + } +} diff --git a/trunk/Docking/DockOutlineBase.cs b/trunk/Docking/DockOutlineBase.cs new file mode 100644 index 0000000..9e56645 --- /dev/null +++ b/trunk/Docking/DockOutlineBase.cs @@ -0,0 +1,161 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + internal abstract class DockOutlineBase + { + public DockOutlineBase() + { + Init(); + } + + private void Init() + { + SetValues(Rectangle.Empty, null, DockStyle.None, -1); + SaveOldValues(); + } + + private Rectangle m_oldFloatWindowBounds; + protected Rectangle OldFloatWindowBounds + { + get { return m_oldFloatWindowBounds; } + } + + private Control m_oldDockTo; + protected Control OldDockTo + { + get { return m_oldDockTo; } + } + + private DockStyle m_oldDock; + protected DockStyle OldDock + { + get { return m_oldDock; } + } + + private int m_oldContentIndex; + protected int OldContentIndex + { + get { return m_oldContentIndex; } + } + + protected bool SameAsOldValue + { + get + { + return FloatWindowBounds == OldFloatWindowBounds && + DockTo == OldDockTo && + Dock == OldDock && + ContentIndex == OldContentIndex; + } + } + + private Rectangle m_floatWindowBounds; + public Rectangle FloatWindowBounds + { + get { return m_floatWindowBounds; } + } + + private Control m_dockTo; + public Control DockTo + { + get { return m_dockTo; } + } + + private DockStyle m_dock; + public DockStyle Dock + { + get { return m_dock; } + } + + private int m_contentIndex; + public int ContentIndex + { + get { return m_contentIndex; } + } + + public bool FlagFullEdge + { + get { return m_contentIndex != 0; } + } + + private bool m_flagTestDrop = false; + public bool FlagTestDrop + { + get { return m_flagTestDrop; } + set { m_flagTestDrop = value; } + } + + private void SaveOldValues() + { + m_oldDockTo = m_dockTo; + m_oldDock = m_dock; + m_oldContentIndex = m_contentIndex; + m_oldFloatWindowBounds = m_floatWindowBounds; + } + + protected abstract void OnShow(); + + protected abstract void OnClose(); + + private void SetValues(Rectangle floatWindowBounds, Control dockTo, DockStyle dock, int contentIndex) + { + m_floatWindowBounds = floatWindowBounds; + m_dockTo = dockTo; + m_dock = dock; + m_contentIndex = contentIndex; + FlagTestDrop = true; + } + + private void TestChange() + { + if (m_floatWindowBounds != m_oldFloatWindowBounds || + m_dockTo != m_oldDockTo || + m_dock != m_oldDock || + m_contentIndex != m_oldContentIndex) + OnShow(); + } + + public void Show() + { + SaveOldValues(); + SetValues(Rectangle.Empty, null, DockStyle.None, -1); + TestChange(); + } + + public void Show(DockPane pane, DockStyle dock) + { + SaveOldValues(); + SetValues(Rectangle.Empty, pane, dock, -1); + TestChange(); + } + + public void Show(DockPane pane, int contentIndex) + { + SaveOldValues(); + SetValues(Rectangle.Empty, pane, DockStyle.Fill, contentIndex); + TestChange(); + } + + public void Show(DockPanel dockPanel, DockStyle dock, bool fullPanelEdge) + { + SaveOldValues(); + SetValues(Rectangle.Empty, dockPanel, dock, fullPanelEdge ? -1 : 0); + TestChange(); + } + + public void Show(Rectangle floatWindowBounds) + { + SaveOldValues(); + SetValues(floatWindowBounds, null, DockStyle.None, -1); + TestChange(); + } + + public void Close() + { + OnClose(); + } + } +} diff --git a/trunk/Docking/DockPane.SplitterControl.cs b/trunk/Docking/DockPane.SplitterControl.cs new file mode 100644 index 0000000..da35ed2 --- /dev/null +++ b/trunk/Docking/DockPane.SplitterControl.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + partial class DockPane + { + private class SplitterControl : Control, ISplitterDragSource + { + DockPane m_pane; + + public SplitterControl(DockPane pane) + { + SetStyle(ControlStyles.Selectable, false); + m_pane = pane; + } + + public DockPane DockPane + { + get { return m_pane; } + } + + private DockAlignment m_alignment; + public DockAlignment Alignment + { + get { return m_alignment; } + set + { + m_alignment = value; + if (m_alignment == DockAlignment.Left || m_alignment == DockAlignment.Right) + Cursor = Cursors.VSplit; + else if (m_alignment == DockAlignment.Top || m_alignment == DockAlignment.Bottom) + Cursor = Cursors.HSplit; + else + Cursor = Cursors.Default; + + if (DockPane.DockState == DockState.Document) + Invalidate(); + } + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + if (DockPane.DockState != DockState.Document) + return; + + Graphics g = e.Graphics; + Rectangle rect = ClientRectangle; + if (Alignment == DockAlignment.Top || Alignment == DockAlignment.Bottom) + g.DrawLine(SystemPens.ControlDark, rect.Left, rect.Bottom - 1, rect.Right, rect.Bottom - 1); + else if (Alignment == DockAlignment.Left || Alignment == DockAlignment.Right) + g.DrawLine(SystemPens.ControlDarkDark, rect.Right - 1, rect.Top, rect.Right - 1, rect.Bottom); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if (e.Button != MouseButtons.Left) + return; + + DockPane.DockPanel.BeginDrag(this, Parent.RectangleToScreen(Bounds)); + } + + #region ISplitterDragSource Members + + void ISplitterDragSource.BeginDrag(Rectangle rectSplitter) + { + } + + void ISplitterDragSource.EndDrag() + { + } + + bool ISplitterDragSource.IsVertical + { + get + { + NestedDockingStatus status = DockPane.NestedDockingStatus; + return (status.DisplayingAlignment == DockAlignment.Left || + status.DisplayingAlignment == DockAlignment.Right); + } + } + + Rectangle ISplitterDragSource.DragLimitBounds + { + get + { + NestedDockingStatus status = DockPane.NestedDockingStatus; + Rectangle rectLimit = Parent.RectangleToScreen(status.LogicalBounds); + if (((ISplitterDragSource)this).IsVertical) + { + rectLimit.X += MeasurePane.MinSize; + rectLimit.Width -= 2 * MeasurePane.MinSize; + } + else + { + rectLimit.Y += MeasurePane.MinSize; + rectLimit.Height -= 2 * MeasurePane.MinSize; + } + + return rectLimit; + } + } + + void ISplitterDragSource.MoveSplitter(int offset) + { + NestedDockingStatus status = DockPane.NestedDockingStatus; + double proportion = status.Proportion; + if (status.LogicalBounds.Width <= 0 || status.LogicalBounds.Height <= 0) + return; + else if (status.DisplayingAlignment == DockAlignment.Left) + proportion += ((double)offset) / (double)status.LogicalBounds.Width; + else if (status.DisplayingAlignment == DockAlignment.Right) + proportion -= ((double)offset) / (double)status.LogicalBounds.Width; + else if (status.DisplayingAlignment == DockAlignment.Top) + proportion += ((double)offset) / (double)status.LogicalBounds.Height; + else + proportion -= ((double)offset) / (double)status.LogicalBounds.Height; + + DockPane.SetNestedDockingProportion(proportion); + } + + #region IDragSource Members + + Control IDragSource.DragControl + { + get { return this; } + } + + #endregion + + #endregion + } + + private SplitterControl m_splitter; + private SplitterControl Splitter + { + get { return m_splitter; } + } + + internal Rectangle SplitterBounds + { + set { Splitter.Bounds = value; } + } + + internal DockAlignment SplitterAlignment + { + set { Splitter.Alignment = value; } + } + } +} \ No newline at end of file diff --git a/trunk/Docking/DockPane.cs b/trunk/Docking/DockPane.cs new file mode 100644 index 0000000..83dd35c --- /dev/null +++ b/trunk/Docking/DockPane.cs @@ -0,0 +1,1288 @@ +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 LSLEditor.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); + if (DockState == DockState.Document && DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Top) + y += rectTabStrip.Height; + + 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 width = rectWindow.Width; + int height = TabStripControl.MeasureHeight(); + + int y = 0; + if (DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + y = rectWindow.Height - height; + else + y = rectWindow.Y; + + 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= 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 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=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]; + if (c.DockHandler.DockState == DockState) + { + 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 + } +} diff --git a/trunk/Docking/DockPaneCaptionBase.cs b/trunk/Docking/DockPaneCaptionBase.cs new file mode 100644 index 0000000..5c2c180 --- /dev/null +++ b/trunk/Docking/DockPaneCaptionBase.cs @@ -0,0 +1,100 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Security.Permissions; + +namespace LSLEditor.Docking +{ + public abstract class DockPaneCaptionBase : Control + { + protected internal DockPaneCaptionBase(DockPane pane) + { + m_dockPane = pane; + + SetStyle(ControlStyles.OptimizedDoubleBuffer | + ControlStyles.ResizeRedraw | + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint, true); + SetStyle(ControlStyles.Selectable, false); + } + + private DockPane m_dockPane; + protected DockPane DockPane + { + get { return m_dockPane; } + } + + protected DockPane.AppearanceStyle Appearance + { + get { return DockPane.Appearance; } + } + + protected bool HasTabPageContextMenu + { + get { return DockPane.HasTabPageContextMenu; } + } + + protected void ShowTabPageContextMenu(Point position) + { + DockPane.ShowTabPageContextMenu(this, position); + } + + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); + + if (e.Button == MouseButtons.Right) + ShowTabPageContextMenu(new Point(e.X, e.Y)); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if (e.Button == MouseButtons.Left && + DockPane.DockPanel.AllowEndUserDocking && + DockPane.AllowDockDragAndDrop && + !DockHelper.IsDockStateAutoHide(DockPane.DockState) && + DockPane.ActiveContent != null) + DockPane.DockPanel.BeginDrag(DockPane); + } + + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_LBUTTONDBLCLK) + { + if (DockHelper.IsDockStateAutoHide(DockPane.DockState)) + { + DockPane.DockPanel.ActiveAutoHideContent = null; + return; + } + + if (DockPane.IsFloat) + DockPane.RestoreToPanel(); + else + DockPane.Float(); + } + base.WndProc(ref m); + } + + internal void RefreshChanges() + { + if (IsDisposed) + return; + + OnRefreshChanges(); + } + + protected virtual void OnRightToLeftLayoutChanged() + { + } + + protected virtual void OnRefreshChanges() + { + } + + protected internal abstract int MeasureHeight(); + } +} diff --git a/trunk/Docking/DockPaneCollection.cs b/trunk/Docking/DockPaneCollection.cs new file mode 100644 index 0000000..7896aec --- /dev/null +++ b/trunk/Docking/DockPaneCollection.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + public class DockPaneCollection : ReadOnlyCollection + { + internal DockPaneCollection() + : base(new List()) + { + } + + internal int Add(DockPane pane) + { + if (Items.Contains(pane)) + return Items.IndexOf(pane); + + Items.Add(pane); + return Count - 1; + } + + internal void AddAt(DockPane pane, int index) + { + if (index < 0 || index > Items.Count - 1) + return; + + if (Contains(pane)) + return; + + Items.Insert(index, pane); + } + + internal void Dispose() + { + for (int i=Count - 1; i>=0; i--) + this[i].Close(); + } + + internal void Remove(DockPane pane) + { + Items.Remove(pane); + } + } +} diff --git a/trunk/Docking/DockPaneStripBase.cs b/trunk/Docking/DockPaneStripBase.cs new file mode 100644 index 0000000..10b6368 --- /dev/null +++ b/trunk/Docking/DockPaneStripBase.cs @@ -0,0 +1,252 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Collections; +using System.Collections.Generic; +using System.Security.Permissions; +using System.Diagnostics.CodeAnalysis; + +namespace LSLEditor.Docking +{ + public abstract class DockPaneStripBase : Control + { + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + protected internal class Tab : IDisposable + { + private IDockContent m_content; + + public Tab(IDockContent content) + { + m_content = content; + } + + ~Tab() + { + Dispose(false); + } + + public IDockContent Content + { + get { return m_content; } + } + + public Form ContentForm + { + get { return m_content as Form; } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + protected sealed class TabCollection : IEnumerable + { + #region IEnumerable Members + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + #endregion + + internal TabCollection(DockPane pane) + { + m_dockPane = pane; + } + + private DockPane m_dockPane; + public DockPane DockPane + { + get { return m_dockPane; } + } + + public int Count + { + get { return DockPane.DisplayingContents.Count; } + } + + public Tab this[int index] + { + get + { + IDockContent content = DockPane.DisplayingContents[index]; + if (content == null) + throw (new ArgumentOutOfRangeException("index")); + return content.DockHandler.GetTab(DockPane.TabStripControl); + } + } + + public bool Contains(Tab tab) + { + return (IndexOf(tab) != -1); + } + + public bool Contains(IDockContent content) + { + return (IndexOf(content) != -1); + } + + public int IndexOf(Tab tab) + { + if (tab == null) + return -1; + + return DockPane.DisplayingContents.IndexOf(tab.Content); + } + + public int IndexOf(IDockContent content) + { + return DockPane.DisplayingContents.IndexOf(content); + } + } + + protected DockPaneStripBase(DockPane pane) + { + m_dockPane = pane; + + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + SetStyle(ControlStyles.Selectable, false); + AllowDrop = true; + } + + private DockPane m_dockPane; + protected DockPane DockPane + { + get { return m_dockPane; } + } + + protected DockPane.AppearanceStyle Appearance + { + get { return DockPane.Appearance; } + } + + private TabCollection m_tabs = null; + protected TabCollection Tabs + { + get + { + if (m_tabs == null) + m_tabs = new TabCollection(DockPane); + + return m_tabs; + } + } + + internal void RefreshChanges() + { + if (IsDisposed) + return; + + OnRefreshChanges(); + } + + protected virtual void OnRefreshChanges() + { + } + + protected internal abstract int MeasureHeight(); + + protected internal abstract void EnsureTabVisible(IDockContent content); + + protected int HitTest() + { + return HitTest(PointToClient(Control.MousePosition)); + } + + protected internal abstract int HitTest(Point point); + + protected internal abstract GraphicsPath GetOutline(int index); + + protected internal virtual Tab CreateTab(IDockContent content) + { + return new Tab(content); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + int index = HitTest(); + if (index != -1) + { + IDockContent content = Tabs[index].Content; + if (DockPane.ActiveContent != content) + DockPane.ActiveContent = content; + } + + if (e.Button == MouseButtons.Left) + { + if (DockPane.DockPanel.AllowEndUserDocking && DockPane.AllowDockDragAndDrop && DockPane.ActiveContent.DockHandler.AllowEndUserDocking) + DockPane.DockPanel.BeginDrag(DockPane.ActiveContent.DockHandler); + } + } + + protected bool HasTabPageContextMenu + { + get { return DockPane.HasTabPageContextMenu; } + } + + protected void ShowTabPageContextMenu(Point position) + { + DockPane.ShowTabPageContextMenu(this, position); + } + + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); + + if (e.Button == MouseButtons.Right) + ShowTabPageContextMenu(new Point(e.X, e.Y)); + } + + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_LBUTTONDBLCLK) + { + base.WndProc(ref m); + + int index = HitTest(); + if (DockPane.DockPanel.AllowEndUserDocking && index != -1) + { + IDockContent content = Tabs[index].Content; + if (content.DockHandler.CheckDockState(!content.DockHandler.IsFloat) != DockState.Unknown) + content.DockHandler.IsFloat = !content.DockHandler.IsFloat; + } + + return; + } + + base.WndProc(ref m); + return; + } + + protected override void OnDragOver(DragEventArgs drgevent) + { + base.OnDragOver(drgevent); + + int index = HitTest(); + if (index != -1) + { + IDockContent content = Tabs[index].Content; + if (DockPane.ActiveContent != content) + DockPane.ActiveContent = content; + } + } + } +} diff --git a/trunk/Docking/DockPanel.AutoHideWindow.cs b/trunk/Docking/DockPanel.AutoHideWindow.cs new file mode 100644 index 0000000..062768a --- /dev/null +++ b/trunk/Docking/DockPanel.AutoHideWindow.cs @@ -0,0 +1,612 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace LSLEditor.Docking +{ + partial class DockPanel + { + private class AutoHideWindowControl : Panel, ISplitterDragSource + { + private class SplitterControl : SplitterBase + { + public SplitterControl(AutoHideWindowControl autoHideWindow) + { + m_autoHideWindow = autoHideWindow; + } + + private AutoHideWindowControl m_autoHideWindow; + private AutoHideWindowControl AutoHideWindow + { + get { return m_autoHideWindow; } + } + + protected override int SplitterSize + { + get { return Measures.SplitterSize; } + } + + protected override void StartDrag() + { + AutoHideWindow.DockPanel.BeginDrag(AutoHideWindow, AutoHideWindow.RectangleToScreen(Bounds)); + } + } + + #region consts + private const int ANIMATE_TIME = 100; // in mini-seconds + #endregion + + private Timer m_timerMouseTrack; + private SplitterControl m_splitter; + + public AutoHideWindowControl(DockPanel dockPanel) + { + m_dockPanel = dockPanel; + + m_timerMouseTrack = new Timer(); + m_timerMouseTrack.Tick += new EventHandler(TimerMouseTrack_Tick); + + Visible = false; + m_splitter = new SplitterControl(this); + Controls.Add(m_splitter); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + m_timerMouseTrack.Dispose(); + } + base.Dispose(disposing); + } + + private DockPanel m_dockPanel = null; + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private DockPane m_activePane = null; + public DockPane ActivePane + { + get { return m_activePane; } + } + private void SetActivePane() + { + DockPane value = (ActiveContent == null ? null : ActiveContent.DockHandler.Pane); + + if (value == m_activePane) + return; + + m_activePane = value; + } + + private IDockContent m_activeContent = null; + public IDockContent ActiveContent + { + get { return m_activeContent; } + set + { + if (value == m_activeContent) + return; + + if (value != null) + { + if (!DockHelper.IsDockStateAutoHide(value.DockHandler.DockState) || value.DockHandler.DockPanel != DockPanel) + throw (new InvalidOperationException(Strings.DockPanel_ActiveAutoHideContent_InvalidValue)); + } + + DockPanel.SuspendLayout(); + + if (m_activeContent != null) + { + if (m_activeContent.DockHandler.Form.ContainsFocus) + DockPanel.ContentFocusManager.GiveUpFocus(m_activeContent); + AnimateWindow(false); + } + + m_activeContent = value; + SetActivePane(); + if (ActivePane != null) + ActivePane.ActiveContent = m_activeContent; + + if (m_activeContent != null) + AnimateWindow(true); + + DockPanel.ResumeLayout(); + DockPanel.RefreshAutoHideStrip(); + + SetTimerMouseTrack(); + } + } + + public DockState DockState + { + get { return ActiveContent == null ? DockState.Unknown : ActiveContent.DockHandler.DockState; } + } + + private bool m_flagAnimate = true; + private bool FlagAnimate + { + get { return m_flagAnimate; } + set { m_flagAnimate = value; } + } + + private bool m_flagDragging = false; + internal bool FlagDragging + { + get { return m_flagDragging; } + set + { + if (m_flagDragging == value) + return; + + m_flagDragging = value; + SetTimerMouseTrack(); + } + } + + private void AnimateWindow(bool show) + { + if (!FlagAnimate && Visible != show) + { + Visible = show; + return; + } + + Parent.SuspendLayout(); + + Rectangle rectSource = GetRectangle(!show); + Rectangle rectTarget = GetRectangle(show); + int dxLoc, dyLoc; + int dWidth, dHeight; + dxLoc = dyLoc = dWidth = dHeight = 0; + if (DockState == DockState.DockTopAutoHide) + dHeight = show ? 1 : -1; + else if (DockState == DockState.DockLeftAutoHide) + dWidth = show ? 1 : -1; + else if (DockState == DockState.DockRightAutoHide) + { + dxLoc = show ? -1 : 1; + dWidth = show ? 1 : -1; + } + else if (DockState == DockState.DockBottomAutoHide) + { + dyLoc = (show ? -1 : 1); + dHeight = (show ? 1 : -1); + } + + if (show) + { + Bounds = DockPanel.GetAutoHideWindowBounds(new Rectangle(-rectTarget.Width, -rectTarget.Height, rectTarget.Width, rectTarget.Height)); + if (Visible == false) + Visible = true; + PerformLayout(); + } + + SuspendLayout(); + + LayoutAnimateWindow(rectSource); + if (Visible == false) + Visible = true; + + int speedFactor = 1; + int totalPixels = (rectSource.Width != rectTarget.Width) ? + Math.Abs(rectSource.Width - rectTarget.Width) : + Math.Abs(rectSource.Height - rectTarget.Height); + int remainPixels = totalPixels; + DateTime startingTime = DateTime.Now; + while (rectSource != rectTarget) + { + DateTime startPerMove = DateTime.Now; + + rectSource.X += dxLoc * speedFactor; + rectSource.Y += dyLoc * speedFactor; + rectSource.Width += dWidth * speedFactor; + rectSource.Height += dHeight * speedFactor; + if (Math.Sign(rectTarget.X - rectSource.X) != Math.Sign(dxLoc)) + rectSource.X = rectTarget.X; + if (Math.Sign(rectTarget.Y - rectSource.Y) != Math.Sign(dyLoc)) + rectSource.Y = rectTarget.Y; + if (Math.Sign(rectTarget.Width - rectSource.Width) != Math.Sign(dWidth)) + rectSource.Width = rectTarget.Width; + if (Math.Sign(rectTarget.Height - rectSource.Height) != Math.Sign(dHeight)) + rectSource.Height = rectTarget.Height; + + LayoutAnimateWindow(rectSource); + if (Parent != null) + Parent.Update(); + + remainPixels -= speedFactor; + + while (true) + { + TimeSpan time = new TimeSpan(0, 0, 0, 0, ANIMATE_TIME); + TimeSpan elapsedPerMove = DateTime.Now - startPerMove; + TimeSpan elapsedTime = DateTime.Now - startingTime; + if (((int)((time - elapsedTime).TotalMilliseconds)) <= 0) + { + speedFactor = remainPixels; + break; + } + else + speedFactor = remainPixels * (int)elapsedPerMove.TotalMilliseconds / (int)((time - elapsedTime).TotalMilliseconds); + if (speedFactor >= 1) + break; + } + } + ResumeLayout(); + Parent.ResumeLayout(); + } + + private void LayoutAnimateWindow(Rectangle rect) + { + Bounds = DockPanel.GetAutoHideWindowBounds(rect); + + Rectangle rectClient = ClientRectangle; + + if (DockState == DockState.DockLeftAutoHide) + ActivePane.Location = new Point(rectClient.Right - 2 - Measures.SplitterSize - ActivePane.Width, ActivePane.Location.Y); + else if (DockState == DockState.DockTopAutoHide) + ActivePane.Location = new Point(ActivePane.Location.X, rectClient.Bottom - 2 - Measures.SplitterSize - ActivePane.Height); + } + + private Rectangle GetRectangle(bool show) + { + if (DockState == DockState.Unknown) + return Rectangle.Empty; + + Rectangle rect = DockPanel.AutoHideWindowRectangle; + + if (show) + return rect; + + if (DockState == DockState.DockLeftAutoHide) + rect.Width = 0; + else if (DockState == DockState.DockRightAutoHide) + { + rect.X += rect.Width; + rect.Width = 0; + } + else if (DockState == DockState.DockTopAutoHide) + rect.Height = 0; + else + { + rect.Y += rect.Height; + rect.Height = 0; + } + + return rect; + } + + private void SetTimerMouseTrack() + { + if (ActivePane == null || ActivePane.IsActivated || FlagDragging) + { + m_timerMouseTrack.Enabled = false; + return; + } + + // start the timer + int hovertime = SystemInformation.MouseHoverTime ; + + // assign a default value 400 in case of setting Timer.Interval invalid value exception + if (hovertime <= 0) + hovertime = 400; + + m_timerMouseTrack.Interval = 2 * (int)hovertime; + m_timerMouseTrack.Enabled = true; + } + + protected virtual Rectangle DisplayingRectangle + { + get + { + Rectangle rect = ClientRectangle; + + // exclude the border and the splitter + if (DockState == DockState.DockBottomAutoHide) + { + rect.Y += 2 + Measures.SplitterSize; + rect.Height -= 2 + Measures.SplitterSize; + } + else if (DockState == DockState.DockRightAutoHide) + { + rect.X += 2 + Measures.SplitterSize; + rect.Width -= 2 + Measures.SplitterSize; + } + else if (DockState == DockState.DockTopAutoHide) + rect.Height -= 2 + Measures.SplitterSize; + else if (DockState == DockState.DockLeftAutoHide) + rect.Width -= 2 + Measures.SplitterSize; + + return rect; + } + } + + protected override void OnLayout(LayoutEventArgs levent) + { + DockPadding.All = 0; + if (DockState == DockState.DockLeftAutoHide) + { + DockPadding.Right = 2; + m_splitter.Dock = DockStyle.Right; + } + else if (DockState == DockState.DockRightAutoHide) + { + DockPadding.Left = 2; + m_splitter.Dock = DockStyle.Left; + } + else if (DockState == DockState.DockTopAutoHide) + { + DockPadding.Bottom = 2; + m_splitter.Dock = DockStyle.Bottom; + } + else if (DockState == DockState.DockBottomAutoHide) + { + DockPadding.Top = 2; + m_splitter.Dock = DockStyle.Top; + } + + Rectangle rectDisplaying = DisplayingRectangle; + Rectangle rectHidden = new Rectangle(-rectDisplaying.Width, rectDisplaying.Y, rectDisplaying.Width, rectDisplaying.Height); + foreach (Control c in Controls) + { + DockPane pane = c as DockPane; + if (pane == null) + continue; + + + if (pane == ActivePane) + pane.Bounds = rectDisplaying; + else + pane.Bounds = rectHidden; + } + + base.OnLayout(levent); + } + + protected override void OnPaint(PaintEventArgs e) + { + // Draw the border + Graphics g = e.Graphics; + + if (DockState == DockState.DockBottomAutoHide) + g.DrawLine(SystemPens.ControlLightLight, 0, 1, ClientRectangle.Right, 1); + else if (DockState == DockState.DockRightAutoHide) + g.DrawLine(SystemPens.ControlLightLight, 1, 0, 1, ClientRectangle.Bottom); + else if (DockState == DockState.DockTopAutoHide) + { + g.DrawLine(SystemPens.ControlDark, 0, ClientRectangle.Height - 2, ClientRectangle.Right, ClientRectangle.Height - 2); + g.DrawLine(SystemPens.ControlDarkDark, 0, ClientRectangle.Height - 1, ClientRectangle.Right, ClientRectangle.Height - 1); + } + else if (DockState == DockState.DockLeftAutoHide) + { + g.DrawLine(SystemPens.ControlDark, ClientRectangle.Width - 2, 0, ClientRectangle.Width - 2, ClientRectangle.Bottom); + g.DrawLine(SystemPens.ControlDarkDark, ClientRectangle.Width - 1, 0, ClientRectangle.Width - 1, ClientRectangle.Bottom); + } + + base.OnPaint(e); + } + + public void RefreshActiveContent() + { + if (ActiveContent == null) + return; + + if (!DockHelper.IsDockStateAutoHide(ActiveContent.DockHandler.DockState)) + { + FlagAnimate = false; + ActiveContent = null; + FlagAnimate = true; + } + } + + public void RefreshActivePane() + { + SetTimerMouseTrack(); + } + + private void TimerMouseTrack_Tick(object sender, EventArgs e) + { + if (IsDisposed) + return; + + if (ActivePane == null || ActivePane.IsActivated) + { + m_timerMouseTrack.Enabled = false; + return; + } + + DockPane pane = ActivePane; + Point ptMouseInAutoHideWindow = PointToClient(Control.MousePosition); + Point ptMouseInDockPanel = DockPanel.PointToClient(Control.MousePosition); + + Rectangle rectTabStrip = DockPanel.GetTabStripRectangle(pane.DockState); + + if (!ClientRectangle.Contains(ptMouseInAutoHideWindow) && !rectTabStrip.Contains(ptMouseInDockPanel)) + { + ActiveContent = null; + m_timerMouseTrack.Enabled = false; + } + } + + #region ISplitterDragSource Members + + void ISplitterDragSource.BeginDrag(Rectangle rectSplitter) + { + FlagDragging = true; + } + + void ISplitterDragSource.EndDrag() + { + FlagDragging = false; + } + + bool ISplitterDragSource.IsVertical + { + get { return (DockState == DockState.DockLeftAutoHide || DockState == DockState.DockRightAutoHide); } + } + + Rectangle ISplitterDragSource.DragLimitBounds + { + get + { + Rectangle rectLimit = DockPanel.DockArea; + + if ((this as ISplitterDragSource).IsVertical) + { + rectLimit.X += MeasurePane.MinSize; + rectLimit.Width -= 2 * MeasurePane.MinSize; + } + else + { + rectLimit.Y += MeasurePane.MinSize; + rectLimit.Height -= 2 * MeasurePane.MinSize; + } + + return DockPanel.RectangleToScreen(rectLimit); + } + } + + void ISplitterDragSource.MoveSplitter(int offset) + { + Rectangle rectDockArea = DockPanel.DockArea; + IDockContent content = ActiveContent; + if (DockState == DockState.DockLeftAutoHide && rectDockArea.Width > 0) + { + if (content.DockHandler.AutoHidePortion < 1) + content.DockHandler.AutoHidePortion += ((double)offset) / (double)rectDockArea.Width; + else + content.DockHandler.AutoHidePortion = Width + offset; + } + else if (DockState == DockState.DockRightAutoHide && rectDockArea.Width > 0) + { + if (content.DockHandler.AutoHidePortion < 1) + content.DockHandler.AutoHidePortion -= ((double)offset) / (double)rectDockArea.Width; + else + content.DockHandler.AutoHidePortion = Width - offset; + } + else if (DockState == DockState.DockBottomAutoHide && rectDockArea.Height > 0) + { + if (content.DockHandler.AutoHidePortion < 1) + content.DockHandler.AutoHidePortion -= ((double)offset) / (double)rectDockArea.Height; + else + content.DockHandler.AutoHidePortion = Height - offset; + } + else if (DockState == DockState.DockTopAutoHide && rectDockArea.Height > 0) + { + if (content.DockHandler.AutoHidePortion < 1) + content.DockHandler.AutoHidePortion += ((double)offset) / (double)rectDockArea.Height; + else + content.DockHandler.AutoHidePortion = Height + offset; + } + } + + #region IDragSource Members + + Control IDragSource.DragControl + { + get { return this; } + } + + #endregion + + #endregion + } + + private AutoHideWindowControl AutoHideWindow + { + get { return m_autoHideWindow; } + } + + internal Control AutoHideControl + { + get { return m_autoHideWindow; } + } + + internal void RefreshActiveAutoHideContent() + { + AutoHideWindow.RefreshActiveContent(); + } + + internal Rectangle AutoHideWindowRectangle + { + get + { + DockState state = AutoHideWindow.DockState; + Rectangle rectDockArea = DockArea; + if (ActiveAutoHideContent == null) + return Rectangle.Empty; + + if (Parent == null) + return Rectangle.Empty; + + Rectangle rect = Rectangle.Empty; + double autoHideSize = ActiveAutoHideContent.DockHandler.AutoHidePortion; + if (state == DockState.DockLeftAutoHide) + { + if (autoHideSize < 1) + autoHideSize = rectDockArea.Width * autoHideSize; + if (autoHideSize > rectDockArea.Width - MeasurePane.MinSize) + autoHideSize = rectDockArea.Width - MeasurePane.MinSize; + rect.X = rectDockArea.X; + rect.Y = rectDockArea.Y; + rect.Width = (int)autoHideSize; + rect.Height = rectDockArea.Height; + } + else if (state == DockState.DockRightAutoHide) + { + if (autoHideSize < 1) + autoHideSize = rectDockArea.Width * autoHideSize; + if (autoHideSize > rectDockArea.Width - MeasurePane.MinSize) + autoHideSize = rectDockArea.Width - MeasurePane.MinSize; + rect.X = rectDockArea.X + rectDockArea.Width - (int)autoHideSize; + rect.Y = rectDockArea.Y; + rect.Width = (int)autoHideSize; + rect.Height = rectDockArea.Height; + } + else if (state == DockState.DockTopAutoHide) + { + if (autoHideSize < 1) + autoHideSize = rectDockArea.Height * autoHideSize; + if (autoHideSize > rectDockArea.Height - MeasurePane.MinSize) + autoHideSize = rectDockArea.Height - MeasurePane.MinSize; + rect.X = rectDockArea.X; + rect.Y = rectDockArea.Y; + rect.Width = rectDockArea.Width; + rect.Height = (int)autoHideSize; + } + else if (state == DockState.DockBottomAutoHide) + { + if (autoHideSize < 1) + autoHideSize = rectDockArea.Height * autoHideSize; + if (autoHideSize > rectDockArea.Height - MeasurePane.MinSize) + autoHideSize = rectDockArea.Height - MeasurePane.MinSize; + rect.X = rectDockArea.X; + rect.Y = rectDockArea.Y + rectDockArea.Height - (int)autoHideSize; + rect.Width = rectDockArea.Width; + rect.Height = (int)autoHideSize; + } + + return rect; + } + } + + internal Rectangle GetAutoHideWindowBounds(Rectangle rectAutoHideWindow) + { + if (DocumentStyle == DocumentStyle.SystemMdi || + DocumentStyle == DocumentStyle.DockingMdi) + return (Parent == null) ? Rectangle.Empty : Parent.RectangleToClient(RectangleToScreen(rectAutoHideWindow)); + else + return rectAutoHideWindow; + } + + internal void RefreshAutoHideStrip() + { + AutoHideStripControl.RefreshChanges(); + } + + } +} diff --git a/trunk/Docking/DockPanel.DockDragHandler.cs b/trunk/Docking/DockPanel.DockDragHandler.cs new file mode 100644 index 0000000..ebc2254 --- /dev/null +++ b/trunk/Docking/DockPanel.DockDragHandler.cs @@ -0,0 +1,814 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.ComponentModel; + +namespace LSLEditor.Docking +{ + partial class DockPanel + { + private sealed class DockDragHandler : DragHandler + { + private class DockIndicator : DragForm + { + #region IHitTest + private interface IHitTest + { + DockStyle HitTest(Point pt); + DockStyle Status { get; set; } + } + #endregion + + #region PanelIndicator + private class PanelIndicator : PictureBox, IHitTest + { + private static Image _imagePanelLeft = Resources.DockIndicator_PanelLeft; + private static Image _imagePanelRight = Resources.DockIndicator_PanelRight; + private static Image _imagePanelTop = Resources.DockIndicator_PanelTop; + private static Image _imagePanelBottom = Resources.DockIndicator_PanelBottom; + private static Image _imagePanelFill = Resources.DockIndicator_PanelFill; + private static Image _imagePanelLeftActive = Resources.DockIndicator_PanelLeft_Active; + private static Image _imagePanelRightActive = Resources.DockIndicator_PanelRight_Active; + private static Image _imagePanelTopActive = Resources.DockIndicator_PanelTop_Active; + private static Image _imagePanelBottomActive = Resources.DockIndicator_PanelBottom_Active; + private static Image _imagePanelFillActive = Resources.DockIndicator_PanelFill_Active; + + public PanelIndicator(DockStyle dockStyle) + { + m_dockStyle = dockStyle; + SizeMode = PictureBoxSizeMode.AutoSize; + Image = ImageInactive; + } + + private DockStyle m_dockStyle; + private DockStyle DockStyle + { + get { return m_dockStyle; } + } + + private DockStyle m_status; + public DockStyle Status + { + get { return m_status; } + set + { + if (value != DockStyle && value != DockStyle.None) + throw new InvalidEnumArgumentException(); + + if (m_status == value) + return; + + m_status = value; + IsActivated = (m_status != DockStyle.None); + } + } + + private Image ImageInactive + { + get + { + if (DockStyle == DockStyle.Left) + return _imagePanelLeft; + else if (DockStyle == DockStyle.Right) + return _imagePanelRight; + else if (DockStyle == DockStyle.Top) + return _imagePanelTop; + else if (DockStyle == DockStyle.Bottom) + return _imagePanelBottom; + else if (DockStyle == DockStyle.Fill) + return _imagePanelFill; + else + return null; + } + } + + private Image ImageActive + { + get + { + if (DockStyle == DockStyle.Left) + return _imagePanelLeftActive; + else if (DockStyle == DockStyle.Right) + return _imagePanelRightActive; + else if (DockStyle == DockStyle.Top) + return _imagePanelTopActive; + else if (DockStyle == DockStyle.Bottom) + return _imagePanelBottomActive; + else if (DockStyle == DockStyle.Fill) + return _imagePanelFillActive; + else + return null; + } + } + + private bool m_isActivated = false; + private bool IsActivated + { + get { return m_isActivated; } + set + { + m_isActivated = value; + Image = IsActivated ? ImageActive : ImageInactive; + } + } + + public DockStyle HitTest(Point pt) + { + return this.Visible && ClientRectangle.Contains(PointToClient(pt)) ? DockStyle : DockStyle.None; + } + } + #endregion PanelIndicator + + #region PaneIndicator + private class PaneIndicator : PictureBox, IHitTest + { + private struct HotSpotIndex + { + public HotSpotIndex(int x, int y, DockStyle dockStyle) + { + m_x = x; + m_y = y; + m_dockStyle = dockStyle; + } + + private int m_x; + public int X + { + get { return m_x; } + } + + private int m_y; + public int Y + { + get { return m_y; } + } + + private DockStyle m_dockStyle; + public DockStyle DockStyle + { + get { return m_dockStyle; } + } + } + + private static Bitmap _bitmapPaneDiamond = Resources.DockIndicator_PaneDiamond; + private static Bitmap _bitmapPaneDiamondLeft = Resources.DockIndicator_PaneDiamond_Left; + private static Bitmap _bitmapPaneDiamondRight = Resources.DockIndicator_PaneDiamond_Right; + private static Bitmap _bitmapPaneDiamondTop = Resources.DockIndicator_PaneDiamond_Top; + private static Bitmap _bitmapPaneDiamondBottom = Resources.DockIndicator_PaneDiamond_Bottom; + private static Bitmap _bitmapPaneDiamondFill = Resources.DockIndicator_PaneDiamond_Fill; + private static Bitmap _bitmapPaneDiamondHotSpot = Resources.DockIndicator_PaneDiamond_HotSpot; + private static Bitmap _bitmapPaneDiamondHotSpotIndex = Resources.DockIndicator_PaneDiamond_HotSpotIndex; + private static HotSpotIndex[] _hotSpots = new HotSpotIndex[] + { + new HotSpotIndex(1, 0, DockStyle.Top), + new HotSpotIndex(0, 1, DockStyle.Left), + new HotSpotIndex(1, 1, DockStyle.Fill), + new HotSpotIndex(2, 1, DockStyle.Right), + new HotSpotIndex(1, 2, DockStyle.Bottom) + }; + private static GraphicsPath _displayingGraphicsPath = DrawHelper.CalculateGraphicsPathFromBitmap(_bitmapPaneDiamond); + + public PaneIndicator() + { + SizeMode = PictureBoxSizeMode.AutoSize; + Image = _bitmapPaneDiamond; + Region = new Region(DisplayingGraphicsPath); + } + + public static GraphicsPath DisplayingGraphicsPath + { + get { return _displayingGraphicsPath; } + } + + public DockStyle HitTest(Point pt) + { + if (!Visible) + return DockStyle.None; + + pt = PointToClient(pt); + if (!ClientRectangle.Contains(pt)) + return DockStyle.None; + + for (int i = _hotSpots.GetLowerBound(0); i <= _hotSpots.GetUpperBound(0); i++) + { + if (_bitmapPaneDiamondHotSpot.GetPixel(pt.X, pt.Y) == _bitmapPaneDiamondHotSpotIndex.GetPixel(_hotSpots[i].X, _hotSpots[i].Y)) + return _hotSpots[i].DockStyle; + } + + return DockStyle.None; + } + + private DockStyle m_status = DockStyle.None; + public DockStyle Status + { + get { return m_status; } + set + { + m_status = value; + if (m_status == DockStyle.None) + Image = _bitmapPaneDiamond; + else if (m_status == DockStyle.Left) + Image = _bitmapPaneDiamondLeft; + else if (m_status == DockStyle.Right) + Image = _bitmapPaneDiamondRight; + else if (m_status == DockStyle.Top) + Image = _bitmapPaneDiamondTop; + else if (m_status == DockStyle.Bottom) + Image = _bitmapPaneDiamondBottom; + else if (m_status == DockStyle.Fill) + Image = _bitmapPaneDiamondFill; + } + } + } + #endregion PaneIndicator + + #region consts + private int _PanelIndicatorMargin = 10; + #endregion + + private DockDragHandler m_dragHandler; + + public DockIndicator(DockDragHandler dragHandler) + { + m_dragHandler = dragHandler; + Controls.AddRange(new Control[] { + PaneDiamond, + PanelLeft, + PanelRight, + PanelTop, + PanelBottom, + PanelFill + }); + Region = new Region(Rectangle.Empty); + } + + private PaneIndicator m_paneDiamond = null; + private PaneIndicator PaneDiamond + { + get + { + if (m_paneDiamond == null) + m_paneDiamond = new PaneIndicator(); + + return m_paneDiamond; + } + } + + private PanelIndicator m_panelLeft = null; + private PanelIndicator PanelLeft + { + get + { + if (m_panelLeft == null) + m_panelLeft = new PanelIndicator(DockStyle.Left); + + return m_panelLeft; + } + } + + private PanelIndicator m_panelRight = null; + private PanelIndicator PanelRight + { + get + { + if (m_panelRight == null) + m_panelRight = new PanelIndicator(DockStyle.Right); + + return m_panelRight; + } + } + + private PanelIndicator m_panelTop = null; + private PanelIndicator PanelTop + { + get + { + if (m_panelTop == null) + m_panelTop = new PanelIndicator(DockStyle.Top); + + return m_panelTop; + } + } + + private PanelIndicator m_panelBottom = null; + private PanelIndicator PanelBottom + { + get + { + if (m_panelBottom == null) + m_panelBottom = new PanelIndicator(DockStyle.Bottom); + + return m_panelBottom; + } + } + + private PanelIndicator m_panelFill = null; + private PanelIndicator PanelFill + { + get + { + if (m_panelFill == null) + m_panelFill = new PanelIndicator(DockStyle.Fill); + + return m_panelFill; + } + } + + private bool m_fullPanelEdge = false; + public bool FullPanelEdge + { + get { return m_fullPanelEdge; } + set + { + if (m_fullPanelEdge == value) + return; + + m_fullPanelEdge = value; + RefreshChanges(); + } + } + + public DockDragHandler DragHandler + { + get { return m_dragHandler; } + } + + public DockPanel DockPanel + { + get { return DragHandler.DockPanel; } + } + + private DockPane m_dockPane = null; + public DockPane DockPane + { + get { return m_dockPane; } + internal set + { + if (m_dockPane == value) + return; + + DockPane oldDisplayingPane = DisplayingPane; + m_dockPane = value; + if (oldDisplayingPane != DisplayingPane) + RefreshChanges(); + } + } + + private IHitTest m_hitTest = null; + private IHitTest HitTestResult + { + get { return m_hitTest; } + set + { + if (m_hitTest == value) + return; + + if (m_hitTest != null) + m_hitTest.Status = DockStyle.None; + + m_hitTest = value; + } + } + + private DockPane DisplayingPane + { + get { return ShouldPaneDiamondVisible() ? DockPane : null; } + } + + private void RefreshChanges() + { + Region region = new Region(Rectangle.Empty); + Rectangle rectDockArea = FullPanelEdge ? DockPanel.DockArea : DockPanel.DocumentWindowBounds; + + rectDockArea = RectangleToClient(DockPanel.RectangleToScreen(rectDockArea)); + if (ShouldPanelIndicatorVisible(DockState.DockLeft)) + { + PanelLeft.Location = new Point(rectDockArea.X + _PanelIndicatorMargin, rectDockArea.Y + (rectDockArea.Height - PanelRight.Height) / 2); + PanelLeft.Visible = true; + region.Union(PanelLeft.Bounds); + } + else + PanelLeft.Visible = false; + + if (ShouldPanelIndicatorVisible(DockState.DockRight)) + { + PanelRight.Location = new Point(rectDockArea.X + rectDockArea.Width - PanelRight.Width - _PanelIndicatorMargin, rectDockArea.Y + (rectDockArea.Height - PanelRight.Height) / 2); + PanelRight.Visible = true; + region.Union(PanelRight.Bounds); + } + else + PanelRight.Visible = false; + + if (ShouldPanelIndicatorVisible(DockState.DockTop)) + { + PanelTop.Location = new Point(rectDockArea.X + (rectDockArea.Width - PanelTop.Width) / 2, rectDockArea.Y + _PanelIndicatorMargin); + PanelTop.Visible = true; + region.Union(PanelTop.Bounds); + } + else + PanelTop.Visible = false; + + if (ShouldPanelIndicatorVisible(DockState.DockBottom)) + { + PanelBottom.Location = new Point(rectDockArea.X + (rectDockArea.Width - PanelBottom.Width) / 2, rectDockArea.Y + rectDockArea.Height - PanelBottom.Height - _PanelIndicatorMargin); + PanelBottom.Visible = true; + region.Union(PanelBottom.Bounds); + } + else + PanelBottom.Visible = false; + + if (ShouldPanelIndicatorVisible(DockState.Document)) + { + Rectangle rectDocumentWindow = RectangleToClient(DockPanel.RectangleToScreen(DockPanel.DocumentWindowBounds)); + PanelFill.Location = new Point(rectDocumentWindow.X + (rectDocumentWindow.Width - PanelFill.Width) / 2, rectDocumentWindow.Y + (rectDocumentWindow.Height - PanelFill.Height) / 2); + PanelFill.Visible = true; + region.Union(PanelFill.Bounds); + } + else + PanelFill.Visible = false; + + if (ShouldPaneDiamondVisible()) + { + Rectangle rect = RectangleToClient(DockPane.RectangleToScreen(DockPane.ClientRectangle)); + PaneDiamond.Location = new Point(rect.Left + (rect.Width - PaneDiamond.Width) / 2, rect.Top + (rect.Height - PaneDiamond.Height) / 2); + PaneDiamond.Visible = true; + using (GraphicsPath graphicsPath = PaneIndicator.DisplayingGraphicsPath.Clone() as GraphicsPath) + { + Point[] pts = new Point[] + { + new Point(PaneDiamond.Left, PaneDiamond.Top), + new Point(PaneDiamond.Right, PaneDiamond.Top), + new Point(PaneDiamond.Left, PaneDiamond.Bottom) + }; + using (Matrix matrix = new Matrix(PaneDiamond.ClientRectangle, pts)) + { + graphicsPath.Transform(matrix); + } + region.Union(graphicsPath); + } + } + else + PaneDiamond.Visible = false; + + Region = region; + } + + private bool ShouldPanelIndicatorVisible(DockState dockState) + { + if (!Visible) + return false; + + if (DockPanel.DockWindows[dockState].Visible) + return false; + + return DragHandler.DragSource.IsDockStateValid(dockState); + } + + private bool ShouldPaneDiamondVisible() + { + if (DockPane == null) + return false; + + if (!DockPanel.AllowEndUserNestedDocking) + return false; + + return DragHandler.DragSource.CanDockTo(DockPane); + } + + public override void Show(bool bActivate) + { + base.Show(bActivate); + Bounds = SystemInformation.VirtualScreen; + RefreshChanges(); + } + + public void TestDrop() + { + Point pt = Control.MousePosition; + DockPane = DockHelper.PaneAtPoint(pt, DockPanel); + + if (TestDrop(PanelLeft, pt) != DockStyle.None) + HitTestResult = PanelLeft; + else if (TestDrop(PanelRight, pt) != DockStyle.None) + HitTestResult = PanelRight; + else if (TestDrop(PanelTop, pt) != DockStyle.None) + HitTestResult = PanelTop; + else if (TestDrop(PanelBottom, pt) != DockStyle.None) + HitTestResult = PanelBottom; + else if (TestDrop(PanelFill, pt) != DockStyle.None) + HitTestResult = PanelFill; + else if (TestDrop(PaneDiamond, pt) != DockStyle.None) + HitTestResult = PaneDiamond; + else + HitTestResult = null; + + if (HitTestResult != null) + { + if (HitTestResult is PaneIndicator) + DragHandler.Outline.Show(DockPane, HitTestResult.Status); + else + DragHandler.Outline.Show(DockPanel, HitTestResult.Status, FullPanelEdge); + } + } + + private static DockStyle TestDrop(IHitTest hitTest, Point pt) + { + return hitTest.Status = hitTest.HitTest(pt); + } + } + + private class DockOutline : DockOutlineBase + { + public DockOutline() + { + m_dragForm = new DragForm(); + SetDragForm(Rectangle.Empty); + DragForm.BackColor = SystemColors.ActiveCaption; + DragForm.Opacity = 0.5; + DragForm.Show(false); + } + + DragForm m_dragForm; + private DragForm DragForm + { + get { return m_dragForm; } + } + + protected override void OnShow() + { + CalculateRegion(); + } + + protected override void OnClose() + { + DragForm.Close(); + } + + private void CalculateRegion() + { + if (SameAsOldValue) + return; + + if (!FloatWindowBounds.IsEmpty) + SetOutline(FloatWindowBounds); + else if (DockTo is DockPanel) + SetOutline(DockTo as DockPanel, Dock, (ContentIndex != 0)); + else if (DockTo is DockPane) + SetOutline(DockTo as DockPane, Dock, ContentIndex); + else + SetOutline(); + } + + private void SetOutline() + { + SetDragForm(Rectangle.Empty); + } + + private void SetOutline(Rectangle floatWindowBounds) + { + SetDragForm(floatWindowBounds); + } + + private void SetOutline(DockPanel dockPanel, DockStyle dock, bool fullPanelEdge) + { + Rectangle rect = fullPanelEdge ? dockPanel.DockArea : dockPanel.DocumentWindowBounds; + rect.Location = dockPanel.PointToScreen(rect.Location); + if (dock == DockStyle.Top) + { + int height = dockPanel.GetDockWindowSize(DockState.DockTop); + rect = new Rectangle(rect.X, rect.Y, rect.Width, height); + } + else if (dock == DockStyle.Bottom) + { + int height = dockPanel.GetDockWindowSize(DockState.DockBottom); + rect = new Rectangle(rect.X, rect.Bottom - height, rect.Width, height); + } + else if (dock == DockStyle.Left) + { + int width = dockPanel.GetDockWindowSize(DockState.DockLeft); + rect = new Rectangle(rect.X, rect.Y, width, rect.Height); + } + else if (dock == DockStyle.Right) + { + int width = dockPanel.GetDockWindowSize(DockState.DockRight); + rect = new Rectangle(rect.Right - width, rect.Y, width, rect.Height); + } + else if (dock == DockStyle.Fill) + { + rect = dockPanel.DocumentWindowBounds; + rect.Location = dockPanel.PointToScreen(rect.Location); + } + + SetDragForm(rect); + } + + private void SetOutline(DockPane pane, DockStyle dock, int contentIndex) + { + if (dock != DockStyle.Fill) + { + Rectangle rect = pane.DisplayingRectangle; + if (dock == DockStyle.Right) + rect.X += rect.Width / 2; + if (dock == DockStyle.Bottom) + rect.Y += rect.Height / 2; + if (dock == DockStyle.Left || dock == DockStyle.Right) + rect.Width -= rect.Width / 2; + if (dock == DockStyle.Top || dock == DockStyle.Bottom) + rect.Height -= rect.Height / 2; + rect.Location = pane.PointToScreen(rect.Location); + + SetDragForm(rect); + } + else if (contentIndex == -1) + { + Rectangle rect = pane.DisplayingRectangle; + rect.Location = pane.PointToScreen(rect.Location); + SetDragForm(rect); + } + else + { + using (GraphicsPath path = pane.TabStripControl.GetOutline(contentIndex)) + { + RectangleF rectF = path.GetBounds(); + Rectangle rect = new Rectangle((int)rectF.X, (int)rectF.Y, (int)rectF.Width, (int)rectF.Height); + using (Matrix matrix = new Matrix(rect, new Point[] { new Point(0, 0), new Point(rect.Width, 0), new Point(0, rect.Height) })) + { + path.Transform(matrix); + } + Region region = new Region(path); + SetDragForm(rect, region); + } + } + } + + private void SetDragForm(Rectangle rect) + { + DragForm.Bounds = rect; + if (rect == Rectangle.Empty) + DragForm.Region = new Region(Rectangle.Empty); + else if (DragForm.Region != null) + DragForm.Region = null; + } + + private void SetDragForm(Rectangle rect, Region region) + { + DragForm.Bounds = rect; + DragForm.Region = region; + } + } + + public DockDragHandler(DockPanel panel) + : base(panel) + { + } + + public new IDockDragSource DragSource + { + get { return base.DragSource as IDockDragSource; } + set { base.DragSource = value; } + } + + private DockOutlineBase m_outline; + public DockOutlineBase Outline + { + get { return m_outline; } + private set { m_outline = value; } + } + + private DockIndicator m_indicator; + private DockIndicator Indicator + { + get { return m_indicator; } + set { m_indicator = value; } + } + + private Rectangle m_floatOutlineBounds; + private Rectangle FloatOutlineBounds + { + get { return m_floatOutlineBounds; } + set { m_floatOutlineBounds = value; } + } + + public void BeginDrag(IDockDragSource dragSource) + { + DragSource = dragSource; + + if (!BeginDrag()) + { + DragSource = null; + return; + } + + Outline = new DockOutline(); + Indicator = new DockIndicator(this); + Indicator.Show(false); + + FloatOutlineBounds = DragSource.BeginDrag(StartMousePosition); + } + + protected override void OnDragging() + { + TestDrop(); + } + + protected override void OnEndDrag(bool abort) + { + DockPanel.SuspendLayout(true); + + Outline.Close(); + Indicator.Close(); + + EndDrag(abort); + + // Queue a request to layout all children controls + DockPanel.PerformMdiClientLayout(); + + DockPanel.ResumeLayout(true, true); + + DragSource = null; + } + + private void TestDrop() + { + Outline.FlagTestDrop = false; + + Indicator.FullPanelEdge = ((Control.ModifierKeys & Keys.Shift) != 0); + + if ((Control.ModifierKeys & Keys.Control) == 0) + { + Indicator.TestDrop(); + + if (!Outline.FlagTestDrop) + { + DockPane pane = DockHelper.PaneAtPoint(Control.MousePosition, DockPanel); + if (pane != null && DragSource.IsDockStateValid(pane.DockState)) + pane.TestDrop(DragSource, Outline); + } + + if (!Outline.FlagTestDrop && DragSource.IsDockStateValid(DockState.Float)) + { + FloatWindow floatWindow = DockHelper.FloatWindowAtPoint(Control.MousePosition, DockPanel); + if (floatWindow != null) + floatWindow.TestDrop(DragSource, Outline); + } + } + else + Indicator.DockPane = DockHelper.PaneAtPoint(Control.MousePosition, DockPanel); + + if (!Outline.FlagTestDrop) + { + if (DragSource.IsDockStateValid(DockState.Float)) + { + Rectangle rect = FloatOutlineBounds; + rect.Offset(Control.MousePosition.X - StartMousePosition.X, Control.MousePosition.Y - StartMousePosition.Y); + Outline.Show(rect); + } + } + + if (!Outline.FlagTestDrop) + { + Cursor.Current = Cursors.No; + Outline.Show(); + } + else + Cursor.Current = DragControl.Cursor; + } + + private void EndDrag(bool abort) + { + if (abort) + return; + + if (!Outline.FloatWindowBounds.IsEmpty) + DragSource.FloatAt(Outline.FloatWindowBounds); + else if (Outline.DockTo is DockPane) + { + DockPane pane = Outline.DockTo as DockPane; + DragSource.DockTo(pane, Outline.Dock, Outline.ContentIndex); + } + else if (Outline.DockTo is DockPanel) + { + DockPanel panel = Outline.DockTo as DockPanel; + panel.UpdateDockWindowZOrder(Outline.Dock, Outline.FlagFullEdge); + DragSource.DockTo(panel, Outline.Dock); + } + } + } + + private DockDragHandler m_dockDragHandler = null; + private DockDragHandler GetDockDragHandler() + { + if (m_dockDragHandler == null) + m_dockDragHandler = new DockDragHandler(this); + return m_dockDragHandler; + } + + internal void BeginDrag(IDockDragSource dragSource) + { + GetDockDragHandler().BeginDrag(dragSource); + } + } +} diff --git a/trunk/Docking/DockPanel.DragHandler.cs b/trunk/Docking/DockPanel.DragHandler.cs new file mode 100644 index 0000000..370572a --- /dev/null +++ b/trunk/Docking/DockPanel.DragHandler.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.ComponentModel; + +namespace LSLEditor.Docking +{ + partial class DockPanel + { + /// + /// DragHandlerBase is the base class for drag handlers. The derived class should: + /// 1. Define its public method BeginDrag. From within this public BeginDrag method, + /// DragHandlerBase.BeginDrag should be called to initialize the mouse capture + /// and message filtering. + /// 2. Override the OnDragging and OnEndDrag methods. + /// + private abstract class DragHandlerBase : NativeWindow, IMessageFilter + { + protected DragHandlerBase() + { + } + + protected abstract Control DragControl + { + get; + } + + private Point m_startMousePosition = Point.Empty; + protected Point StartMousePosition + { + get { return m_startMousePosition; } + private set { m_startMousePosition = value; } + } + + protected bool BeginDrag() + { + // Avoid re-entrance; + lock (this) + { + if (DragControl == null) + return false; + + StartMousePosition = Control.MousePosition; + + if (!NativeMethods.DragDetect(DragControl.Handle, StartMousePosition)) + return false; + + DragControl.FindForm().Capture = true; + AssignHandle(DragControl.FindForm().Handle); + Application.AddMessageFilter(this); + return true; + } + } + + protected abstract void OnDragging(); + + protected abstract void OnEndDrag(bool abort); + + private void EndDrag(bool abort) + { + ReleaseHandle(); + Application.RemoveMessageFilter(this); + DragControl.FindForm().Capture = false; + + OnEndDrag(abort); + } + + bool IMessageFilter.PreFilterMessage(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_MOUSEMOVE) + OnDragging(); + else if (m.Msg == (int)Win32.Msgs.WM_LBUTTONUP) + EndDrag(false); + else if (m.Msg == (int)Win32.Msgs.WM_CAPTURECHANGED) + EndDrag(true); + else if (m.Msg == (int)Win32.Msgs.WM_KEYDOWN && (int)m.WParam == (int)Keys.Escape) + EndDrag(true); + + return OnPreFilterMessage(ref m); + } + + protected virtual bool OnPreFilterMessage(ref Message m) + { + return false; + } + + protected sealed override void WndProc(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_CANCELMODE || m.Msg == (int)Win32.Msgs.WM_CAPTURECHANGED) + EndDrag(true); + + base.WndProc(ref m); + } + } + + private abstract class DragHandler : DragHandlerBase + { + private DockPanel m_dockPanel; + + protected DragHandler(DockPanel dockPanel) + { + m_dockPanel = dockPanel; + } + + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private IDragSource m_dragSource; + protected IDragSource DragSource + { + get { return m_dragSource; } + set { m_dragSource = value; } + } + + protected sealed override Control DragControl + { + get { return DragSource == null ? null : DragSource.DragControl; } + } + + protected sealed override bool OnPreFilterMessage(ref Message m) + { + if ((m.Msg == (int)Win32.Msgs.WM_KEYDOWN || m.Msg == (int)Win32.Msgs.WM_KEYUP) && + ((int)m.WParam == (int)Keys.ControlKey || (int)m.WParam == (int)Keys.ShiftKey)) + OnDragging(); + + return base.OnPreFilterMessage(ref m); + } + } + } +} diff --git a/trunk/Docking/DockPanel.FocusManager.cs b/trunk/Docking/DockPanel.FocusManager.cs new file mode 100644 index 0000000..d967b58 --- /dev/null +++ b/trunk/Docking/DockPanel.FocusManager.cs @@ -0,0 +1,568 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using System.Diagnostics.CodeAnalysis; + +namespace LSLEditor.Docking +{ + internal interface IContentFocusManager + { + void Activate(IDockContent content); + void GiveUpFocus(IDockContent content); + void AddToList(IDockContent content); + void RemoveFromList(IDockContent content); + } + + partial class DockPanel + { + private interface IFocusManager + { + void SuspendFocusTracking(); + void ResumeFocusTracking(); + bool IsFocusTrackingSuspended { get; } + IDockContent ActiveContent { get; } + DockPane ActivePane { get; } + IDockContent ActiveDocument { get; } + DockPane ActiveDocumentPane { get; } + } + + private class FocusManagerImpl : Component, IContentFocusManager, IFocusManager + { + private class HookEventArgs : EventArgs + { + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public int HookCode; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public IntPtr wParam; + public IntPtr lParam; + } + + private class LocalWindowsHook : IDisposable + { + // Internal properties + private IntPtr m_hHook = IntPtr.Zero; + private NativeMethods.HookProc m_filterFunc = null; + private Win32.HookType m_hookType; + + // Event delegate + public delegate void HookEventHandler(object sender, HookEventArgs e); + + // Event: HookInvoked + public event HookEventHandler HookInvoked; + protected void OnHookInvoked(HookEventArgs e) + { + if (HookInvoked != null) + HookInvoked(this, e); + } + + public LocalWindowsHook(Win32.HookType hook) + { + m_hookType = hook; + m_filterFunc = new NativeMethods.HookProc(this.CoreHookProc); + } + + // Default filter function + public IntPtr CoreHookProc(int code, IntPtr wParam, IntPtr lParam) + { + if (code < 0) + return NativeMethods.CallNextHookEx(m_hHook, code, wParam, lParam); + + // Let clients determine what to do + HookEventArgs e = new HookEventArgs(); + e.HookCode = code; + e.wParam = wParam; + e.lParam = lParam; + OnHookInvoked(e); + + // Yield to the next hook in the chain + return NativeMethods.CallNextHookEx(m_hHook, code, wParam, lParam); + } + + // Install the hook + public void Install() + { + if (m_hHook != IntPtr.Zero) + Uninstall(); + + int threadId = NativeMethods.GetCurrentThreadId(); + m_hHook = NativeMethods.SetWindowsHookEx(m_hookType, m_filterFunc, IntPtr.Zero, threadId); + } + + // Uninstall the hook + public void Uninstall() + { + if (m_hHook != IntPtr.Zero) + { + NativeMethods.UnhookWindowsHookEx(m_hHook); + m_hHook = IntPtr.Zero; + } + } + + ~LocalWindowsHook() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + Uninstall(); + } + } + + private LocalWindowsHook m_localWindowsHook; + private LocalWindowsHook.HookEventHandler m_hookEventHandler; + + public FocusManagerImpl(DockPanel dockPanel) + { + m_dockPanel = dockPanel; + m_localWindowsHook = new LocalWindowsHook(Win32.HookType.WH_CALLWNDPROCRET); + m_hookEventHandler = new LocalWindowsHook.HookEventHandler(HookEventHandler); + m_localWindowsHook.HookInvoked += m_hookEventHandler; + m_localWindowsHook.Install(); + } + + private DockPanel m_dockPanel; + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private bool m_disposed = false; + protected override void Dispose(bool disposing) + { + lock (this) + { + if (!m_disposed && disposing) + { + m_localWindowsHook.Dispose(); + m_disposed = true; + } + + base.Dispose(disposing); + } + } + + private IDockContent m_contentActivating = null; + private IDockContent ContentActivating + { + get { return m_contentActivating; } + set { m_contentActivating = value; } + } + + public void Activate(IDockContent content) + { + if (IsFocusTrackingSuspended) + { + ContentActivating = content; + return; + } + + if (content == null) + return; + DockContentHandler handler = content.DockHandler; + if (handler.Form.IsDisposed) + return; // Should not reach here, but better than throwing an exception + if (ContentContains(content, handler.ActiveWindowHandle)) + NativeMethods.SetFocus(handler.ActiveWindowHandle); + if (!handler.Form.ContainsFocus) + { + if (!handler.Form.SelectNextControl(handler.Form.ActiveControl, true, true, true, true)) + // Since DockContent Form is not selectalbe, use Win32 SetFocus instead + NativeMethods.SetFocus(handler.Form.Handle); + } + } + + private List m_listContent = new List(); + private List ListContent + { + get { return m_listContent; } + } + public void AddToList(IDockContent content) + { + if (ListContent.Contains(content) || IsInActiveList(content)) + return; + + ListContent.Add(content); + } + + public void RemoveFromList(IDockContent content) + { + if (IsInActiveList(content)) + RemoveFromActiveList(content); + if (ListContent.Contains(content)) + ListContent.Remove(content); + } + + private IDockContent m_lastActiveContent = null; + private IDockContent LastActiveContent + { + get { return m_lastActiveContent; } + set { m_lastActiveContent = value; } + } + + private bool IsInActiveList(IDockContent content) + { + return !(content.DockHandler.NextActive == null && LastActiveContent != content); + } + + private void AddLastToActiveList(IDockContent content) + { + IDockContent last = LastActiveContent; + if (last == content) + return; + + DockContentHandler handler = content.DockHandler; + + if (IsInActiveList(content)) + RemoveFromActiveList(content); + + handler.PreviousActive = last; + handler.NextActive = null; + LastActiveContent = content; + if (last != null) + last.DockHandler.NextActive = LastActiveContent; + } + + private void RemoveFromActiveList(IDockContent content) + { + if (LastActiveContent == content) + LastActiveContent = content.DockHandler.PreviousActive; + + IDockContent prev = content.DockHandler.PreviousActive; + IDockContent next = content.DockHandler.NextActive; + if (prev != null) + prev.DockHandler.NextActive = next; + if (next != null) + next.DockHandler.PreviousActive = prev; + + content.DockHandler.PreviousActive = null; + content.DockHandler.NextActive = null; + } + + public void GiveUpFocus(IDockContent content) + { + DockContentHandler handler = content.DockHandler; + if (!handler.Form.ContainsFocus) + return; + + if (IsFocusTrackingSuspended) + DockPanel.DummyControl.Focus(); + + if (LastActiveContent == content) + { + IDockContent prev = handler.PreviousActive; + if (prev != null) + Activate(prev); + else if (ListContent.Count > 0) + Activate(ListContent[ListContent.Count - 1]); + } + else if (LastActiveContent != null) + Activate(LastActiveContent); + else if (ListContent.Count > 0) + Activate(ListContent[ListContent.Count - 1]); + } + + private static bool ContentContains(IDockContent content, IntPtr hWnd) + { + Control control = Control.FromChildHandle(hWnd); + for (Control parent = control; parent != null; parent = parent.Parent) + if (parent == content.DockHandler.Form) + return true; + + return false; + } + + private int m_countSuspendFocusTracking = 0; + public void SuspendFocusTracking() + { + m_countSuspendFocusTracking++; + m_localWindowsHook.HookInvoked -= m_hookEventHandler; + } + + public void ResumeFocusTracking() + { + if (m_countSuspendFocusTracking > 0) + m_countSuspendFocusTracking--; + + if (m_countSuspendFocusTracking == 0) + { + if (ContentActivating != null) + { + Activate(ContentActivating); + ContentActivating = null; + } + m_localWindowsHook.HookInvoked += m_hookEventHandler; + if (!InRefreshActiveWindow) + RefreshActiveWindow(); + } + } + + public bool IsFocusTrackingSuspended + { + get { return m_countSuspendFocusTracking != 0; } + } + + // Windows hook event handler + private void HookEventHandler(object sender, HookEventArgs e) + { + Win32.Msgs msg = (Win32.Msgs)Marshal.ReadInt32(e.lParam, IntPtr.Size * 3); + + if (msg == Win32.Msgs.WM_KILLFOCUS) + { + IntPtr wParam = Marshal.ReadIntPtr(e.lParam, IntPtr.Size * 2); + DockPane pane = GetPaneFromHandle(wParam); + if (pane == null) + RefreshActiveWindow(); + } + else if (msg == Win32.Msgs.WM_SETFOCUS) + RefreshActiveWindow(); + } + + private DockPane GetPaneFromHandle(IntPtr hWnd) + { + Control control = Control.FromChildHandle(hWnd); + + IDockContent content = null; + DockPane pane = null; + for (; control != null; control = control.Parent) + { + content = control as IDockContent; + if (content != null) + content.DockHandler.ActiveWindowHandle = hWnd; + + if (content != null && content.DockHandler.DockPanel == DockPanel) + return content.DockHandler.Pane; + + pane = control as DockPane; + if (pane != null && pane.DockPanel == DockPanel) + break; + } + + return pane; + } + + private bool m_inRefreshActiveWindow = false; + private bool InRefreshActiveWindow + { + get { return m_inRefreshActiveWindow; } + } + + private void RefreshActiveWindow() + { + SuspendFocusTracking(); + m_inRefreshActiveWindow = true; + + DockPane oldActivePane = ActivePane; + IDockContent oldActiveContent = ActiveContent; + IDockContent oldActiveDocument = ActiveDocument; + + SetActivePane(); + SetActiveContent(); + SetActiveDocumentPane(); + SetActiveDocument(); + DockPanel.AutoHideWindow.RefreshActivePane(); + + ResumeFocusTracking(); + m_inRefreshActiveWindow = false; + + if (oldActiveContent != ActiveContent) + DockPanel.OnActiveContentChanged(EventArgs.Empty); + if (oldActiveDocument != ActiveDocument) + DockPanel.OnActiveDocumentChanged(EventArgs.Empty); + if (oldActivePane != ActivePane) + DockPanel.OnActivePaneChanged(EventArgs.Empty); + } + + private DockPane m_activePane = null; + public DockPane ActivePane + { + get { return m_activePane; } + } + + private void SetActivePane() + { + DockPane value = GetPaneFromHandle(NativeMethods.GetFocus()); + if (m_activePane == value) + return; + + if (m_activePane != null) + m_activePane.SetIsActivated(false); + + m_activePane = value; + + if (m_activePane != null) + m_activePane.SetIsActivated(true); + } + + private IDockContent m_activeContent = null; + public IDockContent ActiveContent + { + get { return m_activeContent; } + } + + internal void SetActiveContent() + { + IDockContent value = ActivePane == null ? null : ActivePane.ActiveContent; + + if (m_activeContent == value) + return; + + if (m_activeContent != null) + m_activeContent.DockHandler.IsActivated = false; + + m_activeContent = value; + + if (m_activeContent != null) + { + m_activeContent.DockHandler.IsActivated = true; + if (!DockHelper.IsDockStateAutoHide((m_activeContent.DockHandler.DockState))) + AddLastToActiveList(m_activeContent); + } + } + + private DockPane m_activeDocumentPane = null; + public DockPane ActiveDocumentPane + { + get { return m_activeDocumentPane; } + } + + private void SetActiveDocumentPane() + { + DockPane value = null; + + if (ActivePane != null && ActivePane.DockState == DockState.Document) + value = ActivePane; + + if (value == null && DockPanel.DockWindows != null) + { + if (ActiveDocumentPane == null) + value = DockPanel.DockWindows[DockState.Document].DefaultPane; + else if (ActiveDocumentPane.DockPanel != DockPanel || ActiveDocumentPane.DockState != DockState.Document) + value = DockPanel.DockWindows[DockState.Document].DefaultPane; + else + value = ActiveDocumentPane; + } + + if (m_activeDocumentPane == value) + return; + + if (m_activeDocumentPane != null) + m_activeDocumentPane.SetIsActiveDocumentPane(false); + + m_activeDocumentPane = value; + + if (m_activeDocumentPane != null) + m_activeDocumentPane.SetIsActiveDocumentPane(true); + } + + private IDockContent m_activeDocument = null; + public IDockContent ActiveDocument + { + get { return m_activeDocument; } + } + + private void SetActiveDocument() + { + IDockContent value = ActiveDocumentPane == null ? null : ActiveDocumentPane.ActiveContent; + + if (m_activeDocument == value) + return; + + m_activeDocument = value; + } + } + + private IFocusManager FocusManager + { + get { return m_focusManager; } + } + + internal IContentFocusManager ContentFocusManager + { + get { return m_focusManager; } + } + + internal void SaveFocus() + { + DummyControl.Focus(); + } + + [Browsable(false)] + public IDockContent ActiveContent + { + get { return FocusManager.ActiveContent; } + } + + [Browsable(false)] + public DockPane ActivePane + { + get { return FocusManager.ActivePane; } + } + + [Browsable(false)] + public IDockContent ActiveDocument + { + get { return FocusManager.ActiveDocument; } + } + + [Browsable(false)] + public DockPane ActiveDocumentPane + { + get { return FocusManager.ActiveDocumentPane; } + } + + private static readonly object ActiveDocumentChangedEvent = new object(); + [LocalizedCategory("Category_PropertyChanged")] + [LocalizedDescription("DockPanel_ActiveDocumentChanged_Description")] + public event EventHandler ActiveDocumentChanged + { + add { Events.AddHandler(ActiveDocumentChangedEvent, value); } + remove { Events.RemoveHandler(ActiveDocumentChangedEvent, value); } + } + protected virtual void OnActiveDocumentChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[ActiveDocumentChangedEvent]; + if (handler != null) + handler(this, e); + } + + private static readonly object ActiveContentChangedEvent = new object(); + [LocalizedCategory("Category_PropertyChanged")] + [LocalizedDescription("DockPanel_ActiveContentChanged_Description")] + public event EventHandler ActiveContentChanged + { + add { Events.AddHandler(ActiveContentChangedEvent, value); } + remove { Events.RemoveHandler(ActiveContentChangedEvent, value); } + } + protected void OnActiveContentChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[ActiveContentChangedEvent]; + if (handler != null) + handler(this, e); + } + + private static readonly object ActivePaneChangedEvent = new object(); + [LocalizedCategory("Category_PropertyChanged")] + [LocalizedDescription("DockPanel_ActivePaneChanged_Description")] + public event EventHandler ActivePaneChanged + { + add { Events.AddHandler(ActivePaneChangedEvent, value); } + remove { Events.RemoveHandler(ActivePaneChangedEvent, value); } + } + protected virtual void OnActivePaneChanged(EventArgs e) + { + EventHandler handler = (EventHandler)Events[ActivePaneChangedEvent]; + if (handler != null) + handler(this, e); + } + } +} diff --git a/trunk/Docking/DockPanel.MdiClientController.cs b/trunk/Docking/DockPanel.MdiClientController.cs new file mode 100644 index 0000000..24fd0cf --- /dev/null +++ b/trunk/Docking/DockPanel.MdiClientController.cs @@ -0,0 +1,430 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Runtime.InteropServices; + +namespace LSLEditor.Docking +{ + partial class DockPanel + { + // This class comes from Jacob Slusser's MdiClientController class: + // http://www.codeproject.com/cs/miscctrl/mdiclientcontroller.asp + private class MdiClientController : NativeWindow, IComponent, IDisposable + { + private bool m_autoScroll = true; + private BorderStyle m_borderStyle = BorderStyle.Fixed3D; + private MdiClient m_mdiClient = null; + private Form m_parentForm = null; + private ISite m_site = null; + + public MdiClientController() + { + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + lock (this) + { + if (Site != null && Site.Container != null) + Site.Container.Remove(this); + + if (Disposed != null) + Disposed(this, EventArgs.Empty); + } + } + } + + public bool AutoScroll + { + get { return m_autoScroll; } + set + { + // By default the MdiClient control scrolls. It can appear though that + // there are no scrollbars by turning them off when the non-client + // area is calculated. I decided to expose this method following + // the .NET vernacular of an AutoScroll property. + m_autoScroll = value; + if (MdiClient != null) + UpdateStyles(); + } + } + + public BorderStyle BorderStyle + { + set + { + // Error-check the enum. + if (!Enum.IsDefined(typeof(BorderStyle), value)) + throw new InvalidEnumArgumentException(); + + m_borderStyle = value; + + if (MdiClient == null) + return; + + // This property can actually be visible in design-mode, + // but to keep it consistent with the others, + // prevent this from being show at design-time. + if (Site != null && Site.DesignMode) + return; + + // There is no BorderStyle property exposed by the MdiClient class, + // but this can be controlled by Win32 functions. A Win32 ExStyle + // of WS_EX_CLIENTEDGE is equivalent to a Fixed3D border and a + // Style of WS_BORDER is equivalent to a FixedSingle border. + + // This code is inspired Jason Dori's article: + // "Adding designable borders to user controls". + // http://www.codeproject.com/cs/miscctrl/CsAddingBorders.asp + + // Get styles using Win32 calls + int style = NativeMethods.GetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_STYLE); + int exStyle = NativeMethods.GetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE); + + // Add or remove style flags as necessary. + switch (m_borderStyle) + { + case BorderStyle.Fixed3D: + exStyle |= (int)Win32.WindowExStyles.WS_EX_CLIENTEDGE; + style &= ~((int)Win32.WindowStyles.WS_BORDER); + break; + + case BorderStyle.FixedSingle: + exStyle &= ~((int)Win32.WindowExStyles.WS_EX_CLIENTEDGE); + style |= (int)Win32.WindowStyles.WS_BORDER; + break; + + case BorderStyle.None: + style &= ~((int)Win32.WindowStyles.WS_BORDER); + exStyle &= ~((int)Win32.WindowExStyles.WS_EX_CLIENTEDGE); + break; + } + + // Set the styles using Win32 calls + NativeMethods.SetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_STYLE, style); + NativeMethods.SetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE, exStyle); + + // Cause an update of the non-client area. + UpdateStyles(); + } + } + + public MdiClient MdiClient + { + get { return m_mdiClient; } + } + + [Browsable(false)] + public Form ParentForm + { + get { return m_parentForm; } + set + { + // If the ParentForm has previously been set, + // unwire events connected to the old parent. + if (m_parentForm != null) + { + m_parentForm.HandleCreated -= new EventHandler(ParentFormHandleCreated); + m_parentForm.MdiChildActivate -= new EventHandler(ParentFormMdiChildActivate); + } + + m_parentForm = value; + + if (m_parentForm == null) + return; + + // If the parent form has not been created yet, + // wait to initialize the MDI client until it is. + if (m_parentForm.IsHandleCreated) + { + InitializeMdiClient(); + RefreshProperties(); + } + else + m_parentForm.HandleCreated += new EventHandler(ParentFormHandleCreated); + + m_parentForm.MdiChildActivate += new EventHandler(ParentFormMdiChildActivate); + } + } + + public ISite Site + { + get { return m_site; } + set + { + m_site = value; + + if (m_site == null) + return; + + // If the component is dropped onto a form during design-time, + // set the ParentForm property. + IDesignerHost host = (value.GetService(typeof(IDesignerHost)) as IDesignerHost); + if (host != null) + { + Form parent = host.RootComponent as Form; + if (parent != null) + ParentForm = parent; + } + } + } + + public void RenewMdiClient() + { + // Reinitialize the MdiClient and its properties. + InitializeMdiClient(); + RefreshProperties(); + } + + public event EventHandler Disposed; + + public event EventHandler HandleAssigned; + + public event EventHandler MdiChildActivate; + + public event LayoutEventHandler Layout; + + protected virtual void OnHandleAssigned(EventArgs e) + { + // Raise the HandleAssigned event. + if (HandleAssigned != null) + HandleAssigned(this, e); + } + + protected virtual void OnMdiChildActivate(EventArgs e) + { + // Raise the MdiChildActivate event + if (MdiChildActivate != null) + MdiChildActivate(this, e); + } + + protected virtual void OnLayout(LayoutEventArgs e) + { + // Raise the Layout event + if (Layout != null) + Layout(this, e); + } + + public event PaintEventHandler Paint; + + protected virtual void OnPaint(PaintEventArgs e) + { + // Raise the Paint event. + if (Paint != null) + Paint(this, e); + } + + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case (int)Win32.Msgs.WM_NCCALCSIZE: + // If AutoScroll is set to false, hide the scrollbars when the control + // calculates its non-client area. + if (!AutoScroll) + NativeMethods.ShowScrollBar(m.HWnd, (int)Win32.ScrollBars.SB_BOTH, 0 /*false*/); + break; + } + + base.WndProc(ref m); + } + + private void ParentFormHandleCreated(object sender, EventArgs e) + { + // The form has been created, unwire the event, and initialize the MdiClient. + this.m_parentForm.HandleCreated -= new EventHandler(ParentFormHandleCreated); + InitializeMdiClient(); + RefreshProperties(); + } + + private void ParentFormMdiChildActivate(object sender, EventArgs e) + { + OnMdiChildActivate(e); + } + + private void MdiClientLayout(object sender, LayoutEventArgs e) + { + OnLayout(e); + } + + private void MdiClientHandleDestroyed(object sender, EventArgs e) + { + // If the MdiClient handle has been released, drop the reference and + // release the handle. + if (m_mdiClient != null) + { + m_mdiClient.HandleDestroyed -= new EventHandler(MdiClientHandleDestroyed); + m_mdiClient = null; + } + + ReleaseHandle(); + } + + private void InitializeMdiClient() + { + // If the mdiClient has previously been set, unwire events connected + // to the old MDI. + if (MdiClient != null) + { + MdiClient.HandleDestroyed -= new EventHandler(MdiClientHandleDestroyed); + MdiClient.Layout -= new LayoutEventHandler(MdiClientLayout); + } + + if (ParentForm == null) + return; + + // Get the MdiClient from the parent form. + foreach (Control control in ParentForm.Controls) + { + // If the form is an MDI container, it will contain an MdiClient control + // just as it would any other control. + + m_mdiClient = control as MdiClient; + if (m_mdiClient == null) + continue; + + // Assign the MdiClient Handle to the NativeWindow. + ReleaseHandle(); + AssignHandle(MdiClient.Handle); + + // Raise the HandleAssigned event. + OnHandleAssigned(EventArgs.Empty); + + // Monitor the MdiClient for when its handle is destroyed. + MdiClient.HandleDestroyed += new EventHandler(MdiClientHandleDestroyed); + MdiClient.Layout += new LayoutEventHandler(MdiClientLayout); + + break; + } + } + + private void RefreshProperties() + { + // Refresh all the properties + BorderStyle = m_borderStyle; + AutoScroll = m_autoScroll; + } + + private void UpdateStyles() + { + // To show style changes, the non-client area must be repainted. Using the + // control's Invalidate method does not affect the non-client area. + // Instead use a Win32 call to signal the style has changed. + NativeMethods.SetWindowPos(MdiClient.Handle, IntPtr.Zero, 0, 0, 0, 0, + Win32.FlagsSetWindowPos.SWP_NOACTIVATE | + Win32.FlagsSetWindowPos.SWP_NOMOVE | + Win32.FlagsSetWindowPos.SWP_NOSIZE | + Win32.FlagsSetWindowPos.SWP_NOZORDER | + Win32.FlagsSetWindowPos.SWP_NOOWNERZORDER | + Win32.FlagsSetWindowPos.SWP_FRAMECHANGED); + } + } + + private MdiClientController m_mdiClientController = null; + private MdiClientController GetMdiClientController() + { + if (m_mdiClientController == null) + { + m_mdiClientController = new MdiClientController(); + m_mdiClientController.HandleAssigned += new EventHandler(MdiClientHandleAssigned); + m_mdiClientController.MdiChildActivate += new EventHandler(ParentFormMdiChildActivate); + m_mdiClientController.Layout += new LayoutEventHandler(MdiClient_Layout); + } + + return m_mdiClientController; + } + + private void ParentFormMdiChildActivate(object sender, EventArgs e) + { + if (GetMdiClientController().ParentForm == null) + return; + + IDockContent content = GetMdiClientController().ParentForm.ActiveMdiChild as IDockContent; + if (content == null) + return; + + if (content.DockHandler.DockPanel == this && content.DockHandler.Pane != null) + content.DockHandler.Pane.ActiveContent = content; + } + + private bool MdiClientExists + { + get { return GetMdiClientController().MdiClient != null; } + } + + private void SetMdiClientBounds(Rectangle bounds) + { + GetMdiClientController().MdiClient.Bounds = bounds; + } + + private void SuspendMdiClientLayout() + { + if (GetMdiClientController().MdiClient != null) + GetMdiClientController().MdiClient.SuspendLayout(); + } + + private void ResumeMdiClientLayout(bool perform) + { + if (GetMdiClientController().MdiClient != null) + GetMdiClientController().MdiClient.ResumeLayout(perform); + } + + private void PerformMdiClientLayout() + { + if (GetMdiClientController().MdiClient != null) + GetMdiClientController().MdiClient.PerformLayout(); + } + + // Called when: + // 1. DockPanel.DocumentStyle changed + // 2. DockPanel.Visible changed + // 3. MdiClientController.Handle assigned + private void SetMdiClient() + { + MdiClientController controller = GetMdiClientController(); + + if (this.DocumentStyle == DocumentStyle.DockingMdi) + { + controller.AutoScroll = false; + controller.BorderStyle = BorderStyle.None; + if (MdiClientExists) + controller.MdiClient.Dock = DockStyle.Fill; + } + else if (DocumentStyle == DocumentStyle.DockingSdi || DocumentStyle == DocumentStyle.DockingWindow) + { + controller.AutoScroll = true; + controller.BorderStyle = BorderStyle.Fixed3D; + if (MdiClientExists) + controller.MdiClient.Dock = DockStyle.Fill; + } + else if (this.DocumentStyle == DocumentStyle.SystemMdi) + { + controller.AutoScroll = true; + controller.BorderStyle = BorderStyle.Fixed3D; + if (controller.MdiClient != null) + { + controller.MdiClient.Dock = DockStyle.None; + controller.MdiClient.Bounds = SystemMdiClientBounds; + } + } + } + + internal Rectangle RectangleToMdiClient(Rectangle rect) + { + if (MdiClientExists) + return GetMdiClientController().MdiClient.RectangleToClient(rect); + else + return Rectangle.Empty; + } + } +} diff --git a/trunk/Docking/DockPanel.Persistor.cs b/trunk/Docking/DockPanel.Persistor.cs new file mode 100644 index 0000000..b51ea44 --- /dev/null +++ b/trunk/Docking/DockPanel.Persistor.cs @@ -0,0 +1,781 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; +using System.Drawing; +using LSLEditor.Docking; +using System.IO; +using System.Text; +using System.Xml; +using System.Globalization; + +namespace LSLEditor.Docking +{ + partial class DockPanel + { + private static class Persistor + { + private const string ConfigFileVersion = "1.0"; + private static string[] CompatibleConfigFileVersions = new string[] { }; + + private class DummyContent : DockContent + { + } + + private struct DockPanelStruct + { + private double m_dockLeftPortion; + public double DockLeftPortion + { + get { return m_dockLeftPortion; } + set { m_dockLeftPortion = value; } + } + + private double m_dockRightPortion; + public double DockRightPortion + { + get { return m_dockRightPortion; } + set { m_dockRightPortion = value; } + } + + private double m_dockTopPortion; + public double DockTopPortion + { + get { return m_dockTopPortion; } + set { m_dockTopPortion = value; } + } + + private double m_dockBottomPortion; + public double DockBottomPortion + { + get { return m_dockBottomPortion; } + set { m_dockBottomPortion = value; } + } + + private int m_indexActiveDocumentPane; + public int IndexActiveDocumentPane + { + get { return m_indexActiveDocumentPane; } + set { m_indexActiveDocumentPane = value; } + } + + private int m_indexActivePane; + public int IndexActivePane + { + get { return m_indexActivePane; } + set { m_indexActivePane = value; } + } + } + + private struct ContentStruct + { + private string m_persistString; + public string PersistString + { + get { return m_persistString; } + set { m_persistString = value; } + } + + private double m_autoHidePortion; + public double AutoHidePortion + { + get { return m_autoHidePortion; } + set { m_autoHidePortion = value; } + } + + private bool m_isHidden; + public bool IsHidden + { + get { return m_isHidden; } + set { m_isHidden = value; } + } + + private bool m_isFloat; + public bool IsFloat + { + get { return m_isFloat; } + set { m_isFloat = value; } + } + } + + private struct PaneStruct + { + private DockState m_dockState; + public DockState DockState + { + get { return m_dockState; } + set { m_dockState = value; } + } + + private int m_indexActiveContent; + public int IndexActiveContent + { + get { return m_indexActiveContent; } + set { m_indexActiveContent = value; } + } + + private int[] m_indexContents; + public int[] IndexContents + { + get { return m_indexContents; } + set { m_indexContents = value; } + } + + private int m_zOrderIndex; + public int ZOrderIndex + { + get { return m_zOrderIndex; } + set { m_zOrderIndex = value; } + } + } + + private struct NestedPane + { + private int m_indexPane; + public int IndexPane + { + get { return m_indexPane; } + set { m_indexPane = value; } + } + + private int m_indexPrevPane; + public int IndexPrevPane + { + get { return m_indexPrevPane; } + set { m_indexPrevPane = value; } + } + + private DockAlignment m_alignment; + public DockAlignment Alignment + { + get { return m_alignment; } + set { m_alignment = value; } + } + + private double m_proportion; + public double Proportion + { + get { return m_proportion; } + set { m_proportion = value; } + } + } + + private struct DockWindowStruct + { + private DockState m_dockState; + public DockState DockState + { + get { return m_dockState; } + set { m_dockState = value; } + } + + private int m_zOrderIndex; + public int ZOrderIndex + { + get { return m_zOrderIndex; } + set { m_zOrderIndex = value; } + } + + private NestedPane[] m_nestedPanes; + public NestedPane[] NestedPanes + { + get { return m_nestedPanes; } + set { m_nestedPanes = value; } + } + } + + private struct FloatWindowStruct + { + private Rectangle m_bounds; + public Rectangle Bounds + { + get { return m_bounds; } + set { m_bounds = value; } + } + + private int m_zOrderIndex; + public int ZOrderIndex + { + get { return m_zOrderIndex; } + set { m_zOrderIndex = value; } + } + + private NestedPane[] m_nestedPanes; + public NestedPane[] NestedPanes + { + get { return m_nestedPanes; } + set { m_nestedPanes = value; } + } + } + + public static void SaveAsXml(DockPanel dockPanel, string fileName) + { + SaveAsXml(dockPanel, fileName, Encoding.Unicode); + } + + public static void SaveAsXml(DockPanel dockPanel, string fileName, Encoding encoding) + { + FileStream fs = new FileStream(fileName, FileMode.Create); + try + { + SaveAsXml(dockPanel, fs, encoding); + } + finally + { + fs.Close(); + } + } + + public static void SaveAsXml(DockPanel dockPanel, Stream stream, Encoding encoding) + { + SaveAsXml(dockPanel, stream, encoding, false); + } + + public static void SaveAsXml(DockPanel dockPanel, Stream stream, Encoding encoding, bool upstream) + { + XmlTextWriter xmlOut = new XmlTextWriter(stream, encoding); + + // Use indenting for readability + xmlOut.Formatting = Formatting.Indented; + + if (!upstream) + xmlOut.WriteStartDocument(); + + // Always begin file with identification and warning + xmlOut.WriteComment(Strings.DockPanel_Persistor_XmlFileComment1); + xmlOut.WriteComment(Strings.DockPanel_Persistor_XmlFileComment2); + + // Associate a version number with the root element so that future version of the code + // will be able to be backwards compatible or at least recognise out of date versions + xmlOut.WriteStartElement("DockPanel"); + xmlOut.WriteAttributeString("FormatVersion", ConfigFileVersion); + xmlOut.WriteAttributeString("DockLeftPortion", dockPanel.DockLeftPortion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("DockRightPortion", dockPanel.DockRightPortion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("DockTopPortion", dockPanel.DockTopPortion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("DockBottomPortion", dockPanel.DockBottomPortion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("ActiveDocumentPane", dockPanel.Panes.IndexOf(dockPanel.ActiveDocumentPane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("ActivePane", dockPanel.Panes.IndexOf(dockPanel.ActivePane).ToString(CultureInfo.InvariantCulture)); + + // Contents + xmlOut.WriteStartElement("Contents"); + xmlOut.WriteAttributeString("Count", dockPanel.Contents.Count.ToString(CultureInfo.InvariantCulture)); + foreach (IDockContent content in dockPanel.Contents) + { + xmlOut.WriteStartElement("Content"); + xmlOut.WriteAttributeString("ID", dockPanel.Contents.IndexOf(content).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("PersistString", content.DockHandler.PersistString); + xmlOut.WriteAttributeString("AutoHidePortion", content.DockHandler.AutoHidePortion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("IsHidden", content.DockHandler.IsHidden.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("IsFloat", content.DockHandler.IsFloat.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + + // Panes + xmlOut.WriteStartElement("Panes"); + xmlOut.WriteAttributeString("Count", dockPanel.Panes.Count.ToString(CultureInfo.InvariantCulture)); + foreach (DockPane pane in dockPanel.Panes) + { + xmlOut.WriteStartElement("Pane"); + xmlOut.WriteAttributeString("ID", dockPanel.Panes.IndexOf(pane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("DockState", pane.DockState.ToString()); + xmlOut.WriteAttributeString("ActiveContent", dockPanel.Contents.IndexOf(pane.ActiveContent).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteStartElement("Contents"); + xmlOut.WriteAttributeString("Count", pane.Contents.Count.ToString(CultureInfo.InvariantCulture)); + foreach (IDockContent content in pane.Contents) + { + xmlOut.WriteStartElement("Content"); + xmlOut.WriteAttributeString("ID", pane.Contents.IndexOf(content).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("RefID", dockPanel.Contents.IndexOf(content).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + + // DockWindows + xmlOut.WriteStartElement("DockWindows"); + int dockWindowId = 0; + foreach (DockWindow dw in dockPanel.DockWindows) + { + xmlOut.WriteStartElement("DockWindow"); + xmlOut.WriteAttributeString("ID", dockWindowId.ToString(CultureInfo.InvariantCulture)); + dockWindowId++; + xmlOut.WriteAttributeString("DockState", dw.DockState.ToString()); + xmlOut.WriteAttributeString("ZOrderIndex", dockPanel.Controls.IndexOf(dw).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteStartElement("NestedPanes"); + xmlOut.WriteAttributeString("Count", dw.NestedPanes.Count.ToString(CultureInfo.InvariantCulture)); + foreach (DockPane pane in dw.NestedPanes) + { + xmlOut.WriteStartElement("Pane"); + xmlOut.WriteAttributeString("ID", dw.NestedPanes.IndexOf(pane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("RefID", dockPanel.Panes.IndexOf(pane).ToString(CultureInfo.InvariantCulture)); + NestedDockingStatus status = pane.NestedDockingStatus; + xmlOut.WriteAttributeString("PrevPane", dockPanel.Panes.IndexOf(status.PreviousPane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("Alignment", status.Alignment.ToString()); + xmlOut.WriteAttributeString("Proportion", status.Proportion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + + // FloatWindows + RectangleConverter rectConverter = new RectangleConverter(); + xmlOut.WriteStartElement("FloatWindows"); + xmlOut.WriteAttributeString("Count", dockPanel.FloatWindows.Count.ToString(CultureInfo.InvariantCulture)); + foreach (FloatWindow fw in dockPanel.FloatWindows) + { + xmlOut.WriteStartElement("FloatWindow"); + xmlOut.WriteAttributeString("ID", dockPanel.FloatWindows.IndexOf(fw).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("Bounds", rectConverter.ConvertToInvariantString(fw.Bounds)); + xmlOut.WriteAttributeString("ZOrderIndex", fw.DockPanel.FloatWindows.IndexOf(fw).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteStartElement("NestedPanes"); + xmlOut.WriteAttributeString("Count", fw.NestedPanes.Count.ToString(CultureInfo.InvariantCulture)); + foreach (DockPane pane in fw.NestedPanes) + { + xmlOut.WriteStartElement("Pane"); + xmlOut.WriteAttributeString("ID", fw.NestedPanes.IndexOf(pane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("RefID", dockPanel.Panes.IndexOf(pane).ToString(CultureInfo.InvariantCulture)); + NestedDockingStatus status = pane.NestedDockingStatus; + xmlOut.WriteAttributeString("PrevPane", dockPanel.Panes.IndexOf(status.PreviousPane).ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteAttributeString("Alignment", status.Alignment.ToString()); + xmlOut.WriteAttributeString("Proportion", status.Proportion.ToString(CultureInfo.InvariantCulture)); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); + xmlOut.WriteEndElement(); + } + xmlOut.WriteEndElement(); // + + xmlOut.WriteEndElement(); + + if (!upstream) + { + xmlOut.WriteEndDocument(); + xmlOut.Close(); + } + else + xmlOut.Flush(); + } + + public static void LoadFromXml(DockPanel dockPanel, string fileName, DeserializeDockContent deserializeContent) + { + FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); + try + { + LoadFromXml(dockPanel, fs, deserializeContent); + } + finally + { + fs.Close(); + } + } + + public static void LoadFromXml(DockPanel dockPanel, Stream stream, DeserializeDockContent deserializeContent) + { + LoadFromXml(dockPanel, stream, deserializeContent, true); + } + + private static ContentStruct[] LoadContents(XmlTextReader xmlIn) + { + int countOfContents = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + ContentStruct[] contents = new ContentStruct[countOfContents]; + MoveToNextElement(xmlIn); + for (int i = 0; i < countOfContents; i++) + { + int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "Content" || id != i) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + + contents[i].PersistString = xmlIn.GetAttribute("PersistString"); + contents[i].AutoHidePortion = Convert.ToDouble(xmlIn.GetAttribute("AutoHidePortion"), CultureInfo.InvariantCulture); + contents[i].IsHidden = Convert.ToBoolean(xmlIn.GetAttribute("IsHidden"), CultureInfo.InvariantCulture); + contents[i].IsFloat = Convert.ToBoolean(xmlIn.GetAttribute("IsFloat"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + } + + return contents; + } + + private static PaneStruct[] LoadPanes(XmlTextReader xmlIn) + { + EnumConverter dockStateConverter = new EnumConverter(typeof(DockState)); + int countOfPanes = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + PaneStruct[] panes = new PaneStruct[countOfPanes]; + MoveToNextElement(xmlIn); + for (int i = 0; i < countOfPanes; i++) + { + int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "Pane" || id != i) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + + panes[i].DockState = (DockState)dockStateConverter.ConvertFrom(xmlIn.GetAttribute("DockState")); + panes[i].IndexActiveContent = Convert.ToInt32(xmlIn.GetAttribute("ActiveContent"), CultureInfo.InvariantCulture); + panes[i].ZOrderIndex = -1; + + MoveToNextElement(xmlIn); + if (xmlIn.Name != "Contents") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + int countOfPaneContents = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + panes[i].IndexContents = new int[countOfPaneContents]; + MoveToNextElement(xmlIn); + for (int j = 0; j < countOfPaneContents; j++) + { + int id2 = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "Content" || id2 != j) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + + panes[i].IndexContents[j] = Convert.ToInt32(xmlIn.GetAttribute("RefID"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + } + } + + return panes; + } + + private static DockWindowStruct[] LoadDockWindows(XmlTextReader xmlIn, DockPanel dockPanel) + { + EnumConverter dockStateConverter = new EnumConverter(typeof(DockState)); + EnumConverter dockAlignmentConverter = new EnumConverter(typeof(DockAlignment)); + int countOfDockWindows = dockPanel.DockWindows.Count; + DockWindowStruct[] dockWindows = new DockWindowStruct[countOfDockWindows]; + MoveToNextElement(xmlIn); + for (int i = 0; i < countOfDockWindows; i++) + { + int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "DockWindow" || id != i) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + + dockWindows[i].DockState = (DockState)dockStateConverter.ConvertFrom(xmlIn.GetAttribute("DockState")); + dockWindows[i].ZOrderIndex = Convert.ToInt32(xmlIn.GetAttribute("ZOrderIndex"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + if (xmlIn.Name != "DockList" && xmlIn.Name != "NestedPanes") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + int countOfNestedPanes = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + dockWindows[i].NestedPanes = new NestedPane[countOfNestedPanes]; + MoveToNextElement(xmlIn); + for (int j = 0; j < countOfNestedPanes; j++) + { + int id2 = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "Pane" || id2 != j) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + dockWindows[i].NestedPanes[j].IndexPane = Convert.ToInt32(xmlIn.GetAttribute("RefID"), CultureInfo.InvariantCulture); + dockWindows[i].NestedPanes[j].IndexPrevPane = Convert.ToInt32(xmlIn.GetAttribute("PrevPane"), CultureInfo.InvariantCulture); + dockWindows[i].NestedPanes[j].Alignment = (DockAlignment)dockAlignmentConverter.ConvertFrom(xmlIn.GetAttribute("Alignment")); + dockWindows[i].NestedPanes[j].Proportion = Convert.ToDouble(xmlIn.GetAttribute("Proportion"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + } + } + + return dockWindows; + } + + private static FloatWindowStruct[] LoadFloatWindows(XmlTextReader xmlIn) + { + EnumConverter dockAlignmentConverter = new EnumConverter(typeof(DockAlignment)); + RectangleConverter rectConverter = new RectangleConverter(); + int countOfFloatWindows = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + FloatWindowStruct[] floatWindows = new FloatWindowStruct[countOfFloatWindows]; + MoveToNextElement(xmlIn); + for (int i = 0; i < countOfFloatWindows; i++) + { + int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "FloatWindow" || id != i) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + + floatWindows[i].Bounds = (Rectangle)rectConverter.ConvertFromInvariantString(xmlIn.GetAttribute("Bounds")); + floatWindows[i].ZOrderIndex = Convert.ToInt32(xmlIn.GetAttribute("ZOrderIndex"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + if (xmlIn.Name != "DockList" && xmlIn.Name != "NestedPanes") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + int countOfNestedPanes = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture); + floatWindows[i].NestedPanes = new NestedPane[countOfNestedPanes]; + MoveToNextElement(xmlIn); + for (int j = 0; j < countOfNestedPanes; j++) + { + int id2 = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture); + if (xmlIn.Name != "Pane" || id2 != j) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + floatWindows[i].NestedPanes[j].IndexPane = Convert.ToInt32(xmlIn.GetAttribute("RefID"), CultureInfo.InvariantCulture); + floatWindows[i].NestedPanes[j].IndexPrevPane = Convert.ToInt32(xmlIn.GetAttribute("PrevPane"), CultureInfo.InvariantCulture); + floatWindows[i].NestedPanes[j].Alignment = (DockAlignment)dockAlignmentConverter.ConvertFrom(xmlIn.GetAttribute("Alignment")); + floatWindows[i].NestedPanes[j].Proportion = Convert.ToDouble(xmlIn.GetAttribute("Proportion"), CultureInfo.InvariantCulture); + MoveToNextElement(xmlIn); + } + } + + return floatWindows; + } + + public static void LoadFromXml(DockPanel dockPanel, Stream stream, DeserializeDockContent deserializeContent, bool closeStream) + { + + if (dockPanel.Contents.Count != 0) + throw new InvalidOperationException(Strings.DockPanel_LoadFromXml_AlreadyInitialized); + + XmlTextReader xmlIn = new XmlTextReader(stream); + xmlIn.WhitespaceHandling = WhitespaceHandling.None; + xmlIn.MoveToContent(); + + while (!xmlIn.Name.Equals("DockPanel")) + { + if (!MoveToNextElement(xmlIn)) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + } + + string formatVersion = xmlIn.GetAttribute("FormatVersion"); + if (!IsFormatVersionValid(formatVersion)) + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidFormatVersion); + + DockPanelStruct dockPanelStruct = new DockPanelStruct(); + dockPanelStruct.DockLeftPortion = Convert.ToDouble(xmlIn.GetAttribute("DockLeftPortion"), CultureInfo.InvariantCulture); + dockPanelStruct.DockRightPortion = Convert.ToDouble(xmlIn.GetAttribute("DockRightPortion"), CultureInfo.InvariantCulture); + dockPanelStruct.DockTopPortion = Convert.ToDouble(xmlIn.GetAttribute("DockTopPortion"), CultureInfo.InvariantCulture); + dockPanelStruct.DockBottomPortion = Convert.ToDouble(xmlIn.GetAttribute("DockBottomPortion"), CultureInfo.InvariantCulture); + dockPanelStruct.IndexActiveDocumentPane = Convert.ToInt32(xmlIn.GetAttribute("ActiveDocumentPane"), CultureInfo.InvariantCulture); + dockPanelStruct.IndexActivePane = Convert.ToInt32(xmlIn.GetAttribute("ActivePane"), CultureInfo.InvariantCulture); + + // Load Contents + MoveToNextElement(xmlIn); + if (xmlIn.Name != "Contents") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + ContentStruct[] contents = LoadContents(xmlIn); + + // Load Panes + if (xmlIn.Name != "Panes") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + PaneStruct[] panes = LoadPanes(xmlIn); + + // Load DockWindows + if (xmlIn.Name != "DockWindows") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + DockWindowStruct[] dockWindows = LoadDockWindows(xmlIn, dockPanel); + + // Load FloatWindows + if (xmlIn.Name != "FloatWindows") + throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat); + FloatWindowStruct[] floatWindows = LoadFloatWindows(xmlIn); + + if (closeStream) + xmlIn.Close(); + + dockPanel.SuspendLayout(true); + + dockPanel.DockLeftPortion = dockPanelStruct.DockLeftPortion; + dockPanel.DockRightPortion = dockPanelStruct.DockRightPortion; + dockPanel.DockTopPortion = dockPanelStruct.DockTopPortion; + dockPanel.DockBottomPortion = dockPanelStruct.DockBottomPortion; + + // Set DockWindow ZOrders + int prevMaxDockWindowZOrder = int.MaxValue; + for (int i = 0; i < dockWindows.Length; i++) + { + int maxDockWindowZOrder = -1; + int index = -1; + for (int j = 0; j < dockWindows.Length; j++) + { + if (dockWindows[j].ZOrderIndex > maxDockWindowZOrder && dockWindows[j].ZOrderIndex < prevMaxDockWindowZOrder) + { + maxDockWindowZOrder = dockWindows[j].ZOrderIndex; + index = j; + } + } + + dockPanel.DockWindows[dockWindows[index].DockState].BringToFront(); + prevMaxDockWindowZOrder = maxDockWindowZOrder; + } + + // Create Contents + for (int i = 0; i < contents.Length; i++) + { + IDockContent content = deserializeContent(contents[i].PersistString); + if (content == null) + content = new DummyContent(); + content.DockHandler.DockPanel = dockPanel; + content.DockHandler.AutoHidePortion = contents[i].AutoHidePortion; + content.DockHandler.IsHidden = true; + content.DockHandler.IsFloat = contents[i].IsFloat; + } + + // Create panes + for (int i = 0; i < panes.Length; i++) + { + DockPane pane = null; + for (int j = 0; j < panes[i].IndexContents.Length; j++) + { + IDockContent content = dockPanel.Contents[panes[i].IndexContents[j]]; + if (j == 0) + pane = dockPanel.DockPaneFactory.CreateDockPane(content, panes[i].DockState, false); + else if (panes[i].DockState == DockState.Float) + content.DockHandler.FloatPane = pane; + else + content.DockHandler.PanelPane = pane; + } + } + + // Assign Panes to DockWindows + for (int i = 0; i < dockWindows.Length; i++) + { + for (int j = 0; j < dockWindows[i].NestedPanes.Length; j++) + { + DockWindow dw = dockPanel.DockWindows[dockWindows[i].DockState]; + int indexPane = dockWindows[i].NestedPanes[j].IndexPane; + DockPane pane = dockPanel.Panes[indexPane]; + int indexPrevPane = dockWindows[i].NestedPanes[j].IndexPrevPane; + DockPane prevPane = (indexPrevPane == -1) ? dw.NestedPanes.GetDefaultPreviousPane(pane) : dockPanel.Panes[indexPrevPane]; + DockAlignment alignment = dockWindows[i].NestedPanes[j].Alignment; + double proportion = dockWindows[i].NestedPanes[j].Proportion; + pane.DockTo(dw, prevPane, alignment, proportion); + if (panes[indexPane].DockState == dw.DockState) + panes[indexPane].ZOrderIndex = dockWindows[i].ZOrderIndex; + } + } + + // Create float windows + for (int i = 0; i < floatWindows.Length; i++) + { + FloatWindow fw = null; + for (int j = 0; j < floatWindows[i].NestedPanes.Length; j++) + { + int indexPane = floatWindows[i].NestedPanes[j].IndexPane; + DockPane pane = dockPanel.Panes[indexPane]; + if (j == 0) + fw = dockPanel.FloatWindowFactory.CreateFloatWindow(dockPanel, pane, floatWindows[i].Bounds); + else + { + int indexPrevPane = floatWindows[i].NestedPanes[j].IndexPrevPane; + DockPane prevPane = indexPrevPane == -1 ? null : dockPanel.Panes[indexPrevPane]; + DockAlignment alignment = floatWindows[i].NestedPanes[j].Alignment; + double proportion = floatWindows[i].NestedPanes[j].Proportion; + pane.DockTo(fw, prevPane, alignment, proportion); + } + + if (panes[indexPane].DockState == fw.DockState) + panes[indexPane].ZOrderIndex = floatWindows[i].ZOrderIndex; + } + } + + // sort IDockContent by its Pane's ZOrder + int[] sortedContents = null; + if (contents.Length > 0) + { + sortedContents = new int[contents.Length]; + for (int i = 0; i < contents.Length; i++) + sortedContents[i] = i; + + int lastDocument = contents.Length; + for (int i = 0; i < contents.Length - 1; i++) + { + for (int j = i + 1; j < contents.Length; j++) + { + DockPane pane1 = dockPanel.Contents[sortedContents[i]].DockHandler.Pane; + int ZOrderIndex1 = pane1 == null ? 0 : panes[dockPanel.Panes.IndexOf(pane1)].ZOrderIndex; + DockPane pane2 = dockPanel.Contents[sortedContents[j]].DockHandler.Pane; + int ZOrderIndex2 = pane2 == null ? 0 : panes[dockPanel.Panes.IndexOf(pane2)].ZOrderIndex; + if (ZOrderIndex1 > ZOrderIndex2) + { + int temp = sortedContents[i]; + sortedContents[i] = sortedContents[j]; + sortedContents[j] = temp; + } + } + } + } + + // show non-document IDockContent first to avoid screen flickers + for (int i = 0; i < contents.Length; i++) + { + IDockContent content = dockPanel.Contents[sortedContents[i]]; + if (content.DockHandler.Pane != null && content.DockHandler.Pane.DockState != DockState.Document) + content.DockHandler.IsHidden = contents[sortedContents[i]].IsHidden; + } + + // after all non-document IDockContent, show document IDockContent + for (int i = 0; i < contents.Length; i++) + { + IDockContent content = dockPanel.Contents[sortedContents[i]]; + if (content.DockHandler.Pane != null && content.DockHandler.Pane.DockState == DockState.Document) + content.DockHandler.IsHidden = contents[sortedContents[i]].IsHidden; + } + + for (int i = 0; i < panes.Length; i++) + dockPanel.Panes[i].ActiveContent = panes[i].IndexActiveContent == -1 ? null : dockPanel.Contents[panes[i].IndexActiveContent]; + + if (dockPanelStruct.IndexActiveDocumentPane != -1) + dockPanel.Panes[dockPanelStruct.IndexActiveDocumentPane].Activate(); + + if (dockPanelStruct.IndexActivePane != -1) + dockPanel.Panes[dockPanelStruct.IndexActivePane].Activate(); + + for (int i = dockPanel.Contents.Count - 1; i >= 0; i--) + if (dockPanel.Contents[i] is DummyContent) + dockPanel.Contents[i].DockHandler.Form.Close(); + + dockPanel.ResumeLayout(true, true); + } + + private static bool MoveToNextElement(XmlTextReader xmlIn) + { + if (!xmlIn.Read()) + return false; + + while (xmlIn.NodeType == XmlNodeType.EndElement) + { + if (!xmlIn.Read()) + return false; + } + + return true; + } + + private static bool IsFormatVersionValid(string formatVersion) + { + if (formatVersion == ConfigFileVersion) + return true; + + foreach (string s in CompatibleConfigFileVersions) + if (s == formatVersion) + return true; + + return false; + } + } + + public void SaveAsXml(string fileName) + { + Persistor.SaveAsXml(this, fileName); + } + + public void SaveAsXml(string fileName, Encoding encoding) + { + Persistor.SaveAsXml(this, fileName, encoding); + } + + public void SaveAsXml(Stream stream, Encoding encoding) + { + Persistor.SaveAsXml(this, stream, encoding); + } + + public void SaveAsXml(Stream stream, Encoding encoding, bool upstream) + { + Persistor.SaveAsXml(this, stream, encoding, upstream); + } + + public void LoadFromXml(string fileName, DeserializeDockContent deserializeContent) + { + Persistor.LoadFromXml(this, fileName, deserializeContent); + } + + public void LoadFromXml(Stream stream, DeserializeDockContent deserializeContent) + { + Persistor.LoadFromXml(this, stream, deserializeContent); + } + + public void LoadFromXml(Stream stream, DeserializeDockContent deserializeContent, bool closeStream) + { + Persistor.LoadFromXml(this, stream, deserializeContent, closeStream); + } + } +} diff --git a/trunk/Docking/DockPanel.SplitterDragHandler.cs b/trunk/Docking/DockPanel.SplitterDragHandler.cs new file mode 100644 index 0000000..e6bab36 --- /dev/null +++ b/trunk/Docking/DockPanel.SplitterDragHandler.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.ComponentModel; + +namespace LSLEditor.Docking +{ + partial class DockPanel + { + private sealed class SplitterDragHandler : DragHandler + { + private class SplitterOutline + { + public SplitterOutline() + { + m_dragForm = new DragForm(); + SetDragForm(Rectangle.Empty); + DragForm.BackColor = Color.Black; + DragForm.Opacity = 0.7; + DragForm.Show(false); + } + + DragForm m_dragForm; + private DragForm DragForm + { + get { return m_dragForm; } + } + + public void Show(Rectangle rect) + { + SetDragForm(rect); + } + + public void Close() + { + DragForm.Close(); + } + + private void SetDragForm(Rectangle rect) + { + DragForm.Bounds = rect; + if (rect == Rectangle.Empty) + DragForm.Region = new Region(Rectangle.Empty); + else if (DragForm.Region != null) + DragForm.Region = null; + } + } + + public SplitterDragHandler(DockPanel dockPanel) + : base(dockPanel) + { + } + + public new ISplitterDragSource DragSource + { + get { return base.DragSource as ISplitterDragSource; } + private set { base.DragSource = value; } + } + + private SplitterOutline m_outline; + private SplitterOutline Outline + { + get { return m_outline; } + set { m_outline = value; } + } + + private Rectangle m_rectSplitter; + private Rectangle RectSplitter + { + get { return m_rectSplitter; } + set { m_rectSplitter = value; } + } + + public void BeginDrag(ISplitterDragSource dragSource, Rectangle rectSplitter) + { + DragSource = dragSource; + RectSplitter = rectSplitter; + + if (!BeginDrag()) + { + DragSource = null; + return; + } + + Outline = new SplitterOutline(); + Outline.Show(rectSplitter); + DragSource.BeginDrag(rectSplitter); + } + + protected override void OnDragging() + { + Outline.Show(GetSplitterOutlineBounds(Control.MousePosition)); + } + + protected override void OnEndDrag(bool abort) + { + DockPanel.SuspendLayout(true); + + Outline.Close(); + + if (!abort) + DragSource.MoveSplitter(GetMovingOffset(Control.MousePosition)); + + DragSource.EndDrag(); + DockPanel.ResumeLayout(true, true); + } + + private int GetMovingOffset(Point ptMouse) + { + Rectangle rect = GetSplitterOutlineBounds(ptMouse); + if (DragSource.IsVertical) + return rect.X - RectSplitter.X; + else + return rect.Y - RectSplitter.Y; + } + + private Rectangle GetSplitterOutlineBounds(Point ptMouse) + { + Rectangle rectLimit = DragSource.DragLimitBounds; + + Rectangle rect = RectSplitter; + if (rectLimit.Width <= 0 || rectLimit.Height <= 0) + return rect; + + if (DragSource.IsVertical) + { + rect.X += ptMouse.X - StartMousePosition.X; + rect.Height = rectLimit.Height; + } + else + { + rect.Y += ptMouse.Y - StartMousePosition.Y; + rect.Width = rectLimit.Width; + } + + if (rect.Left < rectLimit.Left) + rect.X = rectLimit.X; + if (rect.Top < rectLimit.Top) + rect.Y = rectLimit.Y; + if (rect.Right > rectLimit.Right) + rect.X -= rect.Right - rectLimit.Right; + if (rect.Bottom > rectLimit.Bottom) + rect.Y -= rect.Bottom - rectLimit.Bottom; + + return rect; + } + } + + private SplitterDragHandler m_splitterDragHandler = null; + private SplitterDragHandler GetSplitterDragHandler() + { + if (m_splitterDragHandler == null) + m_splitterDragHandler = new SplitterDragHandler(this); + return m_splitterDragHandler; + } + + internal void BeginDrag(ISplitterDragSource dragSource, Rectangle rectSplitter) + { + GetSplitterDragHandler().BeginDrag(dragSource, rectSplitter); + } + } +} diff --git a/trunk/Docking/DockPanel.bmp b/trunk/Docking/DockPanel.bmp new file mode 100644 index 0000000000000000000000000000000000000000..10d6858f9490df8c44bc54bb02ab98d05d052484 GIT binary patch literal 822 zcmbV_(G7qg3~$x7}%dq7e+dr!<0rf4+`axo8$wKBceVOu6aY@k6LOI;(>ATU_|AQ5wMj X8lVvjpaB}em)YQocLrtG_;(y0(ZY@L literal 0 HcmV?d00001 diff --git a/trunk/Docking/DockPanel.cs b/trunk/Docking/DockPanel.cs new file mode 100644 index 0000000..c602dee --- /dev/null +++ b/trunk/Docking/DockPanel.cs @@ -0,0 +1,1028 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.IO; +using System.Text; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; + +// To simplify the process of finding the toolbox bitmap resource: +// #1 Create an internal class called "resfinder" outside of the root namespace. +// #2 Use "resfinder" in the toolbox bitmap attribute instead of the control name. +// #3 use the "." string to locate the resource. +// See: http://www.bobpowell.net/toolboxbitmap.htm +internal class resfinder +{ +} + +namespace LSLEditor.Docking +{ + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "0#")] + public delegate IDockContent DeserializeDockContent(string persistString); + + [LocalizedDescription("DockPanel_Description")] + [Designer(typeof(System.Windows.Forms.Design.ControlDesigner))] + [ToolboxBitmap(typeof(resfinder), "LSLEditor.Docking.DockPanel.bmp")] + [DefaultProperty("DocumentStyle")] + [DefaultEvent("ActiveContentChanged")] + public partial class DockPanel : Panel + { + private FocusManagerImpl m_focusManager; + private DockPanelExtender m_extender; + private DockPaneCollection m_panes; + private FloatWindowCollection m_floatWindows; + private AutoHideWindowControl m_autoHideWindow; + private DockWindowCollection m_dockWindows; + private DockContent m_dummyContent; + private Control m_dummyControl; + + public DockPanel() + { + m_focusManager = new FocusManagerImpl(this); + m_extender = new DockPanelExtender(this); + m_panes = new DockPaneCollection(); + m_floatWindows = new FloatWindowCollection(); + + SuspendLayout(); + + m_autoHideWindow = new AutoHideWindowControl(this); + m_autoHideWindow.Visible = false; + SetAutoHideWindowParent(); + + m_dummyControl = new DummyControl(); + m_dummyControl.Bounds = new Rectangle(0, 0, 1, 1); + Controls.Add(m_dummyControl); + + m_dockWindows = new DockWindowCollection(this); + Controls.AddRange(new Control[] { + DockWindows[DockState.Document], + DockWindows[DockState.DockLeft], + DockWindows[DockState.DockRight], + DockWindows[DockState.DockTop], + DockWindows[DockState.DockBottom] + }); + + m_dummyContent = new DockContent(); + ResumeLayout(); + } + + private Color m_BackColor; + /// + /// Determines the color with which the client rectangle will be drawn. + /// If you take this property instead of the BackColor it will not have any influence on the borders to the surrounding controls (DockPane). + /// If you use BackColor the borders to the surrounding controls (DockPane) will also change there colors. + /// Alternatively you can use both of them (BackColor to draw the define the color of the borders and DockBackColor to define the color of the client rectangle). + /// For Backgroundimages: Set your prefered Image, then set the DockBackColor and the BackColor to the same Color (Control) + /// + public Color DockBackColor + { + get + { + return !m_BackColor.IsEmpty ? m_BackColor : base.BackColor; + } + set + { + m_BackColor = value; + } + } + + private AutoHideStripBase m_autoHideStripControl = null; + internal AutoHideStripBase AutoHideStripControl + { + get + { + if (m_autoHideStripControl == null) + { + m_autoHideStripControl = AutoHideStripFactory.CreateAutoHideStrip(this); + Controls.Add(m_autoHideStripControl); + } + return m_autoHideStripControl; + } + } + internal void ResetAutoHideStripControl() + { + if (m_autoHideStripControl != null) + m_autoHideStripControl.Dispose(); + + m_autoHideStripControl = null; + } + + private void MdiClientHandleAssigned(object sender, EventArgs e) + { + SetMdiClient(); + PerformLayout(); + } + + private void MdiClient_Layout(object sender, LayoutEventArgs e) + { + if (DocumentStyle != DocumentStyle.DockingMdi) + return; + + foreach (DockPane pane in Panes) + if (pane.DockState == DockState.Document) + pane.SetContentBounds(); + + InvalidateWindowRegion(); + } + + private bool m_disposed = false; + protected override void Dispose(bool disposing) + { + lock (this) + { + if (!m_disposed && disposing) + { + m_focusManager.Dispose(); + if (m_mdiClientController != null) + { + m_mdiClientController.HandleAssigned -= new EventHandler(MdiClientHandleAssigned); + m_mdiClientController.MdiChildActivate -= new EventHandler(ParentFormMdiChildActivate); + m_mdiClientController.Layout -= new LayoutEventHandler(MdiClient_Layout); + m_mdiClientController.Dispose(); + } + FloatWindows.Dispose(); + Panes.Dispose(); + DummyContent.Dispose(); + + m_disposed = true; + } + + base.Dispose(disposing); + } + } + + [Browsable(false)] + public IDockContent ActiveAutoHideContent + { + get { return AutoHideWindow.ActiveContent; } + set { AutoHideWindow.ActiveContent = value; } + } + + private bool m_allowEndUserDocking = true; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_AllowEndUserDocking_Description")] + [DefaultValue(true)] + public bool AllowEndUserDocking + { + get { return m_allowEndUserDocking; } + set { m_allowEndUserDocking = value; } + } + + private bool m_allowEndUserNestedDocking = true; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_AllowEndUserNestedDocking_Description")] + [DefaultValue(true)] + public bool AllowEndUserNestedDocking + { + get { return m_allowEndUserNestedDocking; } + set { m_allowEndUserNestedDocking = value; } + } + + private DockContentCollection m_contents = new DockContentCollection(); + [Browsable(false)] + public DockContentCollection Contents + { + get { return m_contents; } + } + + internal DockContent DummyContent + { + get { return m_dummyContent; } + } + + private bool m_rightToLeftLayout = false; + [DefaultValue(false)] + [LocalizedCategory("Appearance")] + [LocalizedDescription("DockPanel_RightToLeftLayout_Description")] + public bool RightToLeftLayout + { + get { return m_rightToLeftLayout; } + set + { + if (m_rightToLeftLayout == value) + return; + + m_rightToLeftLayout = value; + foreach (FloatWindow floatWindow in FloatWindows) + floatWindow.RightToLeftLayout = value; + } + } + + protected override void OnRightToLeftChanged(EventArgs e) + { + base.OnRightToLeftChanged(e); + foreach (FloatWindow floatWindow in FloatWindows) + { + if (floatWindow.RightToLeft != RightToLeft) + floatWindow.RightToLeft = RightToLeft; + } + } + + private bool m_showDocumentIcon = false; + [DefaultValue(false)] + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_ShowDocumentIcon_Description")] + public bool ShowDocumentIcon + { + get { return m_showDocumentIcon; } + set + { + if (m_showDocumentIcon == value) + return; + + m_showDocumentIcon = value; + Refresh(); + } + } + + private DockPanelSkin m_dockPanelSkin = new DockPanelSkin(); + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockPanelSkin")] + public DockPanelSkin Skin + { + get { return m_dockPanelSkin; } + set { m_dockPanelSkin = value; } + } + + private DocumentTabStripLocation m_documentTabStripLocation = DocumentTabStripLocation.Top; + [DefaultValue(DocumentTabStripLocation.Top)] + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DocumentTabStripLocation")] + public DocumentTabStripLocation DocumentTabStripLocation + { + get { return m_documentTabStripLocation; } + set { m_documentTabStripLocation = value; } + } + + [Browsable(false)] + public DockPanelExtender Extender + { + get { return m_extender; } + } + + public DockPanelExtender.IDockPaneFactory DockPaneFactory + { + get { return Extender.DockPaneFactory; } + } + + public DockPanelExtender.IFloatWindowFactory FloatWindowFactory + { + get { return Extender.FloatWindowFactory; } + } + + internal DockPanelExtender.IDockPaneCaptionFactory DockPaneCaptionFactory + { + get { return Extender.DockPaneCaptionFactory; } + } + + internal DockPanelExtender.IDockPaneStripFactory DockPaneStripFactory + { + get { return Extender.DockPaneStripFactory; } + } + + internal DockPanelExtender.IAutoHideStripFactory AutoHideStripFactory + { + get { return Extender.AutoHideStripFactory; } + } + + [Browsable(false)] + public DockPaneCollection Panes + { + get { return m_panes; } + } + + internal Rectangle DockArea + { + get + { + return new Rectangle(DockPadding.Left, DockPadding.Top, + ClientRectangle.Width - DockPadding.Left - DockPadding.Right, + ClientRectangle.Height - DockPadding.Top - DockPadding.Bottom); + } + } + + private double m_dockBottomPortion = 0.25; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockBottomPortion_Description")] + [DefaultValue(0.25)] + public double DockBottomPortion + { + get { return m_dockBottomPortion; } + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + + if (value == m_dockBottomPortion) + return; + + m_dockBottomPortion = value; + + if (m_dockBottomPortion < 1 && m_dockTopPortion < 1) + { + if (m_dockTopPortion + m_dockBottomPortion > 1) + m_dockTopPortion = 1 - m_dockBottomPortion; + } + + PerformLayout(); + } + } + + private double m_dockLeftPortion = 0.25; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockLeftPortion_Description")] + [DefaultValue(0.25)] + public double DockLeftPortion + { + get { return m_dockLeftPortion; } + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + + if (value == m_dockLeftPortion) + return; + + m_dockLeftPortion = value; + + if (m_dockLeftPortion < 1 && m_dockRightPortion < 1) + { + if (m_dockLeftPortion + m_dockRightPortion > 1) + m_dockRightPortion = 1 - m_dockLeftPortion; + } + PerformLayout(); + } + } + + private double m_dockRightPortion = 0.25; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockRightPortion_Description")] + [DefaultValue(0.25)] + public double DockRightPortion + { + get { return m_dockRightPortion; } + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + + if (value == m_dockRightPortion) + return; + + m_dockRightPortion = value; + + if (m_dockLeftPortion < 1 && m_dockRightPortion < 1) + { + if (m_dockLeftPortion + m_dockRightPortion > 1) + m_dockLeftPortion = 1 - m_dockRightPortion; + } + PerformLayout(); + } + } + + private double m_dockTopPortion = 0.25; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DockTopPortion_Description")] + [DefaultValue(0.25)] + public double DockTopPortion + { + get { return m_dockTopPortion; } + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + + if (value == m_dockTopPortion) + return; + + m_dockTopPortion = value; + + if (m_dockTopPortion < 1 && m_dockBottomPortion < 1) + { + if (m_dockTopPortion + m_dockBottomPortion > 1) + m_dockBottomPortion = 1 - m_dockTopPortion; + } + PerformLayout(); + } + } + + [Browsable(false)] + public DockWindowCollection DockWindows + { + get { return m_dockWindows; } + } + + public void UpdateDockWindowZOrder(DockStyle dockStyle, bool fullPanelEdge) + { + if (dockStyle == DockStyle.Left) + { + if (fullPanelEdge) + DockWindows[DockState.DockLeft].SendToBack(); + else + DockWindows[DockState.DockLeft].BringToFront(); + } + else if (dockStyle == DockStyle.Right) + { + if (fullPanelEdge) + DockWindows[DockState.DockRight].SendToBack(); + else + DockWindows[DockState.DockRight].BringToFront(); + } + else if (dockStyle == DockStyle.Top) + { + if (fullPanelEdge) + DockWindows[DockState.DockTop].SendToBack(); + else + DockWindows[DockState.DockTop].BringToFront(); + } + else if (dockStyle == DockStyle.Bottom) + { + if (fullPanelEdge) + DockWindows[DockState.DockBottom].SendToBack(); + else + DockWindows[DockState.DockBottom].BringToFront(); + } + } + + public int DocumentsCount + { + get + { + int count = 0; + foreach (IDockContent content in Documents) + count++; + + return count; + } + } + + public IDockContent[] DocumentsToArray() + { + int count = DocumentsCount; + IDockContent[] documents = new IDockContent[count]; + int i = 0; + foreach (IDockContent content in Documents) + { + documents[i] = content; + i++; + } + + return documents; + } + + public IEnumerable Documents + { + get + { + foreach (IDockContent content in Contents) + { + if (content.DockHandler.DockState == DockState.Document) + yield return content; + } + } + } + + private Rectangle DocumentRectangle + { + get + { + Rectangle rect = DockArea; + if (DockWindows[DockState.DockLeft].VisibleNestedPanes.Count != 0) + { + rect.X += (int)(DockArea.Width * DockLeftPortion); + rect.Width -= (int)(DockArea.Width * DockLeftPortion); + } + if (DockWindows[DockState.DockRight].VisibleNestedPanes.Count != 0) + rect.Width -= (int)(DockArea.Width * DockRightPortion); + if (DockWindows[DockState.DockTop].VisibleNestedPanes.Count != 0) + { + rect.Y += (int)(DockArea.Height * DockTopPortion); + rect.Height -= (int)(DockArea.Height * DockTopPortion); + } + if (DockWindows[DockState.DockBottom].VisibleNestedPanes.Count != 0) + rect.Height -= (int)(DockArea.Height * DockBottomPortion); + + return rect; + } + } + + private Control DummyControl + { + get { return m_dummyControl; } + } + + [Browsable(false)] + public FloatWindowCollection FloatWindows + { + get { return m_floatWindows; } + } + + private Size m_defaultFloatWindowSize = new Size(300, 300); + [Category("Layout")] + [LocalizedDescription("DockPanel_DefaultFloatWindowSize_Description")] + public Size DefaultFloatWindowSize + { + get { return m_defaultFloatWindowSize; } + set { m_defaultFloatWindowSize = value; } + } + private bool ShouldSerializeDefaultFloatWindowSize() + { + return DefaultFloatWindowSize != new Size(300, 300); + } + + private DocumentStyle m_documentStyle = DocumentStyle.DockingMdi; + [LocalizedCategory("Category_Docking")] + [LocalizedDescription("DockPanel_DocumentStyle_Description")] + [DefaultValue(DocumentStyle.DockingMdi)] + public DocumentStyle DocumentStyle + { + get { return m_documentStyle; } + set + { + if (value == m_documentStyle) + return; + + if (!Enum.IsDefined(typeof(DocumentStyle), value)) + throw new InvalidEnumArgumentException(); + + if (value == DocumentStyle.SystemMdi && DockWindows[DockState.Document].VisibleNestedPanes.Count > 0) + throw new InvalidEnumArgumentException(); + + m_documentStyle = value; + + SuspendLayout(true); + + SetAutoHideWindowParent(); + SetMdiClient(); + InvalidateWindowRegion(); + + foreach (IDockContent content in Contents) + { + if (content.DockHandler.DockState == DockState.Document) + content.DockHandler.SetPaneAndVisible(content.DockHandler.Pane); + } + + PerformMdiClientLayout(); + + ResumeLayout(true, true); + } + } + + private int GetDockWindowSize(DockState dockState) + { + if (dockState == DockState.DockLeft || dockState == DockState.DockRight) + { + int width = ClientRectangle.Width - DockPadding.Left - DockPadding.Right; + int dockLeftSize = m_dockLeftPortion >= 1 ? (int)m_dockLeftPortion : (int)(width * m_dockLeftPortion); + int dockRightSize = m_dockRightPortion >= 1 ? (int)m_dockRightPortion : (int)(width * m_dockRightPortion); + + if (dockLeftSize < MeasurePane.MinSize) + dockLeftSize = MeasurePane.MinSize; + if (dockRightSize < MeasurePane.MinSize) + dockRightSize = MeasurePane.MinSize; + + if (dockLeftSize + dockRightSize > width - MeasurePane.MinSize) + { + int adjust = (dockLeftSize + dockRightSize) - (width - MeasurePane.MinSize); + dockLeftSize -= adjust / 2; + dockRightSize -= adjust / 2; + } + + return dockState == DockState.DockLeft ? dockLeftSize : dockRightSize; + } + else if (dockState == DockState.DockTop || dockState == DockState.DockBottom) + { + int height = ClientRectangle.Height - DockPadding.Top - DockPadding.Bottom; + int dockTopSize = m_dockTopPortion >= 1 ? (int)m_dockTopPortion : (int)(height * m_dockTopPortion); + int dockBottomSize = m_dockBottomPortion >= 1 ? (int)m_dockBottomPortion : (int)(height * m_dockBottomPortion); + + if (dockTopSize < MeasurePane.MinSize) + dockTopSize = MeasurePane.MinSize; + if (dockBottomSize < MeasurePane.MinSize) + dockBottomSize = MeasurePane.MinSize; + + if (dockTopSize + dockBottomSize > height - MeasurePane.MinSize) + { + int adjust = (dockTopSize + dockBottomSize) - (height - MeasurePane.MinSize); + dockTopSize -= adjust / 2; + dockBottomSize -= adjust / 2; + } + + return dockState == DockState.DockTop ? dockTopSize : dockBottomSize; + } + else + return 0; + } + + protected override void OnLayout(LayoutEventArgs levent) + { + SuspendLayout(true); + + AutoHideStripControl.Bounds = ClientRectangle; + + CalculateDockPadding(); + + DockWindows[DockState.DockLeft].Width = GetDockWindowSize(DockState.DockLeft); + DockWindows[DockState.DockRight].Width = GetDockWindowSize(DockState.DockRight); + DockWindows[DockState.DockTop].Height = GetDockWindowSize(DockState.DockTop); + DockWindows[DockState.DockBottom].Height = GetDockWindowSize(DockState.DockBottom); + + AutoHideWindow.Bounds = GetAutoHideWindowBounds(AutoHideWindowRectangle); + + DockWindows[DockState.Document].BringToFront(); + AutoHideWindow.BringToFront(); + + base.OnLayout(levent); + + if (DocumentStyle == DocumentStyle.SystemMdi && MdiClientExists) + { + SetMdiClientBounds(SystemMdiClientBounds); + InvalidateWindowRegion(); + } + else if (DocumentStyle == DocumentStyle.DockingMdi) + InvalidateWindowRegion(); + + ResumeLayout(true, true); + } + + internal Rectangle GetTabStripRectangle(DockState dockState) + { + return AutoHideStripControl.GetTabStripRectangle(dockState); + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + if (DockBackColor == BackColor) return; + + Graphics g = e.Graphics; + SolidBrush bgBrush = new SolidBrush(DockBackColor); + g.FillRectangle(bgBrush, ClientRectangle); + } + + internal void AddContent(IDockContent content) + { + if (content == null) + throw(new ArgumentNullException()); + + if (!Contents.Contains(content)) + { + Contents.Add(content); + OnContentAdded(new DockContentEventArgs(content)); + } + } + + internal void AddPane(DockPane pane) + { + if (Panes.Contains(pane)) + return; + + Panes.Add(pane); + } + + internal void AddFloatWindow(FloatWindow floatWindow) + { + if (FloatWindows.Contains(floatWindow)) + return; + + FloatWindows.Add(floatWindow); + } + + private void CalculateDockPadding() + { + DockPadding.All = 0; + + int height = AutoHideStripControl.MeasureHeight(); + + if (AutoHideStripControl.GetNumberOfPanes(DockState.DockLeftAutoHide) > 0) + DockPadding.Left = height; + if (AutoHideStripControl.GetNumberOfPanes(DockState.DockRightAutoHide) > 0) + DockPadding.Right = height; + if (AutoHideStripControl.GetNumberOfPanes(DockState.DockTopAutoHide) > 0) + DockPadding.Top = height; + if (AutoHideStripControl.GetNumberOfPanes(DockState.DockBottomAutoHide) > 0) + DockPadding.Bottom = height; + } + + internal void RemoveContent(IDockContent content) + { + if (content == null) + throw(new ArgumentNullException()); + + if (Contents.Contains(content)) + { + Contents.Remove(content); + OnContentRemoved(new DockContentEventArgs(content)); + } + } + + internal void RemovePane(DockPane pane) + { + if (!Panes.Contains(pane)) + return; + + Panes.Remove(pane); + } + + internal void RemoveFloatWindow(FloatWindow floatWindow) + { + if (!FloatWindows.Contains(floatWindow)) + return; + + FloatWindows.Remove(floatWindow); + } + + public void SetPaneIndex(DockPane pane, int index) + { + int oldIndex = Panes.IndexOf(pane); + if (oldIndex == -1) + throw(new ArgumentException(Strings.DockPanel_SetPaneIndex_InvalidPane)); + + if (index < 0 || index > Panes.Count - 1) + if (index != -1) + throw(new ArgumentOutOfRangeException(Strings.DockPanel_SetPaneIndex_InvalidIndex)); + + if (oldIndex == index) + return; + if (oldIndex == Panes.Count - 1 && index == -1) + return; + + Panes.Remove(pane); + if (index == -1) + Panes.Add(pane); + else if (oldIndex < index) + Panes.AddAt(pane, index - 1); + else + Panes.AddAt(pane, index); + } + + public void SuspendLayout(bool allWindows) + { + FocusManager.SuspendFocusTracking(); + SuspendLayout(); + if (allWindows) + SuspendMdiClientLayout(); + } + + public void ResumeLayout(bool performLayout, bool allWindows) + { + FocusManager.ResumeFocusTracking(); + ResumeLayout(performLayout); + if (allWindows) + ResumeMdiClientLayout(performLayout); + } + + internal Form ParentForm + { + get + { + if (!IsParentFormValid()) + throw new InvalidOperationException(Strings.DockPanel_ParentForm_Invalid); + + return GetMdiClientController().ParentForm; + } + } + + private bool IsParentFormValid() + { + if (DocumentStyle == DocumentStyle.DockingSdi || DocumentStyle == DocumentStyle.DockingWindow) + return true; + + if (!MdiClientExists) + GetMdiClientController().RenewMdiClient(); + + return (MdiClientExists); + } + + protected override void OnParentChanged(EventArgs e) + { + SetAutoHideWindowParent(); + GetMdiClientController().ParentForm = (this.Parent as Form); + base.OnParentChanged (e); + } + + private void SetAutoHideWindowParent() + { + Control parent; + if (DocumentStyle == DocumentStyle.DockingMdi || + DocumentStyle == DocumentStyle.SystemMdi) + parent = this.Parent; + else + parent = this; + if (AutoHideWindow.Parent != parent) + { + AutoHideWindow.Parent = parent; + AutoHideWindow.BringToFront(); + } + } + + protected override void OnVisibleChanged(EventArgs e) + { + base.OnVisibleChanged (e); + + if (Visible) + SetMdiClient(); + } + + private Rectangle SystemMdiClientBounds + { + get + { + if (!IsParentFormValid() || !Visible) + return Rectangle.Empty; + + Rectangle rect = ParentForm.RectangleToClient(RectangleToScreen(DocumentWindowBounds)); + return rect; + } + } + + internal Rectangle DocumentWindowBounds + { + get + { + Rectangle rectDocumentBounds = DisplayRectangle; + if (DockWindows[DockState.DockLeft].Visible) + { + rectDocumentBounds.X += DockWindows[DockState.DockLeft].Width; + rectDocumentBounds.Width -= DockWindows[DockState.DockLeft].Width; + } + if (DockWindows[DockState.DockRight].Visible) + rectDocumentBounds.Width -= DockWindows[DockState.DockRight].Width; + if (DockWindows[DockState.DockTop].Visible) + { + rectDocumentBounds.Y += DockWindows[DockState.DockTop].Height; + rectDocumentBounds.Height -= DockWindows[DockState.DockTop].Height; + } + if (DockWindows[DockState.DockBottom].Visible) + rectDocumentBounds.Height -= DockWindows[DockState.DockBottom].Height; + + return rectDocumentBounds; + + } + } + + private PaintEventHandler m_dummyControlPaintEventHandler = null; + private void InvalidateWindowRegion() + { + if (DesignMode) + return; + + if (m_dummyControlPaintEventHandler == null) + m_dummyControlPaintEventHandler = new PaintEventHandler(DummyControl_Paint); + + DummyControl.Paint += m_dummyControlPaintEventHandler; + DummyControl.Invalidate(); + } + + void DummyControl_Paint(object sender, PaintEventArgs e) + { + DummyControl.Paint -= m_dummyControlPaintEventHandler; + UpdateWindowRegion(); + } + + private void UpdateWindowRegion() + { + if (this.DocumentStyle == DocumentStyle.DockingMdi) + UpdateWindowRegion_ClipContent(); + else if (this.DocumentStyle == DocumentStyle.DockingSdi || + this.DocumentStyle == DocumentStyle.DockingWindow) + UpdateWindowRegion_FullDocumentArea(); + else if (this.DocumentStyle == DocumentStyle.SystemMdi) + UpdateWindowRegion_EmptyDocumentArea(); + } + + private void UpdateWindowRegion_FullDocumentArea() + { + SetRegion(null); + } + + private void UpdateWindowRegion_EmptyDocumentArea() + { + Rectangle rect = DocumentWindowBounds; + SetRegion(new Rectangle[] { rect }); + } + + private void UpdateWindowRegion_ClipContent() + { + int count = 0; + foreach (DockPane pane in this.Panes) + { + if (!pane.Visible || pane.DockState != DockState.Document) + continue; + + count ++; + } + + if (count == 0) + { + SetRegion(null); + return; + } + + Rectangle[] rects = new Rectangle[count]; + int i = 0; + foreach (DockPane pane in this.Panes) + { + if (!pane.Visible || pane.DockState != DockState.Document) + continue; + + rects[i] = RectangleToClient(pane.RectangleToScreen(pane.ContentRectangle)); + i++; + } + + SetRegion(rects); + } + + private Rectangle[] m_clipRects = null; + private void SetRegion(Rectangle[] clipRects) + { + if (!IsClipRectsChanged(clipRects)) + return; + + m_clipRects = clipRects; + + if (m_clipRects == null || m_clipRects.GetLength(0) == 0) + Region = null; + else + { + Region region = new Region(new Rectangle(0, 0, this.Width, this.Height)); + foreach (Rectangle rect in m_clipRects) + region.Exclude(rect); + Region = region; + } + } + + private bool IsClipRectsChanged(Rectangle[] clipRects) + { + if (clipRects == null && m_clipRects == null) + return false; + else if ((clipRects == null) != (m_clipRects == null)) + return true; + + foreach (Rectangle rect in clipRects) + { + bool matched = false; + foreach (Rectangle rect2 in m_clipRects) + { + if (rect == rect2) + { + matched = true; + break; + } + } + if (!matched) + return true; + } + + foreach (Rectangle rect2 in m_clipRects) + { + bool matched = false; + foreach (Rectangle rect in clipRects) + { + if (rect == rect2) + { + matched = true; + break; + } + } + if (!matched) + return true; + } + return false; + } + + private static readonly object ContentAddedEvent = new object(); + [LocalizedCategory("Category_DockingNotification")] + [LocalizedDescription("DockPanel_ContentAdded_Description")] + public event EventHandler ContentAdded + { + add { Events.AddHandler(ContentAddedEvent, value); } + remove { Events.RemoveHandler(ContentAddedEvent, value); } + } + protected virtual void OnContentAdded(DockContentEventArgs e) + { + EventHandler handler = (EventHandler)Events[ContentAddedEvent]; + if (handler != null) + handler(this, e); + } + + private static readonly object ContentRemovedEvent = new object(); + [LocalizedCategory("Category_DockingNotification")] + [LocalizedDescription("DockPanel_ContentRemoved_Description")] + public event EventHandler ContentRemoved + { + add { Events.AddHandler(ContentRemovedEvent, value); } + remove { Events.RemoveHandler(ContentRemovedEvent, value); } + } + protected virtual void OnContentRemoved(DockContentEventArgs e) + { + EventHandler handler = (EventHandler)Events[ContentRemovedEvent]; + if (handler != null) + handler(this, e); + } + } +} \ No newline at end of file diff --git a/trunk/Docking/DockPanelExtender.cs b/trunk/Docking/DockPanelExtender.cs new file mode 100644 index 0000000..08d431b --- /dev/null +++ b/trunk/Docking/DockPanelExtender.cs @@ -0,0 +1,225 @@ +using System; +using System.Drawing; +using System.Diagnostics.CodeAnalysis; + +namespace LSLEditor.Docking +{ + public sealed class DockPanelExtender + { + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public interface IDockPaneFactory + { + DockPane CreateDockPane(IDockContent content, DockState visibleState, bool show); + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")] + DockPane CreateDockPane(IDockContent content, FloatWindow floatWindow, bool show); + DockPane CreateDockPane(IDockContent content, DockPane previousPane, DockAlignment alignment, double proportion, bool show); + [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")] + DockPane CreateDockPane(IDockContent content, Rectangle floatWindowBounds, bool show); + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public interface IFloatWindowFactory + { + FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane); + FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds); + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public interface IDockPaneCaptionFactory + { + DockPaneCaptionBase CreateDockPaneCaption(DockPane pane); + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public interface IDockPaneStripFactory + { + DockPaneStripBase CreateDockPaneStrip(DockPane pane); + } + + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public interface IAutoHideStripFactory + { + AutoHideStripBase CreateAutoHideStrip(DockPanel panel); + } + + #region DefaultDockPaneFactory + private class DefaultDockPaneFactory : IDockPaneFactory + { + public DockPane CreateDockPane(IDockContent content, DockState visibleState, bool show) + { + return new DockPane(content, visibleState, show); + } + + public DockPane CreateDockPane(IDockContent content, FloatWindow floatWindow, bool show) + { + return new DockPane(content, floatWindow, show); + } + + public DockPane CreateDockPane(IDockContent content, DockPane prevPane, DockAlignment alignment, double proportion, bool show) + { + return new DockPane(content, prevPane, alignment, proportion, show); + } + + public DockPane CreateDockPane(IDockContent content, Rectangle floatWindowBounds, bool show) + { + return new DockPane(content, floatWindowBounds, show); + } + } + #endregion + + #region DefaultFloatWindowFactory + private class DefaultFloatWindowFactory : IFloatWindowFactory + { + public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane) + { + return new FloatWindow(dockPanel, pane); + } + + public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds) + { + return new FloatWindow(dockPanel, pane, bounds); + } + } + #endregion + + #region DefaultDockPaneCaptionFactory + private class DefaultDockPaneCaptionFactory : IDockPaneCaptionFactory + { + public DockPaneCaptionBase CreateDockPaneCaption(DockPane pane) + { + return new VS2005DockPaneCaption(pane); + } + } + #endregion + + #region DefaultDockPaneTabStripFactory + private class DefaultDockPaneStripFactory : IDockPaneStripFactory + { + public DockPaneStripBase CreateDockPaneStrip(DockPane pane) + { + return new VS2005DockPaneStrip(pane); + } + } + #endregion + + #region DefaultAutoHideStripFactory + private class DefaultAutoHideStripFactory : IAutoHideStripFactory + { + public AutoHideStripBase CreateAutoHideStrip(DockPanel panel) + { + return new VS2005AutoHideStrip(panel); + } + } + #endregion + + internal DockPanelExtender(DockPanel dockPanel) + { + m_dockPanel = dockPanel; + } + + private DockPanel m_dockPanel; + private DockPanel DockPanel + { + get { return m_dockPanel; } + } + + private IDockPaneFactory m_dockPaneFactory = null; + public IDockPaneFactory DockPaneFactory + { + get + { + if (m_dockPaneFactory == null) + m_dockPaneFactory = new DefaultDockPaneFactory(); + + return m_dockPaneFactory; + } + set + { + if (DockPanel.Panes.Count > 0) + throw new InvalidOperationException(); + + m_dockPaneFactory = value; + } + } + + private IFloatWindowFactory m_floatWindowFactory = null; + public IFloatWindowFactory FloatWindowFactory + { + get + { + if (m_floatWindowFactory == null) + m_floatWindowFactory = new DefaultFloatWindowFactory(); + + return m_floatWindowFactory; + } + set + { + if (DockPanel.FloatWindows.Count > 0) + throw new InvalidOperationException(); + + m_floatWindowFactory = value; + } + } + + private IDockPaneCaptionFactory m_dockPaneCaptionFactory = null; + public IDockPaneCaptionFactory DockPaneCaptionFactory + { + get + { + if (m_dockPaneCaptionFactory == null) + m_dockPaneCaptionFactory = new DefaultDockPaneCaptionFactory(); + + return m_dockPaneCaptionFactory; + } + set + { + if (DockPanel.Panes.Count > 0) + throw new InvalidOperationException(); + + m_dockPaneCaptionFactory = value; + } + } + + private IDockPaneStripFactory m_dockPaneStripFactory = null; + public IDockPaneStripFactory DockPaneStripFactory + { + get + { + if (m_dockPaneStripFactory == null) + m_dockPaneStripFactory = new DefaultDockPaneStripFactory(); + + return m_dockPaneStripFactory; + } + set + { + if (DockPanel.Contents.Count > 0) + throw new InvalidOperationException(); + + m_dockPaneStripFactory = value; + } + } + + private IAutoHideStripFactory m_autoHideStripFactory = null; + public IAutoHideStripFactory AutoHideStripFactory + { + get + { + if (m_autoHideStripFactory == null) + m_autoHideStripFactory = new DefaultAutoHideStripFactory(); + + return m_autoHideStripFactory; + } + set + { + if (DockPanel.Contents.Count > 0) + throw new InvalidOperationException(); + + if (m_autoHideStripFactory == value) + return; + + m_autoHideStripFactory = value; + DockPanel.ResetAutoHideStripControl(); + } + } + } +} diff --git a/trunk/Docking/DockPanelSkin.cs b/trunk/Docking/DockPanelSkin.cs new file mode 100644 index 0000000..fedd9be --- /dev/null +++ b/trunk/Docking/DockPanelSkin.cs @@ -0,0 +1,421 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Design; +using System.Windows.Forms.Design; +using System.ComponentModel; + +namespace LSLEditor.Docking +{ + #region DockPanelSkin classes + /// + /// The skin to use when displaying the DockPanel. + /// The skin allows custom gradient color schemes to be used when drawing the + /// DockStrips and Tabs. + /// + [TypeConverter(typeof(DockPanelSkinConverter))] + public class DockPanelSkin + { + private AutoHideStripSkin m_autoHideStripSkin; + private DockPaneStripSkin m_dockPaneStripSkin; + + public DockPanelSkin() + { + m_autoHideStripSkin = new AutoHideStripSkin(); + m_dockPaneStripSkin = new DockPaneStripSkin(); + } + + /// + /// The skin used to display the auto hide strips and tabs. + /// + public AutoHideStripSkin AutoHideStripSkin + { + get { return m_autoHideStripSkin; } + set { m_autoHideStripSkin = value; } + } + + /// + /// The skin used to display the Document and ToolWindow style DockStrips and Tabs. + /// + public DockPaneStripSkin DockPaneStripSkin + { + get { return m_dockPaneStripSkin; } + set { m_dockPaneStripSkin = value; } + } + } + + /// + /// The skin used to display the auto hide strip and tabs. + /// + [TypeConverter(typeof(AutoHideStripConverter))] + public class AutoHideStripSkin + { + private DockPanelGradient m_dockStripGradient; + private TabGradient m_TabGradient; + + public AutoHideStripSkin() + { + m_dockStripGradient = new DockPanelGradient(); + m_dockStripGradient.StartColor = SystemColors.ControlLight; + m_dockStripGradient.EndColor = SystemColors.ControlLight; + + m_TabGradient = new TabGradient(); + m_TabGradient.TextColor = SystemColors.ControlDarkDark; + } + + /// + /// The gradient color skin for the DockStrips. + /// + public DockPanelGradient DockStripGradient + { + get { return m_dockStripGradient; } + set { m_dockStripGradient = value; } + } + + /// + /// The gradient color skin for the Tabs. + /// + public TabGradient TabGradient + { + get { return m_TabGradient; } + set { m_TabGradient = value; } + } + } + + /// + /// The skin used to display the document and tool strips and tabs. + /// + [TypeConverter(typeof(DockPaneStripConverter))] + public class DockPaneStripSkin + { + private DockPaneStripGradient m_DocumentGradient; + private DockPaneStripToolWindowGradient m_ToolWindowGradient; + + public DockPaneStripSkin() + { + m_DocumentGradient = new DockPaneStripGradient(); + m_DocumentGradient.DockStripGradient.StartColor = SystemColors.Control; + m_DocumentGradient.DockStripGradient.EndColor = SystemColors.Control; + m_DocumentGradient.ActiveTabGradient.StartColor = SystemColors.ControlLightLight; + m_DocumentGradient.ActiveTabGradient.EndColor = SystemColors.ControlLightLight; + m_DocumentGradient.InactiveTabGradient.StartColor = SystemColors.ControlLight; + m_DocumentGradient.InactiveTabGradient.EndColor = SystemColors.ControlLight; + + m_ToolWindowGradient = new DockPaneStripToolWindowGradient(); + m_ToolWindowGradient.DockStripGradient.StartColor = SystemColors.ControlLight; + m_ToolWindowGradient.DockStripGradient.EndColor = SystemColors.ControlLight; + + m_ToolWindowGradient.ActiveTabGradient.StartColor = SystemColors.Control; + m_ToolWindowGradient.ActiveTabGradient.EndColor = SystemColors.Control; + + m_ToolWindowGradient.InactiveTabGradient.StartColor = Color.Transparent; + m_ToolWindowGradient.InactiveTabGradient.EndColor = Color.Transparent; + m_ToolWindowGradient.InactiveTabGradient.TextColor = SystemColors.ControlDarkDark; + + m_ToolWindowGradient.ActiveCaptionGradient.StartColor = SystemColors.GradientActiveCaption; + m_ToolWindowGradient.ActiveCaptionGradient.EndColor = SystemColors.ActiveCaption; + m_ToolWindowGradient.ActiveCaptionGradient.LinearGradientMode = LinearGradientMode.Vertical; + m_ToolWindowGradient.ActiveCaptionGradient.TextColor = SystemColors.ActiveCaptionText; + + m_ToolWindowGradient.InactiveCaptionGradient.StartColor = SystemColors.GradientInactiveCaption; + m_ToolWindowGradient.InactiveCaptionGradient.EndColor = SystemColors.GradientInactiveCaption; + m_ToolWindowGradient.InactiveCaptionGradient.LinearGradientMode = LinearGradientMode.Vertical; + m_ToolWindowGradient.InactiveCaptionGradient.TextColor = SystemColors.ControlText; + } + + /// + /// The skin used to display the Document style DockPane strip and tab. + /// + public DockPaneStripGradient DocumentGradient + { + get { return m_DocumentGradient; } + set { m_DocumentGradient = value; } + } + + /// + /// The skin used to display the ToolWindow style DockPane strip and tab. + /// + public DockPaneStripToolWindowGradient ToolWindowGradient + { + get { return m_ToolWindowGradient; } + set { m_ToolWindowGradient = value; } + } + } + + /// + /// The skin used to display the DockPane ToolWindow strip and tab. + /// + [TypeConverter(typeof(DockPaneStripGradientConverter))] + public class DockPaneStripToolWindowGradient : DockPaneStripGradient + { + private TabGradient m_activeCaptionGradient; + private TabGradient m_inactiveCaptionGradient; + + public DockPaneStripToolWindowGradient() + { + m_activeCaptionGradient = new TabGradient(); + m_inactiveCaptionGradient = new TabGradient(); + } + + /// + /// The skin used to display the active ToolWindow caption. + /// + public TabGradient ActiveCaptionGradient + { + get { return m_activeCaptionGradient; } + set { m_activeCaptionGradient = value; } + } + + /// + /// The skin used to display the inactive ToolWindow caption. + /// + public TabGradient InactiveCaptionGradient + { + get { return m_inactiveCaptionGradient; } + set { m_inactiveCaptionGradient = value; } + } + } + + /// + /// The skin used to display the DockPane strip and tab. + /// + [TypeConverter(typeof(DockPaneStripGradientConverter))] + public class DockPaneStripGradient + { + private DockPanelGradient m_dockStripGradient; + private TabGradient m_activeTabGradient; + private TabGradient m_inactiveTabGradient; + + public DockPaneStripGradient() + { + m_dockStripGradient = new DockPanelGradient(); + m_activeTabGradient = new TabGradient(); + m_inactiveTabGradient = new TabGradient(); + } + + /// + /// The gradient color skin for the DockStrip. + /// + public DockPanelGradient DockStripGradient + { + get { return m_dockStripGradient; } + set { m_dockStripGradient = value; } + } + + /// + /// The skin used to display the active DockPane tabs. + /// + public TabGradient ActiveTabGradient + { + get { return m_activeTabGradient; } + set { m_activeTabGradient = value; } + } + + /// + /// The skin used to display the inactive DockPane tabs. + /// + public TabGradient InactiveTabGradient + { + get { return m_inactiveTabGradient; } + set { m_inactiveTabGradient = value; } + } + } + + /// + /// The skin used to display the dock pane tab + /// + [TypeConverter(typeof(DockPaneTabGradientConverter))] + public class TabGradient : DockPanelGradient + { + private Color m_textColor; + + public TabGradient() + { + m_textColor = SystemColors.ControlText; + } + + /// + /// The text color. + /// + [DefaultValue(typeof(SystemColors), "ControlText")] + public Color TextColor + { + get { return m_textColor; } + set { m_textColor = value; } + } + } + + /// + /// The gradient color skin. + /// + [TypeConverter(typeof(DockPanelGradientConverter))] + public class DockPanelGradient + { + private Color m_startColor; + private Color m_endColor; + private LinearGradientMode m_linearGradientMode; + + public DockPanelGradient() + { + m_startColor = SystemColors.Control; + m_endColor = SystemColors.Control; + m_linearGradientMode = LinearGradientMode.Horizontal; + } + + /// + /// The beginning gradient color. + /// + [DefaultValue(typeof(SystemColors), "Control")] + public Color StartColor + { + get { return m_startColor; } + set { m_startColor = value; } + } + + /// + /// The ending gradient color. + /// + [DefaultValue(typeof(SystemColors), "Control")] + public Color EndColor + { + get { return m_endColor; } + set { m_endColor = value; } + } + + /// + /// The gradient mode to display the colors. + /// + [DefaultValue(LinearGradientMode.Horizontal)] + public LinearGradientMode LinearGradientMode + { + get { return m_linearGradientMode; } + set { m_linearGradientMode = value; } + } + } + + #endregion + + #region Converters + public class DockPanelSkinConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(DockPanelSkin)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is DockPanelSkin) + { + return "DockPanelSkin"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class DockPanelGradientConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(DockPanelGradient)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is DockPanelGradient) + { + return "DockPanelGradient"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class AutoHideStripConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(AutoHideStripSkin)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is AutoHideStripSkin) + { + return "AutoHideStripSkin"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class DockPaneStripConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(DockPaneStripSkin)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is DockPaneStripSkin) + { + return "DockPaneStripSkin"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class DockPaneStripGradientConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(DockPaneStripGradient)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is DockPaneStripGradient) + { + return "DockPaneStripGradient"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class DockPaneTabGradientConverter : ExpandableObjectConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(TabGradient)) + return true; + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(String) && value is TabGradient) + { + return "DockPaneTabGradient"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + #endregion +} diff --git a/trunk/Docking/DockWindow.SplitterControl.cs b/trunk/Docking/DockWindow.SplitterControl.cs new file mode 100644 index 0000000..756668f --- /dev/null +++ b/trunk/Docking/DockWindow.SplitterControl.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + public partial class DockWindow + { + private class SplitterControl : SplitterBase + { + protected override int SplitterSize + { + get { return Measures.SplitterSize; } + } + + protected override void StartDrag() + { + DockWindow window = Parent as DockWindow; + if (window == null) + return; + + window.DockPanel.BeginDrag(window, window.RectangleToScreen(Bounds)); + } + } + } +} diff --git a/trunk/Docking/DockWindow.cs b/trunk/Docking/DockWindow.cs new file mode 100644 index 0000000..71c6051 --- /dev/null +++ b/trunk/Docking/DockWindow.cs @@ -0,0 +1,243 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.Runtime.InteropServices; +using System.ComponentModel; + +namespace LSLEditor.Docking +{ + [ToolboxItem(false)] + public partial class DockWindow : Panel, INestedPanesContainer, ISplitterDragSource + { + private DockPanel m_dockPanel; + private DockState m_dockState; + private SplitterControl m_splitter; + private NestedPaneCollection m_nestedPanes; + + internal DockWindow(DockPanel dockPanel, DockState dockState) + { + m_nestedPanes = new NestedPaneCollection(this); + m_dockPanel = dockPanel; + m_dockState = dockState; + Visible = false; + + SuspendLayout(); + + if (DockState == DockState.DockLeft || DockState == DockState.DockRight || + DockState == DockState.DockTop || DockState == DockState.DockBottom) + { + m_splitter = new SplitterControl(); + Controls.Add(m_splitter); + } + + if (DockState == DockState.DockLeft) + { + Dock = DockStyle.Left; + m_splitter.Dock = DockStyle.Right; + } + else if (DockState == DockState.DockRight) + { + Dock = DockStyle.Right; + m_splitter.Dock = DockStyle.Left; + } + else if (DockState == DockState.DockTop) + { + Dock = DockStyle.Top; + m_splitter.Dock = DockStyle.Bottom; + } + else if (DockState == DockState.DockBottom) + { + Dock = DockStyle.Bottom; + m_splitter.Dock = DockStyle.Top; + } + else if (DockState == DockState.Document) + { + Dock = DockStyle.Fill; + } + + ResumeLayout(); + } + + public VisibleNestedPaneCollection VisibleNestedPanes + { + get { return NestedPanes.VisibleNestedPanes; } + } + + public NestedPaneCollection NestedPanes + { + get { return m_nestedPanes; } + } + + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + public DockState DockState + { + get { return m_dockState; } + } + + public bool IsFloat + { + get { return DockState == DockState.Float; } + } + + internal DockPane DefaultPane + { + get { return VisibleNestedPanes.Count == 0 ? null : VisibleNestedPanes[0]; } + } + + public virtual Rectangle DisplayingRectangle + { + get + { + Rectangle rect = ClientRectangle; + // if DockWindow is document, exclude the border + if (DockState == DockState.Document) + { + rect.X += 1; + rect.Y += 1; + rect.Width -= 2; + rect.Height -= 2; + } + // exclude the splitter + else if (DockState == DockState.DockLeft) + rect.Width -= Measures.SplitterSize; + else if (DockState == DockState.DockRight) + { + rect.X += Measures.SplitterSize; + rect.Width -= Measures.SplitterSize; + } + else if (DockState == DockState.DockTop) + rect.Height -= Measures.SplitterSize; + else if (DockState == DockState.DockBottom) + { + rect.Y += Measures.SplitterSize; + rect.Height -= Measures.SplitterSize; + } + + return rect; + } + } + + protected override void OnPaint(PaintEventArgs e) + { + // if DockWindow is document, draw the border + if (DockState == DockState.Document) + e.Graphics.DrawRectangle(SystemPens.ControlDark, ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height - 1); + + base.OnPaint(e); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + VisibleNestedPanes.Refresh(); + if (VisibleNestedPanes.Count == 0) + { + if (Visible) + Visible = false; + } + else if (!Visible) + { + Visible = true; + VisibleNestedPanes.Refresh(); + } + + base.OnLayout (levent); + } + + #region ISplitterDragSource Members + + void ISplitterDragSource.BeginDrag(Rectangle rectSplitter) + { + } + + void ISplitterDragSource.EndDrag() + { + } + + bool ISplitterDragSource.IsVertical + { + get { return (DockState == DockState.DockLeft || DockState == DockState.DockRight); } + } + + Rectangle ISplitterDragSource.DragLimitBounds + { + get + { + Rectangle rectLimit = DockPanel.DockArea; + Point location; + if ((Control.ModifierKeys & Keys.Shift) == 0) + location = Location; + else + location = DockPanel.DockArea.Location; + + if (((ISplitterDragSource)this).IsVertical) + { + rectLimit.X += MeasurePane.MinSize; + rectLimit.Width -= 2 * MeasurePane.MinSize; + rectLimit.Y = location.Y; + if ((Control.ModifierKeys & Keys.Shift) == 0) + rectLimit.Height = Height; + } + else + { + rectLimit.Y += MeasurePane.MinSize; + rectLimit.Height -= 2 * MeasurePane.MinSize; + rectLimit.X = location.X; + if ((Control.ModifierKeys & Keys.Shift) == 0) + rectLimit.Width = Width; + } + + return DockPanel.RectangleToScreen(rectLimit); + } + } + + void ISplitterDragSource.MoveSplitter(int offset) + { + if ((Control.ModifierKeys & Keys.Shift) != 0) + SendToBack(); + + Rectangle rectDockArea = DockPanel.DockArea; + if (DockState == DockState.DockLeft && rectDockArea.Width > 0) + { + if (DockPanel.DockLeftPortion > 1) + DockPanel.DockLeftPortion = Width + offset; + else + DockPanel.DockLeftPortion += ((double)offset) / (double)rectDockArea.Width; + } + else if (DockState == DockState.DockRight && rectDockArea.Width > 0) + { + if (DockPanel.DockRightPortion > 1) + DockPanel.DockRightPortion = Width - offset; + else + DockPanel.DockRightPortion -= ((double)offset) / (double)rectDockArea.Width; + } + else if (DockState == DockState.DockBottom && rectDockArea.Height > 0) + { + if (DockPanel.DockBottomPortion > 1) + DockPanel.DockBottomPortion = Height - offset; + else + DockPanel.DockBottomPortion -= ((double)offset) / (double)rectDockArea.Height; + } + else if (DockState == DockState.DockTop && rectDockArea.Height > 0) + { + if (DockPanel.DockTopPortion > 1) + DockPanel.DockTopPortion = Height + offset; + else + DockPanel.DockTopPortion += ((double)offset) / (double)rectDockArea.Height; + } + } + + #region IDragSource Members + + Control IDragSource.DragControl + { + get { return this; } + } + + #endregion + #endregion + } +} diff --git a/trunk/Docking/DockWindowCollection.cs b/trunk/Docking/DockWindowCollection.cs new file mode 100644 index 0000000..ac41974 --- /dev/null +++ b/trunk/Docking/DockWindowCollection.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace LSLEditor.Docking +{ + public class DockWindowCollection : ReadOnlyCollection + { + internal DockWindowCollection(DockPanel dockPanel) + : base(new List()) + { + Items.Add(new DockWindow(dockPanel, DockState.Document)); + Items.Add(new DockWindow(dockPanel, DockState.DockLeft)); + Items.Add(new DockWindow(dockPanel, DockState.DockRight)); + Items.Add(new DockWindow(dockPanel, DockState.DockTop)); + Items.Add(new DockWindow(dockPanel, DockState.DockBottom)); + } + + public DockWindow this [DockState dockState] + { + get + { + if (dockState == DockState.Document) + return Items[0]; + else if (dockState == DockState.DockLeft || dockState == DockState.DockLeftAutoHide) + return Items[1]; + else if (dockState == DockState.DockRight || dockState == DockState.DockRightAutoHide) + return Items[2]; + else if (dockState == DockState.DockTop || dockState == DockState.DockTopAutoHide) + return Items[3]; + else if (dockState == DockState.DockBottom || dockState == DockState.DockBottomAutoHide) + return Items[4]; + + throw (new ArgumentOutOfRangeException()); + } + } + } +} diff --git a/trunk/Docking/DragForm.cs b/trunk/Docking/DragForm.cs new file mode 100644 index 0000000..341ff96 --- /dev/null +++ b/trunk/Docking/DragForm.cs @@ -0,0 +1,64 @@ +using System; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + // Inspired by Chris Sano's article: + // http://msdn.microsoft.com/smartclient/default.aspx?pull=/library/en-us/dnwinforms/html/colorpicker.asp + // In Sano's article, the DragForm needs to meet the following criteria: + // (1) it was not to show up in the task bar; + // ShowInTaskBar = false + // (2) it needed to be the top-most window; + // TopMost = true (not necessary here) + // (3) its icon could not show up in the ALT+TAB window if the user pressed ALT+TAB during a drag-and-drop; + // FormBorderStyle = FormBorderStyle.None; + // Create with WS_EX_TOOLWINDOW window style. + // Compares with the solution in the artile by setting FormBorderStyle as FixedToolWindow, + // and then clip the window caption and border, this way is much simplier. + // (4) it was not to steal focus from the application when displayed. + // User Win32 ShowWindow API with SW_SHOWNOACTIVATE + // In addition, this form should only for display and therefore should act as transparent, otherwise + // WindowFromPoint will return this form, instead of the control beneath. Need BOTH of the following to + // achieve this (don't know why, spent hours to try it out :( ): + // 1. Enabled = false; + // 2. WM_NCHITTEST returns HTTRANSPARENT + internal class DragForm : Form + { + public DragForm() + { + FormBorderStyle = FormBorderStyle.None; + ShowInTaskbar = false; + SetStyle(ControlStyles.Selectable, false); + Enabled = false; + } + + protected override CreateParams CreateParams + { + get + { + CreateParams createParams = base.CreateParams; + createParams.ExStyle |= (int)Win32.WindowExStyles.WS_EX_TOOLWINDOW; + return createParams; + } + } + + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_NCHITTEST) + { + m.Result = (IntPtr)Win32.HitTest.HTTRANSPARENT; + return; + } + + base.WndProc (ref m); + } + + public virtual void Show(bool bActivate) + { + if (bActivate) + Show(); + else + NativeMethods.ShowWindow(Handle, (int)Win32.ShowWindowStyles.SW_SHOWNOACTIVATE); + } + } +} diff --git a/trunk/Docking/DummyControl.cs b/trunk/Docking/DummyControl.cs new file mode 100644 index 0000000..e74d091 --- /dev/null +++ b/trunk/Docking/DummyControl.cs @@ -0,0 +1,13 @@ +using System; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + internal class DummyControl : Control + { + public DummyControl() + { + SetStyle(ControlStyles.Selectable, false); + } + } +} diff --git a/trunk/Docking/Enums.cs b/trunk/Docking/Enums.cs new file mode 100644 index 0000000..4325288 --- /dev/null +++ b/trunk/Docking/Enums.cs @@ -0,0 +1,60 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + [Flags] + [Serializable] + [Editor(typeof(DockAreasEditor), typeof(System.Drawing.Design.UITypeEditor))] + public enum DockAreas + { + Float = 1, + DockLeft = 2, + DockRight = 4, + DockTop = 8, + DockBottom = 16, + Document = 32 + } + + public enum DockState + { + Unknown = 0, + Float = 1, + DockTopAutoHide = 2, + DockLeftAutoHide = 3, + DockBottomAutoHide = 4, + DockRightAutoHide = 5, + Document = 6, + DockTop = 7, + DockLeft = 8, + DockBottom = 9, + DockRight = 10, + Hidden = 11 + } + + public enum DockAlignment + { + Left, + Right, + Top, + Bottom + } + + public enum DocumentStyle + { + DockingMdi, + DockingWindow, + DockingSdi, + SystemMdi, + } + + /// + /// The location to draw the DockPaneStrip for Document style windows. + /// + public enum DocumentTabStripLocation + { + Top, + Bottom + } +} diff --git a/trunk/Docking/FloatWindow.cs b/trunk/Docking/FloatWindow.cs new file mode 100644 index 0000000..98f96e8 --- /dev/null +++ b/trunk/Docking/FloatWindow.cs @@ -0,0 +1,453 @@ +using System; +using System.Collections; +using System.Drawing; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.Security.Permissions; +using System.Diagnostics.CodeAnalysis; + +namespace LSLEditor.Docking +{ + public class FloatWindow : Form, INestedPanesContainer, IDockDragSource + { + private NestedPaneCollection m_nestedPanes; + internal const int WM_CHECKDISPOSE = (int)(Win32.Msgs.WM_USER + 1); + + internal protected FloatWindow(DockPanel dockPanel, DockPane pane) + { + InternalConstruct(dockPanel, pane, false, Rectangle.Empty); + } + + internal protected FloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds) + { + InternalConstruct(dockPanel, pane, true, bounds); + } + + private void InternalConstruct(DockPanel dockPanel, DockPane pane, bool boundsSpecified, Rectangle bounds) + { + if (dockPanel == null) + throw(new ArgumentNullException(Strings.FloatWindow_Constructor_NullDockPanel)); + + m_nestedPanes = new NestedPaneCollection(this); + + FormBorderStyle = FormBorderStyle.SizableToolWindow; + ShowInTaskbar = false; + if (dockPanel.RightToLeft != RightToLeft) + RightToLeft = dockPanel.RightToLeft; + if (RightToLeftLayout != dockPanel.RightToLeftLayout) + RightToLeftLayout = dockPanel.RightToLeftLayout; + + SuspendLayout(); + if (boundsSpecified) + { + Bounds = bounds; + StartPosition = FormStartPosition.Manual; + } + else + { + StartPosition = FormStartPosition.WindowsDefaultLocation; + Size = dockPanel.DefaultFloatWindowSize; + } + + m_dockPanel = dockPanel; + Owner = DockPanel.FindForm(); + DockPanel.AddFloatWindow(this); + if (pane != null) + pane.FloatWindow = this; + + ResumeLayout(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (DockPanel != null) + DockPanel.RemoveFloatWindow(this); + m_dockPanel = null; + } + base.Dispose(disposing); + } + + private bool m_allowEndUserDocking = true; + public bool AllowEndUserDocking + { + get { return m_allowEndUserDocking; } + set { m_allowEndUserDocking = value; } + } + + public NestedPaneCollection NestedPanes + { + get { return m_nestedPanes; } + } + + public VisibleNestedPaneCollection VisibleNestedPanes + { + get { return NestedPanes.VisibleNestedPanes; } + } + + private DockPanel m_dockPanel; + public DockPanel DockPanel + { + get { return m_dockPanel; } + } + + public DockState DockState + { + get { return DockState.Float; } + } + + public bool IsFloat + { + get { return DockState == DockState.Float; } + } + + internal bool IsDockStateValid(DockState dockState) + { + foreach (DockPane pane in NestedPanes) + foreach (IDockContent content in pane.Contents) + if (!DockHelper.IsDockStateValid(dockState, content.DockHandler.DockAreas)) + return false; + + return true; + } + + protected override void OnActivated(EventArgs e) + { + DockPanel.FloatWindows.BringWindowToFront(this); + base.OnActivated (e); + // Propagate the Activated event to the visible panes content objects + foreach (DockPane pane in VisibleNestedPanes) + foreach (IDockContent content in pane.Contents) + content.OnActivated(e); + } + + protected override void OnDeactivate(EventArgs e) + { + base.OnDeactivate(e); + // Propagate the Deactivate event to the visible panes content objects + foreach (DockPane pane in VisibleNestedPanes) + foreach (IDockContent content in pane.Contents) + content.OnDeactivate(e); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + VisibleNestedPanes.Refresh(); + RefreshChanges(); + Visible = (VisibleNestedPanes.Count > 0); + SetText(); + + base.OnLayout(levent); + } + + + [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.Windows.Forms.Control.set_Text(System.String)")] + internal void SetText() + { + DockPane theOnlyPane = (VisibleNestedPanes.Count == 1) ? VisibleNestedPanes[0] : null; + + if (theOnlyPane == null) + Text = " "; // use " " instead of string.Empty because the whole title bar will disappear when ControlBox is set to false. + else if (theOnlyPane.ActiveContent == null) + Text = " "; + else + Text = theOnlyPane.ActiveContent.DockHandler.TabText; + } + + protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) + { + Rectangle rectWorkArea = SystemInformation.VirtualScreen; + + if (y + height > rectWorkArea.Bottom) + y -= (y + height) - rectWorkArea.Bottom; + + if (y < rectWorkArea.Top) + y += rectWorkArea.Top - y; + + base.SetBoundsCore (x, y, width, height, specified); + } + + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)Win32.Msgs.WM_NCLBUTTONDOWN) + { + if (IsDisposed) + return; + + uint result = NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam); + if (result == 2 && DockPanel.AllowEndUserDocking && this.AllowEndUserDocking) // HITTEST_CAPTION + { + Activate(); + m_dockPanel.BeginDrag(this); + } + else + base.WndProc(ref m); + + return; + } + else if (m.Msg == (int)Win32.Msgs.WM_NCRBUTTONDOWN) + { + uint result = NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam); + if (result == 2) // HITTEST_CAPTION + { + DockPane theOnlyPane = (VisibleNestedPanes.Count == 1) ? VisibleNestedPanes[0] : null; + if (theOnlyPane != null && theOnlyPane.ActiveContent != null) + { + theOnlyPane.ShowTabPageContextMenu(this, PointToClient(Control.MousePosition)); + return; + } + } + + base.WndProc(ref m); + return; + } + else if (m.Msg == (int)Win32.Msgs.WM_CLOSE) + { + if (NestedPanes.Count == 0) + { + base.WndProc(ref m); + return; + } + + for (int i = NestedPanes.Count - 1; i >= 0; i--) + { + DockContentCollection contents = NestedPanes[i].Contents; + for (int j = contents.Count - 1; j >= 0; j--) + { + IDockContent content = contents[j]; + if (content.DockHandler.DockState != DockState.Float) + continue; + + if (!content.DockHandler.CloseButton) + continue; + + if (content.DockHandler.HideOnClose) + content.DockHandler.Hide(); + else + content.DockHandler.Close(); + } + } + + return; + } + else if (m.Msg == (int)Win32.Msgs.WM_NCLBUTTONDBLCLK) + { + uint result = NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam); + if (result != 2) // HITTEST_CAPTION + { + base.WndProc(ref m); + return; + } + + DockPanel.SuspendLayout(true); + + // Restore to panel + foreach (DockPane pane in NestedPanes) + { + if (pane.DockState != DockState.Float) + continue; + pane.RestoreToPanel(); + } + + + DockPanel.ResumeLayout(true, true); + return; + } + else if (m.Msg == WM_CHECKDISPOSE) + { + if (NestedPanes.Count == 0) + Dispose(); + + return; + } + + base.WndProc(ref m); + } + + internal void RefreshChanges() + { + if (IsDisposed) + return; + + if (VisibleNestedPanes.Count == 0) + { + ControlBox = true; + return; + } + + for (int i=VisibleNestedPanes.Count - 1; i>=0; i--) + { + DockContentCollection contents = VisibleNestedPanes[i].Contents; + for (int j=contents.Count - 1; j>=0; j--) + { + IDockContent content = contents[j]; + if (content.DockHandler.DockState != DockState.Float) + continue; + + if (content.DockHandler.CloseButton && content.DockHandler.CloseButtonVisible) + { + ControlBox = true; + return; + } + } + } + //Only if there is a ControlBox do we turn it off + //old code caused a flash of the window. + if (ControlBox) + ControlBox = false; + } + + public virtual Rectangle DisplayingRectangle + { + get { return ClientRectangle; } + } + + internal void TestDrop(IDockDragSource dragSource, DockOutlineBase dockOutline) + { + if (VisibleNestedPanes.Count == 1) + { + DockPane pane = VisibleNestedPanes[0]; + if (!dragSource.CanDockTo(pane)) + return; + + Point ptMouse = Control.MousePosition; + uint lParam = Win32Helper.MakeLong(ptMouse.X, ptMouse.Y); + if (NativeMethods.SendMessage(Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, lParam) == (uint)Win32.HitTest.HTCAPTION) + dockOutline.Show(VisibleNestedPanes[0], -1); + } + } + + #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.FloatWindow == this) + return false; + + return true; + } + + Rectangle IDockDragSource.BeginDrag(Point ptMouse) + { + return Bounds; + } + + public void FloatAt(Rectangle floatWindowBounds) + { + Bounds = floatWindowBounds; + } + + public void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex) + { + if (dockStyle == DockStyle.Fill) + { + for (int i = NestedPanes.Count - 1; i >= 0; i--) + { + DockPane paneFrom = NestedPanes[i]; + for (int j = paneFrom.Contents.Count - 1; j >= 0; j--) + { + IDockContent c = paneFrom.Contents[j]; + c.DockHandler.Pane = pane; + if (contentIndex != -1) + pane.SetContentIndex(c, contentIndex); + c.DockHandler.Activate(); + } + } + } + else + { + DockAlignment alignment = DockAlignment.Left; + if (dockStyle == DockStyle.Left) + alignment = DockAlignment.Left; + else if (dockStyle == DockStyle.Right) + alignment = DockAlignment.Right; + else if (dockStyle == DockStyle.Top) + alignment = DockAlignment.Top; + else if (dockStyle == DockStyle.Bottom) + alignment = DockAlignment.Bottom; + + MergeNestedPanes(VisibleNestedPanes, pane.NestedPanesContainer.NestedPanes, pane, alignment, 0.5); + } + } + + public void DockTo(DockPanel panel, DockStyle dockStyle) + { + if (panel != DockPanel) + throw new ArgumentException(Strings.IDockDragSource_DockTo_InvalidPanel, "panel"); + + NestedPaneCollection nestedPanesTo = null; + + if (dockStyle == DockStyle.Top) + nestedPanesTo = DockPanel.DockWindows[DockState.DockTop].NestedPanes; + else if (dockStyle == DockStyle.Bottom) + nestedPanesTo = DockPanel.DockWindows[DockState.DockBottom].NestedPanes; + else if (dockStyle == DockStyle.Left) + nestedPanesTo = DockPanel.DockWindows[DockState.DockLeft].NestedPanes; + else if (dockStyle == DockStyle.Right) + nestedPanesTo = DockPanel.DockWindows[DockState.DockRight].NestedPanes; + else if (dockStyle == DockStyle.Fill) + nestedPanesTo = DockPanel.DockWindows[DockState.Document].NestedPanes; + + DockPane prevPane = null; + for (int i = nestedPanesTo.Count - 1; i >= 0; i--) + if (nestedPanesTo[i] != VisibleNestedPanes[0]) + prevPane = nestedPanesTo[i]; + MergeNestedPanes(VisibleNestedPanes, nestedPanesTo, prevPane, DockAlignment.Left, 0.5); + } + + private static void MergeNestedPanes(VisibleNestedPaneCollection nestedPanesFrom, NestedPaneCollection nestedPanesTo, DockPane prevPane, DockAlignment alignment, double proportion) + { + if (nestedPanesFrom.Count == 0) + return; + + int count = nestedPanesFrom.Count; + DockPane[] panes = new DockPane[count]; + DockPane[] prevPanes = new DockPane[count]; + DockAlignment[] alignments = new DockAlignment[count]; + double[] proportions = new double[count]; + + for (int i = 0; i < count; i++) + { + panes[i] = nestedPanesFrom[i]; + prevPanes[i] = nestedPanesFrom[i].NestedDockingStatus.PreviousPane; + alignments[i] = nestedPanesFrom[i].NestedDockingStatus.Alignment; + proportions[i] = nestedPanesFrom[i].NestedDockingStatus.Proportion; + } + + DockPane pane = panes[0].DockTo(nestedPanesTo.Container, prevPane, alignment, proportion); + panes[0].DockState = nestedPanesTo.DockState; + + for (int i = 1; i < count; i++) + { + for (int j = i; j < count; j++) + { + if (prevPanes[j] == panes[i - 1]) + prevPanes[j] = pane; + } + pane = panes[i].DockTo(nestedPanesTo.Container, prevPanes[i], alignments[i], proportions[i]); + panes[i].DockState = nestedPanesTo.DockState; + } + } + + #endregion + } +} diff --git a/trunk/Docking/FloatWindowCollection.cs b/trunk/Docking/FloatWindowCollection.cs new file mode 100644 index 0000000..9dc4f7c --- /dev/null +++ b/trunk/Docking/FloatWindowCollection.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Drawing; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + public class FloatWindowCollection : ReadOnlyCollection + { + internal FloatWindowCollection() + : base(new List()) + { + } + + internal int Add(FloatWindow fw) + { + if (Items.Contains(fw)) + return Items.IndexOf(fw); + + Items.Add(fw); + return Count - 1; + } + + internal void Dispose() + { + for (int i=Count - 1; i>=0; i--) + this[i].Close(); + } + + internal void Remove(FloatWindow fw) + { + Items.Remove(fw); + } + + internal void BringWindowToFront(FloatWindow fw) + { + Items.Remove(fw); + Items.Add(fw); + } + } +} diff --git a/trunk/Docking/Helpers/DockHelper.cs b/trunk/Docking/Helpers/DockHelper.cs new file mode 100644 index 0000000..ecbae43 --- /dev/null +++ b/trunk/Docking/Helpers/DockHelper.cs @@ -0,0 +1,103 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + internal static class DockHelper + { + public static bool IsDockStateAutoHide(DockState dockState) + { + if (dockState == DockState.DockLeftAutoHide || + dockState == DockState.DockRightAutoHide || + dockState == DockState.DockTopAutoHide || + dockState == DockState.DockBottomAutoHide) + return true; + else + return false; + } + + public static bool IsDockStateValid(DockState dockState, DockAreas dockableAreas) + { + if (((dockableAreas & DockAreas.Float) == 0) && + (dockState == DockState.Float)) + return false; + else if (((dockableAreas & DockAreas.Document) == 0) && + (dockState == DockState.Document)) + return false; + else if (((dockableAreas & DockAreas.DockLeft) == 0) && + (dockState == DockState.DockLeft || dockState == DockState.DockLeftAutoHide)) + return false; + else if (((dockableAreas & DockAreas.DockRight) == 0) && + (dockState == DockState.DockRight || dockState == DockState.DockRightAutoHide)) + return false; + else if (((dockableAreas & DockAreas.DockTop) == 0) && + (dockState == DockState.DockTop || dockState == DockState.DockTopAutoHide)) + return false; + else if (((dockableAreas & DockAreas.DockBottom) == 0) && + (dockState == DockState.DockBottom || dockState == DockState.DockBottomAutoHide)) + return false; + else + return true; + } + + public static bool IsDockWindowState(DockState state) + { + if (state == DockState.DockTop || state == DockState.DockBottom || state == DockState.DockLeft || + state == DockState.DockRight || state == DockState.Document) + return true; + else + return false; + } + + public static DockState ToggleAutoHideState(DockState state) + { + if (state == DockState.DockLeft) + return DockState.DockLeftAutoHide; + else if (state == DockState.DockRight) + return DockState.DockRightAutoHide; + else if (state == DockState.DockTop) + return DockState.DockTopAutoHide; + else if (state == DockState.DockBottom) + return DockState.DockBottomAutoHide; + else if (state == DockState.DockLeftAutoHide) + return DockState.DockLeft; + else if (state == DockState.DockRightAutoHide) + return DockState.DockRight; + else if (state == DockState.DockTopAutoHide) + return DockState.DockTop; + else if (state == DockState.DockBottomAutoHide) + return DockState.DockBottom; + else + return state; + } + + public static DockPane PaneAtPoint(Point pt, DockPanel dockPanel) + { + for (Control control = Win32Helper.ControlAtPoint(pt); control != null; control = control.Parent) + { + IDockContent content = control as IDockContent; + if (content != null && content.DockHandler.DockPanel == dockPanel) + return content.DockHandler.Pane; + + DockPane pane = control as DockPane; + if (pane != null && pane.DockPanel == dockPanel) + return pane; + } + + return null; + } + + public static FloatWindow FloatWindowAtPoint(Point pt, DockPanel dockPanel) + { + for (Control control = Win32Helper.ControlAtPoint(pt); control != null; control = control.Parent) + { + FloatWindow floatWindow = control as FloatWindow; + if (floatWindow != null && floatWindow.DockPanel == dockPanel) + return floatWindow; + } + + return null; + } + } +} diff --git a/trunk/Docking/Helpers/DrawHelper.cs b/trunk/Docking/Helpers/DrawHelper.cs new file mode 100644 index 0000000..b9759fa --- /dev/null +++ b/trunk/Docking/Helpers/DrawHelper.cs @@ -0,0 +1,88 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + internal static class DrawHelper + { + public static Point RtlTransform(Control control, Point point) + { + if (control.RightToLeft != RightToLeft.Yes) + return point; + else + return new Point(control.Right - point.X, point.Y); + } + + public static Rectangle RtlTransform(Control control, Rectangle rectangle) + { + if (control.RightToLeft != RightToLeft.Yes) + return rectangle; + else + return new Rectangle(control.ClientRectangle.Right - rectangle.Right, rectangle.Y, rectangle.Width, rectangle.Height); + } + + public static GraphicsPath GetRoundedCornerTab(GraphicsPath graphicsPath, Rectangle rect, bool upCorner) + { + if (graphicsPath == null) + graphicsPath = new GraphicsPath(); + else + graphicsPath.Reset(); + + int curveSize = 6; + if (upCorner) + { + graphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left, rect.Top + curveSize / 2); + graphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90); + graphicsPath.AddLine(rect.Left + curveSize / 2, rect.Top, rect.Right - curveSize / 2, rect.Top); + graphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Top, curveSize, curveSize), -90, 90); + graphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Bottom); + } + else + { + graphicsPath.AddLine(rect.Right, rect.Top, rect.Right, rect.Bottom - curveSize / 2); + graphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Bottom - curveSize, curveSize, curveSize), 0, 90); + graphicsPath.AddLine(rect.Right - curveSize / 2, rect.Bottom, rect.Left + curveSize / 2, rect.Bottom); + graphicsPath.AddArc(new Rectangle(rect.Left, rect.Bottom - curveSize, curveSize, curveSize), 90, 90); + graphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Top); + } + + return graphicsPath; + } + + public static GraphicsPath CalculateGraphicsPathFromBitmap(Bitmap bitmap) + { + return CalculateGraphicsPathFromBitmap(bitmap, Color.Empty); + } + + // From http://edu.cnzz.cn/show_3281.html + public static GraphicsPath CalculateGraphicsPathFromBitmap(Bitmap bitmap, Color colorTransparent) + { + GraphicsPath graphicsPath = new GraphicsPath(); + if (colorTransparent == Color.Empty) + colorTransparent = bitmap.GetPixel(0, 0); + + for(int row = 0; row < bitmap.Height; row ++) + { + int colOpaquePixel = 0; + for(int col = 0; col < bitmap.Width; col ++) + { + if(bitmap.GetPixel(col, row) != colorTransparent) + { + colOpaquePixel = col; + int colNext = col; + for(colNext = colOpaquePixel; colNext < bitmap.Width; colNext ++) + if(bitmap.GetPixel(colNext, row) == colorTransparent) + break; + + graphicsPath.AddRectangle(new Rectangle(colOpaquePixel, row, colNext - colOpaquePixel, 1)); + col = colNext; + } + } + } + return graphicsPath; + } + } +} diff --git a/trunk/Docking/Helpers/ResourceHelper.cs b/trunk/Docking/Helpers/ResourceHelper.cs new file mode 100644 index 0000000..24e8fef --- /dev/null +++ b/trunk/Docking/Helpers/ResourceHelper.cs @@ -0,0 +1,29 @@ +using System; +using System.Drawing; +using System.Reflection; +using System.Resources; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + internal static class ResourceHelper + { + private static ResourceManager _resourceManager = null; + + private static ResourceManager ResourceManager + { + get + { + if (_resourceManager == null) + _resourceManager = new ResourceManager("LSLEditor.Docking.Strings", typeof(ResourceHelper).Assembly); + return _resourceManager; + } + + } + + public static string GetString(string name) + { + return ResourceManager.GetString(name); + } + } +} diff --git a/trunk/Docking/Helpers/Win32Helper.cs b/trunk/Docking/Helpers/Win32Helper.cs new file mode 100644 index 0000000..5d26655 --- /dev/null +++ b/trunk/Docking/Helpers/Win32Helper.cs @@ -0,0 +1,19 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + internal static class Win32Helper + { + public static Control ControlAtPoint(Point pt) + { + return Control.FromChildHandle(NativeMethods.WindowFromPoint(pt)); + } + + public static uint MakeLong(int low, int high) + { + return (uint)((high << 16) + low); + } + } +} diff --git a/trunk/Docking/InertButtonBase.cs b/trunk/Docking/InertButtonBase.cs new file mode 100644 index 0000000..c0859b7 --- /dev/null +++ b/trunk/Docking/InertButtonBase.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Imaging; + +namespace LSLEditor.Docking +{ + internal abstract class InertButtonBase : Control + { + protected InertButtonBase() + { + SetStyle(ControlStyles.SupportsTransparentBackColor, true); + BackColor = Color.Transparent; + } + + public abstract Bitmap Image + { + get; + } + + private bool m_isMouseOver = false; + protected bool IsMouseOver + { + get { return m_isMouseOver; } + private set + { + if (m_isMouseOver == value) + return; + + m_isMouseOver = value; + Invalidate(); + } + } + + protected override Size DefaultSize + { + get { return Resources.DockPane_Close.Size; } + } + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + bool over = ClientRectangle.Contains(e.X, e.Y); + if (IsMouseOver != over) + IsMouseOver = over; + } + + protected override void OnMouseEnter(EventArgs e) + { + base.OnMouseEnter(e); + if (!IsMouseOver) + IsMouseOver = true; + } + + protected override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + if (IsMouseOver) + IsMouseOver = false; + } + + protected override void OnPaint(PaintEventArgs e) + { + if (IsMouseOver && Enabled) + { + using (Pen pen = new Pen(ForeColor)) + { + e.Graphics.DrawRectangle(pen, Rectangle.Inflate(ClientRectangle, -1, -1)); + } + } + + using (ImageAttributes imageAttributes = new ImageAttributes()) + { + ColorMap[] colorMap = new ColorMap[2]; + colorMap[0] = new ColorMap(); + colorMap[0].OldColor = Color.FromArgb(0, 0, 0); + colorMap[0].NewColor = ForeColor; + colorMap[1] = new ColorMap(); + colorMap[1].OldColor = Image.GetPixel(0, 0); + colorMap[1].NewColor = Color.Transparent; + + imageAttributes.SetRemapTable(colorMap); + + e.Graphics.DrawImage( + Image, + new Rectangle(0, 0, Image.Width, Image.Height), + 0, 0, + Image.Width, + Image.Height, + GraphicsUnit.Pixel, + imageAttributes); + } + + base.OnPaint(e); + } + + public void RefreshChanges() + { + if (IsDisposed) + return; + + bool mouseOver = ClientRectangle.Contains(PointToClient(Control.MousePosition)); + if (mouseOver != IsMouseOver) + IsMouseOver = mouseOver; + + OnRefreshChanges(); + } + + protected virtual void OnRefreshChanges() + { + } + } +} diff --git a/trunk/Docking/Interfaces.cs b/trunk/Docking/Interfaces.cs new file mode 100644 index 0000000..96f02a9 --- /dev/null +++ b/trunk/Docking/Interfaces.cs @@ -0,0 +1,46 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace LSLEditor.Docking +{ + public interface IDockContent + { + DockContentHandler DockHandler { get; } + void OnActivated(EventArgs e); + void OnDeactivate(EventArgs e); + } + + public interface INestedPanesContainer + { + DockState DockState { get; } + Rectangle DisplayingRectangle { get; } + NestedPaneCollection NestedPanes { get; } + VisibleNestedPaneCollection VisibleNestedPanes { get; } + bool IsFloat { get; } + } + + internal interface IDragSource + { + Control DragControl { get; } + } + + internal interface IDockDragSource : IDragSource + { + Rectangle BeginDrag(Point ptMouse); + bool IsDockStateValid(DockState dockState); + bool CanDockTo(DockPane pane); + void FloatAt(Rectangle floatWindowBounds); + void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex); + void DockTo(DockPanel panel, DockStyle dockStyle); + } + + internal interface ISplitterDragSource : IDragSource + { + void BeginDrag(Rectangle rectSplitter); + void EndDrag(); + bool IsVertical { get; } + Rectangle DragLimitBounds { get; } + void MoveSplitter(int offset); + } +} diff --git a/trunk/Docking/Localization.cs b/trunk/Docking/Localization.cs new file mode 100644 index 0000000..03307dd --- /dev/null +++ b/trunk/Docking/Localization.cs @@ -0,0 +1,46 @@ +using System; +using System.ComponentModel; + +namespace LSLEditor.Docking +{ + [AttributeUsage(AttributeTargets.All)] + internal sealed class LocalizedDescriptionAttribute : DescriptionAttribute + { + private bool m_initialized = false; + + public LocalizedDescriptionAttribute(string key) : base(key) + { + } + + public override string Description + { + get + { + if (!m_initialized) + { + string key = base.Description; + DescriptionValue = ResourceHelper.GetString(key); + if (DescriptionValue == null) + DescriptionValue = String.Empty; + + m_initialized = true; + } + + return DescriptionValue; + } + } + } + + [AttributeUsage(AttributeTargets.All)] + internal sealed class LocalizedCategoryAttribute : CategoryAttribute + { + public LocalizedCategoryAttribute(string key) : base(key) + { + } + + protected override string GetLocalizedString(string key) + { + return ResourceHelper.GetString(key); + } + } +} diff --git a/trunk/Docking/Measures.cs b/trunk/Docking/Measures.cs new file mode 100644 index 0000000..cdc4c20 --- /dev/null +++ b/trunk/Docking/Measures.cs @@ -0,0 +1,14 @@ +using System; + +namespace LSLEditor.Docking +{ + internal static class Measures + { + public const int SplitterSize = 4; + } + + internal static class MeasurePane + { + public const int MinSize = 24; + } +} diff --git a/trunk/Docking/NestedDockingStatus.cs b/trunk/Docking/NestedDockingStatus.cs new file mode 100644 index 0000000..aa37220 --- /dev/null +++ b/trunk/Docking/NestedDockingStatus.cs @@ -0,0 +1,108 @@ +using System; +using System.Drawing; + +namespace LSLEditor.Docking +{ + public sealed class NestedDockingStatus + { + internal NestedDockingStatus(DockPane pane) + { + m_dockPane = pane; + } + + private DockPane m_dockPane = null; + public DockPane DockPane + { + get { return m_dockPane; } + } + + private NestedPaneCollection m_nestedPanes = null; + public NestedPaneCollection NestedPanes + { + get { return m_nestedPanes; } + } + + private DockPane m_previousPane = null; + public DockPane PreviousPane + { + get { return m_previousPane; } + } + + private DockAlignment m_alignment = DockAlignment.Left; + public DockAlignment Alignment + { + get { return m_alignment; } + } + + private double m_proportion = 0.5; + public double Proportion + { + get { return m_proportion; } + } + + private bool m_isDisplaying = false; + public bool IsDisplaying + { + get { return m_isDisplaying; } + } + + private DockPane m_displayingPreviousPane = null; + public DockPane DisplayingPreviousPane + { + get { return m_displayingPreviousPane; } + } + + private DockAlignment m_displayingAlignment = DockAlignment.Left; + public DockAlignment DisplayingAlignment + { + get { return m_displayingAlignment; } + } + + private double m_displayingProportion = 0.5; + public double DisplayingProportion + { + get { return m_displayingProportion; } + } + + private Rectangle m_logicalBounds = Rectangle.Empty; + public Rectangle LogicalBounds + { + get { return m_logicalBounds; } + } + + private Rectangle m_paneBounds = Rectangle.Empty; + public Rectangle PaneBounds + { + get { return m_paneBounds; } + } + + private Rectangle m_splitterBounds = Rectangle.Empty; + public Rectangle SplitterBounds + { + get { return m_splitterBounds; } + } + + internal void SetStatus(NestedPaneCollection nestedPanes, DockPane previousPane, DockAlignment alignment, double proportion) + { + m_nestedPanes = nestedPanes; + m_previousPane = previousPane; + m_alignment = alignment; + m_proportion = proportion; + } + + internal void SetDisplayingStatus(bool isDisplaying, DockPane displayingPreviousPane, DockAlignment displayingAlignment, double displayingProportion) + { + m_isDisplaying = isDisplaying; + m_displayingPreviousPane = displayingPreviousPane; + m_displayingAlignment = displayingAlignment; + m_displayingProportion = displayingProportion; + } + + internal void SetDisplayingBounds(Rectangle logicalBounds, Rectangle paneBounds, Rectangle splitterBounds) + { + m_logicalBounds = logicalBounds; + m_paneBounds = paneBounds; + m_splitterBounds = splitterBounds; + } + } +} diff --git a/trunk/Docking/NestedPaneCollection.cs b/trunk/Docking/NestedPaneCollection.cs new file mode 100644 index 0000000..d1b19ca --- /dev/null +++ b/trunk/Docking/NestedPaneCollection.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Drawing; + +namespace LSLEditor.Docking +{ + public sealed class NestedPaneCollection : ReadOnlyCollection + { + private INestedPanesContainer m_container; + private VisibleNestedPaneCollection m_visibleNestedPanes; + + internal NestedPaneCollection(INestedPanesContainer container) + : base(new List()) + { + m_container = container; + m_visibleNestedPanes = new VisibleNestedPaneCollection(this); + } + + public INestedPanesContainer Container + { + get { return m_container; } + } + + public VisibleNestedPaneCollection VisibleNestedPanes + { + get { return m_visibleNestedPanes; } + } + + public DockState DockState + { + get { return Container.DockState; } + } + + public bool IsFloat + { + get { return DockState == DockState.Float; } + } + + internal void Add(DockPane pane) + { + if (pane == null) + return; + + NestedPaneCollection oldNestedPanes = (pane.NestedPanesContainer == null) ? null : pane.NestedPanesContainer.NestedPanes; + if (oldNestedPanes != null) + oldNestedPanes.InternalRemove(pane); + Items.Add(pane); + if (oldNestedPanes != null) + oldNestedPanes.CheckFloatWindowDispose(); + } + + private void CheckFloatWindowDispose() + { + if (Count == 0 && Container.DockState == DockState.Float) + { + FloatWindow floatWindow = (FloatWindow)Container; + if (!floatWindow.Disposing && !floatWindow.IsDisposed) + NativeMethods.PostMessage(((FloatWindow)Container).Handle, FloatWindow.WM_CHECKDISPOSE, 0, 0); + } + } + + internal void Remove(DockPane pane) + { + InternalRemove(pane); + CheckFloatWindowDispose(); + } + + private void InternalRemove(DockPane pane) + { + if (!Contains(pane)) + return; + + NestedDockingStatus statusPane = pane.NestedDockingStatus; + DockPane lastNestedPane = null; + for (int i=Count - 1; i> IndexOf(pane); i--) + { + if (this[i].NestedDockingStatus.PreviousPane == pane) + { + lastNestedPane = this[i]; + break; + } + } + + if (lastNestedPane != null) + { + int indexLastNestedPane = IndexOf(lastNestedPane); + Items.Remove(lastNestedPane); + Items[IndexOf(pane)] = lastNestedPane; + NestedDockingStatus lastNestedDock = lastNestedPane.NestedDockingStatus; + lastNestedDock.SetStatus(this, statusPane.PreviousPane, statusPane.Alignment, statusPane.Proportion); + for (int i=indexLastNestedPane - 1; i>IndexOf(lastNestedPane); i--) + { + NestedDockingStatus status = this[i].NestedDockingStatus; + if (status.PreviousPane == pane) + status.SetStatus(this, lastNestedPane, status.Alignment, status.Proportion); + } + } + else + Items.Remove(pane); + + statusPane.SetStatus(null, null, DockAlignment.Left, 0.5); + statusPane.SetDisplayingStatus(false, null, DockAlignment.Left, 0.5); + statusPane.SetDisplayingBounds(Rectangle.Empty, Rectangle.Empty, Rectangle.Empty); + } + + public DockPane GetDefaultPreviousPane(DockPane pane) + { + for (int i=Count-1; i>=0; i--) + if (this[i] != pane) + return this[i]; + + return null; + } + } +} diff --git a/trunk/Docking/Resources.Designer.cs b/trunk/Docking/Resources.Designer.cs new file mode 100644 index 0000000..90cc35c --- /dev/null +++ b/trunk/Docking/Resources.Designer.cs @@ -0,0 +1,225 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3603 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace LSLEditor.Docking +{ + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LSLEditor.Docking.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Bottom { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Bottom", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Fill { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Fill", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_HotSpot { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_HotSpot", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_HotSpotIndex { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_HotSpotIndex", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Left { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Left", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Right { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Right", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Top { + get { + object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Top", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelBottom { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelBottom", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelBottom_Active { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelBottom_Active", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelFill { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelFill", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelFill_Active { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelFill_Active", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelLeft { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelLeft", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelLeft_Active { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelLeft_Active", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelRight { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelRight", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelRight_Active { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelRight_Active", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelTop { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelTop", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockIndicator_PanelTop_Active { + get { + object obj = ResourceManager.GetObject("DockIndicator_PanelTop_Active", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockPane_AutoHide { + get { + object obj = ResourceManager.GetObject("DockPane_AutoHide", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockPane_Close { + get { + object obj = ResourceManager.GetObject("DockPane_Close", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockPane_Dock { + get { + object obj = ResourceManager.GetObject("DockPane_Dock", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockPane_Option { + get { + object obj = ResourceManager.GetObject("DockPane_Option", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap DockPane_OptionOverflow { + get { + object obj = ResourceManager.GetObject("DockPane_OptionOverflow", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/trunk/Docking/Resources.resx b/trunk/Docking/Resources.resx new file mode 100644 index 0000000..bd5a077 --- /dev/null +++ b/trunk/Docking/Resources.resx @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Resources\DockIndicator_PaneDiamond.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_Bottom.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_Fill.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_HotSpot.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_HotSpotIndex.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_Left.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_Right.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PaneDiamond_Top.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelBottom.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelBottom_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelFill.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelFill_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelLeft.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelLeft_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelRight.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelRight_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelTop.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockIndicator_PanelTop_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockPane_AutoHide.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockPane_Close.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockPane_Dock.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockPane_Option.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\DockPane_OptionOverflow.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/trunk/Docking/Resources/DockIndicator_PaneDiamond.bmp b/trunk/Docking/Resources/DockIndicator_PaneDiamond.bmp new file mode 100644 index 0000000000000000000000000000000000000000..70e70e288d70741ca264944ab528dd070fae23f0 GIT binary patch literal 23286 zcmeI4ZEqFF6@baV=ugNm$d^`0Nfjg_I}T|YP?DxikV6WDmJl$QhCmZAZAhXB0Zj@8 zfk?rhT9ts>VCf>TWyh}X#m1O7`QmF+5NX0ol;lGq(P!rD9uNC+*}HeI#9e1K9?dFG_ z*Ec*oeD2)2%a<=tXK|pjp*A-{xy#|wrAyE_llD-O&CX$LY^+cyP>Xa2c|k#gB6}ll zSwnSVv-XRRe!5`y+^13pRMC|3!C`XXNJQwrTNwChvp_HZ9H?oy?srRa#$jskSj7fS z@RRh^kcqvte~rEJs5v`$EN2|1hd;ey!tpD`Pp1jPCLl3!(FE@TO>m{XAZHw|juftr zoG|eyiNZDW(+2x<=BzK53$Bfv$Qg(0XZx;?_j=)M?{zmI=d5=D347KEjXY-@zPK>> z#YI0j>Hl3AG(k?OoP?jw8HXF?k_i(<6C_9=U|?iqghjbX4&f?CN^-z~#xOoUUM`paQgtMZ ztiB3!zySyo6BCt6g}P|HYE3jX2WEf@fpx{KI5gK1WdMS3xVE?R>Yk1(yH`(t_*!M> zip$%VO}zi|#dlshzx9{nZ$CS>@fRa+JbAjaRpQ|_^Z)buV}q~#?6cp^b=w1~IMCnF z73NHohaq4&b@{%qkMLd3o^Sv4;n$yRzy0@jZ*+HkesJT}zpk75^Q!Xp<(Ia#pX+)- z;;}z08r|@8sk3dkqlLV>Zf`L(0g6Zn*nRMiorD8h*6w|4_3k%U?)v?!+dF>q-m3OL zt$1#vO6#CLkx9)g#38#n;Z`+E5*pYN00S6LUd|D zbtY78n1gtwaV+9i!<~dD1-}F9#XqIF$^CiPG&!!-2ek;=(^& z{c5vRUu=^Y33^iCnMQ`35Q#j1DeAX z4@e?8xCAsU9Jv0TAq591#k7ZsBDd0VC{U>yIhcOowTBCXIGE~e54&uqPy!^71OUeU z41m=(7I(eK$wevLz8Maq1sv-&^o#x@K%*4{Cgota<;e5GvXJ(02f0Bsgkg($6%fbr7?Sb`PmcCsZ zNQ2$9qaNud6VU1MB~C zv05S}!U3Z4WI; z+C%tx5m#|nF3%L#;OZO{g3v>iX%A(~!OS0OeqOMR&Gd^=GmnCUnLosg4|L2V9NgN~ zluptf7@)%LFe$~fhjNi7E%QlkZpv}e&L`<&k?leF2Zrmw?US}jTvPSsV$Dmt)fbj< zzX%v0R!ND{FYNfhy!r$;*Bc)Ol8z5{ob>0_e!svxDWyt`0j}9nmlO~r3k3xfhB-tU zBiXrqG-mUDA^k!*BpxT>VCL2Ge&N4oNu?soRbjwv$wHh0h30j^CgdO`nt7BwFUHM# zRt^2aJ~!z^Oug*$!oFYl^J?m%^^HqlfNQqYB?Sb@LMZ`-2{}l1rokQucm81KNUmB8 z<_JGGz2^nvB=acqzFCy_EU8o+0g=1<)#mW~W)d<9=aZ54UVsBs=; z<`2WiO?yxdG0%&z4Urr$Nl?fGRE&&^_5Ffe=np7Vw&9{(iEy^>S>E_SH@EMbN0YpF zi|Y*^91gflJaN>*H7`Xvl0&w3hWmxM-tfWUfXl=aM=jLmOu$Ne$ktBfFf=rThkDl| zZTq{{6862lM&do2R(=!=5-esLh#x6%OhvB(Z<<+C7_IPj2VSEe|iA|6^VvSeIsrp4D&Rz``JV zS5BWk4GNZm(;e*piF9efL2b^~#R(7&JZSjQC>jIOSxzqDaPs6y9vPsZRq&sN=?-?k zunWlD_8@jPGzJ1&O(>M2F(94ghJFlqo~vUM7wpJS%OzvLMFzeB&+Qo0S;~lp(6FTpIq-)7(yoYXQ%|EE(*6* zFjUqP(Cof!x-B6?`!iJKqRq3kM#}43Zh{D{dkPilRCP7SmW)WNlMJ z-13^Xho*x7iX`oU#Z^DFgdH)`aom29R}R!vpQmxd#Vp|W<+1&SwD%IChv!^|1 zl_L{Ba1bmx(@TnVhAo47JYjK>Y3k^8Ziu$QSkXB^n1 zgkOn(S49$DTrP^ld;`IJ0Ko?5^9VWPfK$u_=K~ieebIaY!+ZzB|LTQzjq}BfoN-|L z0WM>_VL zgM(vZW2a7?I)DEBTppJJ+j5t~;oP}%(D*Ftr6gOO!{p>-sZ{zn>qS~n(4bnK!+Uq# zziY_@nH~ISO2yzXGkh?{4P7gY{Ip4+S9}iC)UW%sl7exV9XVXHP6PZTJUeRqARNZA zF%Ox$BZmvdVQ%b`3&tI}Q2t~NH)b3X*0D`zA6gNY^IMCVA*V*1@eB)wK6oW&#Tt0pJbZo!q ze|qT=$Mr8?io{1z01m^$!{g)QY|6!Q@T(jvDF6o=!_?GNwOai{-H|Z1`YJ2{2OvyO zPuFTS>Z0{(G|hn8R zPXG3qvu{3qdfQK?-gtC!(~rkrz3)U%hxlVJFZ=sT_l&&wgHM0H#BC2`#nlohd-zU!U$^VEH9LRt{EqIQ{bp^~uUG$c%X5!! z>Uwy?Qx9}M{=>Bo-z)y=2bZq8@9t+i?(Dkv`*2V@j&dNdXj?@R1XuZd!;26FDzQ#r ziez@kx3cwf%Mk@x<#J)notc@Lot>?(dG2>}QC>31-7p=gEQsjiv1VT65i4-4Brl73 zL^1st;Sf+;S;n1XET5Iag zbd=Tq;of~4dl>m$w|7JL-}dg=zkh$vIsRG=@dYYM7I-q+oYo-}p-HGj>^Vk?QzA(M|J5=MP`oAQ0YJ*+p{oNr;^1j!)Mh z34W5q%}_Y_-hOv?i9LR@)t_p{<&@W0HIcT^&lr4uTJ5JUeA0qpTu^gnbN+4xG$B_E{BBFpiDJd}+C+Qa_ z2k7QJ+_W6*u^gE%OnV5&2L>EbUP@7)eP*^;^(TQ?4k;_{NAolE+XMT(Y<;^r5SFaw z$H|knJ*4MgPiMiw_KR@dWSq1dsH0mPKjDBH5uy9|BniG>$LmTot(##i2loFZvT7nF z!U3zg87D0V2EAZ>7&=G<&6WU{zF)A8k~xLO!;oUfhd~Y}V3!vTXzmt7Rw+4Lx5`No zD9%+F2nifIh=x=3Bttu2R5)T`I84~}!{}i-oaSbm#KH87V0;)L6Ej~VwukmK?ZKZf zk}B@XWlnJwuFpXs2tBeg?V)NpnDs-$^99G)Ouv{g>nJ#w^+Uq=K*vnO!L40G;WX`m z0m?UrNhzj1RLeAJSx@qCGmevXJxLdfZ4bgfGF(R@-H7)H{Us(Kp5m7+2 zk`kp~*ztjN^-&&fFg^^Y9UtsC8Lq3tet~*YN*x~sT(zYx86Zd!3W{XtbBI+&lJodz z%;x<<`h{{xJx;>GtgGeyB7D!1O2w9|!id_E1U~}`P3wY9$w5jq>nNEorp$X*1O39z zn{*ez0pKH(M0u^5@N9 zzF?eW9cA7(%krKjl}aKYayNg~*?-?mLnh^VGFBhdpa|Ln^M!ryw(~`U>nO8+7&~Ix zgK|iiFMJ(hIiQlDkO@?jO!D>pf>h)m$xzw)MY|H=Y~Qnj@qun`-!~7XdG8j}8#Xu$ zaJg9GsD-OuhHxy0eD(DEg_z#3!C`>Q#S%v?ROej4N_)sxPvtN=I*NsQ=bfD&^sdM4 zdE;gAcW++%-m5RX-Lvv{>sD-EvwYjCCtrW|v5m_gdgY1x*FDy;=AmWculmtF&vh0_5$i;``@#Dvb zhK76;O`4x*x2`cu@M=rQMR_vGFp>F5$S1w z?KQHJ_Rw+=cox^?KpZw#L)Y#bV&s9k{i3KGsHx7UQfuG8NjL}!zxpb>g+E3)U~NGh#|$7v1=^Nqj7B2#q}SgMf{u@`7>TkP>z! z999(x1b($F67vlN^8p0woX;Z^i~~k7Qh;?eN0hM=Vp+p?oc(eRlJILeL4@F^xm&RIzyU4m z%-4`OQGoq@J`jE@3Au6hGfEgDB|^bCU_i%lTp0_pxKMJ<*R=GO1`5U@m;c`^!1#b= zvw7oY>v9nD@t!SNtj4j{*w}Z{#Vq960HQlx@2T(L`K2`&6 Oi*i8i+^>Zj3cdw(sg<(; literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PaneDiamond_Hotspot.bmp b/trunk/Docking/Resources/DockIndicator_PaneDiamond_Hotspot.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e801d382d77400616c5ba7c40646e5a387b0c992 GIT binary patch literal 23286 zcmeI3J#K?Q5Joq*$Psda93XxAD5uG#(nm4{9VHC{|D7SN^Vv(#CtA-)Sb8Ijur1Gy zp5IJi)^G2>pXC;>I=|@gF+ZNl^X>JY`Tg6I`E<#N@0`dfHZiL(TuO;Ot~nnq;84FY zIKaVs7a#BeADjR_I1T0lKH!5Bzz3(ne82~Ma02+?G?)+gfDcXpADjmB0Uz+e3Ful) z(f57qkM_!TKA*4c_8?IqjN_QW;Zaa55RS)V5{K=ha0se4kHeNxtRQ4_*d_`=7=~e* zCbfeqtdZ(NT|( z!T}E6SNMPr_}~Qa!D%ob@Bts306sVk<^w+9gA>39r@?%{2Yhe>_~0~{5BPu&P5>XA z2J-1+PLZMj^&O!StwAG}}gg}#%QdKK7 zF2XrztBH2qD1TDr;b~Q>BAi1_8(wW{!Xyri03VzN^8p|5!3p4l(_lW}!^#IK5gxuo?DZdhY962f literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PaneDiamond_HotspotIndex.bmp b/trunk/Docking/Resources/DockIndicator_PaneDiamond_HotspotIndex.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e5ef472c56cb9258fdaa5b45bf9df1d5adbcd38c GIT binary patch literal 90 tcmZ?rjbeZRGa#h_#LQ64$RGihPyv&u#D5@QU;q<93MkhAk%tL`gaEYn5c~iD literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PaneDiamond_Left.bmp b/trunk/Docking/Resources/DockIndicator_PaneDiamond_Left.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1fbda61c089c95635644e4f5d01905477db17842 GIT binary patch literal 23286 zcmeI4?Qc~@8o=?t@K5kB@QX$ljU0zJhW0!*1gKW}b7N4(H|e+;h*>-UBDo$=v6hnR(_n zuV{&Ae-^yx`rpKRoZ(#$2B^=4yIDPswG`>!IDamH%Fg7+;C=@6~x{J7=pg|G6F_qT9RMA=c z#XEnvbNl?eQah5ODdmI1`{aIeckn>YI7|a0!is7^AouVi!%}lmrGYU7!f~k3O;B3;wlGT6?xC9!hssEe)me~7eEjfhvG`;7kk@UyW3j2jc;5eihOV=7Kzw*G?x_d@myyIwRtN6puE&S@)+XkPx^~=A`ciRI=aglzljq105 zJ`4fPDa-!~J8}Q*+3}yx-u~s&t(QJ}{m1UEZ+EXd_wMsk|6Ez#y6p6p_TycP#2qJ6edV`}P(?6QGEMfZn_R)`{D-Y4v*>R&9T2#kLoo+S>7#H&(X4y8O=@ zpL}Rt`+aL3y{qG)Kd!v*cJY_ry;5$bNlT#!a?mg%7MU~Z5444T;;P3&p{NZ z#5#c~lG!2K!d6c$OBD0w{hEctm^(Q+IW;v^UGvQEf+CX(2x@@K$}k-$EXmTxBh9?X z16JTjNrMzqJt66G2&fdPc@m*JvQdOmsnpZc6IpA>dwYA`yO9!7a8XnNn?yZ*M)eGE zsM9d5C3R;y^6L3u*Y35QjQp0k?h{IJ|Nky94{i7b{=0%ZdvWC;SuLG<|gb;H5PJ;jN|ZL|31P z$f>32Y-BEz!Bvo7xmd^W{XvS5{TrGu;Agx!U=}k1N*&f zeY-jkmZWCJ$z!%XBV{Ie0f;oYDbQ2 z4*>;4E6Gv%g&iMQS0AEsz42in>G)vBNq=4K_Y2gMT&nme;HoWUNdZBkkWnDP@c0m^ zj6|pUXw2sQLi&YrNIXu$!K|z0{lb6Gl0rr1tHOZV5(Pg63XSW6O~^rVH0vmtFUHM# zRt^2a&YN^1mR@$guYS~K6Chkz(6FPCH43EDoLIu)@ZrOlazH_=;6Dx1U7UX5 z6p(xDLG)~>4+M^ykSSTCKswEdr5r#(tAIv57bN8@kQ{?)C;@2+0)b4)x*pAi151cH z9qB;w$dM!c{rzDSb()`Ox2`cu@M=pS>rAc`6InP4nglqw9fX3^V}5e2V_^tkWqw~t z0EOEs7%J;=q^#C4w>u#JeTy8IyNg0QNQUPIIaJ_whd4Fnf?QEBRxoyDdybUz6;P$e z&DoaVR)L_9xtQJ&cdpotQYB1>B0=dFjFzkungW892vxb5$e5ZLBr`l$OtMv=&B0r< za$qx!eMR;*)x~YEk(9KDrh`De%*ugh*j)8pOV|)2mFxD4ymFwVI-g3Z!~PY*K~RK? zuaYZ=gBCe5aFv5#xym7z9N0CbX4Cn3nm1+lIEA0Heu144Qv$o_#;=UwV{t=h|-j=83zt2VOPRoRgr+_my04X-#{=QK(NmFJVMSmU=%aX`M`wVg~mNk6G*)QiH@xPYiJ>dN` zcXQSrIG|;n`5F=@3b4P=1pIF$Avex`MhQctJdiUE7|?MXSH^-Y&X-*FH7&iRft+#3 zsy{T7|wg=g=uG4(%nr@qy W11Rb@AFBbkNjac)=2zoJg8u`JR+iHM literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PaneDiamond_Right.bmp b/trunk/Docking/Resources/DockIndicator_PaneDiamond_Right.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1de97a098639b0bb45e11c38ba76ebd8e103e8cf GIT binary patch literal 23286 zcmeI4Yi||R8i4U%_!ImEe$l9CB*C<&-Zkp+Mk*?ZB4V*9!ciz5@thc2_o7kM^N@5$nq)3{;dkQl#coEJd@#IzA|#^KaR;nc`J=e%iX3nl7#J8C8DUc{l0&%4k&+y6pfQY(kC)5kcdL$sk=0jW4mbc| zVq&6FsZbZKSFM4j=D=t6&Lx}+Nl2e_+bcW zPF;R4Y{mW7v*p*%-~Rctjpsgo?Z@t}@3yZ#_1<$+Z!IftTzq^(`{Azp#UK0E-J`2+ zFLkyJceIdJ_w6l)CO{Dh0ll}s(uv!)ZpHgAE#Lg&(oN4lv9aT^|14|&_mYR!K7QZo z_PbU-cx%Uf|5$d{P2w-Pecs}muYa`l+V-2ShJ)I1lmmfT+bZH9xXNc6o`on-iFE=~ zB(p=dm93szhA7A?lM7?+~|AgBQ@E5mf4vSdpik2Lcl4_JXC zB@I$c^@OC$A)r#E=1GL^$VL@PrBY8%Ph_h@-rL*j-i?%ygNvdH*d*#{9Mv)&`{A-C{%Zdi{5-;s170S@`-<0D*; z0X?i|fJ2>zX{{y&!Cchd*Zt8~pMLVgw+A&1|*^_YNI^X5GsPz4C^6PlRCP3R_8!Mj7o;XMCsh5;Xv9zap9kC z{;IQ7Uvv{632DO_MoLm}ARh`kCmfCqVoJlX$iu~moSZ{ta5pwtjEp1)CLGRM4&)rJ zct8@#!6l$!;XwQgx)dCw6w@9iiabiop+Kc-D&#d%}<0b0S$|)VPBw0 z#|dYckb{)M} zB>m!0FWsDno0Nk+mLv0pX%GJRzqprJtXH~PiMiw_6vXBWSq1dsH0mPKjDBH0ipZ&Bnf`Fju(_@S~tT;4($I+ zWYt7UgacM}Gfr9#40_)9(7%fanr+;?N#kKivExG@hZC^N3kNiJ3nHt894=VpxCj*I zDhz}e4y{DPsd|#3oi9opu`nD)?fPM8j~q^OvyJ0m`h_<>^pc60FJjw6OOo~wo-g7m z?#g9OaTTu4K_Lh|vNG+VY&n?qL(TIA$Jk827&YrCIGFWA%=kdZOv1sfT}|O6?STO* zYz~uBOnWF7Y0|Qu_-tN1llUm|N-?Z}bsA)tV0B_&F~ zu;T;k>U}(1Z+sX?IzHHO(qC8m{Q~u*lqx<7xN1vXQb3R-6corXJU&D!BguJuG-mUD zA^k!*BpxT>VAj?0e&N4oNu?soRbfDFNrImOg{F1ECgdO`nst=S7vttVtA>7I=S?~h zOD{WL*!K&6T}@rIzHtE*aMhN&q<|nvC?$|#LJpFgWw6J=T|d}0lAG-X<_pG2)=}nt zvncObQmHrsB6sswox|^&NysEzPe$s48Wcf$V7{>L-FCjHaUEsW55s#+dr%HB^F>&P zNDinZC}aW^CF6X3zaSO)2QpN);i6rMaJKJR-uOT_x9^*~le~9}=?xnk2DnTtan!<9 zFGV<#L$-Q``-Pa^u)$$~%fu2#EmY@Bz)E|_R!`+HG&F>TdegOSA9St2ZGHJ!@wcp5 z_Rb4WzR|hp_2mmUEM2gE@dGbCdheGna`50mP_Px8?&ADU zq)7`7s&lp`PJnP>LBozl(I}8kb5aS1{rmT0$^iwfg8wv3cX9fKQ$X&q2hp>kJ`gx+ zLZK9m0_ij-m2vzaV+wz=8h${xFI< z%}=yj*O(=EwIxu6Y+Q<&ER+O{0S;~lp(6E|pIqx$00QNPborYF0TgblV5qFek+WLI z-0m<7A;>duQD_Ir@Z2DW3bZ@SS_lCYj1`Ps*`6cid<9hLakCtPi$dmNdPm&3;)LCp z4n?h{Uocv-PG|}UiUMt!$e5ZLBr`l$+(Zx*MRg8rrm?Tc-ln>^?KN!=O$PxKN!kOO ztG;Uq8)Af~+b{CUftu=kDzyYPSJ5w5;UE*=hA<;cJ#4ua(phg@=C*OVul&d<}l zDZ9rh{G9a*?2MQa*hM#fWegvS8$u)ZeJ^06sXS*KIHZJK35Qih0-j$kio|>a!F&M0 zI_L8UIpcs)%sA%*7bbknd;!CJ2gCpBg%`*9Vn)t5aQpz1G1f8Tn}GdHihd47gzC?H zK_zeBMd64tRzfUm_>Qw*&OzdTEys)C{WN!T)*d*ZWu5sN5+@3~1zDUgIqz#)dP@U2#?9vCAm-z(YtvYb!`9d) s<&cT_nC(rynv{cVS=VVkc1^d<%K;Sin~&9i+oT*&JM$}Y&ngq)pNSxqvj6}9 literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PaneDiamond_Top.bmp b/trunk/Docking/Resources/DockIndicator_PaneDiamond_Top.bmp new file mode 100644 index 0000000000000000000000000000000000000000..95122a0f31b83e03b34977ac7fdea926907d9a83 GIT binary patch literal 23286 zcmeI4?Q<2?8Nk#3qJKjFf_`a7iyfK4NgB0Q9ktfVM64h!A_hZ6s6uGPb~=nwEmTGZ z3;EPe5vG;QTn3U!Ow7F`hVVAIF`A zo|u?8bLPy&ix(I2xX81G8n-5Em&1h%7ohQR)=NpYJBR7%=~AggEwWvt1qBU?5BPjo&C9ZHmCKR%CgXL+1c4ztwvq6UX2FYngcVPLSSDpFAnXsMHzu09Im|6cX@B`r9B%K-g>U~ z=Gu$9R?q(Gsq?Qrd3MM5XI_0|ddv4FU%K~HUzhk3FRb|J`MbxS`}T)FS?0C}vf?8D zMjO@tKfVtE&8f?OOZ#yD8QlBtKfm?Q_jg_Y!|R_7^#Aq1mdn3;asD^!tGm`**x7TY z|8eoBfA;Xy<_9W$-4nf?q}6?Ui=hor#6m#t13&M>?ccufomV#Od3oLLpFX>*_eZ~6 z-}8&LKiu}rV_SM2+VsTzy^noo{X_SNzxILUYwo@4>8?9_?)fGh)Q+PZ2rSuFkp#h2 zKHu;XM1e}I6PO~I9rCSg{oHayK~}k37<1?5=H}<;>ua9--CUHHOw<6Emti_mS+b>% z$C`PON36iHk`^hZdPX=zREpI+jnEz0s6wSu85|speQ?N!hKAg`u@Z7{QPcsOMm>$A zdPX=jX_(fUx-%VR4ZgSkz~(+ie%I~a)ccqH`wkvFIPm(8H=bR^E&M|}cOb!cB>hN$ zLq7WW2sdLu_w|f$XwopP)g)V(i`vHre*fX0{`mJ#E=3kINRS_TZM)tT$${-#Ba%Zq z``rx5Rtst}pxOEy#43$p5wjZRBrGY|9oRR%R{NM;R$Qby{!et%{L%Tnmp2K7H&^$N zTzwKE=egt4HAsS=Bylqo4t}{2iD--3D33LSieNRvdPvozj;@~dIgk*elHo90xjtt& zkTz1B|I^K1b(ZRjZsH>$t)F46Bm)QXp`h!+;rtk;Gz^P8T#U%+In>6EV3WnjNOEAp z;hN<@&VI!sl2{Hd0SyZW;@{L|;2@=#_Ap!KQCbcqD%Btd(=USdaBd6(Q4 zfB=#Rz@(oMu-e9w;)|SAl)~d%<_psv!tsFtN0gUR)MuZWEmr+WAeKYQiu=+04E^@N zelJ_!t`3AHtHp8hv~3URIoQ)#aIpO%oHrRKEeGo87ROIGphiUKK0Zl;@7M9B5>4x7 z7|VhEe~GM`NQrR3s&2+f%Yi{J7#~Is6G5{jz@_gOtfOR3q46-J*zsYQ!wJ~sg#((q z1(8)s4mYiGQUr=~6$U~Ahc2SwR6WVi&KDJqSQrjdcKtAZR1T-P*(Px?{UR72hRDRs z7m4kmGfjK&=ZmC@yKabs+o|IC@M*&xDsY?b3l7xaH z8TuSzm67B;J{q%mzmR^R98!;ya4_p?dA|tXv!qh7<*G2Ewj{yNfI`!{U{i9C63seF z=8GBgp4C9Vu=6IJh^3dEFYNn8xUQxyTHmAq3b<-ZT{1wBB$N`#FeL{`&N4XQ;I1F+ z8p+KTg}MBBGng+JCs{|C_sz1rXGx`!2#DOxUv>81H`9^4g*{+mN;tRs+S=g%OPJq{eB^)H*9bi;Bv9VQ47^M7qHSE^3_v0jE|3F zq27IG_q+WYar<6b??%mIHFI&}lhi{34gX)|MSmB_yLIUq@+qie@^Xc_`s`HMOE55-?1pCr#(X;z4 z9M~A-?8>QAr$E70aJGx{Kd~k)IH=C~nm7T%g#`^e8bzZ(HqA*T98R1#!IS|CS_S`U znC;^93#WkGV-KQdOMM`4)PzDQ8U?axPAcU93R(p;nza6=}x&2@Wg=s0W{}M5T=5qj9c=_5c+edk z^*OMa#=atZo9dFb*R(yrA!RFCLeXx<0ae*t4PB>ih>^Ou{i3KGsHx7UNl)+=;UFlI zAjsXq_lr8!*ITzvd(bM!25xf@ECu7ht|>Lj<`-#vklo`9e!i9AwM7N%OI5 bx@}($plIHFtOndRAe1M3Ss(A#J zSb@8oUU^0+~+#2UDs_Vo=6tmGS@k%nXQrYkOrA%bj#dkgly(N;QIakcs!0zDb6B$ z#y?5QyoXRIluRZmw=`)kPM8*LBZcwdg$IWB*5ldxhtszQQ#bYrqk9vU-TcL#s98&W z_{`4G=^cUL?Qc$Yfa`L(>b}Q3&!P=;{IuPepF?#=asU7T literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PanelBottom_Active.bmp b/trunk/Docking/Resources/DockIndicator_PanelBottom_Active.bmp new file mode 100644 index 0000000000000000000000000000000000000000..212fb0d366643c01ddb73ad88d5caac25db236fc GIT binary patch literal 2782 zcmds(+iTNc7{=qRe}OmRt$%@6f^1^JvDz^v6PcouiicTrbyn-Cc$#M~3hJP9f(*1* zUO0zrg{(BCwWl;a#I82gwWXyxHWcwfp*~-d)^?4HjTOO{Cok{!yx;pvQYiU4^}Rh4TfP{ zS_88nC~zGey?-J+4_;K6``-UTLB2+F#Znx>1GUb@WHYPLQQ_tS(+i?%1(v9DL6YUV zx<}mkl5_*pD%^Z{ra&}Xh|J`nFcBP*BSi9sT7jM71{H3Rql?@e$uSgki7Z8l%b(q< zFKsAsb1K|&(p%;kSxKf`FZk%n8&HT{ViI44yEq?MOjlJ`f1D2xNv)cXqFSqPm$EF8 z5FwK4EW0egVVB7gKB*-UN2;^zKjMDQ^SHCNyxRYwqBT^02d&tOb}lAYxvNGl#w7g; zt%du{pm!R&og@<}qFd&=26eM_avjjYX-2oqZAK_M{{h$U_s8RLd`j^yitqS4ro!(K z3Wbu%q{J;vSc~J9f@35EaK2X``C)cNCrvl08U=pYW$i_uN)Iih&^%686 z=xm5$pqV5gpe~?ZV$3JWSY*XSnh)_ZvPNRqKwU(dPmF0;)evbuBr36*fJYFhi%9eF z7=mAlNb`rf`$y9cp7IBn2Jj~mJhCGs{m`NOgjfMdsF3W2i-f3ws3$V~fy&4RKxg2u zzn;!1eKND?`P_0Kg0LS=%X=_6`(A(A?e3(T9kJJ2qOLZCUaAeaSmg^L&y{(eEpa_v zMK}_b2Dv=}EoO9tR<> zHbq>n3%O9`f3DmIXg;vzgD3qj?W_W##cdTpG{3oYPJQ9@n%v3dnSI5nU3rPESuqW% z;nfL2!q8_N1 zp!q;&LlgteBnbg^0re7NK1s$RD<;x>h?kKy62k`SBGP%Nb@04iPZ!=f(9UL+iMm7LC z1AqPXbWZ7$nMKd%mID!l{b*X=gUQ+V`qOTAC*ACbz1|XawITFUZNSAUUkG`w%=2uC z>**rrQw5F$&Huf3?)RND{~TBVL=g7Zt&=}(=zYJc{q@p@=kqEb&nUh>IpW%g| z2zj+B;&NTcg)0AZ3?Zw6%Z|Ms{o?;&82hd3#ZrQPA<>vD^BgoOKi=G zX-EyPP6#TG@hcAZf{=M3ZaD!?8NT+ZUN%7UZ``PoPCKLcsPd0CV;=cmMzZ literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PanelLeft.bmp b/trunk/Docking/Resources/DockIndicator_PanelLeft.bmp new file mode 100644 index 0000000000000000000000000000000000000000..551fd88624747761b970c653d7449ec33dbddc13 GIT binary patch literal 2838 zcmZ?r72{?A12Z700mSk^EDOYp3=%++f#Crcm_i}8(h>k|0vdnf#EHw7FW`yRCc zn)yI0u3o(gw2MLjGz8*WH1mPtM~@!eOECZ%0yGL37-;6taSWmg0y+>F0$9y|cybF6 zJwCnt>ABr6E**Sz?bzGfr{CYd@bS@=&rhxc(SJe!=t3gRe}3t}t7}I==HI*U=^@B` zpk6}8|0l-$N2j+vJ-6ot(ERI1-`)b5{}F6HwcP&*96nI@-#Y!_K2_a+VhhmxC+Bt} zhtJ1HSE(5OAorgKn|~b~zj(ucZ;~5wq!0-I6NvN!az8BmKjBC}tNeZUCX-@5EPaB* z2bMm8@e4K|E&TwwK=b#ImuYzYodo zKe6TU8F2c!49Z_X^Fiq!NBFNKHGI(G7o2}T0MidP_d}8mY3TKr|6z&4-Vm_6^|LL64Co_wl&n<_L5bmRCc@HLM-|J7i-JNu^Bldbr)YXR2OSJ(P zt9&8kxiZhQC9bE7oKF=v;t&7dd*^=NIrGnf1rQR#{knDXrwzUDSGB)h+VFf{<>MK} z_b2Dv=}EoO9tR<>Hbq>n3%O9`f3DmIXg;3$cWGx85G`)2fROW>OXt)VPOr(GT%Ori zoZ6L_*qRm7kQ!c{5L6!HR~+sIA@f4qasr$(eC<=cY=GvYwI7ZhJ9hEn#p~Cv0~;08 s1(5c`kt0XWoH+xug2HAGrgn(=2M!znS^@M0upviX05P9-El{BO02Xyfj{pDw literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PanelLeft_Active.bmp b/trunk/Docking/Resources/DockIndicator_PanelLeft_Active.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5182318ed3d451f969799e09333f85e60ede5ad8 GIT binary patch literal 2838 zcmZ?r72{?A12Z700mSk^EDOYp3=%++f#Crcm_i}`GceE&0c`>re&WQ5%a1 zwE>#>Kr60Zy$ZC8LI5-b;#xHGf#OGx9^FeZ02%@`3K$q@=Ff2qq6z{!5Euej&3|}u z3lKd%z5VIA-7hX3e0A;E+uNt#-@owj(Us3nt^?73LICJOBF%q(>A>?#=LOLG>qp<-0-662Y(BNz{|FpDQ1{W(EKOo zb|Z(+$46JG82%vlp9h%m^^aFA~Ec`#=NI$FmefK7lVm>T= zg2M-vK7sKIHXkkh0J%W(_mJd%u=$AaxpwRgDE*(uO#eW`$u=L9zo6lN^bI8a;B>za z$?iX~tEhk_~C;2NwP)=^vQCaJU~i zWkT4%NFiAMK=K!;e1Mccu<{M47t=sA5n|1U#4pf%VEDtz2Wpi+(DVb0Uts_F-&$A`2r;D6V6*%G#|KEG(e&0Fs&w&LH62kqub@HbTz3*4Gzh2t#d|u__ z8O8S}=iKQ@z0n>AA+I(?T&@ebQ00HF+y`hrp89ubXB7}FZmWQh^P5ZO)E7>#$(>xD z*;ky}m6zC>71NL!UY!tB9^+RW?gb(9Lfmo!oHBgvQ@w0}=A*SAjvYI8@#4kn*RKN` s71RZg_QR1QN6wr%1GIv|W)G%zi1`N&8~|DY^aZdXM_m9hpQi0k0Kv25U;qFB literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PanelRight.bmp b/trunk/Docking/Resources/DockIndicator_PanelRight.bmp new file mode 100644 index 0000000000000000000000000000000000000000..003cbb02a6df99653e66cf887fff26d684f97f09 GIT binary patch literal 2838 zcmZ?r72{?A12Z700mSk^EDOYp3=%++f#Crcm_i}8(h>k|0vdnf#EHw7FW`yRCc zn)yI0fZ*!Yt3c~00YDRg<^UawWA;h7yC0w4{_x}$AOgCO67zxDf#!dLn1B29 ztLsOfUpn~o-0nwIG9Tgod*|Om%|Gz;+#YI~4{`s;hgaUi&A)u$>3OP!55)bSfaXKP z9~eFdo}4EqeD)@}Va7Jp{qXR=cJu`}e#r=*JxOjW{e97_fVv;ad`S8s&-_*XK0pT} zTLDi$AMRZM#qTvx_yE%nG<}{RA$bIN<{zYD`G812 zK=Xm&4+$T#;ukGsAY5qr0p(wC`ngVi_+T|37XDYE=7ZBGFnmDaPh$GPYChckACSri z>X)C8@BxQEuzUcQpWBEj|DVn&eKND?`P^~{3E@7PmiJ(C_PzeJ+ucbwJ7TZ5L|ttN zy;K`;vC0=ho-6Y_TjF}U$oW)(BhZ6*>X+Yp=YHQg^Ur|=5E8=ux^?oW4ZZJIwZC54 z@O)n7;~B;GC+FPhNxjh?2O+OEMO>~6xlrYQt{haJ;HiI?c2)t=;$$Wa$S%%@!o6lgvGL|{nP literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PanelRight_Active.bmp b/trunk/Docking/Resources/DockIndicator_PanelRight_Active.bmp new file mode 100644 index 0000000000000000000000000000000000000000..dad423551dc270a8fc196ced8f72bf9c9e01ecac GIT binary patch literal 2838 zcmZ?r72{?A12Z700mSk^EDOYp3=%++f#Crcm_i}`GceE&0d3m4b?b=}CoW&UeEat8 zdsGELXQP=9v;qjOUcCymjuHSg0cZ}U`9Sdt7cLw+bZ9SS;ONn#K%+3tpW_%r6$Er0 z(EC`;|4#^fesUd%K0dng{{Drxw@$yhcI^4315eKFetdfS!;@Qp2EP3IyB|@>e1!Y&oqr28|G?98d#GhT#Qh&1UU?5U|MG#S=cyJx5chuq znhyV72iA?b%a^H=%% z03D2M1w8$HxOV{*zt=$F157{A^m&4W^a*tTDt}*~fyh=MrJoCLKdNHkd1Kv{qt`?;RDLQ!1PH*_!CG!(C`PEe~^mh z10wwZ%?E}*Bz(w4re>$i1$;_hXbITzlg!^b(-h;{6_xjUrcPHKKh`rtt zb+sY%Qfcy!1f^k Dd#2bL literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockIndicator_PanelTop.bmp b/trunk/Docking/Resources/DockIndicator_PanelTop.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f6293fd2bc2b474bdb32322ee92ba986f7fa0233 GIT binary patch literal 2870 zcmZ?rHREOg12Z700mQOEtN_G}3=%*R2%z#14uqV!Vht@2!`7`^PnfA?H~^T^+FtnZZ1&b=+UEl$pt{YKofv|MmKkkV-O_>=pLX)v77s! zTmW>?sJXzvBRL%QCb{iRcH5JLKtK`9SRmP4pb@M5ePPIFrN1wxq2#z1VhTL{VKtO| zb0Io$8A_44cnlqW=6-&19T-LAk@)g4&_wbOf%NFttPCzrz})xuFTB48LLXoZ2>1Q{^AM2_Kv|#^1l>FT9*Dqf0_MKGeHw&rff1a2 z`}7+ix&=Z|1rRk51z!l6P=T$zQQG9=L&Yhmr8|`rr@@iAW<+_jyRsQG7eSqfTtml_@RsqrCwu<@9 zrE}^Fr`P08F3;>MPVLG|Y|V;kNDZ$}2r7^9D-QR9ka;0)IRQ=?zV@kJHb8UH+a<@2 z9lLn(;`Qs-fvpv)0BF19$dMyw&YS@nO{89I?YNv{O`%R=bZb?okz%Rv$w1j zsI|av#8{890b`A@4j#tqY{LA!AOxR0Yp%c)Fk-P-Hk(ydHQyww=K?LuGQPu_VJ+KS zJr{*&G#a*QSPKHKxt<$p?OKhnA6)3-+dg%xvw z7gMkG;0KGsuxl$Gm9!pO!<@!(b$ChO^p*xQq^KL z{uP=e;ti~aHPG0ETbYn56VZwiC7uKljge%5k>^#~Ntz`SZaMR|lo87r5&kccBvF

|x4stI={`G#r?zKA$QraVZ|fKHJqqC~2^(}X)6e+6mrmm2XzMur9nR$VC7dQ7#DpB2ayPTOS?#GU6{iJU#uuQwa2Zy5;&XxQBW9;?C^(?s1Foe_ z$^ZG0>ptl5)lda;5~H5(wZ9nFKIIT3r__-t!i6jyUpsgLB8dq_yD2hO1*Ej$+#W)uqO_%To D=uj!( literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockPane_AutoHide.bmp b/trunk/Docking/Resources/DockPane_AutoHide.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2f395fc0103c27921866c86c1e18e06eb0437c15 GIT binary patch literal 774 zcmZ?rWn*Rl12Z700mK48%n!tj3=%++f#CuZm_i}`4+Q{pF-guu@gay7ogS!Nx V9KT|q>@ZLd3m6bh(7yw#0058Bb*TUV literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockPane_Option.bmp b/trunk/Docking/Resources/DockPane_Option.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0d9927a7ce5d055bfc510269000a26a74b54bb24 GIT binary patch literal 774 zcmZ?rWn*Rl12Z700mK48%n!tj3=%++f#CuZm_i}`4@Us;A(1{q4i17^kQEcO1yeCW NEd(7fssMio006TLlZyZV literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/DockPane_OptionOverflow.bmp b/trunk/Docking/Resources/DockPane_OptionOverflow.bmp new file mode 100644 index 0000000000000000000000000000000000000000..02e4bf2905c71009e0a642e171211bf86da659ce GIT binary patch literal 774 zcmZ?rWn*Rl12Z700mK48%n!tj3=%++f#CuZm_i}`4@Us;A(1{q4i17^kQEcO1yeCW UEd(8atbkPWNmY+**HB>t0L6i0y8r+H literal 0 HcmV?d00001 diff --git a/trunk/Docking/Resources/Dockindicator_PaneDiamond_Fill.bmp b/trunk/Docking/Resources/Dockindicator_PaneDiamond_Fill.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cbe0a156ab38a1bdd969735c4bb24cc1c9865744 GIT binary patch literal 23286 zcmeI4?Qa~#8NjdqMgIi;f_`ZQgo;Q(HU>%o0i}h=gp!apgy7(mkQ5RJ2p|+efF>m( z3Qhc}RYRhdSh^^&Wn<&J*f`FceDT?7qVSp^-~&kTn|XF0kN4%gx3{PIHd&2FbI? zQ>RXyKYxBUi;FaysBv?Wb~&6ocMck#q`j16t8WahMrCT(wRE{3JXx zVtg;`KVzRfWbO_h&KZZ<(GM>ecjQ9p!&%&@aY&3`GR}KI13YOT$Qg%=W5tVOM~y#D zpm@prw9fvVyX(v4flFgYbH?HF$$`t0{hmA7f7x}&x$8YZz}_`NBhML!&(92he%5zR z__H&^#>p*}6Y#@1E;ItPOycO1T+o#f4? z^Yb*1N`SM|*EaTd(nri$swR4y97* z^y$-)?V|6IrAHjsw|ps*Fp3;-7#bQH8yjO&E|NpI$dQs9aG)|wPEJ-TmA}>O2_uWI z!W?h_!qn7MwOXYtTCREnt<9lOPzdZRX2pS|ek>H~CHa4Qem(@@aOvIdi@Uon>{>Vb z_LJ2&SD)Xpa_Y55&%XS~>21H8eBu6yO}`y`_Kp+X?c$FJ16)>y=|EvgmNp(~ z=0zT`0!K=kq?qa%;1EzLQu8E2w`ZdW<#M^NuP^e&A@A?+ckf0@NWn!>18frY^cmGN zz@b6Iw3gHz>By_^{k{7(cGL5_ZtsS!|L)zhfB*j8SGK+J#0qZVAK1PP3BDugK>{4o z(bq?~5d(Ty&j5!84bxgol7+dbeYE!RplS+qyX*Ik3IQ zO^{?YqXq+-Y?y;sr7PcxB?Y?!`^HzQpRmh{3lt~(6Wug@bbkN24FciKm7PRa zpNPnL@AxzgqTt6#+ysR~INyLov_)-{#~MOGu$o~#q-at`SI^oUh=@_iaF{Azoi-eZ z8^|vF(@kG>mg0+U;v*q$IKfCs3J#=0MpuQy*;-#^gdi1Lz)`s_2a#i~CEL~=-2@bF{d1jF@# z{a&`dT^$HZQgi*}Nn0P1bFing;9%Q@KW@@bS`L)a&5oaNK#hRVeSH!IKU~HIB^uXF zFp>lN|MIYEB00hVtGekYEeAS1uYVXk$OD=z0WMu%FprWkg~~&hV*7^y4kuuj7Y=Cd zW<*j6IV@P@xChA2RTu~{9NKvdr|L<9cDyKa#KLeGxATXQ!*V#yO*W2$X%}Aq&`%;} zyojw2ZAt1wc)W-!xGR@2#Z|aA2ZbQ?NXpcQisfMD4|R_h9Ah)>V%*H5;9%wtG5rG# zGYJQ`bajQ3)CW4KusKX}G4-KRqDsqrl9!vZpS1Hynpk9g5dMMgI`I0WuHx5Ke0f;o zQg3y^5^fg(1w<>!QQC#=ADCAk<>h+)!%))x!S<8>yxMOUs3*D9@KL~3Tgs9Gf#RE3g&j9(L`=QxcwyHU{=Ay9XnErTDB!9sWk~@+qL51ZJ%ra>!QCaJvxG8#Xu$aG6-*D23{r30SEQ+3KkrMn*=k zQ185{^h2~e;VobKZMPozl;4ytpuCQg8GVL`)=M%E~hPIF=jhhxW%F=T*(TETxB zrn@-(!YLs4*n{ZVR38W&H6c^7MuBvi6H7UOf?5HMMlMLoSs*zE(^LXd69fX8l651R z3x`a6NFG0ad~k3ujG{sF6ZO_LW(i)c37IHQA}I#4h$w|ZfP>pWC`cpbC)YX_fRLfR zJEBnOMDtO&wSum)5y#7N7n@oW79#{f=b+FAlHs{Q4i&Tjg!w4wE9kqjJx9v<3aHZJ z7H>^(o06>+G8WT1;?5PjF=~WqP}(l&Etw~@1_ZxWpgaQ^Lo=OZmgkCF==`Kbu^VpDu^)d_qoZU~Ls z_q~99OyxP_z#%2?f<_j3+I~e{~ zFT7`*FJ|P71IG_A8DkwYz6sdRr0C~RM5zAU7gX~0T@;QeVAf|E(nC#@Wv(VThCma>fAzI*#MYSdhi}l6ha#(pwtH z8HY^%e=`T`ZY-OP8#h~*gP4!^Y)NA^j +// This code was generated by a tool. +// Runtime Version:2.0.50727.3603 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace LSLEditor.Docking { + using System; + + + ///

+ /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LSLEditor.Docking.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Docking. + /// + internal static string Category_Docking { + get { + return ResourceManager.GetString("Category_Docking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Docking Notification. + /// + internal static string Category_DockingNotification { + get { + return ResourceManager.GetString("Category_DockingNotification", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Property Changed. + /// + internal static string Category_PropertyChanged { + get { + return ResourceManager.GetString("Category_PropertyChanged", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (Float). + /// + internal static string DockAreaEditor_FloatCheckBoxText { + get { + return ResourceManager.GetString("DockAreaEditor_FloatCheckBoxText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines if end user drag and drop docking is allowed.. + /// + internal static string DockContent_AllowEndUserDocking_Description { + get { + return ResourceManager.GetString("DockContent_AllowEndUserDocking_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The size to display the content in auto hide mode. Value < 1 to specify the size in portion; value >= 1 to specify the size in pixel.. + /// + internal static string DockContent_AutoHidePortion_Description { + get { + return ResourceManager.GetString("DockContent_AutoHidePortion_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable/Disable the close button of the content.. + /// + internal static string DockContent_CloseButton_Description { + get { + return ResourceManager.GetString("DockContent_CloseButton_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows or hides the close button of the content. This property does not function with System MDI Document Style.. + /// + internal static string DockContent_CloseButtonVisible_Description { + get { + return ResourceManager.GetString("DockContent_CloseButtonVisible_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The form must be of type IDockContent.. + /// + internal static string DockContent_Constructor_InvalidForm { + get { + return ResourceManager.GetString("DockContent_Constructor_InvalidForm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gets or sets a value indicating in which area of the DockPanel the content allowed to show.. + /// + internal static string DockContent_DockAreas_Description { + get { + return ResourceManager.GetString("DockContent_DockAreas_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when the value of DockState property changed.. + /// + internal static string DockContent_DockStateChanged_Description { + get { + return ResourceManager.GetString("DockContent_DockStateChanged_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Indicates the content will be hidden instead of being closed.. + /// + internal static string DockContent_HideOnClose_Description { + get { + return ResourceManager.GetString("DockContent_HideOnClose_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The desired docking state when first showing.. + /// + internal static string DockContent_ShowHint_Description { + get { + return ResourceManager.GetString("DockContent_ShowHint_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Context menu displayed for the dock pane tab strip.. + /// + internal static string DockContent_TabPageContextMenu_Description { + get { + return ResourceManager.GetString("DockContent_TabPageContextMenu_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The tab text displayed in the dock pane. If not set, the Text property will be used.. + /// + internal static string DockContent_TabText_Description { + get { + return ResourceManager.GetString("DockContent_TabText_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The text displayed when mouse hovers over the tab.. + /// + internal static string DockContent_ToolTipText_Description { + get { + return ResourceManager.GetString("DockContent_ToolTipText_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The provided value is out of range.. + /// + internal static string DockContentHandler_AutoHidePortion_OutOfRange { + get { + return ResourceManager.GetString("DockContentHandler_AutoHidePortion_OutOfRange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Value: The value of DockAreas conflicts with current DockState.. + /// + internal static string DockContentHandler_DockAreas_InvalidValue { + get { + return ResourceManager.GetString("DockContentHandler_DockAreas_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane.. + /// + internal static string DockContentHandler_DockPane_InvalidValue { + get { + return ResourceManager.GetString("DockContentHandler_DockPane_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane.. + /// + internal static string DockContentHandler_FloatPane_InvalidValue { + get { + return ResourceManager.GetString("DockContentHandler_FloatPane_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid value, conflicts with DockableAreas property.. + /// + internal static string DockContentHandler_IsFloat_InvalidValue { + get { + return ResourceManager.GetString("DockContentHandler_IsFloat_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The dock state is invalid.. + /// + internal static string DockContentHandler_SetDockState_InvalidState { + get { + return ResourceManager.GetString("DockContentHandler_SetDockState_InvalidState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The dock panel is null.. + /// + internal static string DockContentHandler_SetDockState_NullPanel { + get { + return ResourceManager.GetString("DockContentHandler_SetDockState_NullPanel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid beforeContent, it must be contained by the pane.. + /// + internal static string DockContentHandler_Show_InvalidBeforeContent { + get { + return ResourceManager.GetString("DockContentHandler_Show_InvalidBeforeContent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid DockState: Content can not be showed as "Unknown" or "Hidden".. + /// + internal static string DockContentHandler_Show_InvalidDockState { + get { + return ResourceManager.GetString("DockContentHandler_Show_InvalidDockState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The previous pane is invalid. It can not be null, and its docking state must not be auto-hide.. + /// + internal static string DockContentHandler_Show_InvalidPrevPane { + get { + return ResourceManager.GetString("DockContentHandler_Show_InvalidPrevPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DockPanel can not be null.. + /// + internal static string DockContentHandler_Show_NullDockPanel { + get { + return ResourceManager.GetString("DockContentHandler_Show_NullDockPanel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The Pane can not be null.. + /// + internal static string DockContentHandler_Show_NullPane { + get { + return ResourceManager.GetString("DockContentHandler_Show_NullPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid value, check DockableAreas property.. + /// + internal static string DockContentHandler_ShowHint_InvalidValue { + get { + return ResourceManager.GetString("DockContentHandler_ShowHint_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Context menu displayed for the dock pane tab strip.. + /// + internal static string DockHandler_TabPageContextMenuStrip_Description { + get { + return ResourceManager.GetString("DockHandler_TabPageContextMenuStrip_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Press SHIFT for docking to full side.. + /// + internal static string DockIndicator_ToolTipText { + get { + return ResourceManager.GetString("DockIndicator_ToolTipText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Content: ActiveContent must be one of the visible contents, or null if there is no visible content.. + /// + internal static string DockPane_ActiveContent_InvalidValue { + get { + return ResourceManager.GetString("DockPane_ActiveContent_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid argument: Content can not be "null".. + /// + internal static string DockPane_Constructor_NullContent { + get { + return ResourceManager.GetString("DockPane_Constructor_NullContent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid argument: The content's DockPanel can not be "null".. + /// + internal static string DockPane_Constructor_NullDockPanel { + get { + return ResourceManager.GetString("DockPane_Constructor_NullDockPanel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified container conflicts with the IsFloat property.. + /// + internal static string DockPane_DockTo_InvalidContainer { + get { + return ResourceManager.GetString("DockPane_DockTo_InvalidContainer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The previous pane does not exist in the nested docking pane collection.. + /// + internal static string DockPane_DockTo_NoPrevPane { + get { + return ResourceManager.GetString("DockPane_DockTo_NoPrevPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The container can not be null.. + /// + internal static string DockPane_DockTo_NullContainer { + get { + return ResourceManager.GetString("DockPane_DockTo_NullContainer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The previous pane can not be null when the nested docking pane collection is not empty.. + /// + internal static string DockPane_DockTo_NullPrevPane { + get { + return ResourceManager.GetString("DockPane_DockTo_NullPrevPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The previous pane can not be itself.. + /// + internal static string DockPane_DockTo_SelfPrevPane { + get { + return ResourceManager.GetString("DockPane_DockTo_SelfPrevPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FloatWindow property can not be set to "null" when DockState is DockState.Float.. + /// + internal static string DockPane_FloatWindow_InvalidValue { + get { + return ResourceManager.GetString("DockPane_FloatWindow_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Content: Content not within the collection.. + /// + internal static string DockPane_SetContentIndex_InvalidContent { + get { + return ResourceManager.GetString("DockPane_SetContentIndex_InvalidContent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Index: The index is out of range.. + /// + internal static string DockPane_SetContentIndex_InvalidIndex { + get { + return ResourceManager.GetString("DockPane_SetContentIndex_InvalidIndex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The state for the dock pane is invalid.. + /// + internal static string DockPane_SetDockState_InvalidState { + get { + return ResourceManager.GetString("DockPane_SetDockState_InvalidState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Auto Hide. + /// + internal static string DockPaneCaption_ToolTipAutoHide { + get { + return ResourceManager.GetString("DockPaneCaption_ToolTipAutoHide", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Close. + /// + internal static string DockPaneCaption_ToolTipClose { + get { + return ResourceManager.GetString("DockPaneCaption_ToolTipClose", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Options. + /// + internal static string DockPaneCaption_ToolTipOptions { + get { + return ResourceManager.GetString("DockPaneCaption_ToolTipOptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Content: The content must be auto-hide state and associates with this DockPanel.. + /// + internal static string DockPanel_ActiveAutoHideContent_InvalidValue { + get { + return ResourceManager.GetString("DockPanel_ActiveAutoHideContent_InvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when the value of ActiveContentProperty changed.. + /// + internal static string DockPanel_ActiveContentChanged_Description { + get { + return ResourceManager.GetString("DockPanel_ActiveContentChanged_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when the value of ActiveDocument property changed.. + /// + internal static string DockPanel_ActiveDocumentChanged_Description { + get { + return ResourceManager.GetString("DockPanel_ActiveDocumentChanged_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when the value of ActivePane property changed.. + /// + internal static string DockPanel_ActivePaneChanged_Description { + get { + return ResourceManager.GetString("DockPanel_ActivePaneChanged_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines if the drag and drop docking is allowed.. + /// + internal static string DockPanel_AllowEndUserDocking_Description { + get { + return ResourceManager.GetString("DockPanel_AllowEndUserDocking_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines if the drag and drop nested docking is allowed.. + /// + internal static string DockPanel_AllowEndUserNestedDocking_Description { + get { + return ResourceManager.GetString("DockPanel_AllowEndUserNestedDocking_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when a content added to the DockPanel.. + /// + internal static string DockPanel_ContentAdded_Description { + get { + return ResourceManager.GetString("DockPanel_ContentAdded_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Occurs when a content removed from the DockPanel.. + /// + internal static string DockPanel_ContentRemoved_Description { + get { + return ResourceManager.GetString("DockPanel_ContentRemoved_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The default size of float window.. + /// + internal static string DockPanel_DefaultFloatWindowSize_Description { + get { + return ResourceManager.GetString("DockPanel_DefaultFloatWindowSize_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provides Visual Studio .Net style docking.. + /// + internal static string DockPanel_Description { + get { + return ResourceManager.GetString("DockPanel_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Size of the bottom docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels.. + /// + internal static string DockPanel_DockBottomPortion_Description { + get { + return ResourceManager.GetString("DockPanel_DockBottomPortion_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Size of the left docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels.. + /// + internal static string DockPanel_DockLeftPortion_Description { + get { + return ResourceManager.GetString("DockPanel_DockLeftPortion_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The visual skin to use when displaying the docked windows.. + /// + internal static string DockPanel_DockPanelSkin { + get { + return ResourceManager.GetString("DockPanel_DockPanelSkin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Size of the right docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels.. + /// + internal static string DockPanel_DockRightPortion_Description { + get { + return ResourceManager.GetString("DockPanel_DockRightPortion_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Size of the top docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels.. + /// + internal static string DockPanel_DockTopPortion_Description { + get { + return ResourceManager.GetString("DockPanel_DockTopPortion_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The style of the document window.. + /// + internal static string DockPanel_DocumentStyle_Description { + get { + return ResourceManager.GetString("DockPanel_DocumentStyle_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines where the tab strip for Document style content is drawn.. + /// + internal static string DockPanel_DocumentTabStripLocation { + get { + return ResourceManager.GetString("DockPanel_DocumentTabStripLocation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The DockPanel has already been initialized.. + /// + internal static string DockPanel_LoadFromXml_AlreadyInitialized { + get { + return ResourceManager.GetString("DockPanel_LoadFromXml_AlreadyInitialized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The configuration file's version is invalid.. + /// + internal static string DockPanel_LoadFromXml_InvalidFormatVersion { + get { + return ResourceManager.GetString("DockPanel_LoadFromXml_InvalidFormatVersion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The XML file format is invalid.. + /// + internal static string DockPanel_LoadFromXml_InvalidXmlFormat { + get { + return ResourceManager.GetString("DockPanel_LoadFromXml_InvalidXmlFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid parent form. When using DockingMdi or SystemMdi document style, the DockPanel control must be the child control of the main MDI container form.. + /// + internal static string DockPanel_ParentForm_Invalid { + get { + return ResourceManager.GetString("DockPanel_ParentForm_Invalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DockPanel configuration file. Author: Weifen Luo, all rights reserved.. + /// + internal static string DockPanel_Persistor_XmlFileComment1 { + get { + return ResourceManager.GetString("DockPanel_Persistor_XmlFileComment1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to !!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!!. + /// + internal static string DockPanel_Persistor_XmlFileComment2 { + get { + return ResourceManager.GetString("DockPanel_Persistor_XmlFileComment2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Indicates whether the control layout is right-to-left when the RightToLeft property is set to Yes.. + /// + internal static string DockPanel_RightToLeftLayout_Description { + get { + return ResourceManager.GetString("DockPanel_RightToLeftLayout_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Index: The index is out of range.. + /// + internal static string DockPanel_SetPaneIndex_InvalidIndex { + get { + return ResourceManager.GetString("DockPanel_SetPaneIndex_InvalidIndex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Pane: DockPane not within the collection.. + /// + internal static string DockPanel_SetPaneIndex_InvalidPane { + get { + return ResourceManager.GetString("DockPanel_SetPaneIndex_InvalidPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines if the document icon will be displayed in the tab strip.. + /// + internal static string DockPanel_ShowDocumentIcon_Description { + get { + return ResourceManager.GetString("DockPanel_ShowDocumentIcon_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Close. + /// + internal static string DockPaneStrip_ToolTipClose { + get { + return ResourceManager.GetString("DockPaneStrip_ToolTipClose", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Window List. + /// + internal static string DockPaneStrip_ToolTipWindowList { + get { + return ResourceManager.GetString("DockPaneStrip_ToolTipWindowList", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid argument: DockPanel can not be "null".. + /// + internal static string FloatWindow_Constructor_NullDockPanel { + get { + return ResourceManager.GetString("FloatWindow_Constructor_NullDockPanel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Index: The index is out of range.. + /// + internal static string FloatWindow_SetPaneIndex_InvalidIndex { + get { + return ResourceManager.GetString("FloatWindow_SetPaneIndex_InvalidIndex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Pane: DockPane not within the collection.. + /// + internal static string FloatWindow_SetPaneIndex_InvalidPane { + get { + return ResourceManager.GetString("FloatWindow_SetPaneIndex_InvalidPane", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid DockPanel.. + /// + internal static string IDockDragSource_DockTo_InvalidPanel { + get { + return ResourceManager.GetString("IDockDragSource_DockTo_InvalidPanel", resourceCulture); + } + } + } +} diff --git a/trunk/Docking/Strings.resx b/trunk/Docking/Strings.resx new file mode 100644 index 0000000..d5ff49d --- /dev/null +++ b/trunk/Docking/Strings.resx @@ -0,0 +1,357 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Docking + + + Docking Notification + + + Property Changed + + + (Float) + + + Determines if end user drag and drop docking is allowed. + + + The size to display the content in auto hide mode. Value < 1 to specify the size in portion; value >= 1 to specify the size in pixel. + + + Enable/Disable the close button of the content. + + + The form must be of type IDockContent. + + + Gets or sets a value indicating in which area of the DockPanel the content allowed to show. + + + Occurs when the value of DockState property changed. + + + Indicates the content will be hidden instead of being closed. + + + The desired docking state when first showing. + + + Context menu displayed for the dock pane tab strip. + + + The tab text displayed in the dock pane. If not set, the Text property will be used. + + + The text displayed when mouse hovers over the tab. + + + The provided value is out of range. + + + Invalid Value: The value of DockAreas conflicts with current DockState. + + + The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane. + + + The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane. + + + Invalid value, conflicts with DockableAreas property. + + + The dock state is invalid. + + + The dock panel is null. + + + Invalid beforeContent, it must be contained by the pane. + + + Invalid DockState: Content can not be showed as "Unknown" or "Hidden". + + + The previous pane is invalid. It can not be null, and its docking state must not be auto-hide. + + + DockPanel can not be null. + + + The Pane can not be null. + + + Invalid value, check DockableAreas property. + + + Context menu displayed for the dock pane tab strip. + + + Press SHIFT for docking to full side. + + + Invalid Content: ActiveContent must be one of the visible contents, or null if there is no visible content. + + + Invalid argument: Content can not be "null". + + + Invalid argument: The content's DockPanel can not be "null". + + + The specified container conflicts with the IsFloat property. + + + The previous pane does not exist in the nested docking pane collection. + + + The container can not be null. + + + The previous pane can not be null when the nested docking pane collection is not empty. + + + The previous pane can not be itself. + + + FloatWindow property can not be set to "null" when DockState is DockState.Float. + + + Invalid Content: Content not within the collection. + + + Invalid Index: The index is out of range. + + + The state for the dock pane is invalid. + + + Auto Hide + + + Close + + + Options + + + Invalid Content: The content must be auto-hide state and associates with this DockPanel. + + + Occurs when the value of ActiveContentProperty changed. + + + Occurs when the value of ActiveDocument property changed. + + + Occurs when the value of ActivePane property changed. + + + Determines if the drag and drop docking is allowed. + + + Determines if the drag and drop nested docking is allowed. + + + Occurs when a content added to the DockPanel. + + + Occurs when a content removed from the DockPanel. + + + The default size of float window. + + + Provides Visual Studio .Net style docking. + + + Size of the bottom docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels. + + + Size of the left docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels. + + + Size of the right docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels. + + + Size of the top docking window. Value < 1 to specify the size in portion; value > 1 to specify the size in pixels. + + + The style of the document window. + + + The DockPanel has already been initialized. + + + The configuration file's version is invalid. + + + The XML file format is invalid. + + + Invalid parent form. When using DockingMdi or SystemMdi document style, the DockPanel control must be the child control of the main MDI container form. + + + DockPanel configuration file. Author: Weifen Luo, all rights reserved. + + + !!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!! + + + Indicates whether the control layout is right-to-left when the RightToLeft property is set to Yes. + + + Invalid Index: The index is out of range. + + + Invalid Pane: DockPane not within the collection. + + + Determines if the document icon will be displayed in the tab strip. + + + Close + + + Window List + + + Invalid argument: DockPanel can not be "null". + + + Invalid Index: The index is out of range. + + + Invalid Pane: DockPane not within the collection. + + + Invalid DockPanel. + + + Shows or hides the close button of the content. This property does not function with System MDI Document Style. + + + The visual skin to use when displaying the docked windows. + + + Determines where the tab strip for Document style content is drawn. + + \ No newline at end of file diff --git a/trunk/Docking/VS2005AutoHideStrip.cs b/trunk/Docking/VS2005AutoHideStrip.cs new file mode 100644 index 0000000..1a78052 --- /dev/null +++ b/trunk/Docking/VS2005AutoHideStrip.cs @@ -0,0 +1,505 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using System.Drawing.Drawing2D; +using System.ComponentModel; + +namespace LSLEditor.Docking +{ + internal class VS2005AutoHideStrip : AutoHideStripBase + { + private class TabVS2005 : Tab + { + internal TabVS2005(IDockContent content) + : base(content) + { + } + + private int m_tabX = 0; + public int TabX + { + get { return m_tabX; } + set { m_tabX = value; } + } + + private int m_tabWidth = 0; + public int TabWidth + { + get { return m_tabWidth; } + set { m_tabWidth = value; } + } + + } + + private const int _ImageHeight = 16; + private const int _ImageWidth = 16; + private const int _ImageGapTop = 2; + private const int _ImageGapLeft = 4; + private const int _ImageGapRight = 2; + private const int _ImageGapBottom = 2; + private const int _TextGapLeft = 0; + private const int _TextGapRight = 0; + private const int _TabGapTop = 3; + private const int _TabGapLeft = 4; + private const int _TabGapBetween = 10; + + #region Customizable Properties + private static Font TextFont + { + get { return SystemInformation.MenuFont; } + } + + private static StringFormat _stringFormatTabHorizontal; + private StringFormat StringFormatTabHorizontal + { + get + { + if (_stringFormatTabHorizontal == null) + { + _stringFormatTabHorizontal = new StringFormat(); + _stringFormatTabHorizontal.Alignment = StringAlignment.Near; + _stringFormatTabHorizontal.LineAlignment = StringAlignment.Center; + _stringFormatTabHorizontal.FormatFlags = StringFormatFlags.NoWrap; + _stringFormatTabHorizontal.Trimming = StringTrimming.None; + } + + if (RightToLeft == RightToLeft.Yes) + _stringFormatTabHorizontal.FormatFlags |= StringFormatFlags.DirectionRightToLeft; + else + _stringFormatTabHorizontal.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft; + + return _stringFormatTabHorizontal; + } + } + + private static StringFormat _stringFormatTabVertical; + private StringFormat StringFormatTabVertical + { + get + { + if (_stringFormatTabVertical == null) + { + _stringFormatTabVertical = new StringFormat(); + _stringFormatTabVertical.Alignment = StringAlignment.Near; + _stringFormatTabVertical.LineAlignment = StringAlignment.Center; + _stringFormatTabVertical.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.DirectionVertical; + _stringFormatTabVertical.Trimming = StringTrimming.None; + } + if (RightToLeft == RightToLeft.Yes) + _stringFormatTabVertical.FormatFlags |= StringFormatFlags.DirectionRightToLeft; + else + _stringFormatTabVertical.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft; + + return _stringFormatTabVertical; + } + } + + private static int ImageHeight + { + get { return _ImageHeight; } + } + + private static int ImageWidth + { + get { return _ImageWidth; } + } + + private static int ImageGapTop + { + get { return _ImageGapTop; } + } + + private static int ImageGapLeft + { + get { return _ImageGapLeft; } + } + + private static int ImageGapRight + { + get { return _ImageGapRight; } + } + + private static int ImageGapBottom + { + get { return _ImageGapBottom; } + } + + private static int TextGapLeft + { + get { return _TextGapLeft; } + } + + private static int TextGapRight + { + get { return _TextGapRight; } + } + + private static int TabGapTop + { + get { return _TabGapTop; } + } + + private static int TabGapLeft + { + get { return _TabGapLeft; } + } + + private static int TabGapBetween + { + get { return _TabGapBetween; } + } + + private static Pen PenTabBorder + { + get { return SystemPens.GrayText; } + } + #endregion + + private static Matrix _matrixIdentity = new Matrix(); + private static Matrix MatrixIdentity + { + get { return _matrixIdentity; } + } + + private static DockState[] _dockStates; + private static DockState[] DockStates + { + get + { + if (_dockStates == null) + { + _dockStates = new DockState[4]; + _dockStates[0] = DockState.DockLeftAutoHide; + _dockStates[1] = DockState.DockRightAutoHide; + _dockStates[2] = DockState.DockTopAutoHide; + _dockStates[3] = DockState.DockBottomAutoHide; + } + return _dockStates; + } + } + + private static GraphicsPath _graphicsPath; + internal static GraphicsPath GraphicsPath + { + get + { + if (_graphicsPath == null) + _graphicsPath = new GraphicsPath(); + + return _graphicsPath; + } + } + + public VS2005AutoHideStrip(DockPanel panel) : base(panel) + { + SetStyle(ControlStyles.ResizeRedraw | + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer, true); + BackColor = SystemColors.ControlLight; + } + + protected override void OnPaint(PaintEventArgs e) + { + Graphics g = e.Graphics; + + Color startColor = DockPanel.Skin.AutoHideStripSkin.DockStripGradient.StartColor; + Color endColor = DockPanel.Skin.AutoHideStripSkin.DockStripGradient.EndColor; + LinearGradientMode gradientMode = DockPanel.Skin.AutoHideStripSkin.DockStripGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode)) + { + g.FillRectangle(brush, ClientRectangle); + } + + DrawTabStrip(g); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + CalculateTabs(); + base.OnLayout (levent); + } + + private void DrawTabStrip(Graphics g) + { + DrawTabStrip(g, DockState.DockTopAutoHide); + DrawTabStrip(g, DockState.DockBottomAutoHide); + DrawTabStrip(g, DockState.DockLeftAutoHide); + DrawTabStrip(g, DockState.DockRightAutoHide); + } + + private void DrawTabStrip(Graphics g, DockState dockState) + { + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + + if (rectTabStrip.IsEmpty) + return; + + Matrix matrixIdentity = g.Transform; + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + { + Matrix matrixRotated = new Matrix(); + matrixRotated.RotateAt(90, new PointF((float)rectTabStrip.X + (float)rectTabStrip.Height / 2, + (float)rectTabStrip.Y + (float)rectTabStrip.Height / 2)); + g.Transform = matrixRotated; + } + + foreach (Pane pane in GetPanes(dockState)) + { + foreach (TabVS2005 tab in pane.AutoHideTabs) + DrawTab(g, tab); + } + g.Transform = matrixIdentity; + } + + private void CalculateTabs() + { + CalculateTabs(DockState.DockTopAutoHide); + CalculateTabs(DockState.DockBottomAutoHide); + CalculateTabs(DockState.DockLeftAutoHide); + CalculateTabs(DockState.DockRightAutoHide); + } + + private void CalculateTabs(DockState dockState) + { + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + + int imageHeight = rectTabStrip.Height - ImageGapTop - ImageGapBottom; + int imageWidth = ImageWidth; + if (imageHeight > ImageHeight) + imageWidth = ImageWidth * (imageHeight / ImageHeight); + + int x = TabGapLeft + rectTabStrip.X; + foreach (Pane pane in GetPanes(dockState)) + { + foreach (TabVS2005 tab in pane.AutoHideTabs) + { + int width = imageWidth + ImageGapLeft + ImageGapRight + + TextRenderer.MeasureText(tab.Content.DockHandler.TabText, TextFont).Width + + TextGapLeft + TextGapRight; + tab.TabX = x; + tab.TabWidth = width; + x += width; + } + + x += TabGapBetween; + } + } + + private Rectangle RtlTransform(Rectangle rect, DockState dockState) + { + Rectangle rectTransformed; + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + rectTransformed = rect; + else + rectTransformed = DrawHelper.RtlTransform(this, rect); + + return rectTransformed; + } + + private GraphicsPath GetTabOutline(TabVS2005 tab, bool transformed, bool rtlTransform) + { + DockState dockState = tab.Content.DockHandler.DockState; + Rectangle rectTab = GetTabRectangle(tab, transformed); + if (rtlTransform) + rectTab = RtlTransform(rectTab, dockState); + bool upTab = (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockBottomAutoHide); + DrawHelper.GetRoundedCornerTab(GraphicsPath, rectTab, upTab); + + return GraphicsPath; + } + + private void DrawTab(Graphics g, TabVS2005 tab) + { + Rectangle rectTabOrigin = GetTabRectangle(tab); + if (rectTabOrigin.IsEmpty) + return; + + DockState dockState = tab.Content.DockHandler.DockState; + IDockContent content = tab.Content; + + GraphicsPath path = GetTabOutline(tab, false, true); + + Color startColor = DockPanel.Skin.AutoHideStripSkin.TabGradient.StartColor; + Color endColor = DockPanel.Skin.AutoHideStripSkin.TabGradient.EndColor; + LinearGradientMode gradientMode = DockPanel.Skin.AutoHideStripSkin.TabGradient.LinearGradientMode; + g.FillPath(new LinearGradientBrush(rectTabOrigin, startColor, endColor, gradientMode), path); + g.DrawPath(PenTabBorder, path); + + // Set no rotate for drawing icon and text + Matrix matrixRotate = g.Transform; + g.Transform = MatrixIdentity; + + // Draw the icon + Rectangle rectImage = rectTabOrigin; + rectImage.X += ImageGapLeft; + rectImage.Y += ImageGapTop; + int imageHeight = rectTabOrigin.Height - ImageGapTop - ImageGapBottom; + int imageWidth = ImageWidth; + if (imageHeight > ImageHeight) + imageWidth = ImageWidth * (imageHeight/ImageHeight); + rectImage.Height = imageHeight; + rectImage.Width = imageWidth; + rectImage = GetTransformedRectangle(dockState, rectImage); + g.DrawIcon(((Form)content).Icon, RtlTransform(rectImage, dockState)); + + // Draw the text + Rectangle rectText = rectTabOrigin; + rectText.X += ImageGapLeft + imageWidth + ImageGapRight + TextGapLeft; + rectText.Width -= ImageGapLeft + imageWidth + ImageGapRight + TextGapLeft; + rectText = RtlTransform(GetTransformedRectangle(dockState, rectText), dockState); + + Color textColor = DockPanel.Skin.AutoHideStripSkin.TabGradient.TextColor; + + if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide) + g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabVertical); + else + g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabHorizontal); + + // Set rotate back + g.Transform = matrixRotate; + } + + private Rectangle GetLogicalTabStripRectangle(DockState dockState) + { + return GetLogicalTabStripRectangle(dockState, false); + } + + private Rectangle GetLogicalTabStripRectangle(DockState dockState, bool transformed) + { + if (!DockHelper.IsDockStateAutoHide(dockState)) + return Rectangle.Empty; + + int leftPanes = GetPanes(DockState.DockLeftAutoHide).Count; + int rightPanes = GetPanes(DockState.DockRightAutoHide).Count; + int topPanes = GetPanes(DockState.DockTopAutoHide).Count; + int bottomPanes = GetPanes(DockState.DockBottomAutoHide).Count; + + int x, y, width, height; + + height = MeasureHeight(); + if (dockState == DockState.DockLeftAutoHide && leftPanes > 0) + { + x = 0; + y = (topPanes == 0) ? 0 : height; + width = Height - (topPanes == 0 ? 0 : height) - (bottomPanes == 0 ? 0 :height); + } + else if (dockState == DockState.DockRightAutoHide && rightPanes > 0) + { + x = Width - height; + if (leftPanes != 0 && x < height) + x = height; + y = (topPanes == 0) ? 0 : height; + width = Height - (topPanes == 0 ? 0 : height) - (bottomPanes == 0 ? 0 :height); + } + else if (dockState == DockState.DockTopAutoHide && topPanes > 0) + { + x = leftPanes == 0 ? 0 : height; + y = 0; + width = Width - (leftPanes == 0 ? 0 : height) - (rightPanes == 0 ? 0 : height); + } + else if (dockState == DockState.DockBottomAutoHide && bottomPanes > 0) + { + x = leftPanes == 0 ? 0 : height; + y = Height - height; + if (topPanes != 0 && y < height) + y = height; + width = Width - (leftPanes == 0 ? 0 : height) - (rightPanes == 0 ? 0 : height); + } + else + return Rectangle.Empty; + + if (!transformed) + return new Rectangle(x, y, width, height); + else + return GetTransformedRectangle(dockState, new Rectangle(x, y, width, height)); + } + + private Rectangle GetTabRectangle(TabVS2005 tab) + { + return GetTabRectangle(tab, false); + } + + private Rectangle GetTabRectangle(TabVS2005 tab, bool transformed) + { + DockState dockState = tab.Content.DockHandler.DockState; + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + + if (rectTabStrip.IsEmpty) + return Rectangle.Empty; + + int x = tab.TabX; + int y = rectTabStrip.Y + + (dockState == DockState.DockTopAutoHide || dockState == DockState.DockRightAutoHide ? + 0 : TabGapTop); + int width = tab.TabWidth; + int height = rectTabStrip.Height - TabGapTop; + + if (!transformed) + return new Rectangle(x, y, width, height); + else + return GetTransformedRectangle(dockState, new Rectangle(x, y, width, height)); + } + + private Rectangle GetTransformedRectangle(DockState dockState, Rectangle rect) + { + if (dockState != DockState.DockLeftAutoHide && dockState != DockState.DockRightAutoHide) + return rect; + + PointF[] pts = new PointF[1]; + // the center of the rectangle + pts[0].X = (float)rect.X + (float)rect.Width / 2; + pts[0].Y = (float)rect.Y + (float)rect.Height / 2; + Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState); + Matrix matrix = new Matrix(); + matrix.RotateAt(90, new PointF((float)rectTabStrip.X + (float)rectTabStrip.Height / 2, + (float)rectTabStrip.Y + (float)rectTabStrip.Height / 2)); + matrix.TransformPoints(pts); + + return new Rectangle((int)(pts[0].X - (float)rect.Height / 2 + .5F), + (int)(pts[0].Y - (float)rect.Width / 2 + .5F), + rect.Height, rect.Width); + } + + protected override IDockContent HitTest(Point ptMouse) + { + foreach(DockState state in DockStates) + { + Rectangle rectTabStrip = GetLogicalTabStripRectangle(state, true); + if (!rectTabStrip.Contains(ptMouse)) + continue; + + foreach(Pane pane in GetPanes(state)) + { + DockState dockState = pane.DockPane.DockState; + foreach(TabVS2005 tab in pane.AutoHideTabs) + { + GraphicsPath path = GetTabOutline(tab, true, true); + if (path.IsVisible(ptMouse)) + return tab.Content; + } + } + } + + return null; + } + + protected internal override int MeasureHeight() + { + return Math.Max(ImageGapBottom + + ImageGapTop + ImageHeight, + TextFont.Height) + TabGapTop; + } + + protected override void OnRefreshChanges() + { + CalculateTabs(); + Invalidate(); + } + + protected override AutoHideStripBase.Tab CreateTab(IDockContent content) + { + return new TabVS2005(content); + } + } +} diff --git a/trunk/Docking/VS2005DockPaneCaption.cs b/trunk/Docking/VS2005DockPaneCaption.cs new file mode 100644 index 0000000..1a738e5 --- /dev/null +++ b/trunk/Docking/VS2005DockPaneCaption.cs @@ -0,0 +1,478 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using System.ComponentModel; +using System.Windows.Forms.VisualStyles; + +namespace LSLEditor.Docking +{ + internal class VS2005DockPaneCaption : DockPaneCaptionBase + { + private sealed class InertButton : InertButtonBase + { + private Bitmap m_image, m_imageAutoHide; + + public InertButton(VS2005DockPaneCaption dockPaneCaption, Bitmap image, Bitmap imageAutoHide) + : base() + { + m_dockPaneCaption = dockPaneCaption; + m_image = image; + m_imageAutoHide = imageAutoHide; + RefreshChanges(); + } + + private VS2005DockPaneCaption m_dockPaneCaption; + private VS2005DockPaneCaption DockPaneCaption + { + get { return m_dockPaneCaption; } + } + + public bool IsAutoHide + { + get { return DockPaneCaption.DockPane.IsAutoHide; } + } + + public override Bitmap Image + { + get { return IsAutoHide ? m_imageAutoHide : m_image; } + } + + protected override void OnRefreshChanges() + { + if (DockPaneCaption.DockPane.DockPanel != null) + { + if (DockPaneCaption.TextColor != ForeColor) + { + ForeColor = DockPaneCaption.TextColor; + Invalidate(); + } + } + } + } + + #region consts + private const int _TextGapTop = 2; + private const int _TextGapBottom = 0; + private const int _TextGapLeft = 3; + private const int _TextGapRight = 3; + private const int _ButtonGapTop = 2; + private const int _ButtonGapBottom = 1; + private const int _ButtonGapBetween = 1; + private const int _ButtonGapLeft = 1; + private const int _ButtonGapRight = 2; + #endregion + + private static Bitmap _imageButtonClose; + private static Bitmap ImageButtonClose + { + get + { + if (_imageButtonClose == null) + _imageButtonClose = Resources.DockPane_Close; + + return _imageButtonClose; + } + } + + private InertButton m_buttonClose; + private InertButton ButtonClose + { + get + { + if (m_buttonClose == null) + { + m_buttonClose = new InertButton(this, ImageButtonClose, ImageButtonClose); + m_toolTip.SetToolTip(m_buttonClose, ToolTipClose); + m_buttonClose.Click += new EventHandler(Close_Click); + Controls.Add(m_buttonClose); + } + + return m_buttonClose; + } + } + + private static Bitmap _imageButtonAutoHide; + private static Bitmap ImageButtonAutoHide + { + get + { + if (_imageButtonAutoHide == null) + _imageButtonAutoHide = Resources.DockPane_AutoHide; + + return _imageButtonAutoHide; + } + } + + private static Bitmap _imageButtonDock; + private static Bitmap ImageButtonDock + { + get + { + if (_imageButtonDock == null) + _imageButtonDock = Resources.DockPane_Dock; + + return _imageButtonDock; + } + } + + private InertButton m_buttonAutoHide; + private InertButton ButtonAutoHide + { + get + { + if (m_buttonAutoHide == null) + { + m_buttonAutoHide = new InertButton(this, ImageButtonDock, ImageButtonAutoHide); + m_toolTip.SetToolTip(m_buttonAutoHide, ToolTipAutoHide); + m_buttonAutoHide.Click += new EventHandler(AutoHide_Click); + Controls.Add(m_buttonAutoHide); + } + + return m_buttonAutoHide; + } + } + + private static Bitmap _imageButtonOptions; + private static Bitmap ImageButtonOptions + { + get + { + if (_imageButtonOptions == null) + _imageButtonOptions = Resources.DockPane_Option; + + return _imageButtonOptions; + } + } + + private InertButton m_buttonOptions; + private InertButton ButtonOptions + { + get + { + if (m_buttonOptions == null) + { + m_buttonOptions = new InertButton(this, ImageButtonOptions, ImageButtonOptions); + m_toolTip.SetToolTip(m_buttonOptions, ToolTipOptions); + m_buttonOptions.Click += new EventHandler(Options_Click); + Controls.Add(m_buttonOptions); + } + return m_buttonOptions; + } + } + + private IContainer m_components; + private IContainer Components + { + get { return m_components; } + } + + private ToolTip m_toolTip; + + public VS2005DockPaneCaption(DockPane pane) : base(pane) + { + SuspendLayout(); + + m_components = new Container(); + m_toolTip = new ToolTip(Components); + + ResumeLayout(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + Components.Dispose(); + base.Dispose(disposing); + } + + private static int TextGapTop + { + get { return _TextGapTop; } + } + + private static Font TextFont + { + get { return SystemInformation.MenuFont; } + } + + private static int TextGapBottom + { + get { return _TextGapBottom; } + } + + private static int TextGapLeft + { + get { return _TextGapLeft; } + } + + private static int TextGapRight + { + get { return _TextGapRight; } + } + + private static int ButtonGapTop + { + get { return _ButtonGapTop; } + } + + private static int ButtonGapBottom + { + get { return _ButtonGapBottom; } + } + + private static int ButtonGapLeft + { + get { return _ButtonGapLeft; } + } + + private static int ButtonGapRight + { + get { return _ButtonGapRight; } + } + + private static int ButtonGapBetween + { + get { return _ButtonGapBetween; } + } + + private static string _toolTipClose; + private static string ToolTipClose + { + get + { + if (_toolTipClose == null) + _toolTipClose = Strings.DockPaneCaption_ToolTipClose; + return _toolTipClose; + } + } + + private static string _toolTipOptions; + private static string ToolTipOptions + { + get + { + if (_toolTipOptions == null) + _toolTipOptions = Strings.DockPaneCaption_ToolTipOptions; + + return _toolTipOptions; + } + } + + private static string _toolTipAutoHide; + private static string ToolTipAutoHide + { + get + { + if (_toolTipAutoHide == null) + _toolTipAutoHide = Strings.DockPaneCaption_ToolTipAutoHide; + return _toolTipAutoHide; + } + } + + private static Blend _activeBackColorGradientBlend; + private static Blend ActiveBackColorGradientBlend + { + get + { + if (_activeBackColorGradientBlend == null) + { + Blend blend = new Blend(2); + + blend.Factors = new float[]{0.5F, 1.0F}; + blend.Positions = new float[]{0.0F, 1.0F}; + _activeBackColorGradientBlend = blend; + } + + return _activeBackColorGradientBlend; + } + } + + private Color TextColor + { + get + { + if (DockPane.IsActivated) + return DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.TextColor; + else + return DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.TextColor; + } + } + + private static TextFormatFlags _textFormat = + TextFormatFlags.SingleLine | + TextFormatFlags.EndEllipsis | + TextFormatFlags.VerticalCenter; + private TextFormatFlags TextFormat + { + get + { + if (RightToLeft == RightToLeft.No) + return _textFormat; + else + return _textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right; + } + } + + protected internal override int MeasureHeight() + { + int height = TextFont.Height + TextGapTop + TextGapBottom; + + if (height < ButtonClose.Image.Height + ButtonGapTop + ButtonGapBottom) + height = ButtonClose.Image.Height + ButtonGapTop + ButtonGapBottom; + + return height; + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint (e); + DrawCaption(e.Graphics); + } + + private void DrawCaption(Graphics g) + { + if (ClientRectangle.Width == 0 || ClientRectangle.Height == 0) + return; + + if (DockPane.IsActivated) + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode)) + { + brush.Blend = ActiveBackColorGradientBlend; + g.FillRectangle(brush, ClientRectangle); + } + } + else + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode)) + { + g.FillRectangle(brush, ClientRectangle); + } + } + + Rectangle rectCaption = ClientRectangle; + + Rectangle rectCaptionText = rectCaption; + rectCaptionText.X += TextGapLeft; + rectCaptionText.Width -= TextGapLeft + TextGapRight; + rectCaptionText.Width -= ButtonGapLeft + ButtonClose.Width + ButtonGapRight; + if (ShouldShowAutoHideButton) + rectCaptionText.Width -= ButtonAutoHide.Width + ButtonGapBetween; + if (HasTabPageContextMenu) + rectCaptionText.Width -= ButtonOptions.Width + ButtonGapBetween; + rectCaptionText.Y += TextGapTop; + rectCaptionText.Height -= TextGapTop + TextGapBottom; + + Color colorText; + if (DockPane.IsActivated) + colorText = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.TextColor; + else + colorText = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.TextColor; + + TextRenderer.DrawText(g, DockPane.CaptionText, TextFont, DrawHelper.RtlTransform(this, rectCaptionText), colorText, TextFormat); + } + + protected override void OnLayout(LayoutEventArgs levent) + { + SetButtonsPosition(); + base.OnLayout (levent); + } + + protected override void OnRefreshChanges() + { + SetButtons(); + Invalidate(); + } + + private bool CloseButtonEnabled + { + get { return (DockPane.ActiveContent != null)? DockPane.ActiveContent.DockHandler.CloseButton : false; } + } + + /// + /// Determines whether the close button is visible on the content + /// + private bool CloseButtonVisible + { + get { return (DockPane.ActiveContent != null) ? DockPane.ActiveContent.DockHandler.CloseButtonVisible : false; } + } + + private bool ShouldShowAutoHideButton + { + get { return !DockPane.IsFloat; } + } + + private void SetButtons() + { + ButtonClose.Enabled = CloseButtonEnabled; + ButtonClose.Visible = CloseButtonVisible; + ButtonAutoHide.Visible = ShouldShowAutoHideButton; + ButtonOptions.Visible = HasTabPageContextMenu; + ButtonClose.RefreshChanges(); + ButtonAutoHide.RefreshChanges(); + ButtonOptions.RefreshChanges(); + + SetButtonsPosition(); + } + + private void SetButtonsPosition() + { + // set the size and location for close and auto-hide buttons + Rectangle rectCaption = ClientRectangle; + int buttonWidth = ButtonClose.Image.Width; + int buttonHeight = ButtonClose.Image.Height; + int height = rectCaption.Height - ButtonGapTop - ButtonGapBottom; + if (buttonHeight < height) + { + buttonWidth = buttonWidth * (height / buttonHeight); + buttonHeight = height; + } + Size buttonSize = new Size(buttonWidth, buttonHeight); + int x = rectCaption.X + rectCaption.Width - 1 - ButtonGapRight - m_buttonClose.Width; + int y = rectCaption.Y + ButtonGapTop; + Point point = new Point(x, y); + ButtonClose.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + + // If the close button is not visible draw the auto hide button overtop. + // Otherwise it is drawn to the left of the close button. + if (CloseButtonVisible) + point.Offset(-(buttonWidth + ButtonGapBetween), 0); + + ButtonAutoHide.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + if (ShouldShowAutoHideButton) + point.Offset(-(buttonWidth + ButtonGapBetween), 0); + ButtonOptions.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize)); + } + + private void Close_Click(object sender, EventArgs e) + { + DockPane.CloseActiveContent(); + } + + private void AutoHide_Click(object sender, EventArgs e) + { + DockPane.DockState = DockHelper.ToggleAutoHideState(DockPane.DockState); + if (DockHelper.IsDockStateAutoHide(DockPane.DockState)) + DockPane.DockPanel.ActiveAutoHideContent = null; + + } + + private void Options_Click(object sender, EventArgs e) + { + ShowTabPageContextMenu(PointToClient(Control.MousePosition)); + } + + protected override void OnRightToLeftChanged(EventArgs e) + { + base.OnRightToLeftChanged(e); + PerformLayout(); + } + } +} diff --git a/trunk/Docking/VS2005DockPaneStrip.cs b/trunk/Docking/VS2005DockPaneStrip.cs new file mode 100644 index 0000000..042a906 --- /dev/null +++ b/trunk/Docking/VS2005DockPaneStrip.cs @@ -0,0 +1,1479 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using System.ComponentModel; +using System.Collections; +using System.Collections.Generic; + +namespace LSLEditor.Docking +{ + internal class VS2005DockPaneStrip : DockPaneStripBase + { + private class TabVS2005 : Tab + { + public TabVS2005(IDockContent content) + : base(content) + { + } + + private int m_tabX; + public int TabX + { + get { return m_tabX; } + set { m_tabX = value; } + } + + private int m_tabWidth; + public int TabWidth + { + get { return m_tabWidth; } + set { m_tabWidth = value; } + } + + private int m_maxWidth; + public int MaxWidth + { + get { return m_maxWidth; } + set { m_maxWidth = value; } + } + + private bool m_flag; + protected internal bool Flag + { + get { return m_flag; } + set { m_flag = value; } + } + } + + protected internal override DockPaneStripBase.Tab CreateTab(IDockContent content) + { + return new TabVS2005(content); + } + + private sealed class InertButton : InertButtonBase + { + private Bitmap m_image0, m_image1; + + public InertButton(Bitmap image0, Bitmap image1) + : base() + { + m_image0 = image0; + m_image1 = image1; + } + + private int m_imageCategory = 0; + public int ImageCategory + { + get { return m_imageCategory; } + set + { + if (m_imageCategory == value) + return; + + m_imageCategory = value; + Invalidate(); + } + } + + public override Bitmap Image + { + get { return ImageCategory == 0 ? m_image0 : m_image1; } + } + } + + #region consts + private const int _ToolWindowStripGapTop = 0; + private const int _ToolWindowStripGapBottom = 1; + private const int _ToolWindowStripGapLeft = 0; + private const int _ToolWindowStripGapRight = 0; + private const int _ToolWindowImageHeight = 16; + private const int _ToolWindowImageWidth = 16; + private const int _ToolWindowImageGapTop = 3; + private const int _ToolWindowImageGapBottom = 1; + private const int _ToolWindowImageGapLeft = 2; + private const int _ToolWindowImageGapRight = 0; + private const int _ToolWindowTextGapRight = 3; + private const int _ToolWindowTabSeperatorGapTop = 3; + private const int _ToolWindowTabSeperatorGapBottom = 3; + + private const int _DocumentStripGapTop = 0; + private const int _DocumentStripGapBottom = 1; + private const int _DocumentTabMaxWidth = 200; + private const int _DocumentButtonGapTop = 4; + private const int _DocumentButtonGapBottom = 4; + private const int _DocumentButtonGapBetween = 0; + private const int _DocumentButtonGapRight = 3; + private const int _DocumentTabGapTop = 3; + private const int _DocumentTabGapLeft = 3; + private const int _DocumentTabGapRight = 3; + private const int _DocumentIconGapBottom = 2; + private const int _DocumentIconGapLeft = 8; + private const int _DocumentIconGapRight = 0; + private const int _DocumentIconHeight = 16; + private const int _DocumentIconWidth = 16; + private const int _DocumentTextGapRight = 3; + #endregion + + private static Bitmap _imageButtonClose; + private static Bitmap ImageButtonClose + { + get + { + if (_imageButtonClose == null) + _imageButtonClose = Resources.DockPane_Close; + + return _imageButtonClose; + } + } + + private InertButton m_buttonClose; + private InertButton ButtonClose + { + get + { + if (m_buttonClose == null) + { + m_buttonClose = new InertButton(ImageButtonClose, ImageButtonClose); + m_toolTip.SetToolTip(m_buttonClose, ToolTipClose); + m_buttonClose.Click += new EventHandler(Close_Click); + Controls.Add(m_buttonClose); + } + + return m_buttonClose; + } + } + + private static Bitmap _imageButtonWindowList; + private static Bitmap ImageButtonWindowList + { + get + { + if (_imageButtonWindowList == null) + _imageButtonWindowList = Resources.DockPane_Option; + + return _imageButtonWindowList; + } + } + + private static Bitmap _imageButtonWindowListOverflow; + private static Bitmap ImageButtonWindowListOverflow + { + get + { + if (_imageButtonWindowListOverflow == null) + _imageButtonWindowListOverflow = Resources.DockPane_OptionOverflow; + + return _imageButtonWindowListOverflow; + } + } + + private InertButton m_buttonWindowList; + private InertButton ButtonWindowList + { + get + { + if (m_buttonWindowList == null) + { + m_buttonWindowList = new InertButton(ImageButtonWindowList, ImageButtonWindowListOverflow); + m_toolTip.SetToolTip(m_buttonWindowList, ToolTipSelect); + m_buttonWindowList.Click += new EventHandler(WindowList_Click); + Controls.Add(m_buttonWindowList); + } + + return m_buttonWindowList; + } + } + + private static GraphicsPath GraphicsPath + { + get { return VS2005AutoHideStrip.GraphicsPath; } + } + + private IContainer m_components; + private ToolTip m_toolTip; + private IContainer Components + { + get { return m_components; } + } + + #region Customizable Properties + private static int ToolWindowStripGapTop + { + get { return _ToolWindowStripGapTop; } + } + + private static int ToolWindowStripGapBottom + { + get { return _ToolWindowStripGapBottom; } + } + + private static int ToolWindowStripGapLeft + { + get { return _ToolWindowStripGapLeft; } + } + + private static int ToolWindowStripGapRight + { + get { return _ToolWindowStripGapRight; } + } + + private static int ToolWindowImageHeight + { + get { return _ToolWindowImageHeight; } + } + + private static int ToolWindowImageWidth + { + get { return _ToolWindowImageWidth; } + } + + private static int ToolWindowImageGapTop + { + get { return _ToolWindowImageGapTop; } + } + + private static int ToolWindowImageGapBottom + { + get { return _ToolWindowImageGapBottom; } + } + + private static int ToolWindowImageGapLeft + { + get { return _ToolWindowImageGapLeft; } + } + + private static int ToolWindowImageGapRight + { + get { return _ToolWindowImageGapRight; } + } + + private static int ToolWindowTextGapRight + { + get { return _ToolWindowTextGapRight; } + } + + private static int ToolWindowTabSeperatorGapTop + { + get { return _ToolWindowTabSeperatorGapTop; } + } + + private static int ToolWindowTabSeperatorGapBottom + { + get { return _ToolWindowTabSeperatorGapBottom; } + } + + private static string _toolTipClose; + private static string ToolTipClose + { + get + { + if (_toolTipClose == null) + _toolTipClose = Strings.DockPaneStrip_ToolTipClose; + return _toolTipClose; + } + } + + private static string _toolTipSelect; + private static string ToolTipSelect + { + get + { + if (_toolTipSelect == null) + _toolTipSelect = Strings.DockPaneStrip_ToolTipWindowList; + return _toolTipSelect; + } + } + + private TextFormatFlags ToolWindowTextFormat + { + get + { + TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.HorizontalCenter | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter; + if (RightToLeft == RightToLeft.Yes) + return textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right; + else + return textFormat; + } + } + + private static int DocumentStripGapTop + { + get { return _DocumentStripGapTop; } + } + + private static int DocumentStripGapBottom + { + get { return _DocumentStripGapBottom; } + } + + private TextFormatFlags DocumentTextFormat + { + get + { + TextFormatFlags textFormat = TextFormatFlags.EndEllipsis | + TextFormatFlags.SingleLine | + TextFormatFlags.VerticalCenter | + TextFormatFlags.HorizontalCenter; + if (RightToLeft == RightToLeft.Yes) + return textFormat | TextFormatFlags.RightToLeft; + else + return textFormat; + } + } + + private static int DocumentTabMaxWidth + { + get { return _DocumentTabMaxWidth; } + } + + private static int DocumentButtonGapTop + { + get { return _DocumentButtonGapTop; } + } + + private static int DocumentButtonGapBottom + { + get { return _DocumentButtonGapBottom; } + } + + private static int DocumentButtonGapBetween + { + get { return _DocumentButtonGapBetween; } + } + + private static int DocumentButtonGapRight + { + get { return _DocumentButtonGapRight; } + } + + private static int DocumentTabGapTop + { + get { return _DocumentTabGapTop; } + } + + private static int DocumentTabGapLeft + { + get { return _DocumentTabGapLeft; } + } + + private static int DocumentTabGapRight + { + get { return _DocumentTabGapRight; } + } + + private static int DocumentIconGapBottom + { + get { return _DocumentIconGapBottom; } + } + + private static int DocumentIconGapLeft + { + get { return _DocumentIconGapLeft; } + } + + private static int DocumentIconGapRight + { + get { return _DocumentIconGapRight; } + } + + private static int DocumentIconWidth + { + get { return _DocumentIconWidth; } + } + + private static int DocumentIconHeight + { + get { return _DocumentIconHeight; } + } + + private static int DocumentTextGapRight + { + get { return _DocumentTextGapRight; } + } + + private static Pen PenToolWindowTabBorder + { + get { return SystemPens.GrayText; } + } + + private static Pen PenDocumentTabActiveBorder + { + get { return SystemPens.ControlDarkDark; } + } + + private static Pen PenDocumentTabInactiveBorder + { + get { return SystemPens.GrayText; } + } + #endregion + + public VS2005DockPaneStrip(DockPane pane) : base(pane) + { + SetStyle(ControlStyles.ResizeRedraw | + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer, true); + + SuspendLayout(); + + m_components = new Container(); + m_toolTip = new ToolTip(Components); + m_selectMenu = new ContextMenuStrip(Components); + + ResumeLayout(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + Components.Dispose(); + if (m_boldFont != null) + { + m_boldFont.Dispose(); + m_boldFont = null; + } + } + base.Dispose (disposing); + } + + private static Font TextFont + { + get { return SystemInformation.MenuFont; } + } + + private Font m_font; + private Font m_boldFont; + private Font BoldFont + { + get + { + if (IsDisposed) + return null; + + if (m_boldFont == null) + { + m_font = TextFont; + m_boldFont = new Font(TextFont, FontStyle.Bold); + } + else if (m_font != TextFont) + { + m_boldFont.Dispose(); + m_font = TextFont; + m_boldFont = new Font(TextFont, FontStyle.Bold); + } + + return m_boldFont; + } + } + + private int m_startDisplayingTab = 0; + private int StartDisplayingTab + { + get { return m_startDisplayingTab; } + set + { + m_startDisplayingTab = value; + Invalidate(); + } + } + + private int m_endDisplayingTab = 0; + private int EndDisplayingTab + { + get { return m_endDisplayingTab; } + set { m_endDisplayingTab = value; } + } + + private int m_firstDisplayingTab = 0; + private int FirstDisplayingTab + { + get { return m_firstDisplayingTab; } + set { m_firstDisplayingTab = value; } + } + + private bool m_documentTabsOverflow = false; + private bool DocumentTabsOverflow + { + set + { + if (m_documentTabsOverflow == value) + return; + + m_documentTabsOverflow = value; + if (value) + ButtonWindowList.ImageCategory = 1; + else + ButtonWindowList.ImageCategory = 0; + } + } + + protected internal override int MeasureHeight() + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return MeasureHeight_ToolWindow(); + else + return MeasureHeight_Document(); + } + + private int MeasureHeight_ToolWindow() + { + if (DockPane.IsAutoHide || Tabs.Count <= 1) + return 0; + + int height = Math.Max(TextFont.Height, ToolWindowImageHeight + ToolWindowImageGapTop + ToolWindowImageGapBottom) + + ToolWindowStripGapTop + ToolWindowStripGapBottom; + + return height; + } + + private int MeasureHeight_Document() + { + int height = Math.Max(TextFont.Height + DocumentTabGapTop, + ButtonClose.Height + DocumentButtonGapTop + DocumentButtonGapBottom) + + DocumentStripGapBottom + DocumentStripGapTop; + + return height; + } + + protected override void OnPaint(PaintEventArgs e) + { + Rectangle rect = TabsRectangle; + + if (Appearance == DockPane.AppearanceStyle.Document) + { + rect.X -= DocumentTabGapLeft; + + // Add these values back in so that the DockStrip color is drawn + // beneath the close button and window list button. + rect.Width += DocumentTabGapLeft + + DocumentTabGapRight + + DocumentButtonGapRight + + ButtonClose.Width + + ButtonWindowList.Width; + + // It is possible depending on the DockPanel DocumentStyle to have + // a Document without a DockStrip. + if (rect.Width > 0 && rect.Height > 0) + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(rect, startColor, endColor, gradientMode)) + { + e.Graphics.FillRectangle(brush, rect); + } + } + } + else + { + Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.StartColor; + Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.EndColor; + LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.LinearGradientMode; + using (LinearGradientBrush brush = new LinearGradientBrush(rect, startColor, endColor, gradientMode)) + { + e.Graphics.FillRectangle(brush, rect); + } + } + base.OnPaint (e); + CalculateTabs(); + if (Appearance == DockPane.AppearanceStyle.Document && DockPane.ActiveContent != null) + { + if (EnsureDocumentTabVisible(DockPane.ActiveContent, false)) + CalculateTabs(); + } + + DrawTabStrip(e.Graphics); + } + + protected override void OnRefreshChanges() + { + SetInertButtons(); + Invalidate(); + } + + protected internal override GraphicsPath GetOutline(int index) + { + + if (Appearance == DockPane.AppearanceStyle.Document) + return GetOutline_Document(index); + else + return GetOutline_ToolWindow(index); + + } + + private GraphicsPath GetOutline_Document(int index) + { + Rectangle rectTab = GetTabRectangle(index); + rectTab.X -= rectTab.Height / 2; + rectTab.Intersect(TabsRectangle); + rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); + Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + + GraphicsPath path = new GraphicsPath(); + GraphicsPath pathTab = GetTabOutline_Document(Tabs[index], true, true, true); + path.AddPath(pathTab, true); + + if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom) + { + path.AddLine(rectTab.Right, rectTab.Top, rectPaneClient.Right, rectTab.Top); + path.AddLine(rectPaneClient.Right, rectTab.Top, rectPaneClient.Right, rectPaneClient.Top); + path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Left, rectPaneClient.Top); + path.AddLine(rectPaneClient.Left, rectPaneClient.Top, rectPaneClient.Left, rectTab.Top); + path.AddLine(rectPaneClient.Left, rectTab.Top, rectTab.Right, rectTab.Top); + } + else + { + path.AddLine(rectTab.Right, rectTab.Bottom, rectPaneClient.Right, rectTab.Bottom); + path.AddLine(rectPaneClient.Right, rectTab.Bottom, rectPaneClient.Right, rectPaneClient.Bottom); + path.AddLine(rectPaneClient.Right, rectPaneClient.Bottom, rectPaneClient.Left, rectPaneClient.Bottom); + path.AddLine(rectPaneClient.Left, rectPaneClient.Bottom, rectPaneClient.Left, rectTab.Bottom); + path.AddLine(rectPaneClient.Left, rectTab.Bottom, rectTab.Right, rectTab.Bottom); + } + return path; + } + + private GraphicsPath GetOutline_ToolWindow(int index) + { + Rectangle rectTab = GetTabRectangle(index); + rectTab.Intersect(TabsRectangle); + rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab)); + int y = rectTab.Top; + Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle); + + GraphicsPath path = new GraphicsPath(); + GraphicsPath pathTab = GetTabOutline(Tabs[index], true, true); + path.AddPath(pathTab, true); + path.AddLine(rectTab.Left, rectTab.Top, rectPaneClient.Left, rectTab.Top); + path.AddLine(rectPaneClient.Left, rectTab.Top, rectPaneClient.Left, rectPaneClient.Top); + path.AddLine(rectPaneClient.Left, rectPaneClient.Top, rectPaneClient.Right, rectPaneClient.Top); + path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Right, rectTab.Top); + path.AddLine(rectPaneClient.Right, rectTab.Top, rectTab.Right, rectTab.Top); + return path; + } + + private void CalculateTabs() + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + CalculateTabs_ToolWindow(); + else + CalculateTabs_Document(); + } + + private void CalculateTabs_ToolWindow() + { + if (Tabs.Count <= 1 || DockPane.IsAutoHide) + return; + + Rectangle rectTabStrip = TabStripRectangle; + + // Calculate tab widths + int countTabs = Tabs.Count; + foreach (TabVS2005 tab in Tabs) + { + tab.MaxWidth = GetMaxTabWidth(Tabs.IndexOf(tab)); + tab.Flag = false; + } + + // Set tab whose max width less than average width + bool anyWidthWithinAverage = true; + int totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; + int totalAllocatedWidth = 0; + int averageWidth = totalWidth / countTabs; + int remainedTabs = countTabs; + for (anyWidthWithinAverage=true; anyWidthWithinAverage && remainedTabs>0;) + { + anyWidthWithinAverage = false; + foreach (TabVS2005 tab in Tabs) + { + if (tab.Flag) + continue; + + if (tab.MaxWidth <= averageWidth) + { + tab.Flag = true; + tab.TabWidth = tab.MaxWidth; + totalAllocatedWidth += tab.TabWidth; + anyWidthWithinAverage = true; + remainedTabs--; + } + } + if (remainedTabs != 0) + averageWidth = (totalWidth - totalAllocatedWidth) / remainedTabs; + } + + // If any tab width not set yet, set it to the average width + if (remainedTabs > 0) + { + int roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs); + foreach (TabVS2005 tab in Tabs) + { + if (tab.Flag) + continue; + + tab.Flag = true; + if (roundUpWidth > 0) + { + tab.TabWidth = averageWidth + 1; + roundUpWidth --; + } + else + tab.TabWidth = averageWidth; + } + } + + // Set the X position of the tabs + int x = rectTabStrip.X + ToolWindowStripGapLeft; + foreach (TabVS2005 tab in Tabs) + { + tab.TabX = x; + x += tab.TabWidth; + } + } + + private bool CalculateDocumentTab(Rectangle rectTabStrip, ref int x, int index) + { + bool overflow = false; + + TabVS2005 tab = Tabs[index] as TabVS2005; + tab.MaxWidth = GetMaxTabWidth(index); + int width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth); + if (x + width < rectTabStrip.Right || index == StartDisplayingTab) + { + tab.TabX = x; + tab.TabWidth = width; + EndDisplayingTab = index; + } + else + { + tab.TabX = 0; + tab.TabWidth = 0; + overflow = true; + } + x += width; + + return overflow; + } + + /// + /// Calculate which tabs are displayed and in what order. + /// + private void CalculateTabs_Document() + { + if (m_startDisplayingTab >= Tabs.Count) + m_startDisplayingTab = 0; + + Rectangle rectTabStrip = TabsRectangle; + + int x = rectTabStrip.X + rectTabStrip.Height / 2; + bool overflow = false; + + // Originally all new documents that were considered overflow + // (not enough pane strip space to show all tabs) were added to + // the far left (assuming not right to left) and the tabs on the + // right were dropped from view. If StartDisplayingTab is not 0 + // then we are dealing with making sure a specific tab is kept in focus. + if (m_startDisplayingTab > 0) + { + int tempX = x; + TabVS2005 tab = Tabs[m_startDisplayingTab] as TabVS2005; + tab.MaxWidth = GetMaxTabWidth(m_startDisplayingTab); + int width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth); + + // Add the active tab and tabs to the left + for (int i = StartDisplayingTab; i >= 0; i--) + CalculateDocumentTab(rectTabStrip, ref tempX, i); + + // Store which tab is the first one displayed so that it + // will be drawn correctly (without part of the tab cut off) + FirstDisplayingTab = EndDisplayingTab; + + tempX = x; // Reset X location because we are starting over + + // Start with the first tab displayed - name is a little misleading. + // Loop through each tab and set its location. If there is not enough + // room for all of them overflow will be returned. + for (int i = EndDisplayingTab; i < Tabs.Count; i++) + overflow = CalculateDocumentTab(rectTabStrip, ref tempX, i); + + // If not all tabs are shown then we have an overflow. + if (FirstDisplayingTab != 0) + overflow = true; + } + else + { + for (int i = StartDisplayingTab; i < Tabs.Count; i++) + overflow = CalculateDocumentTab(rectTabStrip, ref x, i); + for (int i = 0; i < StartDisplayingTab; i++) + overflow = CalculateDocumentTab(rectTabStrip, ref x, i); + + FirstDisplayingTab = StartDisplayingTab; + } + + if (!overflow) + { + m_startDisplayingTab = 0; + FirstDisplayingTab = 0; + x = rectTabStrip.X + rectTabStrip.Height / 2; + foreach (TabVS2005 tab in Tabs) + { + tab.TabX = x; + x += tab.TabWidth; + } + } + DocumentTabsOverflow = overflow; + } + + protected internal override void EnsureTabVisible(IDockContent content) + { + if (Appearance != DockPane.AppearanceStyle.Document || !Tabs.Contains(content)) + return; + + CalculateTabs(); + EnsureDocumentTabVisible(content, true); + } + + private bool EnsureDocumentTabVisible(IDockContent content, bool repaint) + { + int index = Tabs.IndexOf(content); + TabVS2005 tab = Tabs[index] as TabVS2005; + if (tab.TabWidth != 0) + return false; + + StartDisplayingTab = index; + if (repaint) + Invalidate(); + + return true; + } + + private int GetMaxTabWidth(int index) + { + if (Appearance == DockPane.AppearanceStyle.ToolWindow) + return GetMaxTabWidth_ToolWindow(index); + else + return GetMaxTabWidth_Document(index); + } + + private int GetMaxTabWidth_ToolWindow(int index) + { + IDockContent content = Tabs[index].Content; + Size sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont); + return ToolWindowImageWidth + sizeString.Width + ToolWindowImageGapLeft + + ToolWindowImageGapRight + ToolWindowTextGapRight; + } + + private int GetMaxTabWidth_Document(int index) + { + IDockContent content = Tabs[index].Content; + + int height = GetTabRectangle_Document(index).Height; + + Size sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); + + if (DockPane.DockPanel.ShowDocumentIcon) + return sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight + DocumentTextGapRight; + else + return sizeText.Width + DocumentIconGapLeft + DocumentTextGapRight; + } + + private void DrawTabStrip(Graphics g) + { + if (Appearance == DockPane.AppearanceStyle.Document) + DrawTabStrip_Document(g); + else + DrawTabStrip_ToolWindow(g); + } + + private void DrawTabStrip_Document(Graphics g) + { + int count = Tabs.Count; + if (count == 0) + return; + + Rectangle rectTabStrip = TabStripRectangle; + + // Draw the tabs + Rectangle rectTabOnly = TabsRectangle; + Rectangle rectTab = Rectangle.Empty; + TabVS2005 tabActive = null; + g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly)); + for (int i=0; i