diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index 24300fe..61a810c 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -116,6 +116,7 @@ namespace MLEM.Ui.Elements { public float DrawAlpha = 1; public bool HasCustomStyle; public bool SetHeightBasedOnChildren; + public bool CanAutoAnchorsAttach = true; private Rectangle area; public Rectangle Area { @@ -158,45 +159,27 @@ namespace MLEM.Ui.Elements { this.SetAreaDirty(); } - public T AddChild(T element, int index = -1, bool propagateInfo = true) where T : Element { + public T AddChild(T element, int index = -1) where T : Element { if (index < 0 || index > this.Children.Count) index = this.Children.Count; this.Children.Insert(index, element); - if (propagateInfo) { - element.Parent = this; - element.PropagateRoot(this.Root); - element.PropagateUiSystem(this.System); - } + element.Parent = this; + element.PropagateRoot(this.Root); + element.PropagateUiSystem(this.System); this.SetSortedChildrenDirty(); this.SetAreaDirty(); return element; } - public void RemoveChild(Element element, bool propagateInfo = true) { + public void RemoveChild(Element element) { this.Children.Remove(element); - if (propagateInfo) { - element.Parent = null; - element.PropagateRoot(null); - element.PropagateUiSystem(null); - } + element.Parent = null; + element.PropagateRoot(null); + element.PropagateUiSystem(null); this.SetSortedChildrenDirty(); this.SetAreaDirty(); } - public void MoveToFront() { - if (this.Parent != null) { - this.Parent.RemoveChild(this, false); - this.Parent.AddChild(this, -1, false); - } - } - - public void MoveToBack() { - if (this.Parent != null) { - this.Parent.RemoveChild(this, false); - this.Parent.AddChild(this, 0, false); - } - } - public void SetAreaDirty() { this.areaDirty = true; if (this.Anchor >= Anchor.AutoLeft && this.Parent != null) @@ -279,7 +262,7 @@ namespace MLEM.Ui.Elements { } if (this.Anchor >= Anchor.AutoLeft) { - var previousChild = this.GetPreviousChild(false); + var previousChild = this.GetPreviousChild(false, false); if (previousChild != null) { var prevArea = previousChild.GetAreaForAutoAnchors(); switch (this.Anchor) { @@ -335,7 +318,7 @@ namespace MLEM.Ui.Elements { return this.Area; } - public Element GetPreviousChild(bool hiddenAlso) { + public Element GetPreviousChild(bool hiddenAlso, bool unattachableAlso) { if (this.Parent == null) return null; @@ -343,6 +326,8 @@ namespace MLEM.Ui.Elements { foreach (var child in this.Parent.Children) { if (!hiddenAlso && child.IsHidden) continue; + if (!unattachableAlso && !child.CanAutoAnchorsAttach) + continue; if (child == this) break; lastChild = child; diff --git a/MLEM.Ui/Elements/Panel.cs b/MLEM.Ui/Elements/Panel.cs index 3cb243c..79ea216 100644 --- a/MLEM.Ui/Elements/Panel.cs +++ b/MLEM.Ui/Elements/Panel.cs @@ -25,14 +25,16 @@ namespace MLEM.Ui.Elements { this.ScrollBar = new ScrollBar(Anchor.TopRight, new Vector2(scrollSize.X, 1), scrollSize.Y, 0) { StepPerScroll = 10, OnValueChanged = (element, value) => { - var firstChild = this.Children[0]; - // if the first child is the scrollbar, there are no other children - if (firstChild == element) + // if there is only one child, then we have just the scroll bar + if (this.Children.Count == 1) return; + // the "real" first child is the scroll bar, which we want to ignore + var firstChild = this.Children[1]; // as all children have to be auto-aligned, moving the first one up will move all others firstChild.PositionOffset = new Vector2(firstChild.PositionOffset.X, -value.Ceil()); this.ForceUpdateArea(); - } + }, + CanAutoAnchorsAttach = false }; this.AddChild(this.ScrollBar); @@ -53,19 +55,17 @@ namespace MLEM.Ui.Elements { if (child is Panel panel && panel.scrollOverflow) throw new NotSupportedException($"A panel that scrolls overflow cannot contain another panel that scrolls overflow ({child})"); } - - // move the scrollbar to the front so it isn't used for auto-aligning - this.ScrollBar.MoveToFront(); } base.ForceUpdateArea(); if (this.scrollOverflow) { - var firstChild = this.Children[0]; - // if the first child is the scrollbar, then we know there's no other children - if (firstChild == this.ScrollBar) + // if there is only one child, then we have just the scroll bar + if (this.Children.Count == 1) return; - var lastChild = this.Children[this.Children.Count - 2]; + // the "real" first child is the scroll bar, which we want to ignore + var firstChild = this.Children[1]; + var lastChild = this.Children[this.Children.Count - 1]; // the max value of the scrollbar is the amount of non-scaled pixels taken up by overflowing components var childrenHeight = lastChild.Area.Bottom - firstChild.Area.Top; this.ScrollBar.MaxValue = (childrenHeight - this.Area.Height) / this.Scale + this.ChildPadding.Y * 2; @@ -85,14 +85,14 @@ namespace MLEM.Ui.Elements { // if we handle overflow, draw using the render target in DrawUnbound if (!this.scrollOverflow) { base.Draw(time, batch, alpha, offset); - } else { + } else if (this.renderTarget != null) { // draw the actual render target (don't apply the alpha here because it's already drawn onto with alpha) batch.Draw(this.renderTarget, this.GetRenderTargetArea().OffsetCopy(offset), Color.White); } } public override void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState = null, SamplerState samplerState = null) { - if (this.scrollOverflow) { + if (this.scrollOverflow && this.renderTarget != null) { // draw children onto the render target batch.GraphicsDevice.SetRenderTarget(this.renderTarget); batch.GraphicsDevice.Clear(Color.Transparent); diff --git a/MLEM.Ui/UiSystem.cs b/MLEM.Ui/UiSystem.cs index 998e971..7b68e67 100644 --- a/MLEM.Ui/UiSystem.cs +++ b/MLEM.Ui/UiSystem.cs @@ -118,22 +118,29 @@ namespace MLEM.Ui { } } - public RootElement Add(string name, Element root) { - if (this.IndexOf(name) >= 0) - throw new ArgumentException($"There is already a root element with name {name}"); + public RootElement Add(string name, Element element) { + var root = new RootElement(name, element, this); + this.Add(root); + return root; + } - var rootInst = new RootElement(name, root, this); - this.rootElements.Add(rootInst); - root.PropagateRoot(rootInst); - root.PropagateUiSystem(this); - return rootInst; + internal void Add(RootElement root, int index = -1) { + if (this.IndexOf(root.Name) >= 0) + throw new ArgumentException($"There is already a root element with name {root.Name}"); + if (index < 0 || index > this.rootElements.Count) + index = this.rootElements.Count; + this.rootElements.Insert(index, root); + root.Element.PropagateRoot(root); + root.Element.PropagateUiSystem(this); } public void Remove(string name) { - var index = this.IndexOf(name); - if (index < 0) + var root = this.Get(name); + if (root == null) return; - this.rootElements.RemoveAt(index); + this.rootElements.Remove(root); + root.Element.PropagateRoot(null); + root.Element.PropagateUiSystem(null); } public RootElement Get(string name) { @@ -179,5 +186,15 @@ namespace MLEM.Ui { this.System = system; } + public void MoveToFront() { + this.System.Remove(this.Name); + this.System.Add(this); + } + + public void MoveToBack() { + this.System.Remove(this.Name); + this.System.Add(this, 0); + } + } } \ No newline at end of file