Fix ctrl-dragging on an existing selection causing deselection of the hovered object

This commit is contained in:
Dean Herbert 2021-04-12 19:05:23 +09:00
parent e8c248f2b2
commit cc2acf5e54
2 changed files with 60 additions and 15 deletions

View File

@ -135,11 +135,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
protected override bool OnMouseDown(MouseDownEvent e) protected override bool OnMouseDown(MouseDownEvent e)
{ {
if (!beginClickSelection(e)) return true; bool selectionPerformed = beginClickSelection(e);
// even if a selection didn't occur, a drag event may still move the selection.
prepareSelectionMovement(); prepareSelectionMovement();
return e.Button == MouseButton.Left; return selectionPerformed || e.Button == MouseButton.Left;
} }
private SelectionBlueprint clickedBlueprint; private SelectionBlueprint clickedBlueprint;
@ -154,7 +155,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
// Deselection should only occur if no selected blueprints are hovered // Deselection should only occur if no selected blueprints are hovered
// A special case for when a blueprint was selected via this click is added since OnClick() may occur outside the hitobject and should not trigger deselection // A special case for when a blueprint was selected via this click is added since OnClick() may occur outside the hitobject and should not trigger deselection
if (endClickSelection() || clickedBlueprint != null) if (endClickSelection(e) || clickedBlueprint != null)
return true; return true;
deselectAll(); deselectAll();
@ -177,7 +178,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
protected override void OnMouseUp(MouseUpEvent e) protected override void OnMouseUp(MouseUpEvent e)
{ {
// Special case for when a drag happened instead of a click // Special case for when a drag happened instead of a click
Schedule(() => endClickSelection()); Schedule(() =>
{
endClickSelection(e);
clickSelectionBegan = false;
isDraggingBlueprint = false;
});
finishSelectionMovement(); finishSelectionMovement();
} }
@ -226,7 +232,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
Beatmap.Update(obj); Beatmap.Update(obj);
changeHandler?.EndChange(); changeHandler?.EndChange();
isDraggingBlueprint = false;
} }
if (DragBox.State == Visibility.Visible) if (DragBox.State == Visibility.Visible)
@ -355,13 +360,28 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// <summary> /// <summary>
/// Finishes the current blueprint selection. /// Finishes the current blueprint selection.
/// </summary> /// </summary>
/// <param name="e">The mouse event which triggered end of selection.</param>
/// <returns>Whether a click selection was active.</returns> /// <returns>Whether a click selection was active.</returns>
private bool endClickSelection() private bool endClickSelection(MouseButtonEvent e)
{ {
if (!clickSelectionBegan) if (!clickSelectionBegan && !isDraggingBlueprint)
return false; {
// if a selection didn't occur, we may want to trigger a deselection.
if (e.ControlPressed && e.Button == MouseButton.Left)
{
// Iterate from the top of the input stack (blueprints closest to the front of the screen first).
// Priority is given to already-selected blueprints.
foreach (SelectionBlueprint blueprint in SelectionBlueprints.AliveChildren.Reverse().OrderByDescending(b => b.IsSelected))
{
if (!blueprint.IsHovered) continue;
return clickSelectionBegan = SelectionHandler.HandleDeselectionRequested(blueprint, e);
}
}
return false;
}
clickSelectionBegan = false;
return true; return true;
} }

View File

@ -228,14 +228,33 @@ namespace osu.Game.Screens.Edit.Compose.Components
return false; return false;
} }
if (e.ControlPressed && e.Button == MouseButton.Left) // while holding control, we only want to add to selection, not replace an existing selection.
if (e.ControlPressed && e.Button == MouseButton.Left && !blueprint.IsSelected)
{
blueprint.ToggleSelection(); blueprint.ToggleSelection();
else
ensureSelected(blueprint);
return true; return true;
} }
return ensureSelected(blueprint);
}
/// <summary>
/// Handle a blueprint requesting selection.
/// </summary>
/// <param name="blueprint">The blueprint.</param>
/// <param name="e">The mouse event responsible for deselection.</param>
/// <returns>Whether a deselection was performed.</returns>
internal bool HandleDeselectionRequested(SelectionBlueprint blueprint, MouseButtonEvent e)
{
if (blueprint.IsSelected)
{
blueprint.ToggleSelection();
return true;
}
return false;
}
private void handleQuickDeletion(SelectionBlueprint blueprint) private void handleQuickDeletion(SelectionBlueprint blueprint)
{ {
if (blueprint.HandleQuickDeletion()) if (blueprint.HandleQuickDeletion())
@ -247,13 +266,19 @@ namespace osu.Game.Screens.Edit.Compose.Components
deleteSelected(); deleteSelected();
} }
private void ensureSelected(SelectionBlueprint blueprint) /// <summary>
/// Ensure the blueprint is in a selected state.
/// </summary>
/// <param name="blueprint">The blueprint to select.</param>
/// <returns>Whether selection state was changed.</returns>
private bool ensureSelected(SelectionBlueprint blueprint)
{ {
if (blueprint.IsSelected) if (blueprint.IsSelected)
return; return false;
DeselectAll?.Invoke(); DeselectAll?.Invoke();
blueprint.Select(); blueprint.Select();
return true;
} }
private void deleteSelected() private void deleteSelected()