1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-10-31 21:00:51 +01:00
MLEM/MLEM.Ui/Elements/Image.cs

149 lines
6.6 KiB
C#
Raw Normal View History

2019-08-27 21:44:02 +02:00
using System;
2019-08-09 22:23:16 +02:00
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
2022-04-25 15:25:58 +02:00
using MLEM.Graphics;
using MLEM.Misc;
2019-08-09 22:23:16 +02:00
using MLEM.Textures;
using MLEM.Ui.Style;
2022-08-20 11:39:28 +02:00
#if FNA
using MLEM.Extensions;
#endif
2019-08-09 22:23:16 +02:00
namespace MLEM.Ui.Elements {
2020-05-22 17:02:24 +02:00
/// <summary>
/// An image element to be used inside of a <see cref="UiSystem"/>.
/// An image is simply an element that displays a supplied <see cref="TextureRegion"/> and optionally allows for the texture region to remain at its original aspect ratio, regardless of the element's size.
/// </summary>
2019-08-09 22:23:16 +02:00
public class Image : Element {
2020-05-22 17:02:24 +02:00
/// <summary>
/// The color to render the image at
/// </summary>
public StyleProp<Color> Color;
2020-05-22 17:02:24 +02:00
/// <summary>
/// A callback to retrieve the <see cref="TextureRegion"/> that this image should render.
/// This can be used if the image changes frequently.
/// </summary>
2019-09-26 17:39:38 +02:00
public TextureCallback GetTextureCallback;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The texture that this <see cref="TextureRegion"/> should render
/// </summary>
public TextureRegion Texture {
2020-05-17 00:59:15 +02:00
get {
this.CheckTextureChange();
return this.displayedTexture;
2020-05-17 00:59:15 +02:00
}
set {
this.explicitlySetTexture = value;
this.CheckTextureChange();
}
}
2020-05-22 17:02:24 +02:00
/// <summary>
/// Whether this image element's <see cref="Element.Size"/> should be based on the size of the <see cref="TextureRegion"/> given.
/// Note that, when scaling to the image's size, the <see cref="Element.Scale"/> is also taken into account.
2020-05-22 17:02:24 +02:00
/// </summary>
public bool ScaleToImage {
get => this.scaleToImage;
set {
if (this.scaleToImage != value) {
this.scaleToImage = value;
this.SetAreaDirty();
}
}
}
2020-05-22 17:02:24 +02:00
/// <summary>
/// Whether to cause the <see cref="TextureRegion"/> to be rendered at its proper aspect ratio.
/// If this is false, the image will be stretched according to this component's size.
/// </summary>
2019-08-27 21:44:02 +02:00
public bool MaintainImageAspect = true;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The <see cref="SpriteEffects"/> that the texture should be rendered with
/// </summary>
2019-09-12 18:44:24 +02:00
public SpriteEffects ImageEffects = SpriteEffects.None;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The scale that the image should be rendered with
/// </summary>
2019-09-12 18:44:24 +02:00
public Vector2 ImageScale = Vector2.One;
2020-05-22 17:02:24 +02:00
/// <summary>
/// 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.
/// </summary>
2019-09-12 18:44:24 +02:00
public float ImageRotation;
2019-08-09 22:23:16 +02:00
/// <inheritdoc />
public override bool IsHidden => base.IsHidden || this.Texture == null;
private bool scaleToImage;
private TextureRegion explicitlySetTexture;
private TextureRegion displayedTexture;
2020-05-22 17:02:24 +02:00
/// <summary>
/// Creates a new image with the given settings
/// </summary>
/// <param name="anchor">The image's anchor</param>
/// <param name="size">The image's size</param>
/// <param name="texture">The texture the image should render</param>
/// <param name="scaleToImage">Whether this image's size should be based on the texture's size</param>
2019-08-09 22:23:16 +02:00
public Image(Anchor anchor, Vector2 size, TextureRegion texture, bool scaleToImage = false) : base(anchor, size) {
2019-09-26 17:39:38 +02:00
this.Texture = texture;
this.scaleToImage = scaleToImage;
this.CanBeSelected = false;
this.CanBeMoused = false;
}
2020-05-22 17:02:24 +02:00
/// <inheritdoc cref="Image(Anchor,Vector2,TextureRegion,bool)"/>
2019-09-26 17:39:38 +02:00
public Image(Anchor anchor, Vector2 size, TextureCallback getTextureCallback, bool scaleToImage = false) : base(anchor, size) {
this.GetTextureCallback = getTextureCallback;
this.Texture = getTextureCallback(this);
this.scaleToImage = scaleToImage;
2019-08-28 18:27:17 +02:00
this.CanBeSelected = false;
2019-09-11 20:10:28 +02:00
this.CanBeMoused = false;
2019-08-09 22:23:16 +02:00
}
2020-05-22 17:02:24 +02:00
/// <inheritdoc />
protected override Vector2 CalcActualSize(RectangleF parentArea) {
return this.Texture != null && this.scaleToImage ? this.Texture.Size.ToVector2() * this.Scale : base.CalcActualSize(parentArea);
2019-09-26 17:39:38 +02:00
}
/// <inheritdoc />
public override void Update(GameTime time) {
this.CheckTextureChange();
base.Update(time);
}
2020-05-22 17:02:24 +02:00
/// <inheritdoc />
2022-04-25 15:25:58 +02:00
public override void Draw(GameTime time, SpriteBatch batch, float alpha, SpriteBatchContext context) {
2020-05-17 00:59:15 +02:00
if (this.Texture == null)
2019-09-26 17:39:38 +02:00
return;
2020-05-17 00:59:15 +02:00
var center = new Vector2(this.Texture.Width / 2F, this.Texture.Height / 2F);
2019-11-05 13:28:41 +01:00
var color = this.Color.OrDefault(Microsoft.Xna.Framework.Color.White) * alpha;
2019-08-27 21:44:02 +02:00
if (this.MaintainImageAspect) {
2020-05-17 00:59:15 +02:00
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);
2019-08-27 21:44:02 +02:00
} else {
2020-05-17 00:59:15 +02:00
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);
2019-08-27 21:44:02 +02:00
}
2022-04-25 15:25:58 +02:00
base.Draw(time, batch, alpha, context);
2019-08-09 22:23:16 +02:00
}
private void CheckTextureChange() {
var newTexture = this.GetTextureCallback?.Invoke(this) ?? this.explicitlySetTexture;
if (this.displayedTexture == newTexture)
return;
var nullChanged = this.displayedTexture == null != (newTexture == null);
this.displayedTexture = newTexture;
if (nullChanged || this.scaleToImage)
this.SetAreaDirty();
}
2020-05-22 17:02:24 +02:00
/// <summary>
/// A delegate method used for <see cref="Image.GetTextureCallback"/>
/// </summary>
/// <param name="image">The current image element</param>
2019-09-26 17:39:38 +02:00
public delegate TextureRegion TextureCallback(Image image);
2019-08-09 22:23:16 +02:00
}
2022-06-17 18:23:47 +02:00
}