#1449 new ControlFocusExited override for allowing controls to know (#1467)

when they lost control focus, separate from keyboard focus
This commit is contained in:
chairbender
2021-01-13 14:18:45 -08:00
committed by GitHub
parent cd3a85ea04
commit c4062bcae9
4 changed files with 58 additions and 27 deletions

View File

@@ -21,8 +21,22 @@ namespace Robust.Client.Interfaces.UserInterface
/// </summary>
Stylesheet? Stylesheet { get; set; }
/// <summary>
/// A control can have "keyboard focus" separate from ControlFocused, obtained when calling
/// Control.GrabKeyboardFocus. Corresponding events in Control are KeyboardFocusEntered/Exited
/// </summary>
Control? KeyboardFocused { get; }
/// <summary>
/// A control gets "ControlFocused" when a mouse button (or any KeyBinding which has CanFocus = true) is
/// pressed down on the control. While it is focused, it will receive mouse hover events and the corresponding
/// keyup event if it still has focus when that occurs (it will NOT receive the keyup if focus has
/// been taken by another control). Focus is removed when a different control takes focus
/// (such as by pressing a different mouse button down over a different control) or when the keyup event
/// happens. When focus is lost on a control, it always fires Control.ControlFocusExited.
/// </summary>
Control? ControlFocused { get; }
LayoutContainer StateRoot { get; }
LayoutContainer WindowRoot { get; }

View File

@@ -757,14 +757,32 @@ namespace Robust.Client.UserInterface
/// <summary>
/// Called when this control receives keyboard focus.
/// </summary>
protected internal virtual void FocusEntered()
protected internal virtual void KeyboardFocusEntered()
{
}
/// <summary>
/// Called when this control loses keyboard focus.
/// Called when this control loses keyboard focus (corresponds to UserInterfaceManager.KeyboardFocused).
/// </summary>
protected internal virtual void FocusExited()
protected internal virtual void KeyboardFocusExited()
{
}
/// <summary>
/// Fired when a control loses control focus for any reason. See <see cref="IUserInterfaceManager.ControlFocused"/>.
/// </summary>
/// <remarks>
/// Controls which have some sort of drag / drop behavior should usually implement this method (typically by cancelling the drag drop).
/// Otherwise, if a user clicks down LMB over one control to initiate a drag, then clicks RMB down
/// over a different control while still holding down LMB, the control being dragged will now lose focus
/// and will no longer receive the keyup for the LMB, thus won't cancel the drag.
/// This should also be considered for controls which have any special KeyBindUp behavior - consider
/// what would happen if the control lost focus and never received the KeyBindUp.
///
/// There is no corresponding ControlFocusEntered - if a control wants to handle that situation they should simply
/// handle KeyBindDown as that's the only way a control would gain focus.
/// </remarks>
protected internal virtual void ControlFocusExited()
{
}

View File

@@ -589,18 +589,18 @@ namespace Robust.Client.UserInterface.Controls
return index;
}
protected internal override void FocusEntered()
protected internal override void KeyboardFocusEntered()
{
base.FocusEntered();
base.KeyboardFocusEntered();
// Reset this so the cursor is always visible immediately after gaining focus..
_resetCursorBlink();
OnFocusEnter?.Invoke(new LineEditEventArgs(this, _text));
}
protected internal override void FocusExited()
protected internal override void KeyboardFocusExited()
{
base.FocusExited();
base.KeyboardFocusExited();
OnFocusExit?.Invoke(new LineEditEventArgs(this, _text));
}

View File

@@ -57,9 +57,7 @@ namespace Robust.Client.UserInterface
public Control? KeyboardFocused { get; private set; }
// When a control receives a mouse down it must also receive a mouse up and mouse moves, always.
// So we keep track of which control is "focused" by the mouse.
private Control? _controlFocused;
public Control? ControlFocused { get; private set; }
public LayoutContainer StateRoot { get; private set; } = default!;
public PopupContainer ModalRoot { get; private set; } = default!;
@@ -244,7 +242,8 @@ namespace Robust.Client.UserInterface
RemoveModal(top);
else
{
_controlFocused = top;
ControlFocused?.ControlFocusExited();
ControlFocused = top;
return false; // prevent anything besides the top modal control from receiving input
}
}
@@ -260,12 +259,12 @@ namespace Robust.Client.UserInterface
{
return false;
}
ControlFocused?.ControlFocusExited();
ControlFocused = control;
_controlFocused = control;
if (_controlFocused.CanKeyboardFocus && _controlFocused.KeyboardFocusOnClick)
if (ControlFocused.CanKeyboardFocus && ControlFocused.KeyboardFocusOnClick)
{
_controlFocused.GrabKeyboardFocus();
ControlFocused.GrabKeyboardFocus();
}
return true;
@@ -273,7 +272,8 @@ namespace Robust.Client.UserInterface
public void HandleCanFocusUp()
{
_controlFocused = null;
ControlFocused?.ControlFocusExited();
ControlFocused = null;
}
public void KeyBindDown(BoundKeyEventArgs args)
@@ -290,7 +290,7 @@ namespace Robust.Client.UserInterface
return;
}
var control = _controlFocused ?? KeyboardFocused ?? MouseGetControl(args.PointerLocation.Position);
var control = ControlFocused ?? KeyboardFocused ?? MouseGetControl(args.PointerLocation.Position);
if (control == null)
{
@@ -311,7 +311,7 @@ namespace Robust.Client.UserInterface
public void KeyBindUp(BoundKeyEventArgs args)
{
var control = _controlFocused ?? KeyboardFocused ?? MouseGetControl(args.PointerLocation.Position);
var control = ControlFocused ?? KeyboardFocused ?? MouseGetControl(args.PointerLocation.Position);
if (control == null)
{
return;
@@ -352,7 +352,7 @@ namespace Robust.Client.UserInterface
_needUpdateActiveCursor = true;
}
var target = _controlFocused ?? newHovered;
var target = ControlFocused ?? newHovered;
if (target != null)
{
var guiArgs = new GUIMouseMoveEventArgs(mouseMoveEventArgs.Relative / UIScale,
@@ -368,7 +368,7 @@ namespace Robust.Client.UserInterface
private void UpdateActiveCursor()
{
// Consider mouse input focus first so that dragging windows don't act up etc.
var cursorTarget = _controlFocused ?? CurrentlyHovered;
var cursorTarget = ControlFocused ?? CurrentlyHovered;
if (cursorTarget == null)
{
@@ -478,13 +478,13 @@ namespace Robust.Client.UserInterface
KeyboardFocused = control;
KeyboardFocused.FocusEntered();
KeyboardFocused.KeyboardFocusEntered();
}
public void ReleaseKeyboardFocus()
{
var oldFocused = KeyboardFocused;
oldFocused?.FocusExited();
oldFocused?.KeyboardFocusExited();
KeyboardFocused = null;
}
@@ -528,10 +528,9 @@ namespace Robust.Client.UserInterface
_clearTooltip();
}
if (control == _controlFocused)
{
_controlFocused = null;
}
if (control != ControlFocused) return;
ControlFocused?.ControlFocusExited();
ControlFocused = null;
}
public void PushModal(Control modal)
@@ -569,7 +568,7 @@ namespace Robust.Client.UserInterface
public void CursorChanged(Control control)
{
if (control == _controlFocused || control == CurrentlyHovered)
if (control == ControlFocused || control == CurrentlyHovered)
{
_needUpdateActiveCursor = true;
}