mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Shared UI - Resolved all remaining warnings
UI - Resolved all remaining warnings Layer properties - Fixed DisableKeyframes layer property attribute not being applied
This commit is contained in:
parent
931b43aa66
commit
8d901027ee
@ -491,6 +491,9 @@ namespace Artemis.Core
|
||||
Entity = entity ?? throw new ArgumentNullException(nameof(entity));
|
||||
PropertyDescription = description ?? throw new ArgumentNullException(nameof(description));
|
||||
IsLoadedFromStorage = fromStorage;
|
||||
|
||||
if (PropertyDescription.DisableKeyframes)
|
||||
KeyframesSupported = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@ -184,7 +184,7 @@ namespace Artemis.UI.Shared
|
||||
return rotationRect.Size;
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
private void OnUnloaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_timer.Stop();
|
||||
|
||||
@ -196,12 +196,12 @@ namespace Artemis.UI.Shared
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
private void OnLoaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
private void TimerOnTick(object sender, EventArgs e)
|
||||
private void TimerOnTick(object? sender, EventArgs e)
|
||||
{
|
||||
if (ShowColors && Visibility == Visibility.Visible)
|
||||
Render();
|
||||
|
||||
@ -13,20 +13,20 @@ namespace Artemis.UI.Shared
|
||||
public class ColorToStringConverter : IValueConverter
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
public object? Convert(object? value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value?.ToString()?.ToUpper();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
public object? ConvertBack(object? value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace((string) value))
|
||||
if (string.IsNullOrWhiteSpace(value as string))
|
||||
return default(Color);
|
||||
|
||||
object color = ColorConverter.ConvertFromString((string) value);
|
||||
object? color = ColorConverter.ConvertFromString((string) value!);
|
||||
if (color is Color c)
|
||||
return c;
|
||||
|
||||
|
||||
@ -14,18 +14,18 @@ namespace Artemis.UI.Shared
|
||||
public class SKColorToStringConverter : IValueConverter
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
public object? Convert(object? value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value?.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
public object ConvertBack(object? value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace((string) value))
|
||||
if (string.IsNullOrWhiteSpace(value as string))
|
||||
return SKColor.Empty;
|
||||
|
||||
return SKColor.TryParse((string) value, out SKColor color) ? color : SKColor.Empty;
|
||||
return SKColor.TryParse((string) value!, out SKColor color) ? color : SKColor.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11,7 +11,7 @@ namespace Artemis.UI.Shared
|
||||
public class TypeToStringConverter : IValueConverter
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
public object? Convert(object value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
bool humanizeProvided = bool.TryParse(parameter?.ToString(), out bool humanize);
|
||||
if (value is Type type)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Artemis.Core.DataModelExpansions;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Artemis.Core.DataModelExpansions;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Shared
|
||||
@ -9,11 +10,13 @@ namespace Artemis.UI.Shared
|
||||
/// <typeparam name="T">The type of the data model</typeparam>
|
||||
public abstract class DataModelDisplayViewModel<T> : DataModelDisplayViewModel
|
||||
{
|
||||
private T _displayValue;
|
||||
[AllowNull]
|
||||
private T _displayValue = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets value that the view model must display
|
||||
/// </summary>
|
||||
[AllowNull]
|
||||
public T DisplayValue
|
||||
{
|
||||
get => _displayValue;
|
||||
@ -24,10 +27,10 @@ namespace Artemis.UI.Shared
|
||||
}
|
||||
}
|
||||
|
||||
internal override object InternalGuard => null;
|
||||
internal override object InternalGuard => new object();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void UpdateValue(object model)
|
||||
public override void UpdateValue(object? model)
|
||||
{
|
||||
DisplayValue = model is T value ? value : default;
|
||||
}
|
||||
@ -45,12 +48,12 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
public abstract class DataModelDisplayViewModel : PropertyChangedBase
|
||||
{
|
||||
private DataModelPropertyAttribute _propertyDescription;
|
||||
private DataModelPropertyAttribute? _propertyDescription;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property description of this value
|
||||
/// </summary>
|
||||
public DataModelPropertyAttribute PropertyDescription
|
||||
public DataModelPropertyAttribute? PropertyDescription
|
||||
{
|
||||
get => _propertyDescription;
|
||||
internal set => SetAndNotify(ref _propertyDescription, value);
|
||||
@ -65,6 +68,6 @@ namespace Artemis.UI.Shared
|
||||
/// Updates the display value
|
||||
/// </summary>
|
||||
/// <param name="model">The value to set</param>
|
||||
public abstract void UpdateValue(object model);
|
||||
public abstract void UpdateValue(object? model);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
@ -16,7 +17,7 @@ namespace Artemis.UI.Shared
|
||||
public abstract class DataModelInputViewModel<T> : DataModelInputViewModel
|
||||
{
|
||||
private bool _closed;
|
||||
private T _inputValue;
|
||||
[AllowNull] private T _inputValue = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="DataModelInputViewModel{T}" /> class
|
||||
@ -32,6 +33,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets or sets the value shown in the input
|
||||
/// </summary>
|
||||
[AllowNull]
|
||||
public T InputValue
|
||||
{
|
||||
get => _inputValue;
|
||||
@ -82,13 +84,13 @@ namespace Artemis.UI.Shared
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
internal abstract object InternalGuard { get; }
|
||||
|
||||
internal Action<object, bool> UpdateCallback { get; set; }
|
||||
internal Action<object?, bool> UpdateCallback { get; set; } = null!; // Set right after construction
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types this input view model can support through type conversion. This list is defined when registering the
|
||||
/// view model.
|
||||
/// </summary>
|
||||
internal IReadOnlyCollection<Type> CompatibleConversionTypes { get; set; }
|
||||
internal IReadOnlyCollection<Type>? CompatibleConversionTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Submits the input value and removes this view model.
|
||||
@ -133,6 +135,6 @@ namespace Artemis.UI.Shared
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public UIElement View { get; set; }
|
||||
public UIElement? View { get; set; }
|
||||
}
|
||||
}
|
||||
@ -12,21 +12,25 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Shared.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a view model that allows selecting a data model property used by boolean operations on a certain data
|
||||
/// model property
|
||||
/// </summary>
|
||||
public class DataModelDynamicViewModel : PropertyChangedBase, IDisposable
|
||||
{
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly Module _module;
|
||||
private readonly Timer _updateTimer;
|
||||
private SolidColorBrush _buttonBrush = new SolidColorBrush(Color.FromRgb(171, 71, 188));
|
||||
private DataModelPath _dataModelPath;
|
||||
private DataModelPropertiesViewModel _dataModelViewModel;
|
||||
private DataModelPath? _dataModelPath;
|
||||
private DataModelPropertiesViewModel? _dataModelViewModel;
|
||||
private bool _displaySwitchButton;
|
||||
private Type[] _filterTypes;
|
||||
private Type[] _filterTypes = new Type[0];
|
||||
private bool _isDataModelViewModelOpen;
|
||||
private bool _isEnabled = true;
|
||||
private string _placeholder = "Select a property";
|
||||
|
||||
public DataModelDynamicViewModel(Module module, ISettingsService settingsService, IDataModelUIService dataModelUIService)
|
||||
internal DataModelDynamicViewModel(Module module, ISettingsService settingsService, IDataModelUIService dataModelUIService)
|
||||
{
|
||||
_module = module;
|
||||
_dataModelUIService = dataModelUIService;
|
||||
@ -39,6 +43,9 @@ namespace Artemis.UI.Shared.Input
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush to use for the input button
|
||||
/// </summary>
|
||||
public SolidColorBrush ButtonBrush
|
||||
{
|
||||
get => _buttonBrush;
|
||||
@ -49,26 +56,41 @@ namespace Artemis.UI.Shared.Input
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the brush to use for the switch button
|
||||
/// </summary>
|
||||
public SolidColorBrush SwitchButtonBrush => new SolidColorBrush(ButtonBrush.Color.Darken());
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the placeholder text when no value is entered
|
||||
/// </summary>
|
||||
public string Placeholder
|
||||
{
|
||||
get => _placeholder;
|
||||
set => SetAndNotify(ref _placeholder, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the enabled state of the input
|
||||
/// </summary>
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set => SetAndNotify(ref _isEnabled, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the switch button should be displayed
|
||||
/// </summary>
|
||||
public bool DisplaySwitchButton
|
||||
{
|
||||
get => _displaySwitchButton;
|
||||
set => SetAndNotify(ref _displaySwitchButton, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the types of properties this view model will allow to be selected
|
||||
/// </summary>
|
||||
public Type[] FilterTypes
|
||||
{
|
||||
get => _filterTypes;
|
||||
@ -79,18 +101,38 @@ namespace Artemis.UI.Shared.Input
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a bindable collection of extra data model view models to show
|
||||
/// </summary>
|
||||
public BindableCollection<DataModelPropertiesViewModel> ExtraDataModelViewModels { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether there are any extra data models
|
||||
/// </summary>
|
||||
public bool HasExtraDataModels => ExtraDataModelViewModels.Any();
|
||||
|
||||
/// <summary>
|
||||
/// Command used by view
|
||||
/// </summary>
|
||||
public DelegateCommand SelectPropertyCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Setting used by view
|
||||
/// </summary>
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
|
||||
public DataModelPropertiesViewModel DataModelViewModel
|
||||
/// <summary>
|
||||
/// Gets or sets root the data model view model
|
||||
/// </summary>
|
||||
public DataModelPropertiesViewModel? DataModelViewModel
|
||||
{
|
||||
get => _dataModelViewModel;
|
||||
private set => SetAndNotify(ref _dataModelViewModel, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the data model is open
|
||||
/// </summary>
|
||||
public bool IsDataModelViewModelOpen
|
||||
{
|
||||
get => _isDataModelViewModelOpen;
|
||||
@ -101,7 +143,10 @@ namespace Artemis.UI.Shared.Input
|
||||
}
|
||||
}
|
||||
|
||||
public DataModelPath DataModelPath
|
||||
/// <summary>
|
||||
/// Gets or sets the data model path of the currently selected data model property
|
||||
/// </summary>
|
||||
public DataModelPath? DataModelPath
|
||||
{
|
||||
get => _dataModelPath;
|
||||
private set
|
||||
@ -113,9 +158,19 @@ namespace Artemis.UI.Shared.Input
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the current selection is valid
|
||||
/// </summary>
|
||||
public bool IsValid => DataModelPath?.IsValid ?? true;
|
||||
public string DisplayValue => DataModelPath?.GetPropertyDescription()?.Name ?? DataModelPath?.Segments.LastOrDefault()?.Identifier;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display name of the currently selected property
|
||||
/// </summary>
|
||||
public string? DisplayValue => DataModelPath?.GetPropertyDescription()?.Name ?? DataModelPath?.Segments.LastOrDefault()?.Identifier;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the human readable path of the currently selected property
|
||||
/// </summary>
|
||||
public string DisplayPath
|
||||
{
|
||||
get
|
||||
@ -128,8 +183,16 @@ namespace Artemis.UI.Shared.Input
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether event child VMs should be loaded, defaults to <see langword="true" />
|
||||
/// </summary>
|
||||
public bool LoadEventChildren { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Changes the root data model VM stored in <see cref="DataModelViewModel" /> to the provided
|
||||
/// <paramref name="dataModel" />
|
||||
/// </summary>
|
||||
/// <param name="dataModel">The data model VM to set the new root data model to</param>
|
||||
public void ChangeDataModel(DataModelPropertiesViewModel dataModel)
|
||||
{
|
||||
if (DataModelViewModel != null)
|
||||
@ -141,12 +204,19 @@ namespace Artemis.UI.Shared.Input
|
||||
DataModelViewModel.UpdateRequested += DataModelOnUpdateRequested;
|
||||
}
|
||||
|
||||
public void ChangeDataModelPath(DataModelPath dataModelPath)
|
||||
/// <summary>
|
||||
/// Changes the currently selected property by its path
|
||||
/// </summary>
|
||||
/// <param name="dataModelPath">The path of the property to set the selection to</param>
|
||||
public void ChangeDataModelPath(DataModelPath? dataModelPath)
|
||||
{
|
||||
DataModelPath?.Dispose();
|
||||
DataModelPath = dataModelPath != null ? new DataModelPath(dataModelPath) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests switching the input type to static using a <see cref="DataModelStaticViewModel" />
|
||||
/// </summary>
|
||||
public void SwitchToStatic()
|
||||
{
|
||||
ChangeDataModelPath(null);
|
||||
@ -158,13 +228,14 @@ namespace Artemis.UI.Shared.Input
|
||||
{
|
||||
// Get the data models
|
||||
DataModelViewModel = _dataModelUIService.GetPluginDataModelVisualization(_module, true);
|
||||
DataModelViewModel.UpdateRequested += DataModelOnUpdateRequested;
|
||||
if (DataModelViewModel != null)
|
||||
DataModelViewModel.UpdateRequested += DataModelOnUpdateRequested;
|
||||
ExtraDataModelViewModels.CollectionChanged += ExtraDataModelViewModelsOnCollectionChanged;
|
||||
_updateTimer.Start();
|
||||
_updateTimer.Elapsed += OnUpdateTimerOnElapsed;
|
||||
}
|
||||
|
||||
private void ExecuteSelectPropertyCommand(object context)
|
||||
private void ExecuteSelectPropertyCommand(object? context)
|
||||
{
|
||||
if (!(context is DataModelVisualizationViewModel selected))
|
||||
return;
|
||||
@ -173,40 +244,61 @@ namespace Artemis.UI.Shared.Input
|
||||
OnPropertySelected(new DataModelInputDynamicEventArgs(DataModelPath));
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <summary>
|
||||
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">
|
||||
/// <see langword="true" /> to release both managed and unmanaged resources;
|
||||
/// <see langword="false" /> to release only unmanaged resources.
|
||||
/// </param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_updateTimer.Stop();
|
||||
_updateTimer.Dispose();
|
||||
_updateTimer.Elapsed -= OnUpdateTimerOnElapsed;
|
||||
|
||||
DataModelPath?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_updateTimer.Stop();
|
||||
_updateTimer.Dispose();
|
||||
_updateTimer.Elapsed -= OnUpdateTimerOnElapsed;
|
||||
|
||||
DataModelPath?.Dispose();
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void DataModelOnUpdateRequested(object sender, EventArgs e)
|
||||
private void DataModelOnUpdateRequested(object? sender, EventArgs e)
|
||||
{
|
||||
DataModelViewModel.ApplyTypeFilter(true, FilterTypes);
|
||||
DataModelViewModel?.ApplyTypeFilter(true, FilterTypes);
|
||||
foreach (DataModelPropertiesViewModel extraDataModelViewModel in ExtraDataModelViewModels)
|
||||
extraDataModelViewModel.ApplyTypeFilter(true, FilterTypes);
|
||||
}
|
||||
|
||||
private void ExtraDataModelViewModelsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
private void ExtraDataModelViewModelsOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(HasExtraDataModels));
|
||||
}
|
||||
|
||||
private void OnUpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
|
||||
private void OnUpdateTimerOnElapsed(object? sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (!IsDataModelViewModelOpen)
|
||||
return;
|
||||
|
||||
|
||||
UpdateDataModelVisualization();
|
||||
}
|
||||
|
||||
private void UpdateDataModelVisualization()
|
||||
{
|
||||
DataModelViewModel.Update(_dataModelUIService, new DataModelUpdateConfiguration(LoadEventChildren));
|
||||
DataModelViewModel?.Update(_dataModelUIService, new DataModelUpdateConfiguration(LoadEventChildren));
|
||||
foreach (DataModelPropertiesViewModel extraDataModelViewModel in ExtraDataModelViewModels)
|
||||
extraDataModelViewModel.Update(_dataModelUIService, new DataModelUpdateConfiguration(LoadEventChildren));
|
||||
}
|
||||
@ -215,14 +307,28 @@ namespace Artemis.UI.Shared.Input
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler<DataModelInputDynamicEventArgs> PropertySelected;
|
||||
public event EventHandler SwitchToStaticRequested;
|
||||
/// <summary>
|
||||
/// Occurs when anew property has been selected
|
||||
/// </summary>
|
||||
public event EventHandler<DataModelInputDynamicEventArgs>? PropertySelected;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a switch to static input has been requested
|
||||
/// </summary>
|
||||
public event EventHandler? SwitchToStaticRequested;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="PropertySelected" /> event
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected virtual void OnPropertySelected(DataModelInputDynamicEventArgs e)
|
||||
{
|
||||
PropertySelected?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="SwitchToStaticRequested" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnSwitchToStaticRequested()
|
||||
{
|
||||
SwitchToStaticRequested?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
@ -11,29 +11,33 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Shared.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a view model that allows inputting a static value used by boolean operations on a certain data model
|
||||
/// property
|
||||
/// </summary>
|
||||
public class DataModelStaticViewModel : PropertyChangedBase, IDisposable
|
||||
{
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly Window _rootView;
|
||||
private readonly Window? _rootView;
|
||||
private SolidColorBrush _buttonBrush = new SolidColorBrush(Color.FromRgb(171, 71, 188));
|
||||
private bool _displaySwitchButton;
|
||||
private DataModelDisplayViewModel _displayViewModel;
|
||||
private DataModelInputViewModel _inputViewModel;
|
||||
private DataModelDisplayViewModel? _displayViewModel;
|
||||
private DataModelInputViewModel? _inputViewModel;
|
||||
private bool _isEnabled;
|
||||
private string _placeholder = "Enter a value";
|
||||
private DataModelPropertyAttribute _targetDescription;
|
||||
private Type _targetType;
|
||||
private object _value;
|
||||
private object? _value;
|
||||
|
||||
public DataModelStaticViewModel(Type targetType, DataModelPropertyAttribute targetDescription, IDataModelUIService dataModelUIService)
|
||||
internal DataModelStaticViewModel(Type targetType, DataModelPropertyAttribute targetDescription, IDataModelUIService dataModelUIService)
|
||||
{
|
||||
_dataModelUIService = dataModelUIService;
|
||||
_rootView = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
|
||||
|
||||
TargetType = targetType;
|
||||
TargetDescription = targetDescription;
|
||||
IsEnabled = TargetType != null;
|
||||
DisplayViewModel = _dataModelUIService.GetDataModelDisplayViewModel(TargetType ?? typeof(object), TargetDescription, true);
|
||||
_targetType = targetType;
|
||||
_targetDescription = targetDescription;
|
||||
_isEnabled = TargetType != null;
|
||||
_displayViewModel = _dataModelUIService.GetDataModelDisplayViewModel(TargetType ?? typeof(object), TargetDescription, true);
|
||||
|
||||
if (_rootView != null)
|
||||
{
|
||||
@ -63,7 +67,7 @@ namespace Artemis.UI.Shared.Input
|
||||
/// <summary>
|
||||
/// Gets the view model used to display the value
|
||||
/// </summary>
|
||||
public DataModelDisplayViewModel DisplayViewModel
|
||||
public DataModelDisplayViewModel? DisplayViewModel
|
||||
{
|
||||
get => _displayViewModel;
|
||||
private set => SetAndNotify(ref _displayViewModel, value);
|
||||
@ -72,7 +76,7 @@ namespace Artemis.UI.Shared.Input
|
||||
/// <summary>
|
||||
/// Gets the view model used to edit the value
|
||||
/// </summary>
|
||||
public DataModelInputViewModel InputViewModel
|
||||
public DataModelInputViewModel? InputViewModel
|
||||
{
|
||||
get => _inputViewModel;
|
||||
private set => SetAndNotify(ref _inputViewModel, value);
|
||||
@ -99,7 +103,7 @@ namespace Artemis.UI.Shared.Input
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the target
|
||||
/// </summary>
|
||||
public object Value
|
||||
public object? Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
@ -173,7 +177,7 @@ namespace Artemis.UI.Shared.Input
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests switching the input type to dynamic
|
||||
/// Requests switching the input type to dynamic using a <see cref="DataModelDynamicViewModel"/>
|
||||
/// </summary>
|
||||
public void SwitchToDynamic()
|
||||
{
|
||||
@ -183,7 +187,7 @@ namespace Artemis.UI.Shared.Input
|
||||
OnSwitchToDynamicRequested();
|
||||
}
|
||||
|
||||
private void ApplyFreeInput(object value, bool submitted)
|
||||
private void ApplyFreeInput(object? value, bool submitted)
|
||||
{
|
||||
if (submitted)
|
||||
OnValueUpdated(new DataModelInputStaticEventArgs(value));
|
||||
@ -204,11 +208,13 @@ namespace Artemis.UI.Shared.Input
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (_rootView != null)
|
||||
{
|
||||
_rootView.MouseUp -= RootViewOnMouseUp;
|
||||
_rootView.KeyUp -= RootViewOnKeyUp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@ -6,21 +6,28 @@ using Artemis.UI.Shared.Services;
|
||||
|
||||
namespace Artemis.UI.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a view model that visualizes an event data model property
|
||||
/// </summary>
|
||||
public class DataModelEventViewModel : DataModelVisualizationViewModel
|
||||
{
|
||||
private Type _displayValueType;
|
||||
private Type? _displayValueType;
|
||||
|
||||
internal DataModelEventViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath) : base(dataModel, parent, dataModelPath)
|
||||
{
|
||||
}
|
||||
|
||||
public Type DisplayValueType
|
||||
/// <summary>
|
||||
/// Gets the type of event arguments this event triggers and that must be displayed as children
|
||||
/// </summary>
|
||||
public Type? DisplayValueType
|
||||
{
|
||||
get => _displayValueType;
|
||||
set => SetAndNotify(ref _displayValueType, value);
|
||||
}
|
||||
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration configuration)
|
||||
/// <inheritdoc />
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||
{
|
||||
DisplayValueType = DataModelPath?.GetPropertyType();
|
||||
|
||||
@ -40,13 +47,16 @@ namespace Artemis.UI.Shared
|
||||
dataModelVisualizationViewModel.Update(dataModelUIService, configuration);
|
||||
}
|
||||
|
||||
public override object GetCurrentValue()
|
||||
/// <summary>
|
||||
/// Always returns <see langword="null"/> for data model events
|
||||
/// </summary>
|
||||
public override object? GetCurrentValue()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
public override string? ToString()
|
||||
{
|
||||
return DisplayPath ?? Path;
|
||||
}
|
||||
|
||||
@ -5,43 +5,63 @@ using Artemis.UI.Shared.Services;
|
||||
|
||||
namespace Artemis.UI.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a view model that wraps a regular <see cref="DataModelPropertiesViewModel" /> but contained in
|
||||
/// a <see cref="DataModelListViewModel" />
|
||||
/// </summary>
|
||||
public class DataModelListPropertiesViewModel : DataModelPropertiesViewModel
|
||||
{
|
||||
private object _displayValue;
|
||||
private readonly ListPredicateWrapperDataModel _listPredicateWrapper;
|
||||
private object? _displayValue;
|
||||
private int _index;
|
||||
private Type _listType;
|
||||
private Type? _listType;
|
||||
|
||||
public DataModelListPropertiesViewModel(Type listType) : base(null, null, null)
|
||||
internal DataModelListPropertiesViewModel(Type listType) : base(null, null, null)
|
||||
{
|
||||
DataModel = ListPredicateWrapperDataModel.Create(listType);
|
||||
_listPredicateWrapper = ListPredicateWrapperDataModel.Create(listType);
|
||||
DataModel = _listPredicateWrapper;
|
||||
ListType = listType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the element within the list
|
||||
/// </summary>
|
||||
public int Index
|
||||
{
|
||||
get => _index;
|
||||
set => SetAndNotify(ref _index, value);
|
||||
}
|
||||
|
||||
public Type ListType
|
||||
/// <summary>
|
||||
/// Gets the type of elements contained in the list
|
||||
/// </summary>
|
||||
public Type? ListType
|
||||
{
|
||||
get => _listType;
|
||||
set => SetAndNotify(ref _listType, value);
|
||||
}
|
||||
|
||||
public new object DisplayValue
|
||||
/// <summary>
|
||||
/// Gets the value of the property that is being visualized
|
||||
/// </summary>
|
||||
public new object? DisplayValue
|
||||
{
|
||||
get => _displayValue;
|
||||
set => SetAndNotify(ref _displayValue, value);
|
||||
}
|
||||
|
||||
public DataModelVisualizationViewModel DisplayViewModel => Children.FirstOrDefault();
|
||||
/// <summary>
|
||||
/// Gets the view model that handles displaying the property
|
||||
/// </summary>
|
||||
public DataModelVisualizationViewModel? DisplayViewModel => Children.FirstOrDefault();
|
||||
|
||||
public override string DisplayPath => null;
|
||||
/// <inheritdoc />
|
||||
public override string? DisplayPath => null;
|
||||
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration configuration)
|
||||
/// <inheritdoc />
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||
{
|
||||
((ListPredicateWrapperDataModel) DataModel).UntypedValue = DisplayValue;
|
||||
_listPredicateWrapper.UntypedValue = DisplayValue;
|
||||
|
||||
PopulateProperties(dataModelUIService, configuration);
|
||||
if (DisplayViewModel == null)
|
||||
@ -52,7 +72,8 @@ namespace Artemis.UI.Shared
|
||||
DisplayViewModel.Update(dataModelUIService, null);
|
||||
}
|
||||
|
||||
public override object GetCurrentValue()
|
||||
/// <inheritdoc />
|
||||
public override object? GetCurrentValue()
|
||||
{
|
||||
return DisplayValue;
|
||||
}
|
||||
|
||||
@ -10,19 +10,22 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
public class DataModelListPropertyViewModel : DataModelPropertyViewModel
|
||||
{
|
||||
private readonly ListPredicateWrapperDataModel _listPredicateWrapper;
|
||||
private int _index;
|
||||
private Type _listType;
|
||||
private Type? _listType;
|
||||
|
||||
internal DataModelListPropertyViewModel(Type listType, DataModelDisplayViewModel displayViewModel) : base(null, null, null)
|
||||
{
|
||||
DataModel = ListPredicateWrapperDataModel.Create(listType);
|
||||
_listPredicateWrapper = ListPredicateWrapperDataModel.Create(listType);
|
||||
DataModel = _listPredicateWrapper;
|
||||
ListType = listType;
|
||||
DisplayViewModel = displayViewModel;
|
||||
}
|
||||
|
||||
internal DataModelListPropertyViewModel(Type listType) : base(null, null, null)
|
||||
{
|
||||
DataModel = ListPredicateWrapperDataModel.Create(listType);
|
||||
_listPredicateWrapper = ListPredicateWrapperDataModel.Create(listType);
|
||||
DataModel = _listPredicateWrapper;
|
||||
ListType = listType;
|
||||
}
|
||||
|
||||
@ -38,26 +41,26 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the type of elements contained in the list
|
||||
/// </summary>
|
||||
public Type ListType
|
||||
public Type? ListType
|
||||
{
|
||||
get => _listType;
|
||||
private set => SetAndNotify(ref _listType, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetCurrentValue()
|
||||
public override object? GetCurrentValue()
|
||||
{
|
||||
return DisplayValue;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration configuration)
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||
{
|
||||
// Display value gets updated by parent, don't do anything if it is null
|
||||
if (DisplayValue == null)
|
||||
return;
|
||||
|
||||
((ListPredicateWrapperDataModel) DataModel).UntypedValue = DisplayValue;
|
||||
_listPredicateWrapper.UntypedValue = DisplayValue;
|
||||
|
||||
if (DisplayViewModel == null)
|
||||
DisplayViewModel = dataModelUIService.GetDataModelDisplayViewModel(DisplayValue.GetType(), PropertyDescription, true);
|
||||
|
||||
@ -13,21 +13,22 @@ namespace Artemis.UI.Shared
|
||||
public class DataModelListViewModel : DataModelVisualizationViewModel
|
||||
{
|
||||
private string _countDisplay;
|
||||
private Type _displayValueType;
|
||||
private IEnumerable _list;
|
||||
private Type? _displayValueType;
|
||||
private IEnumerable? _list;
|
||||
private BindableCollection<DataModelVisualizationViewModel> _listChildren;
|
||||
private int _listCount;
|
||||
|
||||
internal DataModelListViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath)
|
||||
: base(dataModel, parent, dataModelPath)
|
||||
{
|
||||
ListChildren = new BindableCollection<DataModelVisualizationViewModel>();
|
||||
_countDisplay = "0 items";
|
||||
_listChildren = new BindableCollection<DataModelVisualizationViewModel>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the instance of the list that is being visualized
|
||||
/// </summary>
|
||||
public IEnumerable List
|
||||
public IEnumerable? List
|
||||
{
|
||||
get => _list;
|
||||
private set => SetAndNotify(ref _list, value);
|
||||
@ -45,7 +46,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the type of elements this list contains and that must be displayed as children
|
||||
/// </summary>
|
||||
public Type DisplayValueType
|
||||
public Type? DisplayValueType
|
||||
{
|
||||
get => _displayValueType;
|
||||
set => SetAndNotify(ref _displayValueType, value);
|
||||
@ -70,7 +71,7 @@ namespace Artemis.UI.Shared
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration configuration)
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||
{
|
||||
if (Parent != null && !Parent.IsVisualizationExpanded)
|
||||
return;
|
||||
@ -86,10 +87,12 @@ namespace Artemis.UI.Shared
|
||||
if (item == null)
|
||||
continue;
|
||||
|
||||
DataModelVisualizationViewModel child;
|
||||
DataModelVisualizationViewModel? child;
|
||||
if (ListChildren.Count <= index)
|
||||
{
|
||||
child = CreateListChild(dataModelUIService, item.GetType());
|
||||
if (child == null)
|
||||
continue;
|
||||
ListChildren.Add(child);
|
||||
}
|
||||
else
|
||||
@ -126,10 +129,10 @@ namespace Artemis.UI.Shared
|
||||
return $"[List] {DisplayPath ?? Path} - {ListCount} item(s)";
|
||||
}
|
||||
|
||||
private DataModelVisualizationViewModel CreateListChild(IDataModelUIService dataModelUIService, Type listType)
|
||||
private DataModelVisualizationViewModel? CreateListChild(IDataModelUIService dataModelUIService, Type listType)
|
||||
{
|
||||
// If a display VM was found, prefer to use that in any case
|
||||
DataModelDisplayViewModel typeViewModel = dataModelUIService.GetDataModelDisplayViewModel(listType, PropertyDescription);
|
||||
DataModelDisplayViewModel? typeViewModel = dataModelUIService.GetDataModelDisplayViewModel(listType, PropertyDescription);
|
||||
if (typeViewModel != null)
|
||||
return new DataModelListPropertyViewModel(listType, typeViewModel);
|
||||
// For primitives, create a property view model, it may be null that is fine
|
||||
|
||||
@ -10,10 +10,10 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
public class DataModelPropertiesViewModel : DataModelVisualizationViewModel
|
||||
{
|
||||
private object _displayValue;
|
||||
private Type _displayValueType;
|
||||
private object? _displayValue;
|
||||
private Type? _displayValueType;
|
||||
|
||||
internal DataModelPropertiesViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath)
|
||||
internal DataModelPropertiesViewModel(DataModel? dataModel, DataModelVisualizationViewModel? parent, DataModelPath? dataModelPath)
|
||||
: base(dataModel, parent, dataModelPath)
|
||||
{
|
||||
}
|
||||
@ -21,7 +21,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the type of the property that is being visualized
|
||||
/// </summary>
|
||||
public Type DisplayValueType
|
||||
public Type? DisplayValueType
|
||||
{
|
||||
get => _displayValueType;
|
||||
private set => SetAndNotify(ref _displayValueType, value);
|
||||
@ -30,19 +30,19 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the value of the property that is being visualized
|
||||
/// </summary>
|
||||
public object DisplayValue
|
||||
public object? DisplayValue
|
||||
{
|
||||
get => _displayValue;
|
||||
private set => SetAndNotify(ref _displayValue, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration configuration)
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||
{
|
||||
DisplayValueType = DataModelPath?.GetPropertyType();
|
||||
|
||||
// Only set a display value if ToString returns useful information and not just the type name
|
||||
object currentValue = GetCurrentValue();
|
||||
object? currentValue = GetCurrentValue();
|
||||
if (currentValue != null && currentValue.ToString() != currentValue.GetType().ToString())
|
||||
DisplayValue = currentValue.ToString();
|
||||
else
|
||||
@ -60,7 +60,7 @@ namespace Artemis.UI.Shared
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetCurrentValue()
|
||||
public override object? GetCurrentValue()
|
||||
{
|
||||
if (Parent == null || Parent.IsRootViewModel || IsRootViewModel)
|
||||
return DataModel;
|
||||
@ -68,7 +68,7 @@ namespace Artemis.UI.Shared
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
public override string? ToString()
|
||||
{
|
||||
return DisplayPath ?? Path;
|
||||
}
|
||||
|
||||
@ -11,11 +11,11 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
public class DataModelPropertyViewModel : DataModelVisualizationViewModel
|
||||
{
|
||||
private object _displayValue;
|
||||
private Type _displayValueType;
|
||||
private DataModelDisplayViewModel _displayViewModel;
|
||||
private object? _displayValue;
|
||||
private Type? _displayValueType;
|
||||
private DataModelDisplayViewModel? _displayViewModel;
|
||||
|
||||
internal DataModelPropertyViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath)
|
||||
internal DataModelPropertyViewModel(DataModel? dataModel, DataModelVisualizationViewModel? parent, DataModelPath? dataModelPath)
|
||||
: base(dataModel, parent, dataModelPath)
|
||||
{
|
||||
}
|
||||
@ -23,7 +23,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the value of the property that is being visualized
|
||||
/// </summary>
|
||||
public object DisplayValue
|
||||
public object? DisplayValue
|
||||
{
|
||||
get => _displayValue;
|
||||
internal set => SetAndNotify(ref _displayValue, value);
|
||||
@ -32,7 +32,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the type of the property that is being visualized
|
||||
/// </summary>
|
||||
public Type DisplayValueType
|
||||
public Type? DisplayValueType
|
||||
{
|
||||
get => _displayValueType;
|
||||
protected set => SetAndNotify(ref _displayValueType, value);
|
||||
@ -41,26 +41,31 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the view model used to display the display value
|
||||
/// </summary>
|
||||
public DataModelDisplayViewModel DisplayViewModel
|
||||
public DataModelDisplayViewModel? DisplayViewModel
|
||||
{
|
||||
get => _displayViewModel;
|
||||
internal set => SetAndNotify(ref _displayViewModel, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration configuration)
|
||||
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||
{
|
||||
if (Parent != null && !Parent.IsVisualizationExpanded && !Parent.IsRootViewModel)
|
||||
return;
|
||||
|
||||
if (DisplayViewModel == null)
|
||||
{
|
||||
DisplayViewModel = dataModelUIService.GetDataModelDisplayViewModel(DataModelPath.GetPropertyType(), PropertyDescription, true);
|
||||
DisplayViewModel.PropertyDescription = DataModelPath.GetPropertyDescription();
|
||||
Type? propertyType = DataModelPath?.GetPropertyType();
|
||||
if (propertyType != null)
|
||||
{
|
||||
DisplayViewModel = dataModelUIService.GetDataModelDisplayViewModel(propertyType, PropertyDescription, true);
|
||||
if (DisplayViewModel != null)
|
||||
DisplayViewModel.PropertyDescription = DataModelPath?.GetPropertyDescription();
|
||||
}
|
||||
}
|
||||
|
||||
DisplayValue = GetCurrentValue();
|
||||
DisplayValueType = DisplayValue != null ? DisplayValue.GetType() : DataModelPath.GetPropertyType();
|
||||
DisplayValueType = DisplayValue != null ? DisplayValue.GetType() : DataModelPath?.GetPropertyType();
|
||||
|
||||
DisplayViewModel?.UpdateValue(DisplayValue);
|
||||
}
|
||||
|
||||
@ -17,24 +17,24 @@ namespace Artemis.UI.Shared
|
||||
{
|
||||
private const int MaxDepth = 4;
|
||||
private BindableCollection<DataModelVisualizationViewModel> _children;
|
||||
private DataModel _dataModel;
|
||||
private DataModel? _dataModel;
|
||||
private bool _isMatchingFilteredTypes;
|
||||
private bool _isVisualizationExpanded;
|
||||
private DataModelVisualizationViewModel _parent;
|
||||
private DataModelPropertyAttribute _propertyDescription;
|
||||
private DataModelVisualizationViewModel? _parent;
|
||||
private DataModelPropertyAttribute? _propertyDescription;
|
||||
|
||||
internal DataModelVisualizationViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath)
|
||||
internal DataModelVisualizationViewModel(DataModel? dataModel, DataModelVisualizationViewModel? parent, DataModelPath? dataModelPath)
|
||||
{
|
||||
DataModel = dataModel;
|
||||
Parent = parent;
|
||||
_dataModel = dataModel;
|
||||
_children = new BindableCollection<DataModelVisualizationViewModel>();
|
||||
_parent = parent;
|
||||
DataModelPath = dataModelPath;
|
||||
Children = new BindableCollection<DataModelVisualizationViewModel>();
|
||||
IsMatchingFilteredTypes = true;
|
||||
|
||||
if (parent == null)
|
||||
IsRootViewModel = true;
|
||||
else
|
||||
PropertyDescription = DataModelPath?.GetPropertyDescription() ?? DataModel.DataModelDescription;
|
||||
PropertyDescription = DataModelPath?.GetPropertyDescription() ?? DataModel?.DataModelDescription;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -45,12 +45,12 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the data model path to the property this view model is visualizing
|
||||
/// </summary>
|
||||
public DataModelPath DataModelPath { get; }
|
||||
public DataModelPath? DataModelPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the path backing this model
|
||||
/// </summary>
|
||||
public string Path => DataModelPath?.Path;
|
||||
public string? Path => DataModelPath?.Path;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property depth of the view model
|
||||
@ -60,7 +60,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the data model backing this view model
|
||||
/// </summary>
|
||||
public DataModel DataModel
|
||||
public DataModel? DataModel
|
||||
{
|
||||
get => _dataModel;
|
||||
protected set => SetAndNotify(ref _dataModel, value);
|
||||
@ -69,7 +69,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the property description of the property this view model is visualizing
|
||||
/// </summary>
|
||||
public DataModelPropertyAttribute PropertyDescription
|
||||
public DataModelPropertyAttribute? PropertyDescription
|
||||
{
|
||||
get => _propertyDescription;
|
||||
protected set => SetAndNotify(ref _propertyDescription, value);
|
||||
@ -78,7 +78,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the parent of this view model
|
||||
/// </summary>
|
||||
public DataModelVisualizationViewModel Parent
|
||||
public DataModelVisualizationViewModel? Parent
|
||||
{
|
||||
get => _parent;
|
||||
protected set => SetAndNotify(ref _parent, value);
|
||||
@ -119,7 +119,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets a user-friendly representation of the <see cref="DataModelPath" />
|
||||
/// </summary>
|
||||
public virtual string DisplayPath => DataModelPath != null
|
||||
public virtual string? DisplayPath => DataModelPath != null
|
||||
? string.Join(" › ", DataModelPath.Segments.Select(s => s.GetPropertyDescription()?.Name ?? s.Identifier))
|
||||
: null;
|
||||
|
||||
@ -128,18 +128,18 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
/// <param name="dataModelUIService">The data model UI service used during update</param>
|
||||
/// <param name="configuration">The configuration to apply while updating</param>
|
||||
public abstract void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration configuration);
|
||||
public abstract void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value of the property being visualized
|
||||
/// </summary>
|
||||
/// <returns>The current value of the property being visualized</returns>
|
||||
public virtual object GetCurrentValue()
|
||||
public virtual object? GetCurrentValue()
|
||||
{
|
||||
if (IsRootViewModel)
|
||||
return null;
|
||||
|
||||
return DataModelPath.GetValue();
|
||||
return DataModelPath?.GetValue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -148,7 +148,7 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
/// <param name="looseMatch">Whether the type may be a loose match, meaning it can be cast or converted</param>
|
||||
/// <param name="filteredTypes">The types to filter</param>
|
||||
public void ApplyTypeFilter(bool looseMatch, params Type[] filteredTypes)
|
||||
public void ApplyTypeFilter(bool looseMatch, params Type[]? filteredTypes)
|
||||
{
|
||||
if (filteredTypes != null)
|
||||
{
|
||||
@ -176,7 +176,7 @@ namespace Artemis.UI.Shared
|
||||
}
|
||||
|
||||
// If the type couldn't be retrieved either way, assume false
|
||||
Type type = DataModelPath?.GetPropertyType();
|
||||
Type? type = DataModelPath?.GetPropertyType();
|
||||
if (type == null)
|
||||
{
|
||||
IsMatchingFilteredTypes = false;
|
||||
@ -197,12 +197,14 @@ namespace Artemis.UI.Shared
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal void PopulateProperties(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration dataModelUpdateConfiguration)
|
||||
internal void PopulateProperties(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? dataModelUpdateConfiguration)
|
||||
{
|
||||
if (IsRootViewModel && DataModel == null)
|
||||
return;
|
||||
|
||||
Type modelType = IsRootViewModel ? DataModel.GetType() : DataModelPath.GetPropertyType();
|
||||
Type? modelType = IsRootViewModel ? DataModel?.GetType() : DataModelPath?.GetPropertyType();
|
||||
if (modelType == null)
|
||||
throw new ArtemisSharedUIException("Failed to populate data model visualization properties, couldn't get a property type");
|
||||
|
||||
// Add missing static children
|
||||
foreach (PropertyInfo propertyInfo in modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance).OrderBy(t => t.MetadataToken))
|
||||
@ -212,27 +214,30 @@ namespace Artemis.UI.Shared
|
||||
continue;
|
||||
if (propertyInfo.GetCustomAttribute<DataModelIgnoreAttribute>() != null)
|
||||
continue;
|
||||
MethodInfo getMethod = propertyInfo.GetGetMethod();
|
||||
MethodInfo? getMethod = propertyInfo.GetGetMethod();
|
||||
if (getMethod == null || getMethod.GetParameters().Any())
|
||||
continue;
|
||||
|
||||
DataModelVisualizationViewModel child = CreateChild(dataModelUIService, childPath, GetChildDepth());
|
||||
DataModelVisualizationViewModel? child = CreateChild(dataModelUIService, childPath, GetChildDepth());
|
||||
if (child != null)
|
||||
Children.Add(child);
|
||||
}
|
||||
|
||||
// Remove static children that should be hidden
|
||||
ReadOnlyCollection<PropertyInfo> hiddenProperties = DataModel.GetHiddenProperties();
|
||||
foreach (PropertyInfo hiddenProperty in hiddenProperties)
|
||||
if (DataModel != null)
|
||||
{
|
||||
string childPath = AppendToPath(hiddenProperty.Name);
|
||||
DataModelVisualizationViewModel toRemove = Children.FirstOrDefault(c => c.Path != null && c.Path == childPath);
|
||||
if (toRemove != null)
|
||||
Children.Remove(toRemove);
|
||||
ReadOnlyCollection<PropertyInfo> hiddenProperties = DataModel.GetHiddenProperties();
|
||||
foreach (PropertyInfo hiddenProperty in hiddenProperties)
|
||||
{
|
||||
string childPath = AppendToPath(hiddenProperty.Name);
|
||||
DataModelVisualizationViewModel? toRemove = Children.FirstOrDefault(c => c.Path != null && c.Path == childPath);
|
||||
if (toRemove != null)
|
||||
Children.Remove(toRemove);
|
||||
}
|
||||
}
|
||||
|
||||
// Add missing dynamic children
|
||||
object value = Parent == null || Parent.IsRootViewModel ? DataModel : DataModelPath.GetValue();
|
||||
object? value = Parent == null || Parent.IsRootViewModel ? DataModel : DataModelPath?.GetValue();
|
||||
if (value is DataModel dataModel)
|
||||
foreach (KeyValuePair<string, DataModel> kvp in dataModel.DynamicDataModels)
|
||||
{
|
||||
@ -240,19 +245,21 @@ namespace Artemis.UI.Shared
|
||||
if (Children.Any(c => c.Path != null && c.Path.Equals(childPath)))
|
||||
continue;
|
||||
|
||||
DataModelVisualizationViewModel child = CreateChild(dataModelUIService, childPath, GetChildDepth());
|
||||
DataModelVisualizationViewModel? child = CreateChild(dataModelUIService, childPath, GetChildDepth());
|
||||
if (child != null)
|
||||
Children.Add(child);
|
||||
}
|
||||
|
||||
// Remove dynamic children that have been removed from the data model
|
||||
List<DataModelVisualizationViewModel> toRemoveDynamic = Children.Where(c => !c.DataModelPath.IsValid).ToList();
|
||||
List<DataModelVisualizationViewModel> toRemoveDynamic = Children.Where(c => c.DataModelPath != null && !c.DataModelPath.IsValid).ToList();
|
||||
if (toRemoveDynamic.Any())
|
||||
Children.RemoveRange(toRemoveDynamic);
|
||||
}
|
||||
|
||||
private DataModelVisualizationViewModel CreateChild(IDataModelUIService dataModelUIService, string path, int depth)
|
||||
private DataModelVisualizationViewModel? CreateChild(IDataModelUIService dataModelUIService, string path, int depth)
|
||||
{
|
||||
if (DataModel == null)
|
||||
throw new ArtemisSharedUIException("Cannot create a data model visualization child VM for a parent without a data model");
|
||||
if (depth > MaxDepth)
|
||||
return null;
|
||||
|
||||
@ -260,8 +267,8 @@ namespace Artemis.UI.Shared
|
||||
if (!dataModelPath.IsValid)
|
||||
return null;
|
||||
|
||||
PropertyInfo propertyInfo = dataModelPath.GetPropertyInfo();
|
||||
Type propertyType = dataModelPath.GetPropertyType();
|
||||
PropertyInfo? propertyInfo = dataModelPath.GetPropertyInfo();
|
||||
Type? propertyType = dataModelPath.GetPropertyType();
|
||||
|
||||
// Skip properties decorated with DataModelIgnore
|
||||
if (propertyInfo != null && Attribute.IsDefined(propertyInfo, typeof(DataModelIgnoreAttribute)))
|
||||
@ -270,8 +277,11 @@ namespace Artemis.UI.Shared
|
||||
if (DataModel.GetHiddenProperties().Any(p => p.Equals(propertyInfo)))
|
||||
return null;
|
||||
|
||||
if (propertyType == null)
|
||||
return null;
|
||||
|
||||
// If a display VM was found, prefer to use that in any case
|
||||
DataModelDisplayViewModel typeViewModel = dataModelUIService.GetDataModelDisplayViewModel(propertyType, PropertyDescription);
|
||||
DataModelDisplayViewModel? typeViewModel = dataModelUIService.GetDataModelDisplayViewModel(propertyType, PropertyDescription);
|
||||
if (typeViewModel != null)
|
||||
return new DataModelPropertyViewModel(DataModel, this, dataModelPath) {DisplayViewModel = typeViewModel, Depth = depth};
|
||||
// For primitives, create a property view model, it may be null that is fine
|
||||
|
||||
@ -9,7 +9,7 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
public class DataModelInputDynamicEventArgs : EventArgs
|
||||
{
|
||||
internal DataModelInputDynamicEventArgs(DataModelPath dataModelPath)
|
||||
internal DataModelInputDynamicEventArgs(DataModelPath? dataModelPath)
|
||||
{
|
||||
DataModelPath = dataModelPath;
|
||||
}
|
||||
@ -17,6 +17,6 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the data model path that was selected
|
||||
/// </summary>
|
||||
public DataModelPath DataModelPath { get; }
|
||||
public DataModelPath? DataModelPath { get; }
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,7 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
public class DataModelInputStaticEventArgs : EventArgs
|
||||
{
|
||||
internal DataModelInputStaticEventArgs(object value)
|
||||
internal DataModelInputStaticEventArgs(object? value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
@ -16,6 +16,6 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// The value that was submitted
|
||||
/// </summary>
|
||||
public object Value { get; }
|
||||
public object? Value { get; }
|
||||
}
|
||||
}
|
||||
@ -8,12 +8,12 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
public class ProfileEventArgs : EventArgs
|
||||
{
|
||||
internal ProfileEventArgs(Profile profile)
|
||||
internal ProfileEventArgs(Profile? profile)
|
||||
{
|
||||
Profile = profile;
|
||||
}
|
||||
|
||||
internal ProfileEventArgs(Profile profile, Profile previousProfile)
|
||||
internal ProfileEventArgs(Profile? profile, Profile? previousProfile)
|
||||
{
|
||||
Profile = profile;
|
||||
PreviousProfile = previousProfile;
|
||||
@ -22,7 +22,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the profile the event was raised for
|
||||
/// </summary>
|
||||
public Profile Profile { get; }
|
||||
public Profile? Profile { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If applicable, the previous active profile before the event was raised
|
||||
|
||||
@ -8,12 +8,12 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
public class RenderProfileElementEventArgs : EventArgs
|
||||
{
|
||||
internal RenderProfileElementEventArgs(RenderProfileElement renderProfileElement)
|
||||
internal RenderProfileElementEventArgs(RenderProfileElement? renderProfileElement)
|
||||
{
|
||||
RenderProfileElement = renderProfileElement;
|
||||
}
|
||||
|
||||
internal RenderProfileElementEventArgs(RenderProfileElement renderProfileElement, RenderProfileElement previousRenderProfileElement)
|
||||
internal RenderProfileElementEventArgs(RenderProfileElement? renderProfileElement, RenderProfileElement? previousRenderProfileElement)
|
||||
{
|
||||
RenderProfileElement = renderProfileElement;
|
||||
PreviousRenderProfileElement = previousRenderProfileElement;
|
||||
@ -22,7 +22,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets the profile element the event was raised for
|
||||
/// </summary>
|
||||
public RenderProfileElement RenderProfileElement { get; }
|
||||
public RenderProfileElement? RenderProfileElement { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If applicable, the previous active profile element before the event was raised
|
||||
|
||||
@ -15,11 +15,6 @@ namespace Artemis.UI.Shared.LayerBrushes
|
||||
/// </summary>
|
||||
public abstract class LayerBrushConfigurationDialog : ILayerBrushConfigurationDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// The layer brush this dialog belongs to
|
||||
/// </summary>
|
||||
internal BaseLayerBrush LayerBrush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of view model the tab contains
|
||||
/// </summary>
|
||||
|
||||
@ -15,10 +15,11 @@ namespace Artemis.UI.Shared.LayerEffects
|
||||
/// </summary>
|
||||
public abstract class LayerEffectConfigurationDialog : ILayerEffectConfigurationDialog
|
||||
{
|
||||
// TODO: See if this is still in use
|
||||
/// <summary>
|
||||
/// The layer effect this dialog belongs to
|
||||
/// </summary>
|
||||
internal BaseLayerEffect LayerEffect { get; set; }
|
||||
public BaseLayerEffect? LayerEffect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of view model the tab contains
|
||||
|
||||
@ -15,11 +15,6 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
public abstract class PluginConfigurationDialog : IPluginConfigurationDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// The layer brush this dialog belongs to
|
||||
/// </summary>
|
||||
internal PluginFeature PluginFeature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of view model the tab contains
|
||||
/// </summary>
|
||||
|
||||
@ -22,9 +22,10 @@ SOFTWARE. */
|
||||
|
||||
using System;
|
||||
|
||||
// ReSharper disable InheritdocConsiderUsage
|
||||
|
||||
#pragma warning disable 8618
|
||||
#pragma warning disable 1591
|
||||
|
||||
// ReSharper disable InheritdocConsiderUsage
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
@ -12,7 +13,7 @@ namespace Artemis.UI.Shared
|
||||
public abstract class PropertyInputViewModel<T> : PropertyInputViewModel
|
||||
{
|
||||
private bool _inputDragging;
|
||||
private T _inputValue;
|
||||
[AllowNull] private T _inputValue = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="PropertyInputViewModel" /> class
|
||||
@ -73,6 +74,7 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets or sets the input value
|
||||
/// </summary>
|
||||
[AllowNull]
|
||||
public T InputValue
|
||||
{
|
||||
get => _inputValue;
|
||||
|
||||
@ -19,13 +19,13 @@ namespace Artemis.UI.Shared.Screens.Dialogs
|
||||
|
||||
public void Confirm()
|
||||
{
|
||||
if (!Session.IsEnded)
|
||||
if (Session != null && !Session.IsEnded)
|
||||
Session.Close(true);
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
if (!Session.IsEnded)
|
||||
if (Session != null && !Session.IsEnded)
|
||||
Session.Close(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,12 +9,12 @@ namespace Artemis.UI.Shared.Screens.Exceptions
|
||||
{
|
||||
private List<DialogException> _exceptions;
|
||||
|
||||
public ExceptionViewModel(string message, Exception exception)
|
||||
public ExceptionViewModel(string message, Exception? exception)
|
||||
{
|
||||
Header = message;
|
||||
Exceptions = new List<DialogException>();
|
||||
_exceptions = new List<DialogException>();
|
||||
|
||||
Exception currentException = exception;
|
||||
Exception? currentException = exception;
|
||||
while (currentException != null)
|
||||
{
|
||||
Exceptions.Add(new DialogException(currentException));
|
||||
|
||||
@ -59,7 +59,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
set => SetAndNotify(ref _willRemoveColorStop, value);
|
||||
}
|
||||
|
||||
private void ColorStopOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
private void ColorStopOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
_gradientEditorViewModel.ColorGradient.OnColorValuesUpdated();
|
||||
}
|
||||
@ -90,7 +90,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
if (!((IInputElement) sender).IsMouseCaptured)
|
||||
return;
|
||||
|
||||
Canvas parent = VisualTreeUtilities.FindParent<Canvas>((DependencyObject) sender, null);
|
||||
Canvas? parent = VisualTreeUtilities.FindParent<Canvas>((DependencyObject) sender, null);
|
||||
Point position = e.GetPosition(parent);
|
||||
if (position.Y > 50)
|
||||
{
|
||||
@ -103,8 +103,8 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
double minValue = 0.0;
|
||||
double maxValue = _gradientEditorViewModel.PreviewWidth;
|
||||
List<ColorGradientStop> stops = _gradientEditorViewModel.ColorGradient.Stops.OrderBy(s => s.Position).ToList();
|
||||
ColorGradientStop previous = stops.IndexOf(ColorStop) >= 1 ? stops[stops.IndexOf(ColorStop) - 1] : null;
|
||||
ColorGradientStop next = stops.IndexOf(ColorStop) + 1 < stops.Count ? stops[stops.IndexOf(ColorStop) + 1] : null;
|
||||
ColorGradientStop? previous = stops.IndexOf(ColorStop) >= 1 ? stops[stops.IndexOf(ColorStop) - 1] : null;
|
||||
ColorGradientStop? next = stops.IndexOf(ColorStop) + 1 < stops.Count ? stops[stops.IndexOf(ColorStop) + 1] : null;
|
||||
if (previous != null)
|
||||
minValue = previous.Position * _gradientEditorViewModel.PreviewWidth;
|
||||
if (next != null)
|
||||
|
||||
@ -14,7 +14,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
{
|
||||
private readonly List<ColorGradientStop> _originalStops;
|
||||
private double _previewWidth;
|
||||
private ColorStopViewModel _selectedColorStopViewModel;
|
||||
private ColorStopViewModel? _selectedColorStopViewModel;
|
||||
|
||||
public GradientEditorViewModel(ColorGradient colorGradient)
|
||||
{
|
||||
@ -28,7 +28,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
|
||||
public BindableCollection<ColorStopViewModel> ColorStopViewModels { get; set; }
|
||||
|
||||
public ColorStopViewModel SelectedColorStopViewModel
|
||||
public ColorStopViewModel? SelectedColorStopViewModel
|
||||
{
|
||||
get => _selectedColorStopViewModel;
|
||||
set
|
||||
@ -50,7 +50,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
|
||||
public void AddColorStop(object sender, MouseEventArgs e)
|
||||
{
|
||||
Canvas child = VisualTreeUtilities.FindChild<Canvas>((DependencyObject) sender, null);
|
||||
Canvas? child = VisualTreeUtilities.FindChild<Canvas>((DependencyObject) sender, null);
|
||||
float position = (float) (e.GetPosition(child).X / PreviewWidth);
|
||||
ColorGradientStop stop = new ColorGradientStop(ColorGradient.GetColor(position), position);
|
||||
ColorGradient.Stops.Add(stop);
|
||||
@ -74,11 +74,11 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
|
||||
public Point GetPositionInPreview(object sender, MouseEventArgs e)
|
||||
{
|
||||
Canvas parent = VisualTreeUtilities.FindParent<Canvas>((DependencyObject) sender, null);
|
||||
Canvas? parent = VisualTreeUtilities.FindParent<Canvas>((DependencyObject) sender, null);
|
||||
return e.GetPosition(parent);
|
||||
}
|
||||
|
||||
public void SelectColorStop(ColorStopViewModel colorStopViewModel)
|
||||
public void SelectColorStop(ColorStopViewModel? colorStopViewModel)
|
||||
{
|
||||
SelectedColorStopViewModel = colorStopViewModel;
|
||||
foreach (ColorStopViewModel stopViewModel in ColorStopViewModels)
|
||||
@ -87,7 +87,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
|
||||
public void Confirm()
|
||||
{
|
||||
if (!Session.IsEnded)
|
||||
if (Session != null && !Session.IsEnded)
|
||||
Session.Close(true);
|
||||
}
|
||||
|
||||
@ -98,11 +98,11 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
ColorGradient.Stops.AddRange(_originalStops);
|
||||
ColorGradient.OnColorValuesUpdated();
|
||||
|
||||
if (!Session.IsEnded)
|
||||
if (Session != null && !Session.IsEnded)
|
||||
Session.Close(false);
|
||||
}
|
||||
|
||||
private void UpdateColorStopViewModels(object sender, PropertyChangedEventArgs e)
|
||||
private void UpdateColorStopViewModels(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName != nameof(PreviewWidth)) return;
|
||||
foreach (ColorGradientStop colorStop in ColorGradient.Stops.OrderBy(s => s.Position))
|
||||
|
||||
@ -56,7 +56,7 @@ namespace Artemis.UI.Shared.Services
|
||||
_overlayColor = new SKColor(color.R, color.G, color.B, color.A);
|
||||
}
|
||||
|
||||
private void RenderColorPickerOverlay(object sender, FrameRenderingEventArgs e)
|
||||
private void RenderColorPickerOverlay(object? sender, FrameRenderingEventArgs e)
|
||||
{
|
||||
if (_mustRenderOverlay)
|
||||
_overlayOpacity += 0.2f;
|
||||
|
||||
@ -46,7 +46,9 @@ namespace Artemis.UI.Shared.Services
|
||||
|
||||
public void UpdateModules(DataModelPropertiesViewModel mainDataModelVisualization)
|
||||
{
|
||||
List<DataModelVisualizationViewModel> disabledChildren = mainDataModelVisualization.Children.Where(d => !d.DataModel.Feature.IsEnabled).ToList();
|
||||
List<DataModelVisualizationViewModel> disabledChildren = mainDataModelVisualization.Children
|
||||
.Where(d => d.DataModel != null && !d.DataModel.Feature.IsEnabled)
|
||||
.ToList();
|
||||
foreach (DataModelVisualizationViewModel child in disabledChildren)
|
||||
mainDataModelVisualization.Children.Remove(child);
|
||||
|
||||
@ -63,24 +65,24 @@ namespace Artemis.UI.Shared.Services
|
||||
mainDataModelVisualization.Update(this, null);
|
||||
}
|
||||
|
||||
public DataModelPropertiesViewModel GetPluginDataModelVisualization(PluginFeature pluginFeature, bool includeMainDataModel)
|
||||
public DataModelPropertiesViewModel? GetPluginDataModelVisualization(PluginFeature pluginFeature, bool includeMainDataModel)
|
||||
{
|
||||
if (includeMainDataModel)
|
||||
{
|
||||
DataModelPropertiesViewModel mainDataModel = GetMainDataModelVisualization();
|
||||
|
||||
// If the main data model already includes the plugin data model we're done
|
||||
if (mainDataModel.Children.Any(c => c.DataModel.Feature == pluginFeature))
|
||||
if (mainDataModel.Children.Any(c => c.DataModel?.Feature == pluginFeature))
|
||||
return mainDataModel;
|
||||
// Otherwise get just the plugin data model and add it
|
||||
DataModelPropertiesViewModel pluginDataModel = GetPluginDataModelVisualization(pluginFeature, false);
|
||||
DataModelPropertiesViewModel? pluginDataModel = GetPluginDataModelVisualization(pluginFeature, false);
|
||||
if (pluginDataModel != null)
|
||||
mainDataModel.Children.Add(pluginDataModel);
|
||||
|
||||
return mainDataModel;
|
||||
}
|
||||
|
||||
DataModel dataModel = _dataModelService.GetPluginDataModel(pluginFeature);
|
||||
DataModel? dataModel = _dataModelService.GetPluginDataModel(pluginFeature);
|
||||
if (dataModel == null)
|
||||
return null;
|
||||
|
||||
@ -93,15 +95,14 @@ namespace Artemis.UI.Shared.Services
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
public DataModelVisualizationRegistration RegisterDataModelInput<T>(Plugin plugin, IReadOnlyCollection<Type> compatibleConversionTypes = null) where T : DataModelInputViewModel
|
||||
public DataModelVisualizationRegistration RegisterDataModelInput<T>(Plugin plugin, IReadOnlyCollection<Type>? compatibleConversionTypes = null) where T : DataModelInputViewModel
|
||||
{
|
||||
if (compatibleConversionTypes == null)
|
||||
compatibleConversionTypes = new List<Type>();
|
||||
compatibleConversionTypes ??= new List<Type>();
|
||||
Type viewModelType = typeof(T);
|
||||
lock (_registeredDataModelEditors)
|
||||
{
|
||||
Type supportedType = viewModelType.BaseType.GetGenericArguments()[0];
|
||||
DataModelVisualizationRegistration existing = _registeredDataModelEditors.FirstOrDefault(r => r.SupportedType == supportedType);
|
||||
Type supportedType = viewModelType.BaseType!.GetGenericArguments()[0];
|
||||
DataModelVisualizationRegistration? existing = _registeredDataModelEditors.FirstOrDefault(r => r.SupportedType == supportedType);
|
||||
if (existing != null)
|
||||
{
|
||||
if (existing.Plugin != plugin)
|
||||
@ -129,8 +130,8 @@ namespace Artemis.UI.Shared.Services
|
||||
Type viewModelType = typeof(T);
|
||||
lock (_registeredDataModelDisplays)
|
||||
{
|
||||
Type supportedType = viewModelType.BaseType.GetGenericArguments()[0];
|
||||
DataModelVisualizationRegistration existing = _registeredDataModelDisplays.FirstOrDefault(r => r.SupportedType == supportedType);
|
||||
Type supportedType = viewModelType.BaseType!.GetGenericArguments()[0];
|
||||
DataModelVisualizationRegistration? existing = _registeredDataModelDisplays.FirstOrDefault(r => r.SupportedType == supportedType);
|
||||
if (existing != null)
|
||||
{
|
||||
if (existing.Plugin != plugin)
|
||||
@ -174,15 +175,21 @@ namespace Artemis.UI.Shared.Services
|
||||
}
|
||||
}
|
||||
|
||||
public DataModelDisplayViewModel GetDataModelDisplayViewModel(Type propertyType, DataModelPropertyAttribute description, bool fallBackToDefault)
|
||||
public DataModelDisplayViewModel? GetDataModelDisplayViewModel(Type propertyType, DataModelPropertyAttribute? description, bool fallBackToDefault)
|
||||
{
|
||||
lock (_registeredDataModelDisplays)
|
||||
{
|
||||
DataModelDisplayViewModel result;
|
||||
DataModelDisplayViewModel? result;
|
||||
|
||||
DataModelVisualizationRegistration match = _registeredDataModelDisplays.FirstOrDefault(d => d.SupportedType == propertyType);
|
||||
DataModelVisualizationRegistration? match = _registeredDataModelDisplays.FirstOrDefault(d => d.SupportedType == propertyType);
|
||||
if (match != null)
|
||||
{
|
||||
// If this ever happens something is likely wrong with the plugin unload detection
|
||||
if (match.Plugin.Kernel == null)
|
||||
throw new ArtemisSharedUIException("Cannot GetDataModelDisplayViewModel for a registration by an uninitialized plugin");
|
||||
|
||||
result = (DataModelDisplayViewModel) match.Plugin.Kernel.Get(match.ViewModelType);
|
||||
}
|
||||
else if (!fallBackToDefault)
|
||||
result = null;
|
||||
else
|
||||
@ -195,15 +202,15 @@ namespace Artemis.UI.Shared.Services
|
||||
}
|
||||
}
|
||||
|
||||
public DataModelInputViewModel GetDataModelInputViewModel(Type propertyType, DataModelPropertyAttribute description, object initialValue, Action<object, bool> updateCallback)
|
||||
public DataModelInputViewModel? GetDataModelInputViewModel(Type propertyType, DataModelPropertyAttribute? description, object? initialValue, Action<object?, bool> updateCallback)
|
||||
{
|
||||
lock (_registeredDataModelEditors)
|
||||
{
|
||||
// Prefer a VM that natively supports the type
|
||||
DataModelVisualizationRegistration match = _registeredDataModelEditors.FirstOrDefault(d => d.SupportedType == propertyType);
|
||||
DataModelVisualizationRegistration? match = _registeredDataModelEditors.FirstOrDefault(d => d.SupportedType == propertyType);
|
||||
// Fall back on a VM that supports the type through conversion
|
||||
if (match == null)
|
||||
match = _registeredDataModelEditors.FirstOrDefault(d => d.CompatibleConversionTypes.Contains(propertyType));
|
||||
match = _registeredDataModelEditors.FirstOrDefault(d => d.CompatibleConversionTypes != null && d.CompatibleConversionTypes.Contains(propertyType));
|
||||
// Lastly try getting an enum VM if the provided type is an enum
|
||||
if (match == null && propertyType.IsEnum)
|
||||
match = _registeredDataModelEditors.FirstOrDefault(d => d.SupportedType == typeof(Enum));
|
||||
@ -229,7 +236,7 @@ namespace Artemis.UI.Shared.Services
|
||||
return _dataModelVmFactory.DataModelStaticViewModel(targetType, targetDescription);
|
||||
}
|
||||
|
||||
private DataModelInputViewModel InstantiateDataModelInputViewModel(DataModelVisualizationRegistration registration, DataModelPropertyAttribute description, object initialValue)
|
||||
private DataModelInputViewModel InstantiateDataModelInputViewModel(DataModelVisualizationRegistration registration, DataModelPropertyAttribute? description, object? initialValue)
|
||||
{
|
||||
// This assumes the type can be converted, that has been checked when the VM was created
|
||||
if (initialValue != null && initialValue.GetType() != registration.SupportedType)
|
||||
@ -240,6 +247,11 @@ namespace Artemis.UI.Shared.Services
|
||||
new ConstructorArgument("targetDescription", description),
|
||||
new ConstructorArgument("initialValue", initialValue)
|
||||
};
|
||||
|
||||
// If this ever happens something is likely wrong with the plugin unload detection
|
||||
if (registration.Plugin.Kernel == null)
|
||||
throw new ArtemisSharedUIException("Cannot InstantiateDataModelInputViewModel for a registration by an uninitialized plugin");
|
||||
|
||||
DataModelInputViewModel viewModel = (DataModelInputViewModel) registration.Plugin.Kernel.Get(registration.ViewModelType, parameters);
|
||||
viewModel.CompatibleConversionTypes = registration.CompatibleConversionTypes;
|
||||
return viewModel;
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Artemis.Core;
|
||||
@ -16,13 +14,12 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Shared.Services
|
||||
{
|
||||
// TODO: Become plugin-aware and use plugin kernel if injected into a plugin
|
||||
internal class DialogService : IDialogService
|
||||
{
|
||||
private readonly IKernel _kernel;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly IViewManager _viewManager;
|
||||
private readonly IWindowManager _windowManager;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
|
||||
public DialogService(IKernel kernel, IViewManager viewManager, IWindowManager windowManager, IPluginManagementService pluginManagementService)
|
||||
{
|
||||
@ -35,12 +32,12 @@ namespace Artemis.UI.Shared.Services
|
||||
private async Task<object> ShowDialog<T>(IParameter[] parameters) where T : DialogViewModelBase
|
||||
{
|
||||
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
|
||||
return await ShowDialog("RootDialog", _kernel.Get<T>(parameters));
|
||||
return await ShowDialog("RootDialog", GetBestKernel().Get<T>(parameters));
|
||||
}
|
||||
|
||||
private async Task<object> ShowDialog(string identifier, DialogViewModelBase viewModel)
|
||||
private async Task<object> ShowDialog(string? identifier, DialogViewModelBase viewModel)
|
||||
{
|
||||
Task<object> result = null;
|
||||
Task<object>? result = null;
|
||||
await Execute.OnUIThreadAsync(() =>
|
||||
{
|
||||
UIElement view = _viewManager.CreateViewForModel(viewModel);
|
||||
@ -52,12 +49,22 @@ namespace Artemis.UI.Shared.Services
|
||||
result = DialogHost.Show(view, identifier, viewModel.OnDialogOpened, viewModel.OnDialogClosed);
|
||||
});
|
||||
|
||||
if (result == null)
|
||||
throw new ArtemisSharedUIException("Failed to show dialog host");
|
||||
return await result;
|
||||
}
|
||||
|
||||
private async Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters) where T : DialogViewModelBase
|
||||
{
|
||||
if (parameters == null)
|
||||
throw new ArgumentNullException(nameof(parameters));
|
||||
return await ShowDialog(identifier, GetBestKernel().Get<T>(parameters));
|
||||
}
|
||||
|
||||
public async Task<bool> ShowConfirmDialog(string header, string text, string confirmText = "Confirm", string cancelText = "Cancel")
|
||||
{
|
||||
IParameter[] arguments = {
|
||||
IParameter[] arguments =
|
||||
{
|
||||
new ConstructorArgument("header", header),
|
||||
new ConstructorArgument("text", text),
|
||||
new ConstructorArgument("confirmText", confirmText.ToUpper()),
|
||||
@ -69,7 +76,9 @@ namespace Artemis.UI.Shared.Services
|
||||
|
||||
public async Task<bool> ShowConfirmDialogAt(string identifier, string header, string text, string confirmText = "Confirm", string cancelText = "Cancel")
|
||||
{
|
||||
IParameter[] arguments = {
|
||||
if (identifier == null) throw new ArgumentNullException(nameof(identifier));
|
||||
IParameter[] arguments =
|
||||
{
|
||||
new ConstructorArgument("header", header),
|
||||
new ConstructorArgument("text", text),
|
||||
new ConstructorArgument("confirmText", confirmText.ToUpper()),
|
||||
@ -81,7 +90,7 @@ namespace Artemis.UI.Shared.Services
|
||||
|
||||
public async Task<object> ShowDialog<T>() where T : DialogViewModelBase
|
||||
{
|
||||
return await ShowDialog("RootDialog", _kernel.Get<T>());
|
||||
return await ShowDialog("RootDialog", GetBestKernel().Get<T>());
|
||||
}
|
||||
|
||||
public Task<object> ShowDialog<T>(Dictionary<string, object> parameters) where T : DialogViewModelBase
|
||||
@ -95,32 +104,28 @@ namespace Artemis.UI.Shared.Services
|
||||
|
||||
public async Task<object> ShowDialogAt<T>(string identifier) where T : DialogViewModelBase
|
||||
{
|
||||
return await ShowDialog(identifier, _kernel.Get<T>());
|
||||
if (identifier == null) throw new ArgumentNullException(nameof(identifier));
|
||||
return await ShowDialog(identifier, GetBestKernel().Get<T>());
|
||||
}
|
||||
|
||||
public async Task<object> ShowDialogAt<T>(string identifier, Dictionary<string, object> parameters) where T : DialogViewModelBase
|
||||
{
|
||||
if (parameters == null)
|
||||
throw new ArgumentNullException(nameof(parameters));
|
||||
if (identifier == null) throw new ArgumentNullException(nameof(identifier));
|
||||
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
|
||||
|
||||
IParameter[] paramsArray = parameters.Select(kv => new ConstructorArgument(kv.Key, kv.Value)).Cast<IParameter>().ToArray();
|
||||
return await ShowDialogAt<T>(identifier, paramsArray);
|
||||
}
|
||||
|
||||
private async Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters) where T : DialogViewModelBase
|
||||
{
|
||||
Plugin callingPlugin = _pluginManagementService.GetCallingPlugin();
|
||||
if (parameters == null)
|
||||
throw new ArgumentNullException(nameof(parameters));
|
||||
|
||||
if (callingPlugin != null)
|
||||
return await ShowDialog(identifier, callingPlugin.Kernel.Get<T>(parameters));
|
||||
return await ShowDialog(identifier, _kernel.Get<T>(parameters));
|
||||
}
|
||||
|
||||
public void ShowExceptionDialog(string message, Exception exception)
|
||||
{
|
||||
_windowManager.ShowDialog(new ExceptionViewModel(message, exception));
|
||||
}
|
||||
|
||||
private IKernel GetBestKernel()
|
||||
{
|
||||
Plugin? callingPlugin = _pluginManagementService.GetCallingPlugin();
|
||||
return callingPlugin?.Kernel ?? _kernel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,7 +13,7 @@ namespace Artemis.UI.Shared.Services
|
||||
_viewManager = viewManager;
|
||||
}
|
||||
|
||||
public DialogViewModelBase ActiveDialogViewModel { get; set; }
|
||||
public DialogViewModelBase? ActiveDialogViewModel { get; set; }
|
||||
public bool IsOpen { get; set; }
|
||||
|
||||
public void OpenDialog(DialogViewModelBase viewModel, string dialogIdentifier)
|
||||
|
||||
@ -37,7 +37,7 @@ namespace Artemis.UI.Shared.Services
|
||||
/// <param name="pluginFeature">The plugin feature to create hte data model visualization view model for</param>
|
||||
/// <param name="includeMainDataModel">Whether or not also to include the main data model</param>
|
||||
/// <returns>A data model visualization view model containing the data model of the provided feature</returns>
|
||||
DataModelPropertiesViewModel GetPluginDataModelVisualization(PluginFeature pluginFeature, bool includeMainDataModel);
|
||||
DataModelPropertiesViewModel? GetPluginDataModelVisualization(PluginFeature pluginFeature, bool includeMainDataModel);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the children of the provided main data model visualization, removing disabled children and adding newly
|
||||
@ -89,7 +89,7 @@ namespace Artemis.UI.Shared.Services
|
||||
/// returned if nothing else is found
|
||||
/// </param>
|
||||
/// <returns>The most appropriate display view model for the provided <paramref name="propertyType"></paramref></returns>
|
||||
DataModelDisplayViewModel GetDataModelDisplayViewModel(Type propertyType, DataModelPropertyAttribute description, bool fallBackToDefault = false);
|
||||
DataModelDisplayViewModel? GetDataModelDisplayViewModel(Type propertyType, DataModelPropertyAttribute? description, bool fallBackToDefault = false);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the most appropriate input view model for the provided <paramref name="propertyType" /> that allows
|
||||
@ -100,7 +100,7 @@ namespace Artemis.UI.Shared.Services
|
||||
/// <param name="initialValue">The initial value to show in the input</param>
|
||||
/// <param name="updateCallback">A function to call whenever the input was updated (submitted or not)</param>
|
||||
/// <returns>The most appropriate input view model for the provided <paramref name="propertyType" /></returns>
|
||||
DataModelInputViewModel GetDataModelInputViewModel(Type propertyType, DataModelPropertyAttribute description, object initialValue, Action<object, bool> updateCallback);
|
||||
DataModelInputViewModel? GetDataModelInputViewModel(Type propertyType, DataModelPropertyAttribute? description, object? initialValue, Action<object?, bool> updateCallback);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a view model that allows selecting a value from the data model
|
||||
|
||||
@ -14,17 +14,17 @@ namespace Artemis.UI.Shared.Services
|
||||
/// <summary>
|
||||
/// Gets the currently selected profile
|
||||
/// </summary>
|
||||
Profile SelectedProfile { get; }
|
||||
Profile? SelectedProfile { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the currently selected profile element
|
||||
/// </summary>
|
||||
RenderProfileElement SelectedProfileElement { get; }
|
||||
RenderProfileElement? SelectedProfileElement { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the currently selected data binding property
|
||||
/// </summary>
|
||||
ILayerProperty SelectedDataBinding { get; }
|
||||
ILayerProperty? SelectedDataBinding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current time
|
||||
@ -45,7 +45,7 @@ namespace Artemis.UI.Shared.Services
|
||||
/// Changes the selected profile
|
||||
/// </summary>
|
||||
/// <param name="profile">The profile to select</param>
|
||||
void ChangeSelectedProfile(Profile profile);
|
||||
void ChangeSelectedProfile(Profile? profile);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the selected profile and saves it to persistent storage
|
||||
@ -56,7 +56,7 @@ namespace Artemis.UI.Shared.Services
|
||||
/// Changes the selected profile element
|
||||
/// </summary>
|
||||
/// <param name="profileElement">The profile element to select</param>
|
||||
void ChangeSelectedProfileElement(RenderProfileElement profileElement);
|
||||
void ChangeSelectedProfileElement(RenderProfileElement? profileElement);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the selected profile element and saves the profile it is contained in to persistent storage
|
||||
@ -67,7 +67,7 @@ namespace Artemis.UI.Shared.Services
|
||||
/// Changes the selected data binding property
|
||||
/// </summary>
|
||||
/// <param name="layerProperty">The data binding property to select</param>
|
||||
void ChangeSelectedDataBinding(ILayerProperty layerProperty);
|
||||
void ChangeSelectedDataBinding(ILayerProperty? layerProperty);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the profile preview, forcing UI-elements to re-render
|
||||
@ -90,7 +90,7 @@ namespace Artemis.UI.Shared.Services
|
||||
/// Gets the current module the profile editor is initialized for
|
||||
/// </summary>
|
||||
/// <returns>The current module the profile editor is initialized for</returns>
|
||||
ProfileModule GetCurrentModule();
|
||||
ProfileModule? GetCurrentModule();
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a new profile is selected
|
||||
@ -173,6 +173,6 @@ namespace Artemis.UI.Shared.Services
|
||||
/// If a matching registration is found, creates a new <see cref="PropertyInputViewModel{T}" /> supporting
|
||||
/// <typeparamref name="T" />
|
||||
/// </summary>
|
||||
PropertyInputViewModel<T> CreatePropertyInputViewModel<T>(LayerProperty<T> layerProperty);
|
||||
PropertyInputViewModel<T>? CreatePropertyInputViewModel<T>(LayerProperty<T> layerProperty);
|
||||
}
|
||||
}
|
||||
@ -22,7 +22,7 @@ namespace Artemis.UI.Shared.Services
|
||||
private readonly object _selectedProfileLock = new object();
|
||||
private TimeSpan _currentTime;
|
||||
private int _pixelsPerSecond;
|
||||
private IKernel _kernel;
|
||||
private readonly IKernel _kernel;
|
||||
|
||||
public ProfileEditorService(IProfileService profileService, IKernel kernel, ILogger logger, ICoreService coreService)
|
||||
{
|
||||
@ -42,9 +42,9 @@ namespace Artemis.UI.Shared.Services
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<PropertyInputRegistration> RegisteredPropertyEditors => _registeredPropertyEditors.AsReadOnly();
|
||||
public Profile SelectedProfile { get; private set; }
|
||||
public RenderProfileElement SelectedProfileElement { get; private set; }
|
||||
public ILayerProperty SelectedDataBinding { get; private set; }
|
||||
public Profile? SelectedProfile { get; private set; }
|
||||
public RenderProfileElement? SelectedProfileElement { get; private set; }
|
||||
public ILayerProperty? SelectedDataBinding { get; private set; }
|
||||
|
||||
public TimeSpan CurrentTime
|
||||
{
|
||||
@ -71,7 +71,7 @@ namespace Artemis.UI.Shared.Services
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeSelectedProfile(Profile profile)
|
||||
public void ChangeSelectedProfile(Profile? profile)
|
||||
{
|
||||
lock (_selectedProfileLock)
|
||||
{
|
||||
@ -103,14 +103,16 @@ namespace Artemis.UI.Shared.Services
|
||||
lock (_selectedProfileLock)
|
||||
{
|
||||
_logger.Verbose("UpdateSelectedProfile {profile}", SelectedProfile);
|
||||
_profileService.UpdateProfile(SelectedProfile, true);
|
||||
if (SelectedProfile == null)
|
||||
return;
|
||||
|
||||
_profileService.UpdateProfile(SelectedProfile, true);
|
||||
OnSelectedProfileChanged(new ProfileEventArgs(SelectedProfile));
|
||||
UpdateProfilePreview();
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeSelectedProfileElement(RenderProfileElement profileElement)
|
||||
public void ChangeSelectedProfileElement(RenderProfileElement? profileElement)
|
||||
{
|
||||
lock (_selectedProfileElementLock)
|
||||
{
|
||||
@ -131,13 +133,16 @@ namespace Artemis.UI.Shared.Services
|
||||
lock (_selectedProfileElementLock)
|
||||
{
|
||||
_logger.Verbose("UpdateSelectedProfileElement {profile}", SelectedProfileElement);
|
||||
if (SelectedProfile == null)
|
||||
return;
|
||||
|
||||
_profileService.UpdateProfile(SelectedProfile, true);
|
||||
UpdateProfilePreview();
|
||||
OnSelectedProfileElementUpdated(new RenderProfileElementEventArgs(SelectedProfileElement));
|
||||
UpdateProfilePreview();
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeSelectedDataBinding(ILayerProperty layerProperty)
|
||||
public void ChangeSelectedDataBinding(ILayerProperty? layerProperty)
|
||||
{
|
||||
SelectedDataBinding = layerProperty;
|
||||
OnSelectedDataBindingChanged();
|
||||
@ -159,6 +164,9 @@ namespace Artemis.UI.Shared.Services
|
||||
|
||||
public bool UndoUpdateProfile()
|
||||
{
|
||||
if (SelectedProfile == null)
|
||||
return false;
|
||||
|
||||
bool undid = _profileService.UndoUpdateProfile(SelectedProfile);
|
||||
if (!undid)
|
||||
return false;
|
||||
@ -169,6 +177,9 @@ namespace Artemis.UI.Shared.Services
|
||||
|
||||
public bool RedoUpdateProfile()
|
||||
{
|
||||
if (SelectedProfile == null)
|
||||
return false;
|
||||
|
||||
bool redid = _profileService.RedoUpdateProfile(SelectedProfile);
|
||||
if (!redid)
|
||||
return false;
|
||||
@ -189,7 +200,8 @@ namespace Artemis.UI.Shared.Services
|
||||
|
||||
lock (_registeredPropertyEditors)
|
||||
{
|
||||
Type supportedType = viewModelType.BaseType.GetGenericArguments()[0];
|
||||
// Indirectly checked if there's a BaseType above
|
||||
Type supportedType = viewModelType.BaseType!.GetGenericArguments()[0];
|
||||
// If the supported type is a generic, assume there is a base type
|
||||
if (supportedType.IsGenericParameter)
|
||||
{
|
||||
@ -198,7 +210,7 @@ namespace Artemis.UI.Shared.Services
|
||||
supportedType = supportedType.BaseType;
|
||||
}
|
||||
|
||||
PropertyInputRegistration existing = _registeredPropertyEditors.FirstOrDefault(r => r.SupportedType == supportedType);
|
||||
PropertyInputRegistration? existing = _registeredPropertyEditors.FirstOrDefault(r => r.SupportedType == supportedType);
|
||||
if (existing != null)
|
||||
{
|
||||
if (existing.Plugin != plugin)
|
||||
@ -228,9 +240,9 @@ namespace Artemis.UI.Shared.Services
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan SnapToTimeline(TimeSpan time, TimeSpan tolerance, bool snapToSegments, bool snapToCurrentTime, List<TimeSpan> snapTimes = null)
|
||||
public TimeSpan SnapToTimeline(TimeSpan time, TimeSpan tolerance, bool snapToSegments, bool snapToCurrentTime, List<TimeSpan>? snapTimes = null)
|
||||
{
|
||||
if (snapToSegments)
|
||||
if (snapToSegments && SelectedProfileElement != null)
|
||||
{
|
||||
// Snap to the end of the start segment
|
||||
if (Math.Abs(time.TotalMilliseconds - SelectedProfileElement.Timeline.StartSegmentEndPosition.TotalMilliseconds) < tolerance.TotalMilliseconds)
|
||||
@ -255,7 +267,7 @@ namespace Artemis.UI.Shared.Services
|
||||
if (snapTimes != null)
|
||||
{
|
||||
// Find the closest keyframe
|
||||
TimeSpan closeSnapTime = snapTimes.FirstOrDefault(s => Math.Abs(time.TotalMilliseconds - s.TotalMilliseconds) < tolerance.TotalMilliseconds);
|
||||
TimeSpan closeSnapTime = snapTimes.FirstOrDefault(s => Math.Abs(time.TotalMilliseconds - s.TotalMilliseconds) < tolerance.TotalMilliseconds)!;
|
||||
if (closeSnapTime != TimeSpan.Zero)
|
||||
return closeSnapTime;
|
||||
}
|
||||
@ -263,10 +275,10 @@ namespace Artemis.UI.Shared.Services
|
||||
return time;
|
||||
}
|
||||
|
||||
public PropertyInputViewModel<T> CreatePropertyInputViewModel<T>(LayerProperty<T> layerProperty)
|
||||
public PropertyInputViewModel<T>? CreatePropertyInputViewModel<T>(LayerProperty<T> layerProperty)
|
||||
{
|
||||
Type viewModelType = null;
|
||||
PropertyInputRegistration registration = RegisteredPropertyEditors.FirstOrDefault(r => r.SupportedType == typeof(T));
|
||||
Type? viewModelType = null;
|
||||
PropertyInputRegistration? registration = RegisteredPropertyEditors.FirstOrDefault(r => r.SupportedType == typeof(T));
|
||||
|
||||
// Check for enums if no supported type was found
|
||||
if (registration == null && typeof(T).IsEnum)
|
||||
@ -281,22 +293,30 @@ namespace Artemis.UI.Shared.Services
|
||||
else
|
||||
return null;
|
||||
|
||||
if (viewModelType == null)
|
||||
return null;
|
||||
|
||||
ConstructorArgument parameter = new ConstructorArgument("layerProperty", layerProperty);
|
||||
IKernel kernel = registration != null ? registration.Plugin.Kernel : _kernel;
|
||||
// ReSharper disable once InconsistentlySynchronizedField
|
||||
// When you've just spent the last 2 hours trying to figure out a deadlock and reach this line, I'm so, so sorry. I thought this would be fine.
|
||||
IKernel kernel = registration?.Plugin.Kernel ?? _kernel;
|
||||
return (PropertyInputViewModel<T>) kernel.Get(viewModelType, parameter);
|
||||
}
|
||||
|
||||
public ProfileModule GetCurrentModule()
|
||||
public ProfileModule? GetCurrentModule()
|
||||
{
|
||||
return SelectedProfile?.Module;
|
||||
}
|
||||
|
||||
private void ReloadProfile()
|
||||
{
|
||||
if (SelectedProfile == null)
|
||||
return;
|
||||
|
||||
// Trigger a profile change
|
||||
OnSelectedProfileChanged(new ProfileEventArgs(SelectedProfile, SelectedProfile));
|
||||
// Trigger a selected element change
|
||||
RenderProfileElement previousSelectedProfileElement = SelectedProfileElement;
|
||||
RenderProfileElement? previousSelectedProfileElement = SelectedProfileElement;
|
||||
if (SelectedProfileElement is Folder folder)
|
||||
SelectedProfileElement = SelectedProfile.GetAllFolders().FirstOrDefault(f => f.EntityId == folder.EntityId);
|
||||
else if (SelectedProfileElement is Layer layer)
|
||||
@ -305,22 +325,24 @@ namespace Artemis.UI.Shared.Services
|
||||
// Trigger selected data binding change
|
||||
if (SelectedDataBinding != null)
|
||||
{
|
||||
SelectedDataBinding = SelectedProfileElement?.GetAllLayerProperties()?.FirstOrDefault(p => p.Path == SelectedDataBinding.Path);
|
||||
SelectedDataBinding = SelectedProfileElement?.GetAllLayerProperties().FirstOrDefault(p => p.Path == SelectedDataBinding.Path);
|
||||
OnSelectedDataBindingChanged();
|
||||
}
|
||||
|
||||
UpdateProfilePreview();
|
||||
}
|
||||
|
||||
public event EventHandler<ProfileEventArgs> ProfileSelected;
|
||||
public event EventHandler<ProfileEventArgs> SelectedProfileUpdated;
|
||||
public event EventHandler<RenderProfileElementEventArgs> ProfileElementSelected;
|
||||
public event EventHandler<RenderProfileElementEventArgs> SelectedProfileElementUpdated;
|
||||
public event EventHandler SelectedDataBindingChanged;
|
||||
public event EventHandler CurrentTimeChanged;
|
||||
public event EventHandler PixelsPerSecondChanged;
|
||||
public event EventHandler ProfilePreviewUpdated;
|
||||
public event EventHandler CurrentTimelineChanged;
|
||||
#region Events
|
||||
|
||||
public event EventHandler<ProfileEventArgs>? ProfileSelected;
|
||||
public event EventHandler<ProfileEventArgs>? SelectedProfileUpdated;
|
||||
public event EventHandler<RenderProfileElementEventArgs>? ProfileElementSelected;
|
||||
public event EventHandler<RenderProfileElementEventArgs>? SelectedProfileElementUpdated;
|
||||
public event EventHandler? SelectedDataBindingChanged;
|
||||
public event EventHandler? CurrentTimeChanged;
|
||||
public event EventHandler? PixelsPerSecondChanged;
|
||||
public event EventHandler? ProfilePreviewUpdated;
|
||||
public event EventHandler? CurrentTimelineChanged;
|
||||
|
||||
protected virtual void OnSelectedProfileChanged(ProfileEventArgs e)
|
||||
{
|
||||
@ -367,10 +389,13 @@ namespace Artemis.UI.Shared.Services
|
||||
SelectedDataBindingChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void SelectedProfileOnDeactivated(object sender, EventArgs e)
|
||||
private void SelectedProfileOnDeactivated(object? sender, EventArgs e)
|
||||
{
|
||||
// Execute.PostToUIThread(() => ChangeSelectedProfile(null));
|
||||
ChangeSelectedProfile(null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@ -9,8 +9,8 @@ namespace Artemis.UI.Shared
|
||||
/// </summary>
|
||||
public class ShortcutUtilities
|
||||
{
|
||||
private static readonly Type m_type = Type.GetTypeFromProgID("WScript.Shell");
|
||||
private static readonly object m_shell = Activator.CreateInstance(m_type);
|
||||
private static readonly Type MType = Type.GetTypeFromProgID("WScript.Shell")!;
|
||||
private static readonly object MShell = Activator.CreateInstance(MType)!;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a shortcut
|
||||
@ -24,7 +24,10 @@ namespace Artemis.UI.Shared
|
||||
/// <param name="iconPath">The icon path of the shortcut</param>
|
||||
public static void Create(string fileName, string targetPath, string arguments, string workingDirectory, string description, string hotkey, string iconPath)
|
||||
{
|
||||
IWshShortcut shortcut = (IWshShortcut) m_type.InvokeMember("CreateShortcut", BindingFlags.InvokeMethod, null, m_shell, new object[] {fileName});
|
||||
IWshShortcut? shortcut = (IWshShortcut?) MType.InvokeMember("CreateShortcut", BindingFlags.InvokeMethod, null, MShell, new object[] {fileName});
|
||||
if (shortcut == null)
|
||||
throw new ArtemisSharedUIException("InvokeMember CreateShortcut returned null");
|
||||
|
||||
shortcut.Description = description;
|
||||
shortcut.Hotkey = hotkey;
|
||||
shortcut.TargetPath = targetPath;
|
||||
@ -34,7 +37,7 @@ namespace Artemis.UI.Shared
|
||||
shortcut.IconLocation = iconPath;
|
||||
shortcut.Save();
|
||||
}
|
||||
|
||||
|
||||
[ComImport]
|
||||
[TypeLibType(0x1040)]
|
||||
[Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")]
|
||||
@ -118,14 +121,7 @@ namespace Artemis.UI.Shared
|
||||
}
|
||||
|
||||
[DispId(0x3ee)]
|
||||
int WindowStyle
|
||||
{
|
||||
[DispId(0x3ee)]
|
||||
get;
|
||||
[param: In]
|
||||
[DispId(0x3ee)]
|
||||
set;
|
||||
}
|
||||
int WindowStyle { [DispId(0x3ee)] get; [param: In] [DispId(0x3ee)] set; }
|
||||
|
||||
[DispId(0x3ef)]
|
||||
string WorkingDirectory
|
||||
@ -141,6 +137,7 @@ namespace Artemis.UI.Shared
|
||||
|
||||
[TypeLibFunc(0x40)]
|
||||
[DispId(0x7d0)]
|
||||
// ReSharper disable once InconsistentNaming - No idea if that breaks it and cba to test
|
||||
void Load([In] [MarshalAs(UnmanagedType.BStr)] string PathLink);
|
||||
|
||||
[DispId(0x7d1)]
|
||||
|
||||
@ -20,12 +20,12 @@ namespace Artemis.UI.Shared
|
||||
/// If not matching item can be found,
|
||||
/// a null parent is being returned.
|
||||
/// </returns>
|
||||
public static T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
|
||||
public static T? FindChild<T>(DependencyObject? parent, string? childName) where T : DependencyObject
|
||||
{
|
||||
// Confirm parent and childName are valid.
|
||||
if (parent == null) return null;
|
||||
|
||||
T foundChild = null;
|
||||
T? foundChild = null;
|
||||
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
|
||||
for (int i = 0; i < childrenCount; i++)
|
||||
@ -72,10 +72,10 @@ namespace Artemis.UI.Shared
|
||||
/// If not matching item can be found,
|
||||
/// a null parent is being returned.
|
||||
/// </returns>
|
||||
public static T FindParent<T>(DependencyObject child, string parentName) where T : DependencyObject
|
||||
public static T? FindParent<T>(DependencyObject child, string? parentName) where T : DependencyObject
|
||||
{
|
||||
// Get parent item
|
||||
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
|
||||
DependencyObject? parentObject = VisualTreeHelper.GetParent(child);
|
||||
|
||||
// We've reached the end of the tree
|
||||
if (parentObject == null)
|
||||
|
||||
@ -14,7 +14,6 @@ using Artemis.Core.Ninject;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Ninject;
|
||||
using Artemis.UI.Screens;
|
||||
using Artemis.UI.Screens.Splash;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Artemis.UI.Stylet;
|
||||
@ -88,7 +87,8 @@ namespace Artemis.UI
|
||||
|
||||
protected override void ConfigureIoC(IKernel kernel)
|
||||
{
|
||||
// kernel.Settings.InjectNonPublic = true;
|
||||
// This is kinda needed for the VM factories in the Shared UI but perhaps there's a less global solution
|
||||
kernel.Settings.InjectNonPublic = true;
|
||||
|
||||
// Load the UI modules
|
||||
kernel.Load<UIModule>();
|
||||
@ -123,7 +123,7 @@ namespace Artemis.UI
|
||||
Execute.OnUIThread(() => Application.Current.Shutdown());
|
||||
}
|
||||
|
||||
private void CreateDataDirectory(ILogger logger)
|
||||
private static void CreateDataDirectory(ILogger logger)
|
||||
{
|
||||
// Ensure the data folder exists
|
||||
if (Directory.Exists(Constants.DataFolder))
|
||||
@ -161,14 +161,5 @@ namespace Artemis.UI
|
||||
Environment.Exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
private void ShowMainWindow(IWindowManager windowManager, SplashViewModel splashViewModel)
|
||||
{
|
||||
Execute.OnUIThread(() =>
|
||||
{
|
||||
windowManager.ShowWindow(RootViewModel);
|
||||
splashViewModel.RequestClose();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,12 @@
|
||||
using System.Timers;
|
||||
using System;
|
||||
using System.Timers;
|
||||
using Artemis.Core.Modules;
|
||||
using Humanizer;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Modules.Tabs
|
||||
{
|
||||
public class ActivationRequirementViewModel : Screen
|
||||
public sealed class ActivationRequirementViewModel : Screen, IDisposable
|
||||
{
|
||||
private readonly IModuleActivationRequirement _activationRequirement;
|
||||
private readonly Timer _updateTimer;
|
||||
@ -60,5 +61,15 @@ namespace Artemis.UI.Screens.Modules.Tabs
|
||||
RequirementDescription = _activationRequirement.GetUserFriendlyDescription();
|
||||
RequirementMet = _activationRequirement.Evaluate();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_updateTimer?.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -5,27 +5,25 @@ using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Input;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
|
||||
{
|
||||
public abstract class DataModelConditionPredicateViewModel : DataModelConditionViewModel, IDisposable
|
||||
{
|
||||
private readonly IConditionOperatorService _conditionOperatorService;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private BindableCollection<BaseConditionOperator> _operators;
|
||||
private DataModelStaticViewModel _rightSideInputViewModel;
|
||||
private DataModelDynamicViewModel _rightSideSelectionViewModel;
|
||||
private BaseConditionOperator _selectedOperator;
|
||||
|
||||
private List<Type> _supportedInputTypes;
|
||||
|
||||
public DataModelConditionPredicateViewModel(
|
||||
protected DataModelConditionPredicateViewModel(
|
||||
DataModelConditionPredicate dataModelConditionPredicate,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
@ -199,17 +197,27 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
|
||||
#region IDisposable
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (LeftSideSelectionViewModel != null)
|
||||
{
|
||||
LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
|
||||
LeftSideSelectionViewModel.Dispose();
|
||||
LeftSideSelectionViewModel = null;
|
||||
}
|
||||
|
||||
DisposeRightSideStaticViewModel();
|
||||
DisposeRightSideDynamicViewModel();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (LeftSideSelectionViewModel != null)
|
||||
{
|
||||
LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
|
||||
LeftSideSelectionViewModel.Dispose();
|
||||
LeftSideSelectionViewModel = null;
|
||||
}
|
||||
|
||||
DisposeRightSideStaticViewModel();
|
||||
DisposeRightSideDynamicViewModel();
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -284,7 +292,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
Update();
|
||||
}
|
||||
|
||||
private void RightSideInputViewModelOnSwitchToDynamicRequested(object? sender, EventArgs e)
|
||||
private void RightSideInputViewModelOnSwitchToDynamicRequested(object sender, EventArgs e)
|
||||
{
|
||||
DataModelConditionPredicate.PredicateType = ProfileRightSideType.Dynamic;
|
||||
Update();
|
||||
|
||||
@ -10,7 +10,7 @@ using Artemis.UI.Shared.Services;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
{
|
||||
public class DataModelConditionEventViewModel : DataModelConditionViewModel, IDisposable
|
||||
public sealed class DataModelConditionEventViewModel : DataModelConditionViewModel, IDisposable
|
||||
{
|
||||
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
@ -90,7 +90,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void LeftSideSelectionViewModelOnPropertySelected(object? sender, DataModelInputDynamicEventArgs e)
|
||||
private void LeftSideSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
|
||||
{
|
||||
ApplyEvent();
|
||||
}
|
||||
@ -104,7 +104,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
LeftSideSelectionViewModel.Dispose();
|
||||
LeftSideSelectionViewModel.PropertySelected -= LeftSideSelectionViewModelOnPropertySelected;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -11,7 +11,7 @@ using Humanizer;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
{
|
||||
public class DataModelConditionListViewModel : DataModelConditionViewModel, IDisposable
|
||||
public sealed class DataModelConditionListViewModel : DataModelConditionViewModel, IDisposable
|
||||
{
|
||||
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
@ -92,7 +92,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
LeftSideSelectionViewModel.ChangeDataModelPath(DataModelConditionList.ListPath);
|
||||
@ -130,15 +130,19 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
private void LeftSideSelectionViewModelOnPropertySelected(object? sender, DataModelInputDynamicEventArgs e)
|
||||
private void LeftSideSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
|
||||
{
|
||||
ApplyList();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LeftSideSelectionViewModel.Dispose();
|
||||
LeftSideSelectionViewModel.PropertySelected -= LeftSideSelectionViewModelOnPropertySelected;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
|
||||
|
||||
@ -114,7 +114,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
|
||||
RenderProfileElement.DisplayCondition.ChildRemoved += DisplayConditionOnChildrenModified;
|
||||
}
|
||||
|
||||
private void DisplayConditionOnChildrenModified(object? sender, EventArgs e)
|
||||
private void DisplayConditionOnChildrenModified(object sender, EventArgs e)
|
||||
{
|
||||
DisplayStartHint = !RenderProfileElement.DisplayCondition.Children.Any();
|
||||
IsEventCondition = RenderProfileElement.DisplayCondition.Children.Any(c => c is DataModelConditionEvent);
|
||||
|
||||
@ -10,7 +10,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.ConditionalDataBinding
|
||||
{
|
||||
public class ConditionalDataBindingModeViewModel<TLayerProperty, TProperty> : Conductor<DataBindingConditionViewModel<TLayerProperty, TProperty>>.Collection.AllActive, IDataBindingModeViewModel
|
||||
public sealed class ConditionalDataBindingModeViewModel<TLayerProperty, TProperty> : Conductor<DataBindingConditionViewModel<TLayerProperty, TProperty>>.Collection.AllActive, IDataBindingModeViewModel
|
||||
{
|
||||
private readonly IDataBindingsVmFactory _dataBindingsVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
@ -109,7 +109,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
ConditionalDataBinding.ConditionsUpdated -= ConditionalDataBindingOnConditionsUpdated;
|
||||
|
||||
@ -10,11 +10,11 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.ConditionalDataBinding
|
||||
{
|
||||
public class DataBindingConditionViewModel<TLayerProperty, TProperty> : Conductor<DataModelConditionGroupViewModel>, IDisposable
|
||||
public sealed class DataBindingConditionViewModel<TLayerProperty, TProperty> : Conductor<DataModelConditionGroupViewModel>, IDisposable
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
|
||||
public DataBindingConditionViewModel(DataBindingCondition<TLayerProperty, TProperty> dataBindingCondition,
|
||||
IProfileEditorService profileEditorService,
|
||||
@ -44,11 +44,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
||||
ValueViewModel.Value = DataBindingCondition.Value;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ValueViewModel.Dispose();
|
||||
}
|
||||
|
||||
private void ActiveItemOnUpdated(object sender, EventArgs e)
|
||||
{
|
||||
if (!ActiveItem.GetChildren().Any())
|
||||
@ -60,5 +55,15 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
||||
DataBindingCondition.Value = (TProperty) Convert.ChangeType(e.Value, typeof(TProperty));
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
ValueViewModel?.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -10,17 +10,17 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
{
|
||||
public class DataBindingViewModel<TLayerProperty, TProperty> : Conductor<IDataBindingModeViewModel>, IDataBindingViewModel
|
||||
public sealed class DataBindingViewModel<TLayerProperty, TProperty> : Conductor<IDataBindingModeViewModel>, IDataBindingViewModel
|
||||
{
|
||||
private readonly IDataBindingsVmFactory _dataBindingsVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly Timer _updateTimer;
|
||||
private bool _applyTestResultToLayer;
|
||||
private int _easingTime;
|
||||
private bool _isDataBindingEnabled;
|
||||
private bool _isEasingTimeEnabled;
|
||||
private DataBindingModeType _selectedDataBindingMode;
|
||||
private TimelineEasingViewModel _selectedEasingViewModel;
|
||||
private bool _applyTestResultToLayer;
|
||||
|
||||
private bool _updating;
|
||||
private bool _updatingTestResult;
|
||||
@ -46,12 +46,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
TestResultValue = dataModelUIService.GetDataModelDisplayViewModel(typeof(TProperty), null, true);
|
||||
}
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
base.OnInitialActivate();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public DataBindingRegistration<TLayerProperty, TProperty> Registration { get; }
|
||||
|
||||
public BindableCollection<ValueDescription> DataBindingModes { get; }
|
||||
@ -115,12 +109,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
_updateTimer.Dispose();
|
||||
_updateTimer.Elapsed -= OnUpdateTimerOnElapsed;
|
||||
|
||||
Registration.LayerProperty.Updated -= LayerPropertyOnUpdated;
|
||||
base.OnInitialActivate();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
@ -171,18 +163,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
EasingTime = (int) Registration.DataBinding.EasingTime.TotalMilliseconds;
|
||||
SelectedEasingViewModel = EasingViewModels.First(vm => vm.EasingFunction == Registration.DataBinding.EasingFunction);
|
||||
IsEasingTimeEnabled = EasingTime > 0;
|
||||
switch (Registration.DataBinding.DataBindingMode)
|
||||
SelectedDataBindingMode = Registration.DataBinding.DataBindingMode switch
|
||||
{
|
||||
case DirectDataBinding<TLayerProperty, TProperty> _:
|
||||
SelectedDataBindingMode = DataBindingModeType.Direct;
|
||||
break;
|
||||
case ConditionalDataBinding<TLayerProperty, TProperty> _:
|
||||
SelectedDataBindingMode = DataBindingModeType.Conditional;
|
||||
break;
|
||||
default:
|
||||
SelectedDataBindingMode = DataBindingModeType.None;
|
||||
break;
|
||||
}
|
||||
DirectDataBinding<TLayerProperty, TProperty> _ => DataBindingModeType.Direct,
|
||||
ConditionalDataBinding<TLayerProperty, TProperty> _ => DataBindingModeType.Conditional,
|
||||
_ => DataBindingModeType.None
|
||||
};
|
||||
|
||||
ActiveItem?.Update();
|
||||
|
||||
@ -250,7 +236,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
TestResultValue.UpdateValue(Registration.DataBinding != null ? Registration.DataBinding.GetValue(currentValue) : default);
|
||||
}
|
||||
else
|
||||
{
|
||||
TestResultValue.UpdateValue(Registration.DataBinding != null ? Registration.DataBinding.GetValue(default) : default);
|
||||
}
|
||||
|
||||
if (ApplyTestResultToLayer)
|
||||
{
|
||||
@ -288,11 +276,24 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
UpdateTestResult();
|
||||
}
|
||||
|
||||
private void LayerPropertyOnUpdated(object? sender, LayerPropertyEventArgs<TLayerProperty> e)
|
||||
private void LayerPropertyOnUpdated(object sender, LayerPropertyEventArgs<TLayerProperty> e)
|
||||
{
|
||||
if (ApplyTestResultToLayer)
|
||||
if (ApplyTestResultToLayer)
|
||||
Registration.DataBinding?.Apply();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_updateTimer.Dispose();
|
||||
_updateTimer.Elapsed -= OnUpdateTimerOnElapsed;
|
||||
|
||||
Registration.LayerProperty.Updated -= LayerPropertyOnUpdated;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public interface IDataBindingViewModel : IScreen, IDisposable
|
||||
|
||||
@ -52,7 +52,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
||||
SelectedItemIndex = 0;
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnSelectedDataBindingChanged(object? sender, EventArgs e)
|
||||
private void ProfileEditorServiceOnSelectedDataBindingChanged(object sender, EventArgs e)
|
||||
{
|
||||
CreateDataBindingViewModels();
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding
|
||||
{
|
||||
public class DataBindingModifierViewModel<TLayerProperty, TProperty> : PropertyChangedBase, IDisposable
|
||||
public sealed class DataBindingModifierViewModel<TLayerProperty, TProperty> : PropertyChangedBase, IDisposable
|
||||
{
|
||||
private readonly IDataBindingService _dataBindingService;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
@ -161,6 +161,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeDynamicSelectionViewModel();
|
||||
@ -193,13 +194,13 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void DynamicSelectionViewModelOnSwitchToStaticRequested(object? sender, EventArgs e)
|
||||
private void DynamicSelectionViewModelOnSwitchToStaticRequested(object sender, EventArgs e)
|
||||
{
|
||||
Modifier.ParameterType = ProfileRightSideType.Static;
|
||||
Update();
|
||||
}
|
||||
|
||||
private void StaticInputViewModelOnSwitchToDynamicRequested(object? sender, EventArgs e)
|
||||
private void StaticInputViewModelOnSwitchToDynamicRequested(object sender, EventArgs e)
|
||||
{
|
||||
Modifier.ParameterType = ProfileRightSideType.Dynamic;
|
||||
Update();
|
||||
|
||||
@ -12,7 +12,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding
|
||||
{
|
||||
public class DirectDataBindingModeViewModel<TLayerProperty, TProperty> : Screen, IDataBindingModeViewModel
|
||||
public sealed class DirectDataBindingModeViewModel<TLayerProperty, TProperty> : Screen, IDataBindingModeViewModel
|
||||
{
|
||||
private readonly IDataBindingsVmFactory _dataBindingsVmFactory;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
@ -70,6 +70,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
TargetSelectionViewModel.PropertySelected -= TargetSelectionViewModelOnPropertySelected;
|
||||
|
||||
@ -9,7 +9,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
{
|
||||
public class LayerPropertyGroupViewModel : PropertyChangedBase, IDisposable
|
||||
public sealed class LayerPropertyGroupViewModel : PropertyChangedBase, IDisposable
|
||||
{
|
||||
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
|
||||
private bool _isVisible;
|
||||
@ -40,9 +40,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
get => _isVisible;
|
||||
set => SetAndNotify(ref _isVisible, value);
|
||||
}
|
||||
|
||||
public bool IsHighlighted => false;
|
||||
|
||||
|
||||
public bool IsExpanded
|
||||
{
|
||||
get => LayerPropertyGroup.ProfileElement.IsPropertyGroupExpanded(LayerPropertyGroup);
|
||||
@ -53,6 +51,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
TimelineGroupViewModel.Dispose();
|
||||
@ -64,6 +65,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void UpdateOrder(int order)
|
||||
{
|
||||
LayerPropertyGroup.LayerEffect.Order = order;
|
||||
@ -93,7 +96,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
/// </summary>
|
||||
/// <param name="start">The position at which to start removing keyframes, if null this will start at the first keyframe</param>
|
||||
/// <param name="end">The position at which to start removing keyframes, if null this will end at the last keyframe</param>
|
||||
public virtual void WipeKeyframes(TimeSpan? start, TimeSpan? end)
|
||||
public void WipeKeyframes(TimeSpan? start, TimeSpan? end)
|
||||
{
|
||||
foreach (PropertyChangedBase child in Children)
|
||||
{
|
||||
@ -139,7 +142,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
{
|
||||
PropertyDescriptionAttribute propertyAttribute = (PropertyDescriptionAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(PropertyDescriptionAttribute));
|
||||
PropertyGroupDescriptionAttribute groupAttribute = (PropertyGroupDescriptionAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(PropertyGroupDescriptionAttribute));
|
||||
object? value = propertyInfo.GetValue(LayerPropertyGroup);
|
||||
object value = propertyInfo.GetValue(LayerPropertyGroup);
|
||||
|
||||
// Create VMs for properties on the group
|
||||
if (propertyAttribute != null && value is ILayerProperty layerProperty)
|
||||
|
||||
@ -7,7 +7,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
{
|
||||
public class LayerPropertyViewModel : PropertyChangedBase, IDisposable
|
||||
public sealed class LayerPropertyViewModel : PropertyChangedBase, IDisposable
|
||||
{
|
||||
private bool _isVisible;
|
||||
private bool _isHighlighted;
|
||||
|
||||
@ -7,7 +7,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
public class TimelineGroupViewModel : PropertyChangedBase, IDisposable
|
||||
public sealed class TimelineGroupViewModel : PropertyChangedBase, IDisposable
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
|
||||
|
||||
@ -7,11 +7,10 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
public class TimelineKeyframeViewModel<T> : Screen, ITimelineKeyframeViewModel
|
||||
public sealed class TimelineKeyframeViewModel<T> : Screen, ITimelineKeyframeViewModel
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
|
||||
private BindableCollection<TimelineEasingViewModel> _easingViewModels;
|
||||
private bool _isSelected;
|
||||
private string _timestamp;
|
||||
private double _x;
|
||||
@ -65,7 +64,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
Timestamp = $"{Math.Floor(LayerPropertyKeyframe.Position.TotalSeconds):00}.{LayerPropertyKeyframe.Position.Milliseconds:000}";
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnPixelsPerSecondChanged(object? sender, EventArgs e)
|
||||
private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
public class TimelinePropertyViewModel<T> : Conductor<TimelineKeyframeViewModel<T>>.Collection.AllActive, ITimelinePropertyViewModel
|
||||
public sealed class TimelinePropertyViewModel<T> : Conductor<TimelineKeyframeViewModel<T>>.Collection.AllActive, ITimelinePropertyViewModel
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private double _width;
|
||||
|
||||
@ -7,7 +7,6 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Screens.ProfileEditor.Dialogs;
|
||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline.Dialogs;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
@ -15,19 +14,19 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
public class TimelineSegmentViewModel : Screen, IDisposable
|
||||
public sealed class TimelineSegmentViewModel : Screen, IDisposable
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private bool _draggingSegment;
|
||||
private bool _segmentEnabled;
|
||||
private TimeSpan _segmentEnd;
|
||||
private TimeSpan _segmentLength;
|
||||
private TimeSpan _segmentStart;
|
||||
private double _segmentStartPosition;
|
||||
private double _segmentWidth;
|
||||
private bool _showDisableButton;
|
||||
private bool _showRepeatButton;
|
||||
private bool _showSegmentName;
|
||||
private TimeSpan _segmentLength;
|
||||
private TimeSpan _segmentStart;
|
||||
private TimeSpan _segmentEnd;
|
||||
private double _segmentWidth;
|
||||
private bool _segmentEnabled;
|
||||
private double _segmentStartPosition;
|
||||
|
||||
public TimelineSegmentViewModel(SegmentViewModelType segment, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups,
|
||||
IProfileEditorService profileEditorService, IDialogService dialogService)
|
||||
@ -139,6 +138,40 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
await _dialogService.ShowDialog<TimelineSegmentDialogViewModel>(new Dictionary<string, object> {{"segment", this}});
|
||||
}
|
||||
|
||||
public void ShiftNextSegment(TimeSpan amount)
|
||||
{
|
||||
if (Segment == SegmentViewModelType.Start)
|
||||
ShiftKeyframes(SelectedProfileElement.Timeline.StartSegmentEndPosition, null, amount);
|
||||
else if (Segment == SegmentViewModelType.Main)
|
||||
ShiftKeyframes(SelectedProfileElement.Timeline.MainSegmentEndPosition, null, amount);
|
||||
else if (Segment == SegmentViewModelType.End)
|
||||
ShiftKeyframes(SelectedProfileElement.Timeline.EndSegmentEndPosition, null, amount);
|
||||
}
|
||||
|
||||
private void WipeKeyframes(TimeSpan? start, TimeSpan? end)
|
||||
{
|
||||
foreach (LayerPropertyGroupViewModel layerPropertyGroupViewModel in LayerPropertyGroups)
|
||||
layerPropertyGroupViewModel.WipeKeyframes(start, end);
|
||||
}
|
||||
|
||||
private void ShiftKeyframes(TimeSpan? start, TimeSpan? end, TimeSpan amount)
|
||||
{
|
||||
foreach (LayerPropertyGroupViewModel layerPropertyGroupViewModel in LayerPropertyGroups)
|
||||
layerPropertyGroupViewModel.ShiftKeyframes(start, end, amount);
|
||||
}
|
||||
|
||||
#region IDIsposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
ProfileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||
if (SelectedProfileElement != null)
|
||||
SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Updating
|
||||
|
||||
private void UpdateHeader()
|
||||
@ -283,7 +316,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
}
|
||||
// If holding down control, round to the closest 50ms
|
||||
else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||
{
|
||||
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 50.0) * 50.0);
|
||||
}
|
||||
|
||||
UpdateLength(newTime);
|
||||
}
|
||||
@ -304,7 +339,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
SelectedProfileElement.Timeline.MainSegmentEndPosition = newTime;
|
||||
else if (Segment == SegmentViewModelType.End)
|
||||
SelectedProfileElement.Timeline.EndSegmentEndPosition = newTime;
|
||||
|
||||
|
||||
if (difference < TimeSpan.Zero)
|
||||
ShiftNextSegment(difference);
|
||||
|
||||
@ -313,21 +348,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDIsposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
ProfileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||
if (SelectedProfileElement != null)
|
||||
SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void ProfileEditorServiceOnProfileElementSelected(object? sender, RenderProfileElementEventArgs e)
|
||||
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||
{
|
||||
if (e.PreviousRenderProfileElement != null)
|
||||
e.PreviousRenderProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
|
||||
@ -347,34 +370,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
NotifyOfPropertyChange(nameof(RepeatSegment));
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnPixelsPerSecondChanged(object? sender, EventArgs e)
|
||||
private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void ShiftNextSegment(TimeSpan amount)
|
||||
{
|
||||
if (Segment == SegmentViewModelType.Start)
|
||||
ShiftKeyframes(SelectedProfileElement.Timeline.StartSegmentEndPosition, null, amount);
|
||||
else if (Segment == SegmentViewModelType.Main)
|
||||
ShiftKeyframes(SelectedProfileElement.Timeline.MainSegmentEndPosition, null, amount);
|
||||
else if (Segment == SegmentViewModelType.End)
|
||||
ShiftKeyframes(SelectedProfileElement.Timeline.EndSegmentEndPosition, null, amount);
|
||||
}
|
||||
|
||||
private void WipeKeyframes(TimeSpan? start, TimeSpan? end)
|
||||
{
|
||||
foreach (LayerPropertyGroupViewModel layerPropertyGroupViewModel in LayerPropertyGroups)
|
||||
layerPropertyGroupViewModel.WipeKeyframes(start, end);
|
||||
}
|
||||
|
||||
private void ShiftKeyframes(TimeSpan? start, TimeSpan? end, TimeSpan amount)
|
||||
{
|
||||
foreach (LayerPropertyGroupViewModel layerPropertyGroupViewModel in LayerPropertyGroups)
|
||||
layerPropertyGroupViewModel.ShiftKeyframes(start, end, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public enum SegmentViewModelType
|
||||
|
||||
@ -6,14 +6,13 @@ using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
public class TimelineViewModel : Screen, IDisposable
|
||||
public sealed class TimelineViewModel : Screen, IDisposable
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private RectangleGeometry _selectionRectangle;
|
||||
@ -88,7 +87,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
Update();
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnProfileElementSelected(object? sender, RenderProfileElementEventArgs e)
|
||||
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||
{
|
||||
if (e.PreviousRenderProfileElement != null)
|
||||
e.PreviousRenderProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
|
||||
@ -98,6 +97,18 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
Update();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||
if (_profileEditorService.SelectedProfileElement != null)
|
||||
_profileEditorService.SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Command handlers
|
||||
|
||||
public void KeyframeMouseDown(object sender, MouseButtonEventArgs e)
|
||||
@ -105,8 +116,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
// if (e.LeftButton == MouseButtonState.Released)
|
||||
// return;
|
||||
|
||||
ITimelineKeyframeViewModel viewModel = (sender as Ellipse)?.DataContext as ITimelineKeyframeViewModel;
|
||||
if (viewModel == null)
|
||||
if (!((sender as Ellipse)?.DataContext is ITimelineKeyframeViewModel viewModel))
|
||||
return;
|
||||
|
||||
((IInputElement) sender).CaptureMouse();
|
||||
@ -206,7 +216,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
keyframeViewModel.SaveOffsetToKeyframe(sourceKeyframeViewModel);
|
||||
|
||||
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
|
||||
{
|
||||
cursorTime = _profileEditorService.SnapToTimeline(
|
||||
cursorTime,
|
||||
TimeSpan.FromMilliseconds(1000f / _profileEditorService.PixelsPerSecond * 5),
|
||||
@ -214,7 +223,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
false,
|
||||
keyframeViewModels.Where(k => k != sourceKeyframeViewModel).Select(k => k.Position).ToList()
|
||||
);
|
||||
}
|
||||
|
||||
sourceKeyframeViewModel.UpdatePosition(cursorTime);
|
||||
|
||||
@ -306,15 +314,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
|
||||
int clickedIndex = keyframeViewModels.IndexOf(clicked);
|
||||
if (clickedIndex < selectedIndex)
|
||||
{
|
||||
foreach (ITimelineKeyframeViewModel keyframeViewModel in keyframeViewModels.Skip(clickedIndex).Take(selectedIndex - clickedIndex + 1))
|
||||
keyframeViewModel.IsSelected = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (ITimelineKeyframeViewModel keyframeViewModel in keyframeViewModels.Skip(selectedIndex).Take(clickedIndex - selectedIndex + 1))
|
||||
keyframeViewModel.IsSelected = true;
|
||||
}
|
||||
}
|
||||
else if (toggle)
|
||||
{
|
||||
@ -340,17 +344,5 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||
if (_profileEditorService.SelectedProfileElement != null)
|
||||
_profileEditorService.SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
@ -8,7 +7,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
{
|
||||
public class TreePropertyViewModel<T> : Screen, ITreePropertyViewModel
|
||||
public sealed class TreePropertyViewModel<T> : Screen, ITreePropertyViewModel
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private PropertyInputViewModel<T> _propertyInputViewModel;
|
||||
@ -26,7 +25,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
LayerProperty.DataBindingDisabled += LayerPropertyOnDataBindingChange;
|
||||
LayerPropertyViewModel.IsVisible = !LayerProperty.IsHidden;
|
||||
}
|
||||
|
||||
|
||||
public LayerProperty<T> LayerProperty { get; }
|
||||
public LayerPropertyViewModel LayerPropertyViewModel { get; }
|
||||
|
||||
@ -36,22 +35,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
set => SetAndNotify(ref _propertyInputViewModel, value);
|
||||
}
|
||||
|
||||
public bool HasDataBinding => LayerProperty.HasDataBinding;
|
||||
public double GetDepth()
|
||||
{
|
||||
int depth = 0;
|
||||
LayerPropertyGroup current = LayerProperty.LayerPropertyGroup;
|
||||
while (current != null)
|
||||
{
|
||||
depth++;
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
public bool HasPropertyInputViewModel => PropertyInputViewModel != null;
|
||||
|
||||
public bool KeyframesEnabled
|
||||
{
|
||||
get => LayerProperty.KeyframesEnabled;
|
||||
@ -66,6 +49,42 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
_profileEditorService.ChangeSelectedDataBinding(LayerProperty);
|
||||
}
|
||||
|
||||
private void ApplyKeyframesEnabled(bool enable)
|
||||
{
|
||||
// If enabling keyframes for the first time, add a keyframe with the current value at the current position
|
||||
if (enable && !LayerProperty.Keyframes.Any())
|
||||
LayerProperty.AddKeyframe(new LayerPropertyKeyframe<T>(
|
||||
LayerProperty.CurrentValue,
|
||||
_profileEditorService.CurrentTime,
|
||||
Easings.Functions.Linear,
|
||||
LayerProperty
|
||||
));
|
||||
// If disabling keyframes, set the base value to the current value
|
||||
else if (!enable && LayerProperty.Keyframes.Any())
|
||||
LayerProperty.BaseValue = LayerProperty.CurrentValue;
|
||||
|
||||
LayerProperty.KeyframesEnabled = enable;
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public bool HasDataBinding => LayerProperty.HasDataBinding;
|
||||
|
||||
public double GetDepth()
|
||||
{
|
||||
int depth = 0;
|
||||
LayerPropertyGroup current = LayerProperty.LayerPropertyGroup;
|
||||
while (current != null)
|
||||
{
|
||||
depth++;
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
public bool HasPropertyInputViewModel => PropertyInputViewModel != null;
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
@ -79,27 +98,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
|
||||
#endregion
|
||||
|
||||
private void ApplyKeyframesEnabled(bool enable)
|
||||
{
|
||||
// If enabling keyframes for the first time, add a keyframe with the current value at the current position
|
||||
if (enable && !LayerProperty.Keyframes.Any())
|
||||
{
|
||||
LayerProperty.AddKeyframe(new LayerPropertyKeyframe<T>(
|
||||
LayerProperty.CurrentValue,
|
||||
_profileEditorService.CurrentTime,
|
||||
Easings.Functions.Linear,
|
||||
LayerProperty
|
||||
));
|
||||
}
|
||||
// If disabling keyframes, set the base value to the current value
|
||||
else if (!enable && LayerProperty.Keyframes.Any())
|
||||
LayerProperty.BaseValue = LayerProperty.CurrentValue;
|
||||
|
||||
LayerProperty.KeyframesEnabled = enable;
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void ProfileEditorServiceOnSelectedDataBindingChanged(object sender, EventArgs e)
|
||||
@ -107,12 +105,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
LayerPropertyViewModel.IsHighlighted = _profileEditorService.SelectedDataBinding == LayerProperty;
|
||||
}
|
||||
|
||||
private void LayerPropertyOnVisibilityChanged(object? sender, LayerPropertyEventArgs<T> e)
|
||||
private void LayerPropertyOnVisibilityChanged(object sender, LayerPropertyEventArgs<T> e)
|
||||
{
|
||||
LayerPropertyViewModel.IsVisible = !LayerProperty.IsHidden;
|
||||
}
|
||||
|
||||
private void LayerPropertyOnDataBindingChange(object? sender, LayerPropertyEventArgs<T> e)
|
||||
private void LayerPropertyOnDataBindingChange(object sender, LayerPropertyEventArgs<T> e)
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(HasDataBinding));
|
||||
}
|
||||
|
||||
@ -21,12 +21,11 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
_profileEditorService = profileEditorService;
|
||||
}
|
||||
|
||||
public async void CopyElement()
|
||||
public void CopyElement()
|
||||
{
|
||||
Layer layer = Layer.CreateCopy();
|
||||
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
// await Task.Delay(200);
|
||||
_profileEditorService.ChangeSelectedProfileElement(layer);
|
||||
}
|
||||
|
||||
|
||||
@ -16,9 +16,9 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
public abstract class TreeItemViewModel : Conductor<TreeItemViewModel>.Collection.AllActive, IDisposable
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly ILayerBrushService _layerBrushService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly IProfileTreeVmFactory _profileTreeVmFactory;
|
||||
private readonly ILayerBrushService _layerBrushService;
|
||||
private readonly ISurfaceService _surfaceService;
|
||||
private ProfileElement _profileElement;
|
||||
|
||||
@ -49,11 +49,6 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
|
||||
public abstract bool SupportsChildren { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Unsubscribe();
|
||||
}
|
||||
|
||||
public List<TreeItemViewModel> GetAllChildren()
|
||||
{
|
||||
List<TreeItemViewModel> children = new List<TreeItemViewModel>();
|
||||
@ -142,7 +137,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
Layer layer = new Layer(ProfileElement, "New layer");
|
||||
|
||||
// Could be null if the default brush got disabled
|
||||
LayerBrushDescriptor? brush = _layerBrushService.GetDefaultLayerBrush();
|
||||
LayerBrushDescriptor brush = _layerBrushService.GetDefaultLayerBrush();
|
||||
if (brush != null)
|
||||
layer.ChangeLayerBrush(brush);
|
||||
|
||||
@ -212,7 +207,6 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
|
||||
List<TreeItemViewModel> newChildren = new List<TreeItemViewModel>();
|
||||
foreach (ProfileElement profileElement in ProfileElement.Children.OrderBy(c => c.Order))
|
||||
{
|
||||
if (profileElement is Folder folder)
|
||||
{
|
||||
if (Items.FirstOrDefault(p => p is FolderViewModel vm && vm.ProfileElement == folder) == null)
|
||||
@ -223,7 +217,6 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
if (Items.FirstOrDefault(p => p is LayerViewModel vm && vm.ProfileElement == layer) == null)
|
||||
newChildren.Add(_profileTreeVmFactory.LayerViewModel(layer));
|
||||
}
|
||||
}
|
||||
|
||||
if (!newChildren.Any())
|
||||
return;
|
||||
@ -262,5 +255,21 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
{
|
||||
UpdateProfileElements();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing) Unsubscribe();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -391,7 +391,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
UpdateCanSelectEditTool();
|
||||
}
|
||||
|
||||
private void TransformValueChanged(object? sender, LayerPropertyEventArgs e)
|
||||
private void TransformValueChanged(object sender, LayerPropertyEventArgs e)
|
||||
{
|
||||
if (ActiveToolIndex != 1)
|
||||
ActivateToolByIndex(1);
|
||||
|
||||
@ -192,7 +192,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
height = layer.Transform.Scale.CurrentValue.Height;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
throw new ArgumentOutOfRangeException(nameof(e));
|
||||
}
|
||||
|
||||
// Make the sides even if shift is held down
|
||||
@ -326,10 +326,14 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
{
|
||||
// Keep the X position static if dragging vertically
|
||||
if (_draggingVertically)
|
||||
{
|
||||
position.X = _dragStart.X;
|
||||
}
|
||||
// Keep the Y position static if dragging horizontally
|
||||
else if (_draggingHorizontally)
|
||||
{
|
||||
position.Y = _dragStart.Y;
|
||||
}
|
||||
// Snap into place only if the mouse moved atleast a full pixel
|
||||
else if (Math.Abs(position.X - _dragStart.X) > 1 || Math.Abs(position.Y - _dragStart.Y) > 1)
|
||||
{
|
||||
@ -386,23 +390,23 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
|
||||
#region Private methods
|
||||
|
||||
private SKPoint RoundPoint(SKPoint point, int decimals)
|
||||
private static SKPoint RoundPoint(SKPoint point, int decimals)
|
||||
{
|
||||
return new SKPoint((float) Math.Round(point.X, decimals, MidpointRounding.AwayFromZero), (float) Math.Round(point.Y, decimals, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
private SKPoint[] UnTransformPoints(SKPoint[] skPoints, Layer layer, SKPoint pivot, bool includeScale)
|
||||
private static SKPoint[] UnTransformPoints(SKPoint[] skPoints, Layer layer, SKPoint pivot, bool includeScale)
|
||||
{
|
||||
using SKPath counterRotatePath = new SKPath();
|
||||
counterRotatePath.AddPoly(skPoints, false);
|
||||
counterRotatePath.Transform(SKMatrix.MakeRotationDegrees(layer.Transform.Rotation.CurrentValue * -1, pivot.X, pivot.Y));
|
||||
counterRotatePath.Transform(SKMatrix.CreateRotationDegrees(layer.Transform.Rotation.CurrentValue * -1, pivot.X, pivot.Y));
|
||||
if (includeScale)
|
||||
counterRotatePath.Transform(SKMatrix.MakeScale(1f / (layer.Transform.Scale.CurrentValue.Width / 100f), 1f / (layer.Transform.Scale.CurrentValue.Height / 100f)));
|
||||
counterRotatePath.Transform(SKMatrix.CreateScale(1f / (layer.Transform.Scale.CurrentValue.Width / 100f), 1f / (layer.Transform.Scale.CurrentValue.Height / 100f)));
|
||||
|
||||
return counterRotatePath.Points;
|
||||
}
|
||||
|
||||
private Point GetRelativePosition(object sender, MouseEventArgs mouseEventArgs)
|
||||
private static Point GetRelativePosition(object sender, MouseEventArgs mouseEventArgs)
|
||||
{
|
||||
DependencyObject parent = VisualTreeHelper.GetParent((DependencyObject) sender);
|
||||
return mouseEventArgs.GetPosition((IInputElement) parent);
|
||||
@ -410,7 +414,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
|
||||
private float CalculateAngle(Layer layer, object mouseEventSender, MouseEventArgs mouseEvent)
|
||||
{
|
||||
Rect layerBounds = _layerEditorService.GetLayerBounds(layer);
|
||||
Point start = _layerEditorService.GetLayerAnchorPosition(layer);
|
||||
Point arrival = GetRelativePosition(mouseEventSender, mouseEvent);
|
||||
|
||||
|
||||
@ -20,22 +20,22 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens
|
||||
{
|
||||
public class RootViewModel : Conductor<IScreen>
|
||||
public sealed class RootViewModel : Conductor<IScreen>, IDisposable
|
||||
{
|
||||
private readonly IRegistrationService _builtInRegistrationService;
|
||||
private readonly PluginSetting<ApplicationColorScheme> _colorScheme;
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly IDebugService _debugService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly Timer _frameTimeUpdateTimer;
|
||||
private readonly ISnackbarMessageQueue _snackbarMessageQueue;
|
||||
private readonly ThemeWatcher _themeWatcher;
|
||||
private readonly Timer _frameTimeUpdateTimer;
|
||||
private readonly PluginSetting<WindowSize> _windowSize;
|
||||
private bool _activeItemReady;
|
||||
private string _frameTime;
|
||||
private bool _lostFocus;
|
||||
private ISnackbarMessageQueue _mainMessageQueue;
|
||||
private string _windowTitle;
|
||||
private string _frameTime;
|
||||
|
||||
public RootViewModel(
|
||||
IEventAggregator eventAggregator,
|
||||
@ -64,7 +64,7 @@ namespace Artemis.UI.Screens
|
||||
ActiveItem = SidebarViewModel.SelectedItem;
|
||||
ActiveItemReady = true;
|
||||
|
||||
AssemblyInformationalVersionAttribute? versionAttribute = typeof(RootViewModel).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||
AssemblyInformationalVersionAttribute versionAttribute = typeof(RootViewModel).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||
WindowTitle = $"Artemis {versionAttribute?.InformationalVersion}";
|
||||
}
|
||||
|
||||
@ -141,19 +141,18 @@ namespace Artemis.UI.Screens
|
||||
|
||||
private void UpdateFrameTime()
|
||||
{
|
||||
|
||||
FrameTime = $"Frame time: {_coreService.FrameTime.TotalMilliseconds:F2} ms";
|
||||
}
|
||||
|
||||
|
||||
private void SidebarViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(SidebarViewModel.SelectedItem) && ActiveItem != SidebarViewModel.SelectedItem)
|
||||
{
|
||||
SidebarViewModel.IsSidebarOpen = false;
|
||||
// Don't do a fade when selecting a module because the editor is so bulky the animation slows things down
|
||||
if (!(SidebarViewModel.SelectedItem is ModuleRootViewModel))
|
||||
if (!(SidebarViewModel.SelectedItem is ModuleRootViewModel))
|
||||
ActiveItemReady = false;
|
||||
|
||||
|
||||
// Allow the menu to close, it's slower but feels more responsive, funny how that works right
|
||||
Execute.PostToUIThreadAsync(async () =>
|
||||
{
|
||||
@ -209,13 +208,25 @@ namespace Artemis.UI.Screens
|
||||
ApplyColorSchemeSetting();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_frameTimeUpdateTimer?.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
MaterialWindow window = (MaterialWindow) View;
|
||||
if (_windowSize.Value != null)
|
||||
{
|
||||
_windowSize.Value.ApplyToWindow(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
_windowSize.Value = new WindowSize();
|
||||
@ -269,7 +280,7 @@ namespace Artemis.UI.Screens
|
||||
protected override void OnClose()
|
||||
{
|
||||
SidebarViewModel.Dispose();
|
||||
|
||||
|
||||
// Lets force the GC to run after closing the window so it is obvious to users watching task manager
|
||||
// that closing the UI will decrease the memory footprint of the application.
|
||||
Task.Run(async () =>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Timers;
|
||||
using Artemis.Core;
|
||||
@ -10,14 +10,14 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
||||
{
|
||||
public class DataModelDebugViewModel : Screen
|
||||
public sealed class DataModelDebugViewModel : Screen, IDisposable
|
||||
{
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly Timer _updateTimer;
|
||||
|
||||
private bool _isModuleFilterEnabled;
|
||||
private DataModelPropertiesViewModel _mainDataModel;
|
||||
private List<Module> _modules;
|
||||
private string _propertySearch;
|
||||
private Module _selectedModule;
|
||||
|
||||
@ -69,6 +69,17 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
||||
}
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
_updateTimer.Dispose();
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnActivate()
|
||||
{
|
||||
GetDataModel();
|
||||
@ -126,5 +137,15 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
||||
else if (!SelectedModule.IsEnabled)
|
||||
SelectedModule = null;
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_updateTimer?.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -11,7 +11,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
|
||||
{
|
||||
private readonly ISettingsVmFactory _settingsVmFactory;
|
||||
private readonly ISurfaceService _surfaceService;
|
||||
private BindableCollection<DeviceSettingsViewModel> _deviceSettingsViewModels;
|
||||
|
||||
public DeviceSettingsTabViewModel(ISurfaceService surfaceService, ISettingsVmFactory settingsVmFactory)
|
||||
{
|
||||
|
||||
@ -125,34 +125,27 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
|
||||
private PackIconKind GetIconKind()
|
||||
{
|
||||
switch (Feature)
|
||||
return Feature switch
|
||||
{
|
||||
case BaseDataModelExpansion _:
|
||||
return PackIconKind.TableAdd;
|
||||
case DeviceProvider _:
|
||||
return PackIconKind.Devices;
|
||||
case ProfileModule _:
|
||||
return PackIconKind.VectorRectangle;
|
||||
case Module _:
|
||||
return PackIconKind.GearBox;
|
||||
case LayerBrushProvider _:
|
||||
return PackIconKind.Brush;
|
||||
case LayerEffectProvider _:
|
||||
return PackIconKind.AutoAwesome;
|
||||
}
|
||||
|
||||
return PackIconKind.Plugin;
|
||||
BaseDataModelExpansion => PackIconKind.TableAdd,
|
||||
DeviceProvider => PackIconKind.Devices,
|
||||
ProfileModule => PackIconKind.VectorRectangle,
|
||||
Module => PackIconKind.GearBox,
|
||||
LayerBrushProvider => PackIconKind.Brush,
|
||||
LayerEffectProvider => PackIconKind.AutoAwesome,
|
||||
_ => PackIconKind.Plugin
|
||||
};
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void OnFeatureEnabling(object? sender, PluginFeatureEventArgs e)
|
||||
private void OnFeatureEnabling(object sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
if (e.PluginFeature != Feature) return;
|
||||
Enabling = true;
|
||||
}
|
||||
|
||||
private void OnFeatureEnableStopped(object? sender, PluginFeatureEventArgs e)
|
||||
private void OnFeatureEnableStopped(object sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
if (e.PluginFeature != Feature) return;
|
||||
Enabling = false;
|
||||
|
||||
@ -146,14 +146,14 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
||||
}
|
||||
|
||||
private void PluginOnFeatureRemoved(object? sender, PluginFeatureEventArgs e)
|
||||
private void PluginOnFeatureRemoved(object sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
PluginFeatureViewModel viewModel = Items.FirstOrDefault(i => i.Feature == e.PluginFeature);
|
||||
if (viewModel != null)
|
||||
Items.Remove(viewModel);
|
||||
}
|
||||
|
||||
private void PluginOnFeatureAdded(object? sender, PluginFeatureEventArgs e)
|
||||
private void PluginOnFeatureAdded(object sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
Items.Add(_settingsVmFactory.CreatePluginFeatureViewModel(e.PluginFeature));
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Sidebar
|
||||
{
|
||||
public class SidebarViewModel : PropertyChangedBase, IHandle<RequestSelectSidebarItemEvent>, IDisposable
|
||||
public sealed class SidebarViewModel : PropertyChangedBase, IHandle<RequestSelectSidebarItemEvent>, IDisposable
|
||||
{
|
||||
private readonly Timer _activeModulesUpdateTimer;
|
||||
private readonly IKernel _kernel;
|
||||
@ -196,16 +196,9 @@ namespace Artemis.UI.Screens.Sidebar
|
||||
|
||||
#region IDisposable
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
_activeModulesUpdateTimer?.Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
_activeModulesUpdateTimer?.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -81,12 +81,12 @@ namespace Artemis.UI.Screens.Splash
|
||||
Status = "Enabling plugin: " + args.Plugin.Info.Name;
|
||||
}
|
||||
|
||||
private void PluginManagementServiceOnPluginFeatureEnabling(object? sender, PluginFeatureEventArgs e)
|
||||
private void PluginManagementServiceOnPluginFeatureEnabling(object sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
Status = "Enabling: " + e.PluginFeature.GetType().Name.Humanize();
|
||||
}
|
||||
|
||||
private void PluginManagementServiceOnPluginFeatureEnabled(object? sender, PluginFeatureEventArgs e)
|
||||
private void PluginManagementServiceOnPluginFeatureEnabled(object sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
Status = "Initializing UI";
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Services.Interfaces;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using SkiaSharp;
|
||||
using SkiaSharp.Views.WPF;
|
||||
|
||||
@ -14,7 +13,7 @@ namespace Artemis.UI.Services
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
public LayerEditorService(ISettingsService settingsService, IProfileEditorService profileEditorService)
|
||||
public LayerEditorService(ISettingsService settingsService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
}
|
||||
@ -93,11 +92,11 @@ namespace Artemis.UI.Services
|
||||
SKPath path = new SKPath();
|
||||
path.AddRect(layerBounds);
|
||||
if (includeTranslation)
|
||||
path.Transform(SKMatrix.MakeTranslation(x, y));
|
||||
path.Transform(SKMatrix.CreateTranslation(x, y));
|
||||
if (includeScale)
|
||||
path.Transform(SKMatrix.MakeScale(layer.Transform.Scale.CurrentValue.Width / 100f, layer.Transform.Scale.CurrentValue.Height / 100f, anchorPosition.X, anchorPosition.Y));
|
||||
path.Transform(SKMatrix.CreateScale(layer.Transform.Scale.CurrentValue.Width / 100f, layer.Transform.Scale.CurrentValue.Height / 100f, anchorPosition.X, anchorPosition.Y));
|
||||
if (includeRotation)
|
||||
path.Transform(SKMatrix.MakeRotationDegrees(layer.Transform.Rotation.CurrentValue, anchorPosition.X, anchorPosition.Y));
|
||||
path.Transform(SKMatrix.CreateRotationDegrees(layer.Transform.Rotation.CurrentValue, anchorPosition.X, anchorPosition.Y));
|
||||
|
||||
return path;
|
||||
}
|
||||
@ -107,12 +106,10 @@ namespace Artemis.UI.Services
|
||||
{
|
||||
double renderScale = _settingsService.GetSetting("Core.RenderScale", 0.5).Value;
|
||||
if (absolute)
|
||||
{
|
||||
return new SKPoint(
|
||||
100f / layer.Bounds.Width * ((float) (point.X * renderScale) - layer.Bounds.Left) / 100f,
|
||||
100f / layer.Bounds.Height * ((float) (point.Y * renderScale) - layer.Bounds.Top) / 100f
|
||||
);
|
||||
}
|
||||
|
||||
return new SKPoint(
|
||||
100f / layer.Bounds.Width * (float) (point.X * renderScale) / 100f,
|
||||
|
||||
@ -74,7 +74,7 @@ namespace Artemis.UI.Services
|
||||
_registeredBuiltInPropertyEditors = true;
|
||||
}
|
||||
|
||||
private void PluginServiceOnPluginLoaded(object? sender, PluginEventArgs e)
|
||||
private void PluginServiceOnPluginLoaded(object sender, PluginEventArgs e)
|
||||
{
|
||||
e.Plugin.Kernel.Load(new[] {new PluginUIModule(e.Plugin)});
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FluentValidation;
|
||||
using Stylet;
|
||||
@ -26,7 +25,7 @@ namespace Artemis.UI.Stylet
|
||||
{
|
||||
// If someone's calling us synchronously, and ValidationAsync does not complete synchronously,
|
||||
// we'll deadlock unless we continue on another thread.
|
||||
return (await _validator.ValidateAsync(_subject, CancellationToken.None, propertyName).ConfigureAwait(false))
|
||||
return (await _validator.ValidateAsync(_subject, options => options.IncludeProperties(propertyName)).ConfigureAwait(false))
|
||||
.Errors.Select(x => x.ErrorMessage);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user