mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-01-01 18:23:32 +00:00
VisualScripting: Fixed Preview; Added auto-fit mode
This commit is contained in:
parent
405d5b756c
commit
7422a9667d
@ -15,7 +15,10 @@ namespace Artemis.Core
|
|||||||
Type ResultType { get; }
|
Type ResultType { get; }
|
||||||
|
|
||||||
object? Context { get; set; }
|
object? Context { get; set; }
|
||||||
|
|
||||||
|
event EventHandler<INode>? NodeAdded;
|
||||||
|
event EventHandler<INode>? NodeRemoved;
|
||||||
|
|
||||||
void Run();
|
void Run();
|
||||||
void AddNode(INode node);
|
void AddNode(INode node);
|
||||||
void RemoveNode(INode node);
|
void RemoveNode(INode node);
|
||||||
|
|||||||
@ -16,6 +16,9 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
bool IsEvaluated { get; set; }
|
bool IsEvaluated { get; set; }
|
||||||
|
|
||||||
|
event EventHandler<IPin> PinConnected;
|
||||||
|
event EventHandler<IPin> PinDisconnected;
|
||||||
|
|
||||||
void ConnectTo(IPin pin);
|
void ConnectTo(IPin pin);
|
||||||
void DisconnectFrom(IPin pin);
|
void DisconnectFrom(IPin pin);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,9 @@ namespace Artemis.Core
|
|||||||
PinDirection Direction { get; }
|
PinDirection Direction { get; }
|
||||||
Type Type { get; }
|
Type Type { get; }
|
||||||
|
|
||||||
|
event EventHandler<IPin> PinAdded;
|
||||||
|
event EventHandler<IPin> PinRemoved;
|
||||||
|
|
||||||
IPin AddPin();
|
IPin AddPin();
|
||||||
bool Remove(IPin pin);
|
bool Remove(IPin pin);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Artemis.Core
|
namespace Artemis.Core
|
||||||
{
|
{
|
||||||
public abstract class Node : CorePropertyChanged, INode
|
public abstract class Node : CorePropertyChanged, INode
|
||||||
{
|
{
|
||||||
public event EventHandler Resetting;
|
|
||||||
|
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
private string _name;
|
private string _name;
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get => _name;
|
get => _name;
|
||||||
@ -20,7 +16,6 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string _description;
|
private string _description;
|
||||||
|
|
||||||
public string Description
|
public string Description
|
||||||
{
|
{
|
||||||
get => _description;
|
get => _description;
|
||||||
@ -28,7 +23,6 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
private double _x;
|
private double _x;
|
||||||
|
|
||||||
public double X
|
public double X
|
||||||
{
|
{
|
||||||
get => _x;
|
get => _x;
|
||||||
@ -36,7 +30,6 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
private double _y;
|
private double _y;
|
||||||
|
|
||||||
public double Y
|
public double Y
|
||||||
{
|
{
|
||||||
get => _y;
|
get => _y;
|
||||||
@ -44,7 +37,6 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
private object? _storage;
|
private object? _storage;
|
||||||
|
|
||||||
public object? Storage
|
public object? Storage
|
||||||
{
|
{
|
||||||
get => _storage;
|
get => _storage;
|
||||||
@ -61,11 +53,16 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event EventHandler Resetting;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Construtors
|
#region Construtors
|
||||||
|
|
||||||
protected Node()
|
protected Node()
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
protected Node(string name, string description)
|
protected Node(string name, string description)
|
||||||
{
|
{
|
||||||
@ -138,8 +135,7 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Initialize(INodeScript script)
|
public virtual void Initialize(INodeScript script)
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void Evaluate();
|
public abstract void Evaluate();
|
||||||
|
|
||||||
@ -154,12 +150,10 @@ namespace Artemis.Core
|
|||||||
public abstract class Node<T> : CustomViewModelNode where T : ICustomNodeViewModel
|
public abstract class Node<T> : CustomViewModelNode where T : ICustomNodeViewModel
|
||||||
{
|
{
|
||||||
protected Node()
|
protected Node()
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
protected Node(string name, string description) : base(name, description)
|
protected Node(string name, string description) : base(name, description)
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
public override Type CustomViewModelType => typeof(T);
|
public override Type CustomViewModelType => typeof(T);
|
||||||
public T CustomViewModel => (T) BaseCustomViewModel!;
|
public T CustomViewModel => (T) BaseCustomViewModel!;
|
||||||
@ -169,13 +163,11 @@ namespace Artemis.Core
|
|||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected CustomViewModelNode()
|
protected CustomViewModelNode()
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected CustomViewModelNode(string name, string description) : base(name, description)
|
protected CustomViewModelNode(string name, string description) : base(name, description)
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Type CustomViewModelType { get; }
|
public abstract Type CustomViewModelType { get; }
|
||||||
public object? BaseCustomViewModel { get; set; }
|
public object? BaseCustomViewModel { get; set; }
|
||||||
|
|||||||
@ -28,6 +28,13 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event EventHandler<INode>? NodeAdded;
|
||||||
|
public event EventHandler<INode>? NodeRemoved;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public NodeScript(string name, string description, object? context = null)
|
public NodeScript(string name, string description, object? context = null)
|
||||||
@ -67,11 +74,15 @@ namespace Artemis.Core
|
|||||||
public void AddNode(INode node)
|
public void AddNode(INode node)
|
||||||
{
|
{
|
||||||
_nodes.Add(node);
|
_nodes.Add(node);
|
||||||
|
|
||||||
|
NodeAdded?.Invoke(this, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveNode(INode node)
|
public void RemoveNode(INode node)
|
||||||
{
|
{
|
||||||
_nodes.Remove(node);
|
_nodes.Remove(node);
|
||||||
|
|
||||||
|
NodeRemoved?.Invoke(this, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@ -27,6 +27,13 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event EventHandler<IPin> PinConnected;
|
||||||
|
public event EventHandler<IPin> PinDisconnected;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
protected Pin(INode node, string name = "")
|
protected Pin(INode node, string name = "")
|
||||||
@ -46,18 +53,27 @@ namespace Artemis.Core
|
|||||||
{
|
{
|
||||||
_connectedTo.Add(pin);
|
_connectedTo.Add(pin);
|
||||||
OnPropertyChanged(nameof(ConnectedTo));
|
OnPropertyChanged(nameof(ConnectedTo));
|
||||||
|
|
||||||
|
PinConnected?.Invoke(this, pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DisconnectFrom(IPin pin)
|
public void DisconnectFrom(IPin pin)
|
||||||
{
|
{
|
||||||
_connectedTo.Remove(pin);
|
_connectedTo.Remove(pin);
|
||||||
OnPropertyChanged(nameof(ConnectedTo));
|
OnPropertyChanged(nameof(ConnectedTo));
|
||||||
|
|
||||||
|
PinDisconnected?.Invoke(this, pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DisconnectAll()
|
public void DisconnectAll()
|
||||||
{
|
{
|
||||||
|
List<IPin> connectedPins = new(_connectedTo);
|
||||||
|
|
||||||
_connectedTo.Clear();
|
_connectedTo.Clear();
|
||||||
OnPropertyChanged(nameof(ConnectedTo));
|
OnPropertyChanged(nameof(ConnectedTo));
|
||||||
|
|
||||||
|
foreach (IPin pin in connectedPins)
|
||||||
|
PinDisconnected?.Invoke(this, pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNodeResetting(object sender, EventArgs e)
|
private void OnNodeResetting(object sender, EventArgs e)
|
||||||
|
|||||||
@ -20,6 +20,13 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event EventHandler<IPin> PinAdded;
|
||||||
|
public event EventHandler<IPin> PinRemoved;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
protected PinCollection(INode node, string name, int initialCount)
|
protected PinCollection(INode node, string name, int initialCount)
|
||||||
@ -35,14 +42,26 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
|
||||||
public IPin AddPin()
|
public IPin AddPin()
|
||||||
{
|
{
|
||||||
IPin pin = CreatePin();
|
IPin pin = CreatePin();
|
||||||
_pins.Add(pin);
|
_pins.Add(pin);
|
||||||
|
|
||||||
|
PinAdded?.Invoke(this, pin);
|
||||||
|
|
||||||
return pin;
|
return pin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Remove(IPin pin) => _pins.Remove(pin);
|
public bool Remove(IPin pin)
|
||||||
|
{
|
||||||
|
bool removed = _pins.Remove(pin);
|
||||||
|
|
||||||
|
if (removed)
|
||||||
|
PinRemoved?.Invoke(this, pin);
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract IPin CreatePin();
|
protected abstract IPin CreatePin();
|
||||||
|
|
||||||
|
|||||||
@ -43,8 +43,9 @@
|
|||||||
<Separator Grid.Row="1" Grid.Column="0" Style="{StaticResource MaterialDesignDarkSeparator}" Margin="-2 0" />
|
<Separator Grid.Row="1" Grid.Column="0" Style="{StaticResource MaterialDesignDarkSeparator}" Margin="-2 0" />
|
||||||
|
|
||||||
<Grid Grid.Row="2" Grid.Column="0" MouseUp="{s:Action ScriptGridMouseUp}" Cursor="Hand">
|
<Grid Grid.Row="2" Grid.Column="0" MouseUp="{s:Action ScriptGridMouseUp}" Cursor="Hand">
|
||||||
<controls:VisualScriptEditor Script="{Binding RenderProfileElement.DisplayCondition}"
|
<controls:VisualScriptPresenter Script="{Binding RenderProfileElement.DisplayCondition}"
|
||||||
Visibility="{Binding RenderProfileElement.DisplayCondition, Converter={StaticResource NullToVisibilityConverter}}" />
|
AutoFitScript="True"
|
||||||
|
Visibility="{Binding RenderProfileElement.DisplayCondition, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||||
<Border Opacity="0">
|
<Border Opacity="0">
|
||||||
<Border.Background>
|
<Border.Background>
|
||||||
<SolidColorBrush Color="{Binding Color, Source={StaticResource MaterialDesignCardBackground}}" Opacity="0.75" />
|
<SolidColorBrush Color="{Binding Color, Source={StaticResource MaterialDesignCardBackground}}" Opacity="0.75" />
|
||||||
|
|||||||
@ -7,10 +7,6 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
{
|
{
|
||||||
public class VisualScriptEditor : Control
|
public class VisualScriptEditor : Control
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Dependency Properties
|
#region Dependency Properties
|
||||||
|
|
||||||
public static readonly DependencyProperty ScriptProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty ScriptProperty = DependencyProperty.Register(
|
||||||
@ -32,9 +28,5 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ using System.Windows;
|
|||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Threading;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.VisualScripting.Editor.Controls.Wrapper;
|
using Artemis.VisualScripting.Editor.Controls.Wrapper;
|
||||||
using Artemis.VisualScripting.ViewModel;
|
using Artemis.VisualScripting.ViewModel;
|
||||||
@ -32,11 +33,13 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
|
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private bool _fitPending = false;
|
||||||
private Canvas _canvas;
|
private Canvas _canvas;
|
||||||
private ItemsControl _nodeList;
|
private ItemsControl _nodeList;
|
||||||
private ItemsControl _cableList;
|
private ItemsControl _cableList;
|
||||||
private Border _selectionBorder;
|
private Border _selectionBorder;
|
||||||
private TranslateTransform _canvasViewPortTransform;
|
private TranslateTransform _canvasViewPortTransform;
|
||||||
|
private ScaleTransform _canvasViewPortScale;
|
||||||
private Panel _creationBoxParent;
|
private Panel _creationBoxParent;
|
||||||
|
|
||||||
private Vector _viewportCenter = new(0, 0);
|
private Vector _viewportCenter = new(0, 0);
|
||||||
@ -121,7 +124,7 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static readonly DependencyProperty GridSizeProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty GridSizeProperty = DependencyProperty.Register(
|
||||||
"GridSize", typeof(int), typeof(VisualScriptPresenter), new PropertyMetadata(12));
|
"GridSize", typeof(int), typeof(VisualScriptPresenter), new PropertyMetadata(24));
|
||||||
|
|
||||||
public int GridSize
|
public int GridSize
|
||||||
{
|
{
|
||||||
@ -138,6 +141,15 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
set => SetValue(SurfaceSizeProperty, value);
|
set => SetValue(SurfaceSizeProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty AutoFitScriptProperty = DependencyProperty.Register(
|
||||||
|
"AutoFitScript", typeof(bool), typeof(VisualScriptPresenter), new PropertyMetadata(false, AutoFitScriptChanged));
|
||||||
|
|
||||||
|
public bool AutoFitScript
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(AutoFitScriptProperty);
|
||||||
|
set => SetValue(AutoFitScriptProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
@ -163,6 +175,7 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
|
|
||||||
_canvas.AllowDrop = true;
|
_canvas.AllowDrop = true;
|
||||||
|
|
||||||
|
_canvas.LayoutTransform = _canvasViewPortScale = new ScaleTransform(MaxScale, MaxScale);
|
||||||
_canvas.RenderTransform = _canvasViewPortTransform = new TranslateTransform(0, 0);
|
_canvas.RenderTransform = _canvasViewPortTransform = new TranslateTransform(0, 0);
|
||||||
_canvas.MouseLeftButtonDown += OnCanvasMouseLeftButtonDown;
|
_canvas.MouseLeftButtonDown += OnCanvasMouseLeftButtonDown;
|
||||||
_canvas.MouseLeftButtonUp += OnCanvasMouseLeftButtonUp;
|
_canvas.MouseLeftButtonUp += OnCanvasMouseLeftButtonUp;
|
||||||
@ -177,11 +190,22 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
_cableList.ItemsSource = VisualScript?.Cables;
|
_cableList.ItemsSource = VisualScript?.Cables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void AutoFitScriptChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
|
||||||
|
{
|
||||||
|
if (d is not VisualScriptPresenter scriptPresenter) return;
|
||||||
|
|
||||||
|
if ((args.NewValue as bool?) == true)
|
||||||
|
scriptPresenter.FitScript();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnSizeChanged(object sender, SizeChangedEventArgs args)
|
private void OnSizeChanged(object sender, SizeChangedEventArgs args)
|
||||||
{
|
{
|
||||||
if (sender is not VisualScriptPresenter scriptPresenter) return;
|
if (sender is not VisualScriptPresenter scriptPresenter) return;
|
||||||
|
|
||||||
scriptPresenter.UpdatePanning();
|
if (AutoFitScript)
|
||||||
|
scriptPresenter.FitScript();
|
||||||
|
else
|
||||||
|
scriptPresenter.UpdatePanning();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ScriptChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
|
private static void ScriptChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
|
||||||
@ -194,28 +218,33 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
private void ScriptChanged(VisualScript newScript)
|
private void ScriptChanged(VisualScript newScript)
|
||||||
{
|
{
|
||||||
if (VisualScript != null)
|
if (VisualScript != null)
|
||||||
|
{
|
||||||
VisualScript.PropertyChanged -= OnVisualScriptPropertyChanged;
|
VisualScript.PropertyChanged -= OnVisualScriptPropertyChanged;
|
||||||
|
VisualScript.NodeMoved -= OnVisualScriptNodeMoved;
|
||||||
|
VisualScript.NodeCollectionChanged -= OnVisualScriptNodeCollectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
VisualScript = newScript;
|
VisualScript = newScript;
|
||||||
|
|
||||||
if (VisualScript != null)
|
if (VisualScript != null)
|
||||||
{
|
{
|
||||||
VisualScript.PropertyChanged += OnVisualScriptPropertyChanged;
|
VisualScript.PropertyChanged += OnVisualScriptPropertyChanged;
|
||||||
|
VisualScript.NodeMoved += OnVisualScriptNodeMoved;
|
||||||
|
VisualScript.NodeCollectionChanged += OnVisualScriptNodeCollectionChanged;
|
||||||
|
|
||||||
if (_nodeList != null)
|
if (_nodeList != null)
|
||||||
_nodeList.ItemsSource = VisualScript?.Nodes;
|
_nodeList.ItemsSource = VisualScript?.Nodes;
|
||||||
|
|
||||||
if (_cableList != null)
|
if (_cableList != null)
|
||||||
_cableList.ItemsSource = VisualScript?.Cables;
|
_cableList.ItemsSource = VisualScript?.Cables;
|
||||||
|
|
||||||
VisualScript.Nodes.Clear();
|
|
||||||
foreach (INode node in VisualScript.Script.Nodes)
|
|
||||||
InitializeNode(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VisualScript?.RecreateCables();
|
VisualScript?.RecreateCables();
|
||||||
|
|
||||||
CenterAt(new Vector(0, 0));
|
if (AutoFitScript)
|
||||||
|
FitScript();
|
||||||
|
else
|
||||||
|
CenterAt(new Vector(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnVisualScriptPropertyChanged(object sender, PropertyChangedEventArgs args)
|
private void OnVisualScriptPropertyChanged(object sender, PropertyChangedEventArgs args)
|
||||||
@ -225,6 +254,18 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
_cableList.ItemsSource = VisualScript.Cables;
|
_cableList.ItemsSource = VisualScript.Cables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnVisualScriptNodeMoved(object sender, EventArgs args)
|
||||||
|
{
|
||||||
|
if (AutoFitScript)
|
||||||
|
FitScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnVisualScriptNodeCollectionChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (AutoFitScript)
|
||||||
|
FitScript();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnCanvasPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs args)
|
private void OnCanvasPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs args)
|
||||||
{
|
{
|
||||||
_lastRightClickLocation = args.GetPosition(_canvas);
|
_lastRightClickLocation = args.GetPosition(_canvas);
|
||||||
@ -261,6 +302,12 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
|
|
||||||
private void OnCanvasMouseRightButtonDown(object sender, MouseButtonEventArgs args)
|
private void OnCanvasMouseRightButtonDown(object sender, MouseButtonEventArgs args)
|
||||||
{
|
{
|
||||||
|
if (AutoFitScript)
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_dragCanvas = true;
|
_dragCanvas = true;
|
||||||
_dragCanvasStartLocation = args.GetPosition(this);
|
_dragCanvasStartLocation = args.GetPosition(this);
|
||||||
_dragCanvasStartOffset = _viewportCenter;
|
_dragCanvasStartOffset = _viewportCenter;
|
||||||
@ -289,7 +336,7 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
{
|
{
|
||||||
if (args.RightButton == MouseButtonState.Pressed)
|
if (args.RightButton == MouseButtonState.Pressed)
|
||||||
{
|
{
|
||||||
Vector newLocation = _dragCanvasStartOffset + (((args.GetPosition(this) - _dragCanvasStartLocation)) * (1.0 / Scale));
|
Vector newLocation = _dragCanvasStartOffset - (((args.GetPosition(this) - _dragCanvasStartLocation)) * (1.0 / Scale));
|
||||||
CenterAt(newLocation);
|
CenterAt(newLocation);
|
||||||
|
|
||||||
_movedDuringDrag = true;
|
_movedDuringDrag = true;
|
||||||
@ -327,14 +374,18 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
|
|
||||||
private void OnCanvasDragOver(object sender, DragEventArgs args)
|
private void OnCanvasDragOver(object sender, DragEventArgs args)
|
||||||
{
|
{
|
||||||
if (VisualScript == null) return;
|
|
||||||
|
|
||||||
if (VisualScript.IsConnecting)
|
if (VisualScript.IsConnecting)
|
||||||
VisualScript.OnDragOver(args.GetPosition(_canvas));
|
VisualScript.OnDragOver(args.GetPosition(_canvas));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCanvasMouseWheel(object sender, MouseWheelEventArgs args)
|
private void OnCanvasMouseWheel(object sender, MouseWheelEventArgs args)
|
||||||
{
|
{
|
||||||
|
if (AutoFitScript)
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (args.Delta < 0)
|
if (args.Delta < 0)
|
||||||
Scale /= ScaleFactor;
|
Scale /= ScaleFactor;
|
||||||
else
|
else
|
||||||
@ -342,8 +393,6 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
|
|
||||||
Scale = Clamp(Scale, MinScale, MaxScale);
|
Scale = Clamp(Scale, MinScale, MaxScale);
|
||||||
|
|
||||||
_canvas.LayoutTransform = new ScaleTransform(Scale, Scale);
|
|
||||||
|
|
||||||
UpdatePanning();
|
UpdatePanning();
|
||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
@ -373,9 +422,63 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
if (d is not VisualScriptPresenter presenter) return;
|
if (d is not VisualScriptPresenter presenter) return;
|
||||||
if (presenter.VisualScript == null) return;
|
if (presenter.VisualScript == null) return;
|
||||||
|
|
||||||
|
presenter._canvasViewPortScale.ScaleX = presenter.Scale;
|
||||||
|
presenter._canvasViewPortScale.ScaleY = presenter.Scale;
|
||||||
|
|
||||||
presenter.VisualScript.NodeDragScale = 1.0 / presenter.Scale;
|
presenter.VisualScript.NodeDragScale = 1.0 / presenter.Scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void FitScript()
|
||||||
|
{
|
||||||
|
if (_fitPending) return;
|
||||||
|
|
||||||
|
_fitPending = true;
|
||||||
|
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(FitScriptAction));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FitScriptAction()
|
||||||
|
{
|
||||||
|
_fitPending = false;
|
||||||
|
|
||||||
|
if ((Script == null) || (_nodeList == null)) return;
|
||||||
|
|
||||||
|
double minX = double.MaxValue;
|
||||||
|
double maxX = double.MinValue;
|
||||||
|
double minY = double.MaxValue;
|
||||||
|
double maxY = double.MinValue;
|
||||||
|
for (int i = 0; i < _nodeList.Items.Count; i++)
|
||||||
|
{
|
||||||
|
DependencyObject container = _nodeList.ItemContainerGenerator.ContainerFromIndex(i);
|
||||||
|
VisualScriptNodePresenter nodePresenter = GetChildOfType<VisualScriptNodePresenter>(container);
|
||||||
|
if (nodePresenter != null)
|
||||||
|
{
|
||||||
|
minX = Math.Min(minX, nodePresenter.Node.Node.X);
|
||||||
|
minY = Math.Min(minY, nodePresenter.Node.Node.Y);
|
||||||
|
|
||||||
|
maxX = Math.Max(maxX, nodePresenter.Node.Node.X + nodePresenter.ActualWidth);
|
||||||
|
maxY = Math.Max(maxY, nodePresenter.Node.Node.Y + nodePresenter.ActualHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minX >= (double.MaxValue - 1))
|
||||||
|
{
|
||||||
|
Scale = MaxScale;
|
||||||
|
CenterAt(new Vector(0, 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double width = maxX - minX;
|
||||||
|
double height = maxY - minY;
|
||||||
|
|
||||||
|
double scaleX = ActualWidth / width;
|
||||||
|
double scaleY = ActualHeight / height;
|
||||||
|
|
||||||
|
Scale = Clamp(Math.Min(scaleX, scaleY) / 1.05, 0, MaxScale); //DarthAffe 21.08.2021: 5% Border
|
||||||
|
|
||||||
|
CenterAt(new Vector(minX + (width / 2.0), minY + (height / 2.0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void CreateNode(NodeData nodeData)
|
private void CreateNode(NodeData nodeData)
|
||||||
{
|
{
|
||||||
if (nodeData == null) return;
|
if (nodeData == null) return;
|
||||||
@ -385,21 +488,10 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
|
|
||||||
INode node = nodeData.CreateNode(Script, null);
|
INode node = nodeData.CreateNode(Script, null);
|
||||||
node.Initialize(Script);
|
node.Initialize(Script);
|
||||||
|
node.X = _lastRightClickLocation.X - VisualScript.LocationOffset;
|
||||||
|
node.Y = _lastRightClickLocation.Y - VisualScript.LocationOffset;
|
||||||
|
|
||||||
Script.AddNode(node);
|
Script.AddNode(node);
|
||||||
|
|
||||||
InitializeNode(node, _lastRightClickLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeNode(INode node, Point? initialLocation = null)
|
|
||||||
{
|
|
||||||
VisualScriptNode visualScriptNode = new(VisualScript, node);
|
|
||||||
if (initialLocation != null)
|
|
||||||
{
|
|
||||||
visualScriptNode.X = initialLocation.Value.X;
|
|
||||||
visualScriptNode.Y = initialLocation.Value.Y;
|
|
||||||
}
|
|
||||||
visualScriptNode.SnapNodeToGrid();
|
|
||||||
VisualScript.Nodes.Add(visualScriptNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CenterAt(Vector vector)
|
private void CenterAt(Vector vector)
|
||||||
@ -414,8 +506,8 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
if (_canvasViewPortTransform == null) return;
|
if (_canvasViewPortTransform == null) return;
|
||||||
|
|
||||||
double surfaceOffset = (SurfaceSize / 2.0) * Scale;
|
double surfaceOffset = (SurfaceSize / 2.0) * Scale;
|
||||||
_canvasViewPortTransform.X = (((_viewportCenter.X * Scale) + (ActualWidth / 2.0))) - surfaceOffset;
|
_canvasViewPortTransform.X = (((-_viewportCenter.X * Scale) + (ActualWidth / 2.0))) - surfaceOffset;
|
||||||
_canvasViewPortTransform.Y = (((_viewportCenter.Y * Scale) + (ActualHeight / 2.0))) - surfaceOffset;
|
_canvasViewPortTransform.Y = (((-_viewportCenter.Y * Scale) + (ActualHeight / 2.0))) - surfaceOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -436,6 +528,21 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
return new Vector(x, y);
|
return new Vector(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static T GetChildOfType<T>(DependencyObject obj)
|
||||||
|
where T : DependencyObject
|
||||||
|
{
|
||||||
|
if (obj == null) return null;
|
||||||
|
|
||||||
|
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
|
||||||
|
{
|
||||||
|
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
|
||||||
|
|
||||||
|
T result = (child as T) ?? GetChildOfType<T>(child);
|
||||||
|
if (result != null) return result;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Threading;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.VisualScripting.Events;
|
using Artemis.VisualScripting.Events;
|
||||||
using Artemis.VisualScripting.ViewModel;
|
using Artemis.VisualScripting.ViewModel;
|
||||||
@ -14,6 +16,8 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
{
|
{
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private bool _cableRecreationPending = false;
|
||||||
|
|
||||||
private readonly HashSet<VisualScriptNode> _selectedNodes = new();
|
private readonly HashSet<VisualScriptNode> _selectedNodes = new();
|
||||||
private readonly Dictionary<VisualScriptNode, (double X, double Y)> _nodeStartPositions = new();
|
private readonly Dictionary<VisualScriptNode, (double X, double Y)> _nodeStartPositions = new();
|
||||||
private double _nodeDragAccumulationX;
|
private double _nodeDragAccumulationX;
|
||||||
@ -31,6 +35,8 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
set => SetProperty(ref _nodeDragScale, value);
|
set => SetProperty(ref _nodeDragScale, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal double LocationOffset { get; }
|
||||||
|
|
||||||
private VisualScriptPin _isConnectingPin;
|
private VisualScriptPin _isConnectingPin;
|
||||||
private VisualScriptPin IsConnectingPin
|
private VisualScriptPin IsConnectingPin
|
||||||
{
|
{
|
||||||
@ -42,6 +48,7 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<INode, VisualScriptNode> _nodeMapping = new();
|
||||||
public ObservableCollection<VisualScriptNode> Nodes { get; } = new();
|
public ObservableCollection<VisualScriptNode> Nodes { get; } = new();
|
||||||
|
|
||||||
public IEnumerable<VisualScriptCable> Cables => Nodes.SelectMany(n => n.InputPins.SelectMany(p => p.InternalConnections))
|
public IEnumerable<VisualScriptCable> Cables => Nodes.SelectMany(n => n.InputPins.SelectMany(p => p.InternalConnections))
|
||||||
@ -54,6 +61,13 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event EventHandler NodeMoved;
|
||||||
|
public event EventHandler NodeCollectionChanged;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public VisualScript(INodeScript script, int surfaceSize, int gridSize)
|
public VisualScript(INodeScript script, int surfaceSize, int gridSize)
|
||||||
@ -62,7 +76,15 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
this.SurfaceSize = surfaceSize;
|
this.SurfaceSize = surfaceSize;
|
||||||
this.GridSize = gridSize;
|
this.GridSize = gridSize;
|
||||||
|
|
||||||
|
LocationOffset = SurfaceSize / 2.0;
|
||||||
|
|
||||||
Nodes.CollectionChanged += OnNodeCollectionChanged;
|
Nodes.CollectionChanged += OnNodeCollectionChanged;
|
||||||
|
|
||||||
|
script.NodeAdded += OnScriptNodeAdded;
|
||||||
|
script.NodeRemoved += OnScriptRemovedAdded;
|
||||||
|
|
||||||
|
foreach (INode node in Script.Nodes)
|
||||||
|
InitializeNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -85,31 +107,69 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
RegisterNodes(args.NewItems.Cast<VisualScriptNode>());
|
RegisterNodes(args.NewItems.Cast<VisualScriptNode>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnScriptNodeAdded(object sender, INode node)
|
||||||
|
{
|
||||||
|
if (_nodeMapping.ContainsKey(node)) return;
|
||||||
|
|
||||||
|
InitializeNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnScriptRemovedAdded(object sender, INode node)
|
||||||
|
{
|
||||||
|
if (!_nodeMapping.TryGetValue(node, out VisualScriptNode visualScriptNode)) return;
|
||||||
|
|
||||||
|
Nodes.Remove(visualScriptNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeNode(INode node)
|
||||||
|
{
|
||||||
|
VisualScriptNode visualScriptNode = new(this, node);
|
||||||
|
visualScriptNode.SnapNodeToGrid();
|
||||||
|
Nodes.Add(visualScriptNode);
|
||||||
|
}
|
||||||
|
|
||||||
private void RegisterNodes(IEnumerable<VisualScriptNode> nodes)
|
private void RegisterNodes(IEnumerable<VisualScriptNode> nodes)
|
||||||
{
|
{
|
||||||
foreach (VisualScriptNode node in nodes)
|
foreach (VisualScriptNode node in nodes)
|
||||||
{
|
{
|
||||||
|
_nodeMapping.Add(node.Node, node);
|
||||||
|
|
||||||
node.IsSelectedChanged += OnNodeIsSelectedChanged;
|
node.IsSelectedChanged += OnNodeIsSelectedChanged;
|
||||||
node.DragStarting += OnNodeDragStarting;
|
node.DragStarting += OnNodeDragStarting;
|
||||||
node.DragEnding += OnNodeDragEnding;
|
node.DragEnding += OnNodeDragEnding;
|
||||||
node.DragMoving += OnNodeDragMoving;
|
node.DragMoving += OnNodeDragMoving;
|
||||||
|
node.PropertyChanged += OnNodePropertyChanged;
|
||||||
|
|
||||||
if (node.IsSelected)
|
if (node.IsSelected)
|
||||||
_selectedNodes.Add(node);
|
_selectedNodes.Add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeCollectionChanged?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnregisterNodes(IEnumerable<VisualScriptNode> nodes)
|
private void UnregisterNodes(IEnumerable<VisualScriptNode> nodes)
|
||||||
{
|
{
|
||||||
foreach (VisualScriptNode node in nodes)
|
foreach (VisualScriptNode node in nodes)
|
||||||
{
|
{
|
||||||
|
_nodeMapping.Remove(node.Node);
|
||||||
|
|
||||||
node.IsSelectedChanged -= OnNodeIsSelectedChanged;
|
node.IsSelectedChanged -= OnNodeIsSelectedChanged;
|
||||||
node.DragStarting -= OnNodeDragStarting;
|
node.DragStarting -= OnNodeDragStarting;
|
||||||
node.DragEnding -= OnNodeDragEnding;
|
node.DragEnding -= OnNodeDragEnding;
|
||||||
node.DragMoving -= OnNodeDragMoving;
|
node.DragMoving -= OnNodeDragMoving;
|
||||||
|
node.PropertyChanged -= OnNodePropertyChanged;
|
||||||
|
|
||||||
_selectedNodes.Remove(node);
|
_selectedNodes.Remove(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeCollectionChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNodePropertyChanged(object sender, PropertyChangedEventArgs args)
|
||||||
|
{
|
||||||
|
if (string.Equals(args.PropertyName, nameof(VisualScriptNode.X), StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(args.PropertyName, nameof(VisualScriptNode.Y), StringComparison.OrdinalIgnoreCase))
|
||||||
|
NodeMoved?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNodeIsSelectedChanged(object sender, VisualScriptNodeIsSelectedChangedEventArgs args)
|
private void OnNodeIsSelectedChanged(object sender, VisualScriptNodeIsSelectedChangedEventArgs args)
|
||||||
@ -184,8 +244,18 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
Script.RemoveNode(node.Node);
|
Script.RemoveNode(node.Node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void RequestCableRecreation()
|
||||||
|
{
|
||||||
|
if (_cableRecreationPending) return;
|
||||||
|
|
||||||
|
_cableRecreationPending = true;
|
||||||
|
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(RecreateCables));
|
||||||
|
}
|
||||||
|
|
||||||
internal void RecreateCables()
|
internal void RecreateCables()
|
||||||
{
|
{
|
||||||
|
_cableRecreationPending = false;
|
||||||
|
|
||||||
Dictionary<IPin, VisualScriptPin> pinMapping = Nodes.SelectMany(n => n.InputPins)
|
Dictionary<IPin, VisualScriptPin> pinMapping = Nodes.SelectMany(n => n.InputPins)
|
||||||
.Concat(Nodes.SelectMany(n => n.OutputPins))
|
.Concat(Nodes.SelectMany(n => n.OutputPins))
|
||||||
.Concat(Nodes.SelectMany(n => n.InputPinCollections.SelectMany(p => p.Pins)))
|
.Concat(Nodes.SelectMany(n => n.InputPinCollections.SelectMany(p => p.Pins)))
|
||||||
@ -200,13 +270,13 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
{
|
{
|
||||||
foreach (IPin connectedPin in pin.ConnectedTo)
|
foreach (IPin connectedPin in pin.ConnectedTo)
|
||||||
if (!connectedPins.Contains(connectedPin))
|
if (!connectedPins.Contains(connectedPin))
|
||||||
{
|
if (pinMapping.TryGetValue(pin, out VisualScriptPin pin1)
|
||||||
VisualScriptPin pin1 = pinMapping[pin];
|
&& pinMapping.TryGetValue(connectedPin, out VisualScriptPin pin2))
|
||||||
VisualScriptPin pin2 = pinMapping[connectedPin];
|
{
|
||||||
VisualScriptCable cable = new(pin1, pin2, false);
|
VisualScriptCable cable = new(pin1, pin2, false);
|
||||||
pin1.InternalConnections.Add(cable);
|
pin1.InternalConnections.Add(cable);
|
||||||
pin2.InternalConnections.Add(cable);
|
pin2.InternalConnections.Add(cable);
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedPins.Add(pin);
|
connectedPins.Add(pin);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
{
|
{
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
private double _locationOffset;
|
private readonly Dictionary<IPin, VisualScriptPin> _pinMapping = new();
|
||||||
|
|
||||||
public VisualScript Script { get; }
|
public VisualScript Script { get; }
|
||||||
public INode Node { get; }
|
public INode Node { get; }
|
||||||
@ -55,20 +55,20 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
|
|
||||||
public double X
|
public double X
|
||||||
{
|
{
|
||||||
get => Node.X + _locationOffset;
|
get => Node.X + Script.LocationOffset;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Node.X = value - _locationOffset;
|
Node.X = value - Script.LocationOffset;
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double Y
|
public double Y
|
||||||
{
|
{
|
||||||
get => Node.Y + _locationOffset;
|
get => Node.Y + Script.LocationOffset;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Node.Y = value - _locationOffset;
|
Node.Y = value - Script.LocationOffset;
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,8 +100,6 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
|
|
||||||
Node.PropertyChanged += OnNodePropertyChanged;
|
Node.PropertyChanged += OnNodePropertyChanged;
|
||||||
|
|
||||||
_locationOffset = script.SurfaceSize / 2.0;
|
|
||||||
|
|
||||||
ValidatePins();
|
ValidatePins();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +112,12 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
if (string.Equals(args.PropertyName, nameof(Node.Pins), StringComparison.OrdinalIgnoreCase)
|
if (string.Equals(args.PropertyName, nameof(Node.Pins), StringComparison.OrdinalIgnoreCase)
|
||||||
|| string.Equals(args.PropertyName, nameof(Node.PinCollections), StringComparison.OrdinalIgnoreCase))
|
|| string.Equals(args.PropertyName, nameof(Node.PinCollections), StringComparison.OrdinalIgnoreCase))
|
||||||
ValidatePins();
|
ValidatePins();
|
||||||
|
|
||||||
|
else if (string.Equals(args.PropertyName, nameof(Node.X), StringComparison.OrdinalIgnoreCase))
|
||||||
|
OnPropertyChanged(nameof(X));
|
||||||
|
|
||||||
|
else if (string.Equals(args.PropertyName, nameof(Node.Y), StringComparison.OrdinalIgnoreCase))
|
||||||
|
OnPropertyChanged(nameof(Y));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidatePins()
|
private void ValidatePins()
|
||||||
@ -199,8 +203,30 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Pin Mapping
|
||||||
|
|
||||||
|
_pinMapping.Clear();
|
||||||
|
|
||||||
|
foreach (VisualScriptPin pin in InputPins)
|
||||||
|
_pinMapping.Add(pin.Pin, pin);
|
||||||
|
|
||||||
|
foreach (VisualScriptPin pin in OutputPins)
|
||||||
|
_pinMapping.Add(pin.Pin, pin);
|
||||||
|
|
||||||
|
foreach (VisualScriptPinCollection pinCollection in InputPinCollections)
|
||||||
|
foreach (VisualScriptPin pin in pinCollection.Pins)
|
||||||
|
_pinMapping.Add(pin.Pin, pin);
|
||||||
|
|
||||||
|
foreach (VisualScriptPinCollection pinCollection in OutputPinCollections)
|
||||||
|
foreach (VisualScriptPin pin in pinCollection.Pins)
|
||||||
|
_pinMapping.Add(pin.Pin, pin);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal VisualScriptPin GetVisualPin(IPin pin) => ((pin != null) && _pinMapping.TryGetValue(pin, out VisualScriptPin visualScriptPin)) ? visualScriptPin : null;
|
||||||
|
|
||||||
public void SnapNodeToGrid()
|
public void SnapNodeToGrid()
|
||||||
{
|
{
|
||||||
X -= X % Script.GridSize;
|
X -= X % Script.GridSize;
|
||||||
@ -219,8 +245,8 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
OnIsSelectedChanged(IsSelected, alterSelection);
|
OnIsSelectedChanged(IsSelected, alterSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DragStart() => DragStarting?.Invoke(this, new EventArgs());
|
public void DragStart() => DragStarting?.Invoke(this, EventArgs.Empty);
|
||||||
public void DragEnd() => DragEnding?.Invoke(this, new EventArgs());
|
public void DragEnd() => DragEnding?.Invoke(this, EventArgs.Empty);
|
||||||
public void DragMove(double dx, double dy) => DragMoving?.Invoke(this, new VisualScriptNodeDragMovingEventArgs(dx, dy));
|
public void DragMove(double dx, double dy) => DragMoving?.Invoke(this, new VisualScriptNodeDragMovingEventArgs(dx, dy));
|
||||||
|
|
||||||
private void OnIsSelectedChanged(bool isSelected, bool alterSelection) => IsSelectedChanged?.Invoke(this, new VisualScriptNodeIsSelectedChangedEventArgs(isSelected, alterSelection));
|
private void OnIsSelectedChanged(bool isSelected, bool alterSelection) => IsSelectedChanged?.Invoke(this, new VisualScriptNodeIsSelectedChangedEventArgs(isSelected, alterSelection));
|
||||||
|
|||||||
@ -19,6 +19,8 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
|
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private bool _isConnectionUpdated = false;
|
||||||
|
|
||||||
private VisualScriptPin _isConnectingPin;
|
private VisualScriptPin _isConnectingPin;
|
||||||
private VisualScriptCable _isConnectingCable;
|
private VisualScriptCable _isConnectingCable;
|
||||||
|
|
||||||
@ -39,8 +41,7 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point AbsoluteCableTargetPosition => Pin.Direction == PinDirection.Input ? new Point(AbsolutePosition.X - CABLE_OFFSET, AbsolutePosition.Y)
|
public Point AbsoluteCableTargetPosition => Pin.Direction == PinDirection.Input ? new Point(AbsolutePosition.X - CABLE_OFFSET, AbsolutePosition.Y) : new Point(AbsolutePosition.X + CABLE_OFFSET, AbsolutePosition.Y);
|
||||||
: new Point(AbsolutePosition.X + CABLE_OFFSET, AbsolutePosition.Y);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -50,12 +51,22 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
{
|
{
|
||||||
this.Node = node;
|
this.Node = node;
|
||||||
this.Pin = pin;
|
this.Pin = pin;
|
||||||
|
|
||||||
|
pin.PinConnected += PinConnectionChanged;
|
||||||
|
pin.PinDisconnected += PinConnectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
private void PinConnectionChanged(object sender, IPin pin)
|
||||||
|
{
|
||||||
|
if (_isConnectionUpdated) return;
|
||||||
|
|
||||||
|
Node?.Script?.RequestCableRecreation();
|
||||||
|
}
|
||||||
|
|
||||||
public void SetConnecting(bool isConnecting)
|
public void SetConnecting(bool isConnecting)
|
||||||
{
|
{
|
||||||
if (isConnecting)
|
if (isConnecting)
|
||||||
@ -63,8 +74,7 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
if (_isConnectingCable != null)
|
if (_isConnectingCable != null)
|
||||||
SetConnecting(false);
|
SetConnecting(false);
|
||||||
|
|
||||||
_isConnectingPin = new VisualScriptPin(null, new IsConnectingPin(Pin.Direction == PinDirection.Input ? PinDirection.Output : PinDirection.Input, Pin.Type))
|
_isConnectingPin = new VisualScriptPin(null, new IsConnectingPin(Pin.Direction == PinDirection.Input ? PinDirection.Output : PinDirection.Input, Pin.Type)) { AbsolutePosition = AbsolutePosition };
|
||||||
{ AbsolutePosition = AbsolutePosition };
|
|
||||||
_isConnectingCable = new VisualScriptCable(this, _isConnectingPin);
|
_isConnectingCable = new VisualScriptCable(this, _isConnectingPin);
|
||||||
Node.OnIsConnectingPinChanged(_isConnectingPin);
|
Node.OnIsConnectingPinChanged(_isConnectingPin);
|
||||||
}
|
}
|
||||||
@ -81,6 +91,8 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
{
|
{
|
||||||
if (InternalConnections.Contains(cable)) return;
|
if (InternalConnections.Contains(cable)) return;
|
||||||
|
|
||||||
|
_isConnectionUpdated = true;
|
||||||
|
|
||||||
if (Pin.Direction == PinDirection.Input)
|
if (Pin.Direction == PinDirection.Input)
|
||||||
{
|
{
|
||||||
List<VisualScriptCable> cables = InternalConnections.ToList();
|
List<VisualScriptCable> cables = InternalConnections.ToList();
|
||||||
@ -92,21 +104,31 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
Pin.ConnectTo(cable.GetConnectedPin(Pin));
|
Pin.ConnectTo(cable.GetConnectedPin(Pin));
|
||||||
|
|
||||||
Node?.OnPinConnected(new PinConnectedEventArgs(this, cable));
|
Node?.OnPinConnected(new PinConnectedEventArgs(this, cable));
|
||||||
|
|
||||||
|
_isConnectionUpdated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DisconnectAll()
|
public void DisconnectAll()
|
||||||
{
|
{
|
||||||
|
_isConnectionUpdated = true;
|
||||||
|
|
||||||
List<VisualScriptCable> cables = InternalConnections.ToList();
|
List<VisualScriptCable> cables = InternalConnections.ToList();
|
||||||
foreach (VisualScriptCable cable in cables)
|
foreach (VisualScriptCable cable in cables)
|
||||||
cable.Disconnect();
|
cable.Disconnect();
|
||||||
|
|
||||||
|
_isConnectionUpdated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Disconnect(VisualScriptCable cable)
|
internal void Disconnect(VisualScriptCable cable)
|
||||||
{
|
{
|
||||||
|
_isConnectionUpdated = true;
|
||||||
|
|
||||||
InternalConnections.Remove(cable);
|
InternalConnections.Remove(cable);
|
||||||
Pin.DisconnectFrom(cable.GetConnectedPin(Pin));
|
Pin.DisconnectFrom(cable.GetConnectedPin(Pin));
|
||||||
|
|
||||||
Node?.OnPinDisconnected(new PinDisconnectedEventArgs(this, cable));
|
Node?.OnPinDisconnected(new PinDisconnectedEventArgs(this, cable));
|
||||||
|
|
||||||
|
_isConnectionUpdated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -12,6 +12,7 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
public VisualScriptNode Node { get; }
|
public VisualScriptNode Node { get; }
|
||||||
public IPinCollection PinCollection { get; }
|
public IPinCollection PinCollection { get; }
|
||||||
|
|
||||||
|
private readonly Dictionary<IPin, VisualScriptPin> _pinMapping = new();
|
||||||
public ObservableCollection<VisualScriptPin> Pins { get; } = new();
|
public ObservableCollection<VisualScriptPin> Pins { get; } = new();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -33,27 +34,47 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
|||||||
this.Node = node;
|
this.Node = node;
|
||||||
this.PinCollection = pinCollection;
|
this.PinCollection = pinCollection;
|
||||||
|
|
||||||
|
pinCollection.PinAdded += OnPinCollectionPinAdded;
|
||||||
|
pinCollection.PinRemoved += OnPinCollectionPinRemoved;
|
||||||
|
|
||||||
foreach (IPin pin in PinCollection)
|
foreach (IPin pin in PinCollection)
|
||||||
Pins.Add(new VisualScriptPin(node, pin));
|
{
|
||||||
|
VisualScriptPin visualScriptPin = new(node, pin);
|
||||||
|
_pinMapping.Add(pin, visualScriptPin);
|
||||||
|
Pins.Add(visualScriptPin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
private void OnPinCollectionPinRemoved(object sender, IPin pin)
|
||||||
|
{
|
||||||
|
if (!_pinMapping.TryGetValue(pin, out VisualScriptPin visualScriptPin)) return;
|
||||||
|
|
||||||
|
visualScriptPin.DisconnectAll();
|
||||||
|
Pins.Remove(visualScriptPin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPinCollectionPinAdded(object sender, IPin pin)
|
||||||
|
{
|
||||||
|
if (_pinMapping.ContainsKey(pin)) return;
|
||||||
|
|
||||||
|
VisualScriptPin visualScriptPin = new(Node, pin);
|
||||||
|
_pinMapping.Add(pin, visualScriptPin);
|
||||||
|
Pins.Add(visualScriptPin);
|
||||||
|
}
|
||||||
|
|
||||||
public void AddPin()
|
public void AddPin()
|
||||||
{
|
{
|
||||||
IPin pin = PinCollection.AddPin();
|
PinCollection.AddPin();
|
||||||
Pins.Add(new VisualScriptPin(Node, pin));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemovePin(VisualScriptPin pin)
|
public void RemovePin(VisualScriptPin pin)
|
||||||
{
|
{
|
||||||
pin.DisconnectAll();
|
|
||||||
PinCollection.Remove(pin.Pin);
|
PinCollection.Remove(pin.Pin);
|
||||||
Pins.Remove(pin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAll()
|
public void RemoveAll()
|
||||||
{
|
{
|
||||||
List<VisualScriptPin> pins = new(Pins);
|
List<VisualScriptPin> pins = new(Pins);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user