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, new EventArgs());
UpdateActualPlaceableData();
}
///
/// Called when the property was changed.
///
protected virtual void OnSizeChanged()
{
SizeChanged?.Invoke(this, new EventArgs());
UpdateActualPlaceableData();
}
///
/// Called when the property was changed.
///
protected virtual void OnScaleChanged()
{
ScaleChanged?.Invoke(this, new EventArgs());
UpdateActualPlaceableData();
}
///
/// Called when the property was changed.
///
protected virtual void OnRotationChanged()
{
RotationChanged?.Invoke(this, new EventArgs());
UpdateActualPlaceableData();
}
///
/// Called when the property was changed.
///
protected virtual void OnActualLocationChanged() => ActualLocationChanged?.Invoke(this, new EventArgs());
///
/// Called when the property was changed.
///
protected virtual void OnActualSizeChanged() => ActualSizeChanged?.Invoke(this, new EventArgs());
///
/// Called when the property was changed.
///
protected virtual void OnBoundaryChanged() => BoundaryChanged?.Invoke(this, new EventArgs());
#endregion
}