Skip to content

Commit 640b57c

Browse files
committed
Add dragging methods to NodifyEditor
1 parent edd3ff8 commit 640b57c

File tree

7 files changed

+222
-154
lines changed

7 files changed

+222
-154
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
> - Added BeginPanning, UpdatePanning, EndPanning, CancelPanning and AllowPanningCancellation to NodifyEditor
1212
> - Added UpdateCuttingLine to NodifyEditor
1313
> - Added BeginSelecting, UpdateSelection, EndSelecting, CancelSelecting and AllowSelectionCancellation to NodifyEditor
14+
> - Added IsDragging, BeginDragging, UpdateDragging, EndDragging and CancelDragging to NodifyEditor
1415
> - Bugfixes:
1516
1617
#### **Version 6.6.0**

Nodify/Helpers/PushItemsStrategy.cs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Diagnostics;
43
using System.Linq;
54
using System.Windows;
65

@@ -12,12 +11,11 @@ internal interface IPushStrategy
1211
Rect Push(Vector amount);
1312
Rect End();
1413
Rect Cancel();
15-
Rect OnViewportChanged();
14+
Rect GetPushedArea();
1615
}
1716

1817
internal abstract class BasePushStrategy : IPushStrategy
1918
{
20-
private IDraggingStrategy? _draggingStrategy;
2119
private const double _minOffset = 2;
2220
private double _actualOffset;
2321
private double _initialPosition;
@@ -33,7 +31,7 @@ public BasePushStrategy(NodifyEditor editor)
3331
public Rect Start(Point position)
3432
{
3533
var containers = GetFilteredContainers(position);
36-
_draggingStrategy = Editor.CreateDraggingStrategy(containers);
34+
Editor.BeginDragging(containers);
3735

3836
_initialPosition = GetInitialPosition(position);
3937
_actualOffset = 0;
@@ -43,10 +41,8 @@ public Rect Start(Point position)
4341

4442
public Rect Push(Vector amount)
4543
{
46-
Debug.Assert(_draggingStrategy != null);
47-
4844
var offset = GetPushOffset(amount);
49-
_draggingStrategy!.Update(offset);
45+
Editor.UpdateDragging(offset);
5046

5147
_actualOffset += offset.X;
5248
_actualOffset += offset.Y;
@@ -59,23 +55,21 @@ public Rect Push(Vector amount)
5955

6056
public Rect End()
6157
{
62-
Debug.Assert(_draggingStrategy != null);
63-
_draggingStrategy!.End();
58+
Editor.EndDragging();
6459
return new Rect();
6560
}
6661

6762
public Rect Cancel()
6863
{
69-
Debug.Assert(_draggingStrategy != null);
70-
_draggingStrategy!.Abort();
64+
Editor.CancelDragging();
7165
return new Rect();
7266
}
7367

7468
protected abstract IEnumerable<ItemContainer> GetFilteredContainers(Point position);
7569
protected abstract double GetInitialPosition(Point position);
7670
protected abstract Vector GetPushOffset(Vector offset);
7771
protected abstract Rect CalculatePushedArea(double position, double offset);
78-
public abstract Rect OnViewportChanged();
72+
public abstract Rect GetPushedArea();
7973
}
8074

8175
internal sealed class HorizontalPushStrategy : BasePushStrategy
@@ -96,7 +90,7 @@ protected override Vector GetPushOffset(Vector offset)
9690
protected override Rect CalculatePushedArea(double position, double offset)
9791
=> new Rect(position, Editor.ViewportLocation.Y - OffscreenOffset, offset, Editor.ViewportSize.Height + OffscreenOffset * 2);
9892

99-
public override Rect OnViewportChanged()
93+
public override Rect GetPushedArea()
10094
=> CalculatePushedArea(Editor.PushedArea.X, Editor.PushedArea.Width);
10195
}
10296

@@ -118,7 +112,7 @@ protected override Vector GetPushOffset(Vector offset)
118112
protected override Rect CalculatePushedArea(double position, double offset)
119113
=> new Rect(Editor.ViewportLocation.X - OffscreenOffset, position, Editor.ViewportSize.Width + OffscreenOffset * 2, offset);
120114

121-
public override Rect OnViewportChanged()
115+
public override Rect GetPushedArea()
122116
=> CalculatePushedArea(Editor.PushedArea.Y, Editor.PushedArea.Height);
123117
}
124118
}

