diff --git a/CHANGELOG.md b/CHANGELOG.md
index 22fc6bd..c75b094 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -32,6 +32,7 @@ Additions
- Added Element.AutoSizeAddedAbsolute to allow for more granular control of auto-sizing
- Added Element.OnAddedToUi and Element.OnRemovedFromUi
- Added ScrollBar.MouseDragScrolling
+- Added Panel.ScrollToElement
Improvements
- Allow elements to auto-adjust their size even when their children are aligned oddly
diff --git a/MLEM.Ui/Elements/Panel.cs b/MLEM.Ui/Elements/Panel.cs
index 6ccf880..dafda63 100644
--- a/MLEM.Ui/Elements/Panel.cs
+++ b/MLEM.Ui/Elements/Panel.cs
@@ -84,9 +84,7 @@ namespace MLEM.Ui.Elements {
return;
if (e == null || !e.GetParentTree().Contains(this))
return;
- var firstChild = this.Children.FirstOrDefault(c => c != this.ScrollBar);
- if (firstChild != null)
- this.ScrollBar.CurrentValue = (e.Area.Center.Y - this.Area.Height / 2 - firstChild.Area.Top) / e.Scale + this.ChildPadding.Value.Height / 2;
+ this.ScrollToElement(e);
};
this.AddChild(this.ScrollBar);
}
@@ -116,15 +114,6 @@ namespace MLEM.Ui.Elements {
this.ScrollSetup();
}
- private void ScrollChildren() {
- if (!this.scrollOverflow)
- return;
- // we ignore false grandchildren so that the children of the scroll bar stay in place
- foreach (var child in this.GetChildren(c => c != this.ScrollBar, true, true))
- child.ScrollOffset.Y = -this.ScrollBar.CurrentValue;
- this.relevantChildrenDirty = true;
- }
-
///
public override void ForceUpdateSortedChildren() {
base.ForceUpdateSortedChildren();
@@ -144,26 +133,6 @@ namespace MLEM.Ui.Elements {
base.RemoveChildren(e => e != this.ScrollBar && (condition == null || condition(e)));
}
- ///
- protected override IList GetRelevantChildren() {
- var relevant = base.GetRelevantChildren();
- if (this.scrollOverflow) {
- if (this.relevantChildrenDirty)
- this.ForceUpdateRelevantChildren();
- relevant = this.relevantChildren;
- }
- return relevant;
- }
-
- ///
- protected override void OnChildAreaDirty(Element child, bool grandchild) {
- 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)
- this.ScrollChildren();
- }
-
///
public override void Draw(GameTime time, SpriteBatch batch, float alpha, SpriteBatchContext context) {
// draw children onto the render target if we have one
@@ -208,11 +177,32 @@ namespace MLEM.Ui.Elements {
return base.GetElementUnderPos(position);
}
- private RectangleF GetRenderTargetArea() {
- var area = this.ChildPaddedArea;
- area.X = this.DisplayArea.X;
- area.Width = this.DisplayArea.Width;
- return area;
+ ///
+ public override void Dispose() {
+ if (this.renderTarget != null) {
+ this.renderTarget.Dispose();
+ this.renderTarget = null;
+ }
+ base.Dispose();
+ }
+
+ ///
+ /// Scrolls this panel's to the given in such a way that its center is positioned in the center of this panel.
+ ///
+ /// The element to scroll to.
+ public void ScrollToElement(Element element) {
+ this.ScrollToElement(element.Area.Center.Y);
+ }
+
+ ///
+ /// Scrolls this panel's to the given coordinate in such a way that the coordinate is positioned in the center of this panel.
+ ///
+ /// The y coordinate to scroll to, which should have this element's applied.
+ public void ScrollToElement(float elementY) {
+ var firstChild = this.Children.FirstOrDefault(c => c != this.ScrollBar);
+ if (firstChild == null)
+ return;
+ this.ScrollBar.CurrentValue = (elementY - this.Area.Height / 2 - firstChild.Area.Top) / this.Scale + this.ChildPadding.Value.Height / 2;
}
///
@@ -226,6 +216,26 @@ namespace MLEM.Ui.Elements {
this.SetScrollBarStyle();
}
+ ///
+ protected override IList GetRelevantChildren() {
+ var relevant = base.GetRelevantChildren();
+ if (this.scrollOverflow) {
+ if (this.relevantChildrenDirty)
+ this.ForceUpdateRelevantChildren();
+ relevant = this.relevantChildren;
+ }
+ return relevant;
+ }
+
+ ///
+ protected override void OnChildAreaDirty(Element child, bool grandchild) {
+ 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)
+ this.ScrollChildren();
+ }
+
///
/// Prepares the panel for auto-scrolling, creating the render target and setting up the scroll bar's maximum value.
///
@@ -274,15 +284,6 @@ namespace MLEM.Ui.Elements {
}
}
- ///
- public override void Dispose() {
- if (this.renderTarget != null) {
- this.renderTarget.Dispose();
- this.renderTarget = null;
- }
- base.Dispose();
- }
-
private void SetScrollBarStyle() {
if (this.ScrollBar == null)
return;
@@ -309,5 +310,21 @@ namespace MLEM.Ui.Elements {
}
}
+ private RectangleF GetRenderTargetArea() {
+ var area = this.ChildPaddedArea;
+ area.X = this.DisplayArea.X;
+ area.Width = this.DisplayArea.Width;
+ return area;
+ }
+
+ private void ScrollChildren() {
+ if (!this.scrollOverflow)
+ return;
+ // we ignore false grandchildren so that the children of the scroll bar stay in place
+ foreach (var child in this.GetChildren(c => c != this.ScrollBar, true, true))
+ child.ScrollOffset.Y = -this.ScrollBar.CurrentValue;
+ this.relevantChildrenDirty = true;
+ }
+
}
}