mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 11:56:30 +00:00
Profile editor - Moved files
This commit is contained in:
1 parent
f359256ede
commit
75e2fb1689
86 files changed
+199
-215
No files matched your search
+50
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using Artemis.Core.Models.Profile.Conditions.Abstract;
|
||||
using Artemis.UI.Shared.DataModelVisualization.Shared;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions.Abstract
|
||||
{
|
||||
public abstract class DisplayConditionViewModel : PropertyChangedBase, IDisposable
|
||||
{
|
||||
protected DisplayConditionViewModel(DisplayConditionPart model, DisplayConditionViewModel parent)
|
||||
{
|
||||
Model = model;
|
||||
Parent = parent;
|
||||
Children = new BindableCollection<DisplayConditionViewModel>();
|
||||
}
|
||||
|
||||
public DisplayConditionPart Model { get; }
|
||||
public DisplayConditionViewModel Parent { get; set; }
|
||||
public BindableCollection<DisplayConditionViewModel> Children { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var child in Children)
|
||||
child.Dispose();
|
||||
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public abstract void Update();
|
||||
|
||||
public virtual DataModelPropertiesViewModel GetDataModelOverride()
|
||||
{
|
||||
return Parent?.GetDataModelOverride();
|
||||
}
|
||||
|
||||
public virtual void Delete()
|
||||
{
|
||||
Model.Parent.RemoveChild(Model);
|
||||
Parent.Update();
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.DisplayConditions.DisplayConditionGroupView"
|
||||
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"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance Type=local:DisplayConditionGroupViewModel, IsDesignTimeCreatable=False}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DisplayConditions.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
ToolTip="Delete the group and all its children"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
HorizontalAlignment="Left"
|
||||
Visibility="{Binding IsRootGroup, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"
|
||||
Width="25"
|
||||
Height="25"
|
||||
Foreground="#E74C4C"
|
||||
Command="{s:Action Delete}">
|
||||
<materialDesign:PackIcon Kind="Close" Width="18" Height="18" />
|
||||
</Button>
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
ToolTip="Change the operator of the group"
|
||||
Style="{StaticResource DisplayConditionButtonLeftClickMenu}"
|
||||
Background="#E74C4C"
|
||||
BorderBrush="#E74C4C"
|
||||
Margin="3 1"
|
||||
Content="{Binding SelectedBooleanOperator}"
|
||||
Visibility="{Binding DisplayBooleanOperator, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="And" Command="{s:Action SelectBooleanOperator}" CommandParameter="And" />
|
||||
<MenuItem Header="Or" Command="{s:Action SelectBooleanOperator}" CommandParameter="Or" />
|
||||
<MenuItem Header="And not" Command="{s:Action SelectBooleanOperator}" CommandParameter="AndNot" />
|
||||
<MenuItem Header="Or not" Command="{s:Action SelectBooleanOperator}" CommandParameter="OrNot" />
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
</Button>
|
||||
<Button x:Name="AddChildButton"
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
ToolTip="Add another condition to the current group"
|
||||
HorizontalAlignment="Left"
|
||||
Foreground="#4CE758"
|
||||
Width="25"
|
||||
Height="25">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignIconForegroundButton}">
|
||||
<Style.Triggers>
|
||||
<EventTrigger RoutedEvent="Click">
|
||||
<EventTrigger.Actions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
|
||||
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
|
||||
</BooleanAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger.Actions>
|
||||
</EventTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<materialDesign:PackIcon Kind="Add" Width="18" Height="18" />
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Add static condition"
|
||||
ToolTip="A condition that compares a data model property to a static input"
|
||||
Command="{s:Action AddCondition}"
|
||||
CommandParameter="Static">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="FormTextarea" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Add dynamic condition"
|
||||
ToolTip="A condition that compares two data model properties"
|
||||
Command="{s:Action AddCondition}"
|
||||
CommandParameter="Dynamic">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="InsertLink" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Add list condition"
|
||||
ToolTip="A condition that evaluates on items in a list"
|
||||
Command="{s:Action AddCondition}"
|
||||
CommandParameter="List">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="FormatListBulleted" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Add group" ToolTip="A group can contain conditions and other groups" Command="{s:Action AddGroup}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="CodeParentheses" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
</Button>
|
||||
|
||||
<ItemsControl Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" ItemsSource="{Binding Children}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<materialDesign:TransitioningContent>
|
||||
<materialDesign:TransitioningContent.OpeningEffects>
|
||||
<materialDesign:TransitionEffect Kind="FadeIn" />
|
||||
<materialDesign:TransitionEffect Kind="SlideInFromLeft" />
|
||||
</materialDesign:TransitioningContent.OpeningEffects>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||
</materialDesign:TransitioningContent>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Artemis.Core.Models.Profile.Conditions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.DisplayConditions.Abstract;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using Humanizer;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
{
|
||||
public class DisplayConditionGroupViewModel : DisplayConditionViewModel, IViewAware
|
||||
{
|
||||
private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private bool _isInitialized;
|
||||
private bool _isRootGroup;
|
||||
|
||||
public DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent,
|
||||
IProfileEditorService profileEditorService, IDisplayConditionsVmFactory displayConditionsVmFactory) : base(displayConditionGroup, parent)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_displayConditionsVmFactory = displayConditionsVmFactory;
|
||||
|
||||
Children.CollectionChanged += (sender, args) => NotifyOfPropertyChange(nameof(DisplayBooleanOperator));
|
||||
|
||||
Execute.PostToUIThread(async () =>
|
||||
{
|
||||
await Task.Delay(50);
|
||||
IsInitialized = true;
|
||||
});
|
||||
}
|
||||
|
||||
public DisplayConditionGroup DisplayConditionGroup => (DisplayConditionGroup) Model;
|
||||
|
||||
public bool IsRootGroup
|
||||
{
|
||||
get => _isRootGroup;
|
||||
set => SetAndNotify(ref _isRootGroup, value);
|
||||
}
|
||||
|
||||
public bool IsInitialized
|
||||
{
|
||||
get => _isInitialized;
|
||||
set => SetAndNotify(ref _isInitialized, value);
|
||||
}
|
||||
|
||||
public bool DisplayBooleanOperator => Children.Count > 1;
|
||||
public string SelectedBooleanOperator => DisplayConditionGroup.BooleanOperator.Humanize();
|
||||
|
||||
public void AttachView(UIElement view)
|
||||
{
|
||||
View = view;
|
||||
}
|
||||
|
||||
public UIElement View { get; set; }
|
||||
|
||||
public void SelectBooleanOperator(string type)
|
||||
{
|
||||
var enumValue = Enum.Parse<BooleanOperator>(type);
|
||||
DisplayConditionGroup.BooleanOperator = enumValue;
|
||||
NotifyOfPropertyChange(nameof(SelectedBooleanOperator));
|
||||
}
|
||||
|
||||
public void AddCondition(string type)
|
||||
{
|
||||
if (type == "Static")
|
||||
DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Static));
|
||||
else if (type == "Dynamic")
|
||||
DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Dynamic));
|
||||
else if (type == "List")
|
||||
DisplayConditionGroup.AddChild(new DisplayConditionList(DisplayConditionGroup));
|
||||
|
||||
Update();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void AddGroup()
|
||||
{
|
||||
DisplayConditionGroup.AddChild(new DisplayConditionGroup(DisplayConditionGroup));
|
||||
|
||||
Update();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(SelectedBooleanOperator));
|
||||
|
||||
// Remove VMs of effects no longer applied on the layer
|
||||
var toRemove = Children.Where(c => !DisplayConditionGroup.Children.Contains(c.Model)).ToList();
|
||||
// Using RemoveRange breaks our lovely animations
|
||||
foreach (var displayConditionViewModel in toRemove)
|
||||
{
|
||||
Children.Remove(displayConditionViewModel);
|
||||
displayConditionViewModel.Dispose();
|
||||
}
|
||||
|
||||
foreach (var childModel in Model.Children)
|
||||
{
|
||||
if (Children.Any(c => c.Model == childModel))
|
||||
continue;
|
||||
|
||||
switch (childModel)
|
||||
{
|
||||
case DisplayConditionGroup displayConditionGroup:
|
||||
Children.Add(_displayConditionsVmFactory.DisplayConditionGroupViewModel(displayConditionGroup, this));
|
||||
break;
|
||||
case DisplayConditionList displayConditionListPredicate:
|
||||
Children.Add(_displayConditionsVmFactory.DisplayConditionListViewModel(displayConditionListPredicate, this));
|
||||
break;
|
||||
case DisplayConditionPredicate displayConditionPredicate:
|
||||
Children.Add(_displayConditionsVmFactory.DisplayConditionPredicateViewModel(displayConditionPredicate, this));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var childViewModel in Children)
|
||||
childViewModel.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.DisplayConditions.DisplayConditionListView"
|
||||
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"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance Type=local:DisplayConditionListViewModel, IsDesignTimeCreatable=False}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DisplayConditions.xaml" />
|
||||
<ResourceDictionary>
|
||||
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
|
||||
<DataTemplate x:Key="DataModelDataTemplate">
|
||||
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource DataModelSelectionTemplate}" />
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding Data.ShowDataModelValues.Value, Source={StaticResource DataContextProxy}}" Value="True">
|
||||
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource DataModelSelectionTemplateWithValues}" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="0 3" Visibility="{Binding IsInitialized, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
ToolTip="Delete the list predicate and all its children"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
HorizontalAlignment="Left"
|
||||
Foreground="#E74C4C"
|
||||
Width="25"
|
||||
Height="25"
|
||||
Command="{s:Action Delete}">
|
||||
<materialDesign:PackIcon Kind="Close" Width="18" Height="18" />
|
||||
</Button>
|
||||
|
||||
<!-- Left side, the list this predicate is targeting -->
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Background="#ab47bc"
|
||||
BorderBrush="#ab47bc"
|
||||
Style="{StaticResource DisplayConditionButton}"
|
||||
ToolTip="{Binding SelectedListProperty.DisplayPropertyPath}"
|
||||
Click="PropertyButton_OnClick">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu ItemsSource="{Binding TargetDataModel.Children}" IsOpen="{Binding TargetDataModelOpen, Mode=OneWayToSource}">
|
||||
<ContextMenu.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
|
||||
<Setter Property="ItemsSource" Value="{Binding Children}" />
|
||||
<Setter Property="Command" Value="{Binding Data.SelectListPropertyCommand, Source={StaticResource DataContextProxy}}" />
|
||||
<Setter Property="CommandParameter" Value="{Binding}" />
|
||||
<Setter Property="CommandTarget" Value="{Binding}" />
|
||||
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
|
||||
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
|
||||
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelDataTemplate}" />
|
||||
</Style>
|
||||
</ContextMenu.ItemContainerStyle>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding SelectedListProperty.PropertyDescription.Name}"
|
||||
Visibility="{Binding SelectedListProperty, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
<TextBlock Text="« Select a list »"
|
||||
FontStyle="Italic"
|
||||
Visibility="{Binding SelectedListProperty, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<!-- Operator -->
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Style="{StaticResource DisplayConditionButtonLeftClickMenu}"
|
||||
Background="#7B7B7B"
|
||||
BorderBrush="#7B7B7B"
|
||||
Content="{Binding SelectedListOperator}"
|
||||
Click="PropertyButton_OnClick"
|
||||
HorizontalAlignment="Left">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Any" Command="{s:Action SelectListOperator}" CommandParameter="Any" />
|
||||
<MenuItem Header="All" Command="{s:Action SelectListOperator}" CommandParameter="All" />
|
||||
<MenuItem Header="None" Command="{s:Action SelectListOperator}" CommandParameter="None" />
|
||||
<MenuItem Header="Count (NYI)" Command="{s:Action SelectListOperator}" CommandParameter="Count" IsEnabled="False"/>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
</Button>
|
||||
|
||||
<ItemsControl Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" ItemsSource="{Binding Children}" Margin="0 4 0 0">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<materialDesign:TransitioningContent>
|
||||
<materialDesign:TransitioningContent.OpeningEffects>
|
||||
<materialDesign:TransitionEffect Kind="FadeIn" />
|
||||
<materialDesign:TransitionEffect Kind="SlideInFromLeft" />
|
||||
</materialDesign:TransitioningContent.OpeningEffects>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||
</materialDesign:TransitioningContent>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for DisplayConditionListView.xaml
|
||||
/// </summary>
|
||||
public partial class DisplayConditionListView : UserControl
|
||||
{
|
||||
public DisplayConditionListView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void PropertyButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// DataContext is not set when using left button, I don't know why but there it is
|
||||
if (sender is Button button && button.ContextMenu != null)
|
||||
{
|
||||
button.ContextMenu.DataContext = button.DataContext;
|
||||
button.ContextMenu.IsOpen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using Artemis.Core.Models.Profile.Conditions;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.DisplayConditions.Abstract;
|
||||
using Artemis.UI.Shared.DataModelVisualization.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using Artemis.UI.Utilities;
|
||||
using Humanizer;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
{
|
||||
public class DisplayConditionListViewModel : DisplayConditionViewModel
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly IDataModelVisualizationService _dataModelVisualizationService;
|
||||
private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory;
|
||||
private bool _isInitialized;
|
||||
private DataModelListViewModel _selectedListProperty;
|
||||
private DataModelPropertiesViewModel _targetDataModel;
|
||||
private readonly Timer _updateTimer;
|
||||
|
||||
public DisplayConditionListViewModel(
|
||||
DisplayConditionList displayConditionList,
|
||||
DisplayConditionViewModel parent,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelVisualizationService dataModelVisualizationService,
|
||||
IDisplayConditionsVmFactory displayConditionsVmFactory,
|
||||
ISettingsService settingsService) : base(displayConditionList, parent)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataModelVisualizationService = dataModelVisualizationService;
|
||||
_displayConditionsVmFactory = displayConditionsVmFactory;
|
||||
_updateTimer = new Timer(500);
|
||||
|
||||
SelectListPropertyCommand = new DelegateCommand(ExecuteSelectListProperty);
|
||||
|
||||
ShowDataModelValues = settingsService.GetSetting<bool>("ProfileEditor.ShowDataModelValues");
|
||||
|
||||
// Initialize async, no need to wait for it
|
||||
Task.Run(Initialize);
|
||||
}
|
||||
|
||||
public DelegateCommand SelectListPropertyCommand { get; }
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
|
||||
public DisplayConditionList DisplayConditionList => (DisplayConditionList) Model;
|
||||
|
||||
public bool IsInitialized
|
||||
{
|
||||
get => _isInitialized;
|
||||
set => SetAndNotify(ref _isInitialized, value);
|
||||
}
|
||||
|
||||
public bool TargetDataModelOpen { get; set; }
|
||||
|
||||
public DataModelPropertiesViewModel TargetDataModel
|
||||
{
|
||||
get => _targetDataModel;
|
||||
set => SetAndNotify(ref _targetDataModel, value);
|
||||
}
|
||||
|
||||
public DataModelListViewModel SelectedListProperty
|
||||
{
|
||||
get => _selectedListProperty;
|
||||
set => SetAndNotify(ref _selectedListProperty, value);
|
||||
}
|
||||
|
||||
public string SelectedListOperator => DisplayConditionList.ListOperator.Humanize();
|
||||
|
||||
public void SelectListOperator(string type)
|
||||
{
|
||||
var enumValue = Enum.Parse<ListOperator>(type);
|
||||
DisplayConditionList.ListOperator = enumValue;
|
||||
NotifyOfPropertyChange(nameof(SelectedListOperator));
|
||||
}
|
||||
|
||||
public void AddCondition(string type)
|
||||
{
|
||||
if (type == "Static")
|
||||
DisplayConditionList.AddChild(new DisplayConditionPredicate(DisplayConditionList, PredicateType.Static));
|
||||
else if (type == "Dynamic")
|
||||
DisplayConditionList.AddChild(new DisplayConditionPredicate(DisplayConditionList, PredicateType.Dynamic));
|
||||
|
||||
Update();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void AddGroup()
|
||||
{
|
||||
DisplayConditionList.AddChild(new DisplayConditionGroup(DisplayConditionList));
|
||||
|
||||
Update();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
base.Delete();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// Get the data models
|
||||
TargetDataModel = _dataModelVisualizationService.GetMainDataModelVisualization();
|
||||
if (!_dataModelVisualizationService.GetPluginExtendsDataModel(_profileEditorService.GetCurrentModule()))
|
||||
TargetDataModel.Children.Add(_dataModelVisualizationService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule()));
|
||||
|
||||
TargetDataModel.UpdateRequested += TargetDataModelUpdateRequested;
|
||||
|
||||
Update();
|
||||
|
||||
_updateTimer.Start();
|
||||
_updateTimer.Elapsed += OnUpdateTimerOnElapsed;
|
||||
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_updateTimer.Stop();
|
||||
_updateTimer.Elapsed -= OnUpdateTimerOnElapsed;
|
||||
}
|
||||
|
||||
private void OnUpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (TargetDataModelOpen)
|
||||
{
|
||||
TargetDataModel?.Update(_dataModelVisualizationService);
|
||||
SelectedListProperty?.Update(_dataModelVisualizationService);
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetDataModelUpdateRequested(object sender, EventArgs e)
|
||||
{
|
||||
TargetDataModel.ApplyTypeFilter(true, typeof(IList));
|
||||
}
|
||||
|
||||
public void ApplyList()
|
||||
{
|
||||
DisplayConditionList.UpdateList(SelectedListProperty.DataModel, SelectedListProperty.PropertyPath);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public override DataModelPropertiesViewModel GetDataModelOverride()
|
||||
{
|
||||
if (SelectedListProperty != null)
|
||||
return SelectedListProperty.GetListTypeViewModel(_dataModelVisualizationService);
|
||||
|
||||
return base.GetDataModelOverride();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (TargetDataModel == null)
|
||||
return;
|
||||
|
||||
NotifyOfPropertyChange(nameof(SelectedListOperator));
|
||||
|
||||
// Update the selected list property
|
||||
if (DisplayConditionList.ListDataModel != null && DisplayConditionList.ListPropertyPath != null)
|
||||
{
|
||||
var child = TargetDataModel.GetChildByPath(
|
||||
DisplayConditionList.ListDataModel.PluginInfo.Guid,
|
||||
DisplayConditionList.ListPropertyPath
|
||||
);
|
||||
SelectedListProperty = child as DataModelListViewModel;
|
||||
}
|
||||
|
||||
// Ensure filtering is applied to include Enumerables only
|
||||
TargetDataModel.ApplyTypeFilter(true, typeof(IList));
|
||||
|
||||
// Remove VMs of effects no longer applied on the layer
|
||||
var toRemove = Children.Where(c => !DisplayConditionList.Children.Contains(c.Model)).ToList();
|
||||
// Using RemoveRange breaks our lovely animations
|
||||
foreach (var displayConditionViewModel in toRemove)
|
||||
{
|
||||
Children.Remove(displayConditionViewModel);
|
||||
displayConditionViewModel.Dispose();
|
||||
}
|
||||
|
||||
foreach (var childModel in Model.Children)
|
||||
{
|
||||
if (Children.Any(c => c.Model == childModel))
|
||||
continue;
|
||||
if (!(childModel is DisplayConditionGroup displayConditionGroup))
|
||||
continue;
|
||||
|
||||
var viewModel = _displayConditionsVmFactory.DisplayConditionGroupViewModel(displayConditionGroup, this);
|
||||
viewModel.IsRootGroup = true;
|
||||
Children.Add(viewModel);
|
||||
}
|
||||
|
||||
foreach (var childViewModel in Children)
|
||||
childViewModel.Update();
|
||||
}
|
||||
|
||||
|
||||
private void ExecuteSelectListProperty(object context)
|
||||
{
|
||||
if (!(context is DataModelListViewModel dataModelListViewModel))
|
||||
return;
|
||||
|
||||
SelectedListProperty = dataModelListViewModel;
|
||||
ApplyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
<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"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
|
||||
xmlns:displayConditions="clr-namespace:Artemis.UI.Screens.ProfileEditor.DisplayConditions"
|
||||
x:Class="Artemis.UI.Screens.ProfileEditor.DisplayConditions.DisplayConditionPredicateView"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance IsDesignTimeCreatable=False, Type={x:Type displayConditions:DisplayConditionPredicateViewModel}}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DisplayConditions.xaml" />
|
||||
<ResourceDictionary>
|
||||
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
|
||||
<DataTemplate x:Key="DataModelDataTemplate">
|
||||
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource DataModelSelectionTemplate}" />
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding Data.ShowDataModelValues.Value, Source={StaticResource DataContextProxy}}" Value="True">
|
||||
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource DataModelSelectionTemplateWithValues}" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="0 3" Visibility="{Binding IsInitialized, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
ToolTip="Delete the predicate"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
HorizontalAlignment="Left"
|
||||
Foreground="#E74C4C"
|
||||
Width="25"
|
||||
Height="25"
|
||||
Command="{s:Action Delete}">
|
||||
<materialDesign:PackIcon Kind="Close" Width="18" Height="18" />
|
||||
</Button>
|
||||
|
||||
<!-- Left side, always a property -->
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Background="#ab47bc"
|
||||
BorderBrush="#ab47bc"
|
||||
Style="{StaticResource DisplayConditionButton}"
|
||||
ToolTip="{Binding SelectedLeftSideProperty.DisplayPropertyPath}"
|
||||
Click="PropertyButton_OnClick">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu ItemsSource="{Binding LeftSideDataModel.Children}" IsOpen="{Binding LeftSideDataModelOpen, Mode=OneWayToSource}">
|
||||
<ContextMenu.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
|
||||
<Setter Property="ItemsSource" Value="{Binding Children}" />
|
||||
<Setter Property="Command" Value="{Binding Data.SelectLeftPropertyCommand, Source={StaticResource DataContextProxy}}" />
|
||||
<Setter Property="CommandParameter" Value="{Binding}" />
|
||||
<Setter Property="CommandTarget" Value="{Binding}" />
|
||||
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
|
||||
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
|
||||
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelDataTemplate}" />
|
||||
</Style>
|
||||
</ContextMenu.ItemContainerStyle>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding SelectedLeftSideProperty.PropertyDescription.Name}"
|
||||
Visibility="{Binding SelectedLeftSideProperty, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
<TextBlock Text="« Select a property »"
|
||||
FontStyle="Italic"
|
||||
Visibility="{Binding SelectedLeftSideProperty, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<!-- Operator -->
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Style="{StaticResource DisplayConditionButtonLeftClickMenu}"
|
||||
Background="#7B7B7B"
|
||||
BorderBrush="#7B7B7B"
|
||||
Content="{Binding SelectedOperator.Description}"
|
||||
Click="PropertyButton_OnClick">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu ItemsSource="{Binding Operators}">
|
||||
<ContextMenu.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="{Binding Icon}" VerticalAlignment="Center" Margin="0 0 15 0" />
|
||||
<TextBlock Text="{Binding Description}" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ContextMenu.ItemTemplate>
|
||||
<ContextMenu.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
|
||||
<Setter Property="Command" Value="{Binding Data.SelectOperatorCommand, Source={StaticResource DataContextProxy}}" />
|
||||
<Setter Property="CommandParameter" Value="{Binding}" />
|
||||
<Setter Property="CommandTarget" Value="{Binding}" />
|
||||
</Style>
|
||||
</ContextMenu.ItemContainerStyle>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
</Button>
|
||||
|
||||
<Grid Grid.Row="0"
|
||||
Grid.Column="3"
|
||||
Visibility="{Binding SelectedOperator.SupportsRightSide, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<!-- Right side property if type is dynamic -->
|
||||
<Button Background="{DynamicResource PrimaryHueMidBrush}"
|
||||
BorderBrush="{DynamicResource PrimaryHueMidBrush}"
|
||||
Style="{StaticResource DisplayConditionButton}"
|
||||
ToolTip="{Binding SelectedRightSideProperty.DisplayPropertyPath}"
|
||||
Click="PropertyButton_OnClick"
|
||||
Visibility="{Binding ShowRightSidePropertySelection, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu ItemsSource="{Binding RightSideDataModel.Children}">
|
||||
<ContextMenu.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
|
||||
<Setter Property="ItemsSource" Value="{Binding Children}" />
|
||||
<Setter Property="Command" Value="{Binding Data.SelectRightPropertyCommand, Source={StaticResource DataContextProxy}}" />
|
||||
<Setter Property="CommandParameter" Value="{Binding}" />
|
||||
<Setter Property="CommandTarget" Value="{Binding}" />
|
||||
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
|
||||
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
|
||||
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelDataTemplate}" />
|
||||
</Style>
|
||||
</ContextMenu.ItemContainerStyle>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding SelectedRightSideProperty.PropertyDescription.Name}"
|
||||
Visibility="{Binding SelectedRightSideProperty, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
<TextBlock Text="« Select a property »"
|
||||
FontStyle="Italic"
|
||||
Visibility="{Binding SelectedRightSideProperty, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<!-- Right side property if type is static -->
|
||||
<materialDesign:Transitioner SelectedIndex="{Binding RightSideTransitionIndex}"
|
||||
DefaultTransitionOrigin="0.5, 0.5"
|
||||
Margin="3 -4"
|
||||
Visibility="{Binding ShowRightSidePropertySelection, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||
<Button Style="{StaticResource DisplayConditionButton}"
|
||||
Background="{DynamicResource PrimaryHueMidBrush}"
|
||||
BorderBrush="{DynamicResource PrimaryHueMidBrush}"
|
||||
Margin="0 4"
|
||||
Command="{s:Action ActivateRightSideInputViewModel}"
|
||||
HorizontalAlignment="Left">
|
||||
<Grid>
|
||||
<StackPanel Visibility="{Binding RightStaticValue, Converter={StaticResource NullToVisibilityConverter}}" Orientation="Horizontal">
|
||||
<TextBlock FontWeight="Light"
|
||||
Text="{Binding SelectedLeftSideProperty.PropertyDescription.Prefix}"
|
||||
Visibility="{Binding SelectedLeftSideProperty.PropertyDescription.Prefix, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
<TextBlock Text="{Binding RightStaticValue}" />
|
||||
<TextBlock FontWeight="Light"
|
||||
Text="{Binding SelectedLeftSideProperty.PropertyDescription.Affix}"
|
||||
Visibility="{Binding SelectedLeftSideProperty.PropertyDescription.Affix, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="« Enter a value »"
|
||||
FontStyle="Italic"
|
||||
Visibility="{Binding RightStaticValue, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
|
||||
</Grid>
|
||||
</Button>
|
||||
<Border BorderBrush="{DynamicResource PrimaryHueMidBrush}"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
CornerRadius="3"
|
||||
Padding="3"
|
||||
HorizontalAlignment="Left"
|
||||
MinWidth="140">
|
||||
<ContentControl s:View.Model="{Binding RightSideInputViewModel}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
|
||||
</Border>
|
||||
</materialDesign:Transitioner>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for DisplayConditionPredicateView.xaml
|
||||
/// </summary>
|
||||
public partial class DisplayConditionPredicateView : UserControl
|
||||
{
|
||||
public DisplayConditionPredicateView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void PropertyButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// DataContext is not set when using left button, I don't know why but there it is
|
||||
if (sender is Button button && button.ContextMenu != null)
|
||||
{
|
||||
button.ContextMenu.DataContext = button.DataContext;
|
||||
button.ContextMenu.IsOpen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+349
@@ -0,0 +1,349 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using Artemis.Core.Models.Profile.Conditions;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.UI.Events;
|
||||
using Artemis.UI.Screens.ProfileEditor.DisplayConditions.Abstract;
|
||||
using Artemis.UI.Shared.DataModelVisualization;
|
||||
using Artemis.UI.Shared.DataModelVisualization.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using Artemis.UI.Utilities;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
{
|
||||
public class DisplayConditionPredicateViewModel : DisplayConditionViewModel, IHandle<MainWindowKeyEvent>, IHandle<MainWindowMouseEvent>
|
||||
{
|
||||
private readonly IDataModelService _dataModelService;
|
||||
private readonly IDataModelVisualizationService _dataModelVisualizationService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private bool _isInitialized;
|
||||
private DataModelPropertiesViewModel _leftSideDataModel;
|
||||
private BindableCollection<DisplayConditionOperator> _operators;
|
||||
private DataModelPropertiesViewModel _rightSideDataModel;
|
||||
private DataModelInputViewModel _rightSideInputViewModel;
|
||||
private int _rightSideTransitionIndex;
|
||||
private object _rightStaticValue;
|
||||
private DataModelVisualizationViewModel _selectedLeftSideProperty;
|
||||
private DisplayConditionOperator _selectedOperator;
|
||||
private DataModelVisualizationViewModel _selectedRightSideProperty;
|
||||
|
||||
private List<Type> _supportedInputTypes;
|
||||
private readonly Timer _updateTimer;
|
||||
|
||||
public DisplayConditionPredicateViewModel(
|
||||
DisplayConditionPredicate displayConditionPredicate,
|
||||
DisplayConditionViewModel parent,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelVisualizationService dataModelVisualizationService,
|
||||
IDataModelService dataModelService,
|
||||
ISettingsService settingsService,
|
||||
IEventAggregator eventAggregator) : base(displayConditionPredicate, parent)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataModelVisualizationService = dataModelVisualizationService;
|
||||
_dataModelService = dataModelService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_updateTimer = new Timer(500);
|
||||
_supportedInputTypes = new List<Type>();
|
||||
|
||||
SelectLeftPropertyCommand = new DelegateCommand(ExecuteSelectLeftProperty);
|
||||
SelectRightPropertyCommand = new DelegateCommand(ExecuteSelectRightProperty);
|
||||
SelectOperatorCommand = new DelegateCommand(ExecuteSelectOperatorCommand);
|
||||
Operators = new BindableCollection<DisplayConditionOperator>();
|
||||
|
||||
ShowDataModelValues = settingsService.GetSetting<bool>("ProfileEditor.ShowDataModelValues");
|
||||
|
||||
// Initialize async, no need to wait for it
|
||||
Task.Run(Initialize);
|
||||
}
|
||||
|
||||
public DisplayConditionPredicate DisplayConditionPredicate => (DisplayConditionPredicate) Model;
|
||||
public bool ShowRightSidePropertySelection => DisplayConditionPredicate.PredicateType == PredicateType.Dynamic;
|
||||
public bool CanActivateRightSideInputViewModel => SelectedLeftSideProperty?.PropertyInfo != null;
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
|
||||
public bool IsInitialized
|
||||
{
|
||||
get => _isInitialized;
|
||||
private set => SetAndNotify(ref _isInitialized, value);
|
||||
}
|
||||
|
||||
public bool LeftSideDataModelOpen { get; set; }
|
||||
|
||||
public DataModelPropertiesViewModel LeftSideDataModel
|
||||
{
|
||||
get => _leftSideDataModel;
|
||||
set => SetAndNotify(ref _leftSideDataModel, value);
|
||||
}
|
||||
|
||||
public DataModelPropertiesViewModel RightSideDataModel
|
||||
{
|
||||
get => _rightSideDataModel;
|
||||
set => SetAndNotify(ref _rightSideDataModel, value);
|
||||
}
|
||||
|
||||
public bool RightSideDataModelOpen { get; set; }
|
||||
|
||||
public DataModelVisualizationViewModel SelectedLeftSideProperty
|
||||
{
|
||||
get => _selectedLeftSideProperty;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _selectedLeftSideProperty, value)) return;
|
||||
NotifyOfPropertyChange(nameof(CanActivateRightSideInputViewModel));
|
||||
}
|
||||
}
|
||||
|
||||
public DataModelVisualizationViewModel SelectedRightSideProperty
|
||||
{
|
||||
get => _selectedRightSideProperty;
|
||||
set => SetAndNotify(ref _selectedRightSideProperty, value);
|
||||
}
|
||||
|
||||
public object RightStaticValue
|
||||
{
|
||||
get => _rightStaticValue;
|
||||
set => SetAndNotify(ref _rightStaticValue, value);
|
||||
}
|
||||
|
||||
public int RightSideTransitionIndex
|
||||
{
|
||||
get => _rightSideTransitionIndex;
|
||||
set => SetAndNotify(ref _rightSideTransitionIndex, value);
|
||||
}
|
||||
|
||||
public DataModelInputViewModel RightSideInputViewModel
|
||||
{
|
||||
get => _rightSideInputViewModel;
|
||||
set => SetAndNotify(ref _rightSideInputViewModel, value);
|
||||
}
|
||||
|
||||
public BindableCollection<DisplayConditionOperator> Operators
|
||||
{
|
||||
get => _operators;
|
||||
set => SetAndNotify(ref _operators, value);
|
||||
}
|
||||
|
||||
public DisplayConditionOperator SelectedOperator
|
||||
{
|
||||
get => _selectedOperator;
|
||||
set => SetAndNotify(ref _selectedOperator, value);
|
||||
}
|
||||
|
||||
public DelegateCommand SelectLeftPropertyCommand { get; }
|
||||
public DelegateCommand SelectRightPropertyCommand { get; }
|
||||
public DelegateCommand SelectOperatorCommand { get; }
|
||||
|
||||
public void Handle(MainWindowKeyEvent message)
|
||||
{
|
||||
if (RightSideInputViewModel == null)
|
||||
return;
|
||||
|
||||
if (!message.KeyDown && message.EventArgs.Key == Key.Escape)
|
||||
RightSideInputViewModel.Cancel();
|
||||
if (!message.KeyDown && message.EventArgs.Key == Key.Enter)
|
||||
RightSideInputViewModel.Submit();
|
||||
}
|
||||
|
||||
public void Handle(MainWindowMouseEvent message)
|
||||
{
|
||||
if (RightSideInputViewModel == null)
|
||||
return;
|
||||
|
||||
if (message.Sender is FrameworkElement frameworkElement && !frameworkElement.IsDescendantOf(RightSideInputViewModel.View))
|
||||
RightSideInputViewModel.Submit();
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
base.Delete();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// Get the data models
|
||||
LeftSideDataModel = _dataModelVisualizationService.GetMainDataModelVisualization();
|
||||
RightSideDataModel = _dataModelVisualizationService.GetMainDataModelVisualization();
|
||||
if (!_dataModelVisualizationService.GetPluginExtendsDataModel(_profileEditorService.GetCurrentModule()))
|
||||
{
|
||||
LeftSideDataModel.Children.Add(_dataModelVisualizationService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule()));
|
||||
RightSideDataModel.Children.Add(_dataModelVisualizationService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule()));
|
||||
}
|
||||
|
||||
// Determine which types are currently supported
|
||||
var editors = _dataModelVisualizationService.RegisteredDataModelEditors;
|
||||
_supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
|
||||
_supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
|
||||
|
||||
LeftSideDataModel.UpdateRequested += LeftDataModelUpdateRequested;
|
||||
RightSideDataModel.UpdateRequested += RightDataModelUpdateRequested;
|
||||
|
||||
Update();
|
||||
|
||||
_updateTimer.Start();
|
||||
_updateTimer.Elapsed += OnUpdateTimerOnElapsed;
|
||||
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (LeftSideDataModel == null || DisplayConditionPredicate.PredicateType == PredicateType.Dynamic && RightSideDataModel == null)
|
||||
return;
|
||||
|
||||
if (GetDataModelOverride() != null)
|
||||
LeftSideDataModel = GetDataModelOverride();
|
||||
|
||||
// If static, only allow selecting properties also supported by input
|
||||
if (DisplayConditionPredicate.PredicateType == PredicateType.Static)
|
||||
LeftSideDataModel.ApplyTypeFilter(false, _supportedInputTypes.ToArray());
|
||||
|
||||
// Determine the left side property first
|
||||
SelectedLeftSideProperty = LeftSideDataModel.GetChildForCondition(DisplayConditionPredicate, DisplayConditionSide.Left);
|
||||
var leftSideType = SelectedLeftSideProperty?.PropertyInfo?.PropertyType;
|
||||
|
||||
// Get the supported operators
|
||||
Operators.Clear();
|
||||
Operators.AddRange(_dataModelService.GetCompatibleConditionOperators(leftSideType));
|
||||
if (DisplayConditionPredicate.Operator == null)
|
||||
DisplayConditionPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType)));
|
||||
SelectedOperator = DisplayConditionPredicate.Operator;
|
||||
|
||||
// Determine the right side
|
||||
if (DisplayConditionPredicate.PredicateType == PredicateType.Dynamic)
|
||||
{
|
||||
SelectedRightSideProperty = LeftSideDataModel.GetChildForCondition(DisplayConditionPredicate, DisplayConditionSide.Right);
|
||||
if (GetDataModelOverride() != null)
|
||||
RightSideDataModel = GetDataModelOverride();
|
||||
|
||||
RightSideDataModel.ApplyTypeFilter(true, leftSideType);
|
||||
}
|
||||
else
|
||||
RightStaticValue = DisplayConditionPredicate.RightStaticValue;
|
||||
}
|
||||
|
||||
public void ApplyLeftSide()
|
||||
{
|
||||
DisplayConditionPredicate.UpdateLeftSide(SelectedLeftSideProperty.DataModel, SelectedLeftSideProperty.PropertyPath);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
|
||||
SelectedOperator = DisplayConditionPredicate.Operator;
|
||||
Update();
|
||||
}
|
||||
|
||||
public void ApplyRightSideDynamic()
|
||||
{
|
||||
DisplayConditionPredicate.UpdateRightSide(SelectedRightSideProperty.DataModel, SelectedRightSideProperty.PropertyPath);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public void ApplyRightSideStatic(object value, bool isSubmitted)
|
||||
{
|
||||
if (isSubmitted)
|
||||
{
|
||||
DisplayConditionPredicate.UpdateRightSide(value);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
RightSideTransitionIndex = 0;
|
||||
RightSideInputViewModel = null;
|
||||
RightStaticValue = value;
|
||||
_eventAggregator.Unsubscribe(this);
|
||||
}
|
||||
|
||||
public void ApplyOperator()
|
||||
{
|
||||
DisplayConditionPredicate.UpdateOperator(SelectedOperator);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public void ActivateRightSideInputViewModel()
|
||||
{
|
||||
if (SelectedLeftSideProperty?.PropertyInfo == null)
|
||||
return;
|
||||
|
||||
RightSideTransitionIndex = 1;
|
||||
RightSideInputViewModel = _dataModelVisualizationService.GetDataModelInputViewModel(
|
||||
SelectedLeftSideProperty.PropertyInfo.PropertyType,
|
||||
SelectedLeftSideProperty.PropertyDescription,
|
||||
DisplayConditionPredicate.RightStaticValue,
|
||||
ApplyRightSideStatic
|
||||
);
|
||||
_eventAggregator.Subscribe(this);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_updateTimer.Stop();
|
||||
_updateTimer.Elapsed -= OnUpdateTimerOnElapsed;
|
||||
}
|
||||
|
||||
private void OnUpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (LeftSideDataModelOpen)
|
||||
LeftSideDataModel.Update(_dataModelVisualizationService);
|
||||
else if (RightSideDataModelOpen)
|
||||
RightSideDataModel.Update(_dataModelVisualizationService);
|
||||
}
|
||||
|
||||
private void RightDataModelUpdateRequested(object sender, EventArgs e)
|
||||
{
|
||||
var leftSideType = SelectedLeftSideProperty?.PropertyInfo?.PropertyType;
|
||||
if (DisplayConditionPredicate.PredicateType == PredicateType.Dynamic)
|
||||
SelectedRightSideProperty = LeftSideDataModel.GetChildForCondition(DisplayConditionPredicate, DisplayConditionSide.Right);
|
||||
|
||||
// With the data model updated, also reapply the filter
|
||||
RightSideDataModel.ApplyTypeFilter(true, leftSideType);
|
||||
}
|
||||
|
||||
private void LeftDataModelUpdateRequested(object sender, EventArgs e)
|
||||
{
|
||||
if (DisplayConditionPredicate.PredicateType == PredicateType.Static)
|
||||
LeftSideDataModel.ApplyTypeFilter(false, _supportedInputTypes.ToArray());
|
||||
}
|
||||
|
||||
private void ExecuteSelectLeftProperty(object context)
|
||||
{
|
||||
if (!(context is DataModelVisualizationViewModel dataModelVisualizationViewModel))
|
||||
return;
|
||||
|
||||
SelectedLeftSideProperty = dataModelVisualizationViewModel;
|
||||
ApplyLeftSide();
|
||||
}
|
||||
|
||||
private void ExecuteSelectRightProperty(object context)
|
||||
{
|
||||
if (!(context is DataModelVisualizationViewModel dataModelVisualizationViewModel))
|
||||
return;
|
||||
|
||||
SelectedRightSideProperty = dataModelVisualizationViewModel;
|
||||
ApplyRightSideDynamic();
|
||||
}
|
||||
|
||||
private void ExecuteSelectOperatorCommand(object context)
|
||||
{
|
||||
if (!(context is DisplayConditionOperator displayConditionOperator))
|
||||
return;
|
||||
|
||||
SelectedOperator = displayConditionOperator;
|
||||
ApplyOperator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<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"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:displayConditions="clr-namespace:Artemis.UI.Screens.ProfileEditor.DisplayConditions"
|
||||
x:Class="Artemis.UI.Screens.ProfileEditor.DisplayConditions.DisplayConditionsView"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type displayConditions:DisplayConditionsViewModel}}">
|
||||
<UserControl.Resources>
|
||||
<converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<materialDesign:Transitioner AutoApplyTransitionOrigins="True" SelectedIndex="{Binding TransitionerIndex}">
|
||||
<!-- Conditions intro -->
|
||||
<materialDesign:ColorZone Mode="PrimaryDark" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="32">
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" TextAlignment="Center" Margin="0 15">Unleash Artemis's true potential</TextBlock>
|
||||
<TextBlock TextWrapping="Wrap" TextAlignment="Center">Start using conditions to dynamically show and hide groups and layers</TextBlock>
|
||||
|
||||
<Button Style="{DynamicResource MaterialDesignFloatingActionAccentButton}" Command="{x:Static materialDesign:Transitioner.MoveNextCommand}" Margin="16">
|
||||
<materialDesign:PackIcon Kind="ArrowRight" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</materialDesign:ColorZone>
|
||||
|
||||
<!-- Conditions content -->
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Margin="0 0 0 -4">
|
||||
Display conditions
|
||||
</TextBlock>
|
||||
<Separator Grid.Row="1" Grid.Column="0" Style="{StaticResource MaterialDesignDarkSeparator}" Margin="-2 0" />
|
||||
|
||||
<Grid Grid.Row="2" Grid.Column="0">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Background="{StaticResource MaterialDesignCardBackground}">
|
||||
<ContentControl s:View.Model="{Binding RootGroup}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="3">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="20" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" MinWidth="140" />
|
||||
<ColumnDefinition Width="*" MinWidth="170" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Play mode -->
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="PlayOutline" VerticalAlignment="Center" />
|
||||
<TextBlock Text="Play mode" VerticalAlignment="Center">
|
||||
<TextBlock.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-30">
|
||||
<TextBlock>
|
||||
Configure how the layer should act while the conditions above are met
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</TextBlock.ToolTip>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<materialDesign:ColorZone Grid.Row="1" Grid.Column="0" Mode="Standard" CornerRadius="3" Margin="0 0 2 0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Grid.Column="0"
|
||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||
IsChecked="{Binding DisplayContinuously}"
|
||||
MinWidth="0"
|
||||
Padding="5 0">
|
||||
<RadioButton.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||
<TextBlock>
|
||||
Continue repeating the main segment of the timeline while the condition is met
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</RadioButton.ToolTip>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Repeat" VerticalAlignment="Center" />
|
||||
<TextBlock FontSize="12" VerticalAlignment="Center">REPEAT</TextBlock>
|
||||
</StackPanel>
|
||||
</RadioButton>
|
||||
<RadioButton Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||
IsChecked="{Binding DisplayContinuously, Converter={StaticResource InverseBooleanConverter}}"
|
||||
MinWidth="0"
|
||||
Padding="5 0">
|
||||
<RadioButton.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||
<TextBlock>
|
||||
Only play the timeline once when the condition is met
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</RadioButton.ToolTip>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="StopwatchOutline" VerticalAlignment="Center" />
|
||||
<TextBlock FontSize="12" VerticalAlignment="Center">ONCE</TextBlock>
|
||||
</StackPanel>
|
||||
</RadioButton>
|
||||
</Grid>
|
||||
</materialDesign:ColorZone>
|
||||
|
||||
<!-- Stop mode -->
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Stop" VerticalAlignment="Center" />
|
||||
<TextBlock Text="Stop mode" VerticalAlignment="Center">
|
||||
<TextBlock.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-30">
|
||||
<TextBlock>
|
||||
Configure how the layer should act when the conditions above are no longer met
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</TextBlock.ToolTip>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<materialDesign:ColorZone Grid.Row="1" Grid.Column="1" Mode="Standard" CornerRadius="3" Margin="2 0 0 0" HorizontalAlignment="Stretch">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition MinWidth="100" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Grid.Column="0"
|
||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||
IsChecked="{Binding AlwaysFinishTimeline}"
|
||||
MinWidth="0"
|
||||
Padding="5 0">
|
||||
<RadioButton.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||
<TextBlock>
|
||||
When conditions are no longer met, finish the the current run of the main timeline
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</RadioButton.ToolTip>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="PlayOutline" VerticalAlignment="Center" />
|
||||
<TextBlock FontSize="12" VerticalAlignment="Center">FINISH</TextBlock>
|
||||
</StackPanel>
|
||||
</RadioButton>
|
||||
<RadioButton Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||
IsChecked="{Binding AlwaysFinishTimeline, Converter={StaticResource InverseBooleanConverter}}"
|
||||
MinWidth="0"
|
||||
Padding="5 0">
|
||||
<RadioButton.ToolTip>
|
||||
<ToolTip Placement="Center" VerticalOffset="-40">
|
||||
<TextBlock>
|
||||
When conditions are no longer met, skip to the end segment of the timeline
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</RadioButton.ToolTip>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="SkipNextOutline" VerticalAlignment="Center" />
|
||||
<TextBlock FontSize="12" VerticalAlignment="Center">SKIP TO END</TextBlock>
|
||||
</StackPanel>
|
||||
</RadioButton>
|
||||
</Grid>
|
||||
</materialDesign:ColorZone>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
</materialDesign:Transitioner>
|
||||
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,110 @@
|
||||
using System.Linq;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Profile.Conditions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Events;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
{
|
||||
public class DisplayConditionsViewModel : ProfileEditorPanelViewModel
|
||||
{
|
||||
private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private RenderProfileElement _renderProfileElement;
|
||||
private DisplayConditionGroupViewModel _rootGroup;
|
||||
private int _transitionerIndex;
|
||||
private bool _displayContinuously;
|
||||
private bool _alwaysFinishTimeline;
|
||||
|
||||
public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDisplayConditionsVmFactory displayConditionsVmFactory)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_displayConditionsVmFactory = displayConditionsVmFactory;
|
||||
}
|
||||
|
||||
public int TransitionerIndex
|
||||
{
|
||||
get => _transitionerIndex;
|
||||
set => SetAndNotify(ref _transitionerIndex, value);
|
||||
}
|
||||
|
||||
public DisplayConditionGroupViewModel RootGroup
|
||||
{
|
||||
get => _rootGroup;
|
||||
set => SetAndNotify(ref _rootGroup, value);
|
||||
}
|
||||
|
||||
public RenderProfileElement RenderProfileElement
|
||||
{
|
||||
get => _renderProfileElement;
|
||||
set => SetAndNotify(ref _renderProfileElement, value);
|
||||
}
|
||||
|
||||
public bool DisplayContinuously
|
||||
{
|
||||
get => _displayContinuously;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _displayContinuously, value)) return;
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
}
|
||||
|
||||
public bool AlwaysFinishTimeline
|
||||
{
|
||||
get => _alwaysFinishTimeline;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _alwaysFinishTimeline, value)) return;
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ConditionBehaviourEnabled => RenderProfileElement != null;
|
||||
|
||||
protected override void OnActivate()
|
||||
{
|
||||
_profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
||||
}
|
||||
|
||||
protected override void OnDeactivate()
|
||||
{
|
||||
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||
|
||||
RootGroup?.Dispose();
|
||||
RootGroup = null;
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||
{
|
||||
RenderProfileElement = e.RenderProfileElement;
|
||||
NotifyOfPropertyChange(nameof(ConditionBehaviourEnabled));
|
||||
|
||||
_displayContinuously = RenderProfileElement?.DisplayContinuously ?? false;
|
||||
NotifyOfPropertyChange(nameof(DisplayContinuously));
|
||||
_alwaysFinishTimeline = RenderProfileElement?.AlwaysFinishTimeline ?? false;
|
||||
NotifyOfPropertyChange(nameof(AlwaysFinishTimeline));
|
||||
|
||||
if (e.RenderProfileElement == null)
|
||||
{
|
||||
RootGroup?.Dispose();
|
||||
RootGroup = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the layer has a root display condition group
|
||||
if (e.RenderProfileElement.DisplayConditionGroup == null)
|
||||
e.RenderProfileElement.DisplayConditionGroup = new DisplayConditionGroup(null);
|
||||
|
||||
RootGroup?.Dispose();
|
||||
RootGroup = _displayConditionsVmFactory.DisplayConditionGroupViewModel(e.RenderProfileElement.DisplayConditionGroup, null);
|
||||
RootGroup.IsRootGroup = true;
|
||||
RootGroup.Update();
|
||||
|
||||
// Only show the intro to conditions once, and only if the layer has no conditions
|
||||
if (TransitionerIndex != 1)
|
||||
TransitionerIndex = RootGroup.Children.Any() ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user