Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
smoogipoo committed Dec 11, 2024
1 parent c68a3a1 commit bb6c523
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 9 deletions.
8 changes: 8 additions & 0 deletions osu.Framework/Graphics/Drawable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,14 @@ internal set
if (value != null && parent != null)
throw new InvalidOperationException("May not add a drawable to multiple containers.");

// When this drawable is part of any focus hierarchy (whether it is the first responder or not) unfocus the environment.
if (HasFocus)
{
// Prevent re-entry.
HasFocus = false;
GetContainingFocusSystem()!.ResignFocus(GetContainingFocusEnvironment()!.CurrentFocus!);
}

parent = value;
Invalidate(InvalidationFromParentSize | Invalidation.Colour | Invalidation.Presence | Invalidation.Parent);

Expand Down
16 changes: 16 additions & 0 deletions osu.Framework/Input/Focus/IFocusEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ internal void ChangeFocus(InputState state, Drawable? target)
CurrentFocus = target;
}

internal static bool IsDrawableValidForFocus(Drawable drawable)
{
while (drawable != null)
{
if (!drawable.IsAlive || !drawable.IsPresent || drawable.Parent == null)
return false;

if (drawable is IFocusEnvironment)
return true;

drawable = drawable.Parent;
}

return false;
}

internal static IEnumerable<Drawable> BuildFocusSet(Drawable? target)
{
Drawable? d = target;
Expand Down
54 changes: 46 additions & 8 deletions osu.Framework/Input/InputManager_Focus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,30 @@ public partial class InputManager : IFocusSystem, IFocusManager
{
public Drawable? FirstResponder { get; private set; }

private readonly List<IFocusEnvironment> activeEnvironments = new List<IFocusEnvironment>();
private readonly List<FocusRequest> pendingRequests = new List<FocusRequest>();
private int isHandlingClick;
private int isBatchingUpdates;

private void updateFocus()
{
using (BeginFocusUpdateBatch())
{
for (int i = activeEnvironments.Count - 1; i >= 0; i--)
{
IFocusEnvironment env = activeEnvironments[i];
Debug.Assert(env.CurrentFocus != null);

if (!isDrawableValidForFocus(env.CurrentFocus))
{
}
}
}

foreach (IFocusEnvironment env in activeEnvironments)
{
Debug.Assert(env.CurrentFocus != null);
}
}

public void RequestFocus(Drawable target)
=> enqueueRequest(new FocusRequest(FocusRequestType.Request, CurrentState, target));
Expand All @@ -28,16 +50,16 @@ public void AcquireFocus(Drawable target)
public void ResignFocus(Drawable target)
=> enqueueRequest(new FocusRequest(FocusRequestType.Resign, CurrentState, target));

internal ClickFocusUpdateContext BeginClickFocusUpdate() => new ClickFocusUpdateContext(this);
internal FocusUpdateBatch BeginFocusUpdateBatch() => new FocusUpdateBatch(this);

internal readonly ref struct ClickFocusUpdateContext
internal readonly ref struct FocusUpdateBatch
{
private readonly InputManager inputManager;

public ClickFocusUpdateContext(InputManager inputManager)
public FocusUpdateBatch(InputManager inputManager)
{
this.inputManager = inputManager;
inputManager.isHandlingClick++;
inputManager.isBatchingUpdates++;
}

public void HandleClick(Drawable? drawable)
Expand All @@ -50,7 +72,7 @@ public void HandleClick(Drawable? drawable)

public void Dispose()
{
inputManager.isHandlingClick--;
inputManager.isBatchingUpdates--;
inputManager.processPendingRequests();
}
}
Expand All @@ -63,8 +85,8 @@ private void enqueueRequest(FocusRequest request)

private void processPendingRequests()
{
Debug.Assert(isHandlingClick >= 0);
if (isHandlingClick > 0)
Debug.Assert(isBatchingUpdates >= 0);
if (isBatchingUpdates > 0)
return;

for (int i = 0; i < pendingRequests.Count; i++)
Expand Down Expand Up @@ -149,6 +171,22 @@ void resign(InputState state, Drawable target)
private IFocusEnvironment? getEnvironment(Drawable? drawable)
=> drawable?.FindClosestParentOrSelf<IFocusEnvironment>();

private bool isDrawableValidForFocus(Drawable drawable)
{
while (drawable != null)
{
if (!drawable.IsAlive || !drawable.IsPresent || drawable.Parent == null)
return false;

if (drawable is IFocusEnvironment)
break;

drawable = drawable.Parent;
}

return true;
}

void IFocusManager.TriggerFocusContention(Drawable? triggerSource)
{
}
Expand Down
2 changes: 1 addition & 1 deletion osu.Framework/Input/MouseButtonEventManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ private void handleClick(InputState state, List<Drawable>? targets)

Drawable? clicked;

using (var focus = InputManager.BeginClickFocusUpdate())
using (var focus = InputManager.BeginFocusUpdateBatch())
{
clicked = PropagateButtonEvent(drawables, new ClickEvent(state, Button, MouseDownPosition));
ClickedDrawable.SetTarget(clicked!);
Expand Down

0 comments on commit bb6c523

Please sign in to comment.