1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2025-06-19 16:52:03 +00:00

WIP on new chart wizard

This commit is contained in:
Eric Myllyoja 2022-11-25 20:48:05 -05:00
parent 20ac91bbd9
commit 3f6cbb61d4
2 changed files with 162 additions and 23 deletions

View file

@ -1,5 +1,9 @@
package funkin.ui.debug.charting; package funkin.ui.debug.charting;
import funkin.input.Cursor;
import haxe.ui.containers.Box;
import haxe.ui.containers.dialogs.Dialogs;
import haxe.ui.components.Link;
import flixel.util.FlxTimer; import flixel.util.FlxTimer;
import flixel.FlxSprite; import flixel.FlxSprite;
import haxe.ui.containers.dialogs.Dialog; import haxe.ui.containers.dialogs.Dialog;
@ -9,7 +13,8 @@ import haxe.ui.components.Image;
class ChartEditorDialogHandler class ChartEditorDialogHandler
{ {
static final CHART_EDITOR_DIALOG_ABOUT_LAYOUT = Paths.ui('chart-editor/dialogs/about'); static final CHART_EDITOR_DIALOG_ABOUT_LAYOUT = Paths.ui('chart-editor/dialogs/about');
static final CHART_EDITOR_DIALOG_SPLASH_LAYOUT = Paths.ui('chart-editor/dialogs/splash'); static final CHART_EDITOR_DIALOG_WELCOME_LAYOUT = Paths.ui('chart-editor/dialogs/welcome');
static final CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT = Paths.ui('chart-editor/dialogs/upload-inst');
static final CHART_EDITOR_DIALOG_USER_GUIDE_LAYOUT = Paths.ui('chart-editor/dialogs/user-guide'); static final CHART_EDITOR_DIALOG_USER_GUIDE_LAYOUT = Paths.ui('chart-editor/dialogs/user-guide');
/** /**
@ -23,9 +28,9 @@ class ChartEditorDialogHandler
/** /**
* Builds and opens a dialog letting the user create a new chart, open a recent chart, or load from a template. * Builds and opens a dialog letting the user create a new chart, open a recent chart, or load from a template.
*/ */
public static function openSplashDialog(state:ChartEditorState, closable:Bool = true):Void public static function openWelcomeDialog(state:ChartEditorState, closable:Bool = true):Void
{ {
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_SPLASH_LAYOUT, true, closable); var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_WELCOME_LAYOUT, true, closable);
// TODO: Add callbacks to the dialog buttons // TODO: Add callbacks to the dialog buttons
@ -57,6 +62,77 @@ class ChartEditorDialogHandler
bfSprite.visible = true; bfSprite.visible = true;
}); });
} }
// Add handlers to the "Create From Song" section.
var linkCreateBasic:Link = dialog.findComponent('splashCreateFromSongBasic', Link);
linkCreateBasic.onClick = (_event) ->
{
dialog.hideDialog(DialogButton.CANCEL);
openUploadInstDialog(state, false);
};
// Get the list of songs and insert them as links into the "Create From Song" section.
}
public static function openUploadInstDialog(state:ChartEditorState, ?closable:Bool = true):Void
{
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT, true, closable);
var instrumentalBox:Box = dialog.findComponent('instrumentalBox', Box);
instrumentalBox.onMouseOver = (_event) ->
{
instrumentalBox.swapClass('upload-bg', 'upload-bg-hover');
Cursor.cursorMode = Pointer;
}
instrumentalBox.onMouseOut = (_event) ->
{
instrumentalBox.swapClass('upload-bg-hover', 'upload-bg');
Cursor.cursorMode = Default;
}
var onDropFile:String->Void;
instrumentalBox.onClick = (_event) ->
{
Dialogs.openBinaryFile("Open Instrumental", [{label: "Audio File (.ogg)", extension: "ogg"}], function(selectedFile)
{
if (selectedFile != null)
{
trace('Selected file: ' + selectedFile);
state.loadInstrumentalFromBytes(selectedFile.bytes);
dialog.hideDialog(DialogButton.APPLY);
removeDropHandler(onDropFile);
}
});
}
onDropFile = (path:String) ->
{
trace('Dropped file: ' + path);
state.loadInstrumentalFromPath(path);
dialog.hideDialog(DialogButton.APPLY);
removeDropHandler(onDropFile);
};
addDropHandler(onDropFile);
}
static function addDropHandler(handler:String->Void)
{
#if desktop
FlxG.stage.window.onDropFile.add(handler);
#else
trace('addDropHandler not implemented for this platform');
#end
}
static function removeDropHandler(handler:String->Void)
{
#if desktop
FlxG.stage.window.onDropFile.remove(handler);
#end
} }
/** /**

View file

@ -1,5 +1,6 @@
package funkin.ui.debug.charting; package funkin.ui.debug.charting;
import lime.media.AudioBuffer;
import funkin.input.Cursor; import funkin.input.Cursor;
import flixel.FlxSprite; import flixel.FlxSprite;
import flixel.addons.display.FlxSliceSprite; import flixel.addons.display.FlxSliceSprite;
@ -184,7 +185,15 @@ class ChartEditorState extends HaxeUIState
/** /**
* This is the song's length in PIXELS, same format as scrollPosition. * This is the song's length in PIXELS, same format as scrollPosition.
*/ */
var songLength:Int; var songLength(get, default):Int;
function get_songLength():Int
{
if (songLength <= 0)
return 1000;
return songLength;
}
/** /**
* songLength, converted to steps. * songLength, converted to steps.
@ -278,6 +287,14 @@ class ChartEditorState extends HaxeUIState
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY); return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
} }
var isCursorOverHaxeUIButton(get, null):Bool;
function get_isCursorOverHaxeUIButton():Bool
{
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY, haxe.ui.components.Button)
|| Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY, haxe.ui.components.Link);
}
/** /**
* The variation ID for the difficulty which is currently being edited. * The variation ID for the difficulty which is currently being edited.
*/ */
@ -734,7 +751,9 @@ class ChartEditorState extends HaxeUIState
setupUIListeners(); setupUIListeners();
// TODO: We should be loading the music later when the user requests it. // TODO: We should be loading the music later when the user requests it.
loadMusic(); // loadDefaultMusic();
ChartEditorDialogHandler.openSplashDialog(this, false);
} }
function buildDefaultSongData() function buildDefaultSongData()
@ -955,6 +974,9 @@ class ChartEditorState extends HaxeUIState
// Add functionality to the menu items. // Add functionality to the menu items.
addUIClickListener('menubarItemNewChart', (event:MouseEvent) -> ChartEditorDialogHandler.openSplashDialog(this, true));
addUIClickListener('menubarItemLoadInst', (event:MouseEvent) -> ChartEditorDialogHandler.openUploadInstDialog(this, true));
addUIClickListener('menubarItemUndo', (event:MouseEvent) -> undoLastCommand()); addUIClickListener('menubarItemUndo', (event:MouseEvent) -> undoLastCommand());
addUIClickListener('menubarItemRedo', (event:MouseEvent) -> redoLastCommand()); addUIClickListener('menubarItemRedo', (event:MouseEvent) -> redoLastCommand());
@ -1688,8 +1710,11 @@ class ChartEditorState extends HaxeUIState
gridCursor.visible = false; gridCursor.visible = false;
gridCursor.x = -9999; gridCursor.x = -9999;
gridCursor.y = -9999; gridCursor.y = -9999;
}
Cursor.cursorMode = Default; if (isCursorOverHaxeUIButton && Cursor.cursorMode == Default)
{
Cursor.cursorMode = Pointer;
} }
} }
@ -2203,7 +2228,7 @@ class ChartEditorState extends HaxeUIState
*/ */
function handleMusicPlayback() function handleMusicPlayback()
{ {
if (audioInstTrack.playing) if (audioInstTrack != null && audioInstTrack.playing)
{ {
if (FlxG.mouse.pressedMiddle) if (FlxG.mouse.pressedMiddle)
{ {
@ -2227,7 +2252,7 @@ class ChartEditorState extends HaxeUIState
Conductor.update(audioInstTrack.time); Conductor.update(audioInstTrack.time);
// Resync vocals. // Resync vocals.
if (Math.abs(audioInstTrack.time - audioVocalTrack.time) > 100) if (audioVocalTrack != null && Math.abs(audioInstTrack.time - audioVocalTrack.time) > 100)
audioVocalTrack.time = audioInstTrack.time; audioVocalTrack.time = audioInstTrack.time;
// We need time in fractional steps here to allow the song to actually play. // We need time in fractional steps here to allow the song to actually play.
@ -2249,18 +2274,25 @@ class ChartEditorState extends HaxeUIState
function startAudioPlayback() function startAudioPlayback()
{ {
audioInstTrack.play(); if (audioInstTrack != null)
audioVocalTrack.play(); audioInstTrack.play();
if (audioVocalTrack != null)
audioVocalTrack.play();
} }
function stopAudioPlayback() function stopAudioPlayback()
{ {
audioInstTrack.pause(); if (audioInstTrack != null)
audioVocalTrack.pause(); audioInstTrack.pause();
if (audioVocalTrack != null)
audioVocalTrack.pause();
} }
function toggleAudioPlayback() function toggleAudioPlayback()
{ {
if (audioInstTrack == null)
return;
if (audioInstTrack.playing) if (audioInstTrack.playing)
{ {
stopAudioPlayback(); stopAudioPlayback();
@ -2377,15 +2409,32 @@ class ChartEditorState extends HaxeUIState
} }
/** /**
* Load a music track for playback. * Loads an instrumental from an absolute file path, replacing the current instrumental.
*/ */
function loadMusic() public function loadInstrumentalFromPath(path:String):Void
{ {
// TODO: How to load music by selecting with a file dialog? var fileBytes:haxe.io.Bytes = sys.io.File.getBytes(path);
audioInstTrack = FlxG.sound.play(Paths.inst('dadbattle'), 1.0, false); loadInstrumentalFromBytes(fileBytes);
}
/**
* Loads an instrumental from audio byte data, replacing the current instrumental.
*/
public function loadInstrumentalFromBytes(bytes:haxe.io.Bytes):Void
{
audioInstTrack = FlxG.sound.load(openfl.media.Sound.loadCompressedDataFromByteArray(ByteArray.fromBytes(bytes)), 1.0, false);
audioInstTrack.autoDestroy = false; audioInstTrack.autoDestroy = false;
audioInstTrack.pause(); audioInstTrack.pause();
// Tell the user the load was successful.
// TODO: Un-bork this.
// showNotification('Loaded instrumental track successfully.');
postLoadInstrumental();
}
function postLoadInstrumental()
{
// Prevent the time from skipping back to 0 when the song ends. // Prevent the time from skipping back to 0 when the song ends.
audioInstTrack.onComplete = function() audioInstTrack.onComplete = function()
{ {
@ -2393,11 +2442,6 @@ class ChartEditorState extends HaxeUIState
audioVocalTrack.pause(); audioVocalTrack.pause();
}; };
audioVocalTrack = FlxG.sound.play(Paths.voices('dadbattle'), 1.0, false);
audioVocalTrack.autoDestroy = false;
audioVocalTrack.pause();
// TODO: Make sure Conductor works properly with changing BPMs.
var DAD_BATTLE_BPM = 180; var DAD_BATTLE_BPM = 180;
var BOPEEBO_BPM = 100; var BOPEEBO_BPM = 100;
Conductor.forceBPM(DAD_BATTLE_BPM); Conductor.forceBPM(DAD_BATTLE_BPM);
@ -2416,6 +2460,23 @@ class ChartEditorState extends HaxeUIState
moveSongToScrollPosition(); moveSongToScrollPosition();
} }
/**
* Load a music track for playback.
*/
function loadDefaultMusic()
{
// TODO: How to load music by selecting with a file dialog?
audioInstTrack = FlxG.sound.play(Paths.inst('dadbattle'), 1.0, false);
audioInstTrack.autoDestroy = false;
audioInstTrack.pause();
audioVocalTrack = FlxG.sound.play(Paths.voices('dadbattle'), 1.0, false);
audioVocalTrack.autoDestroy = false;
audioVocalTrack.pause();
postLoadInstrumental();
}
/** /**
* When setting the scroll position, except when automatically scrolling during song playback, * When setting the scroll position, except when automatically scrolling during song playback,
* we need to update the conductor's current step time and the timestamp of the audio tracks. * we need to update the conductor's current step time and the timestamp of the audio tracks.
@ -2426,8 +2487,10 @@ class ChartEditorState extends HaxeUIState
Conductor.update(scrollPositionInMs); Conductor.update(scrollPositionInMs);
// Update the songPosition in the audio tracks. // Update the songPosition in the audio tracks.
audioInstTrack.time = scrollPositionInMs + playheadPositionInMs; if (audioInstTrack != null)
audioVocalTrack.time = scrollPositionInMs + playheadPositionInMs; audioInstTrack.time = scrollPositionInMs + playheadPositionInMs;
if (audioVocalTrack != null)
audioVocalTrack.time = scrollPositionInMs + playheadPositionInMs;
// We need to update the note sprites because we changed the scroll position. // We need to update the note sprites because we changed the scroll position.
noteDisplayDirty = true; noteDisplayDirty = true;