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;