1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 11:28:00 +08:00

Merge branch 'master' into efficient-user-retrieval

This commit is contained in:
Dean Herbert 2020-11-07 00:07:29 +09:00 committed by GitHub
commit f94ac1cbc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 155 additions and 54 deletions

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
using Humanizer; using Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -18,6 +19,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit;
using osuTK.Input; using osuTK.Input;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
@ -105,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
switch (action.ActionMethod) switch (action.ActionMethod)
{ {
case PlatformActionMethod.Delete: case PlatformActionMethod.Delete:
return deleteSelected(); return DeleteSelected();
} }
return false; return false;
@ -126,7 +128,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
} }
} }
private bool deleteSelected() [Resolved(CanBeNull = true)]
private IEditorChangeHandler changeHandler { get; set; }
public bool DeleteSelected()
{ {
List<PathControlPoint> toRemove = Pieces.Where(p => p.IsSelected.Value).Select(p => p.ControlPoint).ToList(); List<PathControlPoint> toRemove = Pieces.Where(p => p.IsSelected.Value).Select(p => p.ControlPoint).ToList();
@ -134,7 +139,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
if (toRemove.Count == 0) if (toRemove.Count == 0)
return false; return false;
changeHandler?.BeginChange();
RemoveControlPointsRequested?.Invoke(toRemove); RemoveControlPointsRequested?.Invoke(toRemove);
changeHandler?.EndChange();
// Since pieces are re-used, they will not point to the deleted control points while remaining selected // Since pieces are re-used, they will not point to the deleted control points while remaining selected
foreach (var piece in Pieces) foreach (var piece in Pieces)
@ -169,7 +176,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
return new MenuItem[] return new MenuItem[]
{ {
new OsuMenuItem($"Delete {"control point".ToQuantity(count, count > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", MenuItemType.Destructive, () => deleteSelected()), new OsuMenuItem($"Delete {"control point".ToQuantity(count, count > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", MenuItemType.Destructive, () => DeleteSelected()),
new OsuMenuItem("Curve type") new OsuMenuItem("Curve type")
{ {
Items = items Items = items

View File

@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -72,6 +73,18 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
BodyPiece.UpdateFrom(HitObject); BodyPiece.UpdateFrom(HitObject);
} }
public override bool HandleQuickDeletion()
{
var hoveredControlPoint = ControlPointVisualiser.Pieces.FirstOrDefault(p => p.IsHovered);
if (hoveredControlPoint == null)
return false;
hoveredControlPoint.IsSelected.Value = true;
ControlPointVisualiser.DeleteSelected();
return true;
}
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
@ -109,9 +122,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
rightClickPosition = e.MouseDownPosition; rightClickPosition = e.MouseDownPosition;
return false; // Allow right click to be handled by context menu return false; // Allow right click to be handled by context menu
case MouseButton.Left when e.ControlPressed && IsSelected: case MouseButton.Left:
placementControlPointIndex = addControlPoint(e.MousePosition); if (e.ControlPressed && IsSelected)
return true; // Stop input from being handled and modifying the selection {
placementControlPointIndex = addControlPoint(e.MousePosition);
return true; // Stop input from being handled and modifying the selection
}
break;
} }
return false; return false;
@ -216,7 +234,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
public override Vector2 ScreenSpaceSelectionPoint => BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation); public override Vector2 ScreenSpaceSelectionPoint => BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation);
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BodyPiece.ReceivePositionalInputAt(screenSpacePos); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
BodyPiece.ReceivePositionalInputAt(screenSpacePos) || ControlPointVisualiser?.Pieces.Any(p => p.ReceivePositionalInputAt(screenSpacePos)) == true;
protected virtual SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new SliderCircleSelectionBlueprint(slider, position); protected virtual SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new SliderCircleSelectionBlueprint(slider, position);
} }

View File

@ -42,8 +42,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
private readonly IBindable<Color4> accentColour = new Bindable<Color4>(); private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>(); private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>();
[Resolved]
private DrawableHitObject drawableObject { get; set; }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(DrawableHitObject drawableObject) private void load()
{ {
var drawableOsuObject = (DrawableOsuHitObject)drawableObject; var drawableOsuObject = (DrawableOsuHitObject)drawableObject;
@ -64,32 +67,35 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
private void updateState(ValueChangedEvent<ArmedState> state) private void updateState(ValueChangedEvent<ArmedState> state)
{ {
glow.FadeOut(400); using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime, true))
switch (state.NewValue)
{ {
case ArmedState.Hit: glow.FadeOut(400);
const double flash_in = 40;
const double flash_out = 100;
flash.FadeTo(0.8f, flash_in) switch (state.NewValue)
.Then() {
.FadeOut(flash_out); case ArmedState.Hit:
const double flash_in = 40;
const double flash_out = 100;
explode.FadeIn(flash_in); flash.FadeTo(0.8f, flash_in)
this.ScaleTo(1.5f, 400, Easing.OutQuad); .Then()
.FadeOut(flash_out);
using (BeginDelayedSequence(flash_in, true)) explode.FadeIn(flash_in);
{ this.ScaleTo(1.5f, 400, Easing.OutQuad);
// after the flash, we can hide some elements that were behind it
ring.FadeOut();
circle.FadeOut();
number.FadeOut();
this.FadeOut(800); using (BeginDelayedSequence(flash_in, true))
} {
// after the flash, we can hide some elements that were behind it
ring.FadeOut();
circle.FadeOut();
number.FadeOut();
break; this.FadeOut(800);
}
break;
}
} }
} }
} }

