Skip to content
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
> - Made the setter of NodifyEditor.IsPanning private
> - Renamed StartCutting to BeginCutting in NodifyEditor
> - Renamed PushItems to UpdatePushedArea and StartPushingItems to BeginPushingItems in NodifyEditor
> - Renamed UnselectAllConnection to UnselectAllConnections in NodifyEditor
> - Features:
> - Added BeginPanning, UpdatePanning, EndPanning, CancelPanning and AllowPanningCancellation to NodifyEditor
> - Added UpdateCuttingLine to NodifyEditor
> - Added BeginSelecting, UpdateSelection, EndSelecting, CancelSelecting and AllowSelectionCancellation to NodifyEditor
> - Bugfixes:

#### **Version 6.6.0**
Expand Down
2 changes: 1 addition & 1 deletion Nodify/EditorStates/EditorCuttingState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Nodify
{
public class EditorCuttingState : EditorState
{
public bool Canceled { get; set; } = CuttingLine.AllowCuttingCancellation;
private bool Canceled { get; set; } = CuttingLine.AllowCuttingCancellation;

public EditorCuttingState(NodifyEditor editor) : base(editor)
{
Expand Down
20 changes: 9 additions & 11 deletions Nodify/EditorStates/EditorDefaultState.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Windows;
using System.Windows.Input;
using static Nodify.SelectionHelper;

namespace Nodify
{
Expand Down Expand Up @@ -32,23 +31,22 @@ public EditorDefaultState(NodifyEditor editor) : base(editor)
public override void HandleMouseDown(MouseButtonEventArgs e)
{
EditorGestures.NodifyEditorGestures gestures = EditorGestures.Mappings.Editor;
if (gestures.Cutting.Matches(e.Source, e))
if (Editor.CanSelectMultipleItems && gestures.Selection.Select.Matches(e.Source, e))
{
PushState(new EditorCuttingState(Editor));
SelectionType selectionType = SelectionHelper.GetSelectionType(e);
PushState(new EditorSelectingState(Editor, selectionType));
}
else if (gestures.PushItems.Matches(e.Source, e))
else if (!Editor.DisablePanning && gestures.Pan.Matches(e.Source, e))
{
PushState(new EditorPushingItemsState(Editor));
PushState(new EditorPanningState(Editor));
}
else if (gestures.Selection.Select.Matches(e.Source, e))
else if (gestures.Cutting.Matches(e.Source, e))
{
SelectionType selectionType = GetSelectionType(e);
var selecting = new EditorSelectingState(Editor, selectionType);
PushState(selecting);
PushState(new EditorCuttingState(Editor));
}
else if (!Editor.DisablePanning && gestures.Pan.Matches(e.Source, e))
else if (gestures.PushItems.Matches(e.Source, e))
{
PushState(new EditorPanningState(Editor));
PushState(new EditorPushingItemsState(Editor));
}
}

Expand Down
2 changes: 1 addition & 1 deletion Nodify/EditorStates/EditorPushingItemsState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class EditorPushingItemsState : EditorState
private Point _prevPosition;
private const int _minDragDistance = 10;

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

public EditorPushingItemsState(NodifyEditor editor) : base(editor)
{
Expand Down
41 changes: 20 additions & 21 deletions Nodify/EditorStates/EditorSelectingState.cs
Original file line number Diff line number Diff line change
@@ -1,51 +1,46 @@
using System.Windows.Input;
using static Nodify.SelectionHelper;

namespace Nodify
{
/// <summary>The selecting state of the editor.</summary>
public class EditorSelectingState : EditorState
{
private readonly SelectionType _type;
private bool _canceled;

/// <summary>The selection helper.</summary>
protected SelectionHelper Selection { get; }
private bool Canceled { get; set; } = NodifyEditor.AllowSelectionCancellation;

/// <summary>Constructs an instance of the <see cref="EditorSelectingState"/> state.</summary>
/// <param name="editor">The owner of the state.</param>
/// <param name="type">The selection strategy.</param>
public EditorSelectingState(NodifyEditor editor, SelectionType type) : base(editor)
{
Selection = new SelectionHelper(editor);
_type = type;
}

/// <inheritdoc />
public override void Enter(EditorState? from)
{
Editor.UnselectAllConnection();
Canceled = false;

_canceled = false;
Selection.Start(Editor.MouseLocation, _type);
Editor.BeginSelecting(Editor.MouseLocation, _type);
}

/// <inheritdoc />
public override void Exit()
{
if (_canceled)
// TODO: This is not canceled on LostMouseCapture (add OnLostMouseCapture/OnCancel callback?)
if (Canceled)
{
Selection.Abort();
Editor.CancelSelecting();
}
else
{
Selection.End();
Editor.EndSelecting();
}
}

/// <inheritdoc />
public override void HandleMouseMove(MouseEventArgs e)
=> Selection.Update(Editor.MouseLocation);
public override void HandleMouseMove(MouseEventArgs e)
=> Editor.UpdateSelection(Editor.MouseLocation);

/// <inheritdoc />
public override void HandleMouseDown(MouseButtonEventArgs e)
Expand All @@ -60,12 +55,15 @@ public override void HandleMouseDown(MouseButtonEventArgs e)
public override void HandleMouseUp(MouseButtonEventArgs e)
{
EditorGestures.SelectionGestures gestures = EditorGestures.Mappings.Editor.Selection;

bool canCancel = gestures.Cancel.Matches(e.Source, e);
bool canComplete = gestures.Select.Matches(e.Source, e);
if (canCancel || canComplete)
if(gestures.Select.Matches(e.Source, e))
{
_canceled = !canComplete && canCancel;
PopState();
}
else if(NodifyEditor.AllowSelectionCancellation && gestures.Cancel.Matches(e.Source, e))
{
Canceled = true;
e.Handled = true; // prevents opening context menu

PopState();
}
}
Expand All @@ -76,9 +74,10 @@ public override void HandleAutoPanning(MouseEventArgs e)

public override void HandleKeyUp(KeyEventArgs e)
{
if (EditorGestures.Mappings.Editor.Selection.Cancel.Matches(e.Source, e))
EditorGestures.SelectionGestures gestures = EditorGestures.Mappings.Editor.Selection;
if (NodifyEditor.AllowSelectionCancellation && gestures.Cancel.Matches(e.Source, e))
{
_canceled = true;
Canceled = true;
PopState();
}
}
Expand Down
111 changes: 44 additions & 67 deletions Nodify/Helpers/SelectionHelper.cs
Original file line number Diff line number Diff line change
@@ -1,96 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Nodify
{
/// <summary>
/// Helps with selecting <see cref="ItemContainer"/>s and updating the <see cref="NodifyEditor.SelectedArea"/> and <see cref="NodifyEditor.IsSelecting"/> properties.
/// Helps with selecting <see cref="ItemContainer"/>s.
/// </summary>
public sealed class SelectionHelper
internal sealed class SelectionHelper
{
private readonly NodifyEditor _host;
private Point _startLocation;
private Point _endLocation;
private SelectionType _selectionType;
private bool _isRealtime;
private IReadOnlyList<ItemContainer> _initialSelection = new List<ItemContainer>();

/// <summary>Constructs a new instance of a <see cref="SelectionHelper"/>.</summary>
/// <param name="host">The editor to select items from.</param>
public SelectionHelper(NodifyEditor host)
=> _host = host;

/// <summary>Available selection logic.</summary>
public enum SelectionType
{
/// <summary>Replaces the old selection.</summary>
Replace,
/// <summary>Removes items from existing selection.</summary>
Remove,
/// <summary>Adds items to the current selection.</summary>
Append,
/// <summary>Inverts the selection.</summary>
Invert
}
private IReadOnlyCollection<ItemContainer> _items = Array.Empty<ItemContainer>();
private IReadOnlyList<ItemContainer> _initialSelection = Array.Empty<ItemContainer>();
private Rect _selectedArea;

/// <summary>Attempts to start a new selection.</summary>
/// <param name="containers">The containers that can be part of the selection.</param>
/// <param name="location">The location inside the graph.</param>
/// <param name="selectionType">The type of selection.</param>
/// <remarks>Will not do anything if selection is in progress.</remarks>
public void Start(Point location, SelectionType selectionType)
public Rect Start(IEnumerable<ItemContainer> containers, Point location, SelectionType selectionType, bool realtime)
{
if (!_host.IsSelecting)
{
_selectionType = selectionType;
_initialSelection = _host.SelectedContainers;
_items = containers.Where(x => x.IsSelectable).ToList();
_initialSelection = containers.Where(x => x.IsSelected).ToList();

_isRealtime = _host.EnableRealtimeSelection;
_startLocation = location;
_selectionType = selectionType;

_host.SelectedArea = new Rect();
_host.IsSelecting = true;
}
_isRealtime = realtime;
_startLocation = location;
_endLocation = location;

_selectedArea = new Rect();
return _selectedArea;
}

/// <summary>Update the end location for the selection.</summary>
/// <param name="endLocation">An absolute location.</param>
public void Update(Point endLocation)
public Rect Update(Point endLocation)
{
double left = endLocation.X < _startLocation.X ? endLocation.X : _startLocation.X;
double top = endLocation.Y < _startLocation.Y ? endLocation.Y : _startLocation.Y;
double width = Math.Abs(endLocation.X - _startLocation.X);
double height = Math.Abs(endLocation.Y - _startLocation.Y);
_endLocation = endLocation;

double left = _endLocation.X < _startLocation.X ? _endLocation.X : _startLocation.X;
double top = _endLocation.Y < _startLocation.Y ? _endLocation.Y : _startLocation.Y;
double width = Math.Abs(_endLocation.X - _startLocation.X);
double height = Math.Abs(_endLocation.Y - _startLocation.Y);

_host.SelectedArea = new Rect(left, top, width, height);
_selectedArea = new Rect(left, top, width, height);

if (_isRealtime)
{
PreviewSelection(_host.SelectedArea);
PreviewSelection(_selectedArea);
}

return _selectedArea;
}

/// <summary>Commits the current selection to the editor.</summary>
public void End()
/// <summary>Increase the selected area by the specified amount.</summary>
public Rect Update(Vector amount)
{
if (_host.IsSelecting)
{
PreviewSelection(_host.SelectedArea);
_endLocation += amount;

_host.ApplyPreviewingSelection();
_host.IsSelecting = false;
}
return Update(_endLocation);
}

/// <summary>Aborts the current selection.</summary>
public void Abort()
/// <summary>Commits the current selection to the editor.</summary>
public Rect End()
{
if (_host.IsSelecting)
{
_host.ClearPreviewingSelection();
_host.IsSelecting = false;
}
PreviewSelection(_selectedArea);
_items = Array.Empty<ItemContainer>();
_initialSelection = Array.Empty<ItemContainer>();

return _selectedArea;
}

private void PreviewSelection(Rect area)
Expand Down Expand Up @@ -128,10 +113,8 @@ private void PreviewSelection(Rect area)

private void PreviewUnselectAll()
{
ItemCollection items = _host.Items;
for (var i = 0; i < items.Count; i++)
foreach (var container in _items)
{
var container = (ItemContainer)_host.ItemContainerGenerator.ContainerFromIndex(i);
container.IsPreviewingSelection = false;
}
}
Expand All @@ -145,10 +128,8 @@ private void PreviewSelectArea(Rect area, bool append = false, bool fit = false)

if (area.X != 0 || area.Y != 0 || area.Width > 0 || area.Height > 0)
{
ItemCollection items = _host.Items;
for (var i = 0; i < items.Count; i++)
foreach (var container in _items)
{
var container = (ItemContainer)_host.ItemContainerGenerator.ContainerFromIndex(i);
if (container.IsSelectableInArea(area, fit))
{
container.IsPreviewingSelection = true;
Expand All @@ -159,10 +140,8 @@ private void PreviewSelectArea(Rect area, bool append = false, bool fit = false)

private void PreviewUnselectArea(Rect area, bool fit = false)
{
ItemCollection items = _host.Items;
for (var i = 0; i < items.Count; i++)
foreach (var container in _items)
{
var container = (ItemContainer)_host.ItemContainerGenerator.ContainerFromIndex(i);
if (container.IsSelectableInArea(area, fit))
{
container.IsPreviewingSelection = false;
Expand All @@ -180,10 +159,8 @@ private static void PreviewSelectContainers(IReadOnlyList<ItemContainer> contain

private void PreviewInvertSelection(Rect area, bool fit = false)
{
ItemCollection items = _host.Items;
for (var i = 0; i < items.Count; i++)
foreach (var container in _items)
{
var container = (ItemContainer)_host.ItemContainerGenerator.ContainerFromIndex(i);
if (container.IsSelectableInArea(area, fit))
{
container.IsPreviewingSelection = !container.IsPreviewingSelection;
Expand Down
Loading
Loading