Refactored dock content drag & drop.

This commit is contained in:
Robin 2016-01-05 10:40:55 +00:00
parent f96c0b0f21
commit fe9d60dc0e
7 changed files with 336 additions and 124 deletions

View File

@ -128,9 +128,12 @@
<Compile Include="Docking\DarkDockTab.cs" />
<Compile Include="Docking\DarkDockTabArea.cs" />
<Compile Include="Docking\DockContentEventArgs.cs" />
<Compile Include="Docking\DockDropArea.cs" />
<Compile Include="Docking\DockDropCollection.cs" />
<Compile Include="Docking\DockGroupState.cs" />
<Compile Include="Docking\DockPanelState.cs" />
<Compile Include="Docking\DockRegionState.cs" />
<Compile Include="Docking\DockInsertType.cs" />
<Compile Include="Extensions\BitmapExtensions.cs" />
<Compile Include="Extensions\IEnumerableExtensions.cs" />
<Compile Include="Forms\DarkDialog.cs">

View File

@ -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));

View File

@ -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++;
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -0,0 +1,9 @@
namespace DarkUI.Docking
{
public enum DockInsertType
{
None,
Before,
After
}
}

View File

@ -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<DarkDockRegion, Rectangle> _regionDropAreas = new Dictionary<DarkDockRegion, Rectangle>();
private Dictionary<DarkDockGroup, Rectangle> _groupInsertDropAreas = new Dictionary<DarkDockGroup, Rectangle>();
private Dictionary<DarkDockGroup, Rectangle> _groupDropAreas = new Dictionary<DarkDockGroup, Rectangle>();
private Dictionary<DarkDockRegion, DockDropCollection> _regionDropAreas = new Dictionary<DarkDockRegion, DockDropCollection>();
private Dictionary<DarkDockGroup, DockDropCollection> _groupDropAreas = new Dictionary<DarkDockGroup, DockDropCollection>();
#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<DarkDockRegion, Rectangle>();
_groupInsertDropAreas = new Dictionary<DarkDockGroup, Rectangle>();
_groupDropAreas = new Dictionary<DarkDockGroup, Rectangle>();
_regionDropAreas = new Dictionary<DarkDockRegion, DockDropCollection>();
_groupDropAreas = new Dictionary<DarkDockGroup, DockDropCollection>();
// 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