Merge remote-tracking branch 'origin/feature/chart-editor-snap' into HEAD

This commit is contained in:
EliteMasterEric 2023-09-08 18:20:52 -04:00
commit f46c8821c8
3 changed files with 78 additions and 9 deletions

View file

@ -306,6 +306,7 @@ class ChartEditorDialogHandler
if (state.loadInstrumentalFromBytes(selectedFile.bytes)) if (state.loadInstrumentalFromBytes(selectedFile.bytes))
{ {
trace('Selected file: ' + selectedFile.fullPath); trace('Selected file: ' + selectedFile.fullPath);
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Success', title: 'Success',
@ -313,6 +314,7 @@ class ChartEditorDialogHandler
type: NotificationType.Success, type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
dialog.hideDialog(DialogButton.APPLY); dialog.hideDialog(DialogButton.APPLY);
removeDropHandler(onDropFile); removeDropHandler(onDropFile);
@ -321,6 +323,7 @@ class ChartEditorDialogHandler
{ {
trace('Failed to load instrumental (${selectedFile.fullPath})'); trace('Failed to load instrumental (${selectedFile.fullPath})');
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Failure', title: 'Failure',
@ -328,6 +331,7 @@ class ChartEditorDialogHandler
type: NotificationType.Error, type: NotificationType.Error,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
} }
} }
}); });
@ -339,6 +343,7 @@ class ChartEditorDialogHandler
if (state.loadInstrumentalFromPath(path)) if (state.loadInstrumentalFromPath(path))
{ {
// Tell the user the load was successful. // Tell the user the load was successful.
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Success', title: 'Success',
@ -346,6 +351,7 @@ class ChartEditorDialogHandler
type: NotificationType.Success, type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
dialog.hideDialog(DialogButton.APPLY); dialog.hideDialog(DialogButton.APPLY);
removeDropHandler(onDropFile); removeDropHandler(onDropFile);
@ -362,6 +368,7 @@ class ChartEditorDialogHandler
} }
// Tell the user the load was successful. // Tell the user the load was successful.
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Failure', title: 'Failure',
@ -369,6 +376,7 @@ class ChartEditorDialogHandler
type: NotificationType.Error, type: NotificationType.Error,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
} }
}; };
@ -656,6 +664,7 @@ class ChartEditorDialogHandler
if (state.loadVocalsFromPath(path, charKey)) if (state.loadVocalsFromPath(path, charKey))
{ {
// Tell the user the load was successful. // Tell the user the load was successful.
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Success', title: 'Success',
@ -663,6 +672,7 @@ class ChartEditorDialogHandler
type: NotificationType.Success, type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
vocalsEntryLabel.text = 'Vocals for $charName (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}'; vocalsEntryLabel.text = 'Vocals for $charName (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
dialogNoVocals.hidden = true; dialogNoVocals.hidden = true;
removeDropHandler(onDropFile); removeDropHandler(onDropFile);
@ -679,6 +689,7 @@ class ChartEditorDialogHandler
} }
// Vocals failed to load. // Vocals failed to load.
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Failure', title: 'Failure',
@ -686,6 +697,7 @@ class ChartEditorDialogHandler
type: NotificationType.Error, type: NotificationType.Error,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
vocalsEntryLabel.text = 'Drag and drop vocals for $charName here, or click to browse.'; vocalsEntryLabel.text = 'Drag and drop vocals for $charName here, or click to browse.';
} }
@ -811,6 +823,7 @@ class ChartEditorDialogHandler
if (songMetadataVariation == null) if (songMetadataVariation == null)
{ {
// Tell the user the load was not successful. // Tell the user the load was not successful.
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Failure', title: 'Failure',
@ -818,12 +831,14 @@ class ChartEditorDialogHandler
type: NotificationType.Error, type: NotificationType.Error,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
return; return;
} }
songMetadata.set(variation, songMetadataVariation); songMetadata.set(variation, songMetadataVariation);
// Tell the user the load was successful. // Tell the user the load was successful.
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Success', title: 'Success',
@ -831,6 +846,7 @@ class ChartEditorDialogHandler
type: NotificationType.Success, type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
label.text = 'Metadata file (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}'; label.text = 'Metadata file (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
@ -852,6 +868,7 @@ class ChartEditorDialogHandler
songMetadata.set(variation, songMetadataVariation); songMetadata.set(variation, songMetadataVariation);
// Tell the user the load was successful. // Tell the user the load was successful.
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Success', title: 'Success',
@ -859,6 +876,7 @@ class ChartEditorDialogHandler
type: NotificationType.Success, type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
label.text = 'Metadata file (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}'; label.text = 'Metadata file (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}';
@ -881,6 +899,7 @@ class ChartEditorDialogHandler
state.noteDisplayDirty = true; state.noteDisplayDirty = true;
// Tell the user the load was successful. // Tell the user the load was successful.
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Success', title: 'Success',
@ -888,6 +907,7 @@ class ChartEditorDialogHandler
type: NotificationType.Success, type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
label.text = 'Chart data file (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}'; label.text = 'Chart data file (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
}; };
@ -909,6 +929,7 @@ class ChartEditorDialogHandler
state.noteDisplayDirty = true; state.noteDisplayDirty = true;
// Tell the user the load was successful. // Tell the user the load was successful.
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Success', title: 'Success',
@ -916,6 +937,7 @@ class ChartEditorDialogHandler
type: NotificationType.Success, type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
label.text = 'Chart data file (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}'; label.text = 'Chart data file (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}';
} }
@ -995,6 +1017,7 @@ class ChartEditorDialogHandler
state.loadSong([Constants.DEFAULT_VARIATION => songMetadata], [Constants.DEFAULT_VARIATION => songChartData]); state.loadSong([Constants.DEFAULT_VARIATION => songMetadata], [Constants.DEFAULT_VARIATION => songChartData]);
dialog.hideDialog(DialogButton.APPLY); dialog.hideDialog(DialogButton.APPLY);
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Success', title: 'Success',
@ -1002,6 +1025,7 @@ class ChartEditorDialogHandler
type: NotificationType.Success, type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
} }
}); });
} }
@ -1015,6 +1039,7 @@ class ChartEditorDialogHandler
state.loadSong([Constants.DEFAULT_VARIATION => songMetadata], [Constants.DEFAULT_VARIATION => songChartData]); state.loadSong([Constants.DEFAULT_VARIATION => songMetadata], [Constants.DEFAULT_VARIATION => songChartData]);
dialog.hideDialog(DialogButton.APPLY); dialog.hideDialog(DialogButton.APPLY);
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Success', title: 'Success',
@ -1022,6 +1047,7 @@ class ChartEditorDialogHandler
type: NotificationType.Success, type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
}; };
addDropHandler(importBox, onDropFile); addDropHandler(importBox, onDropFile);

