mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +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:
parent
7c83d5345f
commit
8fd18b9565
@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.Core;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.Services.ProfileEditor.Commands;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a profile editor command that can be used to change the display condition of a profile element.
|
||||||
|
/// </summary>
|
||||||
|
public class ChangeElementDisplayCondition : IProfileEditorCommand, IDisposable
|
||||||
|
{
|
||||||
|
private readonly ICondition? _condition;
|
||||||
|
private readonly ICondition? _oldCondition;
|
||||||
|
private readonly RenderProfileElement _profileElement;
|
||||||
|
private bool _executed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="ChangeElementDisplayCondition" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="profileElement">The render profile element whose display condition to change.</param>
|
||||||
|
/// <param name="condition">The new display condition.</param>
|
||||||
|
public ChangeElementDisplayCondition(RenderProfileElement profileElement, ICondition? condition)
|
||||||
|
{
|
||||||
|
_profileElement = profileElement;
|
||||||
|
_condition = condition;
|
||||||
|
_oldCondition = profileElement.DisplayCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_executed)
|
||||||
|
_oldCondition?.Dispose();
|
||||||
|
else
|
||||||
|
_condition?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string DisplayName => "Change display condition mode";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Execute()
|
||||||
|
{
|
||||||
|
_profileElement.DisplayCondition = _condition;
|
||||||
|
_executed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Undo()
|
||||||
|
{
|
||||||
|
_profileElement.DisplayCondition = _oldCondition;
|
||||||
|
_executed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -65,6 +65,9 @@
|
|||||||
<Compile Update="Screens\VisualScripting\DragCableView.axaml.cs">
|
<Compile Update="Screens\VisualScripting\DragCableView.axaml.cs">
|
||||||
<DependentUpon>DragCableView.axaml</DependentUpon>
|
<DependentUpon>DragCableView.axaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="Screens\VisualScripting\NodeScriptWindowView.axaml.cs">
|
||||||
|
<DependentUpon>NodeScriptWindowView.axaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AvaloniaXaml Update="DefaultTypes\PropertyInput\StringPropertyInputView.axaml">
|
<AvaloniaXaml Update="DefaultTypes\PropertyInput\StringPropertyInputView.axaml">
|
||||||
|
|||||||
@ -92,7 +92,7 @@ namespace Artemis.UI.Ninject.Factories
|
|||||||
|
|
||||||
public interface INodeVmFactory : IVmFactory
|
public interface INodeVmFactory : IVmFactory
|
||||||
{
|
{
|
||||||
NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript);
|
NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript, bool isPreview);
|
||||||
NodePickerViewModel NodePickerViewModel(NodeScript nodeScript);
|
NodePickerViewModel NodePickerViewModel(NodeScript nodeScript);
|
||||||
NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node);
|
NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node);
|
||||||
CableViewModel CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to);
|
CableViewModel CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to);
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
<UserControl 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:displayCondition="clr-namespace:Artemis.UI.Screens.ProfileEditor.DisplayCondition"
|
||||||
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.ProfileEditor.DisplayCondition.DisplayConditionScriptView"
|
||||||
|
x:DataType="displayCondition:DisplayConditionScriptViewModel">
|
||||||
|
<Grid>
|
||||||
|
<Grid IsVisible="{CompiledBinding NodeScriptViewModel, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
|
<ContentControl Content="{CompiledBinding NodeScriptViewModel}" />
|
||||||
|
<Button Classes="icon-button"
|
||||||
|
ToolTip.Tip="Open editor"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Margin="4"
|
||||||
|
Command="{Binding OpenEditor}">
|
||||||
|
<avalonia:MaterialIcon Kind="OpenInNew"></avalonia:MaterialIcon>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Button VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Command="{Binding EnableConditions}"
|
||||||
|
IsVisible="{CompiledBinding NodeScriptViewModel, Converter={x:Static ObjectConverters.IsNull}}">
|
||||||
|
Enable display conditions
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition
|
||||||
|
{
|
||||||
|
public partial class DisplayConditionScriptView : ReactiveUserControl<DisplayConditionScriptViewModel>
|
||||||
|
{
|
||||||
|
public DisplayConditionScriptView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.UI.Ninject.Factories;
|
||||||
|
using Artemis.UI.Screens.VisualScripting;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
|
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
|
||||||
|
using Avalonia.Controls.Mixins;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition;
|
||||||
|
|
||||||
|
public class DisplayConditionScriptViewModel : ActivatableViewModelBase
|
||||||
|
{
|
||||||
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
|
private readonly IWindowService _windowService;
|
||||||
|
private ObservableAsPropertyHelper<NodeScriptViewModel?>? _nodeScriptViewModel;
|
||||||
|
private RenderProfileElement? _profileElement;
|
||||||
|
|
||||||
|
public DisplayConditionScriptViewModel(IProfileEditorService profileEditorService, INodeVmFactory nodeVmFactory, IWindowService windowService)
|
||||||
|
{
|
||||||
|
_profileEditorService = profileEditorService;
|
||||||
|
_windowService = windowService;
|
||||||
|
this.WhenActivated(d =>
|
||||||
|
{
|
||||||
|
profileEditorService.ProfileElement.Subscribe(p => _profileElement = p).DisposeWith(d);
|
||||||
|
_nodeScriptViewModel = profileEditorService.ProfileElement
|
||||||
|
.Select(p => p?.WhenAnyValue(element => element.DisplayCondition) ?? Observable.Never<ICondition?>())
|
||||||
|
.Switch()
|
||||||
|
.Select(c => c is StaticCondition staticCondition ? nodeVmFactory.NodeScriptViewModel(staticCondition.Script, true) : null)
|
||||||
|
.ToProperty(this, vm => vm.NodeScriptViewModel)
|
||||||
|
.DisposeWith(d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeScriptViewModel? NodeScriptViewModel => _nodeScriptViewModel?.Value;
|
||||||
|
|
||||||
|
public async Task EnableConditions()
|
||||||
|
{
|
||||||
|
bool confirmed = await _windowService.ShowConfirmContentDialog(
|
||||||
|
"Display conditions",
|
||||||
|
"Do you want to enable display conditions for this element? \r\n" +
|
||||||
|
"Using display conditions you can dynamically hide or show layers and folders depending on certain parameters."
|
||||||
|
);
|
||||||
|
|
||||||
|
if (confirmed && _profileElement != null)
|
||||||
|
_profileEditorService.ExecuteCommand(new ChangeElementDisplayCondition(_profileElement, new StaticCondition(_profileElement)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OpenEditor()
|
||||||
|
{
|
||||||
|
if (_profileElement?.DisplayCondition is StaticCondition staticCondition)
|
||||||
|
await _windowService.ShowDialogAsync<NodeScriptWindowViewModel, bool>(("nodeScript", staticCondition.Script));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -97,7 +97,7 @@
|
|||||||
<GridSplitter Grid.Row="1" Classes="editor-grid-splitter-horizontal" />
|
<GridSplitter Grid.Row="1" Classes="editor-grid-splitter-horizontal" />
|
||||||
|
|
||||||
<Border Grid.Row="2" Classes="card card-condensed" Margin="4">
|
<Border Grid.Row="2" Classes="card card-condensed" Margin="4">
|
||||||
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Conditions</TextBlock>
|
<ContentControl Content="{CompiledBinding DisplayConditionScriptViewModel}"></ContentControl>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Screens.ProfileEditor.DisplayCondition;
|
||||||
using Artemis.UI.Screens.ProfileEditor.ProfileTree;
|
using Artemis.UI.Screens.ProfileEditor.ProfileTree;
|
||||||
using Artemis.UI.Screens.ProfileEditor.Properties;
|
using Artemis.UI.Screens.ProfileEditor.Properties;
|
||||||
using Artemis.UI.Screens.ProfileEditor.StatusBar;
|
using Artemis.UI.Screens.ProfileEditor.StatusBar;
|
||||||
@ -29,6 +30,7 @@ public class ProfileEditorViewModel : MainScreenViewModel
|
|||||||
ProfileTreeViewModel profileTreeViewModel,
|
ProfileTreeViewModel profileTreeViewModel,
|
||||||
ProfileEditorTitleBarViewModel profileEditorTitleBarViewModel,
|
ProfileEditorTitleBarViewModel profileEditorTitleBarViewModel,
|
||||||
PropertiesViewModel propertiesViewModel,
|
PropertiesViewModel propertiesViewModel,
|
||||||
|
DisplayConditionScriptViewModel displayConditionScriptViewModel,
|
||||||
StatusBarViewModel statusBarViewModel)
|
StatusBarViewModel statusBarViewModel)
|
||||||
: base(hostScreen, "profile-editor")
|
: base(hostScreen, "profile-editor")
|
||||||
{
|
{
|
||||||
@ -36,6 +38,7 @@ public class ProfileEditorViewModel : MainScreenViewModel
|
|||||||
VisualEditorViewModel = visualEditorViewModel;
|
VisualEditorViewModel = visualEditorViewModel;
|
||||||
ProfileTreeViewModel = profileTreeViewModel;
|
ProfileTreeViewModel = profileTreeViewModel;
|
||||||
PropertiesViewModel = propertiesViewModel;
|
PropertiesViewModel = propertiesViewModel;
|
||||||
|
DisplayConditionScriptViewModel = displayConditionScriptViewModel;
|
||||||
StatusBarViewModel = statusBarViewModel;
|
StatusBarViewModel = statusBarViewModel;
|
||||||
TitleBarViewModel = profileEditorTitleBarViewModel;
|
TitleBarViewModel = profileEditorTitleBarViewModel;
|
||||||
|
|
||||||
@ -56,6 +59,7 @@ public class ProfileEditorViewModel : MainScreenViewModel
|
|||||||
public VisualEditorViewModel VisualEditorViewModel { get; }
|
public VisualEditorViewModel VisualEditorViewModel { get; }
|
||||||
public ProfileTreeViewModel ProfileTreeViewModel { get; }
|
public ProfileTreeViewModel ProfileTreeViewModel { get; }
|
||||||
public PropertiesViewModel PropertiesViewModel { get; }
|
public PropertiesViewModel PropertiesViewModel { get; }
|
||||||
|
public DisplayConditionScriptViewModel DisplayConditionScriptViewModel { get; }
|
||||||
public StatusBarViewModel StatusBarViewModel { get; }
|
public StatusBarViewModel StatusBarViewModel { get; }
|
||||||
|
|
||||||
public ReadOnlyObservableCollection<IToolViewModel>? Tools
|
public ReadOnlyObservableCollection<IToolViewModel>? Tools
|
||||||
@ -70,6 +74,7 @@ public class ProfileEditorViewModel : MainScreenViewModel
|
|||||||
public PluginSetting<double> ConditionsHeight => _settingsService.GetSetting("ProfileEditor.ConditionsHeight", 300.0);
|
public PluginSetting<double> ConditionsHeight => _settingsService.GetSetting("ProfileEditor.ConditionsHeight", 300.0);
|
||||||
public PluginSetting<double> PropertiesHeight => _settingsService.GetSetting("ProfileEditor.PropertiesHeight", 300.0);
|
public PluginSetting<double> PropertiesHeight => _settingsService.GetSetting("ProfileEditor.PropertiesHeight", 300.0);
|
||||||
|
|
||||||
|
|
||||||
public void OpenUrl(string url)
|
public void OpenUrl(string url)
|
||||||
{
|
{
|
||||||
Utilities.OpenUrl(url);
|
Utilities.OpenUrl(url);
|
||||||
|
|||||||
@ -7,7 +7,8 @@
|
|||||||
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
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"
|
||||||
|
IsHitTestVisible="{CompiledBinding !IsPreview}">
|
||||||
<UserControl.Styles>
|
<UserControl.Styles>
|
||||||
<Style Selector="FlyoutPresenter.node-picker-flyout">
|
<Style Selector="FlyoutPresenter.node-picker-flyout">
|
||||||
<Setter Property="MaxWidth" Value="1000"></Setter>
|
<Setter Property="MaxWidth" Value="1000"></Setter>
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Events;
|
||||||
using Artemis.UI.Shared.Controls;
|
using Artemis.UI.Shared.Controls;
|
||||||
using Artemis.UI.Shared.Events;
|
using Artemis.UI.Shared.Events;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
@ -35,11 +38,51 @@ public class NodeScriptView : ReactiveUserControl<NodeScriptViewModel>
|
|||||||
UpdateZoomBorderBackground();
|
UpdateZoomBorderBackground();
|
||||||
|
|
||||||
_grid.AddHandler(PointerReleasedEvent, CanvasOnPointerReleased, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
_grid.AddHandler(PointerReleasedEvent, CanvasOnPointerReleased, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
||||||
this.WhenActivated(_ => ViewModel?.PickerPositionSubject.Subscribe(p =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
ViewModel.NodePickerViewModel.Position = p;
|
ViewModel!.PickerPositionSubject.Subscribe(p =>
|
||||||
_grid?.ContextFlyout?.ShowAt(_grid, true);
|
{
|
||||||
}));
|
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)
|
private void CanvasOnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
@ -49,6 +92,27 @@ public class NodeScriptView : ReactiveUserControl<NodeScriptViewModel>
|
|||||||
ViewModel.NodePickerViewModel.Position = e.GetPosition(_grid);
|
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)
|
private void ZoomBorderOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Property.Name == nameof(_zoomBorder.Background))
|
if (e.Property.Name == nameof(_zoomBorder.Background))
|
||||||
|
|||||||
@ -10,7 +10,6 @@ using Artemis.Core.Services;
|
|||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
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.Interfaces;
|
|
||||||
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;
|
||||||
@ -24,25 +23,24 @@ namespace Artemis.UI.Screens.VisualScripting;
|
|||||||
public class NodeScriptViewModel : ActivatableViewModelBase
|
public class NodeScriptViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly INodeEditorService _nodeEditorService;
|
private readonly INodeEditorService _nodeEditorService;
|
||||||
private readonly INotificationService _notificationService;
|
|
||||||
private readonly INodeVmFactory _nodeVmFactory;
|
|
||||||
private readonly INodeService _nodeService;
|
private readonly INodeService _nodeService;
|
||||||
private readonly SourceList<NodeViewModel> _nodeViewModels;
|
private readonly SourceList<NodeViewModel> _nodeViewModels;
|
||||||
|
private readonly INodeVmFactory _nodeVmFactory;
|
||||||
private readonly Subject<Point> _requestedPickerPositionSubject;
|
private readonly Subject<Point> _requestedPickerPositionSubject;
|
||||||
|
|
||||||
private DragCableViewModel? _dragViewModel;
|
private DragCableViewModel? _dragViewModel;
|
||||||
private List<NodeViewModel>? _initialNodeSelection;
|
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;
|
_nodeVmFactory = nodeVmFactory;
|
||||||
_nodeService = nodeService;
|
_nodeService = nodeService;
|
||||||
_nodeEditorService = nodeEditorService;
|
_nodeEditorService = nodeEditorService;
|
||||||
_notificationService = notificationService;
|
|
||||||
_nodeViewModels = new SourceList<NodeViewModel>();
|
_nodeViewModels = new SourceList<NodeViewModel>();
|
||||||
_requestedPickerPositionSubject = new Subject<Point>();
|
_requestedPickerPositionSubject = new Subject<Point>();
|
||||||
|
|
||||||
NodeScript = nodeScript;
|
NodeScript = nodeScript;
|
||||||
|
IsPreview = isPreview;
|
||||||
NodePickerViewModel = _nodeVmFactory.NodePickerViewModel(nodeScript);
|
NodePickerViewModel = _nodeVmFactory.NodePickerViewModel(nodeScript);
|
||||||
History = nodeEditorService.GetHistory(NodeScript);
|
History = nodeEditorService.GetHistory(NodeScript);
|
||||||
PickerPositionSubject = _requestedPickerPositionSubject.AsObservable();
|
PickerPositionSubject = _requestedPickerPositionSubject.AsObservable();
|
||||||
@ -55,13 +53,6 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
|||||||
Observable.FromEventPattern<SingleValueEventArgs<INode>>(x => NodeScript.NodeRemoved += x, x => NodeScript.NodeRemoved -= x)
|
Observable.FromEventPattern<SingleValueEventArgs<INode>>(x => NodeScript.NodeRemoved += x, x => NodeScript.NodeRemoved -= x)
|
||||||
.Subscribe(e => HandleNodeRemoved(e.EventArgs))
|
.Subscribe(e => HandleNodeRemoved(e.EventArgs))
|
||||||
.DisposeWith(d);
|
.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
|
// Create VMs for all nodes
|
||||||
@ -97,6 +88,8 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
|||||||
public NodeEditorHistory History { get; }
|
public NodeEditorHistory History { get; }
|
||||||
public IObservable<Point> PickerPositionSubject { get; }
|
public IObservable<Point> PickerPositionSubject { get; }
|
||||||
|
|
||||||
|
public bool IsPreview { get; }
|
||||||
|
|
||||||
public DragCableViewModel? DragViewModel
|
public DragCableViewModel? DragViewModel
|
||||||
{
|
{
|
||||||
get => _dragViewModel;
|
get => _dragViewModel;
|
||||||
@ -196,7 +189,9 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
// If dropped on top of a compatible pin, connect to it
|
// If dropped on top of a compatible pin, connect to it
|
||||||
if (targetPinVmModel != null && targetPinVmModel.IsCompatibleWith(sourcePinViewModel))
|
if (targetPinVmModel != null && targetPinVmModel.IsCompatibleWith(sourcePinViewModel))
|
||||||
|
{
|
||||||
_nodeEditorService.ExecuteCommand(NodeScript, new ConnectPins(sourcePinViewModel.Pin, targetPinVmModel.Pin));
|
_nodeEditorService.ExecuteCommand(NodeScript, new ConnectPins(sourcePinViewModel.Pin, targetPinVmModel.Pin));
|
||||||
|
}
|
||||||
// If not dropped on a pin allow the user to create a new node
|
// If not dropped on a pin allow the user to create a new node
|
||||||
else if (targetPinVmModel == null)
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -55,7 +55,7 @@ namespace Artemis.UI.Screens.Workshop
|
|||||||
orNode.Result.ConnectTo(exitNode.Pins.First());
|
orNode.Result.ConnectTo(exitNode.Pins.First());
|
||||||
}
|
}
|
||||||
|
|
||||||
VisualEditorViewModel = nodeVmFactory.NodeScriptViewModel(_testScript);
|
VisualEditorViewModel = nodeVmFactory.NodeScriptViewModel(_testScript, false);
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user