1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-12-24 01:09:23 +01:00

added a dropdown menu and also fixed some issues

This commit is contained in:
Ellpeck 2019-09-12 12:39:18 +02:00
parent 0ad17fc40c
commit 8afe9962fb
6 changed files with 80 additions and 29 deletions

View file

@ -185,6 +185,13 @@ namespace Demos {
var bar4 = root.AddChild(new ProgressBar(Anchor.AutoInline, new Vector2(8, 30), Direction2.Up, 10) {PositionOffset = new Vector2(1, 1)});
CoroutineHandler.Start(this.WobbleProgressBar(bar4));
root.AddChild(new VerticalSpace(3));
var dropdown = root.AddChild(new Dropdown(Anchor.AutoLeft, new Vector2(1, 10), "Dropdown Menu"));
dropdown.AddElement("First Option");
dropdown.AddElement("Second Option");
dropdown.AddElement("Third Option");
dropdown.AddElement(new Button(Anchor.AutoLeft, new Vector2(1, 10), "Button Option"));
root.AddChild(new VerticalSpace(3));
root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "There are also some additional \"components\" which are created as combinations of other components. You can find all of them in the ElementHelper class. Here are some examples:"));
root.AddChild(ElementHelper.NumberField(Anchor.AutoLeft, new Vector2(1, 10))).PositionOffset = new Vector2(0, 1);
@ -205,14 +212,14 @@ namespace Demos {
// Below are some querying examples that help you find certain elements easily
var children = root.GetChildren();
var totalChildren = root.GetChildren(regardChildrensChildren: true);
var totalChildren = root.GetChildren(regardGrandchildren: true);
Console.WriteLine($"The root has {children.Count()} children, but there are {totalChildren.Count()} when regarding children's children");
var textFields = root.GetChildren<TextField>();
Console.WriteLine($"The root has {textFields.Count()} text fields");
var paragraphs = root.GetChildren<Paragraph>();
var totalParagraphs = root.GetChildren<Paragraph>(regardChildrensChildren: true);
var totalParagraphs = root.GetChildren<Paragraph>(regardGrandchildren: true);
Console.WriteLine($"The root has {paragraphs.Count()} paragraphs, but there are {totalParagraphs.Count()} when regarding children's children");
var autoWidthChildren = root.GetChildren(e => e.Size.X == 1);

View file

@ -0,0 +1,43 @@
using Microsoft.Xna.Framework;
namespace MLEM.Ui.Elements {
public class Dropdown : Button {
public readonly Panel Panel;
public bool IsOpen {
get => !this.Panel.IsHidden;
set => this.Panel.IsHidden = !value;
}
public Dropdown(Anchor anchor, Vector2 size, string text = null, string tooltipText = null, float tooltipWidth = 50) : base(anchor, size, text, tooltipText, tooltipWidth) {
this.Panel = this.AddChild(new Panel(Anchor.TopCenter, size, Vector2.Zero, true) {
IsHidden = true
});
this.OnAreaUpdated += e => this.Panel.PositionOffset = new Vector2(0, e.Area.Height / this.Scale);
this.Priority = 10000;
this.OnPressed += e => this.IsOpen = !this.IsOpen;
}
public void AddElement(Element element) {
this.Panel.AddChild(element);
}
public void AddElement(string text, GenericCallback pressed = null) {
this.AddElement(p => text, pressed);
}
public void AddElement(Paragraph.TextCallback text, GenericCallback pressed = null) {
var paragraph = new Paragraph(Anchor.AutoLeft, 1, text) {
CanBeMoused = true,
CanBeSelected = true,
PositionOffset = new Vector2(0, 1)
};
if (pressed != null)
paragraph.OnPressed += pressed;
paragraph.OnMouseEnter += e => paragraph.TextColor = Color.LightGray;
paragraph.OnMouseExit += e => paragraph.TextColor = Color.White;
this.AddElement(paragraph);
}
}
}

View file

@ -268,9 +268,9 @@ namespace MLEM.Ui.Elements {
if (this.Anchor >= Anchor.AutoLeft) {
Element previousChild;
if (this.Anchor == Anchor.AutoInline || this.Anchor == Anchor.AutoInlineIgnoreOverflow) {
previousChild = this.GetOlderSibling(false, false);
previousChild = this.GetOlderSibling(e => !e.IsHidden && e.CanAutoAnchorsAttach);
} else {
previousChild = this.GetLowestOlderSibling(false, false);
previousChild = this.GetLowestOlderSibling(e => !e.IsHidden && e.CanAutoAnchorsAttach);
}
if (previousChild != null) {
var prevArea = previousChild.GetAreaForAutoAnchors();
@ -304,12 +304,11 @@ namespace MLEM.Ui.Elements {
child.ForceUpdateArea();
if (this.SetHeightBasedOnChildren && this.Children.Count > 0) {
var lowest = this.GetLowestChild(false, true);
var lowest = this.GetLowestChild(e => !e.IsHidden);
var newHeight = (lowest.UnscrolledArea.Bottom - pos.Y + this.ScaledChildPadding.Y) / this.Scale;
if (newHeight != this.size.Y) {
this.size.Y = newHeight;
if (this.Anchor > Anchor.TopRight)
this.ForceUpdateArea();
this.ForceUpdateArea();
}
}
}
@ -324,12 +323,12 @@ namespace MLEM.Ui.Elements {
return this.UnscrolledArea;
}
public Element GetLowestChild(bool hiddenAlso, bool unattachableAlso) {
public Element GetLowestChild(Func<Element, bool> condition = null) {
Element lowest = null;
// the lowest child is expected to be towards the back, so search is usually faster if done backwards
for (var i = this.Children.Count - 1; i >= 0; i--) {
var child = this.Children[i];
if (!hiddenAlso && child.IsHidden || !unattachableAlso && !child.CanAutoAnchorsAttach)
if (condition != null && !condition(child))
continue;
if (child.Anchor > Anchor.TopRight && child.Anchor < Anchor.AutoLeft)
continue;
@ -339,14 +338,14 @@ namespace MLEM.Ui.Elements {
return lowest;
}
public Element GetLowestOlderSibling(bool hiddenAlso, bool unattachableAlso) {
public Element GetLowestOlderSibling(Func<Element, bool> condition = null) {
if (this.Parent == null)
return null;
Element lowest = null;
foreach (var child in this.Parent.Children) {
if (child == this)
break;
if (!hiddenAlso && child.IsHidden || !unattachableAlso && !child.CanAutoAnchorsAttach)
if (condition != null && !condition(child))
continue;
if (lowest == null || child.UnscrolledArea.Bottom >= lowest.UnscrolledArea.Bottom)
lowest = child;
@ -354,50 +353,52 @@ namespace MLEM.Ui.Elements {
return lowest;
}
public Element GetOlderSibling(bool hiddenAlso, bool unattachableAlso) {
public Element GetOlderSibling(Func<Element, bool> condition = null) {
if (this.Parent == null)
return null;
Element older = null;
foreach (var child in this.Parent.Children) {
if (child == this)
break;
if (!hiddenAlso && child.IsHidden || !unattachableAlso && !child.CanAutoAnchorsAttach)
if (condition != null && !condition(child))
continue;
older = child;
}
return older;
}
public IEnumerable<Element> GetSiblings(bool hiddenAlso) {
public IEnumerable<Element> GetSiblings(Func<Element, bool> condition = null) {
if (this.Parent == null)
yield break;
foreach (var child in this.Parent.Children) {
if (!hiddenAlso && child.IsHidden)
if (condition != null && !condition(child))
continue;
if (child != this)
yield return child;
}
}
public IEnumerable<Element> GetChildren(Func<Element, bool> condition = null, bool regardChildrensChildren = false) {
public IEnumerable<Element> GetChildren(Func<Element, bool> condition = null, bool regardGrandchildren = false, bool ignoreFalseGrandchildren = false) {
foreach (var child in this.Children) {
if (regardChildrensChildren) {
foreach (var cc in child.GetChildren(condition, true))
var applies = condition == null || condition(child);
if (applies)
yield return child;
if (regardGrandchildren && (!ignoreFalseGrandchildren || applies)) {
foreach (var cc in child.GetChildren(condition, true, ignoreFalseGrandchildren))
yield return cc;
}
if (condition == null || condition(child))
yield return child;
}
}
public IEnumerable<T> GetChildren<T>(Func<T, bool> condition = null, bool regardChildrensChildren = false) where T : Element {
public IEnumerable<T> GetChildren<T>(Func<T, bool> condition = null, bool regardGrandchildren = false, bool ignoreFalseGrandchildren = false) where T : Element {
foreach (var child in this.Children) {
if (regardChildrensChildren) {
foreach (var cc in child.GetChildren(condition, true))
var applies = child is T t && (condition == null || condition(t));
if (applies)
yield return (T) child;
if (regardGrandchildren && (!ignoreFalseGrandchildren || applies)) {
foreach (var cc in child.GetChildren(condition, true, ignoreFalseGrandchildren))
yield return cc;
}
if (child is T t && (condition == null || condition(t)))
yield return t;
}
}

View file

@ -69,7 +69,7 @@ namespace MLEM.Ui.Elements {
return;
// the "real" first child is the scroll bar, which we want to ignore
var firstChild = this.Children[1];
var lowestChild = this.GetLowestChild(false, true);
var lowestChild = this.GetLowestChild(e => !e.IsHidden);
// the max value of the scrollbar is the amount of non-scaled pixels taken up by overflowing components
var childrenHeight = lowestChild.Area.Bottom - firstChild.Area.Top;
this.ScrollBar.MaxValue = ((childrenHeight - this.Area.Height) / this.Scale + this.ChildPadding.Y * 2).Ceil();

View file

@ -14,7 +14,7 @@ namespace MLEM.Ui.Elements {
// don't += because we want to override the checking + unchecking behavior of Checkbox
this.OnPressed = element => {
this.Checked = true;
foreach (var sib in this.GetSiblings(true)) {
foreach (var sib in this.GetSiblings()) {
if (sib is RadioButton radio && radio.Group == this.Group)
radio.Checked = false;
}

View file

@ -137,7 +137,7 @@ namespace MLEM.Ui {
protected virtual Element GetTabNextElement(bool backward) {
if (this.ActiveRoot == null)
return null;
var children = this.ActiveRoot.Element.GetChildren(regardChildrensChildren: true).Append(this.ActiveRoot.Element);
var children = this.ActiveRoot.Element.GetChildren(c => !c.IsHidden, true, true).Append(this.ActiveRoot.Element);
if (this.SelectedElement?.Root != this.ActiveRoot) {
return backward ? children.LastOrDefault(c => c.CanBeSelected) : children.FirstOrDefault(c => c.CanBeSelected);
} else {
@ -165,7 +165,7 @@ namespace MLEM.Ui {
protected virtual Element GetGamepadNextElement(Rectangle searchArea) {
if (this.ActiveRoot == null)
return null;
var children = this.ActiveRoot.Element.GetChildren(regardChildrensChildren: true).Append(this.ActiveRoot.Element);
var children = this.ActiveRoot.Element.GetChildren(c => !c.IsHidden, true, true).Append(this.ActiveRoot.Element);
if (this.SelectedElement?.Root != this.ActiveRoot) {
return children.FirstOrDefault(c => c.CanBeSelected);
} else {