mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-26 06:28:35 +01:00
added a dropdown menu and also fixed some issues
This commit is contained in:
parent
0ad17fc40c
commit
8afe9962fb
6 changed files with 80 additions and 29 deletions
|
@ -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)});
|
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));
|
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 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(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);
|
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
|
// Below are some querying examples that help you find certain elements easily
|
||||||
|
|
||||||
var children = root.GetChildren();
|
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");
|
Console.WriteLine($"The root has {children.Count()} children, but there are {totalChildren.Count()} when regarding children's children");
|
||||||
|
|
||||||
var textFields = root.GetChildren<TextField>();
|
var textFields = root.GetChildren<TextField>();
|
||||||
Console.WriteLine($"The root has {textFields.Count()} text fields");
|
Console.WriteLine($"The root has {textFields.Count()} text fields");
|
||||||
|
|
||||||
var paragraphs = root.GetChildren<Paragraph>();
|
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");
|
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);
|
var autoWidthChildren = root.GetChildren(e => e.Size.X == 1);
|
||||||
|
|
43
MLEM.Ui/Elements/Dropdown.cs
Normal file
43
MLEM.Ui/Elements/Dropdown.cs
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -268,9 +268,9 @@ namespace MLEM.Ui.Elements {
|
||||||
if (this.Anchor >= Anchor.AutoLeft) {
|
if (this.Anchor >= Anchor.AutoLeft) {
|
||||||
Element previousChild;
|
Element previousChild;
|
||||||
if (this.Anchor == Anchor.AutoInline || this.Anchor == Anchor.AutoInlineIgnoreOverflow) {
|
if (this.Anchor == Anchor.AutoInline || this.Anchor == Anchor.AutoInlineIgnoreOverflow) {
|
||||||
previousChild = this.GetOlderSibling(false, false);
|
previousChild = this.GetOlderSibling(e => !e.IsHidden && e.CanAutoAnchorsAttach);
|
||||||
} else {
|
} else {
|
||||||
previousChild = this.GetLowestOlderSibling(false, false);
|
previousChild = this.GetLowestOlderSibling(e => !e.IsHidden && e.CanAutoAnchorsAttach);
|
||||||
}
|
}
|
||||||
if (previousChild != null) {
|
if (previousChild != null) {
|
||||||
var prevArea = previousChild.GetAreaForAutoAnchors();
|
var prevArea = previousChild.GetAreaForAutoAnchors();
|
||||||
|
@ -304,12 +304,11 @@ namespace MLEM.Ui.Elements {
|
||||||
child.ForceUpdateArea();
|
child.ForceUpdateArea();
|
||||||
|
|
||||||
if (this.SetHeightBasedOnChildren && this.Children.Count > 0) {
|
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;
|
var newHeight = (lowest.UnscrolledArea.Bottom - pos.Y + this.ScaledChildPadding.Y) / this.Scale;
|
||||||
if (newHeight != this.size.Y) {
|
if (newHeight != this.size.Y) {
|
||||||
this.size.Y = newHeight;
|
this.size.Y = newHeight;
|
||||||
if (this.Anchor > Anchor.TopRight)
|
this.ForceUpdateArea();
|
||||||
this.ForceUpdateArea();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,12 +323,12 @@ namespace MLEM.Ui.Elements {
|
||||||
return this.UnscrolledArea;
|
return this.UnscrolledArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element GetLowestChild(bool hiddenAlso, bool unattachableAlso) {
|
public Element GetLowestChild(Func<Element, bool> condition = null) {
|
||||||
Element lowest = null;
|
Element lowest = null;
|
||||||
// the lowest child is expected to be towards the back, so search is usually faster if done backwards
|
// 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--) {
|
for (var i = this.Children.Count - 1; i >= 0; i--) {
|
||||||
var child = this.Children[i];
|
var child = this.Children[i];
|
||||||
if (!hiddenAlso && child.IsHidden || !unattachableAlso && !child.CanAutoAnchorsAttach)
|
if (condition != null && !condition(child))
|
||||||
continue;
|
continue;
|
||||||
if (child.Anchor > Anchor.TopRight && child.Anchor < Anchor.AutoLeft)
|
if (child.Anchor > Anchor.TopRight && child.Anchor < Anchor.AutoLeft)
|
||||||
continue;
|
continue;
|
||||||
|
@ -339,14 +338,14 @@ namespace MLEM.Ui.Elements {
|
||||||
return lowest;
|
return lowest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element GetLowestOlderSibling(bool hiddenAlso, bool unattachableAlso) {
|
public Element GetLowestOlderSibling(Func<Element, bool> condition = null) {
|
||||||
if (this.Parent == null)
|
if (this.Parent == null)
|
||||||
return null;
|
return null;
|
||||||
Element lowest = null;
|
Element lowest = null;
|
||||||
foreach (var child in this.Parent.Children) {
|
foreach (var child in this.Parent.Children) {
|
||||||
if (child == this)
|
if (child == this)
|
||||||
break;
|
break;
|
||||||
if (!hiddenAlso && child.IsHidden || !unattachableAlso && !child.CanAutoAnchorsAttach)
|
if (condition != null && !condition(child))
|
||||||
continue;
|
continue;
|
||||||
if (lowest == null || child.UnscrolledArea.Bottom >= lowest.UnscrolledArea.Bottom)
|
if (lowest == null || child.UnscrolledArea.Bottom >= lowest.UnscrolledArea.Bottom)
|
||||||
lowest = child;
|
lowest = child;
|
||||||
|
@ -354,50 +353,52 @@ namespace MLEM.Ui.Elements {
|
||||||
return lowest;
|
return lowest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element GetOlderSibling(bool hiddenAlso, bool unattachableAlso) {
|
public Element GetOlderSibling(Func<Element, bool> condition = null) {
|
||||||
if (this.Parent == null)
|
if (this.Parent == null)
|
||||||
return null;
|
return null;
|
||||||
Element older = null;
|
Element older = null;
|
||||||
foreach (var child in this.Parent.Children) {
|
foreach (var child in this.Parent.Children) {
|
||||||
if (child == this)
|
if (child == this)
|
||||||
break;
|
break;
|
||||||
if (!hiddenAlso && child.IsHidden || !unattachableAlso && !child.CanAutoAnchorsAttach)
|
if (condition != null && !condition(child))
|
||||||
continue;
|
continue;
|
||||||
older = child;
|
older = child;
|
||||||
}
|
}
|
||||||
return older;
|
return older;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Element> GetSiblings(bool hiddenAlso) {
|
public IEnumerable<Element> GetSiblings(Func<Element, bool> condition = null) {
|
||||||
if (this.Parent == null)
|
if (this.Parent == null)
|
||||||
yield break;
|
yield break;
|
||||||
foreach (var child in this.Parent.Children) {
|
foreach (var child in this.Parent.Children) {
|
||||||
if (!hiddenAlso && child.IsHidden)
|
if (condition != null && !condition(child))
|
||||||
continue;
|
continue;
|
||||||
if (child != this)
|
if (child != this)
|
||||||
yield return child;
|
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) {
|
foreach (var child in this.Children) {
|
||||||
if (regardChildrensChildren) {
|
var applies = condition == null || condition(child);
|
||||||
foreach (var cc in child.GetChildren(condition, true))
|
if (applies)
|
||||||
|
yield return child;
|
||||||
|
if (regardGrandchildren && (!ignoreFalseGrandchildren || applies)) {
|
||||||
|
foreach (var cc in child.GetChildren(condition, true, ignoreFalseGrandchildren))
|
||||||
yield return cc;
|
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) {
|
foreach (var child in this.Children) {
|
||||||
if (regardChildrensChildren) {
|
var applies = child is T t && (condition == null || condition(t));
|
||||||
foreach (var cc in child.GetChildren(condition, true))
|
if (applies)
|
||||||
|
yield return (T) child;
|
||||||
|
if (regardGrandchildren && (!ignoreFalseGrandchildren || applies)) {
|
||||||
|
foreach (var cc in child.GetChildren(condition, true, ignoreFalseGrandchildren))
|
||||||
yield return cc;
|
yield return cc;
|
||||||
}
|
}
|
||||||
if (child is T t && (condition == null || condition(t)))
|
|
||||||
yield return t;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace MLEM.Ui.Elements {
|
||||||
return;
|
return;
|
||||||
// the "real" first child is the scroll bar, which we want to ignore
|
// the "real" first child is the scroll bar, which we want to ignore
|
||||||
var firstChild = this.Children[1];
|
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
|
// 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;
|
var childrenHeight = lowestChild.Area.Bottom - firstChild.Area.Top;
|
||||||
this.ScrollBar.MaxValue = ((childrenHeight - this.Area.Height) / this.Scale + this.ChildPadding.Y * 2).Ceil();
|
this.ScrollBar.MaxValue = ((childrenHeight - this.Area.Height) / this.Scale + this.ChildPadding.Y * 2).Ceil();
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace MLEM.Ui.Elements {
|
||||||
// don't += because we want to override the checking + unchecking behavior of Checkbox
|
// don't += because we want to override the checking + unchecking behavior of Checkbox
|
||||||
this.OnPressed = element => {
|
this.OnPressed = element => {
|
||||||
this.Checked = true;
|
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)
|
if (sib is RadioButton radio && radio.Group == this.Group)
|
||||||
radio.Checked = false;
|
radio.Checked = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ namespace MLEM.Ui {
|
||||||
protected virtual Element GetTabNextElement(bool backward) {
|
protected virtual Element GetTabNextElement(bool backward) {
|
||||||
if (this.ActiveRoot == null)
|
if (this.ActiveRoot == null)
|
||||||
return 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) {
|
if (this.SelectedElement?.Root != this.ActiveRoot) {
|
||||||
return backward ? children.LastOrDefault(c => c.CanBeSelected) : children.FirstOrDefault(c => c.CanBeSelected);
|
return backward ? children.LastOrDefault(c => c.CanBeSelected) : children.FirstOrDefault(c => c.CanBeSelected);
|
||||||
} else {
|
} else {
|
||||||
|
@ -165,7 +165,7 @@ namespace MLEM.Ui {
|
||||||
protected virtual Element GetGamepadNextElement(Rectangle searchArea) {
|
protected virtual Element GetGamepadNextElement(Rectangle searchArea) {
|
||||||
if (this.ActiveRoot == null)
|
if (this.ActiveRoot == null)
|
||||||
return 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) {
|
if (this.SelectedElement?.Root != this.ActiveRoot) {
|
||||||
return children.FirstOrDefault(c => c.CanBeSelected);
|
return children.FirstOrDefault(c => c.CanBeSelected);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue