-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathPlacementBlueprint.cs
More file actions
139 lines (115 loc) · 4.9 KB
/
PlacementBlueprint.cs
File metadata and controls
139 lines (115 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Objects;
using osuTK;
using osuTK.Input;
namespace osu.Game.Rulesets.Edit
{
/// <summary>
/// A blueprint which governs the placement of something.
/// </summary>
public abstract partial class PlacementBlueprint : VisibilityContainer, IKeyBindingHandler<GlobalAction>
{
/// <summary>
/// Whether the <see cref="HitObject"/> is currently mid-placement, but has not necessarily finished being placed.
/// </summary>
public PlacementState PlacementActive { get; private set; }
/// <summary>
/// Whether this blueprint is currently in a state that can be committed.
/// </summary>
/// <remarks>
/// Override this with any preconditions that should be double-checked on committing.
/// If <c>false</c> is returned and a commit is attempted, the blueprint will be destroyed instead.
/// </remarks>
protected virtual bool IsValidForPlacement => PlacementActive != PlacementState.Waiting || hitObjectComposer.CursorInPlacementArea;
// the blueprint should still be considered for input even if it is hidden,
// especially when such input is the reason for making the blueprint become visible.
public override bool PropagatePositionalInputSubTree => true;
public override bool PropagateNonPositionalInputSubTree => true;
[Resolved]
private HitObjectComposer hitObjectComposer { get; set; } = null!;
protected PlacementBlueprint()
{
RelativeSizeAxes = Axes.Both;
// the blueprint should still be considered for input even if it is hidden,
// especially when such input is the reason for making the blueprint become visible.
AlwaysPresent = true;
}
/// <summary>
/// Signals that the placement has started.
/// </summary>
/// <param name="commitStart">Whether this call is committing a value and continuing with further adjustments.</param>
protected virtual void BeginPlacement(bool commitStart = false)
{
if (commitStart)
PlacementActive = PlacementState.Active;
}
/// <summary>
/// Signals that the placement of <see cref="HitObject"/> has finished.
/// This will destroy this <see cref="PlacementBlueprint"/>, and commit the changes.
/// </summary>
/// <param name="commit">Whether the changes should be committed. Note that a commit may fail if <see cref="IsValidForPlacement"/> is <c>false</c>.</param>
public virtual void EndPlacement(bool commit)
{
switch (PlacementActive)
{
case PlacementState.Finished:
return;
case PlacementState.Waiting:
// ensure placement was started before ending to make state handling simpler.
if (!IsValidForPlacement)
return;
BeginPlacement();
break;
}
PlacementActive = PlacementState.Finished;
}
public abstract SnapResult UpdateTimeAndPosition(Vector2 screenSpacePosition, double fallbackTime);
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
{
if (PlacementActive == PlacementState.Waiting)
return false;
switch (e.Action)
{
case GlobalAction.Back:
EndPlacement(false);
return true;
default:
return false;
}
}
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
{
}
protected override bool Handle(UIEvent e)
{
base.Handle(e);
switch (e)
{
case ScrollEvent:
return false;
case DoubleClickEvent:
return false;
case MouseButtonEvent mouse:
// placement blueprints should generally block mouse from reaching underlying components (ie. performing clicks on interface buttons).
return mouse.Button == MouseButton.Left || PlacementActive == PlacementState.Active;
default:
return false;
}
}
protected override void PopIn() => this.FadeIn();
protected override void PopOut() => this.FadeOut();
public enum PlacementState
{
Waiting,
Active,
Finished
}
}
}