using System; using System.Collections.Generic; using System.Reflection; using Artemis.Core.Services; using Artemis.Storage.Entities.Profile; namespace Artemis.Core { /// /// For internal use only, to implement your own layer property type, extend instead. /// public abstract class BaseLayerProperty { protected readonly List _dataBindingRegistrations = new List(); protected readonly List _dataBindings = new List(); private object _baseValue; private object _currentValue; private object _defaultValue; private bool _isHidden; private bool _keyframesEnabled; internal BaseLayerProperty() { } /// /// Gets or sets the base value of this layer property without any keyframes applied /// public object BaseValue { get => _baseValue; set { if (value != null && value.GetType() != GetPropertyType()) throw new ArtemisCoreException("Cannot update base value because of a type mismatch"); _baseValue = value; } } /// /// Gets the current value of this property as it is affected by it's keyframes, updated once every frame /// public object CurrentValue { get => _currentValue; set { if (value != null && value.GetType() != GetPropertyType()) throw new ArtemisCoreException("Cannot update current value because of a type mismatch"); _currentValue = value; } } /// /// Gets or sets the default value of this layer property. If set, this value is automatically applied if the property /// has no value in storage /// public object DefaultValue { get => _defaultValue; set { if (value != null && value.GetType() != GetPropertyType()) throw new ArtemisCoreException("Cannot update default value because of a type mismatch"); _defaultValue = value; } } /// /// Gets a list containing the active data bindings /// public IReadOnlyList DataBindings => _dataBindings.AsReadOnly(); /// /// Gets a list containing all the data binding registrations /// public IReadOnlyList DataBindingRegistrations => _dataBindingRegistrations.AsReadOnly(); /// /// Gets the profile element (such as layer or folder) this effect is applied to /// public RenderProfileElement ProfileElement { get; internal set; } /// /// The parent group of this layer property, set after construction /// public LayerPropertyGroup Parent { get; internal set; } /// /// Gets whether keyframes are supported on this type of property /// public bool KeyframesSupported { get; protected internal set; } = true; /// /// Gets whether data bindings are supported on this type of property /// public bool DataBindingsSupported { get; protected internal set; } = true; /// /// Gets or sets whether keyframes are enabled on this property, has no effect if is /// False /// public bool KeyframesEnabled { get => _keyframesEnabled; set { if (_keyframesEnabled == value) return; _keyframesEnabled = value; OnKeyframesToggled(); } } /// /// Gets or sets whether the property is hidden in the UI /// public bool IsHidden { get => _isHidden; set { _isHidden = value; OnVisibilityChanged(); } } /// /// Indicates whether the BaseValue was loaded from storage, useful to check whether a default value must be applied /// public bool IsLoadedFromStorage { get; internal set; } /// /// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID /// public bool IsCoreProperty { get; internal set; } /// /// Gets the description attribute applied to this property /// public PropertyDescriptionAttribute PropertyDescription { get; internal set; } /// /// Gets a list of all the keyframes in their non-generic base form, without their values being available /// public abstract IReadOnlyList BaseKeyframes { get; } internal PropertyEntity PropertyEntity { get; set; } internal LayerPropertyGroup LayerPropertyGroup { get; set; } /// /// Overrides the property value with the default value /// public abstract void ApplyDefaultValue(); /// /// Returns the type of the property /// public abstract Type GetPropertyType(); /// /// Applies the provided property entity to the layer property by deserializing the JSON base value and keyframe values /// /// /// /// internal abstract void ApplyToLayerProperty(PropertyEntity entity, LayerPropertyGroup layerPropertyGroup, bool fromStorage); /// /// Saves the property to the underlying property entity that was configured when calling /// /// internal abstract void ApplyToEntity(); #region Data bindings internal void InitializeDataBindings(IDataModelService dataModelService, IDataBindingService dataBindingService) { foreach (var dataBinding in DataBindings) dataBinding.Initialize(dataModelService, dataBindingService); } /// /// Adds a new data binding targeting the given property to the collection /// /// The newly created data binding public DataBinding EnableDataBinding(DataBindingRegistration dataBindingRegistration) { if (dataBindingRegistration.LayerProperty != this) throw new ArtemisCoreException("Cannot enable a data binding using a data binding registration of a different layer property"); var dataBinding = new DataBinding(dataBindingRegistration); _dataBindings.Add(dataBinding); return dataBinding; } /// /// Removes the provided data binding from the collection /// /// The data binding to remove public void DisableDataBinding(DataBinding dataBinding) { _dataBindings.Remove(dataBinding); } #endregion #region Events /// /// Occurs once every frame when the layer property is updated /// public event EventHandler Updated; /// /// Occurs when the base value of the layer property was updated /// public event EventHandler BaseValueChanged; /// /// Occurs when the value of the layer property was updated /// public event EventHandler VisibilityChanged; /// /// Occurs when keyframes are enabled/disabled /// public event EventHandler KeyframesToggled; /// /// Occurs when a new keyframe was added to the layer property /// public event EventHandler KeyframeAdded; /// /// Occurs when a keyframe was removed from the layer property /// public event EventHandler KeyframeRemoved; protected virtual void OnUpdated() { Updated?.Invoke(this, new LayerPropertyEventArgs(this)); } protected virtual void OnBaseValueChanged() { BaseValueChanged?.Invoke(this, new LayerPropertyEventArgs(this)); } protected virtual void OnVisibilityChanged() { VisibilityChanged?.Invoke(this, new LayerPropertyEventArgs(this)); } protected virtual void OnKeyframesToggled() { KeyframesToggled?.Invoke(this, new LayerPropertyEventArgs(this)); } protected virtual void OnKeyframeAdded() { KeyframeAdded?.Invoke(this, new LayerPropertyEventArgs(this)); } protected virtual void OnKeyframeRemoved() { KeyframeRemoved?.Invoke(this, new LayerPropertyEventArgs(this)); } #endregion } }