From fe9d60dc0e23e30f177c7428220c509fc413e8d5 Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 5 Jan 2016 10:40:55 +0000 Subject: [PATCH] Refactored dock content drag & drop. --- DarkUI/DarkUI.csproj | 3 + DarkUI/Docking/DarkDockPanel.cs | 4 +- DarkUI/Docking/DarkDockRegion.cs | 11 +- DarkUI/Docking/DockDropArea.cs | 138 ++++++++++++++ DarkUI/Docking/DockDropCollection.cs | 48 +++++ DarkUI/Docking/DockInsertType.cs | 9 + DarkUI/Win32/DockContentDragFilter.cs | 247 +++++++++++++------------- 7 files changed, 336 insertions(+), 124 deletions(-) create mode 100644 DarkUI/Docking/DockDropArea.cs create mode 100644 DarkUI/Docking/DockDropCollection.cs create mode 100644 DarkUI/Docking/DockInsertType.cs diff --git a/DarkUI/DarkUI.csproj b/DarkUI/DarkUI.csproj index 0b9b31a..6f4914b 100644 --- a/DarkUI/DarkUI.csproj +++ b/DarkUI/DarkUI.csproj @@ -128,9 +128,12 @@ + + + diff --git a/DarkUI/Docking/DarkDockPanel.cs b/DarkUI/Docking/DarkDockPanel.cs index 16579ab..3429e65 100644 --- a/DarkUI/Docking/DarkDockPanel.cs +++ b/DarkUI/Docking/DarkDockPanel.cs @@ -159,7 +159,7 @@ namespace DarkUI.Docking dockContent.Select(); } - public void InsertContent(DarkDockContent dockContent, DarkDockGroup dockGroup) + public void InsertContent(DarkDockContent dockContent, DarkDockGroup dockGroup, DockInsertType insertType) { if (_contents.Contains(dockContent)) RemoveContent(dockContent); @@ -170,7 +170,7 @@ namespace DarkUI.Docking dockContent.DockArea = dockGroup.DockArea; var region = _regions[dockGroup.DockArea]; - region.InsertContent(dockContent, dockGroup); + region.InsertContent(dockContent, dockGroup, insertType); if (ContentAdded != null) ContentAdded(this, new DockContentEventArgs(dockContent)); diff --git a/DarkUI/Docking/DarkDockRegion.cs b/DarkUI/Docking/DarkDockRegion.cs index bc8af13..8875346 100644 --- a/DarkUI/Docking/DarkDockRegion.cs +++ b/DarkUI/Docking/DarkDockRegion.cs @@ -92,9 +92,14 @@ namespace DarkUI.Docking PositionGroups(); } - internal void InsertContent(DarkDockContent dockContent, DarkDockGroup dockGroup) + internal void InsertContent(DarkDockContent dockContent, DarkDockGroup dockGroup, DockInsertType insertType) { - var newGroup = InsertGroup(dockGroup.Order); + var order = dockGroup.Order; + + if (insertType == DockInsertType.After) + order++; + + var newGroup = InsertGroup(order); dockContent.DockRegion = this; newGroup.AddContent(dockContent); @@ -166,7 +171,7 @@ namespace DarkUI.Docking { foreach (var group in _groups) { - if (group.Order <= order) + if (group.Order >= order) group.Order++; } diff --git a/DarkUI/Docking/DockDropArea.cs b/DarkUI/Docking/DockDropArea.cs new file mode 100644 index 0000000..fd6f610 --- /dev/null +++ b/DarkUI/Docking/DockDropArea.cs @@ -0,0 +1,138 @@ +using System.Drawing; + +namespace DarkUI.Docking +{ + internal class DockDropArea + { + #region Property Region + + internal DarkDockPanel DockPanel { get; private set; } + + internal Rectangle DropArea { get; private set; } + + internal Rectangle HighlightArea { get; private set; } + + internal DarkDockRegion DockRegion { get; private set; } + + internal DarkDockGroup DockGroup { get; private set; } + + internal DockInsertType InsertType { get; private set; } + + #endregion + + #region Constructor Region + + internal DockDropArea(DarkDockRegion region, DockInsertType insertType) + { + DockRegion = region; + InsertType = insertType; + } + + internal DockDropArea(DarkDockGroup group, DockInsertType insertType) + { + DockGroup = group; + InsertType = insertType; + } + + #endregion + + #region Method Region + + internal void BuildAreas() + { + if (DockRegion != null) + BuildRegionAreas(); + else if (DockGroup != null) + BuildGroupAreas(); + } + + private void BuildRegionAreas() + { + + } + + private void BuildGroupAreas() + { + switch (InsertType) + { + case DockInsertType.None: + var dropRect = new Rectangle + { + X = DockGroup.PointToScreen(Point.Empty).X, + Y = DockGroup.PointToScreen(Point.Empty).Y, + Width = DockGroup.Width, + Height = DockGroup.Height + }; + + DropArea = dropRect; + HighlightArea = dropRect; + + break; + + case DockInsertType.Before: + var beforeDropWidth = DockGroup.Width; + var beforeDropHeight = DockGroup.Height; + + switch (DockGroup.DockArea) + { + case DarkDockArea.Left: + case DarkDockArea.Right: + beforeDropHeight = DockGroup.Height / 4; + break; + + case DarkDockArea.Bottom: + beforeDropWidth = DockGroup.Width / 4; + break; + } + + var beforeDropRect = new Rectangle + { + X = DockGroup.PointToScreen(Point.Empty).X, + Y = DockGroup.PointToScreen(Point.Empty).Y, + Width = beforeDropWidth, + Height = beforeDropHeight + }; + + DropArea = beforeDropRect; + HighlightArea = beforeDropRect; + + break; + + case DockInsertType.After: + var afterDropX = DockGroup.PointToScreen(Point.Empty).X; + var afterDropY = DockGroup.PointToScreen(Point.Empty).Y; + var afterDropWidth = DockGroup.Width; + var afterDropHeight = DockGroup.Height; + + switch (DockGroup.DockArea) + { + case DarkDockArea.Left: + case DarkDockArea.Right: + afterDropHeight = DockGroup.Height / 4; + afterDropY = DockGroup.PointToScreen(Point.Empty).Y + DockGroup.Height - afterDropHeight; + break; + + case DarkDockArea.Bottom: + afterDropWidth = DockGroup.Width / 4; + afterDropX = DockGroup.PointToScreen(Point.Empty).X + DockGroup.Width - afterDropWidth; + break; + } + + var afterDropRect = new Rectangle + { + X = afterDropX, + Y = afterDropY, + Width = afterDropWidth, + Height = afterDropHeight + }; + + DropArea = afterDropRect; + HighlightArea = afterDropRect; + + break; + } + } + + #endregion + } +} diff --git a/DarkUI/Docking/DockDropCollection.cs b/DarkUI/Docking/DockDropCollection.cs new file mode 100644 index 0000000..521e133 --- /dev/null +++ b/DarkUI/Docking/DockDropCollection.cs @@ -0,0 +1,48 @@ +namespace DarkUI.Docking +{ + internal class DockDropCollection + { + #region Property Region + + internal DockDropArea DropArea { get; private set; } + + internal DockDropArea InsertBeforeArea { get; private set; } + + internal DockDropArea InsertAfterArea { get; private set; } + + #endregion + + #region Constructor Region + + internal DockDropCollection(DarkDockPanel dockPanel, DarkDockRegion region) + { + DropArea = new DockDropArea(region, DockInsertType.None); + InsertBeforeArea = new DockDropArea(region, DockInsertType.Before); + InsertAfterArea = new DockDropArea(region, DockInsertType.After); + + BuildAreas(); + } + + internal DockDropCollection(DarkDockPanel dockPanel, DarkDockGroup group) + { + DropArea = new DockDropArea(group, DockInsertType.None); + InsertBeforeArea = new DockDropArea(group, DockInsertType.Before); + InsertAfterArea = new DockDropArea(group, DockInsertType.After); + + BuildAreas(); + } + + #endregion + + #region Method Region + + private void BuildAreas() + { + DropArea.BuildAreas(); + InsertBeforeArea.BuildAreas(); + InsertAfterArea.BuildAreas(); + } + + #endregion + } +} diff --git a/DarkUI/Docking/DockInsertType.cs b/DarkUI/Docking/DockInsertType.cs new file mode 100644 index 0000000..d8e38d3 --- /dev/null +++ b/DarkUI/Docking/DockInsertType.cs @@ -0,0 +1,9 @@ +namespace DarkUI.Docking +{ + public enum DockInsertType + { + None, + Before, + After + } +} diff --git a/DarkUI/Win32/DockContentDragFilter.cs b/DarkUI/Win32/DockContentDragFilter.cs index 6e0408a..814ffa1 100644 --- a/DarkUI/Win32/DockContentDragFilter.cs +++ b/DarkUI/Win32/DockContentDragFilter.cs @@ -18,13 +18,12 @@ namespace DarkUI.Win32 private DarkTranslucentForm _highlightForm; private bool _isDragging = false; - private bool _insert = false; private DarkDockRegion _targetRegion; private DarkDockGroup _targetGroup; + private DockInsertType _insertType = DockInsertType.None; - private Dictionary _regionDropAreas = new Dictionary(); - private Dictionary _groupInsertDropAreas = new Dictionary(); - private Dictionary _groupDropAreas = new Dictionary(); + private Dictionary _regionDropAreas = new Dictionary(); + private Dictionary _groupDropAreas = new Dictionary(); #endregion @@ -73,10 +72,17 @@ namespace DarkUI.Win32 { _dockPanel.RemoveContent(_dragContent); - if (_insert) - _dockPanel.InsertContent(_dragContent, _targetGroup); - else - _dockPanel.AddContent(_dragContent, _targetGroup); + switch (_insertType) + { + case DockInsertType.None: + _dockPanel.AddContent(_dragContent, _targetGroup); + break; + + case DockInsertType.Before: + case DockInsertType.After: + _dockPanel.InsertContent(_dragContent, _targetGroup, _insertType); + break; + } } StopDrag(); @@ -92,71 +98,28 @@ namespace DarkUI.Win32 public void StartDrag(DarkDockContent content) { - _regionDropAreas = new Dictionary(); - _groupInsertDropAreas = new Dictionary(); - _groupDropAreas = new Dictionary(); + _regionDropAreas = new Dictionary(); + _groupDropAreas = new Dictionary(); + // Add all regions and groups to the drop collections foreach (var region in _dockPanel.Regions.Values) { + if (region.DockArea == DarkDockArea.Document) + continue; + + // If the region is visible then build drop areas for the groups. if (region.Visible) { foreach (var group in region.Groups) { - var rect = new Rectangle - { - X = group.PointToScreen(Point.Empty).X, - Y = group.PointToScreen(Point.Empty).Y, - Width = group.Width, - Height = group.Height - }; - - var insertRect = new Rectangle(); - - switch (group.DockArea) - { - case DarkDockArea.Left: - case DarkDockArea.Right: - - var top = rect.Top; - - if (group.Order > 0) - top -= 7; - - insertRect = new Rectangle - { - X = rect.Left, - Y = top, - Width = rect.Width, - Height = 15 - }; - - break; - - case DarkDockArea.Bottom: - - var left = rect.Left; - - if (group.Order > 0) - left -= 7; - - insertRect = new Rectangle - { - X = left, - Y = rect.Top, - Width = 15, - Height = rect.Height - }; - - break; - } - - _groupDropAreas.Add(group, rect); - _groupInsertDropAreas.Add(group, insertRect); + var collection = new DockDropCollection(_dockPanel, group); + _groupDropAreas.Add(group, collection); } } + // If the region is NOT visible then build a drop area for the region itself. else { - var rect = new Rectangle(); + /*var rect = new Rectangle(); switch (region.DockArea) { @@ -211,7 +174,7 @@ namespace DarkUI.Win32 break; } - _regionDropAreas.Add(region, rect); + _regionDropAreas.Add(region, rect);*/ } } @@ -221,97 +184,143 @@ namespace DarkUI.Win32 private void StopDrag() { + Cursor.Current = Cursors.Default; + _highlightForm.Hide(); _dragContent = null; _isDragging = false; } + private void UpdateHighlightForm(Rectangle rect) + { + Cursor.Current = Cursors.SizeAll; + + _highlightForm.SuspendLayout(); + + _highlightForm.Size = new Size(rect.Width, rect.Height); + _highlightForm.Location = new Point(rect.X, rect.Y); + + _highlightForm.ResumeLayout(); + + if (!_highlightForm.Visible) + { + _highlightForm.Show(); + _highlightForm.BringToFront(); + } + } + private void HandleDrag() { var location = Cursor.Position; + _insertType = DockInsertType.None; + _targetRegion = null; _targetGroup = null; - foreach (var keyValuePair in _regionDropAreas) + // Check all region drop areas + foreach (var collection in _regionDropAreas.Values) { - var region = keyValuePair.Key; - var rect = keyValuePair.Value; - - if (rect.Contains(location)) + if (collection.InsertBeforeArea.DropArea.Contains(location)) { - _targetRegion = region; + _insertType = DockInsertType.Before; + _targetRegion = collection.InsertBeforeArea.DockRegion; + UpdateHighlightForm(collection.InsertBeforeArea.HighlightArea); + return; + } - _highlightForm.Location = new Point(rect.X, rect.Y); - _highlightForm.Size = new Size(rect.Width, rect.Height); + if (collection.InsertAfterArea.DropArea.Contains(location)) + { + _insertType = DockInsertType.After; + _targetRegion = collection.InsertAfterArea.DockRegion; + UpdateHighlightForm(collection.InsertAfterArea.HighlightArea); + return; + } + + if (collection.DropArea.DropArea.Contains(location)) + { + _insertType = DockInsertType.None; + _targetRegion = collection.DropArea.DockRegion; + UpdateHighlightForm(collection.DropArea.HighlightArea); + return; } } - var inserting = false; - - foreach (var keyValuePair in _groupInsertDropAreas) + // Check all group drop areas + foreach (var collection in _groupDropAreas.Values) { - var group = keyValuePair.Key; - var rect = keyValuePair.Value; + var sameRegion = false; + var sameGroup = false; + var groupHasOtherContent = false; - if (group.DockRegion == _dragContent.DockGroup.DockRegion) + if (collection.DropArea.DockGroup == _dragContent.DockGroup) { - if (group == _dragContent.DockGroup) - continue; + sameGroup = true; - if (_dragContent.DockGroup.Order == group.Order - 1) - continue; + if (collection.DropArea.DockGroup.ContentCount > 1) + groupHasOtherContent = true; } - if (rect.Contains(location)) + if (collection.DropArea.DockGroup.DockRegion == _dragContent.DockRegion) { - inserting = true; - - _insert = true; - _targetGroup = group; - - _highlightForm.Location = new Point(rect.X, rect.Y); - _highlightForm.Size = new Size(rect.Width, rect.Height); + sameRegion = true; } - } - if (!inserting) - { - foreach (var keyValuePair in _groupDropAreas) + if (!sameGroup || groupHasOtherContent) { - var group = keyValuePair.Key; - var rect = keyValuePair.Value; + var skipBefore = false; + var skipAfter = false; - if (group == _dragContent.DockGroup) - continue; - - if (group.DockArea == DarkDockArea.Document) - continue; - - if (rect.Contains(location)) + if (sameRegion && !groupHasOtherContent) { - _insert = false; - _targetGroup = group; + if (collection.InsertBeforeArea.DockGroup.Order == _dragContent.DockGroup.Order + 1) + skipBefore = true; - _highlightForm.Location = new Point(rect.X, rect.Y); - _highlightForm.Size = new Size(rect.Width, rect.Height); + if (collection.InsertAfterArea.DockGroup.Order == _dragContent.DockGroup.Order - 1) + skipAfter = true; + } + + if (!skipBefore) + { + if (collection.InsertBeforeArea.DropArea.Contains(location)) + { + _insertType = DockInsertType.Before; + _targetGroup = collection.InsertBeforeArea.DockGroup; + UpdateHighlightForm(collection.InsertBeforeArea.HighlightArea); + return; + } + } + + if (!skipAfter) + { + if (collection.InsertAfterArea.DropArea.Contains(location)) + { + _insertType = DockInsertType.After; + _targetGroup = collection.InsertAfterArea.DockGroup; + UpdateHighlightForm(collection.InsertAfterArea.HighlightArea); + return; + } + } + } + + if (!sameGroup) + { + if (collection.DropArea.DropArea.Contains(location)) + { + _insertType = DockInsertType.None; + _targetGroup = collection.DropArea.DockGroup; + UpdateHighlightForm(collection.DropArea.HighlightArea); + return; } } } - if (_targetRegion == null && _targetGroup == null) - { - if (_highlightForm.Visible) - _highlightForm.Hide(); - } - else - { - if (!_highlightForm.Visible) - { - _highlightForm.Show(); - _highlightForm.BringToFront(); - } - } + // Not hovering over anything - hide the highlight + if (_highlightForm.Visible) + _highlightForm.Hide(); + + // Show we can't drag here + Cursor.Current = Cursors.No; } #endregion