View File

@ -42,11 +42,14 @@ namespace osu.Game.Rulesets.Osu.Skinning
private readonly Bindable<Color4> accentColour = new Bindable<Color4>(); private readonly Bindable<Color4> accentColour = new Bindable<Color4>();
private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>(); private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>();
[Resolved]
private DrawableHitObject drawableObject { get; set; }
[Resolved] [Resolved]
private ISkinSource skin { get; set; } private ISkinSource skin { get; set; }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(DrawableHitObject drawableObject) private void load()
{ {
var drawableOsuObject = (DrawableOsuHitObject)drawableObject; var drawableOsuObject = (DrawableOsuHitObject)drawableObject;
@ -144,28 +147,31 @@ namespace osu.Game.Rulesets.Osu.Skinning
{ {
const double legacy_fade_duration = 240; const double legacy_fade_duration = 240;
switch (state.NewValue) using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime, true))
{ {
case ArmedState.Hit: switch (state.NewValue)
circleSprites.FadeOut(legacy_fade_duration, Easing.Out); {
circleSprites.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); case ArmedState.Hit:
circleSprites.FadeOut(legacy_fade_duration, Easing.Out);
circleSprites.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
if (hasNumber) if (hasNumber)
{
var legacyVersion = skin.GetConfig<LegacySetting, decimal>(LegacySetting.Version)?.Value;
if (legacyVersion >= 2.0m)
// legacy skins of version 2.0 and newer only apply very short fade out to the number piece.
hitCircleText.FadeOut(legacy_fade_duration / 4, Easing.Out);
else
{ {
// old skins scale and fade it normally along other pieces. var legacyVersion = skin.GetConfig<LegacySetting, decimal>(LegacySetting.Version)?.Value;
hitCircleText.FadeOut(legacy_fade_duration, Easing.Out);
hitCircleText.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
}
}
break; if (legacyVersion >= 2.0m)
// legacy skins of version 2.0 and newer only apply very short fade out to the number piece.
hitCircleText.FadeOut(legacy_fade_duration / 4, Easing.Out);
else
{
// old skins scale and fade it normally along other pieces.
hitCircleText.FadeOut(legacy_fade_duration, Easing.Out);
hitCircleText.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
}
}
break;
}
} }
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
@ -20,6 +21,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
protected DrawableSpinner DrawableSpinner { get; private set; } protected DrawableSpinner DrawableSpinner { get; private set; }
private Sprite spin; private Sprite spin;
private Sprite clear;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(DrawableHitObject drawableHitObject, ISkinSource source) private void load(DrawableHitObject drawableHitObject, ISkinSource source)
@ -39,17 +41,58 @@ namespace osu.Game.Rulesets.Osu.Skinning
Scale = new Vector2(SPRITE_SCALE), Scale = new Vector2(SPRITE_SCALE),
Y = 120 - 45 // offset temporarily to avoid overlapping default spin counter Y = 120 - 45 // offset temporarily to avoid overlapping default spin counter
}, },
clear = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Depth = float.MinValue,
Alpha = 0,
Texture = source.GetTexture("spinner-clear"),
Scale = new Vector2(SPRITE_SCALE),
Y = -60
},
}); });
} }
private readonly Bindable<bool> completed = new Bindable<bool>();
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
completed.BindTo(DrawableSpinner.RotationTracker.Complete);
completed.BindValueChanged(onCompletedChanged, true);
DrawableSpinner.ApplyCustomUpdateState += UpdateStateTransforms; DrawableSpinner.ApplyCustomUpdateState += UpdateStateTransforms;
UpdateStateTransforms(DrawableSpinner, DrawableSpinner.State.Value); UpdateStateTransforms(DrawableSpinner, DrawableSpinner.State.Value);
} }
private void onCompletedChanged(ValueChangedEvent<bool> completed)
{
if (completed.NewValue)
{
double startTime = Math.Min(Time.Current, DrawableSpinner.HitStateUpdateTime - 400);
using (BeginAbsoluteSequence(startTime, true))
{
clear.FadeInFromZero(400, Easing.Out);
clear.ScaleTo(SPRITE_SCALE * 2)
.Then().ScaleTo(SPRITE_SCALE * 0.8f, 240, Easing.Out)
.Then().ScaleTo(SPRITE_SCALE, 160);
}
const double fade_out_duration = 50;
using (BeginAbsoluteSequence(DrawableSpinner.HitStateUpdateTime - fade_out_duration, true))
clear.FadeOut(fade_out_duration);
}
else
{
clear.ClearTransforms();
clear.Alpha = 0;
}
}
protected virtual void UpdateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) protected virtual void UpdateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
{ {
switch (drawableHitObject) switch (drawableHitObject)
@ -59,7 +102,6 @@ namespace osu.Game.Rulesets.Osu.Skinning
using (BeginAbsoluteSequence(drawableHitObject.HitStateUpdateTime - fadeOutLength, true)) using (BeginAbsoluteSequence(drawableHitObject.HitStateUpdateTime - fadeOutLength, true))
spin.FadeOutFromOne(fadeOutLength); spin.FadeOutFromOne(fadeOutLength);
break; break;
case DrawableSpinnerTick d: case DrawableSpinnerTick d:

View File

@ -308,7 +308,6 @@ namespace osu.Game.Overlays
if (disabled) if (disabled)
playlist.Hide(); playlist.Hide();
playButton.Enabled.Value = !disabled;
prevButton.Enabled.Value = !disabled; prevButton.Enabled.Value = !disabled;
nextButton.Enabled.Value = !disabled; nextButton.Enabled.Value = !disabled;
playlistButton.Enabled.Value = !disabled; playlistButton.Enabled.Value = !disabled;

View File

@ -143,5 +143,11 @@ namespace osu.Game.Rulesets.Edit
public virtual Quad SelectionQuad => ScreenSpaceDrawQuad; public virtual Quad SelectionQuad => ScreenSpaceDrawQuad;
public virtual Vector2 GetInstantDelta(Vector2 screenSpacePosition) => Parent.ToLocalSpace(screenSpacePosition) - Position; public virtual Vector2 GetInstantDelta(Vector2 screenSpacePosition) => Parent.ToLocalSpace(screenSpacePosition) - Position;
/// <summary>
/// Handle to perform a partial deletion when the user requests a quick delete (Shift+Right Click).
/// </summary>
/// <returns>True if the deletion operation was handled by this blueprint. Returning false will delete the full blueprint.</returns>
public virtual bool HandleQuickDeletion() => false;
} }
} }

