using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using SkiaSharp; using Stylet; namespace Artemis.Core.Models.Profile { public abstract class ProfileElement : PropertyChangedBase, IDisposable { protected virtual void Dispose(bool disposing) { if (disposing) { } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected bool _disposed; private bool _enabled; private Guid _entityId; private string _name; private int _order; private ProfileElement _parent; private Profile _profile; protected List ChildrenList; protected ProfileElement() { ChildrenList = new List(); } public Guid EntityId { get => _entityId; internal set => SetAndNotify(ref _entityId, value); } public Profile Profile { get => _profile; internal set => SetAndNotify(ref _profile, value); } public ProfileElement Parent { get => _parent; internal set => SetAndNotify(ref _parent, value); } /// /// The element's children /// public ReadOnlyCollection Children => ChildrenList.AsReadOnly(); /// /// The order in which this element appears in the update loop and editor /// public int Order { get => _order; internal set => SetAndNotify(ref _order, value); } /// /// The name which appears in the editor /// public string Name { get => _name; set => SetAndNotify(ref _name, value); } /// /// Gets or sets the enabled state, if not enabled the element is skipped in render and update /// public bool Enabled { get => _enabled; set => SetAndNotify(ref _enabled, value); } /// /// Updates the element /// /// public abstract void Update(double deltaTime); /// /// Renders the element /// public abstract void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo); public List GetAllFolders() { if (_disposed) throw new ObjectDisposedException(GetType().Name); var folders = new List(); foreach (var childFolder in Children.Where(c => c is Folder).Cast()) { // Add all folders in this element folders.Add(childFolder); // Add all folders in folders inside this element folders.AddRange(childFolder.GetAllFolders()); } return folders; } public List GetAllLayers() { if (_disposed) throw new ObjectDisposedException(GetType().Name); var layers = new List(); // Add all layers in this element layers.AddRange(Children.Where(c => c is Layer).Cast()); // Add all layers in folders inside this element foreach (var childFolder in Children.Where(c => c is Folder).Cast()) layers.AddRange(childFolder.GetAllLayers()); return layers; } /// /// Adds a profile element to the collection, optionally at the given position (1-based) /// /// The profile element to add /// The order where to place the child (1-based), defaults to the end of the collection public virtual void AddChild(ProfileElement child, int? order = null) { if (_disposed) throw new ObjectDisposedException(GetType().Name); lock (ChildrenList) { // Add to the end of the list if (order == null) { ChildrenList.Add(child); child.Order = ChildrenList.Count; } // Shift everything after the given order else { foreach (var profileElement in ChildrenList.Where(c => c.Order >= order).ToList()) profileElement.Order++; int targetIndex; if (order == 0) targetIndex = 0; else if (order > ChildrenList.Count) targetIndex = ChildrenList.Count; else targetIndex = ChildrenList.FindIndex(c => c.Order == order + 1); ChildrenList.Insert(targetIndex, child); child.Order = order.Value; } child.Parent = this; } OnChildAdded(); } /// /// Removes a profile element from the collection /// /// The profile element to remove public virtual void RemoveChild(ProfileElement child) { if (_disposed) throw new ObjectDisposedException(GetType().Name); lock (ChildrenList) { ChildrenList.Remove(child); // Shift everything after the given order foreach (var profileElement in ChildrenList.Where(c => c.Order > child.Order).ToList()) profileElement.Order--; child.Parent = null; } OnChildRemoved(); } public override string ToString() { return $"{nameof(EntityId)}: {EntityId}, {nameof(Order)}: {Order}, {nameof(Name)}: {Name}"; } /// /// Applies the profile element's properties to the underlying storage entity /// internal abstract void ApplyToEntity(); #region Events public event EventHandler ChildAdded; public event EventHandler ChildRemoved; protected virtual void OnChildAdded() { ChildAdded?.Invoke(this, EventArgs.Empty); } protected virtual void OnChildRemoved() { ChildRemoved?.Invoke(this, EventArgs.Empty); } #endregion } }