using System.Linq; using Microsoft.Xna.Framework; using MLEM.Misc; namespace MLEM.Ui.Elements { /// /// A dropdown component to use inside of a . /// A dropdown is a component that contains a hidden panel which is displayed upon pressing the dropdown button. /// public class Dropdown : Button { /// /// The panel that this dropdown contains. It will be displayed upon pressing the dropdown button. /// public readonly Panel Panel; /// /// This property stores whether the dropdown is currently opened or not /// public bool IsOpen { get => !this.Panel.IsHidden; set { this.Panel.IsHidden = !value; this.OnOpenedOrClosed?.Invoke(this); } } /// /// An event that is invoked when changes /// public GenericCallback OnOpenedOrClosed; /// /// Creates a new dropdown with the given settings /// /// The dropdown's anchor /// The dropdown button's size /// The text displayed on the dropdown button /// The text displayed as a tooltip when hovering over the dropdown button public Dropdown(Anchor anchor, Vector2 size, string text = null, string tooltipText = null) : base(anchor, size, text, tooltipText) { 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.OnOpenedOrClosed += e => this.Priority = this.IsOpen ? 10000 : 0; this.OnPressed += e => this.IsOpen = !this.IsOpen; this.GetGamepadNextElement = (dir, usualNext) => { // Force navigate down to our first child if we're open if (this.IsOpen && dir == Direction2.Down) return this.Panel.GetChildren().FirstOrDefault(c => c.CanBeSelected) ?? usualNext; return usualNext; }; } /// /// Adds an element to this dropdown's /// /// The element to add /// The index to add the child at, or -1 to add it to the end of the list public void AddElement(Element element, int index = -1) { this.Panel.AddChild(element, index); // Since the dropdown causes elements to be over each other, // usual gamepad code doesn't apply element.GetGamepadNextElement = (dir, usualNext) => { if (dir == Direction2.Left || dir == Direction2.Right) return null; if (dir == Direction2.Up) { var prev = element.GetOlderSibling(e => e.CanBeSelected); return prev ?? this; } else if (dir == Direction2.Down) { return element.GetSiblings(e => e.CanBeSelected && e.GetOlderSibling(s => s.CanBeSelected) == element).FirstOrDefault(); } return usualNext; }; } /// /// Adds a pressable element to this dropdown's /// /// The text to display /// The resulting paragraph's event /// The index to add the child at, or -1 to add it to the end of the list public Element AddElement(string text, GenericCallback pressed = null, int index = -1) { return this.AddElement(p => text, pressed, index); } /// /// Adds a pressable element to this dropdown's . /// By default, the paragraph's text color will change from to when hovering over it. /// /// The text to display /// The resulting paragraph's event /// The index to add the child at, or -1 to add it to the end of the list public Element AddElement(Paragraph.TextCallback text, GenericCallback pressed = null, int index = -1) { 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, index); return paragraph; } } }