mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-27 18:15:38 -05:00
312 lines
9.9 KiB
Haxe
312 lines
9.9 KiB
Haxe
|
package funkin.ui.debug.charting.dialogs;
|
||
|
|
||
|
import funkin.input.Cursor;
|
||
|
import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogDropTarget;
|
||
|
import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogParams;
|
||
|
import funkin.util.FileUtil;
|
||
|
import funkin.play.character.CharacterData;
|
||
|
import haxe.io.Path;
|
||
|
import haxe.ui.components.Button;
|
||
|
import haxe.ui.components.Label;
|
||
|
import haxe.ui.containers.dialogs.Dialog.DialogButton;
|
||
|
import haxe.ui.containers.dialogs.Dialog.DialogEvent;
|
||
|
import haxe.ui.containers.Box;
|
||
|
import haxe.ui.containers.dialogs.Dialogs;
|
||
|
import haxe.ui.core.Component;
|
||
|
import haxe.ui.notifications.NotificationManager;
|
||
|
import haxe.ui.notifications.NotificationType;
|
||
|
|
||
|
// @:nullSafety // TODO: Fix null safety when used with HaxeUI build macros.
|
||
|
|
||
|
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/upload-vocals.xml"))
|
||
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||
|
class ChartEditorUploadVocalsDialog extends ChartEditorBaseDialog
|
||
|
{
|
||
|
var dropHandlers:Array<DialogDropTarget> = [];
|
||
|
|
||
|
var vocalContainer:Component;
|
||
|
var dialogCancel:Button;
|
||
|
var dialogNoVocals:Button;
|
||
|
var dialogContinue:Button;
|
||
|
|
||
|
var charIds:Array<String>;
|
||
|
var instId:String;
|
||
|
var hasClearedVocals:Bool = false;
|
||
|
|
||
|
public function new(state2:ChartEditorState, charIds:Array<String>, params2:DialogParams)
|
||
|
{
|
||
|
super(state2, params2);
|
||
|
|
||
|
this.charIds = charIds;
|
||
|
this.instId = chartEditorState.currentInstrumentalId;
|
||
|
|
||
|
dialogCancel.onClick = function(_) {
|
||
|
hideDialog(DialogButton.CANCEL);
|
||
|
}
|
||
|
|
||
|
dialogNoVocals.onClick = function(_) {
|
||
|
// Dismiss
|
||
|
chartEditorState.wipeVocalData();
|
||
|
hideDialog(DialogButton.APPLY);
|
||
|
};
|
||
|
|
||
|
dialogContinue.onClick = function(_) {
|
||
|
// Dismiss
|
||
|
hideDialog(DialogButton.APPLY);
|
||
|
};
|
||
|
|
||
|
buildDropHandlers();
|
||
|
}
|
||
|
|
||
|
function buildDropHandlers():Void
|
||
|
{
|
||
|
for (charKey in charIds)
|
||
|
{
|
||
|
trace('Adding vocal upload for character ${charKey}');
|
||
|
|
||
|
var charMetadata:Null<CharacterData> = CharacterDataParser.fetchCharacterData(charKey);
|
||
|
var charName:String = charMetadata?.name ?? charKey;
|
||
|
|
||
|
var vocalsEntry = new ChartEditorUploadVocalsEntry(charName);
|
||
|
|
||
|
var dropHandler:DialogDropTarget = {component: vocalsEntry, handler: null};
|
||
|
|
||
|
var onDropFile:String->Void = function(pathStr:String) {
|
||
|
trace('Selected file: $pathStr');
|
||
|
var path:Path = new Path(pathStr);
|
||
|
|
||
|
if (chartEditorState.loadVocalsFromPath(path, charKey, this.instId, !this.hasClearedVocals))
|
||
|
{
|
||
|
this.hasClearedVocals = true;
|
||
|
// Tell the user the load was successful.
|
||
|
chartEditorState.success('Loaded Vocals', 'Loaded vocals for $charName (${path.file}.${path.ext}), variation ${chartEditorState.selectedVariation}');
|
||
|
#if FILE_DROP_SUPPORTED
|
||
|
vocalsEntry.vocalsEntryLabel.text = 'Voices for $charName (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
|
||
|
#else
|
||
|
vocalsEntry.vocalsEntryLabel.text = 'Voices for $charName (click to browse)\n${path.file}.${path.ext}';
|
||
|
#end
|
||
|
|
||
|
dialogNoVocals.hidden = true;
|
||
|
chartEditorState.removeDropHandler(dropHandler);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
trace('Failed to load vocal track (${path.file}.${path.ext})');
|
||
|
|
||
|
chartEditorState.error('Failed to Load Vocals',
|
||
|
'Failed to load vocal track (${path.file}.${path.ext}) for variation (${chartEditorState.selectedVariation})');
|
||
|
|
||
|
#if FILE_DROP_SUPPORTED
|
||
|
vocalsEntry.vocalsEntryLabel.text = 'Drag and drop vocals for $charName here, or click to browse.';
|
||
|
#else
|
||
|
vocalsEntry.vocalsEntryLabel.text = 'Click to browse for vocals for $charName.';
|
||
|
#end
|
||
|
}
|
||
|
};
|
||
|
|
||
|
vocalsEntry.onClick = function(_event) {
|
||
|
Dialogs.openBinaryFile('Open $charName Vocals', [
|
||
|
{label: 'Audio File (.ogg)', extension: 'ogg'}], function(selectedFile) {
|
||
|
if (selectedFile != null && selectedFile.bytes != null)
|
||
|
{
|
||
|
trace('Selected file: ' + selectedFile.name);
|
||
|
|
||
|
if (chartEditorState.loadVocalsFromBytes(selectedFile.bytes, charKey, this.instId, !this.hasClearedVocals))
|
||
|
{
|
||
|
hasClearedVocals = true;
|
||
|
// Tell the user the load was successful.
|
||
|
chartEditorState.success('Loaded Vocals',
|
||
|
'Loaded vocals for $charName (${selectedFile.name}), variation ${chartEditorState.selectedVariation}');
|
||
|
|
||
|
#if FILE_DROP_SUPPORTED
|
||
|
vocalsEntry.vocalsEntryLabel.text = 'Voices for $charName (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}';
|
||
|
#else
|
||
|
vocalsEntry.vocalsEntryLabel.text = 'Voices for $charName (click to browse)\n${selectedFile.name}';
|
||
|
#end
|
||
|
|
||
|
dialogNoVocals.hidden = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
trace('Failed to load vocal track (${selectedFile.fullPath})');
|
||
|
|
||
|
chartEditorState.error('Failed to Load Vocals',
|
||
|
'Failed to load vocal track (${selectedFile.name}) for variation (${chartEditorState.selectedVariation})');
|
||
|
|
||
|
#if FILE_DROP_SUPPORTED
|
||
|
vocalsEntry.vocalsEntryLabel.text = 'Drag and drop vocals for $charName here, or click to browse.';
|
||
|
#else
|
||
|
vocalsEntry.vocalsEntryLabel.text = 'Click to browse for vocals for $charName.';
|
||
|
#end
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
dropHandler.handler = onDropFile;
|
||
|
|
||
|
// onDropFile
|
||
|
#if FILE_DROP_SUPPORTED
|
||
|
dropHandlers.push(dropHandler);
|
||
|
#end
|
||
|
|
||
|
vocalContainer.addComponent(vocalsEntry);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static function build(state:ChartEditorState, charIds:Array<String>, ?closable:Bool, ?modal:Bool):ChartEditorUploadVocalsDialog
|
||
|
{
|
||
|
var dialog = new ChartEditorUploadVocalsDialog(state, charIds,
|
||
|
{
|
||
|
closable: closable ?? false,
|
||
|
modal: modal ?? true
|
||
|
});
|
||
|
|
||
|
for (dropTarget in dialog.dropHandlers)
|
||
|
{
|
||
|
state.addDropHandler(dropTarget);
|
||
|
}
|
||
|
|
||
|
dialog.showDialog(modal ?? true);
|
||
|
|
||
|
return dialog;
|
||
|
}
|
||
|
|
||
|
public override function onClose(event:DialogEvent):Void
|
||
|
{
|
||
|
super.onClose(event);
|
||
|
|
||
|
if (event.button != DialogButton.APPLY && !this.closable)
|
||
|
{
|
||
|
// User cancelled the wizard! Back to the welcome dialog.
|
||
|
chartEditorState.openWelcomeDialog(this.closable);
|
||
|
}
|
||
|
|
||
|
for (dropTarget in dropHandlers)
|
||
|
{
|
||
|
chartEditorState.removeDropHandler(dropTarget);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override function lock():Void
|
||
|
{
|
||
|
super.lock();
|
||
|
this.dialogCancel.disabled = true;
|
||
|
}
|
||
|
|
||
|
public override function unlock():Void
|
||
|
{
|
||
|
super.unlock();
|
||
|
this.dialogCancel.disabled = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called when clicking the Upload Chart box.
|
||
|
*/
|
||
|
public function onClickChartBox():Void
|
||
|
{
|
||
|
if (this.locked) return;
|
||
|
|
||
|
this.lock();
|
||
|
// TODO / BUG: File filtering not working on mac finder dialog, so we don't use it for now
|
||
|
#if !mac
|
||
|
FileUtil.browseForBinaryFile('Open Chart', [FileUtil.FILE_EXTENSION_INFO_FNFC], onSelectFile, onCancelBrowse);
|
||
|
#else
|
||
|
FileUtil.browseForBinaryFile('Open Chart', null, onSelectFile, onCancelBrowse);
|
||
|
#end
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called when a file is selected by dropping a file onto the Upload Chart box.
|
||
|
*/
|
||
|
function onDropFileChartBox(pathStr:String):Void
|
||
|
{
|
||
|
var path:Path = new Path(pathStr);
|
||
|
trace('Dropped file (${path})');
|
||
|
|
||
|
try
|
||
|
{
|
||
|
var result:Null<Array<String>> = ChartEditorImportExportHandler.loadFromFNFCPath(chartEditorState, path.toString());
|
||
|
if (result != null)
|
||
|
{
|
||
|
chartEditorState.success('Loaded Chart',
|
||
|
result.length == 0 ? 'Loaded chart (${path.toString()})' : 'Loaded chart (${path.toString()})\n${result.join("\n")}');
|
||
|
this.hideDialog(DialogButton.APPLY);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
chartEditorState.failure('Failed to Load Chart', 'Failed to load chart (${path.toString()})');
|
||
|
}
|
||
|
}
|
||
|
catch (err)
|
||
|
{
|
||
|
chartEditorState.failure('Failed to Load Chart', 'Failed to load chart (${path.toString()}): ${err}');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called when a file is selected by the dialog displayed when clicking the Upload Chart box.
|
||
|
*/
|
||
|
function onSelectFile(selectedFile:SelectedFileInfo):Void
|
||
|
{
|
||
|
this.unlock();
|
||
|
|
||
|
if (selectedFile != null && selectedFile.bytes != null)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
var result:Null<Array<String>> = ChartEditorImportExportHandler.loadFromFNFC(chartEditorState, selectedFile.bytes);
|
||
|
if (result != null)
|
||
|
{
|
||
|
chartEditorState.success('Loaded Chart',
|
||
|
result.length == 0 ? 'Loaded chart (${selectedFile.name})' : 'Loaded chart (${selectedFile.name})\n${result.join("\n")}');
|
||
|
|
||
|
if (selectedFile.fullPath != null) chartEditorState.currentWorkingFilePath = selectedFile.fullPath;
|
||
|
this.hideDialog(DialogButton.APPLY);
|
||
|
}
|
||
|
}
|
||
|
catch (err)
|
||
|
{
|
||
|
chartEditorState.failure('Failed to Load Chart', 'Failed to load chart (${selectedFile.name}): ${err}');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function onCancelBrowse():Void
|
||
|
{
|
||
|
this.unlock();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/upload-vocals-entry.xml"))
|
||
|
class ChartEditorUploadVocalsEntry extends Box
|
||
|
{
|
||
|
public var vocalsEntryLabel:Label;
|
||
|
|
||
|
var charName:String;
|
||
|
|
||
|
public function new(charName:String)
|
||
|
{
|
||
|
super();
|
||
|
|
||
|
this.charName = charName;
|
||
|
|
||
|
#if FILE_DROP_SUPPORTED
|
||
|
vocalsEntryLabel.text = 'Drag and drop vocals for $charName here, or click to browse.';
|
||
|
#else
|
||
|
vocalsEntryLabel.text = 'Click to browse for vocals for $charName.';
|
||
|
#end
|
||
|
|
||
|
this.onMouseOver = function(_event) {
|
||
|
// if (this.locked) return;
|
||
|
this.swapClass('upload-bg', 'upload-bg-hover');
|
||
|
Cursor.cursorMode = Pointer;
|
||
|
}
|
||
|
|
||
|
this.onMouseOut = function(_event) {
|
||
|
this.swapClass('upload-bg-hover', 'upload-bg');
|
||
|
Cursor.cursorMode = Default;
|
||
|
}
|
||
|
}
|
||
|
}
|