using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MLEM.Extensions; using MLEM.Graphics; using MLEM.Misc; using MLEM.Textures; using MLEM.Ui.Style; namespace MLEM.Ui.Elements { /// /// An image element to be used inside of a . /// An image is simply an element that displays a supplied and optionally allows for the texture region to remain at its original aspect ratio, regardless of the element's size. /// public class Image : Element { /// /// The color to render the image at /// public StyleProp Color; /// /// A callback to retrieve the that this image should render. /// This can be used if the image changes frequently. /// public TextureCallback GetTextureCallback; /// /// The texture that this should render /// public TextureRegion Texture { get { if (this.GetTextureCallback != null) this.Texture = this.GetTextureCallback(this); return this.texture; } set { if (this.texture != value) { this.texture = value; this.IsHidden = this.texture == null; if (this.scaleToImage) this.SetAreaDirty(); } } } /// /// Whether this image element's should be based on the size of the given. /// Note that, when scaling to the image's size, the is also taken into account. /// public bool ScaleToImage { get => this.scaleToImage; set { if (this.scaleToImage != value) { this.scaleToImage = value; this.SetAreaDirty(); } } } /// /// Whether to cause the to be rendered at its proper aspect ratio. /// If this is false, the image will be stretched according to this component's size. /// public bool MaintainImageAspect = true; /// /// The that the texture should be rendered with /// public SpriteEffects ImageEffects = SpriteEffects.None; /// /// The scale that the image should be rendered with /// public Vector2 ImageScale = Vector2.One; /// /// The rotation that the image should be rendered with. /// Note that increased rotation does not increase this component's size, even if the rotated texture would go out of bounds of this component. /// public float ImageRotation; private bool scaleToImage; private TextureRegion texture; /// /// Creates a new image with the given settings /// /// The image's anchor /// The image's size /// The texture the image should render /// Whether this image's size should be based on the texture's size public Image(Anchor anchor, Vector2 size, TextureRegion texture, bool scaleToImage = false) : base(anchor, size) { this.Texture = texture; this.scaleToImage = scaleToImage; this.CanBeSelected = false; this.CanBeMoused = false; } /// public Image(Anchor anchor, Vector2 size, TextureCallback getTextureCallback, bool scaleToImage = false) : base(anchor, size) { this.GetTextureCallback = getTextureCallback; this.Texture = getTextureCallback(this); this.scaleToImage = scaleToImage; this.CanBeSelected = false; this.CanBeMoused = false; } /// protected override Vector2 CalcActualSize(RectangleF parentArea) { return this.Texture != null && this.scaleToImage ? this.Texture.Size.ToVector2() * this.Scale : base.CalcActualSize(parentArea); } /// public override void Draw(GameTime time, SpriteBatch batch, float alpha, SpriteBatchContext context) { if (this.Texture == null) return; var center = new Vector2(this.Texture.Width / 2F, this.Texture.Height / 2F); var color = this.Color.OrDefault(Microsoft.Xna.Framework.Color.White) * alpha; if (this.MaintainImageAspect) { var scale = Math.Min(this.DisplayArea.Width / this.Texture.Width, this.DisplayArea.Height / this.Texture.Height); var imageOffset = new Vector2(this.DisplayArea.Width / 2F - this.Texture.Width * scale / 2, this.DisplayArea.Height / 2F - this.Texture.Height * scale / 2); batch.Draw(this.Texture, this.DisplayArea.Location + center * scale + imageOffset, color, this.ImageRotation, center, scale * this.ImageScale, this.ImageEffects, 0); } else { var scale = new Vector2(1F / this.Texture.Width, 1F / this.Texture.Height) * this.DisplayArea.Size; batch.Draw(this.Texture, this.DisplayArea.Location + center * scale, color, this.ImageRotation, center, scale * this.ImageScale, this.ImageEffects, 0); } base.Draw(time, batch, alpha, context); } /// /// A delegate method used for /// /// The current image element public delegate TextureRegion TextureCallback(Image image); } }