Nodify/ItemContainer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ public class ItemContainer : ContentControl, INodifyCanvasItem
2525
public static readonly DependencyProperty SelectedBorderThicknessProperty = DependencyProperty.Register(nameof(SelectedBorderThickness), typeof(Thickness), typeof(ItemContainer), new FrameworkPropertyMetadata(BoxValue.Thickness2));
2626
public static readonly DependencyProperty IsSelectableProperty = DependencyProperty.Register(nameof(IsSelectable), typeof(bool), typeof(ItemContainer), new FrameworkPropertyMetadata(BoxValue.True));
2727
public static readonly DependencyProperty IsSelectedProperty = Selector.IsSelectedProperty.AddOwner(typeof(ItemContainer), new FrameworkPropertyMetadata(BoxValue.False, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsSelectedChanged));
28-
public static readonly DependencyPropertyKey IsPreviewingSelectionPropertyKey = DependencyProperty.RegisterReadOnly(nameof(IsPreviewingSelection), typeof(bool?), typeof(ItemContainer), new FrameworkPropertyMetadata(null));
28+
protected static readonly DependencyPropertyKey IsPreviewingSelectionPropertyKey = DependencyProperty.RegisterReadOnly(nameof(IsPreviewingSelection), typeof(bool?), typeof(ItemContainer), new FrameworkPropertyMetadata(null));
2929
public static readonly DependencyProperty IsPreviewingSelectionProperty = IsPreviewingSelectionPropertyKey.DependencyProperty;
3030
public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(nameof(Location), typeof(Point), typeof(ItemContainer), new FrameworkPropertyMetadata(BoxValue.Point, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnLocationChanged));
3131
public static readonly DependencyProperty ActualSizeProperty = DependencyProperty.Register(nameof(ActualSize), typeof(Size), typeof(ItemContainer), new FrameworkPropertyMetadata(BoxValue.Size));
3232
public static readonly DependencyProperty DesiredSizeForSelectionProperty = DependencyProperty.Register(nameof(DesiredSizeForSelection), typeof(Size?), typeof(ItemContainer), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.NotDataBindable));
33-
public static readonly DependencyPropertyKey IsPreviewingLocationPropertyKey = DependencyProperty.RegisterReadOnly(nameof(IsPreviewingLocation), typeof(bool), typeof(ItemContainer), new FrameworkPropertyMetadata(BoxValue.False));
33+
private static readonly DependencyPropertyKey IsPreviewingLocationPropertyKey = DependencyProperty.RegisterReadOnly(nameof(IsPreviewingLocation), typeof(bool), typeof(ItemContainer), new FrameworkPropertyMetadata(BoxValue.False));
3434
public static readonly DependencyProperty IsPreviewingLocationProperty = IsPreviewingLocationPropertyKey.DependencyProperty;
3535
public static readonly DependencyProperty IsDraggableProperty = DependencyProperty.Register(nameof(IsDraggable), typeof(bool), typeof(ItemContainer), new FrameworkPropertyMetadata(BoxValue.True));
3636

Nodify/Nodes/Node.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class Node : HeaderedContentControl
2525
public static readonly DependencyProperty FooterProperty = DependencyProperty.Register(nameof(Footer), typeof(object), typeof(Node), new FrameworkPropertyMetadata(OnFooterChanged));
2626
public static readonly DependencyProperty FooterTemplateProperty = DependencyProperty.Register(nameof(FooterTemplate), typeof(DataTemplate), typeof(Node));
2727
public static readonly DependencyProperty InputConnectorTemplateProperty = DependencyProperty.Register(nameof(InputConnectorTemplate), typeof(DataTemplate), typeof(Node));
28-
protected internal static readonly DependencyPropertyKey HasFooterPropertyKey = DependencyProperty.RegisterReadOnly(nameof(HasFooter), typeof(bool), typeof(Node), new FrameworkPropertyMetadata(BoxValue.False));
28+
protected static readonly DependencyPropertyKey HasFooterPropertyKey = DependencyProperty.RegisterReadOnly(nameof(HasFooter), typeof(bool), typeof(Node), new FrameworkPropertyMetadata(BoxValue.False));
2929
public static readonly DependencyProperty HasFooterProperty = HasFooterPropertyKey.DependencyProperty;
3030
public static readonly DependencyProperty OutputConnectorTemplateProperty = DependencyProperty.Register(nameof(OutputConnectorTemplate), typeof(DataTemplate), typeof(Node));
3131
public static readonly DependencyProperty InputProperty = DependencyProperty.Register(nameof(Input), typeof(IEnumerable), typeof(Node));

Nodify/NodifyEditor.Dragging.cs

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
using System.Windows.Input;
2+
using System.Windows;
3+
using System.Collections.Generic;
4+
using System.Windows.Controls.Primitives;
5+
using System.Diagnostics;
6+
7+
namespace Nodify
8+
{
9+
public partial class NodifyEditor
10+
{
11+
public static readonly DependencyProperty ItemsDragStartedCommandProperty = DependencyProperty.Register(nameof(ItemsDragStartedCommand), typeof(ICommand), typeof(NodifyEditor));
12+
public static readonly DependencyProperty ItemsDragCompletedCommandProperty = DependencyProperty.Register(nameof(ItemsDragCompletedCommand), typeof(ICommand), typeof(NodifyEditor));
13+
14+
protected static readonly DependencyPropertyKey IsDraggingPropertyKey = DependencyProperty.RegisterReadOnly(nameof(IsDragging), typeof(bool), typeof(NodifyEditor), new FrameworkPropertyMetadata(BoxValue.False, OnIsDraggingChanged));
15+
public static readonly DependencyProperty IsDraggingProperty = IsDraggingPropertyKey.DependencyProperty;
16+
17+
private static void OnIsDraggingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
18+
{
19+
var editor = (NodifyEditor)d;
20+
21+
if ((bool)e.NewValue == true)
22+
{
23+
editor.OnItemsDragStarted();
24+
}
25+
else
26+
{
27+
editor.OnItemsDragCompleted();
28+
}
29+
}
30+
31+
private void OnItemsDragCompleted()
32+
{
33+
if (ItemsDragCompletedCommand?.CanExecute(DataContext) ?? false)
34+
ItemsDragCompletedCommand.Execute(DataContext);
35+
}
36+
37+
private void OnItemsDragStarted()
38+
{
39+
if (ItemsDragStartedCommand?.CanExecute(DataContext) ?? false)
40+
ItemsDragStartedCommand.Execute(DataContext);
41+
}
42+
43+
/// <summary>
44+
/// Invoked when a drag operation starts for the <see cref="SelectedItems"/>, or when <see cref="IsPushingItems"/> is set to true.
45+
/// </summary>
46+
public ICommand? ItemsDragStartedCommand
47+
{
48+
get => (ICommand?)GetValue(ItemsDragStartedCommandProperty);
49+
set => SetValue(ItemsDragStartedCommandProperty, value);
50+
}
51+
52+
/// <summary>
53+
/// Invoked when a drag operation is completed for the <see cref="SelectedItems"/>, or when <see cref="IsPushingItems"/> is set to false.
54+
/// </summary>
55+
public ICommand? ItemsDragCompletedCommand
56+
{
57+
get => (ICommand?)GetValue(ItemsDragCompletedCommandProperty);
58+
set => SetValue(ItemsDragCompletedCommandProperty, value);
59+
}
60+
61+
/// <summary>
62+
/// Gets a value that indicates whether a dragging operation is in progress.
63+
/// </summary>
64+
public bool IsDragging
65+
{
66+
get => (bool)GetValue(IsDraggingProperty);
67+
private set => SetValue(IsDraggingPropertyKey, value);
68+
}
69+
70+
/// <summary>
71+
/// Gets or sets if the current position of containers that are being dragged should not be committed until the end of the dragging operation.
72+
/// </summary>
73+
public static bool EnableDraggingContainersOptimizations { get; set; } = true;
74+
75+
private IDraggingStrategy? _draggingStrategy;
76+
77+
private void RegisterDragEvents()
78+
{
79+
AddHandler(ItemContainer.DragStartedEvent, new DragStartedEventHandler(OnItemsDragStarted));
80+
AddHandler(ItemContainer.DragCompletedEvent, new DragCompletedEventHandler(OnItemsDragCompleted));
81+
AddHandler(ItemContainer.DragDeltaEvent, new DragDeltaEventHandler(OnItemsDragDelta));
82+
}
83+
84+
/// <summary>
85+
/// Initiates the dragging operation using the currently selected <see cref="ItemContainer" />s.
86+
/// </summary>
87+
/// <remarks>This method has no effect if a dragging operation is already in progress.</remarks>
88+
public void BeginDragging()
89+
=> BeginDragging(SelectedContainers);
90+
91+
/// <summary>
92+
/// Initiates the dragging operation for the specified <see cref="ItemContainer" />s.
93+
/// </summary>
94+
/// <param name="containers">The collection of item containers to be dragged.</param>
95+
/// <remarks>This method has no effect if a dragging operation is already in progress.</remarks>
96+
public void BeginDragging(IEnumerable<ItemContainer> containers)
97+
{
98+
if(IsDragging)
99+
{
100+
return;
101+
}
102+
103+
IsDragging = true;
104+
_draggingStrategy = CreateDraggingStrategy(containers);
105+
}
106+
107+
/// <summary>
108+
/// Updates the position of the items being dragged by a specified offset.
109+
/// </summary>
110+
/// <param name="amount">The vector by which to adjust the position of the dragged items.</param>
111+
/// This method adjusts the items positions incrementally. It should only be called while a dragging operation is in progress (see <see cref="BeginDragging"/>).
112+
/// </remarks>
113+
public void UpdateDragging(Vector amount)
114+
{
115+
Debug.Assert(IsDragging);
116+
_draggingStrategy!.Update(amount);
117+
}
118+
119+
/// <summary>
120+
/// Completes the dragging operation, finalizing the position of the dragged items.
121+
/// </summary>
122+
/// <remarks>This method has no effect if there's no dragging operation in progress.</remarks>
123+
public void EndDragging()
124+
{
125+
if (!IsDragging)
126+
{
127+
return;
128+
}
129+
130+
IsBulkUpdatingItems = true;
131+
_draggingStrategy!.End();
132+
IsBulkUpdatingItems = false;
133+
134+
// Draw the containers at the new position.
135+
ItemsHost.InvalidateArrange();
136+
137+
_draggingStrategy = null;
138+
IsDragging = false;
139+
}
140+
141+
/// <summary>
142+
/// Cancels the ongoing dragging operation, reverting any changes made to the positions of the dragged items.
143+
/// </summary>
144+
/// <remarks>This method has no effect if there's no dragging operation in progress.</remarks>
145+
public void CancelDragging()
146+
{
147+
if (!ItemContainer.AllowDraggingCancellation || !IsDragging)
148+
{
149+
return;
150+
}
151+
152+
_draggingStrategy!.Abort();
153+
IsDragging = false;
154+
}
155+
156+
private IDraggingStrategy CreateDraggingStrategy(IEnumerable<ItemContainer> containers)
157+
{
158+
if (EnableDraggingContainersOptimizations)
159+
{
160+
return new DraggingOptimized(containers, GridCellSize);
161+
}
162+
163+
return new DraggingSimple(containers, GridCellSize);
164+
}
165+
166+
private void OnItemsDragStarted(object sender, DragStartedEventArgs e)
167+
{
168+
BeginDragging();
169+
e.Handled = true;
170+
}
171+
172+
private void OnItemsDragDelta(object sender, DragDeltaEventArgs e)
173+
{
174+
UpdateDragging(new Vector(e.HorizontalChange, e.VerticalChange));
175+
}
176+
177+
private void OnItemsDragCompleted(object sender, DragCompletedEventArgs e)
178+
{
179+
if (e.Canceled)
180+
{
181+
CancelDragging();
182+
}
183+
else
184+
{
185+
EndDragging();
186+
}
187+
}
188+
}
189+
}

0 commit comments

Comments
 (0)