From 333b4b033ec387721127df0ea8873505ee9a8832 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Wed, 23 Sep 2020 00:41:24 +0200 Subject: [PATCH] Added a fail-safe for elements with conflicting auto-sizing settings so that they don't cause a cryptic stack overflow --- MLEM.Ui/Elements/Element.cs | 19 ++++++++++++++----- Sandbox/GameImpl.cs | 8 ++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index 0689143..df9486f 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -175,6 +175,7 @@ namespace MLEM.Ui.Elements { } } private bool areaDirty; + private int areaUpdateRecursionCount; /// /// The of this element, but with applied. /// @@ -612,14 +613,14 @@ namespace MLEM.Ui.Elements { child.ForceUpdateArea(); if (this.Children.Count > 0) { - var changed = false; + Element foundChild = null; if (this.SetHeightBasedOnChildren) { var lowest = this.GetLowestChild(e => !e.IsHidden); if (lowest != null) { var newHeight = (lowest.UnscrolledArea.Bottom - pos.Y + this.ScaledChildPadding.Bottom) / this.Scale; if (!newHeight.Equals(this.size.Y, 0.01F)) { this.size.Y = newHeight; - changed = true; + foundChild = lowest; } } } @@ -629,12 +630,20 @@ namespace MLEM.Ui.Elements { var newWidth = (rightmost.UnscrolledArea.Right - pos.X + this.ScaledChildPadding.Right) / this.Scale; if (!newWidth.Equals(this.size.X, 0.01F)) { this.size.X = newWidth; - changed = true; + foundChild = rightmost; } } } - if (changed) - this.ForceUpdateArea(); + if (foundChild != null) { + this.areaUpdateRecursionCount++; + if (this.areaUpdateRecursionCount >= 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 { + this.ForceUpdateArea(); + } + } else { + this.areaUpdateRecursionCount = 0; + } } } diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs index 6e1f8e5..ca23e65 100644 --- a/Sandbox/GameImpl.cs +++ b/Sandbox/GameImpl.cs @@ -191,6 +191,14 @@ namespace Sandbox { testPanel.AddChild(new Button(Anchor.AutoLeft, new Vector2(0.25F, -1))); testPanel.AddChild(new Button(Anchor.AutoLeft, new Vector2(2500, 1)) {PreventParentSpill = true}); this.UiSystem.Add("Test", testPanel); + + var invalidPanel = new Panel(Anchor.Center, Vector2.Zero, Vector2.Zero) { + SetWidthBasedOnChildren = true, + SetHeightBasedOnChildren = true + }; + invalidPanel.AddChild(new Paragraph(Anchor.AutoRight, 1, "This is some test text!", true)); + invalidPanel.AddChild(new VerticalSpace(1)); + this.UiSystem.Add("Invalid", invalidPanel); } protected override void DoUpdate(GameTime gameTime) {