diff --git a/MLEM.Ui/Elements/ElementHelper.cs b/MLEM.Ui/Elements/ElementHelper.cs
index 1ab92db..66b6bb9 100644
--- a/MLEM.Ui/Elements/ElementHelper.cs
+++ b/MLEM.Ui/Elements/ElementHelper.cs
@@ -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;
}
+ ///
+ /// Creates a that acts as a way to input a custom value for a .
+ /// Note that only the first of the given keybind is displayed and edited, all others are ignored. The exception is that, if is set, unbinding the keybind clears all combinations.
+ /// Inputting custom keybinds using this element supports -based modifiers and any -based keys.
+ ///
+ /// The button's anchor
+ /// The button's size
+ /// The keybind that this button should represent
+ /// The input handler to query inputs with
+ /// A placeholder text that is displayed while the keybind is being edited
+ /// An optional generic input that allows the keybind value to be unbound, clearing all combinations
+ /// A placeholder text that is displayed if the keybind is unbound
+ /// An optional function to give each input a display name that is easier to read. If this is null, is used.
+ /// A keybind button with the given settings
+ public static Button KeybindButton(Anchor anchor, Vector2 size, Keybind keybind, InputHandler inputHandler, string activePlaceholder, GenericInput unbindKey = default, string unboundPlaceholder = "", Func 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;
+ }
+
}
///
diff --git a/MLEM/Input/GenericInput.cs b/MLEM/Input/GenericInput.cs
index 4905f83..6427c6a 100644
--- a/MLEM/Input/GenericInput.cs
+++ b/MLEM/Input/GenericInput.cs
@@ -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 {
///
/// The input to convert
/// The resulting keys
- /// If the given generic input's is not
+ /// If the given generic input's is not or
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();
}
///
@@ -115,9 +115,7 @@ namespace MLEM.Input {
/// The resulting button
/// If the given generic input's is not
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();
}
///
@@ -127,9 +125,7 @@ namespace MLEM.Input {
/// The resulting buttons
/// If the given generic input's is not
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();
}
///
@@ -138,6 +134,11 @@ namespace MLEM.Input {
[DataContract]
public enum InputType {
+ ///
+ /// A type representing no value
+ ///
+ [EnumMember]
+ None,
///
/// A type representing
///
diff --git a/MLEM/Input/InputHandler.cs b/MLEM/Input/InputHandler.cs
index d21373e..a19c63b 100644
--- a/MLEM/Input/InputHandler.cs
+++ b/MLEM/Input/InputHandler.cs
@@ -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;
}
}
diff --git a/MLEM/Input/Keybind.cs b/MLEM/Input/Keybind.cs
index 8fdca99..c9888f2 100644
--- a/MLEM/Input/Keybind.cs
+++ b/MLEM/Input/Keybind.cs
@@ -60,6 +60,16 @@ namespace MLEM.Input {
return this;
}
+ ///
+ /// Removes all combinations that match the given predicate
+ ///
+ /// The predicate to match against
+ /// This keybind, for chaining
+ public Keybind Remove(Func predicate) {
+ this.combinations = this.combinations.Where((c, i) => !predicate(c, i)).ToArray();
+ return this;
+ }
+
///
/// Copies all of the combinations from the given keybind into this keybind.
/// Note that this doesn't 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));
}
+ ///
+ /// Returns whether any of this keybind's modifier keys are currently down.
+ /// See for more information.
+ ///
+ /// The input handler to query the keys with
+ /// The index of the gamepad to query, or -1 to query all gamepads
+ /// Whether any of this keyboard's modifier keys are down
+ public bool IsModifierDown(InputHandler handler, int gamepadIndex = -1) {
+ return this.combinations.Any(c => c.IsModifierDown(handler, gamepadIndex));
+ }
+
///
/// Returns an enumerable of all of the combinations that this keybind currently contains
///
@@ -133,15 +154,33 @@ namespace MLEM.Input {
this.Key = key;
}
- internal bool IsDown(InputHandler handler, int gamepadIndex = -1) {
+ ///
+ /// Returns whether this combination is currently down
+ ///
+ /// The input handler to query the keys with
+ /// The index of the gamepad to query, or -1 to query all gamepads
+ /// Whether this combination is down
+ 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) {
+ ///
+ /// Returns whether this combination is currently pressed
+ ///
+ /// The input handler to query the keys with
+ /// The index of the gamepad to query, or -1 to query all gamepads
+ /// Whether this combination is pressed
+ 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) {
+ ///
+ /// Returns whether this combination's modifier keys are currently down
+ ///
+ /// The input handler to query the keys with
+ /// The index of the gamepad to query, or -1 to query all gamepads
+ /// Whether this combination's modifiers are down
+ public bool IsModifierDown(InputHandler handler, int gamepadIndex = -1) {
return this.Modifiers.Length <= 0 || this.Modifiers.Any(m => handler.IsDown(m, gamepadIndex));
}
diff --git a/MLEM/Input/KeysExtensions.cs b/MLEM/Input/KeysExtensions.cs
index 4400aca..ce12613 100644
--- a/MLEM/Input/KeysExtensions.cs
+++ b/MLEM/Input/KeysExtensions.cs
@@ -50,6 +50,11 @@ namespace MLEM.Input {
return ModifierKey.None;
}
+ ///
+ public static ModifierKey GetModifier(this GenericInput input) {
+ return input.Type == GenericInput.InputType.Keyboard ? GetModifier(input) : ModifierKey.None;
+ }
+
///
/// Returns whether the given key is a modifier key or not.
///
@@ -59,6 +64,11 @@ namespace MLEM.Input {
return GetModifier(key) != ModifierKey.None;
}
+ ///
+ public static bool IsModifier(this GenericInput input) {
+ return GetModifier(input) != ModifierKey.None;
+ }
+
}
///
@@ -68,7 +78,7 @@ namespace MLEM.Input {
public enum ModifierKey {
///
- /// No modifier key. Only used for
+ /// No modifier key. Only used for
///
None,
///