Skip to content

Commit

Permalink
Allow changing editor gestures at runtime (#104)
Browse files Browse the repository at this point in the history
Separated selection gestures for ItemContainer and GroupingNode from the NodifyEditor
Added new gesture types: AnyGesture, AllGestures, and NodifyGesture
Fixed a bug where the item container would incorrectly transition to the dragging state on mouse over
  • Loading branch information
miroiu authored May 11, 2024
1 parent 3a0f905 commit 366a61e
Show file tree
Hide file tree
Showing 18 changed files with 422 additions and 111 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@
> - Breaking Changes:
> - Added a parameter for the orientation to DrawArrowGeometry, DrawDefaultArrowhead, DrawRectangleArrowhead and DrawEllipseArrowhead in BaseConnection
> - Added source and target parameters to GetTextPosition in BaseConnection
> - EditorGestures is now a singleton instead of a static class (can be inherited to create custom mappings)
> - Selection gestures for ItemContainer and GroupingNode are now separated from the NodifyEditor selection gestures
> - Renamed EditorGestures.Editor.Zoom to ZoomModifierKey
> - Features:
> - Added SourceOrientation and TargetOrientation to BaseConnection to support vertical connectors (vertical/mixed connection orientation)
> - Added DirectionalArrowsCount to BaseConnection to allow drawing multipe arrows on a connection flowing in the connection direction
> - Added DrawDirectionalArrowsGeometry and DrawDirectionalArrowheadGeometry to BaseConnection to allow customizing the directional arrows
> - Improved EditorGestures to allow changing input gestures at runtime
> - Added new gesture types: AnyGesture, AllGestures, and InputGestureRef
> - Bugfixes:
> - Fixed BaseConnection.Text not always displaying in the center of the connection
> - Fixed a bug where the item container would incorrectly transition to the dragging state on mouse over
#### **Version 5.2.0**

Expand Down
2 changes: 1 addition & 1 deletion Examples/Nodify.Calculator/OperationViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public OperationViewModel()
});
}

private void OnInputValueChanged(object sender, PropertyChangedEventArgs e)
private void OnInputValueChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ConnectorViewModel.Value))
{
Expand Down
70 changes: 70 additions & 0 deletions Examples/Nodify.Playground/EditorInputMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System.Windows.Input;

namespace Nodify.Playground
{
public enum EditorInputMode
{
Default,
PanOnly,
SelectOnly
}

public enum EditorGesturesMappings
{
Default,
Custom
}

public static class EditorInputModeExtensions
{
public static void Apply(this EditorGestures mappings, EditorInputMode inputMode)
{
mappings.Apply(PlaygroundSettings.Instance.EditorGesturesMappings.ToGesturesMappings());

switch (inputMode)
{
case EditorInputMode.PanOnly:
mappings.Editor.Selection.Apply(EditorGestures.SelectionGestures.None);
mappings.ItemContainer.Selection.Apply(EditorGestures.SelectionGestures.None);
mappings.ItemContainer.Drag.Value = MultiGesture.None;
mappings.Connector.Connect.Value = MultiGesture.None;
break;
case EditorInputMode.SelectOnly:
mappings.Editor.Pan.Value = MultiGesture.None;
mappings.ItemContainer.Drag.Value = MultiGesture.None;
mappings.Connector.Connect.Value = MultiGesture.None;
break;
case EditorInputMode.Default:
break;
}
}

public static void Apply(this EditorGestures value, EditorGesturesMappings mappings)
{
var newMappings = mappings.ToGesturesMappings();
value.Apply(newMappings);
}

public static EditorGestures ToGesturesMappings(this EditorGesturesMappings mappings)
{
return mappings switch
{
EditorGesturesMappings.Custom => new CustomGesturesMappings(),
_ => new EditorGestures()
};
}
}

public class CustomGesturesMappings : EditorGestures
{
public CustomGesturesMappings()
{
Editor.Pan.Value = new AnyGesture(new MouseGesture(MouseAction.LeftClick), new MouseGesture(MouseAction.MiddleClick));
Editor.ZoomModifierKey = ModifierKeys.Control;
Editor.Selection.Apply(new SelectionGestures(MouseAction.RightClick));
// comment to drag with right click - we copy the default gestures of the item container which uses left click for selection
ItemContainer.Drag.Value = new AnyGesture(ItemContainer.Selection.Replace.Value, ItemContainer.Selection.Remove.Value, ItemContainer.Selection.Append.Value, ItemContainer.Selection.Invert.Value);
ItemContainer.Selection.Apply(Editor.Selection);
}
}
}
6 changes: 3 additions & 3 deletions Examples/Nodify.Playground/EditorSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private EditorSettings()
() => Instance.ConnectionStyle,
val => Instance.ConnectionStyle = val,
"Connection style: "),
new ProxySettingViewModel<string>(
new ProxySettingViewModel<string?>(
() => Instance.ConnectionText,
val => Instance.ConnectionText = val,
"Connection text: "),
Expand Down Expand Up @@ -344,8 +344,8 @@ public ConnectionStyle ConnectionStyle
set => SetProperty(ref _connectionStyle, value);
}

