Skip to content

Commit 5afcc45

Browse files
committed
Chart editor - select above/below playhead
1 parent 9f9a692 commit 5afcc45

File tree

4 files changed

+357
-8
lines changed

4 files changed

+357
-8
lines changed

source/funkin/ui/debug/charting/ChartEditorState.hx

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import funkin.ui.debug.charting.commands.ChartEditorCommand;
5454
import funkin.ui.debug.charting.commands.CopyItemsCommand;
5555
import funkin.ui.debug.charting.commands.CutItemsCommand;
5656
import funkin.ui.debug.charting.commands.DeselectAllItemsCommand;
57+
import funkin.ui.debug.charting.commands.DeselectAllItemsBetweenTimeCommand;
5758
import funkin.ui.debug.charting.commands.DeselectItemsCommand;
5859
import funkin.ui.debug.charting.commands.ExtendNoteLengthCommand;
5960
import funkin.ui.debug.charting.commands.FlipNotesCommand;
@@ -67,6 +68,7 @@ import funkin.ui.debug.charting.commands.RemoveItemsCommand;
6768
import funkin.ui.debug.charting.commands.RemoveNotesCommand;
6869
import funkin.ui.debug.charting.commands.RemoveStackedNotesCommand;
6970
import funkin.ui.debug.charting.commands.SelectAllItemsCommand;
71+
import funkin.ui.debug.charting.commands.SelectAllItemsBetweenTimeCommand;
7072
import funkin.ui.debug.charting.commands.SelectItemsCommand;
7173
import funkin.ui.debug.charting.commands.SetItemSelectionCommand;
7274
import funkin.ui.debug.charting.components.ChartEditorEventSprite;
@@ -1879,14 +1881,14 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
18791881
var menubarItemSelectRegion:MenuItem;
18801882

18811883
/**
1882-
* The `Edit -> Select Before Cursor` menu item.
1884+
* The `Edit -> Select Before Playhead` menu item.
18831885
*/
1884-
var menubarItemSelectBeforeCursor:MenuItem;
1886+
var menubarItemSelectBeforePlayhead:MenuItem;
18851887

18861888
/**
1887-
* The `Edit -> Select After Cursor` menu item.
1889+
* The `Edit -> Select After Playhead` menu item.
18881890
*/
1889-
var menubarItemSelectAfterCursor:MenuItem;
1891+
var menubarItemSelectAfterPlayhead:MenuItem;
18901892

