mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-12-24 01:09:23 +01:00
clean up navigation a lot
This commit is contained in:
parent
c52c9825f0
commit
672e5eb548
7 changed files with 114 additions and 56 deletions
|
@ -150,7 +150,9 @@ namespace Demos {
|
|||
OnPressed = element => tooltip.IsHidden = !tooltip.IsHidden
|
||||
});
|
||||
|
||||
var slider = new Slider(Anchor.AutoLeft, new Vector2(1, 10), 5, 1);
|
||||
var slider = new Slider(Anchor.AutoLeft, new Vector2(1, 10), 5, 1) {
|
||||
StepPerScroll = 0.01F
|
||||
};
|
||||
root.AddChild(new Paragraph(Anchor.AutoLeft, 1, paragraph => "Slider is at " + (slider.CurrentValue * 100).Floor() + "%") {PositionOffset = new Vector2(0, 1)});
|
||||
root.AddChild(slider);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ using Microsoft.Xna.Framework.Graphics;
|
|||
using Microsoft.Xna.Framework.Input;
|
||||
using MLEM.Extensions;
|
||||
using MLEM.Input;
|
||||
using MLEM.Misc;
|
||||
using MLEM.Textures;
|
||||
using MLEM.Ui.Style;
|
||||
|
||||
|
@ -75,7 +76,7 @@ namespace MLEM.Ui.Elements {
|
|||
}
|
||||
}
|
||||
public Point ScaledChildPadding => this.childPadding.Multiply(this.Scale);
|
||||
|
||||
|
||||
public GenericCallback OnPressed;
|
||||
public GenericCallback OnSecondaryPressed;
|
||||
public GenericCallback OnSelected;
|
||||
|
@ -301,7 +302,7 @@ namespace MLEM.Ui.Elements {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.area = new Rectangle(pos, actualSize);
|
||||
this.OnAreaUpdated?.Invoke(this);
|
||||
|
||||
|
@ -449,6 +450,14 @@ namespace MLEM.Ui.Elements {
|
|||
return this.CanBeMoused && this.Area.Contains(position) ? this : null;
|
||||
}
|
||||
|
||||
public virtual Element GetTabNextElement(bool backward, Element usualNext) {
|
||||
return usualNext;
|
||||
}
|
||||
|
||||
public virtual Element GetGamepadNextElement(Direction2 dir, Element usualNext) {
|
||||
return usualNext;
|
||||
}
|
||||
|
||||
public void AndChildren(Action<Element> action) {
|
||||
action(this);
|
||||
foreach (var child in this.Children)
|
||||
|
|
|
@ -16,11 +16,12 @@ namespace MLEM.Ui.Elements {
|
|||
public static Panel ShowInfoBox(UiSystem system, Anchor anchor, float width, string text, float buttonHeight = 10, string okText = "Okay") {
|
||||
var box = new Panel(anchor, new Vector2(width, 1), Vector2.Zero, true);
|
||||
box.AddChild(new Paragraph(Anchor.AutoLeft, 1, text));
|
||||
box.AddChild(new Button(Anchor.AutoCenter, new Vector2(0.5F, buttonHeight), okText) {
|
||||
var button = box.AddChild(new Button(Anchor.AutoCenter, new Vector2(0.5F, buttonHeight), okText) {
|
||||
OnPressed = element => system.Remove("InfoBox"),
|
||||
PositionOffset = new Vector2(0, 1)
|
||||
});
|
||||
system.Add("InfoBox", box);
|
||||
var root = system.Add("InfoBox", box);
|
||||
root.SelectElement(button);
|
||||
return box;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace MLEM.Ui.Elements {
|
|||
|
||||
// handle automatic element selection, the scroller needs to scroll to the right location
|
||||
this.OnSelectedElementChanged += (element, otherElement) => {
|
||||
if (this.Controls.SelectedLastElementWithMouse)
|
||||
if (!this.Controls.IsAutoNavMode)
|
||||
return;
|
||||
if (otherElement == null || !otherElement.GetParentTree().Contains(this))
|
||||
return;
|
||||
|
|
|
@ -1,10 +1,31 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using MLEM.Misc;
|
||||
|
||||
namespace MLEM.Ui.Elements {
|
||||
public class Slider : ScrollBar {
|
||||
|
||||
public Slider(Anchor anchor, Vector2 size, int scrollerSize, float maxValue) :
|
||||
base(anchor, size, scrollerSize, maxValue, true) {
|
||||
this.CanBeSelected = true;
|
||||
}
|
||||
|
||||
public override void Update(GameTime time) {
|
||||
base.Update(time);
|
||||
|
||||
if (this.IsSelected) {
|
||||
if (this.Input.IsGamepadButtonDown(Buttons.DPadLeft) || this.Input.IsGamepadButtonDown(Buttons.LeftThumbstickLeft)) {
|
||||
this.CurrentValue -= this.StepPerScroll;
|
||||
} else if (this.Input.IsGamepadButtonDown(Buttons.DPadRight) || this.Input.IsGamepadButtonDown(Buttons.LeftThumbstickRight)) {
|
||||
this.CurrentValue += this.StepPerScroll;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Element GetGamepadNextElement(Direction2 dir, Element usualNext) {
|
||||
if (dir == Direction2.Left || dir == Direction2.Right)
|
||||
return null;
|
||||
return base.GetGamepadNextElement(dir, usualNext);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,13 +16,14 @@ namespace MLEM.Ui {
|
|||
private readonly UiSystem system;
|
||||
|
||||
public Element MousedElement { get; private set; }
|
||||
public Element SelectedElement { get; private set; }
|
||||
public bool SelectedLastElementWithMouse { get; private set; }
|
||||
public Element SelectedElement => this.GetActiveRoot()?.SelectedElement;
|
||||
|
||||
public Buttons[] GamepadButtons = {Buttons.A};
|
||||
public Buttons[] SecondaryGamepadButtons = {Buttons.X};
|
||||
public int GamepadIndex = -1;
|
||||
|
||||
public bool IsAutoNavMode { get; private set; }
|
||||
|
||||
public UiControls(UiSystem system, InputHandler inputHandler = null) {
|
||||
this.system = system;
|
||||
this.Input = inputHandler ?? new InputHandler();
|
||||
|
@ -48,17 +49,20 @@ namespace MLEM.Ui {
|
|||
}
|
||||
|
||||
if (this.Input.IsMouseButtonPressed(MouseButton.Left)) {
|
||||
this.IsAutoNavMode = false;
|
||||
var selectedNow = mousedNow != null && mousedNow.CanBeSelected ? mousedNow : null;
|
||||
this.SelectElement(selectedNow, true);
|
||||
this.GetActiveRoot().SelectElement(selectedNow);
|
||||
if (mousedNow != null)
|
||||
mousedNow.OnPressed?.Invoke(mousedNow);
|
||||
} else if (this.Input.IsMouseButtonPressed(MouseButton.Right)) {
|
||||
this.IsAutoNavMode = false;
|
||||
if (mousedNow != null)
|
||||
mousedNow.OnSecondaryPressed?.Invoke(mousedNow);
|
||||
}
|
||||
|
||||
// KEYBOARD INPUT
|
||||
else if (this.Input.IsKeyPressed(Keys.Enter) || this.Input.IsKeyPressed(Keys.Space)) {
|
||||
this.IsAutoNavMode = true;
|
||||
if (this.SelectedElement?.Root != null) {
|
||||
if (this.Input.IsModifierKeyDown(ModifierKey.Shift)) {
|
||||
// secondary action on element using space or enter
|
||||
|
@ -69,76 +73,50 @@ namespace MLEM.Ui {
|
|||
}
|
||||
}
|
||||
} else if (this.Input.IsKeyPressed(Keys.Tab)) {
|
||||
this.IsAutoNavMode = true;
|
||||
// tab or shift-tab to next or previous element
|
||||
this.SelectElement(this.GetTabNextElement(this.Input.IsModifierKeyDown(ModifierKey.Shift)), false);
|
||||
var backward = this.Input.IsModifierKeyDown(ModifierKey.Shift);
|
||||
var next = this.GetTabNextElement(backward);
|
||||
if (this.SelectedElement?.Root != null)
|
||||
next = this.SelectedElement.GetTabNextElement(backward, next);
|
||||
this.GetActiveRoot().SelectElement(next);
|
||||
}
|
||||
|
||||
// TOUCH INPUT
|
||||
else if (this.Input.GetGesture(GestureType.Tap, out var tap)) {
|
||||
this.IsAutoNavMode = false;
|
||||
var tapped = this.GetElementUnderPos(tap.Position.ToPoint());
|
||||
this.SelectElement(tapped, true);
|
||||
this.GetActiveRoot().SelectElement(tapped);
|
||||
if (tapped != null)
|
||||
tapped.OnPressed?.Invoke(tapped);
|
||||
} else if (this.Input.GetGesture(GestureType.Hold, out var hold)) {
|
||||
this.IsAutoNavMode = false;
|
||||
var held = this.GetElementUnderPos(hold.Position.ToPoint());
|
||||
this.SelectElement(held, true);
|
||||
this.GetActiveRoot().SelectElement(held);
|
||||
if (held != null)
|
||||
held.OnSecondaryPressed?.Invoke(held);
|
||||
}
|
||||
|
||||
// GAMEPAD INPUT
|
||||
else if (this.GamepadButtons.Any(b => this.Input.IsGamepadButtonPressed(b, this.GamepadIndex))) {
|
||||
this.IsAutoNavMode = true;
|
||||
if (this.SelectedElement?.Root != null)
|
||||
this.SelectedElement.OnPressed?.Invoke(this.SelectedElement);
|
||||
} else if (this.SecondaryGamepadButtons.Any(b => this.Input.IsGamepadButtonPressed(b, this.GamepadIndex))) {
|
||||
this.IsAutoNavMode = true;
|
||||
if (this.SelectedElement?.Root != null)
|
||||
this.SelectedElement.OnSecondaryPressed?.Invoke(this.SelectedElement);
|
||||
} else if (this.Input.IsGamepadButtonPressed(Buttons.DPadDown) || this.Input.IsGamepadButtonPressed(Buttons.LeftThumbstickDown)) {
|
||||
var next = this.GetGamepadNextElement(searchArea => {
|
||||
searchArea.Height += this.system.Viewport.Height;
|
||||
return searchArea;
|
||||
});
|
||||
if (next != null)
|
||||
this.SelectElement(next, false);
|
||||
this.HandleGamepadNextElement(Direction2.Down);
|
||||
} else if (this.Input.IsGamepadButtonPressed(Buttons.DPadLeft) || this.Input.IsGamepadButtonPressed(Buttons.LeftThumbstickLeft)) {
|
||||
var next = this.GetGamepadNextElement(searchArea => {
|
||||
searchArea.X -= this.system.Viewport.Width;
|
||||
searchArea.Width += this.system.Viewport.Width;
|
||||
return searchArea;
|
||||
});
|
||||
if (next != null)
|
||||
this.SelectElement(next, false);
|
||||
this.HandleGamepadNextElement(Direction2.Left);
|
||||
} else if (this.Input.IsGamepadButtonPressed(Buttons.DPadRight) || this.Input.IsGamepadButtonPressed(Buttons.LeftThumbstickRight)) {
|
||||
var next = this.GetGamepadNextElement(searchArea => {
|
||||
searchArea.Width += this.system.Viewport.Width;
|
||||
return searchArea;
|
||||
});
|
||||
if (next != null)
|
||||
this.SelectElement(next, false);
|
||||
this.HandleGamepadNextElement(Direction2.Right);
|
||||
} else if (this.Input.IsGamepadButtonPressed(Buttons.DPadUp) || this.Input.IsGamepadButtonPressed(Buttons.LeftThumbstickUp)) {
|
||||
var next = this.GetGamepadNextElement(searchArea => {
|
||||
searchArea.Y -= this.system.Viewport.Height;
|
||||
searchArea.Height += this.system.Viewport.Height;
|
||||
return searchArea;
|
||||
});
|
||||
if (next != null)
|
||||
this.SelectElement(next, false);
|
||||
this.HandleGamepadNextElement(Direction2.Up);
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectElement(Element element, bool mouse) {
|
||||
if (this.SelectedElement == element)
|
||||
return;
|
||||
|
||||
if (this.SelectedElement != null)
|
||||
this.SelectedElement.OnDeselected?.Invoke(this.SelectedElement);
|
||||
if (element != null)
|
||||
element.OnSelected?.Invoke(element);
|
||||
this.SelectedElement = element;
|
||||
this.SelectedLastElementWithMouse = mouse;
|
||||
this.system.ApplyToAll(e => e.OnSelectedElementChanged?.Invoke(e, element));
|
||||
}
|
||||
|
||||
public Element GetElementUnderPos(Point position, bool transform = true) {
|
||||
foreach (var root in this.system.GetRootElements()) {
|
||||
var pos = transform ? position.Transform(root.InvTransform) : position;
|
||||
|
@ -150,7 +128,7 @@ namespace MLEM.Ui {
|
|||
}
|
||||
|
||||
private Element GetTabNextElement(bool backward) {
|
||||
var currRoot = this.system.GetRootElements().FirstOrDefault(root => root.CanSelectContent);
|
||||
var currRoot = this.GetActiveRoot();
|
||||
if (currRoot == null)
|
||||
return null;
|
||||
var children = currRoot.Element.GetChildren(regardChildrensChildren: true).Append(currRoot.Element);
|
||||
|
@ -178,15 +156,44 @@ namespace MLEM.Ui {
|
|||
}
|
||||
}
|
||||
|
||||
private Element GetGamepadNextElement(Func<Rectangle, Rectangle> searchAreaFunc) {
|
||||
var currRoot = this.system.GetRootElements().FirstOrDefault(root => root.CanSelectContent);
|
||||
private void HandleGamepadNextElement(Direction2 dir) {
|
||||
this.IsAutoNavMode = true;
|
||||
Rectangle searchArea = default;
|
||||
if (this.SelectedElement?.Root != null) {
|
||||
searchArea = this.SelectedElement.Area;
|
||||
var (_, _, width, height) = this.system.Viewport;
|
||||
switch (dir) {
|
||||
case Direction2.Down:
|
||||
searchArea.Height += height;
|
||||
break;
|
||||
case Direction2.Left:
|
||||
searchArea.X -= width;
|
||||
searchArea.Width += width;
|
||||
break;
|
||||
case Direction2.Right:
|
||||
searchArea.Width += width;
|
||||
break;
|
||||
case Direction2.Up:
|
||||
searchArea.Y -= height;
|
||||
searchArea.Height += height;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var next = this.GetGamepadNextElement(searchArea);
|
||||
if (this.SelectedElement != null)
|
||||
next = this.SelectedElement.GetGamepadNextElement(dir, next);
|
||||
if (next != null)
|
||||
this.GetActiveRoot().SelectElement(next);
|
||||
}
|
||||
|
||||
private Element GetGamepadNextElement(Rectangle searchArea) {
|
||||
var currRoot = this.GetActiveRoot();
|
||||
if (currRoot == null)
|
||||
return null;
|
||||
var children = currRoot.Element.GetChildren(regardChildrensChildren: true).Append(currRoot.Element);
|
||||
if (this.SelectedElement?.Root != currRoot) {
|
||||
return children.FirstOrDefault(c => c.CanBeSelected);
|
||||
} else {
|
||||
var searchArea = searchAreaFunc(this.SelectedElement.Area);
|
||||
Element closest = null;
|
||||
float closestDist = 0;
|
||||
foreach (var child in children) {
|
||||
|
@ -202,5 +209,9 @@ namespace MLEM.Ui {
|
|||
}
|
||||
}
|
||||
|
||||
public RootElement GetActiveRoot() {
|
||||
return this.system.GetRootElements().FirstOrDefault(root => root.CanSelectContent);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -75,7 +75,7 @@ namespace MLEM.Ui {
|
|||
});
|
||||
|
||||
this.OnSelectedElementDrawn = (element, time, batch, alpha) => {
|
||||
if (!this.Controls.SelectedLastElementWithMouse && element.SelectionIndicator != null) {
|
||||
if (this.Controls.IsAutoNavMode && element.SelectionIndicator != null) {
|
||||
batch.Draw(element.SelectionIndicator, element.DisplayArea, Color.White * alpha, element.Scale / 2);
|
||||
}
|
||||
};
|
||||
|
@ -176,12 +176,26 @@ namespace MLEM.Ui {
|
|||
public Matrix Transform = Matrix.Identity;
|
||||
public Matrix InvTransform => Matrix.Invert(this.Transform);
|
||||
|
||||
public Element SelectedElement { get; private set; }
|
||||
|
||||
public RootElement(string name, Element element, UiSystem system) {
|
||||
this.Name = name;
|
||||
this.Element = element;
|
||||
this.System = system;
|
||||
}
|
||||
|
||||
public void SelectElement(Element element) {
|
||||
if (this.SelectedElement == element)
|
||||
return;
|
||||
|
||||
if (this.SelectedElement != null)
|
||||
this.SelectedElement.OnDeselected?.Invoke(this.SelectedElement);
|
||||
if (element != null)
|
||||
element.OnSelected?.Invoke(element);
|
||||
this.SelectedElement = element;
|
||||
this.System.ApplyToAll(e => e.OnSelectedElementChanged?.Invoke(e, element));
|
||||
}
|
||||
|
||||
public void MoveToFront() {
|
||||
this.System.Remove(this.Name);
|
||||
this.System.Add(this);
|
||||
|
|
Loading…
Reference in a new issue