mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-27 10:05:41 -05:00
Added legacy importer
This commit is contained in:
parent
ac876c2f59
commit
3005aa1f3b
5 changed files with 722 additions and 138 deletions
131
source/funkin/play/song/formats/FNFLegacy.hx
Normal file
131
source/funkin/play/song/formats/FNFLegacy.hx
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
package funkin.play.song.formats;
|
||||||
|
|
||||||
|
typedef FNFLegacy =
|
||||||
|
{
|
||||||
|
var song:LegacySongData;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef LegacySongData =
|
||||||
|
{
|
||||||
|
var player1:String; // Boyfriend
|
||||||
|
var player2:String; // Opponent
|
||||||
|
|
||||||
|
var speed:LegacyScrollSpeeds;
|
||||||
|
var stageDefault:String;
|
||||||
|
var bpm:Float;
|
||||||
|
var notes:LegacyNoteData;
|
||||||
|
var song:String; // Song name
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef LegacyScrollSpeeds =
|
||||||
|
{
|
||||||
|
var easy:Float;
|
||||||
|
var normal:Float;
|
||||||
|
var hard:Float;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef LegacyNoteData =
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The easy difficulty.
|
||||||
|
*/
|
||||||
|
var ?easy:Array<LegacyNoteSection>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The normal difficulty.
|
||||||
|
*/
|
||||||
|
var ?normal:Array<LegacyNoteSection>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hard difficulty.
|
||||||
|
*/
|
||||||
|
var ?hard:Array<LegacyNoteSection>;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef LegacyNoteSection =
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Whether the section is a must-hit section.
|
||||||
|
* If true, 0-3 are boyfriends notes, 4-7 are opponents notes.
|
||||||
|
* If false, 0-3 are opponents notes, 4-7 are boyfriends notes.
|
||||||
|
*/
|
||||||
|
var mustHitSection:Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of note data:
|
||||||
|
* - Direction
|
||||||
|
* - Time (ms)
|
||||||
|
* - Sustain Duration (ms)
|
||||||
|
* - Note kind (true = "alt", or string)
|
||||||
|
*/
|
||||||
|
var sectionNotes:Array<LegacyNote>;
|
||||||
|
|
||||||
|
var typeOfSection:Int;
|
||||||
|
var lengthInSteps:Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notes in the old format are stored as an Array<Dynamic>
|
||||||
|
*/
|
||||||
|
abstract LegacyNote(Array<Dynamic>)
|
||||||
|
{
|
||||||
|
public var time(get, set):Float;
|
||||||
|
|
||||||
|
function get_time():Float
|
||||||
|
{
|
||||||
|
return this[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_time(value:Float):Float
|
||||||
|
{
|
||||||
|
return this[0] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var data(get, set):Int;
|
||||||
|
|
||||||
|
function get_data():Int
|
||||||
|
{
|
||||||
|
return this[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_data(value:Int):Int
|
||||||
|
{
|
||||||
|
return this[1] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData(mustHitSection:Bool):Int
|
||||||
|
{
|
||||||
|
if (mustHitSection) return this[1];
|
||||||
|
|
||||||
|
return (this[1] + 4) % 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var length(get, set):Float;
|
||||||
|
|
||||||
|
function get_length():Float
|
||||||
|
{
|
||||||
|
if (this.length < 3) return 0.0;
|
||||||
|
return this[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_length(value:Float):Float
|
||||||
|
{
|
||||||
|
return this[2] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var kind(get, set):String;
|
||||||
|
|
||||||
|
function get_kind():String
|
||||||
|
{
|
||||||
|
if (this.length < 4) return 'normal';
|
||||||
|
|
||||||
|
if (Std.isOfType(this[3], Bool)) return this[3] ? 'alt' : 'normal';
|
||||||
|
|
||||||
|
return this[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_kind(value:String):String
|
||||||
|
{
|
||||||
|
return this[3] = value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,21 @@
|
||||||
package funkin.ui.debug.charting;
|
package funkin.ui.debug.charting;
|
||||||
|
|
||||||
|
import funkin.play.character.CharacterData;
|
||||||
|
import funkin.util.Constants;
|
||||||
|
import funkin.util.SerializerUtil;
|
||||||
|
import funkin.play.song.SongData.SongChartData;
|
||||||
|
import funkin.play.song.SongData.SongMetadata;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import funkin.input.Cursor;
|
import funkin.input.Cursor;
|
||||||
import funkin.play.character.BaseCharacter;
|
import funkin.play.character.BaseCharacter;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import funkin.play.song.Song;
|
import funkin.play.song.Song;
|
||||||
|
import funkin.play.song.SongMigrator;
|
||||||
|
import funkin.play.song.SongValidator;
|
||||||
import funkin.play.song.SongData.SongDataParser;
|
import funkin.play.song.SongData.SongDataParser;
|
||||||
import funkin.play.song.SongData.SongPlayableChar;
|
import funkin.play.song.SongData.SongPlayableChar;
|
||||||
import funkin.play.song.SongData.SongTimeChange;
|
import funkin.play.song.SongData.SongTimeChange;
|
||||||
|
import funkin.util.FileUtil;
|
||||||
import haxe.io.Path;
|
import haxe.io.Path;
|
||||||
import haxe.ui.components.Button;
|
import haxe.ui.components.Button;
|
||||||
import haxe.ui.components.DropDown;
|
import haxe.ui.components.DropDown;
|
||||||
|
@ -40,6 +48,9 @@ class ChartEditorDialogHandler
|
||||||
static final CHART_EDITOR_DIALOG_SONG_METADATA_CHARGROUP_LAYOUT:String = Paths.ui('chart-editor/dialogs/song-metadata-chargroup');
|
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_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_UPLOAD_VOCALS_ENTRY_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-vocals-entry');
|
||||||
|
static final CHART_EDITOR_DIALOG_OPEN_CHART_LAYOUT:String = Paths.ui('chart-editor/dialogs/open-chart');
|
||||||
|
static final CHART_EDITOR_DIALOG_OPEN_CHART_ENTRY_LAYOUT:String = Paths.ui('chart-editor/dialogs/open-chart-entry');
|
||||||
|
static final CHART_EDITOR_DIALOG_IMPORT_CHART_LAYOUT:String = Paths.ui('chart-editor/dialogs/import-chart');
|
||||||
static final CHART_EDITOR_DIALOG_USER_GUIDE_LAYOUT:String = Paths.ui('chart-editor/dialogs/user-guide');
|
static final CHART_EDITOR_DIALOG_USER_GUIDE_LAYOUT:String = Paths.ui('chart-editor/dialogs/user-guide');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,9 +82,141 @@ class ChartEditorDialogHandler
|
||||||
//
|
//
|
||||||
// Create Song Wizard
|
// Create Song Wizard
|
||||||
//
|
//
|
||||||
|
openCreateSongWizard(state, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var linkImportChartLegacy:Link = dialog.findComponent('splashImportChartLegacy', Link);
|
||||||
|
linkImportChartLegacy.onClick = function(_event) {
|
||||||
|
// Hide the welcome dialog
|
||||||
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
|
||||||
|
// Open the "Import Chart" dialog
|
||||||
|
openImportChartWizard(state, 'legacy', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
var buttonBrowse:Button = dialog.findComponent('splashBrowse', Button);
|
||||||
|
buttonBrowse.onClick = function(_event) {
|
||||||
|
// Hide the welcome dialog
|
||||||
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
|
||||||
|
// Open the "Open Chart" dialog
|
||||||
|
openBrowseWizard(state, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var splashTemplateContainer:VBox = dialog.findComponent('splashTemplateContainer', VBox);
|
||||||
|
|
||||||
|
var songList:Array<String> = SongDataParser.listSongIds();
|
||||||
|
// Sort alphabetically
|
||||||
|
songList.sort((a, b) -> a > b ? 1 : -1);
|
||||||
|
|
||||||
|
for (targetSongId in songList)
|
||||||
|
{
|
||||||
|
var songData:Song = SongDataParser.fetchSong(targetSongId);
|
||||||
|
|
||||||
|
if (songData == null) continue;
|
||||||
|
|
||||||
|
var songName:String = songData.getDifficulty().songName;
|
||||||
|
|
||||||
|
var linkTemplateSong:Link = new Link();
|
||||||
|
linkTemplateSong.text = songName;
|
||||||
|
linkTemplateSong.onClick = function(_event) {
|
||||||
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
|
||||||
|
// Load song from template
|
||||||
|
state.loadSongAsTemplate(targetSongId);
|
||||||
|
}
|
||||||
|
|
||||||
|
splashTemplateContainer.addComponent(linkTemplateSong);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the wizard for opening an existing chart from individual files.
|
||||||
|
* @param state
|
||||||
|
* @param closable
|
||||||
|
*/
|
||||||
|
public static function openBrowseWizard(state:ChartEditorState, closable:Bool):Void
|
||||||
|
{
|
||||||
|
// Open the "Open Chart" wizard
|
||||||
|
// Step 1. Open Chart
|
||||||
|
var openChartDialog:Dialog = openChartDialog(state);
|
||||||
|
openChartDialog.onDialogClosed = function(_event) {
|
||||||
|
state.isHaxeUIDialogOpen = false;
|
||||||
|
if (_event.button == DialogButton.APPLY)
|
||||||
|
{
|
||||||
|
// Step 2. Upload instrumental
|
||||||
|
var uploadInstDialog:Dialog = openUploadInstDialog(state, closable);
|
||||||
|
uploadInstDialog.onDialogClosed = function(_event) {
|
||||||
|
state.isHaxeUIDialogOpen = false;
|
||||||
|
if (_event.button == DialogButton.APPLY)
|
||||||
|
{
|
||||||
|
// Step 3. Upload Vocals
|
||||||
|
// NOTE: Uploading vocals is optional, so we don't need to check if the user cancelled the wizard.
|
||||||
|
var uploadVocalsDialog:Dialog = openUploadVocalsDialog(state, closable); // var uploadVocalsDialog:Dialog
|
||||||
|
uploadVocalsDialog.onDialogClosed = function(_event) {
|
||||||
|
state.isHaxeUIDialogOpen = false;
|
||||||
|
state.postLoadInstrumental();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// User cancelled the wizard! Back to the welcome dialog.
|
||||||
|
openWelcomeDialog(state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// User cancelled the wizard! Back to the welcome dialog.
|
||||||
|
openWelcomeDialog(state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function openImportChartWizard(state:ChartEditorState, format:String, closable:Bool):Void
|
||||||
|
{
|
||||||
|
// Open the "Open Chart" wizard
|
||||||
|
// Step 1. Open Chart
|
||||||
|
var openChartDialog:Dialog = openImportChartDialog(state, format);
|
||||||
|
openChartDialog.onDialogClosed = function(_event) {
|
||||||
|
state.isHaxeUIDialogOpen = false;
|
||||||
|
if (_event.button == DialogButton.APPLY)
|
||||||
|
{
|
||||||
|
// Step 2. Upload instrumental
|
||||||
|
var uploadInstDialog:Dialog = openUploadInstDialog(state, closable);
|
||||||
|
uploadInstDialog.onDialogClosed = function(_event) {
|
||||||
|
state.isHaxeUIDialogOpen = false;
|
||||||
|
if (_event.button == DialogButton.APPLY)
|
||||||
|
{
|
||||||
|
// Step 3. Upload Vocals
|
||||||
|
// NOTE: Uploading vocals is optional, so we don't need to check if the user cancelled the wizard.
|
||||||
|
var uploadVocalsDialog:Dialog = openUploadVocalsDialog(state, closable); // var uploadVocalsDialog:Dialog
|
||||||
|
uploadVocalsDialog.onDialogClosed = function(_event) {
|
||||||
|
state.isHaxeUIDialogOpen = false;
|
||||||
|
state.postLoadInstrumental();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// User cancelled the wizard! Back to the welcome dialog.
|
||||||
|
openWelcomeDialog(state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// User cancelled the wizard! Back to the welcome dialog.
|
||||||
|
openWelcomeDialog(state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function openCreateSongWizard(state:ChartEditorState, closable:Bool):Void
|
||||||
|
{
|
||||||
// Step 1. Upload Instrumental
|
// Step 1. Upload Instrumental
|
||||||
var uploadInstDialog:Dialog = openUploadInstDialog(state, false);
|
var uploadInstDialog:Dialog = openUploadInstDialog(state, closable);
|
||||||
uploadInstDialog.onDialogClosed = function(_event) {
|
uploadInstDialog.onDialogClosed = function(_event) {
|
||||||
state.isHaxeUIDialogOpen = false;
|
state.isHaxeUIDialogOpen = false;
|
||||||
if (_event.button == DialogButton.APPLY)
|
if (_event.button == DialogButton.APPLY)
|
||||||
|
@ -103,33 +246,6 @@ class ChartEditorDialogHandler
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var splashTemplateContainer:VBox = dialog.findComponent('splashTemplateContainer', VBox);
|
|
||||||
|
|
||||||
var songList:Array<String> = SongDataParser.listSongIds();
|
|
||||||
|
|
||||||
for (targetSongId in songList)
|
|
||||||
{
|
|
||||||
var songData:Song = SongDataParser.fetchSong(targetSongId);
|
|
||||||
|
|
||||||
if (songData == null) continue;
|
|
||||||
|
|
||||||
var songName:String = songData.getDifficulty().songName;
|
|
||||||
|
|
||||||
var linkTemplateSong:Link = new Link();
|
|
||||||
linkTemplateSong.text = songName;
|
|
||||||
linkTemplateSong.onClick = function(_event) {
|
|
||||||
dialog.hideDialog(DialogButton.CANCEL);
|
|
||||||
|
|
||||||
// Load song from template
|
|
||||||
state.loadSongAsTemplate(targetSongId);
|
|
||||||
}
|
|
||||||
|
|
||||||
splashTemplateContainer.addComponent(linkTemplateSong);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and opens a dialog where the user uploads an instrumental for the current song.
|
* Builds and opens a dialog where the user uploads an instrumental for the current song.
|
||||||
* @param state The current chart editor state.
|
* @param state The current chart editor state.
|
||||||
|
@ -214,11 +330,20 @@ class ChartEditorDialogHandler
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var message:String = if (!ChartEditorState.SUPPORTED_MUSIC_FORMATS.contains(path.ext))
|
||||||
|
{
|
||||||
|
'File format (${path.ext}) not supported for instrumental track (${path.file}.${path.ext})';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
'Failed to load instrumental track (${path.file}.${path.ext})';
|
||||||
|
}
|
||||||
|
|
||||||
// Tell the user the load was successful.
|
// Tell the user the load was successful.
|
||||||
NotificationManager.instance.addNotification(
|
NotificationManager.instance.addNotification(
|
||||||
{
|
{
|
||||||
title: 'Failure',
|
title: 'Failure',
|
||||||
body: 'Failed to load instrumental track (${path.file}.${path.ext})',
|
body: message,
|
||||||
type: NotificationType.Error,
|
type: NotificationType.Error,
|
||||||
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
});
|
});
|
||||||
|
@ -418,12 +543,6 @@ class ChartEditorDialogHandler
|
||||||
moveCharGroup(event.data.id);
|
moveCharGroup(event.data.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (key == null)
|
|
||||||
{
|
|
||||||
// Find the next available player character.
|
|
||||||
trace(charGroupPlayer.dataSource.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
var charGroupOpponent:DropDown = charGroup.findComponent('charGroupOpponent', DropDown);
|
var charGroupOpponent:DropDown = charGroup.findComponent('charGroupOpponent', DropDown);
|
||||||
charGroupOpponent.onChange = function(event:UIEvent) {
|
charGroupOpponent.onChange = function(event:UIEvent) {
|
||||||
charData.opponent = event.data.id;
|
charData.opponent = event.data.id;
|
||||||
|
@ -481,8 +600,8 @@ class ChartEditorDialogHandler
|
||||||
for (charKey in charIdsForVocals)
|
for (charKey in charIdsForVocals)
|
||||||
{
|
{
|
||||||
trace('Adding vocal upload for character ${charKey}');
|
trace('Adding vocal upload for character ${charKey}');
|
||||||
var charMetadata:BaseCharacter = CharacterDataParser.fetchCharacter(charKey);
|
var charMetadata:CharacterData = CharacterDataParser.fetchCharacterData(charKey);
|
||||||
var charName:String = charMetadata.characterName;
|
var charName:String = charMetadata.name;
|
||||||
|
|
||||||
var vocalsEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_UPLOAD_VOCALS_ENTRY_LAYOUT);
|
var vocalsEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_UPLOAD_VOCALS_ENTRY_LAYOUT);
|
||||||
|
|
||||||
|
@ -509,11 +628,20 @@ class ChartEditorDialogHandler
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var message:String = if (!ChartEditorState.SUPPORTED_MUSIC_FORMATS.contains(path.ext))
|
||||||
|
{
|
||||||
|
'File format (${path.ext}) not supported for vocal track (${path.file}.${path.ext})';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
'Failed to load vocal track (${path.file}.${path.ext})';
|
||||||
|
}
|
||||||
|
|
||||||
// Vocals failed to load.
|
// Vocals failed to load.
|
||||||
NotificationManager.instance.addNotification(
|
NotificationManager.instance.addNotification(
|
||||||
{
|
{
|
||||||
title: 'Failure',
|
title: 'Failure',
|
||||||
body: 'Failed to load vocal track (${path.file}.${path.ext})',
|
body: message,
|
||||||
type: NotificationType.Error,
|
type: NotificationType.Error,
|
||||||
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
});
|
});
|
||||||
|
@ -550,6 +678,284 @@ class ChartEditorDialogHandler
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds and opens a dialog where the user upload the JSON files for a 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.
|
||||||
|
*/
|
||||||
|
@:haxe.warning('-WVarInit')
|
||||||
|
public static function openChartDialog(state:ChartEditorState, ?closable:Bool = true):Dialog
|
||||||
|
{
|
||||||
|
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_OPEN_CHART_LAYOUT, true, closable);
|
||||||
|
|
||||||
|
var buttonCancel:Button = dialog.findComponent('dialogCancel', Button);
|
||||||
|
buttonCancel.onClick = function(_event) {
|
||||||
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
var chartContainerA:Component = dialog.findComponent('chartContainerA');
|
||||||
|
var chartContainerB:Component = dialog.findComponent('chartContainerB');
|
||||||
|
|
||||||
|
var songMetadata:Map<String, SongMetadata> = [];
|
||||||
|
var songChartData:Map<String, SongChartData> = [];
|
||||||
|
|
||||||
|
var buttonContinue:Button = dialog.findComponent('dialogContinue', Button);
|
||||||
|
buttonContinue.onClick = function(_event) {
|
||||||
|
state.loadSong(songMetadata, songChartData);
|
||||||
|
|
||||||
|
dialog.hideDialog(DialogButton.APPLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
var onDropFileMetadataVariation:String->Label->String->Void;
|
||||||
|
var onClickMetadataVariation:String->Label->UIEvent->Void;
|
||||||
|
var onDropFileChartDataVariation:String->Label->String->Void;
|
||||||
|
var onClickChartDataVariation:String->Label->UIEvent->Void;
|
||||||
|
|
||||||
|
var constructVariationEntries:Array<String>->Void = function(variations:Array<String>) {
|
||||||
|
// Clear the chart container.
|
||||||
|
while (chartContainerB.getComponentAt(0) != null)
|
||||||
|
{
|
||||||
|
chartContainerB.removeComponent(chartContainerB.getComponentAt(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build an entry for -chart.json.
|
||||||
|
var songDefaultChartDataEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_OPEN_CHART_ENTRY_LAYOUT);
|
||||||
|
var songDefaultChartDataEntryLabel:Label = songDefaultChartDataEntry.findComponent('chartEntryLabel', Label);
|
||||||
|
songDefaultChartDataEntryLabel.text = 'Drag and drop <song>-chart.json file, or click to browse.';
|
||||||
|
|
||||||
|
songDefaultChartDataEntry.onClick = onClickChartDataVariation.bind(Constants.DEFAULT_VARIATION).bind(songDefaultChartDataEntryLabel);
|
||||||
|
addDropHandler(songDefaultChartDataEntry, onDropFileChartDataVariation.bind(Constants.DEFAULT_VARIATION).bind(songDefaultChartDataEntryLabel));
|
||||||
|
chartContainerB.addComponent(songDefaultChartDataEntry);
|
||||||
|
|
||||||
|
for (variation in variations)
|
||||||
|
{
|
||||||
|
// Build entries for -metadata-<variation>.json.
|
||||||
|
var songVariationMetadataEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_OPEN_CHART_ENTRY_LAYOUT);
|
||||||
|
var songVariationMetadataEntryLabel:Label = songVariationMetadataEntry.findComponent('chartEntryLabel', Label);
|
||||||
|
songVariationMetadataEntryLabel.text = 'Drag and drop <song>-metadata-${variation}.json file, or click to browse.';
|
||||||
|
|
||||||
|
songVariationMetadataEntry.onClick = onClickMetadataVariation.bind(variation).bind(songVariationMetadataEntryLabel);
|
||||||
|
addDropHandler(songVariationMetadataEntry, onDropFileMetadataVariation.bind(variation).bind(songVariationMetadataEntryLabel));
|
||||||
|
chartContainerB.addComponent(songVariationMetadataEntry);
|
||||||
|
|
||||||
|
// Build entries for -chart-<variation>.json.
|
||||||
|
var songVariationChartDataEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_OPEN_CHART_ENTRY_LAYOUT);
|
||||||
|
var songVariationChartDataEntryLabel:Label = songVariationChartDataEntry.findComponent('chartEntryLabel', Label);
|
||||||
|
songVariationChartDataEntryLabel.text = 'Drag and drop <song>-chart-${variation}.json file, or click to browse.';
|
||||||
|
|
||||||
|
songVariationChartDataEntry.onClick = onClickChartDataVariation.bind(variation).bind(songVariationChartDataEntryLabel);
|
||||||
|
addDropHandler(songVariationChartDataEntry, onDropFileChartDataVariation.bind(variation).bind(songVariationChartDataEntryLabel));
|
||||||
|
chartContainerB.addComponent(songVariationChartDataEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDropFileMetadataVariation = function(variation:String, label:Label, pathStr:String) {
|
||||||
|
var path:Path = new Path(pathStr);
|
||||||
|
trace('Dropped JSON file (${path})');
|
||||||
|
|
||||||
|
var songMetadataJson:Dynamic = FileUtil.readJSONFromPath(path.toString());
|
||||||
|
var songMetadataVariation:SongMetadata = SongMigrator.migrateSongMetadata(songMetadataJson, 'import');
|
||||||
|
songMetadataVariation = SongValidator.validateSongMetadata(songMetadataVariation, 'import');
|
||||||
|
|
||||||
|
songMetadata.set(variation, songMetadataVariation);
|
||||||
|
|
||||||
|
// Tell the user the load was successful.
|
||||||
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Success',
|
||||||
|
body: 'Loaded metadata file (${path.file}.${path.ext})',
|
||||||
|
type: NotificationType.Success,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
|
||||||
|
label.text = 'Metadata file (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
|
||||||
|
|
||||||
|
if (variation == Constants.DEFAULT_VARIATION) constructVariationEntries(songMetadataVariation.playData.songVariations);
|
||||||
|
};
|
||||||
|
|
||||||
|
onClickMetadataVariation = function(variation:String, label:Label, _event:UIEvent) {
|
||||||
|
Dialogs.openBinaryFile('Open Chart ($variation) Metadata', [
|
||||||
|
{label: 'JSON File (.json)', extension: 'json'}], function(selectedFile) {
|
||||||
|
if (selectedFile != null)
|
||||||
|
{
|
||||||
|
trace('Selected file: ' + selectedFile.name);
|
||||||
|
|
||||||
|
var songMetadataJson:Dynamic = SerializerUtil.fromJSONBytes(selectedFile.bytes);
|
||||||
|
var songMetadataVariation:SongMetadata = SongMigrator.migrateSongMetadata(songMetadataJson, 'import');
|
||||||
|
songMetadataVariation = SongValidator.validateSongMetadata(songMetadataVariation, 'import');
|
||||||
|
songMetadataVariation.variation = variation;
|
||||||
|
|
||||||
|
songMetadata.set(variation, songMetadataVariation);
|
||||||
|
|
||||||
|
// Tell the user the load was successful.
|
||||||
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Success',
|
||||||
|
body: 'Loaded metadata file (${selectedFile.name})',
|
||||||
|
type: NotificationType.Success,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
|
||||||
|
label.text = 'Metadata file (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}';
|
||||||
|
|
||||||
|
if (variation == Constants.DEFAULT_VARIATION) constructVariationEntries(songMetadataVariation.playData.songVariations);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDropFileChartDataVariation = function(variation:String, label:Label, pathStr:String) {
|
||||||
|
var path:Path = new Path(pathStr);
|
||||||
|
trace('Dropped JSON file (${path})');
|
||||||
|
|
||||||
|
var songChartDataJson:Dynamic = FileUtil.readJSONFromPath(path.toString());
|
||||||
|
var songChartDataVariation:SongChartData = SongMigrator.migrateSongChartData(songChartDataJson, 'import');
|
||||||
|
songChartDataVariation = SongValidator.validateSongChartData(songChartDataVariation, 'import');
|
||||||
|
|
||||||
|
songChartData.set(variation, songChartDataVariation);
|
||||||
|
|
||||||
|
// Tell the user the load was successful.
|
||||||
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Success',
|
||||||
|
body: 'Loaded chart data file (${path.file}.${path.ext})',
|
||||||
|
type: NotificationType.Success,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
|
||||||
|
label.text = 'Chart data file (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
|
||||||
|
};
|
||||||
|
|
||||||
|
onClickChartDataVariation = function(variation:String, label:Label, _event:UIEvent) {
|
||||||
|
Dialogs.openBinaryFile('Open Chart ($variation) Metadata', [
|
||||||
|
{label: 'JSON File (.json)', extension: 'json'}], function(selectedFile) {
|
||||||
|
if (selectedFile != null)
|
||||||
|
{
|
||||||
|
trace('Selected file: ' + selectedFile.name);
|
||||||
|
|
||||||
|
var songChartDataJson:Dynamic = SerializerUtil.fromJSONBytes(selectedFile.bytes);
|
||||||
|
var songChartDataVariation:SongChartData = SongMigrator.migrateSongChartData(songChartDataJson, 'import');
|
||||||
|
songChartDataVariation = SongValidator.validateSongChartData(songChartDataVariation, 'import');
|
||||||
|
|
||||||
|
songChartData.set(variation, songChartDataVariation);
|
||||||
|
|
||||||
|
// Tell the user the load was successful.
|
||||||
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Success',
|
||||||
|
body: 'Loaded chart data file (${selectedFile.name})',
|
||||||
|
type: NotificationType.Success,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
|
||||||
|
label.text = 'Chart data file (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var metadataEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_OPEN_CHART_ENTRY_LAYOUT);
|
||||||
|
var metadataEntryLabel:Label = metadataEntry.findComponent('chartEntryLabel', Label);
|
||||||
|
metadataEntryLabel.text = 'Drag and drop <song>-metadata.json file, or click to browse.';
|
||||||
|
|
||||||
|
metadataEntry.onClick = onClickMetadataVariation.bind(Constants.DEFAULT_VARIATION).bind(metadataEntryLabel);
|
||||||
|
addDropHandler(metadataEntry, onDropFileMetadataVariation.bind(Constants.DEFAULT_VARIATION).bind(metadataEntryLabel));
|
||||||
|
|
||||||
|
chartContainerA.addComponent(metadataEntry);
|
||||||
|
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds and opens a dialog where the user can import a chart from an existing file format.
|
||||||
|
* @param state The current chart editor state.
|
||||||
|
* @param format The format to import from.
|
||||||
|
* @param closable
|
||||||
|
* @return Dialog
|
||||||
|
*/
|
||||||
|
public static function openImportChartDialog(state:ChartEditorState, format:String, ?closable:Bool = true):Dialog
|
||||||
|
{
|
||||||
|
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_IMPORT_CHART_LAYOUT, true, closable);
|
||||||
|
|
||||||
|
var prettyFormat:String = switch (format)
|
||||||
|
{
|
||||||
|
case 'legacy': 'FNF Legacy';
|
||||||
|
default: 'Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileFilter = switch (format)
|
||||||
|
{
|
||||||
|
case 'legacy': {label: 'JSON Data File (.json)', extension: 'json'};
|
||||||
|
default: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.title = 'Import Chart - ${prettyFormat}';
|
||||||
|
|
||||||
|
var buttonCancel:Button = dialog.findComponent('dialogCancel', Button);
|
||||||
|
|
||||||
|
buttonCancel.onClick = function(_event) {
|
||||||
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
var importBox:Box = dialog.findComponent('importBox', Box);
|
||||||
|
|
||||||
|
importBox.onMouseOver = function(_event) {
|
||||||
|
importBox.swapClass('upload-bg', 'upload-bg-hover');
|
||||||
|
Cursor.cursorMode = Pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
importBox.onMouseOut = function(_event) {
|
||||||
|
importBox.swapClass('upload-bg-hover', 'upload-bg');
|
||||||
|
Cursor.cursorMode = Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
var onDropFile:String->Void;
|
||||||
|
|
||||||
|
importBox.onClick = function(_event) {
|
||||||
|
Dialogs.openBinaryFile('Import Chart - ${prettyFormat}', [fileFilter], function(selectedFile:SelectedFileInfo) {
|
||||||
|
if (selectedFile != null)
|
||||||
|
{
|
||||||
|
trace('Selected file: ' + selectedFile.fullPath);
|
||||||
|
var selectedFileJson:Dynamic = SerializerUtil.fromJSONBytes(selectedFile.bytes);
|
||||||
|
var songMetadata:SongMetadata = SongMigrator.migrateSongMetadataFromLegacy(selectedFileJson);
|
||||||
|
var songChartData:SongChartData = SongMigrator.migrateSongChartDataFromLegacy(selectedFileJson);
|
||||||
|
|
||||||
|
state.loadSong([Constants.DEFAULT_VARIATION => songMetadata], [Constants.DEFAULT_VARIATION => songChartData]);
|
||||||
|
|
||||||
|
dialog.hideDialog(DialogButton.APPLY);
|
||||||
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Success',
|
||||||
|
body: 'Loaded chart file (${selectedFile.name})',
|
||||||
|
type: NotificationType.Success,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDropFile = function(pathStr:String) {
|
||||||
|
var path:Path = new Path(pathStr);
|
||||||
|
var selectedFileJson:Dynamic = FileUtil.readJSONFromPath(path.toString());
|
||||||
|
var songMetadata:SongMetadata = SongMigrator.migrateSongMetadataFromLegacy(selectedFileJson);
|
||||||
|
var songChartData:SongChartData = SongMigrator.migrateSongChartDataFromLegacy(selectedFileJson);
|
||||||
|
|
||||||
|
state.loadSong([Constants.DEFAULT_VARIATION => songMetadata], [Constants.DEFAULT_VARIATION => songChartData]);
|
||||||
|
|
||||||
|
dialog.hideDialog(DialogButton.APPLY);
|
||||||
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Success',
|
||||||
|
body: 'Loaded chart file (${path.file}.${path.ext})',
|
||||||
|
type: NotificationType.Success,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
addDropHandler(importBox, onDropFile);
|
||||||
|
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and opens a dialog displaying the user guide, providing guidance and help on how to use the chart editor.
|
* Builds and opens a dialog displaying the user guide, providing guidance and help on how to use the chart editor.
|
||||||
*
|
*
|
||||||
|
@ -569,6 +975,8 @@ class ChartEditorDialogHandler
|
||||||
static function openDialog(state:ChartEditorState, key:String, modal:Bool = true, closable:Bool = true):Dialog
|
static function openDialog(state:ChartEditorState, key:String, modal:Bool = true, closable:Bool = true):Dialog
|
||||||
{
|
{
|
||||||
var dialog:Dialog = cast state.buildComponent(key);
|
var dialog:Dialog = cast state.buildComponent(key);
|
||||||
|
if (dialog == null) return null;
|
||||||
|
|
||||||
dialog.destroyOnClose = true;
|
dialog.destroyOnClose = true;
|
||||||
dialog.closable = closable;
|
dialog.closable = closable;
|
||||||
dialog.showDialog(modal);
|
dialog.showDialog(modal);
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ChartEditorEventSprite extends FlxSprite
|
||||||
/**
|
/**
|
||||||
* The image used for all song events. Cached for performance.
|
* The image used for all song events. Cached for performance.
|
||||||
*/
|
*/
|
||||||
var eventGraphic:BitmapData;
|
static var eventSpriteBasic:BitmapData;
|
||||||
|
|
||||||
public function new(parent:ChartEditorState)
|
public function new(parent:ChartEditorState)
|
||||||
{
|
{
|
||||||
|
@ -40,12 +40,12 @@ class ChartEditorEventSprite extends FlxSprite
|
||||||
|
|
||||||
function buildGraphic():Void
|
function buildGraphic():Void
|
||||||
{
|
{
|
||||||
if (eventGraphic == null)
|
if (eventSpriteBasic == null)
|
||||||
{
|
{
|
||||||
eventGraphic = Assets.getBitmapData(Paths.image('ui/chart-editor/event'));
|
eventSpriteBasic = Assets.getBitmapData(Paths.image('ui/chart-editor/event'));
|
||||||
}
|
}
|
||||||
|
|
||||||
loadGraphic(eventGraphic);
|
loadGraphic(eventSpriteBasic);
|
||||||
setGraphicSize(ChartEditorState.GRID_SIZE);
|
setGraphicSize(ChartEditorState.GRID_SIZE);
|
||||||
this.updateHitbox();
|
this.updateHitbox();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ class ChartEditorThemeHandler
|
||||||
// An enum of typedefs or something?
|
// An enum of typedefs or something?
|
||||||
// ================================
|
// ================================
|
||||||
static final BACKGROUND_COLOR_LIGHT:FlxColor = 0xFF673AB7;
|
static final BACKGROUND_COLOR_LIGHT:FlxColor = 0xFF673AB7;
|
||||||
static final BACKGROUND_COLOR_DARK:FlxColor = 0xFF673AB7;
|
static final BACKGROUND_COLOR_DARK:FlxColor = 0xFF361E60;
|
||||||
|
|
||||||
// Color 1 of the grid pattern. Alternates with Color 2.
|
// Color 1 of the grid pattern. Alternates with Color 2.
|
||||||
static final GRID_COLOR_1_LIGHT:FlxColor = 0xFFE7E6E6;
|
static final GRID_COLOR_1_LIGHT:FlxColor = 0xFFE7E6E6;
|
||||||
|
@ -43,13 +43,11 @@ class ChartEditorThemeHandler
|
||||||
// Vertical divider between characters.
|
// Vertical divider between characters.
|
||||||
static final GRID_STRUMLINE_DIVIDER_COLOR_LIGHT:FlxColor = 0xFF111111;
|
static final GRID_STRUMLINE_DIVIDER_COLOR_LIGHT:FlxColor = 0xFF111111;
|
||||||
static final GRID_STRUMLINE_DIVIDER_COLOR_DARK:FlxColor = 0xFFC4C4C4;
|
static final GRID_STRUMLINE_DIVIDER_COLOR_DARK:FlxColor = 0xFFC4C4C4;
|
||||||
// static final GRID_STRUMLINE_DIVIDER_WIDTH:Float = 2;
|
|
||||||
static final GRID_STRUMLINE_DIVIDER_WIDTH:Float = ChartEditorState.GRID_SELECTION_BORDER_WIDTH;
|
static final GRID_STRUMLINE_DIVIDER_WIDTH:Float = ChartEditorState.GRID_SELECTION_BORDER_WIDTH;
|
||||||
|
|
||||||
// Horizontal divider between measures.
|
// Horizontal divider between measures.
|
||||||
static final GRID_MEASURE_DIVIDER_COLOR_LIGHT:FlxColor = 0xFF111111;
|
static final GRID_MEASURE_DIVIDER_COLOR_LIGHT:FlxColor = 0xFF111111;
|
||||||
static final GRID_MEASURE_DIVIDER_COLOR_DARK:FlxColor = 0xFFC4C4C4;
|
static final GRID_MEASURE_DIVIDER_COLOR_DARK:FlxColor = 0xFFC4C4C4;
|
||||||
// static final GRID_MEASURE_DIVIDER_WIDTH:Float = 2;
|
|
||||||
static final GRID_MEASURE_DIVIDER_WIDTH:Float = ChartEditorState.GRID_SELECTION_BORDER_WIDTH;
|
static final GRID_MEASURE_DIVIDER_WIDTH:Float = ChartEditorState.GRID_SELECTION_BORDER_WIDTH;
|
||||||
|
|
||||||
// Border on the square highlighting selected notes.
|
// Border on the square highlighting selected notes.
|
||||||
|
@ -66,6 +64,12 @@ class ChartEditorThemeHandler
|
||||||
static final PLAYHEAD_BLOCK_BORDER_COLOR:FlxColor = 0xFF9D0011;
|
static final PLAYHEAD_BLOCK_BORDER_COLOR:FlxColor = 0xFF9D0011;
|
||||||
static final PLAYHEAD_BLOCK_FILL_COLOR:FlxColor = 0xFFBD0231;
|
static final PLAYHEAD_BLOCK_FILL_COLOR:FlxColor = 0xFFBD0231;
|
||||||
|
|
||||||
|
static final TOTAL_COLUMN_COUNT:Int = ChartEditorState.STRUMLINE_SIZE * 2 + 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the theme is changed, this function updates all of the UI elements to match the new theme.
|
||||||
|
* @param state The ChartEditorState to update.
|
||||||
|
*/
|
||||||
public static function updateTheme(state:ChartEditorState):Void
|
public static function updateTheme(state:ChartEditorState):Void
|
||||||
{
|
{
|
||||||
updateBackground(state);
|
updateBackground(state);
|
||||||
|
@ -73,6 +77,10 @@ class ChartEditorThemeHandler
|
||||||
updateSelectionSquare(state);
|
updateSelectionSquare(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the tint of the background sprite to match the current theme.
|
||||||
|
* @param state The ChartEditorState to update.
|
||||||
|
*/
|
||||||
static function updateBackground(state:ChartEditorState):Void
|
static function updateBackground(state:ChartEditorState):Void
|
||||||
{
|
{
|
||||||
state.menuBG.color = switch (state.currentTheme)
|
state.menuBG.color = switch (state.currentTheme)
|
||||||
|
@ -85,7 +93,7 @@ class ChartEditorThemeHandler
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the checkerboard background image of the chart editor, and adds dividing lines to it.
|
* Builds the checkerboard background image of the chart editor, and adds dividing lines to it.
|
||||||
* @param dark Whether to draw the grid in a dark color instead of a light one.
|
* @param state The ChartEditorState to update.
|
||||||
*/
|
*/
|
||||||
static function updateGridBitmap(state:ChartEditorState):Void
|
static function updateGridBitmap(state:ChartEditorState):Void
|
||||||
{
|
{
|
||||||
|
@ -107,8 +115,8 @@ class ChartEditorThemeHandler
|
||||||
|
|
||||||
// 2 * (Strumline Size) + 1 grid squares wide, by (4 * quarter notes per measure) grid squares tall.
|
// 2 * (Strumline Size) + 1 grid squares wide, by (4 * quarter notes per measure) grid squares tall.
|
||||||
// This gets reused to fill the screen.
|
// This gets reused to fill the screen.
|
||||||
var gridWidth:Int = Std.int(ChartEditorState.GRID_SIZE * (ChartEditorState.STRUMLINE_SIZE * 2 + 1));
|
var gridWidth:Int = Std.int(ChartEditorState.GRID_SIZE * TOTAL_COLUMN_COUNT);
|
||||||
var gridHeight:Int = Std.int(ChartEditorState.GRID_SIZE * (Conductor.stepsPerMeasure));
|
var gridHeight:Int = Std.int(ChartEditorState.GRID_SIZE * Conductor.stepsPerMeasure);
|
||||||
state.gridBitmap = FlxGridOverlay.createGrid(ChartEditorState.GRID_SIZE, ChartEditorState.GRID_SIZE, gridWidth, gridHeight, true, gridColor1, gridColor2);
|
state.gridBitmap = FlxGridOverlay.createGrid(ChartEditorState.GRID_SIZE, ChartEditorState.GRID_SIZE, gridWidth, gridHeight, true, gridColor1, gridColor2);
|
||||||
|
|
||||||
// Selection borders
|
// Selection borders
|
||||||
|
@ -143,7 +151,7 @@ class ChartEditorThemeHandler
|
||||||
selectionBorderColor);
|
selectionBorderColor);
|
||||||
|
|
||||||
// Selection borders across the middle.
|
// Selection borders across the middle.
|
||||||
for (i in 1...(ChartEditorState.STRUMLINE_SIZE * 2 + 1))
|
for (i in 1...TOTAL_COLUMN_COUNT)
|
||||||
{
|
{
|
||||||
state.gridBitmap.fillRect(new Rectangle((ChartEditorState.GRID_SIZE * i) - (ChartEditorState.GRID_SELECTION_BORDER_WIDTH / 2), 0,
|
state.gridBitmap.fillRect(new Rectangle((ChartEditorState.GRID_SIZE * i) - (ChartEditorState.GRID_SELECTION_BORDER_WIDTH / 2), 0,
|
||||||
ChartEditorState.GRID_SELECTION_BORDER_WIDTH, state.gridBitmap.height),
|
ChartEditorState.GRID_SELECTION_BORDER_WIDTH, state.gridBitmap.height),
|
||||||
|
@ -167,7 +175,7 @@ class ChartEditorThemeHandler
|
||||||
// Divider at top
|
// Divider at top
|
||||||
state.gridBitmap.fillRect(new Rectangle(0, 0, state.gridBitmap.width, GRID_MEASURE_DIVIDER_WIDTH / 2), gridMeasureDividerColor);
|
state.gridBitmap.fillRect(new Rectangle(0, 0, state.gridBitmap.width, GRID_MEASURE_DIVIDER_WIDTH / 2), gridMeasureDividerColor);
|
||||||
// Divider at bottom
|
// Divider at bottom
|
||||||
var dividerLineBY = state.gridBitmap.height - (GRID_MEASURE_DIVIDER_WIDTH / 2);
|
var dividerLineBY:Float = state.gridBitmap.height - (GRID_MEASURE_DIVIDER_WIDTH / 2);
|
||||||
state.gridBitmap.fillRect(new Rectangle(0, dividerLineBY, state.gridBitmap.width, GRID_MEASURE_DIVIDER_WIDTH / 2), gridMeasureDividerColor);
|
state.gridBitmap.fillRect(new Rectangle(0, dividerLineBY, state.gridBitmap.width, GRID_MEASURE_DIVIDER_WIDTH / 2), gridMeasureDividerColor);
|
||||||
|
|
||||||
// Draw dividers between the strumlines.
|
// Draw dividers between the strumlines.
|
||||||
|
@ -180,10 +188,10 @@ class ChartEditorThemeHandler
|
||||||
};
|
};
|
||||||
|
|
||||||
// Divider at 1 * (Strumline Size)
|
// Divider at 1 * (Strumline Size)
|
||||||
var dividerLineAX = ChartEditorState.GRID_SIZE * (ChartEditorState.STRUMLINE_SIZE) - (GRID_STRUMLINE_DIVIDER_WIDTH / 2);
|
var dividerLineAX:Float = ChartEditorState.GRID_SIZE * (ChartEditorState.STRUMLINE_SIZE) - (GRID_STRUMLINE_DIVIDER_WIDTH / 2);
|
||||||
state.gridBitmap.fillRect(new Rectangle(dividerLineAX, 0, GRID_STRUMLINE_DIVIDER_WIDTH, state.gridBitmap.height), gridStrumlineDividerColor);
|
state.gridBitmap.fillRect(new Rectangle(dividerLineAX, 0, GRID_STRUMLINE_DIVIDER_WIDTH, state.gridBitmap.height), gridStrumlineDividerColor);
|
||||||
// Divider at 2 * (Strumline Size)
|
// Divider at 2 * (Strumline Size)
|
||||||
var dividerLineBX = ChartEditorState.GRID_SIZE * (ChartEditorState.STRUMLINE_SIZE * 2) - (GRID_STRUMLINE_DIVIDER_WIDTH / 2);
|
var dividerLineBX:Float = ChartEditorState.GRID_SIZE * (ChartEditorState.STRUMLINE_SIZE * 2) - (GRID_STRUMLINE_DIVIDER_WIDTH / 2);
|
||||||
state.gridBitmap.fillRect(new Rectangle(dividerLineBX, 0, GRID_STRUMLINE_DIVIDER_WIDTH, state.gridBitmap.height), gridStrumlineDividerColor);
|
state.gridBitmap.fillRect(new Rectangle(dividerLineBX, 0, GRID_STRUMLINE_DIVIDER_WIDTH, state.gridBitmap.height), gridStrumlineDividerColor);
|
||||||
|
|
||||||
if (state.gridTiledSprite != null)
|
if (state.gridTiledSprite != null)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package funkin.ui.debug.charting;
|
package funkin.ui.debug.charting;
|
||||||
|
|
||||||
import haxe.ui.data.ArrayDataSource;
|
|
||||||
import funkin.play.character.BaseCharacter.CharacterType;
|
import funkin.play.character.BaseCharacter.CharacterType;
|
||||||
import funkin.play.event.SongEvent;
|
import funkin.play.event.SongEvent;
|
||||||
import funkin.play.event.SongEventData;
|
import funkin.play.event.SongEventData;
|
||||||
|
@ -12,15 +11,17 @@ import haxe.ui.components.CheckBox;
|
||||||
import haxe.ui.components.DropDown;
|
import haxe.ui.components.DropDown;
|
||||||
import haxe.ui.components.Label;
|
import haxe.ui.components.Label;
|
||||||
import haxe.ui.components.NumberStepper;
|
import haxe.ui.components.NumberStepper;
|
||||||
import haxe.ui.components.NumberStepper;
|
|
||||||
import haxe.ui.components.Slider;
|
import haxe.ui.components.Slider;
|
||||||
import haxe.ui.components.TextField;
|
import haxe.ui.components.TextField;
|
||||||
import haxe.ui.containers.dialogs.Dialog;
|
|
||||||
import haxe.ui.containers.Box;
|
import haxe.ui.containers.Box;
|
||||||
import haxe.ui.containers.Frame;
|
|
||||||
import haxe.ui.containers.Grid;
|
import haxe.ui.containers.Grid;
|
||||||
import haxe.ui.containers.Group;
|
import haxe.ui.containers.Group;
|
||||||
|
import haxe.ui.containers.VBox;
|
||||||
|
import haxe.ui.containers.dialogs.CollapsibleDialog;
|
||||||
|
import haxe.ui.containers.dialogs.Dialog.DialogButton;
|
||||||
|
import haxe.ui.containers.dialogs.Dialog.DialogEvent;
|
||||||
import haxe.ui.core.Component;
|
import haxe.ui.core.Component;
|
||||||
|
import haxe.ui.data.ArrayDataSource;
|
||||||
import haxe.ui.events.UIEvent;
|
import haxe.ui.events.UIEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,18 +33,26 @@ enum ChartEditorToolMode
|
||||||
Place;
|
Place;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static functions which handle building themed UI elements for a provided ChartEditorState.
|
||||||
|
*/
|
||||||
class ChartEditorToolboxHandler
|
class ChartEditorToolboxHandler
|
||||||
{
|
{
|
||||||
public static function setToolboxState(state:ChartEditorState, id:String, shown:Bool):Void
|
public static function setToolboxState(state:ChartEditorState, id:String, shown:Bool):Void
|
||||||
{
|
{
|
||||||
if (shown) showToolbox(state, id);
|
if (shown)
|
||||||
|
{
|
||||||
|
showToolbox(state, id);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
hideToolbox(state, id);
|
hideToolbox(state, id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function showToolbox(state:ChartEditorState, id:String)
|
public static function showToolbox(state:ChartEditorState, id:String):Void
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = state.activeToolboxes.get(id);
|
var toolbox:CollapsibleDialog = state.activeToolboxes.get(id);
|
||||||
|
|
||||||
if (toolbox == null) toolbox = initToolbox(state, id);
|
if (toolbox == null) toolbox = initToolbox(state, id);
|
||||||
|
|
||||||
|
@ -59,7 +68,7 @@ class ChartEditorToolboxHandler
|
||||||
|
|
||||||
public static function hideToolbox(state:ChartEditorState, id:String):Void
|
public static function hideToolbox(state:ChartEditorState, id:String):Void
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = state.activeToolboxes.get(id);
|
var toolbox:CollapsibleDialog = state.activeToolboxes.get(id);
|
||||||
|
|
||||||
if (toolbox == null) toolbox = initToolbox(state, id);
|
if (toolbox == null) toolbox = initToolbox(state, id);
|
||||||
|
|
||||||
|
@ -73,13 +82,27 @@ class ChartEditorToolboxHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function minimizeToolbox(state:ChartEditorState, id:String):Void {}
|
public static function minimizeToolbox(state:ChartEditorState, id:String):Void
|
||||||
|
|
||||||
public static function maximizeToolbox(state:ChartEditorState, id:String):Void {}
|
|
||||||
|
|
||||||
public static function initToolbox(state:ChartEditorState, id:String):Dialog
|
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = null;
|
var toolbox:CollapsibleDialog = state.activeToolboxes.get(id);
|
||||||
|
|
||||||
|
if (toolbox == null) return;
|
||||||
|
|
||||||
|
toolbox.minimized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function maximizeToolbox(state:ChartEditorState, id:String):Void
|
||||||
|
{
|
||||||
|
var toolbox:CollapsibleDialog = state.activeToolboxes.get(id);
|
||||||
|
|
||||||
|
if (toolbox == null) return;
|
||||||
|
|
||||||
|
toolbox.minimized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function initToolbox(state:ChartEditorState, id:String):CollapsibleDialog
|
||||||
|
{
|
||||||
|
var toolbox:CollapsibleDialog = null;
|
||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_TOOLS_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_TOOLS_LAYOUT:
|
||||||
|
@ -95,9 +118,9 @@ class ChartEditorToolboxHandler
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_CHARACTERS_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_CHARACTERS_LAYOUT:
|
||||||
toolbox = buildToolboxCharactersLayout(state);
|
toolbox = buildToolboxCharactersLayout(state);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT:
|
||||||
toolbox = buildToolboxPlayerPreviewLayout(state);
|
toolbox = null; // buildToolboxPlayerPreviewLayout(state);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT:
|
||||||
toolbox = buildToolboxOpponentPreviewLayout(state);
|
toolbox = null; // buildToolboxOpponentPreviewLayout(state);
|
||||||
default:
|
default:
|
||||||
// This happens if you try to load an unknown layout.
|
// This happens if you try to load an unknown layout.
|
||||||
trace('ChartEditorToolboxHandler.initToolbox() - Unknown toolbox ID: $id');
|
trace('ChartEditorToolboxHandler.initToolbox() - Unknown toolbox ID: $id');
|
||||||
|
@ -114,9 +137,15 @@ class ChartEditorToolboxHandler
|
||||||
return toolbox;
|
return toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getToolbox(state:ChartEditorState, id:String):Dialog
|
/**
|
||||||
|
* Retrieve a toolbox by its layout's asset ID.
|
||||||
|
* @param state The ChartEditorState instance.
|
||||||
|
* @param id The asset ID of the toolbox layout.
|
||||||
|
* @return The toolbox.
|
||||||
|
*/
|
||||||
|
public static function getToolbox(state:ChartEditorState, id:String):CollapsibleDialog
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = state.activeToolboxes.get(id);
|
var toolbox:CollapsibleDialog = state.activeToolboxes.get(id);
|
||||||
|
|
||||||
// Initialize the toolbox without showing it.
|
// Initialize the toolbox without showing it.
|
||||||
if (toolbox == null) toolbox = initToolbox(state, id);
|
if (toolbox == null) toolbox = initToolbox(state, id);
|
||||||
|
@ -124,9 +153,9 @@ class ChartEditorToolboxHandler
|
||||||
return toolbox;
|
return toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildToolboxToolsLayout(state:ChartEditorState):Dialog
|
static function buildToolboxToolsLayout(state:ChartEditorState):CollapsibleDialog
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_TOOLS_LAYOUT);
|
var toolbox:CollapsibleDialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_TOOLS_LAYOUT);
|
||||||
|
|
||||||
if (toolbox == null) return null;
|
if (toolbox == null) return null;
|
||||||
|
|
||||||
|
@ -134,15 +163,15 @@ class ChartEditorToolboxHandler
|
||||||
toolbox.x = 50;
|
toolbox.x = 50;
|
||||||
toolbox.y = 50;
|
toolbox.y = 50;
|
||||||
|
|
||||||
toolbox.onDialogClosed = (event:DialogEvent) -> {
|
toolbox.onDialogClosed = function(event:DialogEvent) {
|
||||||
state.setUICheckboxSelected('menubarItemToggleToolboxTools', false);
|
state.setUICheckboxSelected('menubarItemToggleToolboxTools', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var toolsGroup:Group = toolbox.findComponent("toolboxToolsGroup", Group);
|
var toolsGroup:Group = toolbox.findComponent('toolboxToolsGroup', Group);
|
||||||
|
|
||||||
if (toolsGroup == null) return null;
|
if (toolsGroup == null) return null;
|
||||||
|
|
||||||
toolsGroup.onChange = (event:UIEvent) -> {
|
toolsGroup.onChange = function(event:UIEvent) {
|
||||||
switch (event.target.id)
|
switch (event.target.id)
|
||||||
{
|
{
|
||||||
case 'toolboxToolsGroupSelect':
|
case 'toolboxToolsGroupSelect':
|
||||||
|
@ -157,9 +186,9 @@ class ChartEditorToolboxHandler
|
||||||
return toolbox;
|
return toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildToolboxNoteDataLayout(state:ChartEditorState):Dialog
|
static function buildToolboxNoteDataLayout(state:ChartEditorState):CollapsibleDialog
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT);
|
var toolbox:CollapsibleDialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT);
|
||||||
|
|
||||||
if (toolbox == null) return null;
|
if (toolbox == null) return null;
|
||||||
|
|
||||||
|
@ -167,16 +196,16 @@ class ChartEditorToolboxHandler
|
||||||
toolbox.x = 75;
|
toolbox.x = 75;
|
||||||
toolbox.y = 100;
|
toolbox.y = 100;
|
||||||
|
|
||||||
toolbox.onDialogClosed = (event:DialogEvent) -> {
|
toolbox.onDialogClosed = function(event:DialogEvent) {
|
||||||
state.setUICheckboxSelected('menubarItemToggleToolboxNotes', false);
|
state.setUICheckboxSelected('menubarItemToggleToolboxNotes', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var toolboxNotesNoteKind:DropDown = toolbox.findComponent("toolboxNotesNoteKind", DropDown);
|
var toolboxNotesNoteKind:DropDown = toolbox.findComponent('toolboxNotesNoteKind', DropDown);
|
||||||
var toolboxNotesCustomKindLabel:Label = toolbox.findComponent("toolboxNotesCustomKindLabel", Label);
|
var toolboxNotesCustomKindLabel:Label = toolbox.findComponent('toolboxNotesCustomKindLabel', Label);
|
||||||
var toolboxNotesCustomKind:TextField = toolbox.findComponent("toolboxNotesCustomKind", TextField);
|
var toolboxNotesCustomKind:TextField = toolbox.findComponent('toolboxNotesCustomKind', TextField);
|
||||||
|
|
||||||
toolboxNotesNoteKind.onChange = (event:UIEvent) -> {
|
toolboxNotesNoteKind.onChange = function(event:UIEvent) {
|
||||||
var isCustom = (event.data.id == '~CUSTOM~');
|
var isCustom:Bool = (event.data.id == '~CUSTOM~');
|
||||||
|
|
||||||
if (isCustom)
|
if (isCustom)
|
||||||
{
|
{
|
||||||
|
@ -194,16 +223,16 @@ class ChartEditorToolboxHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toolboxNotesCustomKind.onChange = (event:UIEvent) -> {
|
toolboxNotesCustomKind.onChange = function(event:UIEvent) {
|
||||||
state.selectedNoteKind = toolboxNotesCustomKind.text;
|
state.selectedNoteKind = toolboxNotesCustomKind.text;
|
||||||
}
|
}
|
||||||
|
|
||||||
return toolbox;
|
return toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildToolboxEventDataLayout(state:ChartEditorState):Dialog
|
static function buildToolboxEventDataLayout(state:ChartEditorState):CollapsibleDialog
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT);
|
var toolbox:CollapsibleDialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT);
|
||||||
|
|
||||||
if (toolbox == null) return null;
|
if (toolbox == null) return null;
|
||||||
|
|
||||||
|
@ -211,12 +240,12 @@ class ChartEditorToolboxHandler
|
||||||
toolbox.x = 100;
|
toolbox.x = 100;
|
||||||
toolbox.y = 150;
|
toolbox.y = 150;
|
||||||
|
|
||||||
toolbox.onDialogClosed = (event:DialogEvent) -> {
|
toolbox.onDialogClosed = function(event:DialogEvent) {
|
||||||
state.setUICheckboxSelected('menubarItemToggleToolboxEvents', false);
|
state.setUICheckboxSelected('menubarItemToggleToolboxEvents', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var toolboxEventsEventKind:DropDown = toolbox.findComponent("toolboxEventsEventKind", DropDown);
|
var toolboxEventsEventKind:DropDown = toolbox.findComponent('toolboxEventsEventKind', DropDown);
|
||||||
var toolboxEventsDataGrid:Grid = toolbox.findComponent("toolboxEventsDataGrid", Grid);
|
var toolboxEventsDataGrid:Grid = toolbox.findComponent('toolboxEventsDataGrid', Grid);
|
||||||
|
|
||||||
toolboxEventsEventKind.dataSource = new ArrayDataSource();
|
toolboxEventsEventKind.dataSource = new ArrayDataSource();
|
||||||
|
|
||||||
|
@ -227,7 +256,7 @@ class ChartEditorToolboxHandler
|
||||||
toolboxEventsEventKind.dataSource.add({text: event.getTitle(), value: event.id});
|
toolboxEventsEventKind.dataSource.add({text: event.getTitle(), value: event.id});
|
||||||
}
|
}
|
||||||
|
|
||||||
toolboxEventsEventKind.onChange = (event:UIEvent) -> {
|
toolboxEventsEventKind.onChange = function(event:UIEvent) {
|
||||||
var eventType:String = event.data.value;
|
var eventType:String = event.data.value;
|
||||||
|
|
||||||
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event type changed: $eventType');
|
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event type changed: $eventType');
|
||||||
|
@ -281,9 +310,9 @@ class ChartEditorToolboxHandler
|
||||||
numberStepper.value = field.defaultValue;
|
numberStepper.value = field.defaultValue;
|
||||||
input = numberStepper;
|
input = numberStepper;
|
||||||
case BOOL:
|
case BOOL:
|
||||||
var checkBox = new CheckBox();
|
var checkBox:CheckBox = new CheckBox();
|
||||||
checkBox.id = field.name;
|
checkBox.id = field.name;
|
||||||
checkBox.selected = field.defaultValue == true;
|
checkBox.selected = field.defaultValue;
|
||||||
input = checkBox;
|
input = checkBox;
|
||||||
case ENUM:
|
case ENUM:
|
||||||
var dropDown:DropDown = new DropDown();
|
var dropDown:DropDown = new DropDown();
|
||||||
|
@ -293,7 +322,7 @@ class ChartEditorToolboxHandler
|
||||||
// Add entries to the dropdown.
|
// Add entries to the dropdown.
|
||||||
for (optionName in field.keys.keys())
|
for (optionName in field.keys.keys())
|
||||||
{
|
{
|
||||||
var optionValue = field.keys.get(optionName);
|
var optionValue:String = field.keys.get(optionName);
|
||||||
trace('$optionName : $optionValue');
|
trace('$optionName : $optionValue');
|
||||||
dropDown.dataSource.add({value: optionValue, text: optionName});
|
dropDown.dataSource.add({value: optionValue, text: optionName});
|
||||||
}
|
}
|
||||||
|
@ -314,7 +343,7 @@ class ChartEditorToolboxHandler
|
||||||
|
|
||||||
target.addComponent(input);
|
target.addComponent(input);
|
||||||
|
|
||||||
input.onChange = (event:UIEvent) -> {
|
input.onChange = function(event:UIEvent) {
|
||||||
trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${event.target.value}');
|
trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${event.target.value}');
|
||||||
|
|
||||||
if (event.target.value == null) state.selectedEventData.remove(event.target.id);
|
if (event.target.value == null) state.selectedEventData.remove(event.target.id);
|
||||||
|
@ -324,9 +353,9 @@ class ChartEditorToolboxHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildToolboxDifficultyLayout(state:ChartEditorState):Dialog
|
static function buildToolboxDifficultyLayout(state:ChartEditorState):CollapsibleDialog
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT);
|
var toolbox:CollapsibleDialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT);
|
||||||
|
|
||||||
if (toolbox == null) return null;
|
if (toolbox == null) return null;
|
||||||
|
|
||||||
|
@ -334,36 +363,36 @@ class ChartEditorToolboxHandler
|
||||||
toolbox.x = 125;
|
toolbox.x = 125;
|
||||||
toolbox.y = 200;
|
toolbox.y = 200;
|
||||||
|
|
||||||
toolbox.onDialogClosed = (event:DialogEvent) -> {
|
toolbox.onDialogClosed = function(event:UIEvent) {
|
||||||
state.setUICheckboxSelected('menubarItemToggleToolboxDifficulty', false);
|
state.setUICheckboxSelected('menubarItemToggleToolboxDifficulty', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var difficultyToolboxSaveMetadata:Button = toolbox.findComponent("difficultyToolboxSaveMetadata", Button);
|
var difficultyToolboxSaveMetadata:Button = toolbox.findComponent('difficultyToolboxSaveMetadata', Button);
|
||||||
var difficultyToolboxSaveChart:Button = toolbox.findComponent("difficultyToolboxSaveChart", Button);
|
var difficultyToolboxSaveChart:Button = toolbox.findComponent('difficultyToolboxSaveChart', Button);
|
||||||
var difficultyToolboxSaveAll:Button = toolbox.findComponent("difficultyToolboxSaveAll", Button);
|
var difficultyToolboxSaveAll:Button = toolbox.findComponent('difficultyToolboxSaveAll', Button);
|
||||||
var difficultyToolboxLoadMetadata:Button = toolbox.findComponent("difficultyToolboxLoadMetadata", Button);
|
var difficultyToolboxLoadMetadata:Button = toolbox.findComponent('difficultyToolboxLoadMetadata', Button);
|
||||||
var difficultyToolboxLoadChart:Button = toolbox.findComponent("difficultyToolboxLoadChart", Button);
|
var difficultyToolboxLoadChart:Button = toolbox.findComponent('difficultyToolboxLoadChart', Button);
|
||||||
|
|
||||||
difficultyToolboxSaveMetadata.onClick = (event:UIEvent) -> {
|
difficultyToolboxSaveMetadata.onClick = function(event:UIEvent) {
|
||||||
SongSerializer.exportSongMetadata(state.currentSongMetadata);
|
SongSerializer.exportSongMetadata(state.currentSongMetadata);
|
||||||
};
|
};
|
||||||
|
|
||||||
difficultyToolboxSaveChart.onClick = (event:UIEvent) -> {
|
difficultyToolboxSaveChart.onClick = function(event:UIEvent) {
|
||||||
SongSerializer.exportSongChartData(state.currentSongChartData);
|
SongSerializer.exportSongChartData(state.currentSongChartData);
|
||||||
};
|
};
|
||||||
|
|
||||||
difficultyToolboxSaveAll.onClick = (event:UIEvent) -> {
|
difficultyToolboxSaveAll.onClick = function(event:UIEvent) {
|
||||||
state.exportAllSongData();
|
state.exportAllSongData();
|
||||||
};
|
};
|
||||||
|
|
||||||
difficultyToolboxLoadMetadata.onClick = (event:UIEvent) -> {
|
difficultyToolboxLoadMetadata.onClick = function(event:UIEvent) {
|
||||||
// Replace metadata for current variation.
|
// Replace metadata for current variation.
|
||||||
SongSerializer.importSongMetadataAsync(function(songMetadata) {
|
SongSerializer.importSongMetadataAsync(function(songMetadata) {
|
||||||
state.currentSongMetadata = songMetadata;
|
state.currentSongMetadata = songMetadata;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
difficultyToolboxLoadChart.onClick = (event:UIEvent) -> {
|
difficultyToolboxLoadChart.onClick = function(event:UIEvent) {
|
||||||
// Replace chart data for current variation.
|
// Replace chart data for current variation.
|
||||||
SongSerializer.importSongChartDataAsync(function(songChartData) {
|
SongSerializer.importSongChartDataAsync(function(songChartData) {
|
||||||
state.currentSongChartData = songChartData;
|
state.currentSongChartData = songChartData;
|
||||||
|
@ -376,9 +405,9 @@ class ChartEditorToolboxHandler
|
||||||
return toolbox;
|
return toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildToolboxMetadataLayout(state:ChartEditorState):Dialog
|
static function buildToolboxMetadataLayout(state:ChartEditorState):CollapsibleDialog
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
var toolbox:CollapsibleDialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
|
|
||||||
if (toolbox == null) return null;
|
if (toolbox == null) return null;
|
||||||
|
|
||||||
|
@ -386,13 +415,13 @@ class ChartEditorToolboxHandler
|
||||||
toolbox.x = 150;
|
toolbox.x = 150;
|
||||||
toolbox.y = 250;
|
toolbox.y = 250;
|
||||||
|
|
||||||
toolbox.onDialogClosed = (event:DialogEvent) -> {
|
toolbox.onDialogClosed = function(event:UIEvent) {
|
||||||
state.setUICheckboxSelected('menubarItemToggleToolboxMetadata', false);
|
state.setUICheckboxSelected('menubarItemToggleToolboxMetadata', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var inputSongName:TextField = toolbox.findComponent('inputSongName', TextField);
|
var inputSongName:TextField = toolbox.findComponent('inputSongName', TextField);
|
||||||
inputSongName.onChange = (event:UIEvent) -> {
|
inputSongName.onChange = function(event:UIEvent) {
|
||||||
var valid = event.target.text != null && event.target.text != "";
|
var valid:Bool = event.target.text != null && event.target.text != '';
|
||||||
|
|
||||||
if (valid)
|
if (valid)
|
||||||
{
|
{
|
||||||
|
@ -404,10 +433,11 @@ class ChartEditorToolboxHandler
|
||||||
state.currentSongMetadata.songName = null;
|
state.currentSongMetadata.songName = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
inputSongName.value = state.currentSongMetadata.songName;
|
||||||
|
|
||||||
var inputSongArtist:TextField = toolbox.findComponent('inputSongArtist', TextField);
|
var inputSongArtist:TextField = toolbox.findComponent('inputSongArtist', TextField);
|
||||||
inputSongArtist.onChange = (event:UIEvent) -> {
|
inputSongArtist.onChange = function(event:UIEvent) {
|
||||||
var valid = event.target.text != null && event.target.text != "";
|
var valid:Bool = event.target.text != null && event.target.text != '';
|
||||||
|
|
||||||
if (valid)
|
if (valid)
|
||||||
{
|
{
|
||||||
|
@ -419,28 +449,31 @@ class ChartEditorToolboxHandler
|
||||||
state.currentSongMetadata.artist = null;
|
state.currentSongMetadata.artist = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
inputSongArtist.value = state.currentSongMetadata.artist;
|
||||||
|
|
||||||
var inputStage:DropDown = toolbox.findComponent('inputStage', DropDown);
|
var inputStage:DropDown = toolbox.findComponent('inputStage', DropDown);
|
||||||
inputStage.onChange = (event:UIEvent) -> {
|
inputStage.onChange = function(event:UIEvent) {
|
||||||
var valid = event.data != null && event.data.id != null;
|
var valid:Bool = event.data != null && event.data.id != null;
|
||||||
|
|
||||||
if (valid)
|
if (valid)
|
||||||
{
|
{
|
||||||
state.currentSongMetadata.playData.stage = event.data.id;
|
state.currentSongMetadata.playData.stage = event.data.id;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
inputStage.value = state.currentSongMetadata.playData.stage;
|
||||||
|
|
||||||
var inputNoteSkin:DropDown = toolbox.findComponent('inputNoteSkin', DropDown);
|
var inputNoteSkin:DropDown = toolbox.findComponent('inputNoteSkin', DropDown);
|
||||||
inputNoteSkin.onChange = (event:UIEvent) -> {
|
inputNoteSkin.onChange = function(event:UIEvent) {
|
||||||
if (event.data.id == null) return;
|
if (event.data.id == null) return;
|
||||||
state.currentSongMetadata.playData.noteSkin = event.data.id;
|
state.currentSongMetadata.playData.noteSkin = event.data.id;
|
||||||
};
|
};
|
||||||
|
inputNoteSkin.value = state.currentSongMetadata.playData.noteSkin;
|
||||||
|
|
||||||
var inputBPM:NumberStepper = toolbox.findComponent('inputBPM', NumberStepper);
|
var inputBPM:NumberStepper = toolbox.findComponent('inputBPM', NumberStepper);
|
||||||
inputBPM.onChange = (event:UIEvent) -> {
|
inputBPM.onChange = function(event:UIEvent) {
|
||||||
if (event.value == null || event.value <= 0) return;
|
if (event.value == null || event.value <= 0) return;
|
||||||
|
|
||||||
var timeChanges = state.currentSongMetadata.timeChanges;
|
var timeChanges:Array<SongTimeChange> = state.currentSongMetadata.timeChanges;
|
||||||
if (timeChanges == null || timeChanges.length == 0)
|
if (timeChanges == null || timeChanges.length == 0)
|
||||||
{
|
{
|
||||||
timeChanges = [new SongTimeChange(-1, 0, event.value, 4, 4, [4, 4, 4, 4])];
|
timeChanges = [new SongTimeChange(-1, 0, event.value, 4, 4, [4, 4, 4, 4])];
|
||||||
|
@ -454,28 +487,30 @@ class ChartEditorToolboxHandler
|
||||||
|
|
||||||
state.currentSongMetadata.timeChanges = timeChanges;
|
state.currentSongMetadata.timeChanges = timeChanges;
|
||||||
};
|
};
|
||||||
|
inputBPM.value = state.currentSongMetadata.timeChanges[0].bpm;
|
||||||
|
|
||||||
var inputScrollSpeed:Slider = toolbox.findComponent('inputScrollSpeed', Slider);
|
var inputScrollSpeed:Slider = toolbox.findComponent('inputScrollSpeed', Slider);
|
||||||
inputScrollSpeed.onChange = (event:UIEvent) -> {
|
inputScrollSpeed.onChange = function(event:UIEvent) {
|
||||||
var valid = event.target.value != null && event.target.value > 0;
|
var valid:Bool = event.target.value != null && event.target.value > 0;
|
||||||
|
|
||||||
if (valid)
|
if (valid)
|
||||||
{
|
{
|
||||||
inputScrollSpeed.removeClass('invalid-value');
|
inputScrollSpeed.removeClass('invalid-value');
|
||||||
state.currentSongChartData.scrollSpeed = event.target.value;
|
state.currentSongChartScrollSpeed = event.target.value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state.currentSongChartData.scrollSpeed = null;
|
state.currentSongChartScrollSpeed = 1.0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
inputScrollSpeed.value = state.currentSongChartData.scrollSpeed;
|
||||||
|
|
||||||
return toolbox;
|
return toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildToolboxCharactersLayout(state:ChartEditorState):Dialog
|
static function buildToolboxCharactersLayout(state:ChartEditorState):CollapsibleDialog
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_CHARACTERS_LAYOUT);
|
var toolbox:CollapsibleDialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_CHARACTERS_LAYOUT);
|
||||||
|
|
||||||
if (toolbox == null) return null;
|
if (toolbox == null) return null;
|
||||||
|
|
||||||
|
@ -483,16 +518,16 @@ class ChartEditorToolboxHandler
|
||||||
toolbox.x = 175;
|
toolbox.x = 175;
|
||||||
toolbox.y = 300;
|
toolbox.y = 300;
|
||||||
|
|
||||||
toolbox.onDialogClosed = (event:DialogEvent) -> {
|
toolbox.onDialogClosed = function(event:DialogEvent) {
|
||||||
state.setUICheckboxSelected('menubarItemToggleToolboxCharacters', false);
|
state.setUICheckboxSelected('menubarItemToggleToolboxCharacters', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return toolbox;
|
return toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildToolboxPlayerPreviewLayout(state:ChartEditorState):Dialog
|
static function buildToolboxPlayerPreviewLayout(state:ChartEditorState):CollapsibleDialog
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT);
|
var toolbox:CollapsibleDialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT);
|
||||||
|
|
||||||
if (toolbox == null) return null;
|
if (toolbox == null) return null;
|
||||||
|
|
||||||
|
@ -500,23 +535,23 @@ class ChartEditorToolboxHandler
|
||||||
toolbox.x = 200;
|
toolbox.x = 200;
|
||||||
toolbox.y = 350;
|
toolbox.y = 350;
|
||||||
|
|
||||||
toolbox.onDialogClosed = (event:DialogEvent) -> {
|
toolbox.onDialogClosed = function(event:DialogEvent) {
|
||||||
state.setUICheckboxSelected('menubarItemToggleToolboxPlayerPreview', false);
|
state.setUICheckboxSelected('menubarItemToggleToolboxPlayerPreview', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var charPlayer:CharacterPlayer = toolbox.findComponent('charPlayer');
|
var charPlayer:CharacterPlayer = toolbox.findComponent('charPlayer');
|
||||||
// TODO: We need to implement character swapping in ChartEditorState.
|
// TODO: We need to implement character swapping in ChartEditorState.
|
||||||
charPlayer.loadCharacter('bf');
|
charPlayer.loadCharacter('bf');
|
||||||
// charPlayer.setScale(0.5);
|
charPlayer.characterType = CharacterType.BF;
|
||||||
charPlayer.setCharacterType(CharacterType.BF);
|
|
||||||
charPlayer.flip = true;
|
charPlayer.flip = true;
|
||||||
|
charPlayer.targetScale = 0.5;
|
||||||
|
|
||||||
return toolbox;
|
return toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildToolboxOpponentPreviewLayout(state:ChartEditorState):Dialog
|
static function buildToolboxOpponentPreviewLayout(state:ChartEditorState):CollapsibleDialog
|
||||||
{
|
{
|
||||||
var toolbox:Dialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT);
|
var toolbox:CollapsibleDialog = cast state.buildComponent(ChartEditorState.CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT);
|
||||||
|
|
||||||
if (toolbox == null) return null;
|
if (toolbox == null) return null;
|
||||||
|
|
||||||
|
@ -524,16 +559,18 @@ class ChartEditorToolboxHandler
|
||||||
toolbox.x = 200;
|
toolbox.x = 200;
|
||||||
toolbox.y = 350;
|
toolbox.y = 350;
|
||||||
|
|
||||||
toolbox.onDialogClosed = (event:DialogEvent) -> {
|
var container:VBox = toolbox.findComponent('charPlayerContainer', VBox);
|
||||||
|
|
||||||
|
toolbox.onDialogClosed = function(event:DialogEvent) {
|
||||||
state.setUICheckboxSelected('menubarItemToggleToolboxOpponentPreview', false);
|
state.setUICheckboxSelected('menubarItemToggleToolboxOpponentPreview', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var charPlayer:CharacterPlayer = toolbox.findComponent('charPlayer');
|
var charPlayer:CharacterPlayer = toolbox.findComponent('charPlayer');
|
||||||
// TODO: We need to implement character swapping in ChartEditorState.
|
// TODO: We need to implement character swapping in ChartEditorState.
|
||||||
charPlayer.loadCharacter('dad');
|
charPlayer.loadCharacter('dad');
|
||||||
// charPlayer.setScale(0.5);
|
charPlayer.characterType = CharacterType.DAD;
|
||||||
charPlayer.setCharacterType(CharacterType.DAD);
|
|
||||||
charPlayer.flip = false;
|
charPlayer.flip = false;
|
||||||
|
charPlayer.targetScale = 0.5;
|
||||||
|
|
||||||
return toolbox;
|
return toolbox;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue