Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move all items relative to the cursor by performing a drag gesture #150

Merged
merged 7 commits into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
> - Added InputGroupStyle and OutputGroupStyle to Node
> - Added PanWithMouseWheel, PanHorizontalModifierKey and PanVerticalModifierKey to EditorGestures.Editor
> - Added CornerRadius dependency property to LineConnection, CircuitConnection and StepConnection
> - Added EditorGestures.Editor.PushItems gesture used to start pushing ItemContainers vertically or horizontally
> - Added PushedAreaStyle, PushedAreaOrientation and IsPushingItems dependency properties to NodifyEditor
> - Added NodifyEditor.SnapToGrid utility function
> - Bugfixes:

#### **Version 6.5.0**
Expand Down
15 changes: 1 addition & 14 deletions Nodify/Connections/ConnectionsMultiSelector.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
Expand Down Expand Up @@ -45,18 +44,6 @@ private bool CanSelectMultipleItemsBase
set => base.CanSelectMultipleItems = value;
}

/// <summary>
/// The <see cref="NodifyEditor"/> that owns this <see cref="ConnectionsMultiSelector"/>.
/// </summary>
public NodifyEditor Editor { get; private set; } = default!;

public override void OnApplyTemplate()
{
base.OnApplyTemplate();

Editor = this.GetParentOfType<NodifyEditor>() ?? throw new NotSupportedException($"{nameof(ConnectionsMultiSelector)} cannot be used outside the {nameof(NodifyEditor)}");
}

protected override DependencyObject GetContainerForItemOverride()
{
return new ConnectionContainer(this);
Expand Down
8 changes: 7 additions & 1 deletion Nodify/EditorGestures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public NodifyEditorGestures()
{
Selection = new SelectionGestures();
Cutting = new MouseGesture(MouseAction.LeftClick, ModifierKeys.Alt | ModifierKeys.Shift);
PushItems = new MouseGesture(MouseAction.LeftClick, ModifierKeys.Control | ModifierKeys.Shift);
Pan = new AnyGesture(new MouseGesture(MouseAction.RightClick), new MouseGesture(MouseAction.MiddleClick));
ZoomModifierKey = ModifierKeys.None;
ZoomIn = new MultiGesture(MultiGesture.Match.Any, new KeyGesture(Key.OemPlus, ModifierKeys.Control), new KeyGesture(Key.Add, ModifierKeys.Control));
Expand Down Expand Up @@ -145,7 +146,11 @@ public NodifyEditorGestures()
/// <remarks>Defaults to <see cref="ModifierKeys.Shift"/>.</remarks>
public ModifierKeys PanHorizontalModifierKey { get; set; }

/// <summary>The modifier key required to start zooming with the mouse wheel.</summary>
/// <summary>Gesture used to start pushing.</summary>
/// <remarks>Defaults to <see cref="ModifierKeys.Control"/>+<see cref="ModifierKeys.Shift"/>+<see cref="MouseAction.LeftClick"/>.</remarks>
public InputGestureRef PushItems { get; }

/// <summary>The key modifier required to start zooming by mouse wheel.</summary>
/// <remarks>Defaults to <see cref="ModifierKeys.None"/>.</remarks>
public ModifierKeys ZoomModifierKey { get; set; }

Expand Down Expand Up @@ -185,6 +190,7 @@ public void Apply(NodifyEditorGestures gestures)
PanWithMouseWheel = gestures.PanWithMouseWheel;
PanHorizontalModifierKey = gestures.PanHorizontalModifierKey;
PanVerticalModifierKey = gestures.PanVerticalModifierKey;
PushItems.Value = gestures.PushItems.Value;
}
}

Expand Down
4 changes: 4 additions & 0 deletions Nodify/EditorStates/EditorDefaultState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ public override void HandleMouseDown(MouseButtonEventArgs e)
{
PushState(new EditorCuttingState(Editor));
}
else if (gestures.PushItems.Matches(e.Source, e))
{
PushState(new EditorPushingItemsState(Editor));
}
else if (gestures.Selection.Select.Matches(e.Source, e))
{
SelectionType selectionType = GetSelectionType(e);
Expand Down
89 changes: 89 additions & 0 deletions Nodify/EditorStates/EditorPushingItemsState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Nodify
{
public class EditorPushingItemsState : EditorState
{
private Point _prevPosition;
private const int _minDragDistance = 10;

public bool Canceled { get; set; } = NodifyEditor.AllowPushItemsCancellation;

public EditorPushingItemsState(NodifyEditor editor) : base(editor)
{
}

public override void Enter(EditorState? from)
{
Canceled = false;

_prevPosition = Editor.MouseLocation;
}

public override void Exit()
{
if (!Editor.IsPushingItems)
{
return;
}

if (Canceled)
{
Editor.CancelPushingItems();
}
else
{
Editor.EndPushingItems();
}
}

public override void HandleMouseMove(MouseEventArgs e)
{
if (Editor.IsPushingItems)
{
Editor.PushItems(Editor.MouseLocation - _prevPosition);
_prevPosition = Editor.MouseLocation;
}
else
{
if (Math.Abs(Editor.MouseLocation.X - _prevPosition.X) >= _minDragDistance)
{
Editor.StartPushingItems(_prevPosition, Orientation.Horizontal);
}
else if (Math.Abs(Editor.MouseLocation.Y - _prevPosition.Y) >= _minDragDistance)
{
Editor.StartPushingItems(_prevPosition, Orientation.Vertical);
}
}
}

public override void HandleMouseUp(MouseButtonEventArgs e)
{
EditorGestures.NodifyEditorGestures gestures = EditorGestures.Mappings.Editor;
if (gestures.PushItems.Matches(e.Source, e))
{
PopState();
}
else if (NodifyEditor.AllowPushItemsCancellation && gestures.CancelAction.Matches(e.Source, e))
{
Canceled = true;
e.Handled = true; // prevents opening context menu

PopState();
}
}

public override void HandleKeyUp(KeyEventArgs e)
{
EditorGestures.NodifyEditorGestures gestures = EditorGestures.Mappings.Editor;
if (NodifyEditor.AllowPushItemsCancellation && gestures.CancelAction.Matches(e.Source, e))
{
Canceled = true;
PopState();
}
}
}
}
27 changes: 11 additions & 16 deletions Nodify/Helpers/DraggingOptimized.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ namespace Nodify
/// <summary>
/// Commits the position changes at the end of the operation. Updates the RenderTransform to preview the container position.
/// </summary>
internal class DraggingOptimized : IDraggingStrategy
internal sealed class DraggingOptimized : IDraggingStrategy
{
private readonly NodifyEditor _editor;
private Vector _dragAccumulator;
private readonly uint _gridCellSize;
private readonly List<ItemContainer> _selectedContainers;
private Vector _dragAccumulator = new Vector(0, 0);

public DraggingOptimized(NodifyEditor editor)
public DraggingOptimized(IEnumerable<ItemContainer> containers, uint gridCellSize)
{
_editor = editor;
_selectedContainers = _editor.SelectedContainers.Where(c => c.IsDraggable).ToList();
_gridCellSize = gridCellSize;
_selectedContainers = containers.Where(c => c.IsDraggable).ToList();
}

public void Abort(Vector change)
public void Abort()
{
for (var i = 0; i < _selectedContainers.Count; i++)
{
Expand All @@ -36,7 +36,7 @@ public void Abort(Vector change)
_selectedContainers.Clear();
}

public void End(Vector change)
public void End()
{
for (var i = 0; i < _selectedContainers.Count; i++)
{
Expand All @@ -48,8 +48,8 @@ public void End(Vector change)
// Correct the final position
if (NodifyEditor.EnableSnappingCorrection && (r.X != 0 || r.Y != 0))
{
result.X = (int)result.X / _editor.GridCellSize * _editor.GridCellSize;
result.Y = (int)result.Y / _editor.GridCellSize * _editor.GridCellSize;
result.X = (int)result.X / _gridCellSize * _gridCellSize;
result.Y = (int)result.Y / _gridCellSize * _gridCellSize;
}

container.Location = result;
Expand All @@ -61,15 +61,10 @@ public void End(Vector change)
_selectedContainers.Clear();
}

public void Start(Vector change)
{
_dragAccumulator = new Vector(0, 0);
}

public void Update(Vector change)
{
_dragAccumulator += change;
var delta = new Vector((int)_dragAccumulator.X / _editor.GridCellSize * _editor.GridCellSize, (int)_dragAccumulator.Y / _editor.GridCellSize * _editor.GridCellSize);
var delta = new Vector((int)_dragAccumulator.X / _gridCellSize * _gridCellSize, (int)_dragAccumulator.Y / _gridCellSize * _gridCellSize);
_dragAccumulator -= delta;

if (delta.X != 0 || delta.Y != 0)
Expand Down
37 changes: 15 additions & 22 deletions Nodify/Helpers/DraggingSimple.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,25 @@ namespace Nodify
{
internal interface IDraggingStrategy
{
void Start(Vector change);
void Update(Vector change);
void End(Vector change);
void Abort(Vector change);
void End();
void Abort();
}

internal class DraggingSimple : IDraggingStrategy
internal sealed class DraggingSimple : IDraggingStrategy
{
private readonly NodifyEditor _editor;
private Vector _dragOffset;
private Vector _dragAccumulator;
private readonly IList<ItemContainer> _selectedContainers;
private readonly uint _gridCellSize;
private readonly List<ItemContainer> _selectedContainers;
private Vector _dragOffset = new Vector(0, 0);
private Vector _dragAccumulator = new Vector(0, 0);

public DraggingSimple(NodifyEditor editor)
public DraggingSimple(IEnumerable<ItemContainer> containers, uint gridCellSize)
{
_editor = editor;
_selectedContainers = _editor.SelectedContainers.Where(c => c.IsDraggable).ToList();
_gridCellSize = gridCellSize;
_selectedContainers = containers.Where(c => c.IsDraggable).ToList();
}

public void Abort(Vector change)
public void Abort()
{
for (var i = 0; i < _selectedContainers.Count; i++)
{
Expand All @@ -36,7 +35,7 @@ public void Abort(Vector change)
_selectedContainers.Clear();
}

public void End(Vector change)
public void End()
{
for (var i = 0; i < _selectedContainers.Count; i++)
{
Expand All @@ -46,8 +45,8 @@ public void End(Vector change)
// Correct the final position
if (NodifyEditor.EnableSnappingCorrection)
{
result.X = (int)result.X / _editor.GridCellSize * _editor.GridCellSize;
result.Y = (int)result.Y / _editor.GridCellSize * _editor.GridCellSize;
result.X = (int)result.X / _gridCellSize * _gridCellSize;
result.Y = (int)result.Y / _gridCellSize * _gridCellSize;
}

container.Location = result;
Expand All @@ -56,16 +55,10 @@ public void End(Vector change)
_selectedContainers.Clear();
}

public void Start(Vector change)
{
_dragOffset = new Vector(0, 0);
_dragAccumulator = new Vector(0, 0);
}

public void Update(Vector change)
{
_dragAccumulator += change;
var delta = new Vector((int)_dragAccumulator.X / _editor.GridCellSize * _editor.GridCellSize, (int)_dragAccumulator.Y / _editor.GridCellSize * _editor.GridCellSize);
var delta = new Vector((int)_dragAccumulator.X / _gridCellSize * _gridCellSize, (int)_dragAccumulator.Y / _gridCellSize * _gridCellSize);
_dragAccumulator -= delta;

if (delta.X != 0 || delta.Y != 0)
Expand Down
Loading
Loading