1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-11-27 23:08:35 +01:00

Compare commits

...

3 commits

4 changed files with 35 additions and 11 deletions

View file

@ -46,10 +46,12 @@ Improvements
- Allow dropdowns to have scrolling panels - Allow dropdowns to have scrolling panels
- Improved Panel performance when adding and removing a lot of children - Improved Panel performance when adding and removing a lot of children
- Don't reset the caret position of a text field when selecting or deselecting it - Don't reset the caret position of a text field when selecting or deselecting it
- Improved UiParser.ParseImage with locks and a callback action
Fixes Fixes
- Fixed panels updating their relevant children too much when the scroll bar is hidden - Fixed panels updating their relevant children too much when the scroll bar is hidden
- Fixed a stack overflow exception when a panel's scroll bar auto-hiding causes elements to gain height - Fixed a stack overflow exception when a panel's scroll bar auto-hiding causes elements to gain height
- Fixed scrolling panels calculating their height incorrectly when their first child is hidden
### MLEM.Extended ### MLEM.Extended
Improvements Improvements

View file

@ -144,6 +144,12 @@ namespace MLEM.Ui.Elements {
ret.X = ret.Y * this.Texture.Width / this.Texture.Height + this.ScaledAutoSizeAddedAbsolute.X; ret.X = ret.Y * this.Texture.Width / this.Texture.Height + this.ScaledAutoSizeAddedAbsolute.X;
if (this.SetHeightBasedOnAspect) if (this.SetHeightBasedOnAspect)
ret.Y = ret.X * this.Texture.Height / this.Texture.Width + this.ScaledAutoSizeAddedAbsolute.Y; ret.Y = ret.X * this.Texture.Height / this.Texture.Width + this.ScaledAutoSizeAddedAbsolute.Y;
} else {
// if we don't have a texture and we auto-set width or height, calculate as if we had a texture with a size of 0
if (this.SetWidthBasedOnAspect)
ret.X = this.ScaledAutoSizeAddedAbsolute.X;
if (this.SetHeightBasedOnAspect)
ret.Y = this.ScaledAutoSizeAddedAbsolute.Y;
} }
return ret; return ret;
} }

View file

