//
// Derived from System.Drawing.Rectangle.cs
//
// Author:
// Mike Kestner (mkestner@speakeasy.net)
//
// Copyright (C) 2001 Mike Kestner
// Copyright (C) 2004 Novell, Inc. http://www.novell.com
//
namespace Terminal.Gui;
/// Stores a set of four integers that represent the location and size of a rectangle
public struct Rectangle
{
private int width;
private int height;
/// Gets or sets the x-coordinate of the upper-left corner of this Rectangle structure.
public int X;
/// Gets or sets the y-coordinate of the upper-left corner of this Rectangle structure.
public int Y;
/// Gets or sets the width of this Rect structure.
public int Width
{
get => width;
set
{
if (value < 0)
{
throw new ArgumentException ("Width must be greater or equal to 0.");
}
width = value;
}
}
/// Gets or sets the height of this Rectangle structure.
public int Height
{
get => height;
set
{
if (value < 0)
{
throw new ArgumentException ("Height must be greater or equal to 0.");
}
height = value;
}
}
/// Empty Shared Field
/// An uninitialized Rectangle Structure.
public static readonly Rectangle Empty;
/// FromLTRB Shared Method
/// Produces a Rectangle structure from left, top, right and bottom coordinates.
public static Rectangle FromLTRB (
int left,
int top,
int right,
int bottom
)
{
return new Rectangle (
left,
top,
right - left,
bottom - top
);
}
/// Produces a new Rect by inflating an existing Rect by the specified coordinate values.
///
/// Produces a new Rect by inflating an existing Rect by the specified coordinate values. The rectangle is
/// enlarged in both directions along an axis.
///
public static Rectangle Inflate (Rectangle rect, int x, int y)
{
var r = new Rectangle (rect.Location, rect.Size);
r.Inflate (x, y);
return r;
}
/// Inflates an existing Rect by the specified coordinate values.
///
/// This method enlarges this rectangle, not a copy of it. The rectangle is enlarged in both directions along an
/// axis.
///
public void Inflate (int width, int height)
{
// Set dims first so we don't lose the original values on exception
Width += width * 2;
Height += height * 2;
X -= width;
Y -= height;
}
/// Inflates an existing Rect by the specified Sizwe.
///
/// This method enlarges this rectangle, not a copy of it. The rectangle is enlarged in both directions along an
/// axis.
///
public void Inflate (Size size) { Inflate (size.Width, size.Height); }
/// Intersect Shared Method
/// Produces a new Rectangle by intersecting 2 existing Rectangles. Returns Empty if there is no intersection.
public static Rectangle Intersect (Rectangle a, Rectangle b)
{
// MS.NET returns a non-empty rectangle if the two rectangles
// touch each other
if (!a.IntersectsWithInclusive (b))
{
return Empty;
}
return FromLTRB (
Math.Max (a.Left, b.Left),
Math.Max (a.Top, b.Top),
Math.Min (a.Right, b.Right),
Math.Min (a.Bottom, b.Bottom)
);
}
/// Intersect Method
/// Replaces the Rectangle with the intersection of itself and another Rectangle.
public void Intersect (Rectangle rect) { this = Intersect (this, rect); }
/// Produces the uninion of two rectangles.
/// Produces a new Rectangle from the union of 2 existing Rectangles.
public static Rectangle Union (Rectangle a, Rectangle b)
{
//int x1 = Math.Min (a.X, b.X);
//int x2 = Math.Max (a.X + a.Width, b.X + b.Width);
//int y1 = Math.Min (a.Y, b.Y);oS
//int y2 = Math.Max (a.Y + a.Height, b.Y + b.Height);
//return new Rect (x1, y1, x2 - x1, y2 - y1);
int x1 = Math.Min (a.X, b.X);
int x2 = Math.Max (a.X + Math.Abs (a.Width), b.X + Math.Abs (b.Width));
int y1 = Math.Min (a.Y, b.Y);
int y2 = Math.Max (a.Y + Math.Abs (a.Height), b.Y + Math.Abs (b.Height));
return new Rectangle (x1, y1, x2 - x1, y2 - y1);
}
/// Equality Operator
///
/// Compares two Rectangle objects. The return value is based on the equivalence of the Location and Size
/// properties of the two Rectangles.
///
public static bool operator == (Rectangle left, Rectangle right) { return left.Location == right.Location && left.Size == right.Size; }
/// Inequality Operator
///
/// Compares two Rectangle objects. The return value is based on the equivalence of the Location and Size
/// properties of the two Rectangles.
///
public static bool operator != (Rectangle left, Rectangle right) { return left.Location != right.Location || left.Size != right.Size; }
// -----------------------
// Public Constructors
// -----------------------
/// Rectangle Constructor
/// Creates a Rectangle from Point and Size values.
public Rectangle (Point location, Size size)
{
X = location.X;
Y = location.Y;
width = size.Width;
height = size.Height;
Width = width;
Height = height;
}
/// Rectangle Constructor
/// Creates a Rectangle from a specified x,y location and width and height values.
public Rectangle (int x, int y, int width, int height)
{
X = x;
Y = y;
this.width = width;
this.height = height;
Width = this.width;
Height = this.height;
}
/// Bottom Property
/// The Y coordinate of the bottom edge of the Rectangle. Read only.
public int Bottom => Y + Height;
/// IsEmpty Property
/// Indicates if the width or height are zero. Read only.
public bool IsEmpty => X == 0 && Y == 0 && Width == 0 && Height == 0;
/// Left Property
/// The X coordinate of the left edge of the Rectangle. Read only.
public int Left => X;
/// Location Property
/// The Location of the top-left corner of the Rectangle.
public Point Location
{
get => new (X, Y);
set
{
X = value.X;
Y = value.Y;
}
}
/// Right Property
/// The X coordinate of the right edge of the Rectangle. Read only.
public int Right => X + Width;
/// Size Property
/// The Size of the Rectangle.
public Size Size
{
get => new (Width, Height);
set
{
Width = value.Width;
Height = value.Height;
}
}
/// Top Property
/// The Y coordinate of the top edge of the Rectangle. Read only.
public int Top => Y;
/// Contains Method
/// Checks if an x,y coordinate lies within this Rectangle.
public bool Contains (int x, int y) { return x >= Left && x < Right && y >= Top && y < Bottom; }
/// Contains Method
/// Checks if a Point lies within this Rectangle.
public bool Contains (Point pt) { return Contains (pt.X, pt.Y); }
/// Contains Method
/// Checks if a Rectangle lies entirely within this Rectangle.
public bool Contains (Rectangle rect) { return rect == Intersect (this, rect); }
/// Equals Method
/// Checks equivalence of this Rectangle and another object.
public override bool Equals (object obj)
{
if (!(obj is Rectangle))
{
return false;
}
return this == (Rectangle)obj;
}
/// GetHashCode Method
/// Calculates a hashing value.
public override int GetHashCode () { return X ^
((Y << 13) | (Y >>> 19)) ^
((Width << 26) | (Width >>> 6)) ^
((Height << 7) | (Height >>> 25)); }
/// IntersectsWith Method
/// Checks if a Rectangle intersects with this one.
public bool IntersectsWith (Rectangle rect) { return !(Left >= rect.Right || Right <= rect.Left || Top >= rect.Bottom || Bottom <= rect.Top); }
private bool IntersectsWithInclusive (Rectangle r) { return !(Left > r.Right || Right < r.Left || Top > r.Bottom || Bottom < r.Top); }
/// Offset Method
/// Moves the Rectangle a specified distance.
public void Offset (int x, int y)
{
X += x;
Y += y;
}
/// Offset Method
/// Moves the Rectangle a specified distance.
public void Offset (Point pos)
{
X += pos.X;
Y += pos.Y;
}
/// ToString Method
/// Formats the Rectangle as a string in (x,y,w,h) notation.
public override string ToString () { return $"{{X={X},Y={Y},Width={Width},Height={Height}}}"; }
}