File: Region.cs
Web Access
Project: src\src\Controls\src\Core\Controls.Core.csproj (Microsoft.Maui.Controls)
#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.Maui.Graphics;
 
namespace Microsoft.Maui.Controls
{
	/// <include file="../../docs/Microsoft.Maui.Controls/Region.xml" path="Type[@FullName='Microsoft.Maui.Controls.Region']/Docs/*" />
	public struct Region : IEquatable<Region>
	{
		// While Regions are currently rectangular, they could in the future be transformed into any shape.
		// As such the internals of how it keeps shapes is hidden, so that future internal changes can occur to support shapes
		// such as circles if required, without affecting anything else.
 
		IReadOnlyList<Rect> Regions { get; }
		readonly Thickness? _inflation;
 
		Region(IList<Rect> positions) : this()
		{
			Regions = new ReadOnlyCollection<Rect>(positions);
		}
 
		Region(IList<Rect> positions, Thickness inflation) : this(positions)
		{
			_inflation = inflation;
		}
 
		public static Region FromRectangles(IEnumerable<Rect> rectangles)
		{
			var list = rectangles.ToList();
			return new Region(list);
		}
 
		/// <include file="../../docs/Microsoft.Maui.Controls/Region.xml" path="//Member[@MemberName='FromLines']/Docs/*" />
		public static Region FromLines(double[] lineHeights, double maxWidth, double startX, double endX, double startY)
		{
			var positions = new List<Rect>();
			var endLine = lineHeights.Length - 1;
			var lineHeightTotal = startY;
 
			for (var i = 0; i <= endLine; i++)
				if (endLine != 0) // MultiLine
				{
					if (i == 0) // First Line
						positions.Add(new Rect(startX, lineHeightTotal, maxWidth - startX, lineHeights[i]));
 
					else if (i != endLine) // Middle Line
						positions.Add(new Rect(0, lineHeightTotal, maxWidth, lineHeights[i]));
 
					else // End Line
						positions.Add(new Rect(0, lineHeightTotal, endX, lineHeights[i]));
 
					lineHeightTotal += lineHeights[i];
				}
				else // SingleLine
					positions.Add(new Rect(startX, lineHeightTotal, endX - startX, lineHeights[i]));
 
			return new Region(positions);
		}
 
		/// <include file="../../docs/Microsoft.Maui.Controls/Region.xml" path="//Member[@MemberName='Contains'][1]/Docs/*" />
		public bool Contains(Point pt)
		{
			return Contains(pt.X, pt.Y);
		}
 
		/// <include file="../../docs/Microsoft.Maui.Controls/Region.xml" path="//Member[@MemberName='Contains'][2]/Docs/*" />
		public bool Contains(double x, double y)
		{
			if (Regions == null)
				return false;
 
			for (int i = 0; i < Regions.Count; i++)
				if (Regions[i].Contains(x, y))
					return true;
 
			return false;
		}
 
		/// <include file="../../docs/Microsoft.Maui.Controls/Region.xml" path="//Member[@MemberName='Deflate']/Docs/*" />
		public Region Deflate()
		{
			if (_inflation == null)
				return this;
 
			return Inflate(_inflation.Value.Left * -1, _inflation.Value.Top * -1, _inflation.Value.Right * -1, _inflation.Value.Bottom * -1);
		}
 
		/// <include file="../../docs/Microsoft.Maui.Controls/Region.xml" path="//Member[@MemberName='Inflate'][1]/Docs/*" />
		public Region Inflate(double size)
		{
			return Inflate(size, size, size, size);
		}
 
		/// <include file="../../docs/Microsoft.Maui.Controls/Region.xml" path="//Member[@MemberName='Inflate'][2]/Docs/*" />
		public Region Inflate(double left, double top, double right, double bottom)
		{
			if (Regions == null)
				return this;
 
			Rect[] rectangles = new Rect[Regions.Count];
			for (int i = 0; i < Regions.Count; i++)
			{
				var region = Regions[i];
 
				region.Top -= top;
 
				region.Left -= left;
				region.Width += right + left;
 
				region.Height += bottom + top;
 
				rectangles[i] = region;
			}
 
			var inflation = new Thickness(_inflation == null ? left : left + _inflation.Value.Left,
									   _inflation == null ? top : top + _inflation.Value.Top,
									   _inflation == null ? right : right + _inflation.Value.Right,
									   _inflation == null ? bottom : bottom + _inflation.Value.Bottom);
 
			return new Region(rectangles, inflation);
		}
 
		public bool Equals(Region other) =>
			Regions == other.Regions && _inflation == other._inflation;
 
		public override bool Equals(object obj) => obj is Region other && Equals(other);
 
		public override int GetHashCode() => Regions.GetHashCode() ^ _inflation?.GetHashCode() ?? 0;
 
		public static bool operator ==(Region left, Region right) => left.Equals(right);
 
		public static bool operator !=(Region left, Region right) => !(left == right);
	}
}