mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-30 11:26:53 -05:00
Merge pull request #167 from FunkinCrew/rewrite/feature/snapped-paste
Chart Editor: Snapped Paste and Event Visiblity
This commit is contained in:
commit
965363c062
4 changed files with 90 additions and 20 deletions
2
assets
2
assets
|
@ -1 +1 @@
|
|||
Subproject commit f2e37de1ff308eeaf65babad2a4089096c40cedb
|
||||
Subproject commit 8104d43e584a1f25e574438d7b21a7e671358969
|
|
@ -21,11 +21,21 @@ class SongDataUtils
|
|||
* @param notes The notes to modify.
|
||||
* @param offset The time difference to apply in milliseconds.
|
||||
*/
|
||||
public static function offsetSongNoteData(notes:Array<SongNoteData>, offset:Int):Array<SongNoteData>
|
||||
public static function offsetSongNoteData(notes:Array<SongNoteData>, offset:Float):Array<SongNoteData>
|
||||
{
|
||||
return notes.map(function(note:SongNoteData):SongNoteData {
|
||||
return new SongNoteData(note.time + offset, note.data, note.length, note.kind);
|
||||
});
|
||||
var offsetNote = function(note:SongNoteData):SongNoteData {
|
||||
var time:Float = note.time + offset;
|
||||
var data:Int = note.data;
|
||||
var length:Float = note.length;
|
||||
var kind:String = note.kind;
|
||||
return new SongNoteData(time, data, length, kind);
|
||||
};
|
||||
|
||||
trace(notes);
|
||||
trace(notes[0]);
|
||||
var result = [for (i in 0...notes.length) offsetNote(notes[i])];
|
||||
trace(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,7 +46,7 @@ class SongDataUtils
|
|||
* @param events The events to modify.
|
||||
* @param offset The time difference to apply in milliseconds.
|
||||
*/
|
||||
public static function offsetSongEventData(events:Array<SongEventData>, offset:Int):Array<SongEventData>
|
||||
public static function offsetSongEventData(events:Array<SongEventData>, offset:Float):Array<SongEventData>
|
||||
{
|
||||
return events.map(function(event:SongEventData):SongEventData {
|
||||
return new SongEventData(event.time + offset, event.event, event.value);
|
||||
|
@ -152,7 +162,8 @@ class SongDataUtils
|
|||
*/
|
||||
public static function writeItemsToClipboard(data:SongClipboardItems):Void
|
||||
{
|
||||
var dataString = SerializerUtil.toJSON(data);
|
||||
var writer = new json2object.JsonWriter<SongClipboardItems>();
|
||||
var dataString:String = writer.write(data, ' ');
|
||||
|
||||
ClipboardUtil.setClipboard(dataString);
|
||||
|
||||
|
@ -170,19 +181,24 @@ class SongDataUtils
|
|||
|
||||
trace('Read ${notesString.length} characters from clipboard.');
|
||||
|
||||
var data:SongClipboardItems = notesString.parseJSON();
|
||||
|
||||
if (data == null)
|
||||
var parser = new json2object.JsonParser<SongClipboardItems>();
|
||||
parser.fromJson(notesString, 'clipboard');
|
||||
if (parser.errors.length > 0)
|
||||
{
|
||||
trace('Failed to parse notes from clipboard.');
|
||||
trace('[SongDataUtils] Error parsing note JSON data from clipboard.');
|
||||
for (error in parser.errors)
|
||||
DataError.printError(error);
|
||||
return {
|
||||
valid: false,
|
||||
notes: [],
|
||||
events: []
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var data:SongClipboardItems = parser.value;
|
||||
trace('Parsed ' + data.notes.length + ' notes and ' + data.events.length + ' from clipboard.');
|
||||
data.valid = true;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@ -230,6 +246,7 @@ class SongDataUtils
|
|||
|
||||
typedef SongClipboardItems =
|
||||
{
|
||||
?valid:Bool,
|
||||
notes:Array<SongNoteData>,
|
||||
events:Array<SongEventData>
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package funkin.ui.debug.charting;
|
||||
|
||||
import haxe.ui.notifications.NotificationType;
|
||||
import haxe.ui.notifications.NotificationManager;
|
||||
import funkin.data.song.SongData.SongEventData;
|
||||
import funkin.data.song.SongData.SongNoteData;
|
||||
import funkin.data.song.SongDataUtils;
|
||||
|
@ -760,6 +762,22 @@ class PasteItemsCommand implements ChartEditorCommand
|
|||
{
|
||||
var currentClipboard:SongClipboardItems = SongDataUtils.readItemsFromClipboard();
|
||||
|
||||
if (currentClipboard.valid != true)
|
||||
{
|
||||
#if !mac
|
||||
NotificationManager.instance.addNotification(
|
||||
{
|
||||
title: 'Failed to Paste',
|
||||
body: 'Could not parse clipboard contents.',
|
||||
type: NotificationType.Error,
|
||||
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||
});
|
||||
#end
|
||||
return;
|
||||
}
|
||||
|
||||
trace(currentClipboard.notes);
|
||||
|
||||
addedNotes = SongDataUtils.offsetSongNoteData(currentClipboard.notes, Std.int(targetTimestamp));
|
||||
addedEvents = SongDataUtils.offsetSongEventData(currentClipboard.events, Std.int(targetTimestamp));
|
||||
|
||||
|
@ -773,6 +791,16 @@ class PasteItemsCommand implements ChartEditorCommand
|
|||
state.notePreviewDirty = true;
|
||||
|
||||
state.sortChartData();
|
||||
|
||||
#if !mac
|
||||
NotificationManager.instance.addNotification(
|
||||
{
|
||||
title: 'Paste Successful',
|
||||
body: 'Successfully pasted clipboard contents.',
|
||||
type: NotificationType.Success,
|
||||
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||
});
|
||||
#end
|
||||
}
|
||||
|
||||
public function undo(state:ChartEditorState):Void
|
||||
|
|
|
@ -1547,11 +1547,11 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
renderedEvents.setPosition(gridTiledSprite.x, gridTiledSprite.y);
|
||||
add(renderedEvents);
|
||||
renderedNotes.zIndex = 25;
|
||||
renderedEvents.zIndex = 25;
|
||||
|
||||
renderedSelectionSquares.setPosition(gridTiledSprite.x, gridTiledSprite.y);
|
||||
add(renderedSelectionSquares);
|
||||
renderedNotes.zIndex = 26;
|
||||
renderedSelectionSquares.zIndex = 26;
|
||||
}
|
||||
|
||||
function buildAdditionalUI():Void
|
||||
|
@ -1662,7 +1662,18 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
addUIClickListener('menubarItemCut', _ -> performCommand(new CutItemsCommand(currentNoteSelection, currentEventSelection)));
|
||||
|
||||
addUIClickListener('menubarItemPaste', _ -> performCommand(new PasteItemsCommand(scrollPositionInMs + playheadPositionInMs)));
|
||||
addUIClickListener('menubarItemPaste', _ -> {
|
||||
var targetMs:Float = scrollPositionInMs + playheadPositionInMs;
|
||||
var targetStep:Float = Conductor.getTimeInSteps(targetMs);
|
||||
var targetSnappedStep:Float = Math.floor(targetStep / noteSnapRatio) * noteSnapRatio;
|
||||
var targetSnappedMs:Float = Conductor.getStepTimeInMs(targetSnappedStep);
|
||||
performCommand(new PasteItemsCommand(targetSnappedMs));
|
||||
});
|
||||
|
||||
addUIClickListener('menubarItemPasteUnsnapped', _ -> {
|
||||
var targetMs:Float = scrollPositionInMs + playheadPositionInMs;
|
||||
performCommand(new PasteItemsCommand(targetMs));
|
||||
});
|
||||
|
||||
addUIClickListener('menubarItemDelete', function(_) {
|
||||
if (currentNoteSelection.length > 0 && currentEventSelection.length > 0)
|
||||
|
@ -2335,7 +2346,6 @@ class ChartEditorState extends HaxeUIState
|
|||
// Scroll up.
|
||||
var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.screenY;
|
||||
scrollPositionInPixels -= diff * 0.5; // Too fast!
|
||||
trace('Scroll up: ' + diff);
|
||||
moveSongToScrollPosition();
|
||||
}
|
||||
else if (FlxG.mouse.screenY > (playbarHeadLayout?.y ?? 0.0))
|
||||
|
@ -2343,7 +2353,6 @@ class ChartEditorState extends HaxeUIState
|
|||
// Scroll down.
|
||||
var diff:Float = FlxG.mouse.screenY - (playbarHeadLayout?.y ?? 0.0);
|
||||
scrollPositionInPixels += diff * 0.5; // Too fast!
|
||||
trace('Scroll down: ' + diff);
|
||||
moveSongToScrollPosition();
|
||||
}
|
||||
|
||||
|
@ -2968,8 +2977,8 @@ class ChartEditorState extends HaxeUIState
|
|||
// Set the position and size (because we might be recycling one with bad values).
|
||||
selectionSquare.x = noteSprite.x;
|
||||
selectionSquare.y = noteSprite.y;
|
||||
selectionSquare.width = noteSprite.width;
|
||||
selectionSquare.height = noteSprite.height;
|
||||
selectionSquare.width = GRID_SIZE;
|
||||
selectionSquare.height = GRID_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3000,6 +3009,8 @@ class ChartEditorState extends HaxeUIState
|
|||
FlxG.watch.addQuick("tapNotesRendered", renderedNotes.members.length);
|
||||
FlxG.watch.addQuick("holdNotesRendered", renderedHoldNotes.members.length);
|
||||
FlxG.watch.addQuick("eventsRendered", renderedEvents.members.length);
|
||||
FlxG.watch.addQuick("notesSelected", currentNoteSelection.length);
|
||||
FlxG.watch.addQuick("eventsSelected", currentEventSelection.length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3029,6 +3040,8 @@ class ChartEditorState extends HaxeUIState
|
|||
if (selectionSquareBitmap == null)
|
||||
throw "ERROR: Tried to build selection square, but selectionSquareBitmap is null! Check ChartEditorThemeHandler.updateSelectionSquare()";
|
||||
|
||||
FlxG.bitmapLog.add(selectionSquareBitmap, "selectionSquareBitmap");
|
||||
|
||||
return new FlxSprite().loadGraphic(selectionSquareBitmap);
|
||||
}
|
||||
|
||||
|
@ -3148,8 +3161,20 @@ class ChartEditorState extends HaxeUIState
|
|||
// CTRL + V = Paste
|
||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.V)
|
||||
{
|
||||
// Paste notes from clipboard, at the playhead.
|
||||
performCommand(new PasteItemsCommand(scrollPositionInMs + playheadPositionInMs));
|
||||
// CTRL + SHIFT + V = Paste Unsnapped.
|
||||
var targetMs:Float = if (FlxG.keys.pressed.SHIFT)
|
||||
{
|
||||
scrollPositionInMs + playheadPositionInMs;
|
||||
}
|
||||
else
|
||||
{
|
||||
var targetMs:Float = scrollPositionInMs + playheadPositionInMs;
|
||||
var targetStep:Float = Conductor.getTimeInSteps(targetMs);
|
||||
var targetSnappedStep:Float = Math.floor(targetStep / noteSnapRatio) * noteSnapRatio;
|
||||
var targetSnappedMs:Float = Conductor.getStepTimeInMs(targetSnappedStep);
|
||||
targetSnappedMs;
|
||||
}
|
||||
performCommand(new PasteItemsCommand(targetMs));
|
||||
}
|
||||
|
||||
// DELETE = Delete
|
||||
|
|
Loading…
Reference in a new issue