5
5
* Date: 2009-03-17 5:15 PM
6
6
*
7
7
* Change log:
8
+ * 2018-04-26 JPP - Implemented LeftOfItem and RightOfItem target locations
9
+ * - Added support for rearranging on non-Detail views.
8
10
* v2.9
9
11
* 2015-07-08 JPP - Added SimpleDropSink.EnableFeedback to allow all the pretty and helpful
10
12
* user feedback during drags to be turned off
@@ -268,12 +270,12 @@ public enum DropTargetLocation
268
270
SubItem = 0x20 ,
269
271
270
272
/// <summary>
271
- /// On the right of an item is the target (not currently used)
273
+ /// On the right of an item is the target
272
274
/// </summary>
273
275
RightOfItem = 0x40 ,
274
276
275
277
/// <summary>
276
- /// On the left of an item is the target (not currently used)
278
+ /// On the left of an item is the target
277
279
/// </summary>
278
280
LeftOfItem = 0x80
279
281
}
@@ -619,6 +621,12 @@ public override void DrawFeedback(Graphics g, Rectangle bounds) {
619
621
case DropTargetLocation . BelowItem :
620
622
this . DrawFeedbackBelowItemTarget ( g , bounds ) ;
621
623
break ;
624
+ case DropTargetLocation . LeftOfItem :
625
+ this . DrawFeedbackLeftOfItemTarget ( g , bounds ) ;
626
+ break ;
627
+ case DropTargetLocation . RightOfItem :
628
+ this . DrawFeedbackRightOfItemTarget ( g , bounds ) ;
629
+ break ;
622
630
}
623
631
}
624
632
@@ -812,7 +820,6 @@ protected virtual void CalculateDropTarget(OlvDropEventArgs args, Point pt) {
812
820
813
821
// Which item is the mouse over?
814
822
// If it is not over any item, it's over the background.
815
- //ListViewHitTestInfo info = this.ListView.HitTest(pt.X, pt.Y);
816
823
OlvListViewHitTestInfo info = this . ListView . OlvHitTest ( pt . X , pt . Y ) ;
817
824
if ( info . Item != null && this . CanDropOnItem ) {
818
825
location = DropTargetLocation . Item ;
@@ -822,32 +829,82 @@ protected virtual void CalculateDropTarget(OlvDropEventArgs args, Point pt) {
822
829
}
823
830
824
831
// 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.
826
835
if ( this . CanDropBetween && this . ListView . GetItemCount ( ) > 0 ) {
827
836
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.
844
842
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
+ }
847
868
}
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 ( ) ;
849
904
}
850
905
}
906
+ System . Diagnostics . Debug . WriteLine ( $ "location: { location } ") ;
907
+ System . Diagnostics . Debug . WriteLine ( $ "targetIndex: { targetIndex } ") ;
851
908
852
909
args . DropTargetLocation = location ;
853
910
args . DropTargetIndex = targetIndex ;
@@ -1014,14 +1071,43 @@ protected virtual void DrawFeedbackAboveItemTarget(Graphics g, Rectangle bounds)
1014
1071
/// </summary>
1015
1072
/// <param name="g"></param>
1016
1073
/// <param name="bounds"></param>
1017
- protected virtual void DrawFeedbackBelowItemTarget ( Graphics g , Rectangle bounds ) {
1074
+ protected virtual void DrawFeedbackBelowItemTarget ( Graphics g , Rectangle bounds )
1075
+ {
1018
1076
if ( this . DropTargetItem == null )
1019
1077
return ;
1020
1078
1021
1079
Rectangle r = this . CalculateDropTargetRectangle ( this . DropTargetItem , this . DropTargetSubItemIndex ) ;
1022
1080
this . DrawBetweenLine ( g , r . Left , r . Bottom , r . Right , r . Bottom ) ;
1023
1081
}
1024
1082
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
+
1025
1111
/// <summary>
1026
1112
/// Return a GraphicPath that is round corner rectangle.
1027
1113
/// </summary>
@@ -1077,50 +1163,65 @@ protected virtual Rectangle CalculateDropTargetRectangle(OLVListItem item, int s
1077
1163
/// <param name="y2"></param>
1078
1164
protected virtual void DrawBetweenLine ( Graphics g , int x1 , int y1 , int x2 , int y2 ) {
1079
1165
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 ) ) ;
1117
1174
}
1118
1175
}
1176
+
1119
1177
using ( Pen p = new Pen ( this . FeedbackColor , 3.0f ) ) {
1120
1178
g . DrawLine ( p , x1 , y1 , x2 , y2 ) ;
1121
1179
}
1122
1180
}
1123
1181
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
+
1124
1225
#endregion
1125
1226
1126
1227
private Timer timer ;
@@ -1192,7 +1293,7 @@ protected override void OnModelCanDrop(ModelDropEventArgs args) {
1192
1293
args . InfoMessage = "This list doesn't accept drops from other lists" ;
1193
1294
}
1194
1295
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
1196
1297
if ( args . DropTargetLocation == DropTargetLocation . Background && args . SourceListView == this . ListView ) {
1197
1298
args . Effect = DragDropEffects . None ;
1198
1299
args . DropTargetLocation = DropTargetLocation . None ;
@@ -1217,9 +1318,11 @@ protected override void OnModelDropped(ModelDropEventArgs args) {
1217
1318
public virtual void RearrangeModels ( ModelDropEventArgs args ) {
1218
1319
switch ( args . DropTargetLocation ) {
1219
1320
case DropTargetLocation . AboveItem :
1321
+ case DropTargetLocation . LeftOfItem :
1220
1322
this . ListView . MoveObjects ( args . DropTargetIndex , args . SourceModels ) ;
1221
1323
break ;
1222
1324
case DropTargetLocation . BelowItem :
1325
+ case DropTargetLocation . RightOfItem :
1223
1326
this . ListView . MoveObjects ( args . DropTargetIndex + 1 , args . SourceModels ) ;
1224
1327
break ;
1225
1328
case DropTargetLocation . Background :
@@ -1232,6 +1335,15 @@ public virtual void RearrangeModels(ModelDropEventArgs args) {
1232
1335
if ( args . SourceListView != this . ListView ) {
1233
1336
args . SourceListView . RemoveObjects ( args . SourceModels ) ;
1234
1337
}
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
+ }
1235
1347
}
1236
1348
}
1237
1349
0 commit comments