View file

@ -143,7 +143,7 @@ class ChartEditorNoteSprite extends FlxSprite
return this.noteData; return this.noteData;
} }
public function updateNotePosition(?origin:FlxObject) public function updateNotePosition(?origin:FlxObject):Void
{ {
if (this.noteData == null) return; if (this.noteData == null) return;
@ -173,9 +173,7 @@ class ChartEditorNoteSprite extends FlxSprite
if (this.noteData.stepTime >= 0) if (this.noteData.stepTime >= 0)
{ {
// noteData.stepTime is a calculated value which accounts for BPM changes // noteData.stepTime is a calculated value which accounts for BPM changes
var stepTime:Float = this.noteData.stepTime; this.y = this.noteData.stepTime * ChartEditorState.GRID_SIZE;
var roundedStepTime:Float = Math.floor(stepTime + 0.01); // Add epsilon to fix rounding issues
this.y = roundedStepTime * ChartEditorState.GRID_SIZE;
} }
if (origin != null) if (origin != null)

View file

@ -179,14 +179,24 @@ class ChartEditorState extends HaxeUIState
*/ */
static final SNAP_QUANTS:Array<Int> = [4, 8, 12, 16, 20, 24, 32, 48, 64, 96, 192]; static final SNAP_QUANTS:Array<Int> = [4, 8, 12, 16, 20, 24, 32, 48, 64, 96, 192];
static final BASE_QUANT:Int = 16;
/** /**
* INSTANCE DATA * INSTANCE DATA
*/ */
// ============================== // ==============================
public var currentZoomLevel:Float = 1.0; public var currentZoomLevel:Float = 1.0;
var noteSnapQuantIndex:Int = 3; /**
* The internal index of what note snapping value is in use.
* Increment to make placement more preceise and decrement to make placement less precise.
*/
var noteSnapQuantIndex:Int = 3; // default is 16
/**
* The current note snapping value.
* For example, `32` when snapping to 32nd notes.
*/
public var noteSnapQuant(get, never):Int; public var noteSnapQuant(get, never):Int;
function get_noteSnapQuant():Int function get_noteSnapQuant():Int
@ -194,6 +204,17 @@ class ChartEditorState extends HaxeUIState
return SNAP_QUANTS[noteSnapQuantIndex]; return SNAP_QUANTS[noteSnapQuantIndex];
} }
/**
* The ratio of the current note snapping value to the default.
* For example, `32` becomes `0.5` when snapping to 16th notes.
*/
public var noteSnapRatio(get, never):Float;
function get_noteSnapRatio():Float
{
return BASE_QUANT / noteSnapQuant;
}
/** /**
* scrollPosition is the current position in the song, in pixels. * scrollPosition is the current position in the song, in pixels.
* One pixel is 1/40 of 1 step, and 1/160 of 1 beat. * One pixel is 1/40 of 1 step, and 1/160 of 1 beat.
@ -1769,7 +1790,7 @@ class ChartEditorState extends HaxeUIState
// These ones only happen if the modal dialog is not open. // These ones only happen if the modal dialog is not open.
handleScrollKeybinds(); handleScrollKeybinds();
// handleZoom(); // handleZoom();
// handleSnap(); handleSnap();
handleCursor(); handleCursor();
handleMenubar(); handleMenubar();
@ -2027,11 +2048,29 @@ class ChartEditorState extends HaxeUIState
if (FlxG.keys.justPressed.LEFT) if (FlxG.keys.justPressed.LEFT)
{ {
noteSnapQuantIndex--; noteSnapQuantIndex--;
#if !mac
NotificationManager.instance.addNotification(
{
title: 'Note Snapping',
body: 'Updated note snapping to 1/${noteSnapQuant}',
type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
});
#end
} }
if (FlxG.keys.justPressed.RIGHT) if (FlxG.keys.justPressed.RIGHT)
{ {
noteSnapQuantIndex++; noteSnapQuantIndex++;
#if !mac
NotificationManager.instance.addNotification(
{
title: 'Note Snapping',
body: 'Updated note snapping to 1/${noteSnapQuant}',
type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
});
#end
} }
} }
@ -2119,8 +2158,12 @@ class ChartEditorState extends HaxeUIState
} }
// The song position of the cursor, in steps. // The song position of the cursor, in steps.
var cursorFractionalStep:Float = cursorY / GRID_SIZE / (16 / noteSnapQuant); var cursorFractionalStep:Float = cursorY / GRID_SIZE;
var cursorMs:Float = Conductor.getStepTimeInMs(cursorFractionalStep); var cursorMs:Float = Conductor.getStepTimeInMs(cursorFractionalStep);
// Round the cursor step to the nearest snap quant.
var cursorSnappedStep:Float = Math.floor(cursorFractionalStep / noteSnapRatio) * noteSnapRatio;
var cursorSnappedMs:Float = Conductor.getStepTimeInMs(cursorSnappedStep);
// The direction value for the column at the cursor. // The direction value for the column at the cursor.
var cursorColumn:Int = Math.floor(cursorX / GRID_SIZE); var cursorColumn:Int = Math.floor(cursorX / GRID_SIZE);
if (cursorColumn < 0) cursorColumn = 0; if (cursorColumn < 0) cursorColumn = 0;
@ -2543,7 +2586,7 @@ class ChartEditorState extends HaxeUIState
{ {
eventData.event = selectedEventKind; eventData.event = selectedEventKind;
} }
eventData.time = cursorMs; eventData.time = cursorSnappedMs;
gridGhostEvent.visible = true; gridGhostEvent.visible = true;
gridGhostEvent.eventData = eventData; gridGhostEvent.eventData = eventData;
@ -2564,7 +2607,7 @@ class ChartEditorState extends HaxeUIState
noteData.data = cursorColumn; noteData.data = cursorColumn;
gridGhostNote.playNoteAnimation(); gridGhostNote.playNoteAnimation();
} }
noteData.time = cursorMs; noteData.time = cursorSnappedMs;
gridGhostNote.visible = true; gridGhostNote.visible = true;
gridGhostNote.noteData = noteData; gridGhostNote.noteData = noteData;
@ -4005,6 +4048,7 @@ class ChartEditorState extends HaxeUIState
} }
} }
#if !mac
NotificationManager.instance.addNotification( NotificationManager.instance.addNotification(
{ {
title: 'Success', title: 'Success',
@ -4012,6 +4056,7 @@ class ChartEditorState extends HaxeUIState
type: NotificationType.Success, type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
}); });
#end
} }
/** /**