View File

@ -116,7 +116,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
protected override bool OnMouseDown(MouseDownEvent e) protected override bool OnMouseDown(MouseDownEvent e)
{ {
beginClickSelection(e); if (!beginClickSelection(e)) return true;
prepareSelectionMovement(); prepareSelectionMovement();
return e.Button == MouseButton.Left; return e.Button == MouseButton.Left;
@ -291,19 +292,24 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// Attempts to select any hovered blueprints. /// Attempts to select any hovered blueprints.
/// </summary> /// </summary>
/// <param name="e">The input event that triggered this selection.</param> /// <param name="e">The input event that triggered this selection.</param>
private void beginClickSelection(MouseButtonEvent e) /// <returns>Whether a selection was performed.</returns>
private bool beginClickSelection(MouseButtonEvent e)
{ {
Debug.Assert(!clickSelectionBegan); Debug.Assert(!clickSelectionBegan);
bool selectedPerformed = true;
foreach (SelectionBlueprint blueprint in SelectionBlueprints.AliveChildren) foreach (SelectionBlueprint blueprint in SelectionBlueprints.AliveChildren)
{ {
if (blueprint.IsHovered) if (blueprint.IsHovered)
{ {
SelectionHandler.HandleSelectionRequested(blueprint, e.CurrentState); selectedPerformed &= SelectionHandler.HandleSelectionRequested(blueprint, e.CurrentState);
clickSelectionBegan = true; clickSelectionBegan = true;
break; break;
} }
} }
return selectedPerformed;
} }
/// <summary> /// <summary>

View File

@ -219,18 +219,28 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// </summary> /// </summary>
/// <param name="blueprint">The blueprint.</param> /// <param name="blueprint">The blueprint.</param>
/// <param name="state">The input state at the point of selection.</param> /// <param name="state">The input state at the point of selection.</param>
internal void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) /// <returns>Whether a selection was performed.</returns>
internal bool HandleSelectionRequested(SelectionBlueprint blueprint, InputState state)
{ {
if (state.Keyboard.ShiftPressed && state.Mouse.IsPressed(MouseButton.Right)) if (state.Keyboard.ShiftPressed && state.Mouse.IsPressed(MouseButton.Right))
{
handleQuickDeletion(blueprint); handleQuickDeletion(blueprint);
else if (state.Keyboard.ControlPressed && state.Mouse.IsPressed(MouseButton.Left)) return false;
}
if (state.Keyboard.ControlPressed && state.Mouse.IsPressed(MouseButton.Left))
blueprint.ToggleSelection(); blueprint.ToggleSelection();
else else
ensureSelected(blueprint); ensureSelected(blueprint);
return true;
} }
private void handleQuickDeletion(SelectionBlueprint blueprint) private void handleQuickDeletion(SelectionBlueprint blueprint)
{ {
if (blueprint.HandleQuickDeletion())
return;
if (!blueprint.IsSelected) if (!blueprint.IsSelected)
EditorBeatmap.Remove(blueprint.HitObject); EditorBeatmap.Remove(blueprint.HitObject);
else else