using System; namespace RGB.NET.Core; /// /// Represents a placeable element. /// public class Placeable : AbstractBindable, IPlaceable { #region Properties & Fields /// /// Gets the parent this placeable is placed in. /// protected IPlaceable? Parent { get; } private Point _location = Point.Invalid; /// public Point Location { get => _location; set { if (SetProperty(ref _location, value)) OnLocationChanged(); } } private Size _size = Size.Invalid; /// public Size Size { get => _size; set { if (SetProperty(ref _size, value)) OnSizeChanged(); } } private Scale _scale = new(1); /// public Scale Scale { get => _scale; set { if (SetProperty(ref _scale, value)) OnScaleChanged(); } } private Rotation _rotation = new(0); /// public Rotation Rotation { get => _rotation; set { if (SetProperty(ref _rotation, value)) OnRotationChanged(); } } private Point _actualLocation = Point.Invalid; /// public Point ActualLocation { get => _actualLocation; private set { if (SetProperty(ref _actualLocation, value)) OnActualLocationChanged(); } } private Size _actualSize = Size.Invalid; /// public Size ActualSize { get => _actualSize; private set { if (SetProperty(ref _actualSize, value)) OnActualSizeChanged(); } } private Rectangle _boundary = new(Point.Invalid, Point.Invalid); /// public Rectangle Boundary { get => _boundary; private set { if (SetProperty(ref _boundary, value)) OnBoundaryChanged(); } } #endregion #region Events /// public event EventHandler? LocationChanged; /// public event EventHandler? SizeChanged; /// public event EventHandler? ScaleChanged; /// public event EventHandler? RotationChanged; /// public event EventHandler? ActualLocationChanged; /// public event EventHandler? ActualSizeChanged; /// public event EventHandler? BoundaryChanged; #endregion #region Constructors /// /// Initializes a new instance of the class. /// public Placeable() { } /// /// Initializes a new instance of the class. /// /// The parent this placeable is placed in. public Placeable(IPlaceable parent) { this.Parent = parent; Parent.BoundaryChanged += (_, _) => UpdateActualPlaceableData(); } /// /// Initializes a new instance of the class. /// /// The location of this placeable. /// The size of this placeable. public Placeable(Point location, Size size) { this.Location = location; this.Size = size; } /// /// Initializes a new instance of the class. /// /// The parent placeable this placeable is placed in. /// The location of this placeable. /// The size of this placeable. public Placeable(IPlaceable parent, Point location, Size size) { this.Parent = parent; this.Location = location; this.Size = size; Parent.BoundaryChanged += (_, _) => UpdateActualPlaceableData(); } #endregion #region Methods /// /// Updates the , and based on the , and . /// protected virtual void UpdateActualPlaceableData() { if (Parent != null) { Size actualSize = Size * Parent.Scale; Point actualLocation = (Location * Parent.Scale); Rectangle boundary = new(actualLocation, actualSize); if (Parent.Rotation.IsRotated) { Point parentCenter = new Rectangle(Parent.ActualSize).Center; Point actualParentCenter = new Rectangle(Parent.Boundary.Size).Center; Point centerOffset = new(actualParentCenter.X - parentCenter.X, actualParentCenter.Y - parentCenter.Y); actualLocation = actualLocation.Rotate(Parent.Rotation, new Rectangle(Parent.ActualSize).Center) + centerOffset; boundary = new Rectangle(boundary.Rotate(Parent.Rotation, new Rectangle(Parent.ActualSize).Center)).Translate(centerOffset); } ActualLocation = actualLocation; ActualSize = actualSize; Boundary = boundary; } else { ActualLocation = Location; ActualSize = Size * Scale; Boundary = new Rectangle(Location, new Rectangle(new Rectangle(Location, ActualSize).Rotate(Rotation)).Size); } } /// /// Called when the property was changed. /// protected virtual void OnLocationChanged() { LocationChanged?.Invoke(this, EventArgs.Empty); UpdateActualPlaceableData(); } /// /// Called when the property was changed. /// protected virtual void OnSizeChanged() { SizeChanged?.Invoke(this, EventArgs.Empty); UpdateActualPlaceableData(); } /// /// Called when the property was changed. /// protected virtual void OnScaleChanged() { ScaleChanged?.Invoke(this, EventArgs.Empty); UpdateActualPlaceableData(); } /// /// Called when the property was changed. /// protected virtual void OnRotationChanged() { RotationChanged?.Invoke(this, EventArgs.Empty); UpdateActualPlaceableData(); } /// /// Called when the property was changed. /// protected virtual void OnActualLocationChanged() => ActualLocationChanged?.Invoke(this, EventArgs.Empty); /// /// Called when the property was changed. /// protected virtual void OnActualSizeChanged() => ActualSizeChanged?.Invoke(this, EventArgs.Empty); /// /// Called when the property was changed. /// protected virtual void OnBoundaryChanged() => BoundaryChanged?.Invoke(this, EventArgs.Empty); #endregion }