mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-22 20:58:34 +01:00
added an element helper method to create a keybind button
This commit is contained in:
parent
a5a73af01c
commit
ce920b5219
5 changed files with 128 additions and 21 deletions
|
@ -1,4 +1,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MLEM.Input;
|
||||
using MLEM.Textures;
|
||||
|
||||
namespace MLEM.Ui.Elements {
|
||||
|
@ -111,6 +114,60 @@ namespace MLEM.Ui.Elements {
|
|||
return group;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="Button"/> that acts as a way to input a custom value for a <see cref="Keybind"/>.
|
||||
/// Note that only the first <see cref="Keybind.Combination"/> of the given keybind is displayed and edited, all others are ignored. The exception is that, if <paramref name="unbindKey"/> is set, unbinding the keybind clears all combinations.
|
||||
/// Inputting custom keybinds using this element supports <see cref="ModifierKey"/>-based modifiers and any <see cref="GenericInput"/>-based keys.
|
||||
/// </summary>
|
||||
/// <param name="anchor">The button's anchor</param>
|
||||
/// <param name="size">The button's size</param>
|
||||
/// <param name="keybind">The keybind that this button should represent</param>
|
||||
/// <param name="inputHandler">The input handler to query inputs with</param>
|
||||
/// <param name="activePlaceholder">A placeholder text that is displayed while the keybind is being edited</param>
|
||||
/// <param name="unbindKey">An optional generic input that allows the keybind value to be unbound, clearing all combinations</param>
|
||||
/// <param name="unboundPlaceholder">A placeholder text that is displayed if the keybind is unbound</param>
|
||||
/// <param name="inputName">An optional function to give each input a display name that is easier to read. If this is null, <see cref="GenericInput.ToString"/> is used.</param>
|
||||
/// <returns>A keybind button with the given settings</returns>
|
||||
public static Button KeybindButton(Anchor anchor, Vector2 size, Keybind keybind, InputHandler inputHandler, string activePlaceholder, GenericInput unbindKey = default, string unboundPlaceholder = "", Func<GenericInput, string> inputName = null) {
|
||||
string GetCurrentName() {
|
||||
var combination = keybind.GetCombinations().FirstOrDefault();
|
||||
if (combination == null)
|
||||
return unboundPlaceholder;
|
||||
return string.Join(" + ", combination.Modifiers
|
||||
.Append(combination.Key)
|
||||
.Select(i => inputName?.Invoke(i) ?? i.ToString()));
|
||||
}
|
||||
|
||||
var button = new Button(anchor, size, GetCurrentName());
|
||||
var active = false;
|
||||
var activeNext = false;
|
||||
button.OnPressed = e => {
|
||||
button.Text.Text = activePlaceholder;
|
||||
activeNext = true;
|
||||
};
|
||||
button.OnUpdated = (e, time) => {
|
||||
if (activeNext) {
|
||||
active = true;
|
||||
activeNext = false;
|
||||
} else if (active) {
|
||||
if (unbindKey != default && inputHandler.IsPressed(unbindKey)) {
|
||||
keybind.Clear();
|
||||
button.Text.Text = unboundPlaceholder;
|
||||
active = false;
|
||||
} else if (inputHandler.InputsPressed.Length > 0) {
|
||||
var key = inputHandler.InputsPressed.FirstOrDefault(i => !i.IsModifier());
|
||||
if (key != default) {
|
||||
var mods = inputHandler.InputsDown.Where(i => i.IsModifier());
|
||||
keybind.Remove((c, i) => i == 0).Add(key, mods.ToArray());
|
||||
button.Text.Text = GetCurrentName();
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return button;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -29,13 +29,13 @@ namespace MLEM.Input {
|
|||
public override string ToString() {
|
||||
switch (this.Type) {
|
||||
case InputType.Mouse:
|
||||
return ((MouseButton) this).ToString();
|
||||
return this.Type.ToString() + (MouseButton) this;
|
||||
case InputType.Keyboard:
|
||||
return ((Keys) this).ToString();
|
||||
return this.Type.ToString() + (Keys) this;
|
||||
case InputType.Gamepad:
|
||||
return ((Buttons) this).ToString();
|
||||
return this.Type.ToString() + (Buttons) this;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(this.Type));
|
||||
return this.Type.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,11 +101,11 @@ namespace MLEM.Input {
|
|||
/// </summary>
|
||||
/// <param name="input">The input to convert</param>
|
||||
/// <returns>The resulting keys</returns>
|
||||
/// <exception cref="ArgumentException">If the given generic input's <see cref="Type"/> is not <see cref="InputType.Keyboard"/></exception>
|
||||
/// <exception cref="ArgumentException">If the given generic input's <see cref="Type"/> is not <see cref="InputType.Keyboard"/> or <see cref="InputType.None"/></exception>
|
||||
public static implicit operator Keys(GenericInput input) {
|
||||
if (input.Type != InputType.Keyboard)
|
||||
throw new ArgumentException();
|
||||
return (Keys) input.value;
|
||||
if (input.Type == InputType.None)
|
||||
return Keys.None;
|
||||
return input.Type == InputType.Keyboard ? (Keys) input.value : throw new ArgumentException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -115,9 +115,7 @@ namespace MLEM.Input {
|
|||
/// <returns>The resulting button</returns>
|
||||
/// <exception cref="ArgumentException">If the given generic input's <see cref="Type"/> is not <see cref="InputType.Mouse"/></exception>
|
||||
public static implicit operator MouseButton(GenericInput input) {
|
||||
if (input.Type != InputType.Mouse)
|
||||
throw new ArgumentException();
|
||||
return (MouseButton) input.value;
|
||||
return input.Type == InputType.Mouse ? (MouseButton) input.value : throw new ArgumentException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -127,9 +125,7 @@ namespace MLEM.Input {
|
|||
/// <returns>The resulting buttons</returns>
|
||||
/// <exception cref="ArgumentException">If the given generic input's <see cref="Type"/> is not <see cref="InputType.Gamepad"/></exception>
|
||||
public static implicit operator Buttons(GenericInput input) {
|
||||
if (input.Type != InputType.Gamepad)
|
||||
throw new ArgumentException();
|
||||
return (Buttons) input.value;
|
||||
return input.Type == InputType.Gamepad ? (Buttons) input.value : throw new ArgumentException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -138,6 +134,11 @@ namespace MLEM.Input {
|
|||
[DataContract]
|
||||
public enum InputType {
|
||||
|
||||
/// <summary>
|
||||
/// A type representing no value
|
||||
/// </summary>
|
||||
[EnumMember]
|
||||
None,
|
||||
/// <summary>
|
||||
/// A type representing <see cref="MouseButton"/>
|
||||
/// </summary>
|
||||
|
|
|
@ -523,7 +523,7 @@ namespace MLEM.Input {
|
|||
case GenericInput.InputType.Mouse:
|
||||
return this.IsMouseButtonDown(control);
|
||||
default:
|
||||
throw new ArgumentException(nameof(control));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -544,7 +544,7 @@ namespace MLEM.Input {
|
|||
case GenericInput.InputType.Mouse:
|
||||
return this.IsMouseButtonUp(control);
|
||||
default:
|
||||
throw new ArgumentException(nameof(control));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -565,7 +565,7 @@ namespace MLEM.Input {
|
|||
case GenericInput.InputType.Mouse:
|
||||
return this.IsMouseButtonPressed(control);
|
||||
default:
|
||||
throw new ArgumentException(nameof(control));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,16 @@ namespace MLEM.Input {
|
|||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all combinations that match the given predicate
|
||||
/// </summary>
|
||||
/// <param name="predicate">The predicate to match against</param>
|
||||
/// <returns>This keybind, for chaining</returns>
|
||||
public Keybind Remove(Func<Combination, int, bool> predicate) {
|
||||
this.combinations = this.combinations.Where((c, i) => !predicate(c, i)).ToArray();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies all of the combinations from the given keybind into this keybind.
|
||||
/// Note that this doesn't <see cref="Clear"/> this keybind, so combinations will be merged rather than replaced.
|
||||
|
@ -93,6 +103,17 @@ namespace MLEM.Input {
|
|||
return this.combinations.Any(c => c.IsPressed(handler, gamepadIndex));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether any of this keybind's modifier keys are currently down.
|
||||
/// See <see cref="InputHandler.IsDown"/> for more information.
|
||||
/// </summary>
|
||||
/// <param name="handler">The input handler to query the keys with</param>
|
||||
/// <param name="gamepadIndex">The index of the gamepad to query, or -1 to query all gamepads</param>
|
||||
/// <returns>Whether any of this keyboard's modifier keys are down</returns>
|
||||
public bool IsModifierDown(InputHandler handler, int gamepadIndex = -1) {
|
||||
return this.combinations.Any(c => c.IsModifierDown(handler, gamepadIndex));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerable of all of the combinations that this keybind currently contains
|
||||
/// </summary>
|
||||
|
@ -133,15 +154,33 @@ namespace MLEM.Input {
|
|||
this.Key = key;
|
||||
}
|
||||
|
||||
internal bool IsDown(InputHandler handler, int gamepadIndex = -1) {
|
||||
/// <summary>
|
||||
/// Returns whether this combination is currently down
|
||||
/// </summary>
|
||||
/// <param name="handler">The input handler to query the keys with</param>
|
||||
/// <param name="gamepadIndex">The index of the gamepad to query, or -1 to query all gamepads</param>
|
||||
/// <returns>Whether this combination is down</returns>
|
||||
public bool IsDown(InputHandler handler, int gamepadIndex = -1) {
|
||||
return this.IsModifierDown(handler, gamepadIndex) && handler.IsDown(this.Key, gamepadIndex);
|
||||
}
|
||||
|
||||
internal bool IsPressed(InputHandler handler, int gamepadIndex = -1) {
|
||||
/// <summary>
|
||||
/// Returns whether this combination is currently pressed
|
||||
/// </summary>
|
||||
/// <param name="handler">The input handler to query the keys with</param>
|
||||
/// <param name="gamepadIndex">The index of the gamepad to query, or -1 to query all gamepads</param>
|
||||
/// <returns>Whether this combination is pressed</returns>
|
||||
public bool IsPressed(InputHandler handler, int gamepadIndex = -1) {
|
||||
return this.IsModifierDown(handler, gamepadIndex) && handler.IsPressed(this.Key, gamepadIndex);
|
||||
}
|
||||
|
||||
private bool IsModifierDown(InputHandler handler, int gamepadIndex = -1) {
|
||||
/// <summary>
|
||||
/// Returns whether this combination's modifier keys are currently down
|
||||
/// </summary>
|
||||
/// <param name="handler">The input handler to query the keys with</param>
|
||||
/// <param name="gamepadIndex">The index of the gamepad to query, or -1 to query all gamepads</param>
|
||||
/// <returns>Whether this combination's modifiers are down</returns>
|
||||
public bool IsModifierDown(InputHandler handler, int gamepadIndex = -1) {
|
||||
return this.Modifiers.Length <= 0 || this.Modifiers.Any(m => handler.IsDown(m, gamepadIndex));
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,11 @@ namespace MLEM.Input {
|
|||
return ModifierKey.None;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="GetModifier(Microsoft.Xna.Framework.Input.Keys)"/>
|
||||
public static ModifierKey GetModifier(this GenericInput input) {
|
||||
return input.Type == GenericInput.InputType.Keyboard ? GetModifier(input) : ModifierKey.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the given key is a modifier key or not.
|
||||
/// </summary>
|
||||
|
@ -59,6 +64,11 @@ namespace MLEM.Input {
|
|||
return GetModifier(key) != ModifierKey.None;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IsModifier(Microsoft.Xna.Framework.Input.Keys)"/>
|
||||
public static bool IsModifier(this GenericInput input) {
|
||||
return GetModifier(input) != ModifierKey.None;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -68,7 +78,7 @@ namespace MLEM.Input {
|
|||
public enum ModifierKey {
|
||||
|
||||
/// <summary>
|
||||
/// No modifier key. Only used for <see cref="KeysExtensions.GetModifier"/>
|
||||
/// No modifier key. Only used for <see cref="KeysExtensions.GetModifier(Keys)"/>
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
|
|
Loading…
Reference in a new issue