mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-27 10:05:41 -05:00
Merge pull request #295 from FunkinCrew/bugfix/chart-editor-upload-vocals-rewrite
Rewrite Upload Vocals dialog.
This commit is contained in:
commit
5df16afd7c
4 changed files with 364 additions and 173 deletions
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit e0a1446ae956b15a20bf039de0c46a59b8e242bb
|
Subproject commit 7e19c4cfa7db57178f03ed4a58a9fd4d2b93dea7
|
|
@ -13,6 +13,7 @@ import haxe.ui.notifications.NotificationType;
|
||||||
|
|
||||||
// @:nullSafety // TODO: Fix null safety when used with HaxeUI build macros.
|
// @:nullSafety // TODO: Fix null safety when used with HaxeUI build macros.
|
||||||
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/upload-chart.xml"))
|
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/upload-chart.xml"))
|
||||||
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
class ChartEditorUploadChartDialog extends ChartEditorBaseDialog
|
class ChartEditorUploadChartDialog extends ChartEditorBaseDialog
|
||||||
{
|
{
|
||||||
var dropHandlers:Array<DialogDropTarget> = [];
|
var dropHandlers:Array<DialogDropTarget> = [];
|
||||||
|
|
|
@ -0,0 +1,311 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogDropTarget;
|
||||||
import funkin.ui.debug.charting.dialogs.ChartEditorCharacterIconSelectorMenu;
|
import funkin.ui.debug.charting.dialogs.ChartEditorCharacterIconSelectorMenu;
|
||||||
import funkin.ui.debug.charting.dialogs.ChartEditorUploadChartDialog;
|
import funkin.ui.debug.charting.dialogs.ChartEditorUploadChartDialog;
|
||||||
import funkin.ui.debug.charting.dialogs.ChartEditorWelcomeDialog;
|
import funkin.ui.debug.charting.dialogs.ChartEditorWelcomeDialog;
|
||||||
|
import funkin.ui.debug.charting.dialogs.ChartEditorUploadVocalsDialog;
|
||||||
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
|
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
|
||||||
import funkin.util.Constants;
|
import funkin.util.Constants;
|
||||||
import funkin.util.DateUtil;
|
import funkin.util.DateUtil;
|
||||||
|
@ -59,11 +60,8 @@ using Lambda;
|
||||||
class ChartEditorDialogHandler
|
class ChartEditorDialogHandler
|
||||||
{
|
{
|
||||||
// Paths to HaxeUI layout files for each dialog.
|
// Paths to HaxeUI layout files for each dialog.
|
||||||
static final CHART_EDITOR_DIALOG_UPLOAD_CHART_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-chart');
|
|
||||||
static final CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-inst');
|
static final CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-inst');
|
||||||
static final CHART_EDITOR_DIALOG_SONG_METADATA_LAYOUT:String = Paths.ui('chart-editor/dialogs/song-metadata');
|
static final CHART_EDITOR_DIALOG_SONG_METADATA_LAYOUT:String = Paths.ui('chart-editor/dialogs/song-metadata');
|
||||||
static final CHART_EDITOR_DIALOG_UPLOAD_VOCALS_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-vocals');
|
|
||||||
static final CHART_EDITOR_DIALOG_UPLOAD_VOCALS_ENTRY_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-vocals-entry');
|
|
||||||
static final CHART_EDITOR_DIALOG_OPEN_CHART_PARTS_LAYOUT:String = Paths.ui('chart-editor/dialogs/open-chart-parts');
|
static final CHART_EDITOR_DIALOG_OPEN_CHART_PARTS_LAYOUT:String = Paths.ui('chart-editor/dialogs/open-chart-parts');
|
||||||
static final CHART_EDITOR_DIALOG_OPEN_CHART_PARTS_ENTRY_LAYOUT:String = Paths.ui('chart-editor/dialogs/open-chart-parts-entry');
|
static final CHART_EDITOR_DIALOG_OPEN_CHART_PARTS_ENTRY_LAYOUT:String = Paths.ui('chart-editor/dialogs/open-chart-parts-entry');
|
||||||
static final CHART_EDITOR_DIALOG_IMPORT_CHART_LAYOUT:String = Paths.ui('chart-editor/dialogs/import-chart');
|
static final CHART_EDITOR_DIALOG_IMPORT_CHART_LAYOUT:String = Paths.ui('chart-editor/dialogs/import-chart');
|
||||||
|
@ -105,6 +103,56 @@ class ChartEditorDialogHandler
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds and opens a dialog letting the user browse for a chart file to open.
|
||||||
|
* @param state The current chart editor state.
|
||||||
|
* @param closable Whether the dialog can be closed by the user.
|
||||||
|
* @return The dialog that was opened.
|
||||||
|
*/
|
||||||
|
public static function openBrowseFNFC(state:ChartEditorState, closable:Bool):Null<Dialog>
|
||||||
|
{
|
||||||
|
var dialog = ChartEditorUploadChartDialog.build(state, closable);
|
||||||
|
|
||||||
|
dialog.zIndex = 1000;
|
||||||
|
state.isHaxeUIDialogOpen = true;
|
||||||
|
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds and opens a dialog where the user uploads vocals for the current song.
|
||||||
|
* @param state The current chart editor state.
|
||||||
|
* @param closable Whether the dialog can be closed by the user.
|
||||||
|
* @return The dialog that was opened.
|
||||||
|
*/
|
||||||
|
public static function openUploadVocalsDialog(state:ChartEditorState, closable:Bool = true):Dialog
|
||||||
|
{
|
||||||
|
var charData:SongCharacterData = state.currentSongMetadata.playData.characters;
|
||||||
|
|
||||||
|
var hasClearedVocals:Bool = false;
|
||||||
|
|
||||||
|
var charIdsForVocals:Array<String> = [charData.player, charData.opponent];
|
||||||
|
|
||||||
|
var dialog = ChartEditorUploadVocalsDialog.build(state, charIdsForVocals, closable);
|
||||||
|
|
||||||
|
dialog.zIndex = 1000;
|
||||||
|
state.isHaxeUIDialogOpen = true;
|
||||||
|
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds and opens the dialog for selecting a character.
|
||||||
|
*/
|
||||||
|
public static function openCharacterDropdown(state:ChartEditorState, charType:CharacterType, lockPosition:Bool = false):Null<Menu>
|
||||||
|
{
|
||||||
|
var menu = ChartEditorCharacterIconSelectorMenu.build(state, charType, lockPosition);
|
||||||
|
|
||||||
|
menu.zIndex = 1000;
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and opens a dialog letting the user know a backup is available, and prompting them to load it.
|
* Builds and opens a dialog letting the user know a backup is available, and prompting them to load it.
|
||||||
*/
|
*/
|
||||||
|
@ -186,22 +234,6 @@ class ChartEditorDialogHandler
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds and opens a dialog letting the user browse for a chart file to open.
|
|
||||||
* @param state The current chart editor state.
|
|
||||||
* @param closable Whether the dialog can be closed by the user.
|
|
||||||
* @return The dialog that was opened.
|
|
||||||
*/
|
|
||||||
public static function openBrowseFNFC(state:ChartEditorState, closable:Bool):Null<Dialog>
|
|
||||||
{
|
|
||||||
var dialog = ChartEditorUploadChartDialog.build(state, closable);
|
|
||||||
|
|
||||||
dialog.zIndex = 1000;
|
|
||||||
state.isHaxeUIDialogOpen = true;
|
|
||||||
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the wizard for opening an existing chart from individual files.
|
* Open the wizard for opening an existing chart from individual files.
|
||||||
* @param state
|
* @param state
|
||||||
|
@ -288,15 +320,6 @@ class ChartEditorDialogHandler
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function openCharacterDropdown(state:ChartEditorState, charType:CharacterType, lockPosition:Bool = false):Null<Menu>
|
|
||||||
{
|
|
||||||
var menu = ChartEditorCharacterIconSelectorMenu.build(state, charType, lockPosition);
|
|
||||||
|
|
||||||
menu.zIndex = 1000;
|
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function openCreateSongWizardBasicOnly(state:ChartEditorState, closable:Bool):Void
|
public static function openCreateSongWizardBasicOnly(state:ChartEditorState, closable:Bool):Void
|
||||||
{
|
{
|
||||||
// Step 1. Song Metadata
|
// Step 1. Song Metadata
|
||||||
|
@ -699,150 +722,6 @@ class ChartEditorDialogHandler
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds and opens a dialog where the user uploads vocals for the current song.
|
|
||||||
* @param state The current chart editor state.
|
|
||||||
* @param closable Whether the dialog can be closed by the user.
|
|
||||||
* @return The dialog that was opened.
|
|
||||||
*/
|
|
||||||
public static function openUploadVocalsDialog(state:ChartEditorState, closable:Bool = true):Dialog
|
|
||||||
{
|
|
||||||
var instId:String = state.currentInstrumentalId;
|
|
||||||
var charIdsForVocals:Array<String> = [];
|
|
||||||
|
|
||||||
var charData:SongCharacterData = state.currentSongMetadata.playData.characters;
|
|
||||||
|
|
||||||
var hasClearedVocals:Bool = false;
|
|
||||||
|
|
||||||
charIdsForVocals.push(charData.player);
|
|
||||||
charIdsForVocals.push(charData.opponent);
|
|
||||||
|
|
||||||
var dialog:Null<Dialog> = openDialog(state, CHART_EDITOR_DIALOG_UPLOAD_VOCALS_LAYOUT, true, closable);
|
|
||||||
if (dialog == null) throw 'Could not locate Upload Vocals dialog';
|
|
||||||
|
|
||||||
var dialogContainer:Null<Component> = dialog.findComponent('vocalContainer');
|
|
||||||
if (dialogContainer == null) throw 'Could not locate vocalContainer in Upload Vocals dialog';
|
|
||||||
|
|
||||||
var buttonCancel:Null<Button> = dialog.findComponent('dialogCancel', Button);
|
|
||||||
if (buttonCancel == null) throw 'Could not locate dialogCancel button in Upload Vocals dialog';
|
|
||||||
buttonCancel.onClick = function(_) {
|
|
||||||
dialog.hideDialog(DialogButton.CANCEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
var dialogNoVocals:Null<Button> = dialog.findComponent('dialogNoVocals', Button);
|
|
||||||
if (dialogNoVocals == null) throw 'Could not locate dialogNoVocals button in Upload Vocals dialog';
|
|
||||||
dialogNoVocals.onClick = function(_) {
|
|
||||||
// Dismiss
|
|
||||||
state.wipeVocalData();
|
|
||||||
dialog.hideDialog(DialogButton.APPLY);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (charKey in charIdsForVocals)
|
|
||||||
{
|
|
||||||
trace('Adding vocal upload for character ${charKey}');
|
|
||||||
var charMetadata:Null<CharacterData> = CharacterDataParser.fetchCharacterData(charKey);
|
|
||||||
var charName:String = charMetadata != null ? charMetadata.name : charKey;
|
|
||||||
|
|
||||||
var vocalsEntry:Component = RuntimeComponentBuilder.fromAsset(CHART_EDITOR_DIALOG_UPLOAD_VOCALS_ENTRY_LAYOUT);
|
|
||||||
|
|
||||||
var vocalsEntryLabel:Null<Label> = vocalsEntry.findComponent('vocalsEntryLabel', Label);
|
|
||||||
if (vocalsEntryLabel == null) throw 'Could not locate vocalsEntryLabel in Upload Vocals dialog';
|
|
||||||
#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
|
|
||||||
|
|
||||||
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 (state.loadVocalsFromPath(path, charKey, instId, !hasClearedVocals))
|
|
||||||
{
|
|
||||||
hasClearedVocals = true;
|
|
||||||
// Tell the user the load was successful.
|
|
||||||
state.success('Loaded Vocals', 'Loaded vocals for $charName (${path.file}.${path.ext}), variation ${state.selectedVariation}');
|
|
||||||
#if FILE_DROP_SUPPORTED
|
|
||||||
vocalsEntryLabel.text = 'Voices for $charName (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
|
|
||||||
#else
|
|
||||||
vocalsEntryLabel.text = 'Voices for $charName (click to browse)\n${path.file}.${path.ext}';
|
|
||||||
#end
|
|
||||||
|
|
||||||
dialogNoVocals.hidden = true;
|
|
||||||
state.removeDropHandler(dropHandler);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trace('Failed to load vocal track (${path.file}.${path.ext})');
|
|
||||||
|
|
||||||
state.error('Failed to Load Vocals', 'Failed to load vocal track (${path.file}.${path.ext}) for variation (${state.selectedVariation})');
|
|
||||||
|
|
||||||
#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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
dropHandler.handler = onDropFile;
|
|
||||||
|
|
||||||
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 (state.loadVocalsFromBytes(selectedFile.bytes, charKey, instId, !hasClearedVocals))
|
|
||||||
{
|
|
||||||
hasClearedVocals = true;
|
|
||||||
// Tell the user the load was successful.
|
|
||||||
state.success('Loaded Vocals', 'Loaded vocals for $charName (${selectedFile.name}), variation ${state.selectedVariation}');
|
|
||||||
|
|
||||||
#if FILE_DROP_SUPPORTED
|
|
||||||
vocalsEntryLabel.text = 'Voices for $charName (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}';
|
|
||||||
#else
|
|
||||||
vocalsEntryLabel.text = 'Voices for $charName (click to browse)\n${selectedFile.name}';
|
|
||||||
#end
|
|
||||||
|
|
||||||
dialogNoVocals.hidden = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trace('Failed to load vocal track (${selectedFile.fullPath})');
|
|
||||||
|
|
||||||
state.error('Failed to Load Vocals', 'Failed to load vocal track (${selectedFile.name}) for variation (${state.selectedVariation})');
|
|
||||||
|
|
||||||
#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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// onDropFile
|
|
||||||
#if FILE_DROP_SUPPORTED
|
|
||||||
addDropHandler(dropHandler);
|
|
||||||
#end
|
|
||||||
dialogContainer.addComponent(vocalsEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
var dialogContinue:Null<Button> = dialog.findComponent('dialogContinue', Button);
|
|
||||||
if (dialogContinue == null) throw 'Could not locate dialogContinue button in Upload Vocals dialog';
|
|
||||||
dialogContinue.onClick = function(_) {
|
|
||||||
// Dismiss
|
|
||||||
dialog.hideDialog(DialogButton.APPLY);
|
|
||||||
};
|
|
||||||
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and opens a dialog where the user upload the JSON files for a song.
|
* Builds and opens a dialog where the user upload the JSON files for a song.
|
||||||
* @param state The current chart editor state.
|
* @param state The current chart editor state.
|
||||||
|
|
Loading…
Reference in a new issue