// Copyright (c) Craftwork Games. All rights reserved. // Licensed under the MIT license. // See LICENSE file in the project root for full license information. using System; using Microsoft.Xna.Framework; namespace MonoGame.Extended.Graphics; /// /// Represents a nine-patch texture. /// /// /// /// A nine-patch texture is a specialized texture object used for rendering scalable graphical assets, /// particularly user interface (UI) elements.It consists of a single texture region subdivided into nine /// distinct subregions. When rendered, the four corner subregions remain unscaled, preserving their original /// dimensions. The top and bottom edge subregions are stretched horizontally, while the left and right edge /// subregions are stretched vertically. The central subregion is scaled along both axes to fill the desired /// dimensions. /// /// /// This approach is highly beneficial for UI components that require dynamic scaling, such as containers for /// menus, dialog boxes, or other resizable elements. By leveraging the nine-patch texture, these graphical /// assets can be seamlessly scaled to different sizes while maintaining their visual integrity and preventing /// undesirable distortions or stretching artifacts. /// /// public class NinePatch { /// The index representing the top-left patch. public const int TopLeft = 0; /// The index representing the top-middle patch. public const int TopMiddle = 1; /// The index representing the top-right patch. public const int TopRight = 2; /// The index representing the middle-left patch. public const int MiddleLeft = 3; /// The index representing the middle patch. public const int Middle = 4; /// The index representing the middle-right patch. public const int MiddleRight = 5; /// The index representing the bottom-left patch. public const int BottomLeft = 6; /// The index representing the bottom-middle patch. public const int BottomMiddle = 7; /// The index representing the bottom-right patch. public const int BottomRight = 8; private readonly Texture2DRegion[] _patches; /// /// Gets the name assigned to this nine-patch. /// public string Name { get; } /// /// The size of the border patches around the middle patch. /// public Thickness Padding { get; } /// /// Gets a read-only span of the texture regions that make up the nine-patch. /// /// /// Elements are in order of top-left, top-middle, top-right, middle-left, middle, middle-right, bottom-left, /// bottom-middle, and bottom-right. /// public ReadOnlySpan Patches => _patches; /// /// Initializes a new instance of the class with the specified patches. /// /// /// The array should contain the elements in the order of top-left, top-middle, /// top-right, middle-left, middle, middle-right, bottom-left, bottom-middle, and bottom-right. /// /// An array of nine objects. /// Thrown if is null. /// /// Thrown if does not contain exactly nine elements. /// public NinePatch(Texture2DRegion[] patches) : this(patches, null) { } /// /// Initializes a new instance of the class with the specified patches and name. /// /// /// An array of nine objects. /// The top, left, bottom and right regions must to be of exactly the same size. /// Mid patches can be as small as 1x1. /// /// /// The name of the nine-patch. If null or empty, a default name will be generated based on the texture name of the /// top-left patch. /// /// Thrown if is null. /// /// Thrown if does not contain exactly nine elements. /// public NinePatch(Texture2DRegion[] patches, string name) { ArgumentNullException.ThrowIfNull(patches); if (patches.Length != 9) { throw new ArgumentException($"{nameof(patches)} must contain exactly 9 elements.", nameof(patches)); } if (string.IsNullOrEmpty(name)) { name = $"{patches[0].Texture.Name}-nine-patch"; } _patches = patches; Size topLeft = patches[NinePatch.TopLeft].OriginalSize; Size bottomRight = patches[NinePatch.BottomRight].OriginalSize; Padding = new Thickness(topLeft.Width, topLeft.Height, bottomRight.Width, bottomRight.Height); Name = name; } }