Core - Refactored display conditions

Profile editor - Added UIs for each condition type
This commit is contained in:
Robert committed 2022-04-09 00:11:22 +02:00
1 parent 66ea718316
commit 3dfc25b092
47 files changed
+1305 -546

No files matched your search

@@ -1,19 +1,18 @@
using System;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition
{
public class ConditionTypeViewModel : ViewModelBase
{
public ConditionTypeViewModel(string name, string description, Type? conditionType)
{
Name = name;
Description = description;
ConditionType = conditionType;
}
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition;
public string Name { get; }
public string Description { get; }
public Type? ConditionType { get; }
public class ConditionTypeViewModel : ViewModelBase
{
public ConditionTypeViewModel(string name, string description, Type conditionType)
{
Name = name;
Description = description;
ConditionType = conditionType;
}
public string Name { get; }
public string Description { get; }
public Type ConditionType { get; }
}
@@ -0,0 +1,16 @@
<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:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes.AlwaysOnConditionView">
<DockPanel VerticalAlignment="Top" Margin="0 5">
<avalonia:MaterialIcon Kind="InfoCircle" Margin="5 0"/>
<TextBlock Foreground="{DynamicResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap">
After playing the start segment, the main segment is endlessly repeated.
</TextBlock>
</DockPanel>
</UserControl>
@@ -0,0 +1,17 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes;
public class AlwaysOnConditionView : UserControl
{
public AlwaysOnConditionView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
@@ -0,0 +1,14 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes;
public class AlwaysOnConditionViewModel : ViewModelBase
{
private readonly AlwaysOnCondition _alwaysOnCondition;
public AlwaysOnConditionViewModel(AlwaysOnCondition alwaysOnCondition)
{
_alwaysOnCondition = alwaysOnCondition;
}
}
@@ -0,0 +1,59 @@
<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:dataModelPicker="clr-namespace:Artemis.UI.Shared.Controls.DataModelPicker;assembly=Artemis.UI.Shared"
xmlns:conditionTypes="clr-namespace:Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes.EventConditionView"
x:DataType="conditionTypes:EventConditionViewModel">
<DockPanel HorizontalAlignment="Stretch">
<DockPanel.Styles>
<Style Selector="DockPanel > TextBlock">
<Setter Property="Margin" Value="0 5" />
</Style>
</DockPanel.Styles>
<TextBlock DockPanel.Dock="Top">Triggered by event</TextBlock>
<dataModelPicker:DataModelPickerButton Placeholder="Select an event"
DockPanel.Dock="Top"
HorizontalAlignment="Stretch"
FilterTypes="{CompiledBinding FilterTypes}"
DataModelPath="{CompiledBinding EventPath}"/>
<TextBlock DockPanel.Dock="Top">When the event fires..</TextBlock>
<ComboBox PlaceholderText="Select a play mode" HorizontalAlignment="Stretch" DockPanel.Dock="Top" SelectedIndex="{CompiledBinding SelectedTriggerMode}">
<ComboBoxItem>
Play the timeline once
</ComboBoxItem>
<ComboBoxItem>
Toggle the element on or off
</ComboBoxItem>
</ComboBox>
<TextBlock DockPanel.Dock="Top" IsVisible="{CompiledBinding ShowOverlapOptions}">And if already playing..</TextBlock>
<ComboBox PlaceholderText="Select a play mode"
HorizontalAlignment="Stretch"
DockPanel.Dock="Top"
SelectedIndex="{CompiledBinding SelectedOverlapMode}"
IsVisible="{CompiledBinding ShowOverlapOptions}">
<ComboBoxItem>
Restart the timeline
</ComboBoxItem>
<ComboBoxItem IsEnabled="{CompiledBinding IsConditionForLayer}">
Play a second copy
</ComboBoxItem>
<ComboBoxItem>
Do nothing
</ComboBoxItem>
</ComboBox>
<Button DockPanel.Dock="Bottom"
ToolTip.Tip="Open editor"
Margin="0 15 0 5"
Command="{CompiledBinding OpenEditor}"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom">
Edit condition script
</Button>
</DockPanel>
</UserControl>
@@ -0,0 +1,17 @@
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes;
public class EventConditionView : ReactiveUserControl<EventConditionViewModel>
{
public EventConditionView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
@@ -0,0 +1,73 @@
using System;
using System.Collections.ObjectModel;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.UI.Screens.VisualScripting;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
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.ConditionTypes;
public class EventConditionViewModel : ActivatableViewModelBase
{
private readonly EventCondition _eventCondition;
private readonly IProfileEditorService _profileEditorService;
private readonly ObservableAsPropertyHelper<bool> _showOverlapOptions;
private readonly IWindowService _windowService;
private ObservableAsPropertyHelper<DataModelPath?>? _eventPath;
private ObservableAsPropertyHelper<int>? _selectedOverlapMode;
private ObservableAsPropertyHelper<int>? _selectedTriggerMode;
public EventConditionViewModel(EventCondition eventCondition, IProfileEditorService profileEditorService, IWindowService windowService)
{
_eventCondition = eventCondition;
_profileEditorService = profileEditorService;
_windowService = windowService;
_showOverlapOptions = this.WhenAnyValue(vm => vm.SelectedTriggerMode)
.Select(m => m == 0)
.ToProperty(this, vm => vm.ShowOverlapOptions);
this.WhenActivated(d =>
{
_eventPath = eventCondition.WhenAnyValue(c => c.EventPath).ToProperty(this, vm => vm.EventPath).DisposeWith(d);
_selectedTriggerMode = eventCondition.WhenAnyValue(c => c.TriggerMode).Select(m => (int) m).ToProperty(this, vm => vm.SelectedTriggerMode).DisposeWith(d);
_selectedOverlapMode = eventCondition.WhenAnyValue(c => c.OverlapMode).Select(m => (int) m).ToProperty(this, vm => vm.SelectedOverlapMode).DisposeWith(d);
});
OpenEditor = ReactiveCommand.CreateFromTask(ExecuteOpenEditor);
}
public ObservableCollection<Type> FilterTypes { get; } = new() {typeof(IDataModelEvent)};
public ReactiveCommand<Unit, Unit> OpenEditor { get; }
public bool ShowOverlapOptions => _showOverlapOptions.Value;
public bool IsConditionForLayer => _eventCondition.ProfileElement is Layer;
public DataModelPath? EventPath
{
get => _eventPath?.Value != null ? new DataModelPath(_eventPath.Value) : null;
set => _profileEditorService.ExecuteCommand(new UpdateEventConditionPath(_eventCondition, value != null ? new DataModelPath(value) : null));
}
public int SelectedTriggerMode
{
get => _selectedTriggerMode?.Value ?? 0;
set => _profileEditorService.ExecuteCommand(new UpdateEventTriggerMode(_eventCondition, (EventTriggerMode) value));
}
public int SelectedOverlapMode
{
get => _selectedOverlapMode?.Value ?? 0;
set => _profileEditorService.ExecuteCommand(new UpdateEventOverlapMode(_eventCondition, (EventOverlapMode) value));
}
private async Task ExecuteOpenEditor()
{
await _windowService.ShowDialogAsync<NodeScriptWindowViewModel, bool>(("nodeScript", _eventCondition.NodeScript));
}
}
@@ -0,0 +1,15 @@
<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: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.ConditionTypes.PlayOnceConditionView">
<DockPanel VerticalAlignment="Top" Margin="0 5">
<avalonia:MaterialIcon Kind="InfoCircle" Margin="5 0"/>
<TextBlock Foreground="{DynamicResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap">
Every segment of the timeline is played once.
</TextBlock>
</DockPanel>
</UserControl>
@@ -0,0 +1,17 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes;
public class PlayOnceConditionView : UserControl
{
public PlayOnceConditionView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
@@ -0,0 +1,14 @@
using Artemis.Core;
using Artemis.UI.Shared;
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes;
public class PlayOnceConditionViewModel : ViewModelBase
{
private readonly PlayOnceCondition _playOnceCondition;
public PlayOnceConditionViewModel(PlayOnceCondition playOnceCondition)
{
_playOnceCondition = playOnceCondition;
}
}
@@ -0,0 +1,45 @@
<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:conditionTypes="clr-namespace:Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes"
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.ConditionTypes.StaticConditionView"
x:DataType="conditionTypes:StaticConditionViewModel">
<DockPanel HorizontalAlignment="Stretch">
<DockPanel.Styles>
<Style Selector="DockPanel > TextBlock">
<Setter Property="Margin" Value="0 5" />
</Style>
</DockPanel.Styles>
<TextBlock DockPanel.Dock="Top">While condition is met..</TextBlock>
<ComboBox DockPanel.Dock="Top" PlaceholderText="Select a play mode" HorizontalAlignment="Stretch" SelectedIndex="{CompiledBinding SelectedPlayMode}">
<ComboBoxItem>Repeat the main segment</ComboBoxItem>
<ComboBoxItem>Play the main segment once</ComboBoxItem>
</ComboBox>
<TextBlock DockPanel.Dock="Top">And when no longer met..</TextBlock>
<ComboBox DockPanel.Dock="Top" PlaceholderText="Select a stop mode" HorizontalAlignment="Stretch" SelectedIndex="{CompiledBinding SelectedStopMode}">
<ComboBoxItem>Finish the main segment</ComboBoxItem>
<ComboBoxItem>Skip forward to the end segment</ComboBoxItem>
</ComboBox>
<DockPanel DockPanel.Dock="Top" Margin="0 5">
<avalonia:MaterialIcon Kind="InfoCircle" Margin="5 0" />
<TextBlock Foreground="{DynamicResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap">
The start- and end-segments are played once each time the condition is met.
</TextBlock>
</DockPanel>
<Button DockPanel.Dock="Bottom"
ToolTip.Tip="Open editor"
Margin="0 15 0 5"
Command="{CompiledBinding OpenEditor}"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom">
Edit condition script
</Button>
</DockPanel>
</UserControl>
@@ -0,0 +1,17 @@
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes;
public class StaticConditionView : ReactiveUserControl<StaticConditionViewModel>
{
public StaticConditionView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
@@ -0,0 +1,56 @@
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.UI.Screens.VisualScripting;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.ProfileEditor;
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
using ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes;
public class StaticConditionViewModel : ActivatableViewModelBase
{
private readonly IProfileEditorService _profileEditorService;
private readonly StaticCondition _staticCondition;
private readonly IWindowService _windowService;
private ObservableAsPropertyHelper<int>? _selectedPlayMode;
private ObservableAsPropertyHelper<int>? _selectedStopMode;
public StaticConditionViewModel(StaticCondition staticCondition, IProfileEditorService profileEditorService, IWindowService windowService)
{
_staticCondition = staticCondition;
_profileEditorService = profileEditorService;
_windowService = windowService;
this.WhenActivated(d =>
{
_selectedPlayMode = staticCondition.WhenAnyValue(c => c.PlayMode).Select(m => (int) m).ToProperty(this, vm => vm.SelectedPlayMode).DisposeWith(d);
_selectedStopMode = staticCondition.WhenAnyValue(c => c.StopMode).Select(m => (int) m).ToProperty(this, vm => vm.SelectedStopMode).DisposeWith(d);
});
OpenEditor = ReactiveCommand.CreateFromTask(ExecuteOpenEditor);
}
public ReactiveCommand<Unit, Unit> OpenEditor { get; }
public int SelectedPlayMode
{
get => _selectedPlayMode?.Value ?? 0;
set => _profileEditorService.ExecuteCommand(new UpdateStaticPlayMode(_staticCondition, (StaticPlayMode) value));
}
public int SelectedStopMode
{
get => _selectedStopMode?.Value ?? 0;
set => _profileEditorService.ExecuteCommand(new UpdateStaticStopMode(_staticCondition, (StaticStopMode) value));
}
private async Task ExecuteOpenEditor()
{
await _windowService.ShowDialogAsync<NodeScriptWindowViewModel, bool>(("nodeScript", _staticCondition.NodeScript));
}
}
@@ -3,8 +3,6 @@
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"
xmlns:dataModelPicker="clr-namespace:Artemis.UI.Shared.Controls.DataModelPicker;assembly=Artemis.UI.Shared"
mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="650"
x:Class="Artemis.UI.Screens.ProfileEditor.DisplayCondition.DisplayConditionScriptView"
x:DataType="displayCondition:DisplayConditionScriptViewModel">
@@ -20,19 +18,14 @@
</Style>
</UserControl.Styles>
<ScrollViewer>
<DockPanel LastChildFill="False">
<DockPanel.Styles>
<Style Selector="DockPanel > TextBlock">
<Setter Property="Margin" Value="0 5"></Setter>
</Style>
</DockPanel.Styles>
<TextBlock DockPanel.Dock="Top">Condition type</TextBlock>
<Grid RowDefinitions="Auto,Auto,*">
<TextBlock Grid.Row="0" Margin="0 5">Activation type</TextBlock>
<ComboBox Name="ConditionType"
DockPanel.Dock="Top"
Grid.Row="1"
Classes="condition-type"
PlaceholderText="Select a condition type"
PlaceholderText="Select an activation type"
Items="{CompiledBinding ConditionTypeViewModels}"
IsEnabled="{CompiledBinding ProfileElement, Converter={x:Static ObjectConverters.IsNotNull}}"
SelectedItem="{CompiledBinding SelectedConditionTypeViewModel}"
HorizontalAlignment="Stretch">
<ComboBox.ItemTemplate>
@@ -44,64 +37,7 @@
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Event options -->
<DockPanel IsVisible="{CompiledBinding ShowEventOptions}" DockPanel.Dock="Top" HorizontalAlignment="Stretch">
<TextBlock DockPanel.Dock="Top">Triggered by event</TextBlock>
<dataModelPicker:DataModelPickerButton Placeholder="Select an event"
DockPanel.Dock="Top"
HorizontalAlignment="Stretch" />
<TextBlock DockPanel.Dock="Top">When the event fires..</TextBlock>
<ComboBox PlaceholderText="Select a play mode" HorizontalAlignment="Stretch" DockPanel.Dock="Top">
<ComboBoxItem>
Play the timeline once
</ComboBoxItem>
<ComboBoxItem>
Toggle the element on or off
</ComboBoxItem>
</ComboBox>
<TextBlock DockPanel.Dock="Top">And if already playing..</TextBlock>
<ComboBox PlaceholderText="Select a play mode" HorizontalAlignment="Stretch" DockPanel.Dock="Top">
<ComboBoxItem>
Restart the timeline
</ComboBoxItem>
<ComboBoxItem>
Play a second copy
</ComboBoxItem>
<ComboBoxItem>
Do nothing
</ComboBoxItem>
</ComboBox>
</DockPanel>
<!-- Static options -->
<DockPanel IsVisible="{CompiledBinding ShowStaticOptions}" HorizontalAlignment="Stretch" DockPanel.Dock="Top">
<TextBlock DockPanel.Dock="Top">While condition is met..</TextBlock>
<ComboBox DockPanel.Dock="Top" PlaceholderText="Select a play mode" HorizontalAlignment="Stretch">
<ComboBoxItem>Play the main segment once</ComboBoxItem>
<ComboBoxItem>Repeat the main segment</ComboBoxItem>
</ComboBox>
<TextBlock DockPanel.Dock="Top">And when no longer met..</TextBlock>
<ComboBox DockPanel.Dock="Top" PlaceholderText="Select a stop mode" HorizontalAlignment="Stretch">
<ComboBoxItem>Finish the main segment</ComboBoxItem>
<ComboBoxItem>Skip forward to the end segment</ComboBoxItem>
</ComboBox>
<DockPanel DockPanel.Dock="Top" Margin="0 5">
<avalonia:MaterialIcon Kind="InfoCircle" Margin="5 0"></avalonia:MaterialIcon>
<TextBlock Foreground="{DynamicResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap">
The start- and end-segments are always played once.
</TextBlock>
</DockPanel>
</DockPanel>
<Button DockPanel.Dock="Bottom" ToolTip.Tip="Open editor" Margin="0 15 0 5" Command="{Binding OpenEditor}" HorizontalAlignment="Stretch">
Edit condition script
</Button>
</DockPanel>
<ContentControl Grid.Row="2" Content="{CompiledBinding ConditionViewModel}" />
</Grid>
</ScrollViewer>
</UserControl>
@@ -1,18 +1,17 @@
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition
{
public partial class DisplayConditionScriptView : ReactiveUserControl<DisplayConditionScriptViewModel>
{
public DisplayConditionScriptView()
{
InitializeComponent();
}
namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition;
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public class DisplayConditionScriptView : ReactiveUserControl<DisplayConditionScriptViewModel>
{
public DisplayConditionScriptView()
{
InitializeComponent();
}
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
@@ -1,13 +1,9 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.ObjectModel;
using System.Linq;
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;
using Artemis.UI.Shared.Services.ProfileEditor;
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
using Avalonia.Controls.Mixins;
@@ -17,81 +13,79 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition;
public class DisplayConditionScriptViewModel : ActivatableViewModelBase
{
private readonly ObservableAsPropertyHelper<ViewModelBase?> _conditionViewModel;
private readonly IConditionVmFactory _conditionVmFactory;
private readonly IProfileEditorService _profileEditorService;
private readonly ObservableAsPropertyHelper<bool> _showEventOptions;
private readonly ObservableAsPropertyHelper<bool> _showStaticOptions;
private readonly IWindowService _windowService;
private ObservableAsPropertyHelper<NodeScriptViewModel?>? _nodeScriptViewModel;
private RenderProfileElement? _profileElement;
private ObservableAsPropertyHelper<RenderProfileElement?>? _profileElement;
private ObservableAsPropertyHelper<ConditionTypeViewModel?>? _selectedConditionTypeViewModel;
public DisplayConditionScriptViewModel(IProfileEditorService profileEditorService, INodeVmFactory nodeVmFactory, IWindowService windowService)
public DisplayConditionScriptViewModel(IProfileEditorService profileEditorService, IConditionVmFactory conditionVmFactory)
{
_profileEditorService = profileEditorService;
_windowService = windowService;
_conditionVmFactory = conditionVmFactory;
ConditionTypeViewModels = new ObservableCollection<ConditionTypeViewModel>
{
new("None", "The element is always active.", null),
new("Regular", "The element is activated when the provided visual script ends in true.", typeof(StaticCondition)),
new("Event", "The element is activated when the selected event fires.\r\n" +
"Events that contain data can conditionally trigger the layer using a visual script.", typeof(EventCondition))
new("Always", "The element is always active.", typeof(AlwaysOnCondition)),
new("Once", "The element is shown once until its timeline is finished.", typeof(PlayOnceCondition)),
new("Conditional", "The element is activated when the provided visual script ends in true.", typeof(StaticCondition)),
new("On event", "The element is activated when the selected event fires.\r\n" +
"Events that contain data can conditionally trigger the layer using a visual script.", typeof(EventCondition))
};
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 INodeScriptCondition {NodeScript: NodeScript nodeScript} ? nodeVmFactory.NodeScriptViewModel(nodeScript, true) : null)
.ToProperty(this, vm => vm.NodeScriptViewModel)
.DisposeWith(d);
_profileElement = profileEditorService.ProfileElement.ToProperty(this, vm => vm.ProfileElement).DisposeWith(d);
_selectedConditionTypeViewModel = profileEditorService.ProfileElement
.Select(p => p?.WhenAnyValue(element => element.DisplayCondition) ?? Observable.Never<ICondition?>())
.Select(p => p?.WhenAnyValue(element => element.DisplayCondition) ?? Observable.Return<ICondition?>(null))
.Switch()
.Select(c => c != null ? ConditionTypeViewModels.FirstOrDefault(vm => vm.ConditionType == c.GetType()) : null)
.ToProperty(this, vm => vm.SelectedConditionTypeViewModel)
.DisposeWith(d);
});
_showStaticOptions = this.WhenAnyValue(vm => vm.SelectedConditionTypeViewModel)
.Select(c => c != null && c.ConditionType == typeof(StaticCondition))
.ToProperty(this, vm => vm.ShowStaticOptions);
_showEventOptions = this.WhenAnyValue(vm => vm.SelectedConditionTypeViewModel)
.Select(c => c != null && c.ConditionType == typeof(EventCondition))
.ToProperty(this, vm => vm.ShowEventOptions);
_conditionViewModel = this.WhenAnyValue(vm => vm.SelectedConditionTypeViewModel).Select(_ => CreateConditionViewModel()).ToProperty(this, vm => vm.ConditionViewModel);
}
public NodeScriptViewModel? NodeScriptViewModel => _nodeScriptViewModel?.Value;
public RenderProfileElement? ProfileElement => _profileElement?.Value;
public ViewModelBase? ConditionViewModel => _conditionViewModel.Value;
public ObservableCollection<ConditionTypeViewModel> ConditionTypeViewModels { get; }
public ConditionTypeViewModel? SelectedConditionTypeViewModel
{
get => _selectedConditionTypeViewModel?.Value;
set
{
if (_profileElement == null)
return;
ICondition? condition = null;
if (value?.ConditionType == typeof(StaticCondition))
condition = new StaticCondition(_profileElement);
else if (value?.ConditionType == typeof(EventCondition))
condition = new EventCondition(_profileElement);
_profileEditorService.ExecuteCommand(new ChangeConditionType(_profileElement, condition));
}
set => ApplyConditionType(value);
}
public bool ShowStaticOptions => _showStaticOptions.Value;
public bool ShowEventOptions => _showEventOptions.Value;
public async Task OpenEditor()
private ViewModelBase? CreateConditionViewModel()
{
if (_profileElement?.DisplayCondition is StaticCondition staticCondition)
await _windowService.ShowDialogAsync<NodeScriptWindowViewModel, bool>(("nodeScript", staticCondition.Script));
if (ProfileElement == null)
return null;
if (ProfileElement.DisplayCondition is AlwaysOnCondition alwaysOnCondition)
return _conditionVmFactory.AlwaysOnConditionViewModel(alwaysOnCondition);
if (ProfileElement.DisplayCondition is PlayOnceCondition playOnceCondition)
return _conditionVmFactory.PlayOnceConditionViewModel(playOnceCondition);
if (ProfileElement.DisplayCondition is StaticCondition staticCondition)
return _conditionVmFactory.StaticConditionViewModel(staticCondition);
if (ProfileElement.DisplayCondition is EventCondition eventCondition)
return _conditionVmFactory.EventConditionViewModel(eventCondition);
return null;
}
private void ApplyConditionType(ConditionTypeViewModel? value)
{
if (ProfileElement == null || value == null || ProfileElement.DisplayCondition.GetType() == value.ConditionType)
return;
if (value.ConditionType == typeof(AlwaysOnCondition))
_profileEditorService.ExecuteCommand(new ChangeConditionType(ProfileElement, new AlwaysOnCondition(ProfileElement)));
if (value.ConditionType == typeof(PlayOnceCondition))
_profileEditorService.ExecuteCommand(new ChangeConditionType(ProfileElement, new PlayOnceCondition(ProfileElement)));
if (value.ConditionType == typeof(StaticCondition))
_profileEditorService.ExecuteCommand(new ChangeConditionType(ProfileElement, new StaticCondition(ProfileElement)));
if (value.ConditionType == typeof(EventCondition))
_profileEditorService.ExecuteCommand(new ChangeConditionType(ProfileElement, new EventCondition(ProfileElement)));
}
}
@@ -46,13 +46,6 @@
Command="{Binding DisableSegment}">
<avalonia:MaterialIcon Kind="CloseCircle" />
</Button>
<ToggleButton Name="SegmentRepeat"
Classes="icon-button icon-button-small"
ToolTip.Tip="Repeat this segment"
IsChecked="{CompiledBinding RepeatSegment}"
Padding="0">
<avalonia:MaterialIcon Kind="Repeat" />
</ToggleButton>
</StackPanel>
<Button Name="AddEndSegment"
@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using Artemis.Core;
using Artemis.UI.Shared.Services.ProfileEditor;
@@ -13,12 +10,11 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
public class MainSegmentViewModel : TimelineSegmentViewModel
{
private RenderProfileElement? _profileElement;
private ObservableAsPropertyHelper<double>? _start;
private readonly ObservableAsPropertyHelper<double> _width;
private ObservableAsPropertyHelper<double>? _end;
private ObservableAsPropertyHelper<string?>? _endTimestamp;
private ObservableAsPropertyHelper<bool>? _repeatSegment;
private readonly ObservableAsPropertyHelper<double> _width;
private RenderProfileElement? _profileElement;
private ObservableAsPropertyHelper<double>? _start;
public MainSegmentViewModel(IProfileEditorService profileEditorService) : base(profileEditorService)
{
@@ -44,12 +40,6 @@ public class MainSegmentViewModel : TimelineSegmentViewModel
.Select(p => $"{Math.Floor(p.TotalSeconds):00}.{p.Milliseconds:000}")
.ToProperty(this, vm => vm.EndTimestamp)
.DisposeWith(d);
_repeatSegment = profileEditorService.ProfileElement
.Select(p => p?.WhenAnyValue(element => element.Timeline.PlayMode) ?? Observable.Never<TimelinePlayMode>())
.Switch()
.Select(p => p == TimelinePlayMode.Repeat)
.ToProperty(this, vm => vm.RepeatSegment)
.DisposeWith(d);
});
_width = this.WhenAnyValue(vm => vm.StartX, vm => vm.EndX).Select(t => t.Item2 - t.Item1).ToProperty(this, vm => vm.Width);
@@ -73,10 +63,4 @@ public class MainSegmentViewModel : TimelineSegmentViewModel
public override double Width => _width.Value;
public override string? EndTimestamp => _endTimestamp?.Value;
public override ResizeTimelineSegment.SegmentType Type => ResizeTimelineSegment.SegmentType.Main;
public bool RepeatSegment
{
get => _repeatSegment?.Value ?? false;
set => throw new NotImplementedException();
}
}