1
0
Fork 0
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:
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)}); 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);

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) { 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;
} }
} }

View file

@ -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();

View file

@ -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;
} }

View file

@ -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 {