diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index fed4503..f3dd110 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -84,16 +84,17 @@ namespace MLEM.Ui.Elements { public GenericCallback OnSecondaryPressed; public GenericCallback OnSelected; public GenericCallback OnDeselected; - public GenericCallback OnMouseEnter; public GenericCallback OnMouseExit; public TextInputCallback OnTextInput; public GenericCallback OnAreaUpdated; + public OtherElementCallback OnMousedElementChanged; + public OtherElementCallback OnSelectedElementChanged; private UiSystem system; public UiSystem System { get => this.system; - private set { + internal set { this.system = value; if (this.system != null && !this.HasCustomStyle) this.InitStyle(this.system.Style); @@ -102,7 +103,7 @@ namespace MLEM.Ui.Elements { protected UiControls Controls => this.System.Controls; protected InputHandler Input => this.Controls.Input; public Point MousePos => this.Input.MousePosition; - public RootElement Root { get; private set; } + public RootElement Root { get; internal set; } public float Scale => this.Root.ActualScale; public Element Parent { get; private set; } public bool IsMouseOver { get; private set; } @@ -174,8 +175,10 @@ namespace MLEM.Ui.Elements { index = this.Children.Count; this.Children.Insert(index, element); element.Parent = this; - element.PropagateRoot(this.Root); - element.PropagateUiSystem(this.System); + element.Propagate(e => { + e.Root = this.Root; + e.System = this.System; + }); this.SetSortedChildrenDirty(); this.SetAreaDirty(); return element; @@ -184,8 +187,10 @@ namespace MLEM.Ui.Elements { public void RemoveChild(Element element) { this.Children.Remove(element); element.Parent = null; - element.PropagateRoot(null); - element.PropagateUiSystem(null); + element.Propagate(e => { + e.Root = null; + e.System = null; + }); this.SetSortedChildrenDirty(); this.SetAreaDirty(); } @@ -426,7 +431,7 @@ namespace MLEM.Ui.Elements { child.Draw(time, batch, alpha * child.DrawAlpha, offset); } - if (this.IsSelected && this.Controls.ShowSelectionIndicator && this.SelectionIndicator != null) { + if (this.IsSelected && !this.Controls.SelectedLastElementWithMouse && this.SelectionIndicator != null) { batch.Draw(this.SelectionIndicator, this.DisplayArea.OffsetCopy(offset), Color.White * alpha); } } @@ -457,22 +462,12 @@ namespace MLEM.Ui.Elements { public delegate void GenericCallback(Element element); - internal void PropagateUiSystem(UiSystem system) { - this.System = system; - foreach (var child in this.Children) - child.PropagateUiSystem(system); - } + public delegate void OtherElementCallback(Element thisElement, Element otherElement); - internal void PropagateRoot(RootElement root) { - this.Root = root; + internal void Propagate(Action action) { + action(this); foreach (var child in this.Children) - child.PropagateRoot(root); - } - - internal void PropagateInput(Keys key, char character) { - this.OnTextInput?.Invoke(this, key, character); - foreach (var child in this.Children) - child.PropagateInput(key, character); + child.Propagate(action); } } diff --git a/MLEM.Ui/Elements/Panel.cs b/MLEM.Ui/Elements/Panel.cs index 0eef8ba..ec38f81 100644 --- a/MLEM.Ui/Elements/Panel.cs +++ b/MLEM.Ui/Elements/Panel.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MLEM.Extensions; @@ -33,6 +34,15 @@ namespace MLEM.Ui.Elements { // modify the padding so that the scroll bar isn't over top of something else this.ScrollBar.PositionOffset -= new Vector2(scrollSize.X + 1, 0); this.ChildPadding += new Point(scrollSize.X, 0); + + // handle automatic element selection, the scroller needs to scroll to the right location + this.OnSelectedElementChanged += (element, otherElement) => { + if (this.Controls.SelectedLastElementWithMouse) + return; + if (otherElement == null || !otherElement.GetParentTree().Contains(this)) + return; + this.ScrollBar.CurrentValue = (otherElement.Area.Bottom - this.Children[1].Area.Top - this.Area.Height / 2) / this.Scale; + }; } } diff --git a/MLEM.Ui/UiControls.cs b/MLEM.Ui/UiControls.cs index 62ed326..dc073a3 100644 --- a/MLEM.Ui/UiControls.cs +++ b/MLEM.Ui/UiControls.cs @@ -14,7 +14,7 @@ namespace MLEM.Ui { public Element MousedElement { get; private set; } public Element SelectedElement { get; private set; } - public bool ShowSelectionIndicator; + public bool SelectedLastElementWithMouse { get; private set; } public UiControls(UiSystem system, InputHandler inputHandler = null) { this.system = system; @@ -34,13 +34,14 @@ namespace MLEM.Ui { if (mousedNow != null) mousedNow.OnMouseEnter?.Invoke(mousedNow); this.MousedElement = mousedNow; + this.system.Propagate(e => e.OnMousedElementChanged?.Invoke(e, mousedNow)); } if (this.Input.IsMouseButtonPressed(MouseButton.Left)) { // select element var selectedNow = mousedNow != null && mousedNow.CanBeSelected ? mousedNow : null; if (this.SelectedElement != selectedNow) - this.SelectElement(selectedNow, false); + this.SelectElement(selectedNow, true); // first action on element if (mousedNow != null) @@ -61,17 +62,18 @@ namespace MLEM.Ui { } } else if (this.Input.IsKeyPressed(Keys.Tab)) { // tab or shift-tab to next or previous element - this.SelectElement(this.GetNextElement(this.Input.IsModifierKeyDown(ModifierKey.Shift)), true); + this.SelectElement(this.GetNextElement(this.Input.IsModifierKeyDown(ModifierKey.Shift)), false); } } - public void SelectElement(Element element, bool show) { + public void SelectElement(Element element, bool mouse) { if (this.SelectedElement != null) this.SelectedElement.OnDeselected?.Invoke(this.SelectedElement); if (element != null) element.OnSelected?.Invoke(element); this.SelectedElement = element; - this.ShowSelectionIndicator = show; + this.SelectedLastElementWithMouse = mouse; + this.system.Propagate(e => e.OnSelectedElementChanged?.Invoke(e, element)); } public Element GetMousedElement() { diff --git a/MLEM.Ui/UiSystem.cs b/MLEM.Ui/UiSystem.cs index e2d1293..637e14c 100644 --- a/MLEM.Ui/UiSystem.cs +++ b/MLEM.Ui/UiSystem.cs @@ -38,7 +38,7 @@ namespace MLEM.Ui { set { this.style = value; foreach (var root in this.rootElements) { - root.Element.PropagateUiSystem(this); + root.Element.Propagate(e => e.System = this); root.Element.SetAreaDirty(); } } @@ -62,7 +62,7 @@ namespace MLEM.Ui { }; window.TextInput += (sender, args) => { foreach (var root in this.rootElements) - root.Element.PropagateInput(args.Key, args.Character); + root.Element.Propagate(e => e.OnTextInput?.Invoke(e, args.Key, args.Character)); }; } @@ -101,8 +101,10 @@ namespace MLEM.Ui { if (index < 0 || index > this.rootElements.Count) index = this.rootElements.Count; this.rootElements.Insert(index, root); - root.Element.PropagateRoot(root); - root.Element.PropagateUiSystem(this); + root.Element.Propagate(e => { + e.Root = root; + e.System = this; + }); return true; } @@ -111,8 +113,10 @@ namespace MLEM.Ui { if (root == null) return; this.rootElements.Remove(root); - root.Element.PropagateRoot(null); - root.Element.PropagateUiSystem(null); + root.Element.Propagate(e => { + e.Root = null; + e.System = null; + }); } public RootElement Get(string name) { @@ -129,6 +133,11 @@ namespace MLEM.Ui { yield return this.rootElements[i]; } + internal void Propagate(Action action) { + foreach (var root in this.rootElements) + root.Element.Propagate(action); + } + } public class RootElement {