1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-05-13 20:58:45 +02:00

fixed stack overflow with nested auto-sized children

This commit is contained in:
Ell 2021-03-29 06:41:38 +02:00
parent 3e20aaf6c5
commit 79ba6864e7
2 changed files with 52 additions and 22 deletions

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@ -524,27 +525,10 @@ namespace MLEM.Ui.Elements {
var parentArea = this.Parent != null ? this.Parent.ChildPaddedArea : (RectangleF) this.system.Viewport;
var parentCenterX = parentArea.X + parentArea.Width / 2;
var parentCenterY = parentArea.Y + parentArea.Height / 2;
var actualSize = this.CalcActualSize(parentArea);
UpdateDisplayArea(actualSize);
if (this.Children.Count > 0) {
var autoSize = this.DisplayArea.Size;
if (this.SetHeightBasedOnChildren) {
var lowest = this.GetLowestChild(e => !e.IsHidden);
if (lowest != null)
autoSize.Y = lowest.UnscrolledArea.Bottom - this.DisplayArea.Y + this.ScaledChildPadding.Bottom;
}
if (this.SetWidthBasedOnChildren) {
var rightmost = this.GetRightmostChild(e => !e.IsHidden);
if (rightmost != null)
autoSize.X = rightmost.UnscrolledArea.Right - this.DisplayArea.X + this.ScaledChildPadding.Right;
}
if (this.TreatSizeAsMinimum)
autoSize = Vector2.Max(autoSize, actualSize);
if (autoSize != this.DisplayArea.Size)
UpdateDisplayArea(autoSize);
}
var recursion = 0;
UpdateDisplayArea(actualSize);
void UpdateDisplayArea(Vector2 newSize) {
var pos = new Vector2();
@ -639,9 +623,38 @@ namespace MLEM.Ui.Elements {
this.System.OnElementAreaUpdated?.Invoke(this);
foreach (var child in this.Children)
child.SetAreaDirty();
// clear the dirty flag again in case our children just set us dirty
this.areaDirty = false;
child.ForceUpdateArea();
if (this.Children.Count > 0) {
Element foundChild = null;
var autoSize = this.Area.Size;
if (this.SetHeightBasedOnChildren) {
var lowest = this.GetLowestChild(e => !e.IsHidden);
var newY = lowest?.UnscrolledArea.Bottom - pos.Y + this.ScaledChildPadding.Bottom;
if (newY != null && autoSize.Y != newY) {
autoSize.Y = newY.Value;
foundChild = lowest;
}
}
if (this.SetWidthBasedOnChildren) {
var rightmost = this.GetRightmostChild(e => !e.IsHidden);
var newX = rightmost?.UnscrolledArea.Right - pos.X + this.ScaledChildPadding.Right;
if (newX != null && autoSize.X != newX) {
autoSize.X = newX.Value;
foundChild = rightmost;
}
}
if (this.TreatSizeAsMinimum)
autoSize = Vector2.Max(autoSize, actualSize);
if (autoSize != this.Area.Size) {
recursion++;
if (recursion >= 16) {
throw new ArithmeticException($"The area of {this} with root {this.Root?.Name} has recursively updated too often. Does its child {foundChild} contain any conflicting auto-sizing settings?");
} else {
UpdateDisplayArea(autoSize);
}
}
}
}
}

View file

@ -22,6 +22,7 @@ using MLEM.Ui;
using MLEM.Ui.Elements;
using MLEM.Ui.Style;
using MonoGame.Extended.Tiled;
using Group = MLEM.Ui.Elements.Group;
namespace Sandbox {
public class GameImpl : MlemGame {
@ -205,6 +206,22 @@ namespace Sandbox {
invalidPanel.AddChild(new Paragraph(Anchor.AutoRight, 1, "This is some test text!", true));
invalidPanel.AddChild(new VerticalSpace(1));
this.UiSystem.Add("Invalid", invalidPanel);*/
var loadGroup = new Group(Anchor.TopLeft, Vector2.One, false);
var loadPanel = loadGroup.AddChild(new Panel(Anchor.Center, new Vector2(150, 150), Vector2.Zero, false, true, new Point(5, 10), false) {
ChildPadding = new Padding(5, 10, 5, 5)
});
for (var i = 0; i < 1; i++) {
var button = loadPanel.AddChild(new Button(Anchor.AutoLeft, new Vector2(1)) {
SetHeightBasedOnChildren = true,
Padding = new Padding(0, 0, 0, 1),
ChildPadding = new Vector2(3)
});
button.AddChild(new Group(Anchor.AutoLeft, new Vector2(0.5F, 30), false) {
CanBeMoused = false
});
}
this.UiSystem.Add("Load", loadGroup);
}
protected override void DoUpdate(GameTime gameTime) {