18911893
/**
18921894
* The `Edit -> Decrease Note Snap Precision` menu item.
@@ -3114,6 +3116,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
31143116

31153117
menubarItemSelectNone.onClick = _ -> performCommand(new DeselectAllItemsCommand());
31163118

3119+
menubarItemSelectBeforePlayhead.onClick = _ -> performCommand(new SelectAllItemsBetweenTimeCommand(scrollPositionInMs + playheadPositionInMs, true, true, true));
3120+
3121+
menubarItemSelectAfterPlayhead.onClick = _ -> performCommand(new SelectAllItemsBetweenTimeCommand(scrollPositionInMs + playheadPositionInMs, false, true, true));
3122+
31173123
menubarItemPlaytestFull.onClick = _ -> testSongInPlayState(false);
31183124
menubarItemPlaytestMinimal.onClick = _ -> testSongInPlayState(true);
31193125

@@ -4267,7 +4273,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
42674273
}
42684274

42694275
// HOME = Scroll to Top
4270-
if (FlxG.keys.justPressed.HOME)
4276+
if (!FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.HOME)
42714277
{
42724278
// Scroll amount is the difference between the current position and the top.
42734279
scrollAmount = 0 - this.scrollPositionInPixels;
@@ -4283,7 +4289,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
42834289
}
42844290

42854291
// END = Scroll to Bottom
4286-
if (FlxG.keys.justPressed.END)
4292+
if (!FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.END)
42874293
{
42884294
// Scroll amount is the difference between the current position and the bottom.
42894295
scrollAmount = this.songLengthInPixels - this.scrollPositionInPixels;
@@ -5921,6 +5927,26 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
59215927
// Deselect all items.
59225928
performCommand(new DeselectAllItemsCommand());
59235929
}
5930+
5931+
// SHIFT + Home = Select all above playhead
5932+
if (FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.HOME)
5933+
{
5934+
// CTRL + SHIFT + Home = Inverse - deselect all above playhead
5935+
if (FlxG.keys.pressed.CONTROL)
5936+
performCommand(new DeselectAllItemsBetweenTimeCommand(scrollPositionInMs + playheadPositionInMs, true, true, true));
5937+
else
5938+
performCommand(new SelectAllItemsBetweenTimeCommand(scrollPositionInMs + playheadPositionInMs, true, true, true));
5939+
}
5940+
5941+
// SHIFT + End = Select all below playhead
5942+
if (FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.END)
5943+
{
5944+
// CTRL + SHIFT + Home = Inverse - deselect all below playhead
5945+
if (FlxG.keys.pressed.CONTROL)
5946+
performCommand(new DeselectAllItemsBetweenTimeCommand(scrollPositionInMs + playheadPositionInMs, false, true, true));
5947+
else
5948+
performCommand(new SelectAllItemsBetweenTimeCommand(scrollPositionInMs + playheadPositionInMs, false, true, true));
5949+
}
59245950
}
59255951

59265952
/**
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package funkin.ui.debug.charting.commands;
2+
3+
import funkin.data.song.SongData.SongNoteData;
4+
import funkin.data.song.SongData.SongEventData;
5+
import funkin.data.song.SongDataUtils;
6+
7+
/**
8+
* Command that deselects all selected notes and/or events above or past the time given in the chart editor.
9+
*/
10+
@:nullSafety
11+
@:access(funkin.ui.debug.charting.ChartEditorState)
12+
class DeselectAllItemsBetweenTimeCommand implements ChartEditorCommand
13+
{
14+
var time:Float;
15+
var above:Bool;
16+
17+
var notes:Array<SongNoteData>;
18+
var events:Array<SongEventData>;
19+
20+
var shouldDeselectNotes:Bool;
21+
var shouldDeselectEvents:Bool;
22+
23+
public function new(time:Float, above:Bool, shouldDeselectNotes:Bool, shouldDeselectEvents:Bool)
24+
{
25+
this.time = time;
26+
this.above = above;
27+
28+
this.notes = [];
29+
this.events = [];
30+
31+
this.shouldDeselectNotes = shouldDeselectNotes;
32+
this.shouldDeselectEvents = shouldDeselectEvents;
33+
}
34+
35+
public function execute(state:ChartEditorState):Void
36+
{
37+
if (above)
38+
{
39+
if (shouldDeselectNotes)
40+
{
41+
for (i in 0...state.currentSongChartNoteData.length)
42+
{
43+
if (state.currentSongChartNoteData[i].time < time)
44+
notes.push(state.currentSongChartNoteData[i]);
45+
else
46+
// We've reached the end of the notes above this time,
47+
// there's no reason to waste our time running this loop to completion
48+
break;
49+
}
50+
}
51+
if (shouldDeselectEvents)
52+
{
53+
for (i in 0...state.currentSongChartEventData.length)
54+
{
55+
if (state.currentSongChartEventData[i].time < time)
56+
events.push(state.currentSongChartEventData[i]);
57+
else
58+
break;
59+
}
60+
}
61+
}
62+
else // Deselecting below the time given
63+
{
64+
if (shouldDeselectNotes)
65+
{
66+
for (i in 0...state.currentSongChartNoteData.length)
67+
{
68+
// Backwards for loop (kinda). Neat!
69+
if (state.currentSongChartNoteData[state.currentSongChartNoteData.length - i - 1].time > time)
70+
notes.push(state.currentSongChartNoteData[state.currentSongChartNoteData.length - i - 1]);
71+
else
72+
// We've reached the end of the notes below this time,
73+
// there's no reason to waste our time running this loop to completion
74+
break;
75+
}
76+
}
77+
if (shouldDeselectEvents)
78+
{
79+
for (i in 0...state.currentSongChartEventData.length)
80+
{
81+
if (state.currentSongChartEventData[state.currentSongChartEventData.length - i - 1].time > time)
82+
events.push(state.currentSongChartEventData[state.currentSongChartEventData.length- i - 1]);
83+
else
84+
break;
85+
}
86+
}
87+
}
88+
89+
state.currentNoteSelection = SongDataUtils.subtractNotes(state.currentNoteSelection, this.notes);
90+
state.currentEventSelection = SongDataUtils.subtractEvents(state.currentEventSelection, this.events);
91+
92+
state.noteDisplayDirty = true;
93+
state.notePreviewDirty = true;
94+
}
95+
96+
public function undo(state:ChartEditorState):Void
97+
{
98+
for (note in this.notes)
99+
{
100+
state.currentNoteSelection.push(note);
101+
}
102+
103+
for (event in this.events)
104+
{
105+
state.currentEventSelection.push(event);
106+
}
107+
108+
state.noteDisplayDirty = true;
109+
state.notePreviewDirty = true;
110+
}
111+
112+
public function shouldAddToHistory(state:ChartEditorState):Bool
113+
{
114+
// This command is undoable. Add to the history if we actually performed an action.
115+
return (notes.length > 0 || events.length > 0);
116+
}
117+
118+
public function toString():String
119+
{
120+
var isPlural = (notes.length + events.length) > 1;
121+
var notesOnly = (notes.length > 0 && events.length == 0);
122+
var eventsOnly = (notes.length == 0 && events.length > 0);
123+
124+
if (notesOnly)
125+
{
126+
return 'Deselect ${notes.length} ${isPlural ? 'Notes' : 'Note'}';
127+
}
128+
else if (eventsOnly)
129+
{
130+
return 'Deselect ${events.length} ${isPlural ? 'Events' : 'Event'}';
131+
}
132+
133+
return 'Deselect ${notes.length + events.length} Items';
134+
}
135+
}

0 commit comments

Comments
 (0)