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 string _displayName;
|
||||||
private readonly EventConditionEntity _entity;
|
private readonly EventConditionEntity _entity;
|
||||||
private EventDefaultNode _eventNode;
|
private EventDefaultNode? _eventNode;
|
||||||
private TimeLineEventOverlapMode _eventOverlapMode;
|
private TimeLineEventOverlapMode _eventOverlapMode;
|
||||||
private DataModelPath? _eventPath;
|
private DataModelPath? _eventPath;
|
||||||
private DateTime _lastProcessedTrigger;
|
private DateTime _lastProcessedTrigger;
|
||||||
|
private NodeScript<bool>? _script;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="EventCondition" /> class
|
||||||
|
/// </summary>
|
||||||
public EventCondition(ProfileElement profileElement)
|
public EventCondition(ProfileElement profileElement)
|
||||||
{
|
{
|
||||||
_entity = new EventConditionEntity();
|
_entity = new EventConditionEntity();
|
||||||
_displayName = profileElement.GetType().Name;
|
_displayName = profileElement.GetType().Name;
|
||||||
|
|
||||||
ProfileElement = profileElement;
|
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)
|
internal EventCondition(EventConditionEntity entity, ProfileElement profileElement)
|
||||||
@ -36,18 +39,21 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the script that drives the event condition
|
/// Gets the script that drives the event condition
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NodeScript<bool> Script { get; private set; }
|
public NodeScript<bool>? Script
|
||||||
|
{
|
||||||
|
get => _script;
|
||||||
|
set => SetAndNotify(ref _script, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the path to the event that drives this event condition
|
/// Gets or sets the path to the event that drives this event condition
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DataModelPath? EventPath
|
public DataModelPath? EventPath
|
||||||
{
|
{
|
||||||
set => SetAndNotify(ref _eventPath, value);
|
|
||||||
get => _eventPath;
|
get => _eventPath;
|
||||||
|
set => SetAndNotify(ref _eventPath, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets how the condition behaves when events trigger before the timeline finishes
|
/// Gets or sets how the condition behaves when events trigger before the timeline finishes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -62,7 +68,7 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdateEventNode()
|
public void UpdateEventNode()
|
||||||
{
|
{
|
||||||
if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent)
|
if (Script == null || EventPath?.GetValue() is not IDataModelEvent dataModelEvent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Script.Nodes.FirstOrDefault(n => n is EventDefaultNode) is EventDefaultNode existing)
|
if (Script.Nodes.FirstOrDefault(n => n is EventDefaultNode) is EventDefaultNode existing)
|
||||||
@ -72,7 +78,7 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_eventNode = new EventDefaultNode();
|
_eventNode = new EventDefaultNode() {X = -300};
|
||||||
_eventNode.UpdateDataModelEvent(dataModelEvent);
|
_eventNode.UpdateDataModelEvent(dataModelEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,13 +88,24 @@ namespace Artemis.Core
|
|||||||
Script.RemoveNode(_eventNode);
|
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()
|
private bool Evaluate()
|
||||||
{
|
{
|
||||||
if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent || dataModelEvent.LastTrigger <= _lastProcessedTrigger)
|
if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent || dataModelEvent.LastTrigger <= _lastProcessedTrigger)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_lastProcessedTrigger = dataModelEvent.LastTrigger;
|
_lastProcessedTrigger = dataModelEvent.LastTrigger;
|
||||||
if (!Script.ExitNodeConnected)
|
|
||||||
|
if (Script == null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Script.Run();
|
Script.Run();
|
||||||
@ -149,7 +166,7 @@ namespace Artemis.Core
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Script.Dispose();
|
Script?.Dispose();
|
||||||
EventPath?.Dispose();
|
EventPath?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,16 +176,18 @@ namespace Artemis.Core
|
|||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
EventOverlapMode = (TimeLineEventOverlapMode) _entity.EventOverlapMode;
|
EventOverlapMode = (TimeLineEventOverlapMode) _entity.EventOverlapMode;
|
||||||
Script = new NodeScript<bool>($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", _entity.Script, ProfileElement.Profile);
|
if (_entity.Script != null)
|
||||||
EventPath = new DataModelPath(_entity.EventPath);
|
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 />
|
/// <inheritdoc />
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
_entity.EventOverlapMode = (int) EventOverlapMode;
|
_entity.EventOverlapMode = (int) EventOverlapMode;
|
||||||
Script.Save();
|
Script?.Save();
|
||||||
_entity.Script = Script.Entity;
|
_entity.Script = Script?.Entity;
|
||||||
EventPath?.Save();
|
EventPath?.Save();
|
||||||
_entity.EventPath = EventPath?.Entity;
|
_entity.EventPath = EventPath?.Entity;
|
||||||
}
|
}
|
||||||
@ -176,6 +195,9 @@ namespace Artemis.Core
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void LoadNodeScript()
|
public void LoadNodeScript()
|
||||||
{
|
{
|
||||||
|
if (Script == null)
|
||||||
|
return;
|
||||||
|
|
||||||
Script.Load();
|
Script.Load();
|
||||||
UpdateEventNode();
|
UpdateEventNode();
|
||||||
Script.LoadConnections();
|
Script.LoadConnections();
|
||||||
|
|||||||
@ -189,6 +189,18 @@ namespace Artemis.Core
|
|||||||
if (sourcePin.Direction == targetPin.Direction)
|
if (sourcePin.Direction == targetPin.Direction)
|
||||||
continue;
|
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)
|
// Only connect the nodes if they aren't already connected (LoadConnections may be called twice or more)
|
||||||
if (!targetPin.ConnectedTo.Contains(sourcePin))
|
if (!targetPin.ConnectedTo.Contains(sourcePin))
|
||||||
targetPin.ConnectTo(sourcePin);
|
targetPin.ConnectTo(sourcePin);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
".NETCoreApp,Version=v5.0": {
|
"net5.0-windows7.0": {
|
||||||
"Humanizer.Core": {
|
"Humanizer.Core": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[2.11.10, )",
|
"requested": "[2.11.10, )",
|
||||||
|
|||||||
@ -52,7 +52,7 @@
|
|||||||
</ToolTip>
|
</ToolTip>
|
||||||
</RadioButton.ToolTip>
|
</RadioButton.ToolTip>
|
||||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
<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
|
NONE
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
|
|||||||
@ -1,19 +1,21 @@
|
|||||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event.EventConditionView"
|
<UserControl
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls;assembly=Artemis.VisualScripting"
|
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls;assembly=Artemis.VisualScripting"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
||||||
xmlns:controls1="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d"
|
xmlns:Shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared" x:Class="Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event.EventConditionView"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
mc:Ignorable="d"
|
||||||
d:DataContext="{d:DesignInstance {x:Type local:EventConditionViewModel}}">
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
|
d:DataContext="{d:DesignInstance {x:Type local:EventConditionViewModel}}">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
|
<Shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||||
<converters:ComparisonConverter x:Key="ComparisonConverter" />
|
<converters:ComparisonConverter x:Key="ComparisonConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
@ -24,21 +26,39 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<Grid Grid.Row="0" VerticalAlignment="Stretch">
|
<Grid Grid.Row="0" VerticalAlignment="Stretch">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<controls1:DataModelPicker Grid.Row="0"
|
<shared:DataModelPicker Grid.Row="0"
|
||||||
Margin="0 0 0 5"
|
Grid.Column="0"
|
||||||
ButtonBrush="DarkGoldenrod"
|
Margin="0 0 0 5"
|
||||||
DataModelPath="{Binding EventCondition.EventPath}"
|
ButtonBrush="DarkGoldenrod"
|
||||||
DataModelPathSelected="{s:Action DataModelPathSelected}"
|
DataModelPath="{Binding EventCondition.EventPath}"
|
||||||
FilterTypes="{Binding FilterTypes}"
|
DataModelPathSelected="{s:Action DataModelPathSelected}"
|
||||||
ShowFullPath="True"
|
FilterTypes="{Binding FilterTypes}"
|
||||||
Modules="{Binding Modules}" />
|
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" />
|
<controls:VisualScriptPresenter Script="{Binding EventCondition.Script}" AutoFitScript="True" />
|
||||||
<Border VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
<Border VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||||
<Border.Background>
|
<Border.Background>
|
||||||
@ -66,19 +86,29 @@
|
|||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</Border.Style>
|
</Border.Style>
|
||||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" VerticalAlignment="Center" TextAlignment="Center">
|
||||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" VerticalAlignment="Center">
|
Click to edit script
|
||||||
Click to edit script
|
<materialDesign:PackIcon Kind="OpenInNew" Margin="0 0 0 -6 " Width="30" Height="30" VerticalAlignment="Center" />
|
||||||
</TextBlock>
|
</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>
|
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</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>
|
</Grid>
|
||||||
|
|
||||||
<!-- Trigger mode -->
|
<!-- Trigger mode -->
|
||||||
@ -86,7 +116,7 @@
|
|||||||
<TextBlock.ToolTip>
|
<TextBlock.ToolTip>
|
||||||
<ToolTip Placement="Center" VerticalOffset="-30">
|
<ToolTip Placement="Center" VerticalOffset="-30">
|
||||||
<TextBlock>
|
<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>
|
</TextBlock>
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
</TextBlock.ToolTip>
|
</TextBlock.ToolTip>
|
||||||
@ -102,63 +132,71 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<RadioButton Grid.Column="0"
|
<RadioButton Grid.Column="0"
|
||||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||||
IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Restart}}">
|
IsChecked="{Binding EventOverlapMode, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Restart}, Converter={StaticResource ComparisonConverter}}">
|
||||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
|
||||||
<materialDesign:PackIcon Kind="Repeat" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
|
||||||
RESTART
|
|
||||||
</TextBlock>
|
|
||||||
<RadioButton.ToolTip>
|
<RadioButton.ToolTip>
|
||||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||||
<TextBlock>
|
<TextBlock>
|
||||||
Stop the current run and restart the timeline
|
<Run Text="Stop the current run and restart the timeline" />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
</RadioButton.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>
|
||||||
<RadioButton Grid.Column="1"
|
<RadioButton Grid.Column="1"
|
||||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||||
IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Toggle}}">
|
IsChecked="{Binding EventOverlapMode, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Toggle}, Converter={StaticResource ComparisonConverter}}">
|
||||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
|
||||||
<materialDesign:PackIcon Kind="TrafficLight" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
|
||||||
TOGGLE
|
|
||||||
</TextBlock>
|
|
||||||
<RadioButton.ToolTip>
|
<RadioButton.ToolTip>
|
||||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||||
<TextBlock>
|
<TextBlock>
|
||||||
Repeat the timeline until the event fires again
|
<Run Text="Repeat the timeline until the event fires again" />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
</RadioButton.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>
|
||||||
<RadioButton Grid.Column="2"
|
<RadioButton Grid.Column="2"
|
||||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||||
IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Ignore}}">
|
IsChecked="{Binding EventOverlapMode, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Ignore}, Converter={StaticResource ComparisonConverter}}">
|
||||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
|
||||||
<materialDesign:PackIcon Kind="EarHearingOff" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
|
||||||
IGNORE
|
|
||||||
</TextBlock>
|
|
||||||
<RadioButton.ToolTip>
|
<RadioButton.ToolTip>
|
||||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||||
<TextBlock>
|
<TextBlock>
|
||||||
Ignore subsequent event fires until the timeline finishes
|
<Run Text="Ignore subsequent event fires until the timeline finishes" />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
</RadioButton.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>
|
||||||
<RadioButton Grid.Column="3"
|
<RadioButton Grid.Column="3"
|
||||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||||
IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Copy}}">
|
IsChecked="{Binding EventOverlapMode, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Copy}, Converter={StaticResource ComparisonConverter}}">
|
||||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
|
||||||
<materialDesign:PackIcon Kind="ContentCopy" VerticalAlignment="Center" Margin="-3 0 0 -3" />
|
|
||||||
COPY
|
|
||||||
</TextBlock>
|
|
||||||
<RadioButton.ToolTip>
|
<RadioButton.ToolTip>
|
||||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||||
<TextBlock>
|
<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>
|
</TextBlock>
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
</RadioButton.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>
|
</RadioButton>
|
||||||
</Grid>
|
</Grid>
|
||||||
</materialDesign:ColorZone>
|
</materialDesign:ColorZone>
|
||||||
|
|||||||
@ -12,9 +12,10 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event
|
|||||||
{
|
{
|
||||||
public class EventConditionViewModel : Screen
|
public class EventConditionViewModel : Screen
|
||||||
{
|
{
|
||||||
|
private readonly INodeVmFactory _nodeVmFactory;
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly IWindowManager _windowManager;
|
private readonly IWindowManager _windowManager;
|
||||||
private readonly INodeVmFactory _nodeVmFactory;
|
private NodeScript<bool> _oldScript;
|
||||||
|
|
||||||
public EventConditionViewModel(EventCondition eventCondition, IProfileEditorService profileEditorService, IWindowManager windowManager, INodeVmFactory nodeVmFactory)
|
public EventConditionViewModel(EventCondition eventCondition, IProfileEditorService profileEditorService, IWindowManager windowManager, INodeVmFactory nodeVmFactory)
|
||||||
{
|
{
|
||||||
@ -22,6 +23,10 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event
|
|||||||
_windowManager = windowManager;
|
_windowManager = windowManager;
|
||||||
_nodeVmFactory = nodeVmFactory;
|
_nodeVmFactory = nodeVmFactory;
|
||||||
EventCondition = eventCondition;
|
EventCondition = eventCondition;
|
||||||
|
|
||||||
|
FilterTypes = new BindableCollection<Type> {typeof(IDataModelEvent)};
|
||||||
|
if (_profileEditorService.SelectedProfileConfiguration?.Module != null)
|
||||||
|
Modules = new BindableCollection<Module> {_profileEditorService.SelectedProfileConfiguration.Module};
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventCondition EventCondition { get; }
|
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)
|
public void DataModelPathSelected(object sender, DataModelSelectedEventArgs e)
|
||||||
{
|
{
|
||||||
EventCondition.UpdateEventNode();
|
EventCondition.UpdateEventNode();
|
||||||
|
|||||||
@ -49,17 +49,10 @@
|
|||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</Border.Style>
|
</Border.Style>
|
||||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" VerticalAlignment="Center" TextAlignment="Center">
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
Click to edit script
|
||||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" VerticalAlignment="Center">
|
<materialDesign:PackIcon Kind="OpenInNew" Margin="0 0 0 -6 " Width="30" Height="30" VerticalAlignment="Center" />
|
||||||
Click to edit script
|
</TextBlock>
|
||||||
</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>
|
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid Grid.Row="1">
|
<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(bool), new SKColor(0xFFCD3232));
|
||||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(string), new SKColor(0xFFFFD700));
|
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(string), new SKColor(0xFFFFD700));
|
||||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(int), new SKColor(0xFF32CD32));
|
_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(float), new SKColor(0xFFFF7C00));
|
||||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(SKColor), new SKColor(0xFFAD3EED));
|
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(SKColor), new SKColor(0xFFAD3EED));
|
||||||
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(IList), new SKColor(0xFFED3E61));
|
_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))
|
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);
|
_nodeService.RegisterNodeType(Constants.CorePlugin, nodeType);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
".NETCoreApp,Version=v5.0": {
|
"net5.0-windows10.0.17763": {
|
||||||
"FluentValidation": {
|
"FluentValidation": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[10.3.0, )",
|
"requested": "[10.3.0, )",
|
||||||
|
|||||||
@ -114,8 +114,8 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
return nameContains;
|
return nameContains;
|
||||||
|
|
||||||
if (SourcePin.Pin.Direction == PinDirection.Input)
|
if (SourcePin.Pin.Direction == PinDirection.Input)
|
||||||
return nameContains && (nodeData.OutputType == typeof(object) || nodeData.OutputType == SourcePin.Pin.Type);
|
return nodeData.OutputType != null && nameContains && (nodeData.OutputType == typeof(object) || nodeData.OutputType.IsAssignableTo(SourcePin.Pin.Type));
|
||||||
return nameContains && (nodeData.InputType == typeof(object) || nodeData.InputType == SourcePin.Pin.Type);
|
return nodeData.InputType != null && nameContains && (nodeData.InputType == typeof(object) || nodeData.InputType.IsAssignableFrom(SourcePin.Pin.Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ItemsSourceChanged()
|
private void ItemsSourceChanged()
|
||||||
|
|||||||
@ -190,6 +190,7 @@ namespace Artemis.VisualScripting.Editor.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool IsTypeCompatible(Type type) => (Pin.Pin.Type == type)
|
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.Input) && (Pin.Pin.Type == typeof(object)))
|
||||||
|| ((Pin.Pin.Direction == PinDirection.Output) && (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
|
// Connect to the first matching input or output pin
|
||||||
List<IPin> pins = node.Pins.ToList();
|
List<IPin> pins = node.Pins.ToList();
|
||||||
pins.AddRange(node.PinCollections.SelectMany(c => c));
|
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
|
IPin preferredPin = SourcePin.Pin.Direction == PinDirection.Input
|
||||||
? pins.FirstOrDefault(p => p.Direction == PinDirection.Output)
|
? 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,
|
"version": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
".NETCoreApp,Version=v5.0": {
|
"net5.0-windows7.0": {
|
||||||
"JetBrains.Annotations": {
|
"JetBrains.Annotations": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[2021.1.0, )",
|
"requested": "[2021.1.0, )",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user