diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs
index c97adde427..804a4fcba0 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs
@@ -37,6 +37,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
isPlacingEnd = true;
piece.FadeTo(1f, 150, Easing.OutQuint);
+
+ BeginPlacement();
}
return true;
diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
index 398680cb8d..a94d1e9039 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
@@ -84,5 +84,7 @@ namespace osu.Game.Rulesets.Osu.UI
judgementLayer.Add(explosion);
}
+
+ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObjectContainer.ReceivePositionalInputAt(screenSpacePos);
}
}
diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs
index 932cfe5789..86ecbc0bb0 100644
--- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs
+++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs
@@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Input;
using osu.Framework.Logging;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
@@ -37,6 +38,8 @@ namespace osu.Game.Rulesets.Edit
private BlueprintContainer blueprintContainer;
+ private InputManager inputManager;
+
internal HitObjectComposer(Ruleset ruleset)
{
Ruleset = ruleset;
@@ -114,6 +117,13 @@ namespace osu.Game.Rulesets.Edit
toolboxCollection.Items[0].Select();
}
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ inputManager = GetContainingInputManager();
+ }
+
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
@@ -137,6 +147,11 @@ namespace osu.Game.Rulesets.Edit
});
}
+ ///
+ /// Whether the user's cursor is currently in an area of the that is valid for placement.
+ ///
+ public virtual bool CursorInPlacementArea => rulesetContainer.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position);
+
///
/// Adds a to the and visualises it.
///
diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs
index b726b683ea..45dc7e4a05 100644
--- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs
+++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs
@@ -1,6 +1,8 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
+using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
@@ -18,8 +20,18 @@ namespace osu.Game.Rulesets.Edit
///
/// A blueprint which governs the creation of a new to actualisation.
///
- public abstract class PlacementBlueprint : CompositeDrawable, IRequireHighFrequencyMousePosition
+ public abstract class PlacementBlueprint : CompositeDrawable, IStateful, IRequireHighFrequencyMousePosition
{
+ ///
+ /// Invoked when has changed.
+ ///
+ public event Action StateChanged;
+
+ ///
+ /// Whether the is currently being placed, but has not necessarily finished being placed.
+ ///
+ public bool PlacementBegun { get; private set; }
+
///
/// The that is being placed.
///
@@ -37,6 +49,8 @@ namespace osu.Game.Rulesets.Edit
HitObject = hitObject;
RelativeSizeAxes = Axes.Both;
+
+ Alpha = 0;
}
[BackgroundDependencyLoader]
@@ -49,7 +63,25 @@ namespace osu.Game.Rulesets.Edit
ApplyDefaultsToHitObject();
}
- private bool placementBegun;
+ private PlacementState state;
+
+ public PlacementState State
+ {
+ get => state;
+ set
+ {
+ if (state == value)
+ return;
+ state = value;
+
+ if (state == PlacementState.Shown)
+ Show();
+ else
+ Hide();
+
+ StateChanged?.Invoke(value);
+ }
+ }
///
/// Signals that the placement of has started.
@@ -57,7 +89,7 @@ namespace osu.Game.Rulesets.Edit
protected void BeginPlacement()
{
placementHandler.BeginPlacement(HitObject);
- placementBegun = true;
+ PlacementBegun = true;
}
///
@@ -66,7 +98,7 @@ namespace osu.Game.Rulesets.Edit
///
protected void EndPlacement()
{
- if (!placementBegun)
+ if (!PlacementBegun)
BeginPlacement();
placementHandler.EndPlacement(HitObject);
}
@@ -93,4 +125,10 @@ namespace osu.Game.Rulesets.Edit
}
}
}
+
+ public enum PlacementState
+ {
+ Hidden,
+ Shown,
+ }
}
diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
index acbfd1f1d6..1623ef0100 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
@@ -18,7 +18,10 @@ namespace osu.Game.Screens.Edit.Compose.Components
public class BlueprintContainer : CompositeDrawable
{
private SelectionBlueprintContainer selectionBlueprints;
+
private Container placementBlueprintContainer;
+ private PlacementBlueprint currentPlacement;
+
private SelectionBox selectionBox;
private IEnumerable selections => selectionBlueprints.Children.Where(c => c.IsAlive);
@@ -117,19 +120,32 @@ namespace osu.Game.Screens.Edit.Compose.Components
return true;
}
+ protected override void Update()
+ {
+ base.Update();
+
+ if (currentPlacement != null)
+ {
+ if (composer.CursorInPlacementArea)
+ currentPlacement.State = PlacementState.Shown;
+ else if (currentPlacement?.PlacementBegun == false)
+ currentPlacement.State = PlacementState.Hidden;
+ }
+ }
+
///
/// Refreshes the current placement tool.
///
private void refreshTool()
{
placementBlueprintContainer.Clear();
+ currentPlacement = null;
var blueprint = CurrentTool?.CreatePlacementBlueprint();
if (blueprint != null)
- placementBlueprintContainer.Child = blueprint;
+ placementBlueprintContainer.Child = currentPlacement = blueprint;
}
-
///
/// Select all masks in a given rectangle selection area.
///