Skip to content

Commit 66c71d9

Browse files
author
grammarian
committed
- Added support for rearranging on non-Detail views.
- Implemented LeftOfItem and RightOfItem target locations git-svn-id: https://svn.code.sf.net/p/objectlistview/code/cs/trunk@817 0bec5ed8-b53f-49e6-9885-ce7bc93af311
1 parent 038a55f commit 66c71d9

File tree

1 file changed

+174
-62
lines changed

1 file changed

+174
-62
lines changed

ObjectListView/DragDrop/DropSink.cs

Lines changed: 174 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* Date: 2009-03-17 5:15 PM
66
*
77
* Change log:
8+
* 2018-04-26 JPP - Implemented LeftOfItem and RightOfItem target locations
9+
* - Added support for rearranging on non-Detail views.
810
* v2.9
911
* 2015-07-08 JPP - Added SimpleDropSink.EnableFeedback to allow all the pretty and helpful
1012
* user feedback during drags to be turned off
@@ -268,12 +270,12 @@ public enum DropTargetLocation
268270
SubItem = 0x20,
269271

270272
/// <summary>
271-
/// On the right of an item is the target (not currently used)
273+
/// On the right of an item is the target
272274
/// </summary>
273275
RightOfItem = 0x40,
274276

275277
/// <summary>
276-
/// On the left of an item is the target (not currently used)
278+
/// On the left of an item is the target
277279
/// </summary>
278280
LeftOfItem = 0x80
279281
}
@@ -619,6 +621,12 @@ public override void DrawFeedback(Graphics g, Rectangle bounds) {
619621
case DropTargetLocation.BelowItem:
620622
this.DrawFeedbackBelowItemTarget(g, bounds);
621623
break;
624+
case DropTargetLocation.LeftOfItem:
625+
this.DrawFeedbackLeftOfItemTarget(g, bounds);
626+
break;
627+
case DropTargetLocation.RightOfItem:
628+
this.DrawFeedbackRightOfItemTarget(g, bounds);
629+
break;
622630
}
623631
}
624632

