mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 11:56:30 +00:00
Node editor - Added preview mode
in this mode the editor is read-only and rescales itself to fit it's container
This commit is contained in:
1 parent
7c83d5345f
commit
8fd18b9565
16 files changed
+299
-21
No files matched your search
@@ -7,7 +7,8 @@
|
||||
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.VisualScripting.NodeScriptView"
|
||||
x:DataType="visualScripting:NodeScriptViewModel">
|
||||
x:DataType="visualScripting:NodeScriptViewModel"
|
||||
IsHitTestVisible="{CompiledBinding !IsPreview}">
|
||||
<UserControl.Styles>
|
||||
<Style Selector="FlyoutPresenter.node-picker-flyout">
|
||||
<Setter Property="MaxWidth" Value="1000"></Setter>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.UI.Shared.Controls;
|
||||
using Artemis.UI.Shared.Events;
|
||||
using Avalonia;
|
||||
@@ -35,11 +38,51 @@ public class NodeScriptView : ReactiveUserControl<NodeScriptViewModel>
|
||||
UpdateZoomBorderBackground();
|
||||
|
||||
_grid.AddHandler(PointerReleasedEvent, CanvasOnPointerReleased, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
||||
this.WhenActivated(_ => ViewModel?.PickerPositionSubject.Subscribe(p =>
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
ViewModel.NodePickerViewModel.Position = p;
|
||||
_grid?.ContextFlyout?.ShowAt(_grid, true);
|
||||
}));
|
||||
ViewModel!.PickerPositionSubject.Subscribe(p =>
|
||||
{
|
||||
ViewModel.NodePickerViewModel.Position = p;
|
||||
_grid?.ContextFlyout?.ShowAt(_grid, true);
|
||||
}).DisposeWith(d);
|
||||
|
||||
if (ViewModel.IsPreview)
|
||||
{
|
||||
BoundsProperty.Changed.Subscribe(BoundsPropertyChanged).DisposeWith(d);
|
||||
ViewModel.NodeScript.NodeAdded += NodesChanged;
|
||||
ViewModel.NodeScript.NodeRemoved += NodesChanged;
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
ViewModel.NodeScript.NodeAdded -= NodesChanged;
|
||||
ViewModel.NodeScript.NodeRemoved -= NodesChanged;
|
||||
}).DisposeWith(d);
|
||||
}
|
||||
|
||||
AutoFit(true);
|
||||
});
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
AutoFitIfPreview();
|
||||
return base.MeasureOverride(availableSize);
|
||||
}
|
||||
|
||||
private void AutoFitIfPreview()
|
||||
{
|
||||
if (ViewModel != null && ViewModel.IsPreview)
|
||||
AutoFit(true);
|
||||
}
|
||||
|
||||
private void NodesChanged(object? sender, SingleValueEventArgs<INode> e)
|
||||
{
|
||||
AutoFitIfPreview();
|
||||
}
|
||||
|
||||
private void BoundsPropertyChanged(AvaloniaPropertyChangedEventArgs<Rect> obj)
|
||||
{
|
||||
if (_nodesContainer.ItemContainerGenerator.Containers.Select(c => c.ContainerControl).Contains(obj.Sender))
|
||||
AutoFitIfPreview();
|
||||
}
|
||||
|
||||
private void CanvasOnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||
@@ -49,6 +92,27 @@ public class NodeScriptView : ReactiveUserControl<NodeScriptViewModel>
|
||||
ViewModel.NodePickerViewModel.Position = e.GetPosition(_grid);
|
||||
}
|
||||
|
||||
private void AutoFit(bool skipTransitions)
|
||||
{
|
||||
if (!_nodesContainer.ItemContainerGenerator.Containers.Any())
|
||||
return;
|
||||
|
||||
double left = _nodesContainer.ItemContainerGenerator.Containers.Select(c => c.ContainerControl.Bounds.Left).Min();
|
||||
double top = _nodesContainer.ItemContainerGenerator.Containers.Select(c => c.ContainerControl.Bounds.Top).Min();
|
||||
double bottom = _nodesContainer.ItemContainerGenerator.Containers.Select(c => c.ContainerControl.Bounds.Bottom).Max();
|
||||
double right = _nodesContainer.ItemContainerGenerator.Containers.Select(c => c.ContainerControl.Bounds.Right).Max();
|
||||
|
||||
// Add a 5 pixel margin around the rect
|
||||
Rect scriptRect = new(new Point(left - 5, top - 5), new Point(right + 5, bottom + 5));
|
||||
|
||||
// The scale depends on the available space
|
||||
double scale = Math.Min(1, Math.Min(Bounds.Width / scriptRect.Width, Bounds.Height / scriptRect.Height));
|
||||
|
||||
// Pan and zoom to make the script fit
|
||||
_zoomBorder.Zoom(scale, 0, 0, skipTransitions);
|
||||
_zoomBorder.Pan(Bounds.Center.X - scriptRect.Center.X * scale, Bounds.Center.Y - scriptRect.Center.Y * scale, skipTransitions);
|
||||
}
|
||||
|
||||
private void ZoomBorderOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property.Name == nameof(_zoomBorder.Background))
|
||||
|
||||
@@ -10,7 +10,6 @@ using Artemis.Core.Services;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.VisualScripting.Pins;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using Artemis.UI.Shared.Services.NodeEditor;
|
||||
using Artemis.UI.Shared.Services.NodeEditor.Commands;
|
||||
using Avalonia;
|
||||
@@ -24,25 +23,24 @@ namespace Artemis.UI.Screens.VisualScripting;
|
||||
public class NodeScriptViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly INodeEditorService _nodeEditorService;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly INodeVmFactory _nodeVmFactory;
|
||||
private readonly INodeService _nodeService;
|
||||
private readonly SourceList<NodeViewModel> _nodeViewModels;
|
||||
private readonly INodeVmFactory _nodeVmFactory;
|
||||
private readonly Subject<Point> _requestedPickerPositionSubject;
|
||||
|
||||
private DragCableViewModel? _dragViewModel;
|
||||
private List<NodeViewModel>? _initialNodeSelection;
|
||||
|
||||
public NodeScriptViewModel(NodeScript nodeScript, INodeVmFactory nodeVmFactory, INodeService nodeService, INodeEditorService nodeEditorService, INotificationService notificationService)
|
||||
public NodeScriptViewModel(NodeScript nodeScript, bool isPreview, INodeVmFactory nodeVmFactory, INodeService nodeService, INodeEditorService nodeEditorService)
|
||||
{
|
||||
_nodeVmFactory = nodeVmFactory;
|
||||
_nodeService = nodeService;
|
||||
_nodeEditorService = nodeEditorService;
|
||||
_notificationService = notificationService;
|
||||
_nodeViewModels = new SourceList<NodeViewModel>();
|
||||
_requestedPickerPositionSubject = new Subject<Point>();
|
||||
|
||||
NodeScript = nodeScript;
|
||||
IsPreview = isPreview;
|
||||
NodePickerViewModel = _nodeVmFactory.NodePickerViewModel(nodeScript);
|
||||
History = nodeEditorService.GetHistory(NodeScript);
|
||||
PickerPositionSubject = _requestedPickerPositionSubject.AsObservable();
|
||||
@@ -55,13 +53,6 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
||||
Observable.FromEventPattern<SingleValueEventArgs<INode>>(x => NodeScript.NodeRemoved += x, x => NodeScript.NodeRemoved -= x)
|
||||
.Subscribe(e => HandleNodeRemoved(e.EventArgs))
|
||||
.DisposeWith(d);
|
||||
|
||||
nodeEditorService.GetHistory(NodeScript).Undo
|
||||
.Subscribe(c => _notificationService.CreateNotification().WithMessage(c != null ? $"Undid {c.DisplayName}" : "Nothing to undo").Show())
|
||||
.DisposeWith(d);
|
||||
nodeEditorService.GetHistory(NodeScript).Redo
|
||||
.Subscribe(c => _notificationService.CreateNotification().WithMessage(c != null ? $"Redid {c.DisplayName}" : "Nothing to redo").Show())
|
||||
.DisposeWith(d);
|
||||
});
|
||||
|
||||
// Create VMs for all nodes
|
||||
@@ -97,6 +88,8 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
||||
public NodeEditorHistory History { get; }
|
||||
public IObservable<Point> PickerPositionSubject { get; }
|
||||
|
||||
public bool IsPreview { get; }
|
||||
|
||||
public DragCableViewModel? DragViewModel
|
||||
{
|
||||
get => _dragViewModel;
|
||||
@@ -196,7 +189,9 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
||||
|
||||
// If dropped on top of a compatible pin, connect to it
|
||||
if (targetPinVmModel != null && targetPinVmModel.IsCompatibleWith(sourcePinViewModel))
|
||||
{
|
||||
_nodeEditorService.ExecuteCommand(NodeScript, new ConnectPins(sourcePinViewModel.Pin, targetPinVmModel.Pin));
|
||||
}
|
||||
// If not dropped on a pin allow the user to create a new node
|
||||
else if (targetPinVmModel == null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:visualScripting="clr-namespace:Artemis.UI.Screens.VisualScripting"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.VisualScripting.NodeScriptWindowView"
|
||||
x:DataType="visualScripting:NodeScriptWindowViewModel"
|
||||
Title="VisualEditorWindowView">
|
||||
<ContentControl Content="{CompiledBinding NodeScriptViewModel}" />
|
||||
</Window>
|
||||
@@ -0,0 +1,21 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Artemis.UI.Screens.VisualScripting
|
||||
{
|
||||
public partial class NodeScriptWindowView : ReactiveCoreWindow<NodeScriptWindowViewModel>
|
||||
{
|
||||
public NodeScriptWindowView()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared;
|
||||
|
||||
namespace Artemis.UI.Screens.VisualScripting
|
||||
{
|
||||
public class NodeScriptWindowViewModel : DialogViewModelBase<bool>
|
||||
{
|
||||
public NodeScript NodeScript { get; }
|
||||
public NodeScriptViewModel NodeScriptViewModel { get; set; }
|
||||
|
||||
public NodeScriptWindowViewModel(NodeScript nodeScript, INodeVmFactory vmFactory)
|
||||
{
|
||||
NodeScript = nodeScript;
|
||||
NodeScriptViewModel = vmFactory.NodeScriptViewModel(NodeScript, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user