using System;
using Microsoft.Xna.Framework;
using MLEM.Extensions;
using MLEM.Misc;
namespace MLEM.Ui.Elements {
///
/// A squishing group is a whose automatically get resized so that they do not overlap each other.
/// The order in which elements are squished depends on their , where elements with a lower priority will move out of the way of elements with a higher priority.
/// If all elements have the same priority, their addition order (their order in ) determines squish order.
///
public class SquishingGroup : Group {
///
/// Creates a new squishing group with the given settings.
///
/// The group's anchor.
/// The group's size.
public SquishingGroup(Anchor anchor, Vector2 size) : base(anchor, size, false) {}
///
public override void SetAreaAndUpdateChildren(RectangleF area) {
base.SetAreaAndUpdateChildren(area);
// we squish children in order of priority, since auto-anchoring is based on addition order
for (var i = 0; i < this.SortedChildren.Count; i++) {
var child = this.SortedChildren[i];
if (SquishingGroup.SquishChild(child, out var squished))
child.SetAreaAndUpdateChildren(squished);
}
}
///
protected override void OnChildAreaDirty(Element child, bool grandchild) {
base.OnChildAreaDirty(child, grandchild);
if (!grandchild)
this.SetAreaDirty();
}
private static bool SquishChild(Element element, out RectangleF squishedArea) {
squishedArea = default;
if (element.IsHidden)
return false;
var pos = element.Area.Location;
var size = element.Area.Size;
foreach (var sibling in element.GetSiblings(e => !e.IsHidden)) {
var siblingArea = sibling.Area;
var leftIntersect = siblingArea.Right - pos.X;
var rightIntersect = pos.X + size.X - siblingArea.Left;
var bottomIntersect = siblingArea.Bottom - pos.Y;
var topIntersect = pos.Y + size.Y - siblingArea.Top;
if (leftIntersect > 0 && rightIntersect > 0 && bottomIntersect > 0 && topIntersect > 0) {
if (rightIntersect + leftIntersect < topIntersect + bottomIntersect) {
if (rightIntersect > leftIntersect) {
size.X -= siblingArea.Right - pos.X;
pos.X = Math.Max(pos.X, siblingArea.Right);
} else {
size.X = Math.Min(pos.X + size.X, siblingArea.Left) - pos.X;
}
} else {
if (topIntersect > bottomIntersect) {
size.Y -= siblingArea.Bottom - pos.Y;
pos.Y = Math.Max(pos.Y, siblingArea.Bottom);
} else {
size.Y = Math.Min(pos.Y + size.Y, siblingArea.Top) - pos.Y;
}
}
}
}
if (!pos.Equals(element.Area.Location, Element.Epsilon) || !size.Equals(element.Area.Size, Element.Epsilon)) {
squishedArea = new RectangleF(pos, size);
return true;
}
return false;
}
}
}