diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5679acc..22bdf78 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,6 +37,7 @@ Additions
- Allow specifying a maximum amount of characters for a TextField
- Added a multiline editing mode to TextField
- Added a formatting code to allow for inline font changes
+- Added PreventSiblingSpill to Element
Improvements
- **Made Image ScaleToImage take ui scale into account**
diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs
index 1398e05..7bcb555 100644
--- a/MLEM.Ui/Elements/Element.cs
+++ b/MLEM.Ui/Elements/Element.cs
@@ -241,9 +241,16 @@ namespace MLEM.Ui.Elements {
/// Set this field to true to cause this element's final display area to never exceed that of its .
/// If the resulting area is too large, the size of this element is shrunk to fit the target area.
/// This can be useful if an element should fill the remaining area of a parent exactly.
+ /// When setting this value after this element has already been added to a ui, should be called.
///
public bool PreventParentSpill;
///
+ /// Set this field to true to cause this element's final display ever to never overlap with any of its siblings ().
+ /// If the resulting area is too large, the size of this element is shrunk to best accomodate for the areas of its siblings.
+ /// When setting this value after this element has already been added to a ui, should be called.
+ ///
+ public bool PreventSiblingSpill;
+ ///
/// The transparency (alpha value) that this element is rendered with.
/// Note that, when is called, this alpha value is multiplied with the 's alpha value and passed down to this element's .
///
@@ -333,6 +340,10 @@ namespace MLEM.Ui.Elements {
///
public GenericCallback OnAreaUpdated;
///
+ /// Event that is called when this element's area is marked as dirty using .
+ ///
+ public GenericCallback OnAreaDirty;
+ ///
/// Event that is called when the element that is currently being moused changes within the ui system.
/// Note that the event fired doesn't necessarily correlate to this specific element.
///
@@ -516,8 +527,17 @@ namespace MLEM.Ui.Elements {
///
public void SetAreaDirty() {
this.areaDirty = true;
- if (this.Parent != null && (this.Anchor >= Anchor.AutoLeft || this.Parent.SetWidthBasedOnChildren || this.Parent.SetHeightBasedOnChildren))
- this.Parent.SetAreaDirty();
+ if (this.Parent != null) {
+ // set parent dirty if the parent's layout depends on our area
+ if (this.Anchor >= Anchor.AutoLeft || this.Parent.SetWidthBasedOnChildren || this.Parent.SetHeightBasedOnChildren)
+ this.Parent.SetAreaDirty();
+ // set siblings dirty that depend on our area
+ foreach (var sibling in this.GetSiblings()) {
+ if (sibling.PreventSiblingSpill)
+ sibling.SetAreaDirty();
+ }
+ }
+ this.System?.InvokeOnElementAreaDirty(this);
}
///
@@ -644,6 +664,30 @@ namespace MLEM.Ui.Elements {
newSize.Y = parentArea.Bottom - pos.Y;
}
+ if (this.PreventSiblingSpill) {
+ foreach (var sibling in this.GetSiblings(e => !e.IsHidden)) {
+ var leftIntersect = sibling.Area.Right - pos.X;
+ var rightIntersect = pos.X + newSize.X - sibling.Area.Left;
+ var bottomIntersect = sibling.Area.Bottom - pos.Y;
+ var topIntersect = pos.Y + newSize.Y - sibling.Area.Top;
+ if (leftIntersect > 0 && rightIntersect > 0 && bottomIntersect > 0 && topIntersect > 0) {
+ if (rightIntersect + leftIntersect < topIntersect + bottomIntersect) {
+ if (rightIntersect > leftIntersect) {
+ pos.X = Math.Max(pos.X, sibling.Area.Right);
+ } else {
+ newSize.X = Math.Min(pos.X + newSize.X, sibling.Area.Left) - pos.X;
+ }
+ } else {
+ if (topIntersect > bottomIntersect) {
+ pos.Y = Math.Max(pos.Y, sibling.Area.Bottom);
+ } else {
+ newSize.Y = Math.Min(pos.Y + newSize.Y, sibling.Area.Top) - pos.Y;
+ }
+ }
+ }
+ }
+ }
+
this.area = new RectangleF(pos, newSize);
this.System.InvokeOnElementAreaUpdated(this);
diff --git a/MLEM.Ui/UiSystem.cs b/MLEM.Ui/UiSystem.cs
index 77e56c0..36fbec4 100644
--- a/MLEM.Ui/UiSystem.cs
+++ b/MLEM.Ui/UiSystem.cs
@@ -152,6 +152,10 @@ namespace MLEM.Ui {
///
public event Element.GenericCallback OnElementAreaUpdated;
///
+ /// Event that is invoked when an element's area is marked as dirty using .
+ ///
+ public event Element.GenericCallback OnElementAreaDirty;
+ ///
/// Event that is invoked when the that the mouse is currently over changes
///
public event Element.GenericCallback OnMousedElementChanged;
@@ -193,6 +197,7 @@ namespace MLEM.Ui {
this.OnElementTouchEnter += e => e.OnTouchEnter?.Invoke(e);
this.OnElementTouchExit += e => e.OnTouchExit?.Invoke(e);
this.OnElementAreaUpdated += e => e.OnAreaUpdated?.Invoke(e);
+ this.OnElementAreaDirty += e => e.OnAreaDirty?.Invoke(e);
this.OnMousedElementChanged += e => this.ApplyToAll(t => t.OnMousedElementChanged?.Invoke(t, e));
this.OnTouchedElementChanged += e => this.ApplyToAll(t => t.OnTouchedElementChanged?.Invoke(t, e));
this.OnSelectedElementChanged += e => this.ApplyToAll(t => t.OnSelectedElementChanged?.Invoke(t, e));
@@ -357,6 +362,7 @@ namespace MLEM.Ui {
internal void InvokeOnSelectedElementDrawn(Element element, GameTime time, SpriteBatch batch, float alpha) => this.OnSelectedElementDrawn?.Invoke(element, time, batch, alpha);
internal void InvokeOnElementUpdated(Element element, GameTime time) => this.OnElementUpdated?.Invoke(element, time);
internal void InvokeOnElementAreaUpdated(Element element) => this.OnElementAreaUpdated?.Invoke(element);
+ internal void InvokeOnElementAreaDirty(Element element) => this.OnElementAreaDirty?.Invoke(element);
internal void InvokeOnElementPressed(Element element) => this.OnElementPressed?.Invoke(element);
internal void InvokeOnElementSecondaryPressed(Element element) => this.OnElementSecondaryPressed?.Invoke(element);
internal void InvokeOnElementSelected(Element element) => this.OnElementSelected?.Invoke(element);
diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs
index 70e4f18..759a2f1 100644
--- a/Sandbox/GameImpl.cs
+++ b/Sandbox/GameImpl.cs
@@ -8,7 +8,6 @@ using Microsoft.Xna.Framework.Input;
using MLEM.Cameras;
using MLEM.Data;
using MLEM.Data.Content;
-using MLEM.Extended.Extensions;
using MLEM.Extended.Font;
using MLEM.Extended.Tiled;
using MLEM.Extensions;
@@ -22,9 +21,7 @@ using MLEM.Textures;
using MLEM.Ui;
using MLEM.Ui.Elements;
using MLEM.Ui.Style;
-using MonoGame.Extended;
using MonoGame.Extended.Tiled;
-using Group = MLEM.Ui.Elements.Group;
namespace Sandbox {
public class GameImpl : MlemGame {
@@ -216,7 +213,7 @@ namespace Sandbox {
invalidPanel.AddChild(new VerticalSpace(1));
this.UiSystem.Add("Invalid", invalidPanel);*/
- var loadGroup = new Group(Anchor.TopLeft, Vector2.One, false);
+ /*var loadGroup = new Group(Anchor.TopLeft, Vector2.One, false);
var loadPanel = loadGroup.AddChild(new Panel(Anchor.Center, new Vector2(150, 150), Vector2.Zero, false, true, false) {
ChildPadding = new Padding(5, 10, 5, 5)
});
@@ -240,7 +237,30 @@ namespace Sandbox {
}
};
par.OnDrawn = (e, time, batch, a) => batch.DrawRectangle(e.DisplayArea.ToExtended(), Color.Red);
- this.UiSystem.Add("Load", loadGroup);
+ this.UiSystem.Add("Load", loadGroup);*/
+
+ var spillPanel = new Panel(Anchor.Center, new Vector2(100), Vector2.Zero);
+ spillPanel.AddChild(new Button(Anchor.TopLeft, new Vector2(30), "TL") {
+ OnUpdated = (e, time) => e.IsHidden = Input.IsKeyDown(Keys.D1)
+ });
+ spillPanel.AddChild(new Button(Anchor.TopRight, new Vector2(30), "TR") {
+ OnUpdated = (e, time) => e.IsHidden = Input.IsKeyDown(Keys.D2)
+ });
+ spillPanel.AddChild(new Button(Anchor.BottomLeft, new Vector2(30), "BL") {
+ OnUpdated = (e, time) => e.IsHidden = Input.IsKeyDown(Keys.D3)
+ });
+ spillPanel.AddChild(new Button(Anchor.BottomRight, new Vector2(30), "BR") {
+ OnUpdated = (e, time) => e.IsHidden = Input.IsKeyDown(Keys.D4)
+ });
+ spillPanel.AddChild(new Button(Anchor.Center, Vector2.Zero, "Spill Test") {
+ PositionOffset = new Vector2(-10, -5),
+ Size = new Vector2(60, 55),
+ OnPressed = e => {
+ e.PreventSiblingSpill = !e.PreventSiblingSpill;
+ e.SetAreaDirty();
+ }
+ });
+ this.UiSystem.Add("SpillTest", spillPanel);
}
protected override void DoUpdate(GameTime gameTime) {