@@ -812,7 +820,6 @@ protected virtual void CalculateDropTarget(OlvDropEventArgs args, Point pt) {
812820

813821
// Which item is the mouse over?
814822
// If it is not over any item, it's over the background.
815-
//ListViewHitTestInfo info = this.ListView.HitTest(pt.X, pt.Y);
816823
OlvListViewHitTestInfo info = this.ListView.OlvHitTest(pt.X, pt.Y);
817824
if (info.Item != null && this.CanDropOnItem) {
818825
location = DropTargetLocation.Item;
@@ -822,32 +829,82 @@ protected virtual void CalculateDropTarget(OlvDropEventArgs args, Point pt) {
822829
}
823830

824831
// Check to see if the mouse is "between" rows.
825-
// ("between" is somewhat loosely defined)
832+
// ("between" is somewhat loosely defined).
833+
// If the view is Details or List, then "between" is considered vertically.
834+
// If the view is SmallIcon, LargeIcon or Tile, then "between" is considered horizontally.
826835
if (this.CanDropBetween && this.ListView.GetItemCount() > 0) {
827836

828-
// If the mouse is over an item, check to see if it is near the top or bottom
829-
if (location == DropTargetLocation.Item) {
830-
if (pt.Y - SMALL_VALUE <= info.Item.Bounds.Top)
831-
location = DropTargetLocation.AboveItem;
832-
if (pt.Y + SMALL_VALUE >= info.Item.Bounds.Bottom)
833-
location = DropTargetLocation.BelowItem;
834-
} else {
835-
// Is there an item a little below the mouse?
836-
// If so, we say the drop point is above that row
837-
info = this.ListView.OlvHitTest(pt.X, pt.Y + SMALL_VALUE);
838-
if (info.Item != null) {
839-
targetIndex = info.Item.Index;
840-
location = DropTargetLocation.AboveItem;
841-
} else {
842-
// Is there an item a little above the mouse?
843-
info = this.ListView.OlvHitTest(pt.X, pt.Y - SMALL_VALUE);
837+
switch (this.ListView.View) {
838+
case View.LargeIcon:
839+
case View.Tile:
840+
case View.SmallIcon:
841+
// If the mouse is over an item, check to see if it is near the left or right edge.
844842
if (info.Item != null) {
845-
targetIndex = info.Item.Index;
846-
location = DropTargetLocation.BelowItem;
843+
System.Diagnostics.Debug.WriteLine($"target item. pt: {pt}. bounds: {info.Item.Bounds}");
844+
int delta = this.CanDropOnItem ? SMALL_VALUE : info.Item.Bounds.Width / 2;
845+
if (pt.X <= info.Item.Bounds.Left + delta) {
846+
targetIndex = info.Item.Index;
847+
location = DropTargetLocation.LeftOfItem;
848+
} else if (pt.X >= info.Item.Bounds.Right - delta) {
849+
targetIndex = info.Item.Index;
850+
location = DropTargetLocation.RightOfItem;
851+
}
852+
} else {
853+
// Is there an item a little to the *right* of the mouse?
854+
// If so, we say the drop point is *left* that item
855+
int probeWidth = SMALL_VALUE * 2;
856+
info = this.ListView.OlvHitTest(pt.X + probeWidth, pt.Y);
857+
if (info.Item != null) {
858+
targetIndex = info.Item.Index;
859+
location = DropTargetLocation.LeftOfItem;
860+
} else {
861+
// Is there an item a little to the left of the mouse?
862+
info = this.ListView.OlvHitTest(pt.X - probeWidth, pt.Y);
863+
if (info.Item != null) {
864+
targetIndex = info.Item.Index;
865+
location = DropTargetLocation.RightOfItem;
866+
}
867+
}
847868
}
848-
}
869+
break;
870+
case View.Details:
871+
case View.List:
872+
// If the mouse is over an item, check to see if it is near the top or bottom
873+
if (info.Item != null) {
874+
int delta = this.CanDropOnItem ? SMALL_VALUE : this.ListView.RowHeightEffective / 2;
875+
System.Diagnostics.Debug.WriteLine($"target item. pt: {pt}. bounds: {info.Item.Bounds}. delta={delta}");
876+
877+
if (pt.Y <= info.Item.Bounds.Top + delta) {
878+
targetIndex = info.Item.Index;
879+
location = DropTargetLocation.AboveItem;
880+
} else if (pt.Y >= info.Item.Bounds.Bottom - delta) {
881+
targetIndex = info.Item.Index;
882+
location = DropTargetLocation.BelowItem;
883+
}
884+
} else {
885+
// Is there an item a little below the mouse?
886+
// If so, we say the drop point is above that row
887+
info = this.ListView.OlvHitTest(pt.X, pt.Y + SMALL_VALUE);
888+
if (info.Item != null) {
889+
targetIndex = info.Item.Index;
890+
location = DropTargetLocation.AboveItem;
891+
} else {
892+
// Is there an item a little above the mouse?
893+
info = this.ListView.OlvHitTest(pt.X, pt.Y - SMALL_VALUE);
894+
if (info.Item != null) {
895+
targetIndex = info.Item.Index;
896+
location = DropTargetLocation.BelowItem;
897+
}
898+
}
899+
}
900+
901+
break;
902+
default:
903+
throw new ArgumentOutOfRangeException();
849904
}
850905
}
906+
System.Diagnostics.Debug.WriteLine($"location: {location}");
907+
System.Diagnostics.Debug.WriteLine($"targetIndex: {targetIndex}");
851908

852909
args.DropTargetLocation = location;
853910
args.DropTargetIndex = targetIndex;
@@ -1014,14 +1071,43 @@ protected virtual void DrawFeedbackAboveItemTarget(Graphics g, Rectangle bounds)
10141071
/// </summary>
10151072
/// <param name="g"></param>
10161073
/// <param name="bounds"></param>
1017-
protected virtual void DrawFeedbackBelowItemTarget(Graphics g, Rectangle bounds) {
1074+
protected virtual void DrawFeedbackBelowItemTarget(Graphics g, Rectangle bounds)
1075+
{
10181076
if (this.DropTargetItem == null)
10191077
return;
10201078

10211079
Rectangle r = this.CalculateDropTargetRectangle(this.DropTargetItem, this.DropTargetSubItemIndex);
10221080
this.DrawBetweenLine(g, r.Left, r.Bottom, r.Right, r.Bottom);
10231081
}
10241082

1083+
/// <summary>
1084+
/// Draw the feedback that shows the drop will occur to the left of target
1085+
/// </summary>
1086+
/// <param name="g"></param>
1087+
/// <param name="bounds"></param>
1088+
protected virtual void DrawFeedbackLeftOfItemTarget(Graphics g, Rectangle bounds)
1089+
{
1090+
if (this.DropTargetItem == null)
1091+
return;
1092+
1093+
Rectangle r = this.CalculateDropTargetRectangle(this.DropTargetItem, this.DropTargetSubItemIndex);
1094+
this.DrawBetweenLine(g, r.Left, r.Top, r.Left, r.Bottom);
1095+
}
1096+
1097+
/// <summary>
1098+
/// Draw the feedback that shows the drop will occur to the right of target
1099+
/// </summary>
1100+
/// <param name="g"></param>
1101+
/// <param name="bounds"></param>
1102+
protected virtual void DrawFeedbackRightOfItemTarget(Graphics g, Rectangle bounds)
1103+
{
1104+
if (this.DropTargetItem == null)
1105+
return;
1106+
1107+
Rectangle r = this.CalculateDropTargetRectangle(this.DropTargetItem, this.DropTargetSubItemIndex);
1108+
this.DrawBetweenLine(g, r.Right, r.Top, r.Right, r.Bottom);
1109+
}
1110+
10251111
/// <summary>
10261112
/// Return a GraphicPath that is round corner rectangle.
10271113
/// </summary>
@@ -1077,50 +1163,65 @@ protected virtual Rectangle CalculateDropTargetRectangle(OLVListItem item, int s
10771163
/// <param name="y2"></param>
10781164
protected virtual void DrawBetweenLine(Graphics g, int x1, int y1, int x2, int y2) {
10791165
using (Brush b = new SolidBrush(this.FeedbackColor)) {
1080-
int x = x1;
1081-
int y = y1;
1082-
using (GraphicsPath gp = new GraphicsPath()) {
1083-
gp.AddLine(
1084-
x, y + 5,
1085-
x, y - 5);
1086-
gp.AddBezier(
1087-
x, y - 6,
1088-
x + 3, y - 2,
1089-
x + 6, y - 1,
1090-
x + 11, y);
1091-
gp.AddBezier(
1092-
x + 11, y,
1093-
x + 6, y + 1,
1094-
x + 3, y + 2,
1095-
x, y + 6);
1096-
gp.CloseFigure();
1097-
g.FillPath(b, gp);
1098-
}
1099-
x = x2;
1100-
y = y2;
1101-
using (GraphicsPath gp = new GraphicsPath()) {
1102-
gp.AddLine(
1103-
x, y + 6,
1104-
x, y - 6);
1105-
gp.AddBezier(
1106-
x, y - 7,
1107-
x - 3, y - 2,
1108-
x - 6, y - 1,
1109-
x - 11, y);
1110-
gp.AddBezier(
1111-
x - 11, y,
1112-
x - 6, y + 1,
1113-
x - 3, y + 2,
1114-
x, y + 7);
1115-
gp.CloseFigure();
1116-
g.FillPath(b, gp);
1166+
if (y1 == y2) {
1167+
// Put right and left arrow on a horizontal line
1168+
DrawClosedFigure(g, b, RightPointingArrow(x1, y1));
1169+
DrawClosedFigure(g, b, LeftPointingArrow(x2, y2));
1170+
} else {
1171+
// Put up and down arrows on a vertical line
1172+
DrawClosedFigure(g, b, DownPointingArrow(x1, y1));
1173+
DrawClosedFigure(g, b, UpPointingArrow(x2, y2));
11171174
}
11181175
}
1176+
11191177
using (Pen p = new Pen(this.FeedbackColor, 3.0f)) {
11201178
g.DrawLine(p, x1, y1, x2, y2);
11211179
}
11221180
}
11231181

1182+
private const int ARROW_SIZE = 6;
1183+
1184+
private static void DrawClosedFigure(Graphics g, Brush b, Point[] pts) {
1185+
using (GraphicsPath gp = new GraphicsPath()) {
1186+
gp.StartFigure();
1187+
gp.AddLines(pts);
1188+
gp.CloseFigure();
1189+
g.FillPath(b, gp);
1190+
}
1191+
}
1192+
1193+
private static Point[] RightPointingArrow(int x, int y) {
1194+
return new Point[] {
1195+
new Point(x, y - ARROW_SIZE),
1196+
new Point(x, y + ARROW_SIZE),
1197+
new Point(x + ARROW_SIZE, y)
1198+
};
1199+
}
1200+
1201+
private static Point[] LeftPointingArrow(int x, int y) {
1202+
return new Point[] {
1203+
new Point(x, y - ARROW_SIZE),
1204+
new Point(x, y + ARROW_SIZE),
1205+
new Point(x - ARROW_SIZE, y)
1206+
};
1207+
}
1208+
1209+
private static Point[] DownPointingArrow(int x, int y) {
1210+
return new Point[] {
1211+
new Point(x - ARROW_SIZE, y),
1212+
new Point(x + ARROW_SIZE, y),
1213+
new Point(x, y + ARROW_SIZE)
1214+
};
1215+
}
1216+
1217+
private static Point[] UpPointingArrow(int x, int y) {
1218+
return new Point[] {
1219+
new Point(x - ARROW_SIZE, y),
1220+
new Point(x + ARROW_SIZE, y),
1221+
new Point(x, y - ARROW_SIZE)
1222+
};
1223+
}
1224+
11241225
#endregion
11251226

11261227
private Timer timer;
@@ -1192,7 +1293,7 @@ protected override void OnModelCanDrop(ModelDropEventArgs args) {
11921293
args.InfoMessage = "This list doesn't accept drops from other lists";
11931294
}
11941295

1195-
// If we are rearranging a list, don't allow drops on the background
1296+
// If we are rearranging the same list, don't allow drops on the background
11961297
if (args.DropTargetLocation == DropTargetLocation.Background && args.SourceListView == this.ListView) {
11971298
args.Effect = DragDropEffects.None;
11981299
args.DropTargetLocation = DropTargetLocation.None;
@@ -1217,9 +1318,11 @@ protected override void OnModelDropped(ModelDropEventArgs args) {
12171318
public virtual void RearrangeModels(ModelDropEventArgs args) {
12181319
switch (args.DropTargetLocation) {
12191320
case DropTargetLocation.AboveItem:
1321+
case DropTargetLocation.LeftOfItem:
12201322
this.ListView.MoveObjects(args.DropTargetIndex, args.SourceModels);
12211323
break;
12221324
case DropTargetLocation.BelowItem:
1325+
case DropTargetLocation.RightOfItem:
12231326
this.ListView.MoveObjects(args.DropTargetIndex + 1, args.SourceModels);
12241327
break;
12251328
case DropTargetLocation.Background:
@@ -1232,6 +1335,15 @@ public virtual void RearrangeModels(ModelDropEventArgs args) {
12321335
if (args.SourceListView != this.ListView) {
12331336
args.SourceListView.RemoveObjects(args.SourceModels);
12341337
}
1338+
1339+
// Some views have to be "encouraged" to show the changes
1340+
switch (this.ListView.View) {
1341+
case View.LargeIcon:
1342+
case View.SmallIcon:
1343+
case View.Tile:
1344+
this.ListView.BuildList();
1345+
break;
1346+
}
12351347
}
12361348
}
12371349

0 commit comments

Comments
 (0)