-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathManiaSelectionHandler.cs
More file actions
141 lines (109 loc) · 5.55 KB
/
ManiaSelectionHandler.cs
File metadata and controls
141 lines (109 loc) · 5.55 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
140
141
// 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 System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Edit.Compose.Components;
namespace osu.Game.Rulesets.Mania.Edit
{
public partial class ManiaSelectionHandler : EditorSelectionHandler
{
[Resolved]
private HitObjectComposer composer { get; set; } = null!;
protected override void OnSelectionChanged()
{
base.OnSelectionChanged();
var selectedObjects = SelectedItems.OfType<ManiaHitObject>().ToArray();
SelectionBox.CanFlipX = canFlipX(selectedObjects);
SelectionBox.CanFlipY = canFlipY(selectedObjects);
}
public override bool HandleMovement(MoveSelectionEvent<HitObject> moveEvent)
{
var hitObjectBlueprint = (HitObjectSelectionBlueprint)moveEvent.Blueprint;
int lastColumn = ((ManiaHitObject)hitObjectBlueprint.Item).Column;
performColumnMovement(lastColumn, moveEvent);
return true;
}
public override bool HandleFlip(Direction direction, bool flipOverOrigin)
{
var selectedObjects = SelectedItems.OfType<ManiaHitObject>().ToArray();
var maniaPlayfield = ((ManiaHitObjectComposer)composer).Playfield;
if (selectedObjects.Length == 0)
return false;
switch (direction)
{
case Direction.Horizontal:
if (!canFlipX(selectedObjects))
return false;
int firstColumn = flipOverOrigin ? 0 : selectedObjects.Min(ho => ho.Column);
int lastColumn = flipOverOrigin ? (int)EditorBeatmap.BeatmapInfo.Difficulty.CircleSize - 1 : selectedObjects.Max(ho => ho.Column);
performOnSelection(maniaObject =>
{
maniaPlayfield.Remove(maniaObject);
maniaObject.Column = firstColumn + (lastColumn - maniaObject.Column);
maniaPlayfield.Add(maniaObject);
});
return true;
case Direction.Vertical:
if (!canFlipY(selectedObjects))
return false;
double selectionStartTime = selectedObjects.Min(ho => ho.StartTime);
double selectionEndTime = selectedObjects.Max(ho => ho.GetEndTime());
performOnSelection(hitObject =>
{
hitObject.StartTime = selectionStartTime + (selectionEndTime - hitObject.GetEndTime());
});
return true;
default:
throw new ArgumentOutOfRangeException(nameof(direction), direction, "Cannot flip over the supplied direction.");
}
}
private static bool canFlipX(ManiaHitObject[] selectedObjects)
=> selectedObjects.Select(ho => ho.Column).Distinct().Count() > 1;
private static bool canFlipY(ManiaHitObject[] selectedObjects)
=> selectedObjects.Length > 1 && selectedObjects.Min(ho => ho.StartTime) < selectedObjects.Max(ho => ho.GetEndTime());
private void performColumnMovement(int lastColumn, MoveSelectionEvent<HitObject> moveEvent)
{
var maniaPlayfield = ((ManiaHitObjectComposer)composer).Playfield;
var currentColumn = maniaPlayfield.GetClosestColumnByPosition((moveEvent.Blueprint.ScreenSpaceSelectionPoint + moveEvent.ScreenSpaceDelta).X);
if (currentColumn == null)
return;
int columnDelta = currentColumn.Index - lastColumn;
if (columnDelta == 0)
return;
int minColumn = int.MaxValue;
int maxColumn = int.MinValue;
var selectedObjects = EditorBeatmap.SelectedHitObjects.OfType<ManiaHitObject>().ToArray();
// find min/max in an initial pass before actually performing the movement.
foreach (var obj in selectedObjects)
{
if (obj.Column < minColumn)
minColumn = obj.Column;
if (obj.Column > maxColumn)
maxColumn = obj.Column;
}
columnDelta = Math.Clamp(columnDelta, -minColumn, maniaPlayfield.TotalColumns - 1 - maxColumn);
performOnSelection(h =>
{
maniaPlayfield.Remove(h);
h.Column += columnDelta;
maniaPlayfield.Add(h);
});
}
private void performOnSelection(Action<ManiaHitObject> action)
{
var selectedObjects = EditorBeatmap.SelectedHitObjects.OfType<ManiaHitObject>().ToArray();
EditorBeatmap.PerformOnSelection(h => action.Invoke((ManiaHitObject)h));
// `HitObjectUsageEventBuffer`'s usage transferal flows and the playfield's `SetKeepAlive()` functionality do not combine well with mania's usage patterns,
// leading to selections being sometimes partially dropped if some of the objects being moved are off screen
// (check blame for detailed explanation).
// thus, ensure that selection is preserved manually.
EditorBeatmap.SelectedHitObjects.Clear();
EditorBeatmap.SelectedHitObjects.AddRange(selectedObjects);
}
}
}