Fix 5 or 6 issues with charting
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package funkin.ui.debug.charting;
|
||||
|
||||
import haxe.io.Path;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.input.Cursor;
|
||||
@@ -8,6 +9,7 @@ import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
import funkin.play.song.SongData.SongDataParser;
|
||||
import funkin.play.song.SongData.SongPlayableChar;
|
||||
import funkin.play.song.SongData.SongTimeChange;
|
||||
import haxe.ui.core.Component;
|
||||
import haxe.ui.components.Button;
|
||||
import haxe.ui.components.DropDown;
|
||||
import haxe.ui.components.Image;
|
||||
@@ -18,7 +20,6 @@ import haxe.ui.components.TextField;
|
||||
import haxe.ui.containers.Box;
|
||||
import haxe.ui.containers.dialogs.Dialog;
|
||||
import haxe.ui.containers.dialogs.Dialogs;
|
||||
import haxe.ui.containers.properties.Property;
|
||||
import haxe.ui.containers.properties.PropertyGrid;
|
||||
import haxe.ui.containers.properties.PropertyGroup;
|
||||
import haxe.ui.containers.VBox;
|
||||
@@ -27,16 +28,19 @@ import haxe.ui.events.UIEvent;
|
||||
|
||||
using Lambda;
|
||||
|
||||
/**
|
||||
* Handles dialogs for the new Chart Editor.
|
||||
*/
|
||||
class ChartEditorDialogHandler
|
||||
{
|
||||
static final CHART_EDITOR_DIALOG_ABOUT_LAYOUT = Paths.ui('chart-editor/dialogs/about');
|
||||
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_SONG_METADATA_LAYOUT = Paths.ui('chart-editor/dialogs/song-metadata');
|
||||
static final CHART_EDITOR_DIALOG_SONG_METADATA_CHARGROUP_LAYOUT = Paths.ui('chart-editor/dialogs/song-metadata-chargroup');
|
||||
static final CHART_EDITOR_DIALOG_UPLOAD_VOCALS_LAYOUT = Paths.ui('chart-editor/dialogs/upload-vocals');
|
||||
static final CHART_EDITOR_DIALOG_UPLOAD_VOCALS_ENTRY_LAYOUT = Paths.ui('chart-editor/dialogs/upload-vocals-entry');
|
||||
static final CHART_EDITOR_DIALOG_USER_GUIDE_LAYOUT = Paths.ui('chart-editor/dialogs/user-guide');
|
||||
static final CHART_EDITOR_DIALOG_ABOUT_LAYOUT:String = Paths.ui('chart-editor/dialogs/about');
|
||||
static final CHART_EDITOR_DIALOG_WELCOME_LAYOUT:String = Paths.ui('chart-editor/dialogs/welcome');
|
||||
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_CHARGROUP_LAYOUT:String = Paths.ui('chart-editor/dialogs/song-metadata-chargroup');
|
||||
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_USER_GUIDE_LAYOUT:String = Paths.ui('chart-editor/dialogs/user-guide');
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -55,55 +59,23 @@ class ChartEditorDialogHandler
|
||||
|
||||
// TODO: Add callbacks to the dialog buttons
|
||||
|
||||
// Switch the graphic for frames.
|
||||
var bfSpritePlaceholder:Image = dialog.findComponent('bfSprite', Image);
|
||||
|
||||
// TODO: Replace this bullshit with a custom HaxeUI component that loads the sprite from the game's assets.
|
||||
|
||||
if (bfSpritePlaceholder != null)
|
||||
{
|
||||
var bfSprite:FlxSprite = new FlxSprite(0, 0);
|
||||
|
||||
bfSprite.visible = false;
|
||||
|
||||
var frames = Paths.getSparrowAtlas(bfSpritePlaceholder.resource);
|
||||
bfSprite.frames = frames;
|
||||
|
||||
bfSprite.animation.addByPrefix('idle', 'Boyfriend DJ0', 24, true);
|
||||
bfSprite.animation.play('idle');
|
||||
|
||||
bfSpritePlaceholder.rootComponent.add(bfSprite);
|
||||
bfSpritePlaceholder.visible = false;
|
||||
|
||||
new FlxTimer().start(0.10, (_timer:FlxTimer) ->
|
||||
{
|
||||
bfSprite.x = bfSpritePlaceholder.screenLeft;
|
||||
bfSprite.y = bfSpritePlaceholder.screenTop;
|
||||
bfSprite.setGraphicSize(Std.int(bfSpritePlaceholder.width), Std.int(bfSpritePlaceholder.height));
|
||||
bfSprite.visible = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Add handlers to the "Create From Song" section.
|
||||
var linkCreateBasic:Link = dialog.findComponent('splashCreateFromSongBasic', Link);
|
||||
linkCreateBasic.onClick = (_event) ->
|
||||
{
|
||||
linkCreateBasic.onClick = (_event) -> {
|
||||
dialog.hideDialog(DialogButton.CANCEL);
|
||||
|
||||
// Create song wizard
|
||||
var uploadInstDialog = openUploadInstDialog(state, false);
|
||||
uploadInstDialog.onDialogClosed = (_event) ->
|
||||
{
|
||||
uploadInstDialog.onDialogClosed = (_event) -> {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
if (_event.button == DialogButton.APPLY)
|
||||
{
|
||||
var songMetadataDialog = openSongMetadataDialog(state);
|
||||
songMetadataDialog.onDialogClosed = (_event) ->
|
||||
{
|
||||
songMetadataDialog.onDialogClosed = (_event) -> {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
if (_event.button == DialogButton.APPLY)
|
||||
{
|
||||
var uploadVocalsDialog = openUploadVocalsDialog(state);
|
||||
var uploadVocalsDialog = openUploadVocalsDialog(state, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -145,8 +117,7 @@ class ChartEditorDialogHandler
|
||||
|
||||
var linkTemplateSong:Link = new Link();
|
||||
linkTemplateSong.text = songName;
|
||||
linkTemplateSong.onClick = (_event) ->
|
||||
{
|
||||
linkTemplateSong.onClick = (_event) -> {
|
||||
dialog.hideDialog(DialogButton.CANCEL);
|
||||
|
||||
// Load song from template
|
||||
@@ -165,72 +136,111 @@ class ChartEditorDialogHandler
|
||||
|
||||
var instrumentalBox:Box = dialog.findComponent('instrumentalBox', Box);
|
||||
|
||||
instrumentalBox.onMouseOver = (_event) ->
|
||||
{
|
||||
instrumentalBox.onMouseOver = (_event) -> {
|
||||
instrumentalBox.swapClass('upload-bg', 'upload-bg-hover');
|
||||
Cursor.cursorMode = Pointer;
|
||||
}
|
||||
|
||||
instrumentalBox.onMouseOut = (_event) ->
|
||||
{
|
||||
instrumentalBox.onMouseOut = (_event) -> {
|
||||
instrumentalBox.swapClass('upload-bg-hover', 'upload-bg');
|
||||
Cursor.cursorMode = Default;
|
||||
}
|
||||
|
||||
var onDropFile:String->Void;
|
||||
|
||||
instrumentalBox.onClick = (_event) ->
|
||||
{
|
||||
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);
|
||||
}
|
||||
{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) ->
|
||||
{
|
||||
onDropFile = (path:String) -> {
|
||||
trace('Dropped file: ' + path);
|
||||
state.loadInstrumentalFromPath(path);
|
||||
dialog.hideDialog(DialogButton.APPLY);
|
||||
removeDropHandler(onDropFile);
|
||||
};
|
||||
|
||||
addDropHandler(onDropFile);
|
||||
addDropHandler(instrumentalBox, onDropFile);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
static function addDropHandler(handler:String->Void)
|
||||
static var dropHandlers:Array<
|
||||
{
|
||||
component:Component,
|
||||
handler:(String->Void)
|
||||
}> = [];
|
||||
|
||||
static function addDropHandler(component:Component, handler:String->Void):Void
|
||||
{
|
||||
#if desktop
|
||||
FlxG.stage.window.onDropFile.add(handler);
|
||||
if (!FlxG.stage.window.onDropFile.has(onDropFile)) FlxG.stage.window.onDropFile.add(onDropFile);
|
||||
|
||||
dropHandlers.push(
|
||||
{
|
||||
component: component,
|
||||
handler: handler
|
||||
});
|
||||
#else
|
||||
trace('addDropHandler not implemented for this platform');
|
||||
#end
|
||||
}
|
||||
|
||||
static function removeDropHandler(handler:String->Void)
|
||||
static function removeDropHandler(handler:String->Void):Void
|
||||
{
|
||||
#if desktop
|
||||
FlxG.stage.window.onDropFile.remove(handler);
|
||||
#end
|
||||
}
|
||||
|
||||
static function clearDropHandlers():Void
|
||||
{
|
||||
#if desktop
|
||||
dropHandlers = [];
|
||||
FlxG.stage.window.onDropFile.remove(onDropFile);
|
||||
#end
|
||||
}
|
||||
|
||||
static function onDropFile(path:String):Void
|
||||
{
|
||||
// a VERY short timer to wait for the mouse position to update
|
||||
new FlxTimer().start(0.01, function(_) {
|
||||
trace("mouseX: " + FlxG.mouse.screenX + ", mouseY: " + FlxG.mouse.screenY);
|
||||
|
||||
for (handler in dropHandlers)
|
||||
{
|
||||
if (handler.component.hitTest(FlxG.mouse.screenX, FlxG.mouse.screenY))
|
||||
{
|
||||
trace('File dropped on component! ' + handler.component.id);
|
||||
handler.handler(path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
trace('File dropped on nothing!' + path);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the dialog in the wizard where the user can set song metadata like name and artist and BPM.
|
||||
* @param state The ChartEditorState instance.
|
||||
* @return The dialog to open.
|
||||
*/
|
||||
public static function openSongMetadataDialog(state:ChartEditorState):Dialog
|
||||
{
|
||||
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_SONG_METADATA_LAYOUT, true, false);
|
||||
|
||||
var dialogSongName:TextField = dialog.findComponent('dialogSongName', TextField);
|
||||
dialogSongName.onChange = (event:UIEvent) ->
|
||||
{
|
||||
var valid = event.target.text != null && event.target.text != "";
|
||||
dialogSongName.onChange = function(event:UIEvent) {
|
||||
var valid:Bool = event.target.text != null && event.target.text != '';
|
||||
|
||||
if (valid)
|
||||
{
|
||||
@@ -245,9 +255,8 @@ class ChartEditorDialogHandler
|
||||
state.currentSongMetadata.songName = null;
|
||||
|
||||
var dialogSongArtist:TextField = dialog.findComponent('dialogSongArtist', TextField);
|
||||
dialogSongArtist.onChange = (event:UIEvent) ->
|
||||
{
|
||||
var valid = event.target.text != null && event.target.text != "";
|
||||
dialogSongArtist.onChange = function(event:UIEvent) {
|
||||
var valid:Bool = event.target.text != null && event.target.text != '';
|
||||
|
||||
if (valid)
|
||||
{
|
||||
@@ -262,8 +271,7 @@ class ChartEditorDialogHandler
|
||||
state.currentSongMetadata.artist = null;
|
||||
|
||||
var dialogStage:DropDown = dialog.findComponent('dialogStage', DropDown);
|
||||
dialogStage.onChange = (event:UIEvent) ->
|
||||
{
|
||||
dialogStage.onChange = function(event:UIEvent) {
|
||||
var valid = event.data != null && event.data.id != null;
|
||||
|
||||
if (event.data.id == null) return;
|
||||
@@ -272,16 +280,14 @@ class ChartEditorDialogHandler
|
||||
state.currentSongMetadata.playData.stage = null;
|
||||
|
||||
var dialogNoteSkin:DropDown = dialog.findComponent('dialogNoteSkin', DropDown);
|
||||
dialogNoteSkin.onChange = (event:UIEvent) ->
|
||||
{
|
||||
dialogNoteSkin.onChange = (event:UIEvent) -> {
|
||||
if (event.data.id == null) return;
|
||||
state.currentSongMetadata.playData.noteSkin = event.data.id;
|
||||
};
|
||||
state.currentSongMetadata.playData.noteSkin = null;
|
||||
|
||||
var dialogBPM:NumberStepper = dialog.findComponent('dialogBPM', NumberStepper);
|
||||
dialogBPM.onChange = (event:UIEvent) ->
|
||||
{
|
||||
dialogBPM.onChange = (event:UIEvent) -> {
|
||||
if (event.value == null || event.value <= 0) return;
|
||||
|
||||
var timeChanges = state.currentSongMetadata.timeChanges;
|
||||
@@ -301,11 +307,9 @@ class ChartEditorDialogHandler
|
||||
|
||||
var dialogCharGrid:PropertyGrid = dialog.findComponent('dialogCharGrid', PropertyGrid);
|
||||
var dialogCharAdd:Button = dialog.findComponent('dialogCharAdd', Button);
|
||||
dialogCharAdd.onClick = (_event) ->
|
||||
{
|
||||
dialogCharAdd.onClick = (_event) -> {
|
||||
var charGroup:PropertyGroup;
|
||||
charGroup = buildCharGroup(state, null, () ->
|
||||
{
|
||||
charGroup = buildCharGroup(state, null, () -> {
|
||||
dialogCharGrid.removeComponent(charGroup);
|
||||
});
|
||||
dialogCharGrid.addComponent(charGroup);
|
||||
@@ -317,8 +321,7 @@ class ChartEditorDialogHandler
|
||||
dialogCharGrid.addComponent(buildCharGroup(state, 'bf', null));
|
||||
|
||||
var dialogContinue:Button = dialog.findComponent('dialogContinue', Button);
|
||||
dialogContinue.onClick = (_event) ->
|
||||
{
|
||||
dialogContinue.onClick = (_event) -> {
|
||||
dialog.hideDialog(DialogButton.APPLY);
|
||||
};
|
||||
|
||||
@@ -329,8 +332,7 @@ class ChartEditorDialogHandler
|
||||
{
|
||||
var groupKey = key;
|
||||
|
||||
var getCharData = () ->
|
||||
{
|
||||
var getCharData = () -> {
|
||||
if (groupKey == null) groupKey = 'newChar${state.currentSongMetadata.playData.playableChars.keys().count()}';
|
||||
|
||||
var result = state.currentSongMetadata.playData.playableChars.get(groupKey);
|
||||
@@ -342,16 +344,14 @@ class ChartEditorDialogHandler
|
||||
return result;
|
||||
}
|
||||
|
||||
var moveCharGroup = (target:String) ->
|
||||
{
|
||||
var moveCharGroup = (target:String) -> {
|
||||
var charData = getCharData();
|
||||
state.currentSongMetadata.playData.playableChars.remove(groupKey);
|
||||
state.currentSongMetadata.playData.playableChars.set(target, charData);
|
||||
groupKey = target;
|
||||
}
|
||||
|
||||
var removeGroup = () ->
|
||||
{
|
||||
var removeGroup = () -> {
|
||||
state.currentSongMetadata.playData.playableChars.remove(groupKey);
|
||||
removeFunc();
|
||||
}
|
||||
@@ -361,8 +361,7 @@ class ChartEditorDialogHandler
|
||||
var charGroup:PropertyGroup = cast state.buildComponent(CHART_EDITOR_DIALOG_SONG_METADATA_CHARGROUP_LAYOUT);
|
||||
|
||||
var charGroupPlayer:DropDown = charGroup.findComponent('charGroupPlayer', DropDown);
|
||||
charGroupPlayer.onChange = (event:UIEvent) ->
|
||||
{
|
||||
charGroupPlayer.onChange = (event:UIEvent) -> {
|
||||
charGroup.text = event.data.text;
|
||||
moveCharGroup(event.data.id);
|
||||
};
|
||||
@@ -374,22 +373,19 @@ class ChartEditorDialogHandler
|
||||
}
|
||||
|
||||
var charGroupOpponent:DropDown = charGroup.findComponent('charGroupOpponent', DropDown);
|
||||
charGroupOpponent.onChange = (event:UIEvent) ->
|
||||
{
|
||||
charGroupOpponent.onChange = (event:UIEvent) -> {
|
||||
charData.opponent = event.data.id;
|
||||
};
|
||||
charGroupOpponent.value = getCharData().opponent;
|
||||
|
||||
var charGroupGirlfriend:DropDown = charGroup.findComponent('charGroupGirlfriend', DropDown);
|
||||
charGroupGirlfriend.onChange = (event:UIEvent) ->
|
||||
{
|
||||
charGroupGirlfriend.onChange = (event:UIEvent) -> {
|
||||
charData.girlfriend = event.data.id;
|
||||
};
|
||||
charGroupGirlfriend.value = getCharData().girlfriend;
|
||||
|
||||
var charGroupRemove:Button = charGroup.findComponent('charGroupRemove', Button);
|
||||
charGroupRemove.onClick = (_event:MouseEvent) ->
|
||||
{
|
||||
charGroupRemove.onClick = (_event:MouseEvent) -> {
|
||||
removeGroup();
|
||||
};
|
||||
|
||||
@@ -413,7 +409,11 @@ class ChartEditorDialogHandler
|
||||
|
||||
var dialogContainer = dialog.findComponent('vocalContainer');
|
||||
|
||||
var onDropFile:String->Void;
|
||||
var dialogNoVocals:Button = dialog.findComponent('dialogNoVocals', Button);
|
||||
dialogNoVocals.onClick = function(_event) {
|
||||
// Dismiss
|
||||
dialog.hideDialog(DialogButton.APPLY);
|
||||
};
|
||||
|
||||
for (charKey in charIdsForVocals)
|
||||
{
|
||||
@@ -426,39 +426,46 @@ class ChartEditorDialogHandler
|
||||
var vocalsEntryLabel:Label = vocalsEntry.findComponent('vocalsEntryLabel', Label);
|
||||
vocalsEntryLabel.text = 'Click to browse for a vocal track for $charName.';
|
||||
|
||||
vocalsEntry.onClick = (_event) ->
|
||||
{
|
||||
var onDropFile:String->Void = function(fullPath:String) {
|
||||
trace('Selected file: $fullPath');
|
||||
var directory:String = Path.directory(fullPath);
|
||||
var filename:String = Path.withoutDirectory(directory);
|
||||
|
||||
vocalsEntryLabel.text = 'Vocals for $charName (click to browse)\n${filename}';
|
||||
state.loadVocalsFromPath(fullPath, charKey);
|
||||
dialogNoVocals.hidden = true;
|
||||
removeDropHandler(onDropFile);
|
||||
};
|
||||
|
||||
vocalsEntry.onClick = function(_event) {
|
||||
Dialogs.openBinaryFile('Open $charName Vocals', [
|
||||
{label: "Audio File (.ogg)", extension: "ogg"}], function(selectedFile)
|
||||
{
|
||||
if (selectedFile != null)
|
||||
{
|
||||
trace('Selected file: ' + selectedFile.name + "~" + selectedFile.fullPath);
|
||||
vocalsEntryLabel.text = 'Vocals for $charName (click to browse)\n${selectedFile.name}';
|
||||
state.loadVocalsFromBytes(selectedFile.bytes);
|
||||
removeDropHandler(onDropFile);
|
||||
}
|
||||
{label: 'Audio File (.ogg)', extension: 'ogg'}], function(selectedFile) {
|
||||
if (selectedFile != null)
|
||||
{
|
||||
trace('Selected file: ' + selectedFile.name);
|
||||
vocalsEntryLabel.text = 'Vocals for $charName (click to browse)\n${selectedFile.name}';
|
||||
state.loadVocalsFromBytes(selectedFile.bytes, charKey);
|
||||
dialogNoVocals.hidden = true;
|
||||
removeDropHandler(onDropFile);
|
||||
}
|
||||
});
|
||||
|
||||
// onDropFile
|
||||
addDropHandler(vocalsEntry, onDropFile);
|
||||
}
|
||||
|
||||
dialogContainer.addComponent(vocalsEntry);
|
||||
}
|
||||
|
||||
var dialogContinue:Button = dialog.findComponent('dialogContinue', Button);
|
||||
dialogContinue.onClick = (_event) ->
|
||||
{
|
||||
dialogContinue.onClick = function(_event) {
|
||||
// Dismiss
|
||||
dialog.hideDialog(DialogButton.APPLY);
|
||||
};
|
||||
|
||||
// TODO: Redo the logic for file drop handler to be more robust.
|
||||
// We need to distinguish which component the mouse is over when the file is dropped.
|
||||
|
||||
onDropFile = (path:String) ->
|
||||
{
|
||||
trace('Dropped file: ' + path);
|
||||
};
|
||||
addDropHandler(onDropFile);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@@ -483,8 +490,7 @@ class ChartEditorDialogHandler
|
||||
dialog.showDialog(modal);
|
||||
|
||||
state.isHaxeUIDialogOpen = true;
|
||||
dialog.onDialogClosed = (_event) ->
|
||||
{
|
||||
dialog.onDialogClosed = (_event) -> {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user