2019-01-24 16:43:03 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2021-01-13 16:59:47 +08:00
using System ;
2017-08-15 23:08:59 +08:00
using System.Collections.Generic ;
2023-10-11 14:30:04 +08:00
using System.Diagnostics ;
2017-08-15 23:08:59 +08:00
using System.Linq ;
using osu.Framework.Allocation ;
2023-10-20 13:39:36 +08:00
using osu.Framework.Audio ;
using osu.Framework.Audio.Sample ;
2021-05-25 19:08:40 +08:00
using osu.Framework.Bindables ;
2017-08-15 23:08:59 +08:00
using osu.Framework.Extensions ;
using osu.Framework.Extensions.Color4Extensions ;
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
2019-04-02 13:51:28 +08:00
using osu.Framework.Graphics.Effects ;
2017-08-15 23:08:59 +08:00
using osu.Framework.Graphics.Shapes ;
2021-11-08 13:55:26 +08:00
using osu.Framework.Input ;
2017-08-18 17:22:00 +08:00
using osu.Framework.Input.Bindings ;
2018-10-02 11:02:47 +08:00
using osu.Framework.Input.Events ;
2022-05-16 13:09:37 +08:00
using osu.Framework.Localisation ;
2023-10-20 13:39:36 +08:00
using osu.Framework.Utils ;
2023-10-12 22:30:22 +08:00
using osu.Game.Database ;
2017-08-15 23:08:59 +08:00
using osu.Game.Graphics.Sprites ;
2019-06-21 12:50:05 +08:00
using osu.Game.Graphics.UserInterface ;
2022-11-24 15:26:57 +08:00
using osu.Game.Graphics.UserInterfaceV2 ;
2021-01-13 16:59:47 +08:00
using osu.Game.Input.Bindings ;
2022-01-28 12:53:48 +08:00
using osu.Game.Resources.Localisation.Web ;
2023-10-12 22:30:22 +08:00
using osu.Game.Rulesets ;
2019-06-21 12:50:05 +08:00
using osuTK ;
2018-11-20 15:51:59 +08:00
using osuTK.Input ;
2018-04-13 17:19:50 +08:00
2021-07-21 12:18:24 +08:00
namespace osu.Game.Overlays.Settings.Sections.Input
2017-08-15 23:08:59 +08:00
{
2023-10-13 17:29:06 +08:00
public partial class KeyBindingRow : Container , IFilterable
2017-08-15 23:08:59 +08:00
{
2022-11-17 14:23:20 +08:00
/// <summary>
2022-11-18 12:55:37 +08:00
/// Invoked when the binding of this row is updated with a change being written.
2022-11-17 14:23:20 +08:00
/// </summary>
2023-10-11 17:25:19 +08:00
public KeyBindingUpdated ? BindingUpdated { get ; set ; }
public delegate void KeyBindingUpdated ( KeyBindingRow sender , KeyBindingUpdatedEventArgs args ) ;
2023-10-12 22:30:22 +08:00
public Func < List < RealmKeyBinding > > GetAllSectionBindings { get ; set ; } = null ! ;
2022-11-17 14:23:20 +08:00
2023-10-11 14:21:19 +08:00
/// <summary>
/// Whether left and right mouse button clicks should be included in the edited bindings.
/// </summary>
2023-10-11 14:20:25 +08:00
public bool AllowMainMouseButtons { get ; init ; }
2018-04-13 17:19:50 +08:00
2023-10-11 17:08:10 +08:00
/// <summary>
/// The bindings to display in this row.
/// </summary>
public BindableList < RealmKeyBinding > KeyBindings { get ; } = new BindableList < RealmKeyBinding > ( ) ;
2023-10-11 14:21:19 +08:00
/// <summary>
/// The default key bindings for this row.
/// </summary>
2023-10-11 14:30:04 +08:00
public IEnumerable < KeyCombination > Defaults { get ; init ; } = Array . Empty < KeyCombination > ( ) ;
2018-04-13 17:19:50 +08:00
2023-10-11 14:18:48 +08:00
#region IFilterable
2018-04-13 17:19:50 +08:00
2017-08-15 23:08:59 +08:00
private bool matchingFilter ;
2018-04-13 17:19:50 +08:00
2017-08-15 23:08:59 +08:00
public bool MatchingFilter
{
2019-02-28 12:58:19 +08:00
get = > matchingFilter ;
2017-08-15 23:08:59 +08:00
set
{
matchingFilter = value ;
this . FadeTo ( ! matchingFilter ? 0 : 1 ) ;
}
}
2018-04-13 17:19:50 +08:00
2023-10-11 14:18:48 +08:00
public bool FilteringActive { get ; set ; }
2021-05-26 17:03:15 +08:00
2023-10-11 17:08:10 +08:00
public IEnumerable < LocalisableString > FilterTerms = > KeyBindings . Select ( b = > ( LocalisableString ) keyCombinationProvider . GetReadableString ( b . KeyCombination ) ) . Prepend ( text . Text ) ;
2021-05-26 17:03:15 +08:00
2023-10-11 14:18:48 +08:00
#endregion
2023-10-11 21:36:27 +08:00
public readonly object Action ;
2023-10-11 14:18:48 +08:00
private Bindable < bool > isDefault { get ; } = new BindableBool ( true ) ;
2019-03-28 23:29:07 +08:00
2023-10-12 22:30:22 +08:00
[Resolved]
private RealmAccess realm { get ; set ; } = null ! ;
[Resolved]
private RulesetStore rulesets { get ; set ; } = null ! ;
2021-11-08 13:55:26 +08:00
[Resolved]
2023-10-11 14:30:04 +08:00
private ReadableKeyCombinationProvider keyCombinationProvider { get ; set ; } = null ! ;
2021-11-08 13:55:26 +08:00
2023-10-11 14:30:04 +08:00
private Container content = null ! ;
2023-10-11 14:18:48 +08:00
2023-10-11 14:30:04 +08:00
private OsuSpriteText text = null ! ;
private FillFlowContainer cancelAndClearButtons = null ! ;
private FillFlowContainer < KeyButton > buttons = null ! ;
2018-04-13 17:19:50 +08:00
2023-10-11 14:30:04 +08:00
private KeyButton ? bindTarget ;
2021-05-15 09:24:08 +08:00
2023-10-20 13:39:36 +08:00
private Sample ? [ ] ? keypressSamples ;
2023-10-11 14:18:48 +08:00
private const float transition_time = 150 ;
private const float height = 20 ;
private const float padding = 5 ;
public override bool ReceivePositionalInputAt ( Vector2 screenSpacePos ) = >
content . ReceivePositionalInputAt ( screenSpacePos ) ;
public override bool AcceptsFocus = > bindTarget = = null ;
2018-04-13 17:19:50 +08:00
2023-10-11 14:21:19 +08:00
/// <summary>
/// Creates a new <see cref="KeyBindingRow"/>.
/// </summary>
/// <param name="action">The action that this row contains bindings for.</param>
2023-10-11 17:08:10 +08:00
public KeyBindingRow ( object action )
2017-08-15 23:08:59 +08:00
{
2023-10-12 22:30:22 +08:00
Action = action ;
2018-04-13 17:19:50 +08:00
2017-08-15 23:08:59 +08:00
RelativeSizeAxes = Axes . X ;
AutoSizeAxes = Axes . Y ;
}
2018-04-13 17:19:50 +08:00
2017-08-15 23:08:59 +08:00
[BackgroundDependencyLoader]
2023-10-20 13:39:36 +08:00
private void load ( OverlayColourProvider colourProvider , AudioManager audioManager )
2017-08-15 23:08:59 +08:00
{
2021-05-26 17:03:15 +08:00
RelativeSizeAxes = Axes . X ;
AutoSizeAxes = Axes . Y ;
2021-10-19 02:36:47 +08:00
Padding = new MarginPadding { Right = SettingsPanel . CONTENT_MARGINS } ;
2018-04-13 17:19:50 +08:00
2021-10-19 02:36:47 +08:00
InternalChildren = new Drawable [ ]
2017-08-15 23:08:59 +08:00
{
2021-10-19 02:36:47 +08:00
new Container
2017-08-15 23:08:59 +08:00
{
2021-10-19 02:36:47 +08:00
RelativeSizeAxes = Axes . Y ,
Width = SettingsPanel . CONTENT_MARGINS ,
2023-07-13 12:46:50 +08:00
Child = new RevertToDefaultButton < bool >
2021-10-19 02:36:47 +08:00
{
Current = isDefault ,
Action = RestoreDefaults ,
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
}
2021-10-16 05:15:28 +08:00
} ,
2021-10-19 02:36:47 +08:00
new Container
2021-10-16 05:15:28 +08:00
{
2021-10-19 02:36:47 +08:00
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y ,
Padding = new MarginPadding { Left = SettingsPanel . CONTENT_MARGINS } ,
Children = new Drawable [ ]
2021-05-26 17:03:15 +08:00
{
2021-10-16 05:15:28 +08:00
content = new Container
2021-05-26 17:03:15 +08:00
{
2021-10-16 05:15:28 +08:00
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y ,
Masking = true ,
CornerRadius = padding ,
EdgeEffect = new EdgeEffectParameters
2021-05-26 17:03:15 +08:00
{
2021-10-16 05:15:28 +08:00
Radius = 2 ,
Colour = colourProvider . Highlight1 . Opacity ( 0 ) ,
Type = EdgeEffectType . Shadow ,
Hollow = true ,
2021-05-26 17:03:15 +08:00
} ,
2021-10-16 05:15:28 +08:00
Children = new Drawable [ ]
{
new Box
{
RelativeSizeAxes = Axes . Both ,
Colour = colourProvider . Background5 ,
} ,
text = new OsuSpriteText
{
2023-10-11 21:36:27 +08:00
Text = Action . GetLocalisableDescription ( ) ,
2021-10-16 05:15:28 +08:00
Margin = new MarginPadding ( 1.5f * padding ) ,
} ,
buttons = new FillFlowContainer < KeyButton >
{
AutoSizeAxes = Axes . Both ,
Anchor = Anchor . TopRight ,
Origin = Anchor . TopRight
} ,
cancelAndClearButtons = new FillFlowContainer
{
AutoSizeAxes = Axes . Both ,
Padding = new MarginPadding ( padding ) { Top = height + padding * 2 } ,
Anchor = Anchor . TopRight ,
Origin = Anchor . TopRight ,
Alpha = 0 ,
Spacing = new Vector2 ( 5 ) ,
Children = new Drawable [ ]
{
2022-11-17 14:23:20 +08:00
new CancelButton { Action = ( ) = > finalise ( false ) } ,
2021-10-16 05:15:28 +08:00
new ClearButton { Action = clear } ,
} ,
2021-11-08 21:32:00 +08:00
} ,
new HoverClickSounds ( )
2021-10-16 05:15:28 +08:00
}
2021-10-19 02:36:47 +08:00
}
2021-05-26 17:03:15 +08:00
}
2021-11-08 21:32:00 +08:00
}
2017-08-15 23:08:59 +08:00
} ;
2018-04-13 17:19:50 +08:00
2023-10-11 17:08:10 +08:00
KeyBindings . BindCollectionChanged ( ( _ , _ ) = >
{
Scheduler . AddOnce ( updateButtons ) ;
updateIsDefaultValue ( ) ;
} , true ) ;
2023-10-20 13:39:36 +08:00
keypressSamples = new Sample [ 4 ] ;
for ( int i = 0 ; i < keypressSamples . Length ; i + + )
keypressSamples [ i ] = audioManager . Samples . Get ( $@"Keyboard/key-press-{1 + i}" ) ;
2023-10-11 17:08:10 +08:00
}
2017-08-23 18:26:49 +08:00
public void RestoreDefaults ( )
{
int i = 0 ;
2019-04-01 11:16:05 +08:00
2017-08-23 18:26:49 +08:00
foreach ( var d in Defaults )
{
2020-08-03 14:25:23 +08:00
var button = buttons [ i + + ] ;
2017-08-23 18:26:49 +08:00
button . UpdateKeyCombination ( d ) ;
2023-10-11 21:36:27 +08:00
2024-11-02 02:26:59 +08:00
tryPersistKeyBinding ( button . KeyBinding . Value , advanceToNextBinding : false , restoringDefaults : true ) ;
2017-08-23 18:26:49 +08:00
}
2021-05-25 19:08:40 +08:00
2021-05-26 17:28:00 +08:00
isDefault . Value = true ;
2017-08-23 18:26:49 +08:00
}
2018-04-13 17:19:50 +08:00
2018-10-02 11:02:47 +08:00
protected override bool OnHover ( HoverEvent e )
2017-08-15 23:08:59 +08:00
{
2021-05-26 17:03:15 +08:00
content . FadeEdgeEffectTo ( 1 , transition_time , Easing . OutQuint ) ;
2018-04-13 17:19:50 +08:00
2018-10-02 11:02:47 +08:00
return base . OnHover ( e ) ;
2017-08-15 23:08:59 +08:00
}
2018-04-13 17:19:50 +08:00
2018-10-02 11:02:47 +08:00
protected override void OnHoverLost ( HoverLostEvent e )
2017-08-15 23:08:59 +08:00
{
2021-05-26 17:03:15 +08:00
content . FadeEdgeEffectTo ( 0 , transition_time , Easing . OutQuint ) ;
2018-04-13 17:19:50 +08:00
2018-10-02 11:02:47 +08:00
base . OnHoverLost ( e ) ;
2017-08-15 23:08:59 +08:00
}
2018-04-13 17:19:50 +08:00
2018-10-02 11:02:47 +08:00
protected override bool OnClick ( ClickEvent e ) = > true ;
2018-04-13 17:19:50 +08:00
2018-10-02 11:02:47 +08:00
protected override bool OnMouseDown ( MouseDownEvent e )
2017-08-18 17:22:00 +08:00
{
2023-10-11 14:30:04 +08:00
if ( ! HasFocus )
return base . OnMouseDown ( e ) ;
Debug . Assert ( bindTarget ! = null ) ;
if ( ! bindTarget . IsHovered )
2018-10-02 11:02:47 +08:00
return base . OnMouseDown ( e ) ;
2018-04-13 17:19:50 +08:00
2017-08-22 17:21:00 +08:00
if ( ! AllowMainMouseButtons )
2017-08-18 17:22:00 +08:00
{
2018-10-02 11:02:47 +08:00
switch ( e . Button )
2017-08-18 17:22:00 +08:00
{
2017-08-22 17:21:00 +08:00
case MouseButton . Left :
case MouseButton . Right :
return true ;
2017-08-18 17:22:00 +08:00
}
}
2018-04-13 17:19:50 +08:00
2022-11-18 14:20:46 +08:00
bindTarget . UpdateKeyCombination ( KeyCombination . FromInputState ( e . CurrentState ) , KeyCombination . FromMouseButton ( e . Button ) ) ;
2017-08-22 17:21:00 +08:00
return true ;
2017-08-15 23:08:59 +08:00
}
2018-04-13 17:19:50 +08:00
2020-01-20 17:17:21 +08:00
protected override void OnMouseUp ( MouseUpEvent e )
2017-08-18 17:22:00 +08:00
{
2017-08-22 17:21:00 +08:00
// don't do anything until the last button is released.
2018-10-02 11:44:14 +08:00
if ( ! HasFocus | | e . HasAnyButtonPressed )
2020-01-20 17:17:21 +08:00
{
base . OnMouseUp ( e ) ;
return ;
}
2018-04-13 17:19:50 +08:00
2023-10-11 14:30:04 +08:00
Debug . Assert ( bindTarget ! = null ) ;
2017-08-22 17:21:00 +08:00
if ( bindTarget . IsHovered )
2023-10-12 22:30:22 +08:00
finalise ( false ) ;
2020-08-03 03:52:12 +08:00
// prevent updating bind target before clear button's action
else if ( ! cancelAndClearButtons . Any ( b = > b . IsHovered ) )
2017-08-22 17:21:00 +08:00
updateBindTarget ( ) ;
2017-08-18 17:22:00 +08:00
}
2018-04-13 17:19:50 +08:00
2018-10-02 11:02:47 +08:00
protected override bool OnScroll ( ScrollEvent e )
2017-08-22 13:42:49 +08:00
{
if ( HasFocus )
{
2023-10-11 14:30:04 +08:00
Debug . Assert ( bindTarget ! = null ) ;
2017-08-22 13:42:49 +08:00
if ( bindTarget . IsHovered )
{
2022-11-18 14:20:46 +08:00
bindTarget . UpdateKeyCombination ( KeyCombination . FromInputState ( e . CurrentState , e . ScrollDelta ) , KeyCombination . FromScrollDelta ( e . ScrollDelta ) . First ( ) ) ;
2017-08-22 13:42:49 +08:00
finalise ( ) ;
return true ;
}
}
2018-04-13 17:19:50 +08:00
2018-10-02 11:02:47 +08:00
return base . OnScroll ( e ) ;
2017-08-22 13:42:49 +08:00
}
2018-04-13 17:19:50 +08:00
2018-10-02 11:02:47 +08:00
protected override bool OnKeyDown ( KeyDownEvent e )
2017-08-15 23:08:59 +08:00
{
2022-11-18 14:20:46 +08:00
if ( ! HasFocus | | e . Repeat )
2017-08-18 17:22:00 +08:00
return false ;
2018-04-13 17:19:50 +08:00
2023-10-11 14:30:04 +08:00
Debug . Assert ( bindTarget ! = null ) ;
2023-10-20 13:39:36 +08:00
keypressSamples ? [ RNG . Next ( 0 , keypressSamples . Length ) ] ? . Play ( ) ;
2022-11-18 14:20:46 +08:00
bindTarget . UpdateKeyCombination ( KeyCombination . FromInputState ( e . CurrentState ) , KeyCombination . FromKey ( e . Key ) ) ;
2018-10-02 11:02:47 +08:00
if ( ! isModifier ( e . Key ) ) finalise ( ) ;
2018-04-13 17:19:50 +08:00
2017-08-18 17:22:00 +08:00
return true ;
2023-10-13 17:29:06 +08:00
bool isModifier ( Key k ) = > k < Key . F1 ;
2017-08-15 23:08:59 +08:00
}
2018-04-13 17:19:50 +08:00
2020-01-20 18:35:37 +08:00
protected override void OnKeyUp ( KeyUpEvent e )
2017-08-16 18:17:42 +08:00
{
2020-01-20 18:35:37 +08:00
if ( ! HasFocus )
{
base . OnKeyUp ( e ) ;
return ;
}
2018-04-13 17:19:50 +08:00
2017-08-22 17:21:00 +08:00
finalise ( ) ;
2017-08-16 18:17:42 +08:00
}
2018-04-13 17:19:50 +08:00
2018-09-19 19:52:57 +08:00
protected override bool OnJoystickPress ( JoystickPressEvent e )
2018-05-12 23:10:55 +08:00
{
if ( ! HasFocus )
return false ;
2023-10-11 14:30:04 +08:00
Debug . Assert ( bindTarget ! = null ) ;
2022-11-18 14:20:46 +08:00
bindTarget . UpdateKeyCombination ( KeyCombination . FromInputState ( e . CurrentState ) , KeyCombination . FromJoystickButton ( e . Button ) ) ;
2018-05-12 23:10:55 +08:00
finalise ( ) ;
return true ;
}
2020-01-20 19:30:25 +08:00
protected override void OnJoystickRelease ( JoystickReleaseEvent e )
2018-05-12 23:10:55 +08:00
{
if ( ! HasFocus )
2020-01-20 19:30:25 +08:00
{
base . OnJoystickRelease ( e ) ;
return ;
}
2018-05-12 23:10:55 +08:00
finalise ( ) ;
}
2020-05-10 12:39:20 +08:00
protected override bool OnMidiDown ( MidiDownEvent e )
{
if ( ! HasFocus )
return false ;
2023-10-11 14:30:04 +08:00
Debug . Assert ( bindTarget ! = null ) ;
2022-11-18 14:20:46 +08:00
bindTarget . UpdateKeyCombination ( KeyCombination . FromInputState ( e . CurrentState ) , KeyCombination . FromMidiKey ( e . Key ) ) ;
2020-05-10 12:39:20 +08:00
finalise ( ) ;
return true ;
}
protected override void OnMidiUp ( MidiUpEvent e )
{
if ( ! HasFocus )
{
base . OnMidiUp ( e ) ;
return ;
}
finalise ( ) ;
}
2022-10-15 15:11:28 +08:00
protected override bool OnTabletAuxiliaryButtonPress ( TabletAuxiliaryButtonPressEvent e )
{
if ( ! HasFocus )
return false ;
2023-10-11 14:30:04 +08:00
Debug . Assert ( bindTarget ! = null ) ;
2022-11-18 14:20:46 +08:00
bindTarget . UpdateKeyCombination ( KeyCombination . FromInputState ( e . CurrentState ) , KeyCombination . FromTabletAuxiliaryButton ( e . Button ) ) ;
2022-10-15 15:11:28 +08:00
finalise ( ) ;
return true ;
}
protected override void OnTabletAuxiliaryButtonRelease ( TabletAuxiliaryButtonReleaseEvent e )
{
if ( ! HasFocus )
{
base . OnTabletAuxiliaryButtonRelease ( e ) ;
return ;
}
finalise ( ) ;
}
protected override bool OnTabletPenButtonPress ( TabletPenButtonPressEvent e )
{
if ( ! HasFocus )
return false ;
2023-10-11 14:30:04 +08:00
Debug . Assert ( bindTarget ! = null ) ;
2022-11-18 14:20:46 +08:00
bindTarget . UpdateKeyCombination ( KeyCombination . FromInputState ( e . CurrentState ) , KeyCombination . FromTabletPenButton ( e . Button ) ) ;
2022-10-15 15:11:28 +08:00
finalise ( ) ;
return true ;
}
protected override void OnTabletPenButtonRelease ( TabletPenButtonReleaseEvent e )
{
if ( ! HasFocus )
{
base . OnTabletPenButtonRelease ( e ) ;
return ;
}
finalise ( ) ;
}
2023-10-13 17:29:06 +08:00
private void updateButtons ( )
{
if ( buttons . Count > KeyBindings . Count )
buttons . RemoveRange ( buttons . Skip ( KeyBindings . Count ) . ToArray ( ) , true ) ;
while ( buttons . Count < KeyBindings . Count )
buttons . Add ( new KeyButton ( ) ) ;
foreach ( var ( button , binding ) in buttons . Zip ( KeyBindings ) )
button . KeyBinding . Value = binding ;
}
2019-06-21 12:50:05 +08:00
private void clear ( )
{
2020-06-04 21:17:00 +08:00
if ( bindTarget = = null )
return ;
2019-06-21 12:50:05 +08:00
bindTarget . UpdateKeyCombination ( InputKey . None ) ;
2023-10-12 22:30:22 +08:00
finalise ( false ) ;
2019-06-21 12:50:05 +08:00
}
2023-10-12 22:30:22 +08:00
private void finalise ( bool advanceToNextBinding = true )
2017-08-16 18:17:42 +08:00
{
2017-08-18 17:22:00 +08:00
if ( bindTarget ! = null )
{
2021-05-25 19:08:40 +08:00
updateIsDefaultValue ( ) ;
2017-08-18 17:22:00 +08:00
bindTarget . IsBinding = false ;
2023-10-12 22:30:22 +08:00
var bindingToPersist = bindTarget . KeyBinding . Value ;
2017-08-18 17:22:00 +08:00
Schedule ( ( ) = >
{
// schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.)
bindTarget = null ;
2023-10-12 22:30:22 +08:00
tryPersistKeyBinding ( bindingToPersist , advanceToNextBinding ) ;
2017-08-18 17:22:00 +08:00
} ) ;
}
2018-04-13 17:19:50 +08:00
2017-08-18 17:22:00 +08:00
if ( HasFocus )
2024-05-27 17:23:32 +08:00
GetContainingFocusManager ( ) ! . ChangeFocus ( null ) ;
2018-04-13 17:19:50 +08:00
2020-08-03 03:52:12 +08:00
cancelAndClearButtons . FadeOut ( 300 , Easing . OutQuint ) ;
cancelAndClearButtons . BypassAutoSizeAxes | = Axes . Y ;
2017-08-18 17:22:00 +08:00
}
2018-04-13 17:19:50 +08:00
2023-10-13 17:29:06 +08:00
protected override void OnFocus ( FocusEvent e )
{
content . AutoSizeDuration = 500 ;
content . AutoSizeEasing = Easing . OutQuint ;
cancelAndClearButtons . FadeIn ( 300 , Easing . OutQuint ) ;
cancelAndClearButtons . BypassAutoSizeAxes & = ~ Axes . Y ;
updateBindTarget ( ) ;
base . OnFocus ( e ) ;
}
protected override void OnFocusLost ( FocusLostEvent e )
{
finalise ( false ) ;
base . OnFocusLost ( e ) ;
}
2024-11-02 02:26:59 +08:00
private bool isConflictingBinding ( RealmKeyBinding first , RealmKeyBinding second , bool restoringDefaults )
{
if ( first . ID = = second . ID )
return false ;
// ignore conflicts with same action bindings during revert. the assumption is that the other binding will be reverted subsequently in the same higher-level operation.
// this happens if the bindings for an action are rebound to the same keys, but the ordering of the bindings itself is different.
if ( restoringDefaults & & first . ActionInt = = second . ActionInt )
return false ;
return first . KeyCombination . Equals ( second . KeyCombination ) ;
}
private void tryPersistKeyBinding ( RealmKeyBinding keyBinding , bool advanceToNextBinding , bool restoringDefaults = false )
2023-10-12 22:30:22 +08:00
{
2023-10-13 17:18:06 +08:00
List < RealmKeyBinding > bindings = GetAllSectionBindings ( ) ;
RealmKeyBinding ? existingBinding = keyBinding . KeyCombination . Equals ( new KeyCombination ( InputKey . None ) )
2023-10-12 22:30:22 +08:00
? null
2024-11-02 02:26:59 +08:00
: bindings . FirstOrDefault ( other = > isConflictingBinding ( keyBinding , other , restoringDefaults ) ) ;
2024-10-30 16:02:51 +08:00
2023-10-12 22:30:22 +08:00
if ( existingBinding = = null )
{
2023-10-31 19:25:08 +08:00
realm . Write ( r = > r . Find < RealmKeyBinding > ( keyBinding . ID ) ! . KeyCombinationString = keyBinding . KeyCombination . ToString ( ) ) ;
2023-10-13 17:18:06 +08:00
BindingUpdated ? . Invoke ( this , new KeyBindingUpdatedEventArgs ( bindingConflictResolved : false , advanceToNextBinding ) ) ;
2023-10-12 22:30:22 +08:00
return ;
}
var keyBindingBeforeUpdate = bindings . Single ( other = > other . ID = = keyBinding . ID ) ;
showBindingConflictPopover (
new KeyBindingConflictInfo (
new ConflictingKeyBinding ( existingBinding . ID , existingBinding . GetAction ( rulesets ) , existingBinding . KeyCombination , new KeyCombination ( InputKey . None ) ) ,
new ConflictingKeyBinding ( keyBindingBeforeUpdate . ID , Action , keyBinding . KeyCombination , keyBindingBeforeUpdate . KeyCombination ) ) ) ;
}
2020-08-03 03:26:09 +08:00
/// <summary>
/// Updates the bind target to the currently hovered key button or the first if clicked anywhere else.
/// </summary>
2017-08-18 17:22:00 +08:00
private void updateBindTarget ( )
2017-08-15 23:08:59 +08:00
{
if ( bindTarget ! = null ) bindTarget . IsBinding = false ;
2020-08-03 14:25:23 +08:00
bindTarget = buttons . FirstOrDefault ( b = > b . IsHovered ) ? ? buttons . FirstOrDefault ( ) ;
2017-08-15 23:08:59 +08:00
if ( bindTarget ! = null ) bindTarget . IsBinding = true ;
}
2018-04-13 17:19:50 +08:00
2021-05-26 17:03:15 +08:00
private void updateIsDefaultValue ( )
{
2023-10-11 17:08:10 +08:00
isDefault . Value = KeyBindings . Select ( b = > b . KeyCombination ) . SequenceEqual ( Defaults ) ;
2021-05-26 17:03:15 +08:00
}
2022-11-26 23:19:36 +08:00
private partial class CancelButton : RoundedButton
2019-06-21 12:50:05 +08:00
{
public CancelButton ( )
{
2022-01-28 12:53:48 +08:00
Text = CommonStrings . ButtonsCancel ;
2019-06-21 12:50:05 +08:00
Size = new Vector2 ( 80 , 20 ) ;
}
}
2022-11-26 23:19:36 +08:00
public partial class ClearButton : DangerousRoundedButton
2019-06-21 12:50:05 +08:00
{
public ClearButton ( )
{
2022-01-28 12:53:48 +08:00
Text = CommonStrings . ButtonsClear ;
2019-06-21 12:50:05 +08:00
Size = new Vector2 ( 80 , 20 ) ;
}
}
2017-08-15 23:08:59 +08:00
}
2017-09-13 22:18:02 +08:00
}