mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Node editor - Added node selection
This commit is contained in:
parent
034879a2c9
commit
885cd852fc
@ -166,23 +166,20 @@ public class SelectionRectangle : Control
|
|||||||
((SelectionRectangle) sender).SubscribeToInputElement();
|
((SelectionRectangle) sender).SubscribeToInputElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ParentOnPointerMoved(object? sender, PointerEventArgs e)
|
||||||
private void ParentOnPointerPressed(object? sender, PointerPressedEventArgs e)
|
|
||||||
{
|
{
|
||||||
if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
e.Pointer.Capture(this);
|
// Capture the pointer and initialize dragging the first time it moves
|
||||||
|
|
||||||
_startPosition = e.GetPosition(Parent);
|
|
||||||
_absoluteStartPosition = e.GetPosition(VisualRoot);
|
|
||||||
_displayRect = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ParentOnPointerMoved(object? sender, PointerEventArgs e)
|
|
||||||
{
|
|
||||||
if (!ReferenceEquals(e.Pointer.Captured, this))
|
if (!ReferenceEquals(e.Pointer.Captured, this))
|
||||||
return;
|
{
|
||||||
|
e.Pointer.Capture(this);
|
||||||
|
|
||||||
|
_startPosition = e.GetPosition(Parent);
|
||||||
|
_absoluteStartPosition = e.GetPosition(VisualRoot);
|
||||||
|
_displayRect = null;
|
||||||
|
}
|
||||||
|
|
||||||
Point currentPosition = e.GetPosition(Parent);
|
Point currentPosition = e.GetPosition(Parent);
|
||||||
Point absoluteCurrentPosition = e.GetPosition(VisualRoot);
|
Point absoluteCurrentPosition = e.GetPosition(VisualRoot);
|
||||||
@ -223,7 +220,6 @@ public class SelectionRectangle : Control
|
|||||||
{
|
{
|
||||||
if (_oldInputElement != null)
|
if (_oldInputElement != null)
|
||||||
{
|
{
|
||||||
_oldInputElement.PointerPressed -= ParentOnPointerPressed;
|
|
||||||
_oldInputElement.PointerMoved -= ParentOnPointerMoved;
|
_oldInputElement.PointerMoved -= ParentOnPointerMoved;
|
||||||
_oldInputElement.PointerReleased -= ParentOnPointerReleased;
|
_oldInputElement.PointerReleased -= ParentOnPointerReleased;
|
||||||
}
|
}
|
||||||
@ -232,7 +228,6 @@ public class SelectionRectangle : Control
|
|||||||
|
|
||||||
if (InputElement != null)
|
if (InputElement != null)
|
||||||
{
|
{
|
||||||
InputElement.PointerPressed += ParentOnPointerPressed;
|
|
||||||
InputElement.PointerMoved += ParentOnPointerMoved;
|
InputElement.PointerMoved += ParentOnPointerMoved;
|
||||||
InputElement.PointerReleased += ParentOnPointerReleased;
|
InputElement.PointerReleased += ParentOnPointerReleased;
|
||||||
}
|
}
|
||||||
@ -259,7 +254,6 @@ public class SelectionRectangle : Control
|
|||||||
{
|
{
|
||||||
if (_oldInputElement != null)
|
if (_oldInputElement != null)
|
||||||
{
|
{
|
||||||
_oldInputElement.PointerPressed -= ParentOnPointerPressed;
|
|
||||||
_oldInputElement.PointerMoved -= ParentOnPointerMoved;
|
_oldInputElement.PointerMoved -= ParentOnPointerMoved;
|
||||||
_oldInputElement.PointerReleased -= ParentOnPointerReleased;
|
_oldInputElement.PointerReleased -= ParentOnPointerReleased;
|
||||||
_oldInputElement = null;
|
_oldInputElement = null;
|
||||||
|
|||||||
@ -94,7 +94,7 @@ namespace Artemis.UI.Ninject.Factories
|
|||||||
{
|
{
|
||||||
NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript);
|
NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript);
|
||||||
NodePickerViewModel NodePickerViewModel(NodeScript nodeScript);
|
NodePickerViewModel NodePickerViewModel(NodeScript nodeScript);
|
||||||
NodeViewModel NodeViewModel(NodeScript nodeScript, INode node);
|
NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface INodePinVmFactory
|
public interface INodePinVmFactory
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:paz="clr-namespace:Avalonia.Controls.PanAndZoom;assembly=Avalonia.Controls.PanAndZoom"
|
xmlns:paz="clr-namespace:Avalonia.Controls.PanAndZoom;assembly=Avalonia.Controls.PanAndZoom"
|
||||||
xmlns:visualScripting="clr-namespace:Artemis.UI.Screens.VisualScripting"
|
xmlns:visualScripting="clr-namespace:Artemis.UI.Screens.VisualScripting"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.VisualScripting.NodeScriptView"
|
x:Class="Artemis.UI.Screens.VisualScripting.NodeScriptView"
|
||||||
x:DataType="visualScripting:NodeScriptViewModel">
|
x:DataType="visualScripting:NodeScriptViewModel">
|
||||||
@ -23,7 +24,10 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Background="{DynamicResource LargeCheckerboardBrush}"
|
Background="{DynamicResource LargeCheckerboardBrush}"
|
||||||
ZoomChanged="ZoomBorder_OnZoomChanged">
|
ZoomChanged="ZoomBorder_OnZoomChanged"
|
||||||
|
MaxZoomX="1"
|
||||||
|
MaxZoomY="1"
|
||||||
|
PointerReleased="ZoomBorder_OnPointerReleased">
|
||||||
<Grid Name="ContainerGrid" Background="Transparent">
|
<Grid Name="ContainerGrid" Background="Transparent">
|
||||||
<Grid.ContextFlyout>
|
<Grid.ContextFlyout>
|
||||||
<Flyout FlyoutPresenterClasses="node-picker-flyout">
|
<Flyout FlyoutPresenterClasses="node-picker-flyout">
|
||||||
@ -52,7 +56,7 @@
|
|||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
||||||
<!-- Nodes -->
|
<!-- Nodes -->
|
||||||
<ItemsControl Items="{CompiledBinding NodeViewModels}">
|
<ItemsControl Name="NodesContainer" Items="{CompiledBinding NodeViewModels}">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<Canvas />
|
<Canvas />
|
||||||
@ -65,6 +69,17 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</ItemsControl.Styles>
|
</ItemsControl.Styles>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
||||||
|
<controls:SelectionRectangle Name="SelectionRectangle"
|
||||||
|
InputElement="{Binding #ZoomBorder}"
|
||||||
|
SelectionUpdated="SelectionRectangle_OnSelectionUpdated"
|
||||||
|
SelectionFinished="SelectionRectangle_OnSelectionFinished"
|
||||||
|
BorderBrush="{DynamicResource SystemAccentColor}"
|
||||||
|
BorderRadius="8">
|
||||||
|
<controls:SelectionRectangle.Background>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight1}" Opacity="0.2"></SolidColorBrush>
|
||||||
|
</controls:SelectionRectangle.Background>
|
||||||
|
</controls:SelectionRectangle>
|
||||||
</Grid>
|
</Grid>
|
||||||
</paz:ZoomBorder>
|
</paz:ZoomBorder>
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Artemis.UI.Shared.Controls;
|
||||||
|
using Artemis.UI.Shared.Events;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Generators;
|
||||||
using Avalonia.Controls.PanAndZoom;
|
using Avalonia.Controls.PanAndZoom;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
@ -15,13 +20,17 @@ namespace Artemis.UI.Screens.VisualScripting
|
|||||||
{
|
{
|
||||||
private readonly ZoomBorder _zoomBorder;
|
private readonly ZoomBorder _zoomBorder;
|
||||||
private readonly Grid _grid;
|
private readonly Grid _grid;
|
||||||
|
private readonly ItemsControl _nodesContainer;
|
||||||
|
private readonly SelectionRectangle _selectionRectangle;
|
||||||
|
|
||||||
public NodeScriptView()
|
public NodeScriptView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
_nodesContainer = this.Find<ItemsControl>("NodesContainer");
|
||||||
_zoomBorder = this.Find<ZoomBorder>("ZoomBorder");
|
_zoomBorder = this.Find<ZoomBorder>("ZoomBorder");
|
||||||
_grid = this.Find<Grid>("ContainerGrid");
|
_grid = this.Find<Grid>("ContainerGrid");
|
||||||
|
_selectionRectangle = this.Find<SelectionRectangle>("SelectionRectangle");
|
||||||
_zoomBorder.PropertyChanged += ZoomBorderOnPropertyChanged;
|
_zoomBorder.PropertyChanged += ZoomBorderOnPropertyChanged;
|
||||||
UpdateZoomBorderBackground();
|
UpdateZoomBorderBackground();
|
||||||
|
|
||||||
@ -56,5 +65,23 @@ namespace Artemis.UI.Screens.VisualScripting
|
|||||||
{
|
{
|
||||||
UpdateZoomBorderBackground();
|
UpdateZoomBorderBackground();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SelectionRectangle_OnSelectionUpdated(object? sender, SelectionRectangleEventArgs e)
|
||||||
|
{
|
||||||
|
List<ItemContainerInfo> itemContainerInfos = _nodesContainer.ItemContainerGenerator.Containers.Where(c => c.ContainerControl.Bounds.Intersects(e.Rectangle)).ToList();
|
||||||
|
List<NodeViewModel> nodes = itemContainerInfos.Where(c => c.Item is NodeViewModel).Select(c => (NodeViewModel) c.Item).ToList();
|
||||||
|
ViewModel?.UpdateNodeSelection(nodes, e.KeyModifiers.HasFlag(KeyModifiers.Shift), e.KeyModifiers.HasFlag(KeyModifiers.Control));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectionRectangle_OnSelectionFinished(object? sender, SelectionRectangleEventArgs e)
|
||||||
|
{
|
||||||
|
ViewModel?.FinishNodeSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ZoomBorder_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!_selectionRectangle.IsSelecting)
|
||||||
|
ViewModel?.ClearNodeSelection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Events;
|
using Artemis.Core.Events;
|
||||||
using Artemis.Core.Services;
|
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services.NodeEditor;
|
using Artemis.UI.Shared.Services.NodeEditor;
|
||||||
@ -16,19 +16,16 @@ namespace Artemis.UI.Screens.VisualScripting;
|
|||||||
|
|
||||||
public class NodeScriptViewModel : ActivatableViewModelBase
|
public class NodeScriptViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly INodeService _nodeService;
|
|
||||||
private readonly INodeEditorService _nodeEditorService;
|
|
||||||
private readonly INodeVmFactory _nodeVmFactory;
|
private readonly INodeVmFactory _nodeVmFactory;
|
||||||
|
private List<NodeViewModel>? _initialNodeSelection;
|
||||||
|
|
||||||
public NodeScriptViewModel(NodeScript nodeScript, INodeVmFactory nodeVmFactory, INodeService nodeService, INodeEditorService nodeEditorService)
|
public NodeScriptViewModel(NodeScript nodeScript, INodeVmFactory nodeVmFactory, INodeEditorService nodeEditorService)
|
||||||
{
|
{
|
||||||
_nodeVmFactory = nodeVmFactory;
|
_nodeVmFactory = nodeVmFactory;
|
||||||
_nodeService = nodeService;
|
|
||||||
_nodeEditorService = nodeEditorService;
|
|
||||||
|
|
||||||
NodeScript = nodeScript;
|
NodeScript = nodeScript;
|
||||||
NodePickerViewModel = _nodeVmFactory.NodePickerViewModel(nodeScript);
|
NodePickerViewModel = _nodeVmFactory.NodePickerViewModel(nodeScript);
|
||||||
History = _nodeEditorService.GetHistory(NodeScript);
|
History = nodeEditorService.GetHistory(NodeScript);
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
@ -42,7 +39,9 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
NodeViewModels = new ObservableCollection<NodeViewModel>();
|
NodeViewModels = new ObservableCollection<NodeViewModel>();
|
||||||
foreach (INode nodeScriptNode in NodeScript.Nodes)
|
foreach (INode nodeScriptNode in NodeScript.Nodes)
|
||||||
NodeViewModels.Add(_nodeVmFactory.NodeViewModel(NodeScript, nodeScriptNode));
|
NodeViewModels.Add(_nodeVmFactory.NodeViewModel(this, nodeScriptNode));
|
||||||
|
|
||||||
|
CableViewModels = new ObservableCollection<CableViewModel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeScript NodeScript { get; }
|
public NodeScript NodeScript { get; }
|
||||||
@ -51,9 +50,60 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
|||||||
public NodePickerViewModel NodePickerViewModel { get; }
|
public NodePickerViewModel NodePickerViewModel { get; }
|
||||||
public NodeEditorHistory History { get; }
|
public NodeEditorHistory History { get; }
|
||||||
|
|
||||||
|
public void UpdateNodeSelection(List<NodeViewModel> nodes, bool expand, bool invert)
|
||||||
|
{
|
||||||
|
_initialNodeSelection ??= NodeViewModels.Where(vm => vm.IsSelected).ToList();
|
||||||
|
|
||||||
|
if (expand)
|
||||||
|
{
|
||||||
|
foreach (NodeViewModel nodeViewModel in nodes)
|
||||||
|
nodeViewModel.IsSelected = true;
|
||||||
|
}
|
||||||
|
else if (invert)
|
||||||
|
{
|
||||||
|
foreach (NodeViewModel nodeViewModel in nodes)
|
||||||
|
nodeViewModel.IsSelected = !_initialNodeSelection.Contains(nodeViewModel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (NodeViewModel nodeViewModel in nodes)
|
||||||
|
nodeViewModel.IsSelected = true;
|
||||||
|
foreach (NodeViewModel nodeViewModel in NodeViewModels.Except(nodes))
|
||||||
|
nodeViewModel.IsSelected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinishNodeSelection()
|
||||||
|
{
|
||||||
|
_initialNodeSelection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearNodeSelection()
|
||||||
|
{
|
||||||
|
foreach (NodeViewModel nodeViewModel in NodeViewModels)
|
||||||
|
nodeViewModel.IsSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartNodeDrag(Point position)
|
||||||
|
{
|
||||||
|
foreach (NodeViewModel nodeViewModel in NodeViewModels)
|
||||||
|
nodeViewModel.SaveDragOffset(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateNodeDrag(Point position)
|
||||||
|
{
|
||||||
|
foreach (NodeViewModel nodeViewModel in NodeViewModels)
|
||||||
|
nodeViewModel.UpdatePosition(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinishNodeDrag()
|
||||||
|
{
|
||||||
|
// TODO: Command
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleNodeAdded(SingleValueEventArgs<INode> eventArgs)
|
private void HandleNodeAdded(SingleValueEventArgs<INode> eventArgs)
|
||||||
{
|
{
|
||||||
NodeViewModels.Add(_nodeVmFactory.NodeViewModel(NodeScript, eventArgs.Value));
|
NodeViewModels.Add(_nodeVmFactory.NodeViewModel(this, eventArgs.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleNodeRemoved(SingleValueEventArgs<INode> eventArgs)
|
private void HandleNodeRemoved(SingleValueEventArgs<INode> eventArgs)
|
||||||
|
|||||||
@ -13,14 +13,29 @@
|
|||||||
<Setter Property="Background" Value="{DynamicResource ContentDialogBackground}" />
|
<Setter Property="Background" Value="{DynamicResource ContentDialogBackground}" />
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource CardStrokeColorDefaultBrush}" />
|
<Setter Property="BorderBrush" Value="{DynamicResource CardStrokeColorDefaultBrush}" />
|
||||||
<Setter Property="BorderThickness" Value="1" />
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Setter Property="Transitions">
|
||||||
|
<Setter.Value>
|
||||||
|
<Transitions>
|
||||||
|
<BrushTransition Property="BorderBrush" Duration="0:0:0.2" Easing="CubicEaseOut"/>
|
||||||
|
</Transitions>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Border.node-container-selected">
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource SystemAccentColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ContentControl#CustomViewModelContainer">
|
<Style Selector="ContentControl#CustomViewModelContainer">
|
||||||
<Setter Property="Margin" Value="20 0"></Setter>
|
<Setter Property="Margin" Value="20 0"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
<Border Classes="node-container">
|
<Border Classes="node-container" Classes.node-container-selected="{CompiledBinding IsSelected}">
|
||||||
<Grid RowDefinitions="Auto,*">
|
<Grid RowDefinitions="Auto,*">
|
||||||
<Border Grid.Row="0" Background="{DynamicResource TaskDialogHeaderBackground}" CornerRadius="6 6 0 0">
|
<Border Grid.Row="0"
|
||||||
|
Background="{DynamicResource TaskDialogHeaderBackground}"
|
||||||
|
CornerRadius="6 6 0 0"
|
||||||
|
Cursor="Hand"
|
||||||
|
PointerReleased="InputElement_OnPointerReleased"
|
||||||
|
PointerMoved="InputElement_OnPointerMoved">
|
||||||
<Grid Classes="node-header"
|
<Grid Classes="node-header"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
ColumnDefinitions="*,Auto">
|
ColumnDefinitions="*,Auto">
|
||||||
|
|||||||
@ -1,12 +1,18 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
|
using Avalonia.Controls.PanAndZoom;
|
||||||
|
using Avalonia.Input;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
using Avalonia.VisualTree;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.VisualScripting;
|
namespace Artemis.UI.Screens.VisualScripting;
|
||||||
|
|
||||||
public class NodeView : ReactiveUserControl<NodeViewModel>
|
public class NodeView : ReactiveUserControl<NodeViewModel>
|
||||||
{
|
{
|
||||||
|
private bool _dragging;
|
||||||
|
|
||||||
public NodeView()
|
public NodeView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -33,4 +39,40 @@ public class NodeView : ReactiveUserControl<NodeViewModel>
|
|||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
if (ViewModel == null || e.InitialPressMouseButton != MouseButton.Left)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_dragging)
|
||||||
|
{
|
||||||
|
_dragging = false;
|
||||||
|
ViewModel.NodeScriptViewModel.FinishNodeDrag();
|
||||||
|
e.Pointer.Capture(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewModel.NodeScriptViewModel.UpdateNodeSelection(new List<NodeViewModel> {ViewModel}, e.KeyModifiers.HasFlag(KeyModifiers.Shift), e.KeyModifiers.HasFlag(KeyModifiers.Control));
|
||||||
|
ViewModel.NodeScriptViewModel.FinishNodeSelection();
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InputElement_OnPointerMoved(object? sender, PointerEventArgs e)
|
||||||
|
{
|
||||||
|
PointerPoint point = e.GetCurrentPoint(this.FindAncestorOfType<ZoomBorder>());
|
||||||
|
if (ViewModel == null || !point.Properties.IsLeftButtonPressed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_dragging)
|
||||||
|
{
|
||||||
|
_dragging = true;
|
||||||
|
ViewModel.NodeScriptViewModel.StartNodeDrag(point.Position);
|
||||||
|
e.Pointer.Capture((IInputElement?) sender);
|
||||||
|
}
|
||||||
|
ViewModel.NodeScriptViewModel.UpdateNodeDrag(point.Position);
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -4,10 +4,12 @@ using System.Reactive;
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
|
using Artemis.UI.Screens.SurfaceEditor;
|
||||||
using Artemis.UI.Screens.VisualScripting.Pins;
|
using Artemis.UI.Screens.VisualScripting.Pins;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services.NodeEditor;
|
using Artemis.UI.Shared.Services.NodeEditor;
|
||||||
using Artemis.UI.Shared.Services.NodeEditor.Commands;
|
using Artemis.UI.Shared.Services.NodeEditor.Commands;
|
||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls.Mixins;
|
using Avalonia.Controls.Mixins;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
@ -16,16 +18,18 @@ namespace Artemis.UI.Screens.VisualScripting;
|
|||||||
|
|
||||||
public class NodeViewModel : ActivatableViewModelBase
|
public class NodeViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly NodeScript _nodeScript;
|
|
||||||
private readonly INodeEditorService _nodeEditorService;
|
private readonly INodeEditorService _nodeEditorService;
|
||||||
|
|
||||||
private ICustomNodeViewModel? _customNodeViewModel;
|
private ICustomNodeViewModel? _customNodeViewModel;
|
||||||
private ReactiveCommand<Unit, Unit>? _deleteNode;
|
private ReactiveCommand<Unit, Unit>? _deleteNode;
|
||||||
private ObservableAsPropertyHelper<bool>? _isStaticNode;
|
private ObservableAsPropertyHelper<bool>? _isStaticNode;
|
||||||
|
private double _dragOffsetX;
|
||||||
|
private double _dragOffsetY;
|
||||||
|
private bool _isSelected;
|
||||||
|
|
||||||
public NodeViewModel(NodeScript nodeScript, INode node, INodePinVmFactory nodePinVmFactory, INodeEditorService nodeEditorService)
|
public NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node, INodePinVmFactory nodePinVmFactory, INodeEditorService nodeEditorService)
|
||||||
{
|
{
|
||||||
_nodeScript = nodeScript;
|
NodeScriptViewModel = nodeScriptViewModel;
|
||||||
_nodeEditorService = nodeEditorService;
|
_nodeEditorService = nodeEditorService;
|
||||||
Node = node;
|
Node = node;
|
||||||
|
|
||||||
@ -54,6 +58,7 @@ public class NodeViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
public bool IsStaticNode => _isStaticNode?.Value ?? true;
|
public bool IsStaticNode => _isStaticNode?.Value ?? true;
|
||||||
|
|
||||||
|
public NodeScriptViewModel NodeScriptViewModel { get; set; }
|
||||||
public INode Node { get; }
|
public INode Node { get; }
|
||||||
public ReadOnlyObservableCollection<PinViewModel> InputPinViewModels { get; }
|
public ReadOnlyObservableCollection<PinViewModel> InputPinViewModels { get; }
|
||||||
public ReadOnlyObservableCollection<PinCollectionViewModel> InputPinCollectionViewModels { get; }
|
public ReadOnlyObservableCollection<PinCollectionViewModel> InputPinCollectionViewModels { get; }
|
||||||
@ -72,8 +77,32 @@ public class NodeViewModel : ActivatableViewModelBase
|
|||||||
set => RaiseAndSetIfChanged(ref _deleteNode, value);
|
set => RaiseAndSetIfChanged(ref _deleteNode, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsSelected
|
||||||
|
{
|
||||||
|
get => _isSelected;
|
||||||
|
set => RaiseAndSetIfChanged(ref _isSelected, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveDragOffset(Point mouseStartPosition)
|
||||||
|
{
|
||||||
|
if (!IsSelected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_dragOffsetX = Node.X - mouseStartPosition.X;
|
||||||
|
_dragOffsetY = Node.Y - mouseStartPosition.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdatePosition(Point mousePosition)
|
||||||
|
{
|
||||||
|
if (!IsSelected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Node.X = Math.Round((mousePosition.X + _dragOffsetX) / 10d, 0, MidpointRounding.AwayFromZero) * 10d;
|
||||||
|
Node.Y = Math.Round((mousePosition.Y + _dragOffsetY) / 10d, 0, MidpointRounding.AwayFromZero) * 10d;
|
||||||
|
}
|
||||||
|
|
||||||
private void ExecuteDeleteNode()
|
private void ExecuteDeleteNode()
|
||||||
{
|
{
|
||||||
_nodeEditorService.ExecuteCommand(_nodeScript, new DeleteNode(_nodeScript, Node));
|
_nodeEditorService.ExecuteCommand(NodeScriptViewModel.NodeScript, new DeleteNode(NodeScriptViewModel.NodeScript, Node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user