diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d1c38f..149dc1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Improvements - Increased Element area calculation recursion limit to 64 - Improved the SquishingGroup algorithm by prioritizing each element's final size - Allow specifying start and end indices when drawing a Paragraph +- Allow elements with larger children to influence a panel's scrollable area Fixes - Fixed images not updating their hidden state properly when the displayed texture changes diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index 7d9f55a..9616eb0 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -859,14 +859,16 @@ namespace MLEM.Ui.Elements { /// Returns this element's lowest child element (in terms of y position) that matches the given condition. /// /// The condition to match + /// Whether to evaluate based on the child's , rather than its . /// The lowest element, or null if no such element exists - public Element GetLowestChild(Func condition = null) { + public Element GetLowestChild(Func condition = null, bool total = false) { Element lowest = null; var lowestX = float.MinValue; foreach (var child in this.Children) { if (condition != null && !condition(child)) continue; - var x = !child.Anchor.IsTopAligned() ? child.UnscrolledArea.Height : child.UnscrolledArea.Bottom; + var covered = total ? child.GetTotalCoveredArea(true) : child.UnscrolledArea; + var x = !child.Anchor.IsTopAligned() ? covered.Height : covered.Bottom; if (x >= lowestX) { lowest = child; lowestX = x; @@ -879,14 +881,16 @@ namespace MLEM.Ui.Elements { /// Returns this element's rightmost child (in terms of x position) that matches the given condition. /// /// The condition to match + /// Whether to evaluate based on the child's , rather than its . /// The rightmost element, or null if no such element exists - public Element GetRightmostChild(Func condition = null) { + public Element GetRightmostChild(Func condition = null, bool total = false) { Element rightmost = null; var rightmostX = float.MinValue; foreach (var child in this.Children) { if (condition != null && !condition(child)) continue; - var x = !child.Anchor.IsLeftAligned() ? child.UnscrolledArea.Width : child.UnscrolledArea.Right; + var covered = total ? child.GetTotalCoveredArea(true) : child.UnscrolledArea; + var x = !child.Anchor.IsLeftAligned() ? covered.Width : covered.Right; if (x >= rightmostX) { rightmost = child; rightmostX = x; @@ -900,8 +904,9 @@ namespace MLEM.Ui.Elements { /// The returned element's will always be equal to this element's . /// /// The condition to match + /// Whether to evaluate based on the child's , rather than its . /// The lowest older sibling of this element, or null if no such element exists - public Element GetLowestOlderSibling(Func condition = null) { + public Element GetLowestOlderSibling(Func condition = null, bool total = false) { if (this.Parent == null) return null; Element lowest = null; @@ -910,7 +915,7 @@ namespace MLEM.Ui.Elements { break; if (condition != null && !condition(child)) continue; - if (lowest == null || child.UnscrolledArea.Bottom >= lowest.UnscrolledArea.Bottom) + if (lowest == null || (total ? child.GetTotalCoveredArea(true) : child.UnscrolledArea).Bottom >= lowest.UnscrolledArea.Bottom) lowest = child; } return lowest; @@ -992,6 +997,21 @@ namespace MLEM.Ui.Elements { yield return parent; } + /// + /// Returns the total covered area of this element, which is its (or ), unioned with all of the total covered areas of its . + /// The returned area is only different from this element's (or ) if it has any that are outside of this element's area, or are bigger than this element. + /// + /// Whether to use elements' (instead of their ). + /// This element's total covered area. + public RectangleF GetTotalCoveredArea(bool unscrolled) { + var ret = unscrolled ? this.UnscrolledArea : this.Area; + foreach (var child in this.Children) { + if (!child.IsHidden) + ret = RectangleF.Union(ret, child.GetTotalCoveredArea(unscrolled)); + } + return ret; + } + /// /// Returns a subset of that are currently relevant in terms of drawing and input querying. /// A only returns elements that are currently in view here. diff --git a/MLEM.Ui/Elements/Panel.cs b/MLEM.Ui/Elements/Panel.cs index d5f4cf9..70e7e27 100644 --- a/MLEM.Ui/Elements/Panel.cs +++ b/MLEM.Ui/Elements/Panel.cs @@ -230,8 +230,11 @@ namespace MLEM.Ui.Elements { base.OnChildAreaDirty(child, grandchild); // we only need to scroll when a grandchild changes, since all of our children are forced // to be auto-anchored and so will automatically propagate their changes up to us - if (grandchild) + if (grandchild) { this.ScrollChildren(); + // we also need to re-setup here in case the child is involved in a special GetTotalCoveredArea + this.ScrollSetup(); + } } /// @@ -253,8 +256,8 @@ namespace MLEM.Ui.Elements { float childrenHeight; if (this.Children.Count > 1) { var firstChild = this.Children.FirstOrDefault(c => c != this.ScrollBar); - var lowestChild = this.GetLowestChild(c => c != this.ScrollBar && !c.IsHidden); - childrenHeight = lowestChild.Area.Bottom - firstChild.Area.Top; + var lowestChild = this.GetLowestChild(c => c != this.ScrollBar && !c.IsHidden, true); + childrenHeight = lowestChild.GetTotalCoveredArea(false).Bottom - firstChild.Area.Top; } else { // if we only have one child (the scroll bar), then the children take up no visual height childrenHeight = 0;