mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Nodes - Added enum equality node
Conditions - Implemented event trigger conditions
This commit is contained in:
parent
00125d1478
commit
d6372dffad
@ -10,18 +10,21 @@ namespace Artemis.Core
|
||||
{
|
||||
private readonly string _displayName;
|
||||
private readonly EventConditionEntity _entity;
|
||||
private EventDefaultNode _eventNode;
|
||||
private EventDefaultNode? _eventNode;
|
||||
private TimeLineEventOverlapMode _eventOverlapMode;
|
||||
private DataModelPath? _eventPath;
|
||||
private DateTime _lastProcessedTrigger;
|
||||
private NodeScript<bool>? _script;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="EventCondition" /> class
|
||||
/// </summary>
|
||||
public EventCondition(ProfileElement profileElement)
|
||||
{
|
||||
_entity = new EventConditionEntity();
|
||||
_displayName = profileElement.GetType().Name;
|
||||
|
||||
ProfileElement = profileElement;
|
||||
Script = new NodeScript<bool>($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", profileElement.Profile);
|
||||
}
|
||||
|
||||
internal EventCondition(EventConditionEntity entity, ProfileElement profileElement)
|
||||
@ -36,18 +39,21 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets the script that drives the event condition
|
||||
/// </summary>
|
||||
public NodeScript<bool> Script { get; private set; }
|
||||
public NodeScript<bool>? Script
|
||||
{
|
||||
get => _script;
|
||||
set => SetAndNotify(ref _script, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the event that drives this event condition
|
||||
/// </summary>
|
||||
public DataModelPath? EventPath
|
||||
{
|
||||
set => SetAndNotify(ref _eventPath, value);
|
||||
get => _eventPath;
|
||||
set => SetAndNotify(ref _eventPath, value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how the condition behaves when events trigger before the timeline finishes
|
||||
/// </summary>
|
||||
@ -62,7 +68,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public void UpdateEventNode()
|
||||
{
|
||||
if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent)
|
||||
if (Script == null || EventPath?.GetValue() is not IDataModelEvent dataModelEvent)
|
||||
return;
|
||||
|
||||
if (Script.Nodes.FirstOrDefault(n => n is EventDefaultNode) is EventDefaultNode existing)
|
||||
@ -72,7 +78,7 @@ namespace Artemis.Core
|
||||
}
|
||||
else
|
||||
{
|
||||
_eventNode = new EventDefaultNode();
|
||||
_eventNode = new EventDefaultNode() {X = -300};
|
||||
_eventNode.UpdateDataModelEvent(dataModelEvent);
|
||||
}
|
||||
|
||||
@ -82,13 +88,24 @@ namespace Artemis.Core
|
||||
Script.RemoveNode(_eventNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the <see cref="Script" /> with a new empty node script
|
||||
/// </summary>
|
||||
public void CreateEmptyNodeScript()
|
||||
{
|
||||
Script?.Dispose();
|
||||
Script = new NodeScript<bool>($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", ProfileElement.Profile);
|
||||
UpdateEventNode();
|
||||
}
|
||||
|
||||
private bool Evaluate()
|
||||
{
|
||||
if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent || dataModelEvent.LastTrigger <= _lastProcessedTrigger)
|
||||
return false;
|
||||
|
||||
_lastProcessedTrigger = dataModelEvent.LastTrigger;
|
||||
if (!Script.ExitNodeConnected)
|
||||
|
||||
if (Script == null)
|
||||
return true;
|
||||
|
||||
Script.Run();
|
||||
@ -149,7 +166,7 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
Script.Dispose();
|
||||
Script?.Dispose();
|
||||
EventPath?.Dispose();
|
||||
}
|
||||
|
||||
@ -159,16 +176,18 @@ namespace Artemis.Core
|
||||
public void Load()
|
||||
{
|
||||
EventOverlapMode = (TimeLineEventOverlapMode) _entity.EventOverlapMode;
|
||||
Script = new NodeScript<bool>($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", _entity.Script, ProfileElement.Profile);
|
||||
EventPath = new DataModelPath(_entity.EventPath);
|
||||
if (_entity.Script != null)
|
||||
Script = new NodeScript<bool>($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", _entity.Script, ProfileElement.Profile);
|
||||
if (_entity.EventPath != null)
|
||||
EventPath = new DataModelPath(_entity.EventPath);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Save()
|
||||
{
|
||||
_entity.EventOverlapMode = (int) EventOverlapMode;
|
||||
Script.Save();
|
||||
_entity.Script = Script.Entity;
|
||||
Script?.Save();
|
||||
_entity.Script = Script?.Entity;
|
||||
EventPath?.Save();
|
||||
_entity.EventPath = EventPath?.Entity;
|
||||
}
|
||||
@ -176,6 +195,9 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
public void LoadNodeScript()
|
||||
{
|
||||
if (Script == null)
|
||||
return;
|
||||
|
||||
Script.Load();
|
||||
UpdateEventNode();
|
||||
Script.LoadConnections();
|
||||
|
||||
@ -189,6 +189,18 @@ namespace Artemis.Core
|
||||
if (sourcePin.Direction == targetPin.Direction)
|
||||
continue;
|
||||
|
||||
// Clear existing connections on input pins, we don't want none of that now
|
||||
if (targetPin.Direction == PinDirection.Input)
|
||||
{
|
||||
while (targetPin.ConnectedTo.Any())
|
||||
targetPin.DisconnectFrom(targetPin.ConnectedTo[0]);
|
||||
}
|
||||
if (sourcePin.Direction == PinDirection.Input)
|
||||
{
|
||||
while (sourcePin.ConnectedTo.Any())
|
||||
sourcePin.DisconnectFrom(sourcePin.ConnectedTo[0]);
|
||||
}
|
||||
|
||||
// Only connect the nodes if they aren't already connected (LoadConnections may be called twice or more)
|
||||
if (!targetPin.ConnectedTo.Contains(sourcePin))
|
||||
targetPin.ConnectTo(sourcePin);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
".NETCoreApp,Version=v5.0": {
|
||||
"net5.0-windows7.0": {
|
||||
"Humanizer.Core": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.11.10, )",
|
||||
|
||||
@ -52,7 +52,7 @@
|
||||
</ToolTip>
|
||||
</RadioButton.ToolTip>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<materialDesign:PackIcon Kind="Close" VerticalAlignment="Center" Margin="0 0 2 -3" />
|
||||
<materialDesign:PackIcon Kind="No" VerticalAlignment="Center" Margin="0 0 2 -3" />
|
||||
NONE
|
||||
</TextBlock>
|
||||
</RadioButton>
|
||||
|
||||
@ -1,19 +1,21 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event.EventConditionView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls;assembly=Artemis.VisualScripting"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
||||
xmlns:controls1="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type local:EventConditionViewModel}}">
|
||||
<UserControl
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls;assembly=Artemis.VisualScripting"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||
xmlns:Shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared" x:Class="Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event.EventConditionView"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type local:EventConditionViewModel}}">
|
||||
<UserControl.Resources>
|
||||
<Shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<converters:ComparisonConverter x:Key="ComparisonConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
@ -24,21 +26,39 @@
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0" VerticalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<controls1:DataModelPicker Grid.Row="0"
|
||||
Margin="0 0 0 5"
|
||||
ButtonBrush="DarkGoldenrod"
|
||||
DataModelPath="{Binding EventCondition.EventPath}"
|
||||
DataModelPathSelected="{s:Action DataModelPathSelected}"
|
||||
FilterTypes="{Binding FilterTypes}"
|
||||
ShowFullPath="True"
|
||||
Modules="{Binding Modules}" />
|
||||
<shared:DataModelPicker Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="0 0 0 5"
|
||||
ButtonBrush="DarkGoldenrod"
|
||||
DataModelPath="{Binding EventCondition.EventPath}"
|
||||
DataModelPathSelected="{s:Action DataModelPathSelected}"
|
||||
FilterTypes="{Binding FilterTypes}"
|
||||
ShowFullPath="True"
|
||||
Modules="{Binding Modules}" />
|
||||
|
||||
<Grid Grid.Row="1" MouseUp="{s:Action ScriptGridMouseUp}" Cursor="Hand">
|
||||
<CheckBox Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
IsChecked="{Binding TriggerConditionally}"
|
||||
Content="Conditional trigger"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip="When enabled, the layer will only trigger if the script evaluates to true"
|
||||
Style="{StaticResource MaterialDesignDarkCheckBox}" />
|
||||
|
||||
<Grid Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
MouseUp="{s:Action ScriptGridMouseUp}"
|
||||
Cursor="Hand"
|
||||
Visibility="{Binding EventCondition.Script, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Normal, Mode=OneWay}">
|
||||
<controls:VisualScriptPresenter Script="{Binding EventCondition.Script}" AutoFitScript="True" />
|
||||
<Border VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
<Border.Background>
|
||||
@ -66,19 +86,29 @@
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" VerticalAlignment="Center">
|
||||
Click to edit script
|
||||
</TextBlock>
|
||||
<materialDesign:PackIcon Kind="OpenInNew" Margin="10 " Width="30" Height="30" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" TextWrapping="Wrap" TextAlignment="Center">
|
||||
Scripts with nothing connected to their end-node are always true.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" VerticalAlignment="Center" TextAlignment="Center">
|
||||
Click to edit script
|
||||
<materialDesign:PackIcon Kind="OpenInNew" Margin="0 0 0 -6 " Width="30" Height="30" VerticalAlignment="Center" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Visibility="{Binding EventCondition.Script, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted, Mode=OneWay}">
|
||||
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" TextWrapping="Wrap" TextAlignment="Center" Margin="0 10">
|
||||
Conditional trigger disabled
|
||||
<materialDesign:PackIcon Kind="No" Margin="0 0 0 -6" Width="30" Height="30" VerticalAlignment="Center" />
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" TextWrapping="Wrap" TextAlignment="Center">
|
||||
When enabled, the layer will only trigger if the script evaluates to true
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Trigger mode -->
|
||||
@ -86,7 +116,7 @@
|
||||
<TextBlock.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-30">
|
||||
<TextBlock>
|
||||
Configure how the layer should act when the event(s) trigger
|
||||
<Run Text="Configure how the layer should act when the event(s) trigger" />
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</TextBlock.ToolTip>
|
||||
@ -102,63 +132,71 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Grid.Column="0"
|
||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||
IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Restart}}">
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<materialDesign:PackIcon Kind="Repeat" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
||||
RESTART
|
||||
</TextBlock>
|
||||
IsChecked="{Binding EventOverlapMode, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Restart}, Converter={StaticResource ComparisonConverter}}">
|
||||
<RadioButton.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||
<TextBlock>
|
||||
Stop the current run and restart the timeline
|
||||
<Run Text="Stop the current run and restart the timeline" />
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</RadioButton.ToolTip>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<InlineUIContainer>
|
||||
<materialDesign:PackIcon Kind="Repeat" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
||||
</InlineUIContainer>
|
||||
<Run Text=" RESTART" />
|
||||
</TextBlock>
|
||||
</RadioButton>
|
||||
<RadioButton Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||
IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Toggle}}">
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<materialDesign:PackIcon Kind="TrafficLight" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
||||
TOGGLE
|
||||
</TextBlock>
|
||||
IsChecked="{Binding EventOverlapMode, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Toggle}, Converter={StaticResource ComparisonConverter}}">
|
||||
<RadioButton.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||
<TextBlock>
|
||||
Repeat the timeline until the event fires again
|
||||
<Run Text="Repeat the timeline until the event fires again" />
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</RadioButton.ToolTip>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<InlineUIContainer>
|
||||
<materialDesign:PackIcon Kind="TrafficLight" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
||||
</InlineUIContainer>
|
||||
<Run Text=" TOGGLE" />
|
||||
</TextBlock>
|
||||
</RadioButton>
|
||||
<RadioButton Grid.Column="2"
|
||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||
IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Ignore}}">
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<materialDesign:PackIcon Kind="EarHearingOff" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
||||
IGNORE
|
||||
</TextBlock>
|
||||
IsChecked="{Binding EventOverlapMode, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Ignore}, Converter={StaticResource ComparisonConverter}}">
|
||||
<RadioButton.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||
<TextBlock>
|
||||
Ignore subsequent event fires until the timeline finishes
|
||||
<Run Text="Ignore subsequent event fires until the timeline finishes" />
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</RadioButton.ToolTip>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<InlineUIContainer>
|
||||
<materialDesign:PackIcon Kind="EarHearingOff" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
||||
</InlineUIContainer>
|
||||
<Run Text=" IGNORE" />
|
||||
</TextBlock>
|
||||
</RadioButton>
|
||||
<RadioButton Grid.Column="3"
|
||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||
IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Copy}}">
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<materialDesign:PackIcon Kind="ContentCopy" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
||||
COPY
|
||||
</TextBlock>
|
||||
IsChecked="{Binding EventOverlapMode, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Copy}, Converter={StaticResource ComparisonConverter}}">
|
||||
<RadioButton.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||
<TextBlock>
|
||||
Play another copy of the timeline on top of the current run
|
||||
<Run Text="Play another copy of the timeline on top of the current run" />
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</RadioButton.ToolTip>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<InlineUIContainer>
|
||||
<materialDesign:PackIcon Kind="ContentCopy" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
||||
</InlineUIContainer>
|
||||
<Run Text=" COPY" />
|
||||
</TextBlock>
|
||||
</RadioButton>
|
||||
</Grid>
|
||||
</materialDesign:ColorZone>
|
||||
|
||||
@ -12,9 +12,10 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event
|
||||
{
|
||||
public class EventConditionViewModel : Screen
|
||||
{
|
||||
private readonly INodeVmFactory _nodeVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly IWindowManager _windowManager;
|
||||
private readonly INodeVmFactory _nodeVmFactory;
|
||||
private NodeScript<bool> _oldScript;
|
||||
|
||||
public EventConditionViewModel(EventCondition eventCondition, IProfileEditorService profileEditorService, IWindowManager windowManager, INodeVmFactory nodeVmFactory)
|
||||
{
|
||||
@ -22,6 +23,10 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event
|
||||
_windowManager = windowManager;
|
||||
_nodeVmFactory = nodeVmFactory;
|
||||
EventCondition = eventCondition;
|
||||
|
||||
FilterTypes = new BindableCollection<Type> {typeof(IDataModelEvent)};
|
||||
if (_profileEditorService.SelectedProfileConfiguration?.Module != null)
|
||||
Modules = new BindableCollection<Module> {_profileEditorService.SelectedProfileConfiguration.Module};
|
||||
}
|
||||
|
||||
public EventCondition EventCondition { get; }
|
||||
@ -39,6 +44,42 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event
|
||||
}
|
||||
}
|
||||
|
||||
public bool TriggerConditionally
|
||||
{
|
||||
get => EventCondition.Script != null;
|
||||
set
|
||||
{
|
||||
if (EventCondition.Script != null)
|
||||
{
|
||||
_oldScript = EventCondition.Script;
|
||||
EventCondition.Script = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_oldScript != null)
|
||||
{
|
||||
EventCondition.Script = _oldScript;
|
||||
_oldScript = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
EventCondition.CreateEmptyNodeScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
_oldScript?.Dispose();
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void DataModelPathSelected(object sender, DataModelSelectedEventArgs e)
|
||||
{
|
||||
EventCondition.UpdateEventNode();
|
||||
|
||||
@ -49,17 +49,10 @@
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" VerticalAlignment="Center">
|
||||
Click to edit script
|
||||
</TextBlock>
|
||||
<materialDesign:PackIcon Kind="OpenInNew" Margin="10 " Width="30" Height="30" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" TextWrapping="Wrap" TextAlignment="Center">
|
||||
Scripts with nothing connected to their end-node are always true.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" VerticalAlignment="Center" TextAlignment="Center">
|
||||
Click to edit script
|
||||
<materialDesign:PackIcon Kind="OpenInNew" Margin="0 0 0 -6 " Width="30" Height="30" VerticalAlignment="Center" />
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</Grid>
|
||||
<Grid Grid.Row="1">
|
||||
|
||||
@ -124,10 +124,10 @@ namespace Artemis.UI.Services
|
||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(bool), new SKColor(0xFFCD3232));
|
||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(string), new SKColor(0xFFFFD700));
|
||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(int), new SKColor(0xFF32CD32));
|
||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(double), new SKColor(0xFF1E90FF));
|
||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(float), new SKColor(0xFFFF7C00));
|
||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(SKColor), new SKColor(0xFFAD3EED));
|
||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(IList), new SKColor(0xFFED3E61));
|
||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(Enum), new SKColor(0xFF1E90FF));
|
||||
|
||||
foreach (Type nodeType in typeof(SumIntegersNode).Assembly.GetTypes().Where(t => typeof(INode).IsAssignableFrom(t) && t.IsPublic && !t.IsAbstract && !t.IsInterface))
|
||||
_nodeService.RegisterNodeType(Constants.CorePlugin, nodeType);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
".NETCoreApp,Version=v5.0": {
|
||||
"net5.0-windows10.0.17763": {
|
||||
"FluentValidation": {
|
||||
"type": "Direct",
|
||||
"requested": "[10.3.0, )",
|
||||
|
||||
@ -114,8 +114,8 @@ namespace Artemis.VisualScripting.Editor.Controls
|
||||
return nameContains;
|
||||
|
||||
if (SourcePin.Pin.Direction == PinDirection.Input)
|
||||
return nameContains && (nodeData.OutputType == typeof(object) || nodeData.OutputType == SourcePin.Pin.Type);
|
||||
return nameContains && (nodeData.InputType == typeof(object) || nodeData.InputType == SourcePin.Pin.Type);
|
||||
return nodeData.OutputType != null && nameContains && (nodeData.OutputType == typeof(object) || nodeData.OutputType.IsAssignableTo(SourcePin.Pin.Type));
|
||||
return nodeData.InputType != null && nameContains && (nodeData.InputType == typeof(object) || nodeData.InputType.IsAssignableFrom(SourcePin.Pin.Type));
|
||||
}
|
||||
|
||||
private void ItemsSourceChanged()
|
||||
|
||||
@ -190,6 +190,7 @@ namespace Artemis.VisualScripting.Editor.Controls
|
||||
}
|
||||
|
||||
private bool IsTypeCompatible(Type type) => (Pin.Pin.Type == type)
|
||||
|| (Pin.Pin.Type == typeof(Enum) && type.IsEnum)
|
||||
|| ((Pin.Pin.Direction == PinDirection.Input) && (Pin.Pin.Type == typeof(object)))
|
||||
|| ((Pin.Pin.Direction == PinDirection.Output) && (type == typeof(object)));
|
||||
|
||||
|
||||
@ -537,7 +537,7 @@ namespace Artemis.VisualScripting.Editor.Controls
|
||||
// Connect to the first matching input or output pin
|
||||
List<IPin> pins = node.Pins.ToList();
|
||||
pins.AddRange(node.PinCollections.SelectMany(c => c));
|
||||
pins = pins.Where(p => p.Type == typeof(object) || p.Type == SourcePin.Pin.Type).OrderBy(p => p.Type != typeof(object)).ToList();
|
||||
pins = pins.Where(p => p.Type == typeof(object) || p.Type.IsAssignableFrom(SourcePin.Pin.Type)).OrderBy(p => p.Type != typeof(object)).ToList();
|
||||
|
||||
IPin preferredPin = SourcePin.Pin.Direction == PinDirection.Input
|
||||
? pins.FirstOrDefault(p => p.Direction == PinDirection.Output)
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.UI.Shared;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.CustomViewModels
|
||||
{
|
||||
public class EnumEqualsNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
private readonly EnumEqualsNode _node;
|
||||
|
||||
public EnumEqualsNodeCustomViewModel(EnumEqualsNode node) : base(node)
|
||||
{
|
||||
_node = node;
|
||||
}
|
||||
|
||||
public Enum Input
|
||||
{
|
||||
get => _node.Storage as Enum;
|
||||
set => _node.Storage = value;
|
||||
}
|
||||
|
||||
public BindableCollection<ValueDescription> EnumValues { get; } = new();
|
||||
|
||||
public override void OnActivate()
|
||||
{
|
||||
_node.InputPin.PinConnected += InputPinOnPinConnected;
|
||||
_node.InputPin.PinDisconnected += InputPinOnPinDisconnected;
|
||||
_node.PropertyChanged += NodeOnPropertyChanged;
|
||||
|
||||
if (_node.InputPin.Value != null && _node.InputPin.Value.GetType().IsEnum)
|
||||
EnumValues.AddRange(EnumUtilities.GetAllValuesAndDescriptions(_node.InputPin.Value.GetType()));
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
public override void OnDeactivate()
|
||||
{
|
||||
_node.InputPin.PinConnected -= InputPinOnPinConnected;
|
||||
_node.InputPin.PinDisconnected -= InputPinOnPinDisconnected;
|
||||
_node.PropertyChanged -= NodeOnPropertyChanged;
|
||||
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
private void InputPinOnPinDisconnected(object sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
EnumValues.Clear();
|
||||
}
|
||||
|
||||
private void InputPinOnPinConnected(object sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
EnumValues.Clear();
|
||||
if (_node.InputPin.Value != null && _node.InputPin.Value.GetType().IsEnum)
|
||||
EnumValues.AddRange(EnumUtilities.GetAllValuesAndDescriptions(_node.InputPin.Value.GetType()));
|
||||
}
|
||||
|
||||
private void NodeOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(Node.Storage))
|
||||
OnPropertyChanged(nameof(Input));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
<UserControl x:Class="Artemis.VisualScripting.Nodes.CustomViews.EnumEqualsNodeCustomView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.VisualScripting.Nodes.CustomViews"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<ComboBox Width="140"
|
||||
materialDesign:ComboBoxAssist.ClassicMode="True"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch"
|
||||
SelectedValue="{Binding Input}"
|
||||
ItemsSource="{Binding EnumValues}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description">
|
||||
<ComboBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ComboBox.ItemsPanel>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
30
src/Artemis.VisualScripting/Nodes/EnumEqualsNode.cs
Normal file
30
src/Artemis.VisualScripting/Nodes/EnumEqualsNode.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes
|
||||
{
|
||||
[Node("Enum Equals", "Determines the equality between an input and a selected enum value", InputType = typeof(Enum), OutputType = typeof(bool))]
|
||||
public class EnumEqualsNode : Node<EnumEqualsNodeCustomViewModel>
|
||||
{
|
||||
public EnumEqualsNode() : base("Enum Equals", "Determines the equality between an input and a selected enum value")
|
||||
{
|
||||
InputPin = CreateInputPin<Enum>();
|
||||
OutputPin = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
public InputPin<Enum> InputPin { get; }
|
||||
public OutputPin<bool> OutputPin { get; }
|
||||
|
||||
#region Overrides of Node
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Evaluate()
|
||||
{
|
||||
OutputPin.Value = InputPin.Value != null && InputPin.Value.Equals(Storage);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
".NETCoreApp,Version=v5.0": {
|
||||
"net5.0-windows7.0": {
|
||||
"JetBrains.Annotations": {
|
||||
"type": "Direct",
|
||||
"requested": "[2021.1.0, )",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user