private string _connectionText;
public string ConnectionText
private string? _connectionText;
public string? ConnectionText
{
get => _connectionText;
set => SetProperty(ref _connectionText, value);
Expand Down
27 changes: 25 additions & 2 deletions Examples/Nodify.Playground/PlaygroundSettings.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Nodify.Playground
Expand All @@ -12,6 +11,14 @@ private PlaygroundSettings()
{
Settings = new ObservableCollection<ISettingViewModel>()
{
new ProxySettingViewModel<EditorGesturesMappings>(
() => Instance.EditorGesturesMappings,
val => Instance.EditorGesturesMappings = val,
"Editor input mappings"),
new ProxySettingViewModel<EditorInputMode>(
() => Instance.EditorInputMode,
val => Instance.EditorInputMode = val,
"Editor input mode"),
new ProxySettingViewModel<bool>(
() => Instance.ShowGridLines,
val => Instance.ShowGridLines = val,
Expand Down Expand Up @@ -53,6 +60,22 @@ private PlaygroundSettings()

public static PlaygroundSettings Instance { get; } = new PlaygroundSettings();

private EditorGesturesMappings _editorGesturesMappings;
public EditorGesturesMappings EditorGesturesMappings
{
get => _editorGesturesMappings;
set => SetProperty(ref _editorGesturesMappings, value)
.Then(() => EditorGestures.Mappings.Apply(value));
}

private EditorInputMode _editorInputMode;
public EditorInputMode EditorInputMode
{
get => _editorInputMode;
set => SetProperty(ref _editorInputMode, value)
.Then(() => EditorGestures.Mappings.Apply(value));
}

private bool _shouldConnectNodes = true;
public bool ShouldConnectNodes
{
Expand Down
5 changes: 3 additions & 2 deletions Nodify/Connections/BaseConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,8 @@ protected override void OnMouseDown(MouseButtonEventArgs e)

this.CaptureMouseSafe();

if (EditorGestures.Connection.Split.Matches(e.Source, e) && (SplitCommand?.CanExecute(this) ?? false))
EditorGestures.ConnectionGestures gestures = EditorGestures.Mappings.Connection;
if (gestures.Split.Matches(e.Source, e) && (SplitCommand?.CanExecute(this) ?? false))
{
Point splitLocation = e.GetPosition(this);
object? connection = DataContext;
Expand All @@ -668,7 +669,7 @@ protected override void OnMouseDown(MouseButtonEventArgs e)

e.Handled = true;
}
else if (EditorGestures.Connection.Disconnect.Matches(e.Source, e) && (DisconnectCommand?.CanExecute(this) ?? false))
else if (gestures.Disconnect.Matches(e.Source, e) && (DisconnectCommand?.CanExecute(this) ?? false))
{
Point splitLocation = e.GetPosition(this);
object? connection = DataContext;
Expand Down
12 changes: 7 additions & 5 deletions Nodify/Connections/Connector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -327,11 +327,12 @@ protected override void OnMouseDown(MouseButtonEventArgs e)

e.Handled = true;

if (EditorGestures.Connector.Disconnect.Matches(e.Source, e))
EditorGestures.ConnectorGestures gestures = EditorGestures.Mappings.Connector;
if (gestures.Disconnect.Matches(e.Source, e))
{
OnDisconnect();
}
else if (EditorGestures.Connector.Connect.Matches(e.Source, e))
else if (gestures.Connect.Matches(e.Source, e))
{
if (EnableStickyConnections && IsPendingConnection)
{
Expand All @@ -351,12 +352,13 @@ protected override void OnMouseUp(MouseButtonEventArgs e)
// Don't select the ItemContainer when starting a pending connecton for sticky connections
e.Handled = EnableStickyConnections && IsPendingConnection;

if (!EnableStickyConnections && EditorGestures.Connector.Connect.Matches(e.Source, e))
EditorGestures.ConnectorGestures gestures = EditorGestures.Mappings.Connector;
if (!EnableStickyConnections && gestures.Connect.Matches(e.Source, e))
{
OnConnectorDragCompleted();
e.Handled = true;
}
else if (AllowPendingConnectionCancellation && IsPendingConnection && EditorGestures.Connector.CancelAction.Matches(e.Source, e))
else if (AllowPendingConnectionCancellation && IsPendingConnection && gestures.CancelAction.Matches(e.Source, e))
{
// Cancel pending connection
OnConnectorDragCompleted(cancel: true);
Expand All @@ -375,7 +377,7 @@ protected override void OnMouseUp(MouseButtonEventArgs e)
/// <inheritdoc />
protected override void OnKeyUp(KeyEventArgs e)
{
if (AllowPendingConnectionCancellation && EditorGestures.Connector.CancelAction.Matches(e.Source, e))
if (AllowPendingConnectionCancellation && EditorGestures.Mappings.Connector.CancelAction.Matches(e.Source, e))
{
// Cancel pending connection
OnConnectorDragCompleted(cancel: true);
Expand Down
8 changes: 4 additions & 4 deletions Nodify/EditorCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ public enum Alignment
/// </summary>
public static RoutedUICommand ZoomIn { get; } = new RoutedUICommand("Zoom in", nameof(ZoomIn), typeof(EditorCommands), new InputGestureCollection
{
EditorGestures.ZoomIn
EditorGestures.Mappings.Editor.ZoomIn
});

/// <summary>
/// Zoom out relative to the editor's viewport center.
/// </summary>
public static RoutedUICommand ZoomOut { get; } = new RoutedUICommand("Zoom out", nameof(ZoomOut), typeof(EditorCommands), new InputGestureCollection
{
EditorGestures.ZoomOut
EditorGestures.Mappings.Editor.ZoomOut
});

/// <summary>
Expand All @@ -50,15 +50,15 @@ public enum Alignment
/// </summary>
public static RoutedUICommand BringIntoView { get; } = new RoutedUICommand("Bring location into view", nameof(BringIntoView), typeof(EditorCommands), new InputGestureCollection
{
EditorGestures.ResetViewportLocation
EditorGestures.Mappings.Editor.ResetViewportLocation
});

/// <summary>
/// Scales the editor's viewport to fit all the <see cref="ItemContainer"/>s if that's possible.
/// </summary>
public static RoutedUICommand FitToScreen { get; } = new RoutedUICommand("Fit to screen", nameof(FitToScreen), typeof(EditorCommands), new InputGestureCollection
{
EditorGestures.FitToScreen
EditorGestures.Mappings.Editor.FitToScreen
});

/// <summary>
Expand Down
Loading

0 comments on commit 366a61e

Please sign in to comment.