@ -223,10 +223,10 @@ namespace MLEM.Ui.Elements {
/// </summary> /// </summary>
/// <param name="elementY">The y coordinate to scroll to, which should have this element's <see cref="Element.Scale"/> applied.</param> /// <param name="elementY">The y coordinate to scroll to, which should have this element's <see cref="Element.Scale"/> applied.</param>
public void ScrollToElement(float elementY) { public void ScrollToElement(float elementY) {
var firstChild = this.Children.FirstOrDefault(c => c != this.ScrollBar); var highestValidChild = this.Children.FirstOrDefault(c => c != this.ScrollBar && !c.IsHidden);
if (firstChild == null) if (highestValidChild == null)
return; return;
this.ScrollBar.CurrentValue = (elementY - this.Area.Height / 2 - firstChild.Area.Top) / this.Scale + this.ChildPadding.Value.Height / 2; this.ScrollBar.CurrentValue = (elementY - this.Area.Height / 2 - highestValidChild.Area.Top) / this.Scale + this.ChildPadding.Value.Height / 2;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -282,9 +282,9 @@ namespace MLEM.Ui.Elements {
float childrenHeight; float childrenHeight;
if (this.Children.Count > 1) { if (this.Children.Count > 1) {
var firstChild = this.Children.FirstOrDefault(c => c != this.ScrollBar); var highestValidChild = this.Children.FirstOrDefault(c => c != this.ScrollBar && !c.IsHidden);
var lowestChild = this.GetLowestChild(c => c != this.ScrollBar && !c.IsHidden, true); var lowestChild = this.GetLowestChild(c => c != this.ScrollBar && !c.IsHidden, true);
childrenHeight = lowestChild.GetTotalCoveredArea(false).Bottom - firstChild.Area.Top; childrenHeight = lowestChild.GetTotalCoveredArea(false).Bottom - highestValidChild.Area.Top;
} else { } else {
// if we only have one child (the scroll bar), then the children take up no visual height // if we only have one child (the scroll bar), then the children take up no visual height
childrenHeight = 0; childrenHeight = 0;

View file

@ -10,6 +10,7 @@ using MLEM.Ui.Style;
#if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER #if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER
using System.Net.Http; using System.Net.Http;
#else #else
using System.Net; using System.Net;
#endif #endif
@ -138,23 +139,33 @@ namespace MLEM.Ui.Parsers {
/// This method invokes an asynchronouns action, meaning the <see cref="Image"/>'s <see cref="Image.Texture"/> will likely not have loaded in when this method returns. /// This method invokes an asynchronouns action, meaning the <see cref="Image"/>'s <see cref="Image.Texture"/> will likely not have loaded in when this method returns.
/// </summary> /// </summary>
/// <param name="path">The absolute, relative or web path to the image.</param> /// <param name="path">The absolute, relative or web path to the image.</param>
/// <param name="onImageFetched">An action that is invoked with the loaded image once it is fetched. Note that this action will be invoked asynchronously.</param>
/// <returns>The loaded image.</returns> /// <returns>The loaded image.</returns>
/// <exception cref="NullReferenceException">Thrown if <see cref="GraphicsDevice"/> is null, or if there is an <see cref="Exception"/> loading the image and <see cref="ImageExceptionHandler"/> is unset.</exception> /// <exception cref="NullReferenceException">Thrown if <see cref="GraphicsDevice"/> is null, or if there is an <see cref="Exception"/> loading the image and <see cref="ImageExceptionHandler"/> is unset.</exception>
protected Image ParseImage(string path) { protected Image ParseImage(string path, Action<TextureRegion> onImageFetched = null) {
if (this.GraphicsDevice == null) if (this.GraphicsDevice == null)
throw new NullReferenceException("A UI parser requires a GraphicsDevice for parsing images"); throw new NullReferenceException("A UI parser requires a GraphicsDevice for parsing images");
var imageLock = new object();
TextureRegion image = null; TextureRegion image = null;
return new Image(Anchor.AutoLeft, Vector2.One, _ => image) { return new Image(Anchor.AutoLeft, Vector2.One, _ => {
lock (imageLock)
return image;
}) {
SetHeightBasedOnAspect = true, SetHeightBasedOnAspect = true,
OnAddedToUi = e => { OnAddedToUi = e => {
if (image == null) bool imageNull;
lock (imageLock)
imageNull = image == null;
if (imageNull)
LoadImageAsync(); LoadImageAsync();
}, },
OnRemovedFromUi = e => { OnRemovedFromUi = e => {
lock (imageLock) {
image?.Texture.Dispose(); image?.Texture.Dispose();
image = null; image = null;
} }
}
}; };
async void LoadImageAsync() { async void LoadImageAsync() {
@ -178,7 +189,12 @@ namespace MLEM.Ui.Parsers {
using (var stream = Path.IsPathRooted(path) ? File.OpenRead(path) : TitleContainer.OpenStream(path)) using (var stream = Path.IsPathRooted(path) ? File.OpenRead(path) : TitleContainer.OpenStream(path))
tex = Texture2D.FromStream(this.GraphicsDevice, stream); tex = Texture2D.FromStream(this.GraphicsDevice, stream);
} }
lock (imageLock) {
if (image == null) {
image = new TextureRegion(tex); image = new TextureRegion(tex);
onImageFetched?.Invoke(image);
}
}
} catch (Exception e) { } catch (Exception e) {
if (this.ImageExceptionHandler != null) { if (this.ImageExceptionHandler != null) {
this.ImageExceptionHandler.Invoke(path, e); this.ImageExceptionHandler.Invoke(path, e);