mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-26 01:28:16 -05:00
Numerous chart editor fixes.
This commit is contained in:
parent
20e6c7a2be
commit
fe92d00a04
10 changed files with 575 additions and 367 deletions
|
@ -193,7 +193,8 @@
|
||||||
{
|
{
|
||||||
"props": {
|
"props": {
|
||||||
"max": 1000,
|
"max": 1000,
|
||||||
"ignoreEmptyLines": true
|
"ignoreEmptyLines": true,
|
||||||
|
"severity": "IGNORE"
|
||||||
},
|
},
|
||||||
"type": "FileLength"
|
"type": "FileLength"
|
||||||
},
|
},
|
||||||
|
@ -232,7 +233,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"props": {
|
"props": {
|
||||||
"ignoreReturnAssignments": false,
|
"ignoreReturnAssignments": true,
|
||||||
"severity": "WARNING"
|
"severity": "WARNING"
|
||||||
},
|
},
|
||||||
"type": "InnerAssignment"
|
"type": "InnerAssignment"
|
||||||
|
@ -392,12 +393,13 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"props": {
|
"props": {
|
||||||
|
"oldFunctionTypePolicy": "none",
|
||||||
|
"unaryOpPolicy": "none",
|
||||||
|
"intervalOpPolicy": "none",
|
||||||
|
|
||||||
"newFunctionTypePolicy": "around",
|
"newFunctionTypePolicy": "around",
|
||||||
"ternaryOpPolicy": "around",
|
"ternaryOpPolicy": "around",
|
||||||
"unaryOpPolicy": "none",
|
|
||||||
"oldFunctionTypePolicy": "around",
|
|
||||||
"boolOpPolicy": "around",
|
"boolOpPolicy": "around",
|
||||||
"intervalOpPolicy": "none",
|
|
||||||
"assignOpPolicy": "around",
|
"assignOpPolicy": "around",
|
||||||
"bitwiseOpPolicy": "around",
|
"bitwiseOpPolicy": "around",
|
||||||
"arithmeticOpPolicy": "around",
|
"arithmeticOpPolicy": "around",
|
||||||
|
@ -623,7 +625,9 @@
|
||||||
"type": "UnusedImport"
|
"type": "UnusedImport"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"props": {},
|
"props": {
|
||||||
|
"severity": "WARNING"
|
||||||
|
},
|
||||||
"type": "UnusedLocalVar"
|
"type": "UnusedLocalVar"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
4
hmm.json
4
hmm.json
|
@ -42,14 +42,14 @@
|
||||||
"name": "haxeui-core",
|
"name": "haxeui-core",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "e5cf78d",
|
"ref": "59157d2",
|
||||||
"url": "https://github.com/haxeui/haxeui-core/"
|
"url": "https://github.com/haxeui/haxeui-core/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "haxeui-flixel",
|
"name": "haxeui-flixel",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "f03bb6d",
|
"ref": "d353389",
|
||||||
"url": "https://github.com/haxeui/haxeui-flixel"
|
"url": "https://github.com/haxeui/haxeui-flixel"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
116
source/funkin/input/TurboKeyHandler.hx
Normal file
116
source/funkin/input/TurboKeyHandler.hx
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
package funkin.input;
|
||||||
|
|
||||||
|
import flixel.input.keyboard.FlxKey;
|
||||||
|
import flixel.FlxBasic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles repeating behavior when holding down a key or key combination.
|
||||||
|
*
|
||||||
|
* When the `keys` are pressed, `activated` will be true for the first frame,
|
||||||
|
* then wait `delay` seconds before becoming true for one frame every `interval` seconds.
|
||||||
|
*
|
||||||
|
* Example: Pressing Ctrl+Z will undo, while holding Ctrl+Z will start to undo repeatedly.
|
||||||
|
*/
|
||||||
|
class TurboKeyHandler extends FlxBasic
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Default delay before repeating.
|
||||||
|
*/
|
||||||
|
static inline final DEFAULT_DELAY:Float = 0.4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default interval between repeats.
|
||||||
|
*/
|
||||||
|
static inline final DEFAULT_INTERVAL:Float = 0.1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether all of the keys for this handler are pressed.
|
||||||
|
*/
|
||||||
|
public var allPressed(get, null):Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether all of the keys for this handler are activated,
|
||||||
|
* and the handler is ready to repeat.
|
||||||
|
*/
|
||||||
|
public var activated(default, null):Bool = false;
|
||||||
|
|
||||||
|
var keys:Array<FlxKey>;
|
||||||
|
var delay:Float;
|
||||||
|
var interval:Float;
|
||||||
|
|
||||||
|
var allPressedTime:Float = 0;
|
||||||
|
|
||||||
|
function new(keys:Array<FlxKey>, delay:Float = DEFAULT_DELAY, interval:Float = DEFAULT_INTERVAL)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.keys = keys;
|
||||||
|
this.delay = delay;
|
||||||
|
this.interval = interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_allPressed():Bool
|
||||||
|
{
|
||||||
|
if (keys == null || keys.length == 0) return false;
|
||||||
|
if (keys.length == 1) return FlxG.keys.anyPressed(keys);
|
||||||
|
|
||||||
|
// Check if ANY keys are unpressed
|
||||||
|
for (key in keys)
|
||||||
|
{
|
||||||
|
if (!FlxG.keys.anyPressed([key])) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function update(elapsed:Float):Void
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
|
||||||
|
if (allPressed)
|
||||||
|
{
|
||||||
|
if (allPressedTime == 0)
|
||||||
|
{
|
||||||
|
activated = true;
|
||||||
|
}
|
||||||
|
else if (allPressedTime >= (delay + interval))
|
||||||
|
{
|
||||||
|
activated = true;
|
||||||
|
allPressedTime -= interval;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activated = false;
|
||||||
|
}
|
||||||
|
allPressedTime += elapsed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allPressedTime = 0;
|
||||||
|
activated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a TurboKeyHandler that monitors from a single key.
|
||||||
|
* @param inputKey The key to monitor.
|
||||||
|
* @param delay How long to wait before repeating.
|
||||||
|
* @param repeatDelay How long to wait between repeats.
|
||||||
|
* @return A TurboKeyHandler
|
||||||
|
*/
|
||||||
|
public static overload inline extern function build(inputKey:FlxKey, ?delay:Float = DEFAULT_DELAY, ?interval:Float = DEFAULT_INTERVAL):TurboKeyHandler
|
||||||
|
{
|
||||||
|
return new TurboKeyHandler([inputKey], delay, interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a TurboKeyHandler that monitors a key combination.
|
||||||
|
* @param inputKeys The combination of keys to monitor.
|
||||||
|
* @param delay How long to wait before repeating.
|
||||||
|
* @param repeatDelay How long to wait between repeats.
|
||||||
|
* @return A TurboKeyHandler
|
||||||
|
*/
|
||||||
|
public static overload inline extern function build(inputKeys:Array<FlxKey>, ?delay:Float = DEFAULT_DELAY,
|
||||||
|
?interval:Float = DEFAULT_INTERVAL):TurboKeyHandler
|
||||||
|
{
|
||||||
|
return new TurboKeyHandler(inputKeys, delay, interval);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,8 +17,7 @@ class Module implements IPlayStateScriptedClass implements IStateChangingScripte
|
||||||
|
|
||||||
function set_active(value:Bool):Bool
|
function set_active(value:Bool):Bool
|
||||||
{
|
{
|
||||||
this.active = value;
|
return this.active = value;
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var moduleId(default, null):String = 'UNKNOWN';
|
public var moduleId(default, null):String = 'UNKNOWN';
|
||||||
|
|
|
@ -436,22 +436,19 @@ class AnimateAtlasCharacter extends BaseCharacter
|
||||||
if (!exists || x == value) return x; // early return (no need to transform)
|
if (!exists || x == value) return x; // early return (no need to transform)
|
||||||
|
|
||||||
transformChildren(xTransform, value - x); // offset
|
transformChildren(xTransform, value - x); // offset
|
||||||
x = value;
|
return x = value;
|
||||||
return x;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_y(value:Float):Float
|
override function set_y(value:Float):Float
|
||||||
{
|
{
|
||||||
if (exists && y != value) transformChildren(yTransform, value - y); // offset
|
if (exists && y != value) transformChildren(yTransform, value - y); // offset
|
||||||
y = value;
|
return y = value;
|
||||||
return y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_angle(value:Float):Float
|
override function set_angle(value:Float):Float
|
||||||
{
|
{
|
||||||
if (exists && angle != value) transformChildren(angleTransform, value - angle); // offset
|
if (exists && angle != value) transformChildren(angleTransform, value - angle); // offset
|
||||||
angle = value;
|
return angle = value;
|
||||||
return angle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_alpha(value:Float):Float
|
override function set_alpha(value:Float):Float
|
||||||
|
@ -462,43 +459,37 @@ class AnimateAtlasCharacter extends BaseCharacter
|
||||||
{
|
{
|
||||||
transformChildren(directAlphaTransform, value);
|
transformChildren(directAlphaTransform, value);
|
||||||
}
|
}
|
||||||
alpha = value;
|
return alpha = value;
|
||||||
return alpha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_facing(value:Int):Int
|
override function set_facing(value:Int):Int
|
||||||
{
|
{
|
||||||
if (exists && facing != value) transformChildren(facingTransform, value);
|
if (exists && facing != value) transformChildren(facingTransform, value);
|
||||||
facing = value;
|
return facing = value;
|
||||||
return facing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_flipX(value:Bool):Bool
|
override function set_flipX(value:Bool):Bool
|
||||||
{
|
{
|
||||||
if (exists && flipX != value) transformChildren(flipXTransform, value);
|
if (exists && flipX != value) transformChildren(flipXTransform, value);
|
||||||
flipX = value;
|
return flipX = value;
|
||||||
return flipX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_flipY(value:Bool):Bool
|
override function set_flipY(value:Bool):Bool
|
||||||
{
|
{
|
||||||
if (exists && flipY != value) transformChildren(flipYTransform, value);
|
if (exists && flipY != value) transformChildren(flipYTransform, value);
|
||||||
flipY = value;
|
return flipY = value;
|
||||||
return flipY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_moves(value:Bool):Bool
|
override function set_moves(value:Bool):Bool
|
||||||
{
|
{
|
||||||
if (exists && moves != value) transformChildren(movesTransform, value);
|
if (exists && moves != value) transformChildren(movesTransform, value);
|
||||||
moves = value;
|
return moves = value;
|
||||||
return moves;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_immovable(value:Bool):Bool
|
override function set_immovable(value:Bool):Bool
|
||||||
{
|
{
|
||||||
if (exists && immovable != value) transformChildren(immovableTransform, value);
|
if (exists && immovable != value) transformChildren(immovableTransform, value);
|
||||||
immovable = value;
|
return immovable = value;
|
||||||
return immovable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_solid(value:Bool):Bool
|
override function set_solid(value:Bool):Bool
|
||||||
|
@ -510,15 +501,13 @@ class AnimateAtlasCharacter extends BaseCharacter
|
||||||
override function set_color(value:Int):Int
|
override function set_color(value:Int):Int
|
||||||
{
|
{
|
||||||
if (exists && color != value) transformChildren(gColorTransform, value);
|
if (exists && color != value) transformChildren(gColorTransform, value);
|
||||||
color = value;
|
return color = value;
|
||||||
return color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_blend(value:BlendMode):BlendMode
|
override function set_blend(value:BlendMode):BlendMode
|
||||||
{
|
{
|
||||||
if (exists && blend != value) transformChildren(blendTransform, value);
|
if (exists && blend != value) transformChildren(blendTransform, value);
|
||||||
blend = value;
|
return blend = value;
|
||||||
return blend;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override function set_clipRect(rect:FlxRect):FlxRect
|
override function set_clipRect(rect:FlxRect):FlxRect
|
||||||
|
|
|
@ -126,8 +126,10 @@ class Song // implements IPlayStateScriptedClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the metadata for a specific difficulty, including the chart if it is loaded.
|
* Retrieve the metadata for a specific difficulty, including the chart if it is loaded.
|
||||||
|
* @param diffId The difficulty ID, such as `easy` or `hard`.
|
||||||
|
* @return The difficulty data.
|
||||||
*/
|
*/
|
||||||
public inline function getDifficulty(?diffId:String):SongDifficulty
|
public inline function getDifficulty(diffId:String = null):SongDifficulty
|
||||||
{
|
{
|
||||||
if (diffId == null) diffId = difficulties.keys().array()[0];
|
if (diffId == null) diffId = difficulties.keys().array()[0];
|
||||||
|
|
||||||
|
|
|
@ -70,8 +70,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
|
||||||
|
|
||||||
this.x += xDiff;
|
this.x += xDiff;
|
||||||
this.y += yDiff;
|
this.y += yDiff;
|
||||||
globalOffsets = value;
|
return globalOffsets = value;
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var animOffsets(default, set):Array<Float> = [0, 0];
|
var animOffsets(default, set):Array<Float> = [0, 0];
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
package funkin.ui.debug.charting;
|
package funkin.ui.debug.charting;
|
||||||
|
|
||||||
import haxe.io.Path;
|
|
||||||
import flixel.FlxSprite;
|
|
||||||
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.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 haxe.ui.core.Component;
|
import haxe.io.Path;
|
||||||
import haxe.ui.components.Button;
|
import haxe.ui.components.Button;
|
||||||
import haxe.ui.components.DropDown;
|
import haxe.ui.components.DropDown;
|
||||||
import haxe.ui.components.Image;
|
|
||||||
import haxe.ui.components.Label;
|
import haxe.ui.components.Label;
|
||||||
import haxe.ui.components.Link;
|
import haxe.ui.components.Link;
|
||||||
import haxe.ui.components.NumberStepper;
|
import haxe.ui.components.NumberStepper;
|
||||||
|
@ -23,8 +21,10 @@ import haxe.ui.containers.dialogs.Dialogs;
|
||||||
import haxe.ui.containers.properties.PropertyGrid;
|
import haxe.ui.containers.properties.PropertyGrid;
|
||||||
import haxe.ui.containers.properties.PropertyGroup;
|
import haxe.ui.containers.properties.PropertyGroup;
|
||||||
import haxe.ui.containers.VBox;
|
import haxe.ui.containers.VBox;
|
||||||
import haxe.ui.events.MouseEvent;
|
import haxe.ui.core.Component;
|
||||||
import haxe.ui.events.UIEvent;
|
import haxe.ui.events.UIEvent;
|
||||||
|
import haxe.ui.notifications.NotificationManager;
|
||||||
|
import haxe.ui.notifications.NotificationType;
|
||||||
|
|
||||||
using Lambda;
|
using Lambda;
|
||||||
|
|
||||||
|
@ -43,7 +43,9 @@ class ChartEditorDialogHandler
|
||||||
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');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Builds and opens a dialog giving brief credits for the chart editor.
|
||||||
|
* @param state The current chart editor state.
|
||||||
|
* @return The dialog that was opened.
|
||||||
*/
|
*/
|
||||||
public static inline function openAboutDialog(state:ChartEditorState):Dialog
|
public static inline function openAboutDialog(state:ChartEditorState):Dialog
|
||||||
{
|
{
|
||||||
|
@ -52,72 +54,70 @@ class ChartEditorDialogHandler
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and opens a dialog letting the user create a new chart, open a recent chart, or load from a template.
|
* Builds and opens a dialog letting the user create a new chart, open a recent chart, or load from a template.
|
||||||
|
* @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 openWelcomeDialog(state:ChartEditorState, closable:Bool = true):Dialog
|
public static function openWelcomeDialog(state:ChartEditorState, closable:Bool = true):Dialog
|
||||||
{
|
{
|
||||||
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_WELCOME_LAYOUT, true, closable);
|
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_WELCOME_LAYOUT, true, closable);
|
||||||
|
|
||||||
// TODO: Add callbacks to the dialog buttons
|
|
||||||
|
|
||||||
// Add handlers to the "Create From Song" section.
|
// Add handlers to the "Create From Song" section.
|
||||||
var linkCreateBasic:Link = dialog.findComponent('splashCreateFromSongBasic', Link);
|
var linkCreateBasic:Link = dialog.findComponent('splashCreateFromSongBasic', Link);
|
||||||
linkCreateBasic.onClick = (_event) -> {
|
linkCreateBasic.onClick = function(_event) {
|
||||||
|
// Hide the welcome dialog
|
||||||
dialog.hideDialog(DialogButton.CANCEL);
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
|
||||||
// Create song wizard
|
//
|
||||||
var uploadInstDialog = openUploadInstDialog(state, false);
|
// Create Song Wizard
|
||||||
uploadInstDialog.onDialogClosed = (_event) -> {
|
//
|
||||||
|
|
||||||
|
// Step 1. Upload Instrumental
|
||||||
|
var uploadInstDialog:Dialog = openUploadInstDialog(state, false);
|
||||||
|
uploadInstDialog.onDialogClosed = function(_event) {
|
||||||
state.isHaxeUIDialogOpen = false;
|
state.isHaxeUIDialogOpen = false;
|
||||||
if (_event.button == DialogButton.APPLY)
|
if (_event.button == DialogButton.APPLY)
|
||||||
{
|
{
|
||||||
var songMetadataDialog = openSongMetadataDialog(state);
|
// Step 2. Song Metadata
|
||||||
songMetadataDialog.onDialogClosed = (_event) -> {
|
var songMetadataDialog:Dialog = openSongMetadataDialog(state);
|
||||||
|
songMetadataDialog.onDialogClosed = function(_event) {
|
||||||
state.isHaxeUIDialogOpen = false;
|
state.isHaxeUIDialogOpen = false;
|
||||||
if (_event.button == DialogButton.APPLY)
|
if (_event.button == DialogButton.APPLY)
|
||||||
{
|
{
|
||||||
var uploadVocalsDialog = openUploadVocalsDialog(state, false);
|
// Step 3. Upload Vocals
|
||||||
|
// NOTE: Uploading vocals is optional, so we don't need to check if the user cancelled the wizard.
|
||||||
|
openUploadVocalsDialog(state, false); // var uploadVocalsDialog:Dialog
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// User cancelled the wizard! Back to the welcome dialog.
|
||||||
|
openWelcomeDialog(state);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// User cancelled the wizard! Back to the welcome dialog.
|
||||||
|
openWelcomeDialog(state);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Get the list of songs and insert them as links into the "Create From Song" section.
|
|
||||||
|
|
||||||
/*
|
|
||||||
var linkTemplateDadBattle:Link = dialog.findComponent('splashTemplateDadBattle', Link);
|
|
||||||
linkTemplateDadBattle.onClick = (_event) ->
|
|
||||||
{
|
|
||||||
dialog.hideDialog(DialogButton.CANCEL);
|
|
||||||
|
|
||||||
// Load song from template
|
|
||||||
state.loadSongAsTemplate('dadbattle');
|
|
||||||
}
|
|
||||||
var linkTemplateBopeebo:Link = dialog.findComponent('splashTemplateBopeebo', Link);
|
|
||||||
linkTemplateBopeebo.onClick = (_event) ->
|
|
||||||
{
|
|
||||||
dialog.hideDialog(DialogButton.CANCEL);
|
|
||||||
|
|
||||||
// Load song from template
|
|
||||||
state.loadSongAsTemplate('bopeebo');
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
var splashTemplateContainer:VBox = dialog.findComponent('splashTemplateContainer', VBox);
|
var splashTemplateContainer:VBox = dialog.findComponent('splashTemplateContainer', VBox);
|
||||||
|
|
||||||
var songList:Array<String> = SongDataParser.listSongIds();
|
var songList:Array<String> = SongDataParser.listSongIds();
|
||||||
|
|
||||||
for (targetSongId in songList)
|
for (targetSongId in songList)
|
||||||
{
|
{
|
||||||
var songData = SongDataParser.fetchSong(targetSongId);
|
var songData:Song = SongDataParser.fetchSong(targetSongId);
|
||||||
|
|
||||||
if (songData == null) continue;
|
if (songData == null) continue;
|
||||||
|
|
||||||
var songName = songData.getDifficulty().songName;
|
var songName:String = songData.getDifficulty().songName;
|
||||||
|
|
||||||
var linkTemplateSong:Link = new Link();
|
var linkTemplateSong:Link = new Link();
|
||||||
linkTemplateSong.text = songName;
|
linkTemplateSong.text = songName;
|
||||||
linkTemplateSong.onClick = (_event) -> {
|
linkTemplateSong.onClick = function(_event) {
|
||||||
dialog.hideDialog(DialogButton.CANCEL);
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
|
||||||
// Load song from template
|
// Load song from template
|
||||||
|
@ -130,42 +130,99 @@ class ChartEditorDialogHandler
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds and opens a dialog where the user uploads an instrumental 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 openUploadInstDialog(state:ChartEditorState, ?closable:Bool = true):Dialog
|
public static function openUploadInstDialog(state:ChartEditorState, ?closable:Bool = true):Dialog
|
||||||
{
|
{
|
||||||
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT, true, closable);
|
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT, true, closable);
|
||||||
|
|
||||||
|
var buttonCancel:Button = dialog.findComponent('dialogCancel', Button);
|
||||||
|
|
||||||
|
buttonCancel.onClick = function(_event) {
|
||||||
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
}
|
||||||
|
|
||||||
var instrumentalBox:Box = dialog.findComponent('instrumentalBox', Box);
|
var instrumentalBox:Box = dialog.findComponent('instrumentalBox', Box);
|
||||||
|
|
||||||
instrumentalBox.onMouseOver = (_event) -> {
|
instrumentalBox.onMouseOver = function(_event) {
|
||||||
instrumentalBox.swapClass('upload-bg', 'upload-bg-hover');
|
instrumentalBox.swapClass('upload-bg', 'upload-bg-hover');
|
||||||
Cursor.cursorMode = Pointer;
|
Cursor.cursorMode = Pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
instrumentalBox.onMouseOut = (_event) -> {
|
instrumentalBox.onMouseOut = function(_event) {
|
||||||
instrumentalBox.swapClass('upload-bg-hover', 'upload-bg');
|
instrumentalBox.swapClass('upload-bg-hover', 'upload-bg');
|
||||||
Cursor.cursorMode = Default;
|
Cursor.cursorMode = Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
var onDropFile:String->Void;
|
var onDropFile:String->Void;
|
||||||
|
|
||||||
instrumentalBox.onClick = (_event) -> {
|
instrumentalBox.onClick = function(_event) {
|
||||||
Dialogs.openBinaryFile("Open Instrumental", [
|
Dialogs.openBinaryFile('Open Instrumental', [
|
||||||
{label: "Audio File (.ogg)", extension: "ogg"}], function(selectedFile) {
|
{label: 'Audio File (.ogg)', extension: 'ogg'}], function(selectedFile:SelectedFileInfo) {
|
||||||
if (selectedFile != null)
|
if (selectedFile != null)
|
||||||
{
|
{
|
||||||
trace('Selected file: ' + selectedFile);
|
if (state.loadInstrumentalFromBytes(selectedFile.bytes))
|
||||||
state.loadInstrumentalFromBytes(selectedFile.bytes);
|
{
|
||||||
dialog.hideDialog(DialogButton.APPLY);
|
trace('Selected file: ' + selectedFile.fullPath);
|
||||||
removeDropHandler(onDropFile);
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Success',
|
||||||
|
body: 'Loaded instrumental track (${selectedFile.name})',
|
||||||
|
type: NotificationType.Success,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.hideDialog(DialogButton.APPLY);
|
||||||
|
removeDropHandler(onDropFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace('Failed to load instrumental (${selectedFile.fullPath})');
|
||||||
|
|
||||||
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Failure',
|
||||||
|
body: 'Failed to load instrumental track (${selectedFile.name})',
|
||||||
|
type: NotificationType.Error,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onDropFile = (path:String) -> {
|
onDropFile = function(pathStr:String) {
|
||||||
trace('Dropped file: ' + path);
|
var path:Path = new Path(pathStr);
|
||||||
state.loadInstrumentalFromPath(path);
|
trace('Dropped file (${path})');
|
||||||
dialog.hideDialog(DialogButton.APPLY);
|
if (state.loadInstrumentalFromPath(path))
|
||||||
removeDropHandler(onDropFile);
|
{
|
||||||
|
// Tell the user the load was successful.
|
||||||
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Success',
|
||||||
|
body: 'Loaded instrumental track (${path.file}.${path.ext})',
|
||||||
|
type: NotificationType.Success,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.hideDialog(DialogButton.APPLY);
|
||||||
|
removeDropHandler(onDropFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Tell the user the load was successful.
|
||||||
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Failure',
|
||||||
|
body: 'Failed to load instrumental track (${path.file}.${path.ext})',
|
||||||
|
type: NotificationType.Error,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
addDropHandler(instrumentalBox, onDropFile);
|
addDropHandler(instrumentalBox, onDropFile);
|
||||||
|
@ -213,19 +270,14 @@ class ChartEditorDialogHandler
|
||||||
{
|
{
|
||||||
// a VERY short timer to wait for the mouse position to update
|
// a VERY short timer to wait for the mouse position to update
|
||||||
new FlxTimer().start(0.01, function(_) {
|
new FlxTimer().start(0.01, function(_) {
|
||||||
trace("mouseX: " + FlxG.mouse.screenX + ", mouseY: " + FlxG.mouse.screenY);
|
|
||||||
|
|
||||||
for (handler in dropHandlers)
|
for (handler in dropHandlers)
|
||||||
{
|
{
|
||||||
if (handler.component.hitTest(FlxG.mouse.screenX, FlxG.mouse.screenY))
|
if (handler.component.hitTest(FlxG.mouse.screenX, FlxG.mouse.screenY))
|
||||||
{
|
{
|
||||||
trace('File dropped on component! ' + handler.component.id);
|
|
||||||
handler.handler(path);
|
handler.handler(path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace('File dropped on nothing!' + path);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,6 +290,12 @@ class ChartEditorDialogHandler
|
||||||
{
|
{
|
||||||
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_SONG_METADATA_LAYOUT, true, false);
|
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_SONG_METADATA_LAYOUT, true, false);
|
||||||
|
|
||||||
|
var buttonCancel:Button = dialog.findComponent('dialogCancel', Button);
|
||||||
|
|
||||||
|
buttonCancel.onClick = function(_event) {
|
||||||
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
}
|
||||||
|
|
||||||
var dialogSongName:TextField = dialog.findComponent('dialogSongName', TextField);
|
var dialogSongName:TextField = dialog.findComponent('dialogSongName', TextField);
|
||||||
dialogSongName.onChange = function(event:UIEvent) {
|
dialogSongName.onChange = function(event:UIEvent) {
|
||||||
var valid:Bool = event.target.text != null && event.target.text != '';
|
var valid:Bool = event.target.text != null && event.target.text != '';
|
||||||
|
@ -272,25 +330,23 @@ class ChartEditorDialogHandler
|
||||||
|
|
||||||
var dialogStage:DropDown = dialog.findComponent('dialogStage', DropDown);
|
var dialogStage:DropDown = dialog.findComponent('dialogStage', DropDown);
|
||||||
dialogStage.onChange = function(event:UIEvent) {
|
dialogStage.onChange = function(event:UIEvent) {
|
||||||
var valid = event.data != null && event.data.id != null;
|
if (event.data == null && event.data.id == null) return;
|
||||||
|
|
||||||
if (event.data.id == null) return;
|
|
||||||
state.currentSongMetadata.playData.stage = event.data.id;
|
state.currentSongMetadata.playData.stage = event.data.id;
|
||||||
};
|
};
|
||||||
state.currentSongMetadata.playData.stage = null;
|
state.currentSongMetadata.playData.stage = null;
|
||||||
|
|
||||||
var dialogNoteSkin:DropDown = dialog.findComponent('dialogNoteSkin', DropDown);
|
var dialogNoteSkin:DropDown = dialog.findComponent('dialogNoteSkin', DropDown);
|
||||||
dialogNoteSkin.onChange = (event:UIEvent) -> {
|
dialogNoteSkin.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;
|
||||||
};
|
};
|
||||||
state.currentSongMetadata.playData.noteSkin = null;
|
state.currentSongMetadata.playData.noteSkin = null;
|
||||||
|
|
||||||
var dialogBPM:NumberStepper = dialog.findComponent('dialogBPM', NumberStepper);
|
var dialogBPM:NumberStepper = dialog.findComponent('dialogBPM', NumberStepper);
|
||||||
dialogBPM.onChange = (event:UIEvent) -> {
|
dialogBPM.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])];
|
||||||
|
@ -307,11 +363,9 @@ class ChartEditorDialogHandler
|
||||||
|
|
||||||
var dialogCharGrid:PropertyGrid = dialog.findComponent('dialogCharGrid', PropertyGrid);
|
var dialogCharGrid:PropertyGrid = dialog.findComponent('dialogCharGrid', PropertyGrid);
|
||||||
var dialogCharAdd:Button = dialog.findComponent('dialogCharAdd', Button);
|
var dialogCharAdd:Button = dialog.findComponent('dialogCharAdd', Button);
|
||||||
dialogCharAdd.onClick = (_event) -> {
|
dialogCharAdd.onClick = function(event:UIEvent) {
|
||||||
var charGroup:PropertyGroup;
|
var charGroup:PropertyGroup;
|
||||||
charGroup = buildCharGroup(state, null, () -> {
|
charGroup = buildCharGroup(state, null, () -> dialogCharGrid.removeComponent(charGroup));
|
||||||
dialogCharGrid.removeComponent(charGroup);
|
|
||||||
});
|
|
||||||
dialogCharGrid.addComponent(charGroup);
|
dialogCharGrid.addComponent(charGroup);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -321,18 +375,16 @@ class ChartEditorDialogHandler
|
||||||
dialogCharGrid.addComponent(buildCharGroup(state, 'bf', null));
|
dialogCharGrid.addComponent(buildCharGroup(state, 'bf', null));
|
||||||
|
|
||||||
var dialogContinue:Button = dialog.findComponent('dialogContinue', Button);
|
var dialogContinue:Button = dialog.findComponent('dialogContinue', Button);
|
||||||
dialogContinue.onClick = (_event) -> {
|
dialogContinue.onClick = (_event) -> dialog.hideDialog(DialogButton.APPLY);
|
||||||
dialog.hideDialog(DialogButton.APPLY);
|
|
||||||
};
|
|
||||||
|
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildCharGroup(state:ChartEditorState, ?key:String = null, removeFunc:Void->Void):PropertyGroup
|
static function buildCharGroup(state:ChartEditorState, key:String = null, removeFunc:Void->Void):PropertyGroup
|
||||||
{
|
{
|
||||||
var groupKey = key;
|
var groupKey:String = key;
|
||||||
|
|
||||||
var getCharData = () -> {
|
var getCharData:Void->SongPlayableChar = function() {
|
||||||
if (groupKey == null) groupKey = 'newChar${state.currentSongMetadata.playData.playableChars.keys().count()}';
|
if (groupKey == null) groupKey = 'newChar${state.currentSongMetadata.playData.playableChars.keys().count()}';
|
||||||
|
|
||||||
var result = state.currentSongMetadata.playData.playableChars.get(groupKey);
|
var result = state.currentSongMetadata.playData.playableChars.get(groupKey);
|
||||||
|
@ -344,24 +396,24 @@ class ChartEditorDialogHandler
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
var moveCharGroup = (target:String) -> {
|
var moveCharGroup:String->Void = function(target:String) {
|
||||||
var charData = getCharData();
|
var charData = getCharData();
|
||||||
state.currentSongMetadata.playData.playableChars.remove(groupKey);
|
state.currentSongMetadata.playData.playableChars.remove(groupKey);
|
||||||
state.currentSongMetadata.playData.playableChars.set(target, charData);
|
state.currentSongMetadata.playData.playableChars.set(target, charData);
|
||||||
groupKey = target;
|
groupKey = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
var removeGroup = () -> {
|
var removeGroup:Void->Void = function() {
|
||||||
state.currentSongMetadata.playData.playableChars.remove(groupKey);
|
state.currentSongMetadata.playData.playableChars.remove(groupKey);
|
||||||
removeFunc();
|
removeFunc();
|
||||||
}
|
}
|
||||||
|
|
||||||
var charData = getCharData();
|
var charData:SongPlayableChar = getCharData();
|
||||||
|
|
||||||
var charGroup:PropertyGroup = cast state.buildComponent(CHART_EDITOR_DIALOG_SONG_METADATA_CHARGROUP_LAYOUT);
|
var charGroup:PropertyGroup = cast state.buildComponent(CHART_EDITOR_DIALOG_SONG_METADATA_CHARGROUP_LAYOUT);
|
||||||
|
|
||||||
var charGroupPlayer:DropDown = charGroup.findComponent('charGroupPlayer', DropDown);
|
var charGroupPlayer:DropDown = charGroup.findComponent('charGroupPlayer', DropDown);
|
||||||
charGroupPlayer.onChange = (event:UIEvent) -> {
|
charGroupPlayer.onChange = function(event:UIEvent) {
|
||||||
charGroup.text = event.data.text;
|
charGroup.text = event.data.text;
|
||||||
moveCharGroup(event.data.id);
|
moveCharGroup(event.data.id);
|
||||||
};
|
};
|
||||||
|
@ -373,19 +425,19 @@ class ChartEditorDialogHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
var charGroupOpponent:DropDown = charGroup.findComponent('charGroupOpponent', DropDown);
|
var charGroupOpponent:DropDown = charGroup.findComponent('charGroupOpponent', DropDown);
|
||||||
charGroupOpponent.onChange = (event:UIEvent) -> {
|
charGroupOpponent.onChange = function(event:UIEvent) {
|
||||||
charData.opponent = event.data.id;
|
charData.opponent = event.data.id;
|
||||||
};
|
};
|
||||||
charGroupOpponent.value = getCharData().opponent;
|
charGroupOpponent.value = getCharData().opponent;
|
||||||
|
|
||||||
var charGroupGirlfriend:DropDown = charGroup.findComponent('charGroupGirlfriend', DropDown);
|
var charGroupGirlfriend:DropDown = charGroup.findComponent('charGroupGirlfriend', DropDown);
|
||||||
charGroupGirlfriend.onChange = (event:UIEvent) -> {
|
charGroupGirlfriend.onChange = function(event:UIEvent) {
|
||||||
charData.girlfriend = event.data.id;
|
charData.girlfriend = event.data.id;
|
||||||
};
|
};
|
||||||
charGroupGirlfriend.value = getCharData().girlfriend;
|
charGroupGirlfriend.value = getCharData().girlfriend;
|
||||||
|
|
||||||
var charGroupRemove:Button = charGroup.findComponent('charGroupRemove', Button);
|
var charGroupRemove:Button = charGroup.findComponent('charGroupRemove', Button);
|
||||||
charGroupRemove.onClick = (_event:MouseEvent) -> {
|
charGroupRemove.onClick = function(event:UIEvent) {
|
||||||
removeGroup();
|
removeGroup();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -394,20 +446,31 @@ class ChartEditorDialogHandler
|
||||||
return charGroup;
|
return charGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
public static function openUploadVocalsDialog(state:ChartEditorState, ?closable:Bool = true):Dialog
|
||||||
{
|
{
|
||||||
var charIdsForVocals = [];
|
var charIdsForVocals:Array<String> = [];
|
||||||
|
|
||||||
for (charKey in state.currentSongMetadata.playData.playableChars.keys())
|
for (charKey in state.currentSongMetadata.playData.playableChars.keys())
|
||||||
{
|
{
|
||||||
var charData = state.currentSongMetadata.playData.playableChars.get(charKey);
|
var charData:SongPlayableChar = state.currentSongMetadata.playData.playableChars.get(charKey);
|
||||||
charIdsForVocals.push(charKey);
|
charIdsForVocals.push(charKey);
|
||||||
if (charData.opponent != null) charIdsForVocals.push(charData.opponent);
|
if (charData.opponent != null) charIdsForVocals.push(charData.opponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_UPLOAD_VOCALS_LAYOUT, true, closable);
|
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_UPLOAD_VOCALS_LAYOUT, true, closable);
|
||||||
|
|
||||||
var dialogContainer = dialog.findComponent('vocalContainer');
|
var dialogContainer:Component = dialog.findComponent('vocalContainer');
|
||||||
|
|
||||||
|
var buttonCancel:Button = dialog.findComponent('dialogCancel', Button);
|
||||||
|
buttonCancel.onClick = function(_event) {
|
||||||
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
}
|
||||||
|
|
||||||
var dialogNoVocals:Button = dialog.findComponent('dialogNoVocals', Button);
|
var dialogNoVocals:Button = dialog.findComponent('dialogNoVocals', Button);
|
||||||
dialogNoVocals.onClick = function(_event) {
|
dialogNoVocals.onClick = function(_event) {
|
||||||
|
@ -421,20 +484,42 @@ class ChartEditorDialogHandler
|
||||||
var charMetadata:BaseCharacter = CharacterDataParser.fetchCharacter(charKey);
|
var charMetadata:BaseCharacter = CharacterDataParser.fetchCharacter(charKey);
|
||||||
var charName:String = charMetadata.characterName;
|
var charName:String = charMetadata.characterName;
|
||||||
|
|
||||||
var vocalsEntry = state.buildComponent(CHART_EDITOR_DIALOG_UPLOAD_VOCALS_ENTRY_LAYOUT);
|
var vocalsEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_UPLOAD_VOCALS_ENTRY_LAYOUT);
|
||||||
|
|
||||||
var vocalsEntryLabel:Label = vocalsEntry.findComponent('vocalsEntryLabel', Label);
|
var vocalsEntryLabel:Label = vocalsEntry.findComponent('vocalsEntryLabel', Label);
|
||||||
vocalsEntryLabel.text = 'Click to browse for a vocal track for $charName.';
|
vocalsEntryLabel.text = 'Drag and drop vocals for $charName here, or click to browse.';
|
||||||
|
|
||||||
var onDropFile:String->Void = function(fullPath:String) {
|
var onDropFile:String->Void = function(pathStr:String) {
|
||||||
trace('Selected file: $fullPath');
|
trace('Selected file: $pathStr');
|
||||||
var directory:String = Path.directory(fullPath);
|
var path:Path = new Path(pathStr);
|
||||||
var filename:String = Path.withoutDirectory(directory);
|
|
||||||
|
|
||||||
vocalsEntryLabel.text = 'Vocals for $charName (click to browse)\n${filename}';
|
if (state.loadVocalsFromPath(path, charKey))
|
||||||
state.loadVocalsFromPath(fullPath, charKey);
|
{
|
||||||
dialogNoVocals.hidden = true;
|
// Tell the user the load was successful.
|
||||||
removeDropHandler(onDropFile);
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Success',
|
||||||
|
body: 'Loaded vocal track for $charName (${path.file}.${path.ext})',
|
||||||
|
type: NotificationType.Success,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
vocalsEntryLabel.text = 'Vocals for $charName (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
|
||||||
|
dialogNoVocals.hidden = true;
|
||||||
|
removeDropHandler(onDropFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Vocals failed to load.
|
||||||
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Failure',
|
||||||
|
body: 'Failed to load vocal track (${path.file}.${path.ext})',
|
||||||
|
type: NotificationType.Error,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
|
|
||||||
|
vocalsEntryLabel.text = 'Drag and drop vocals for $charName here, or click to browse.';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
vocalsEntry.onClick = function(_event) {
|
vocalsEntry.onClick = function(_event) {
|
||||||
|
@ -449,11 +534,10 @@ class ChartEditorDialogHandler
|
||||||
removeDropHandler(onDropFile);
|
removeDropHandler(onDropFile);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// onDropFile
|
|
||||||
addDropHandler(vocalsEntry, onDropFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// onDropFile
|
||||||
|
addDropHandler(vocalsEntry, onDropFile);
|
||||||
dialogContainer.addComponent(vocalsEntry);
|
dialogContainer.addComponent(vocalsEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,14 +547,14 @@ class ChartEditorDialogHandler
|
||||||
dialog.hideDialog(DialogButton.APPLY);
|
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.
|
|
||||||
|
|
||||||
return dialog;
|
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.
|
||||||
|
*
|
||||||
|
* @param state The current chart editor state.
|
||||||
|
* @return The dialog that was opened.
|
||||||
*/
|
*/
|
||||||
public static inline function openUserGuideDialog(state:ChartEditorState):Dialog
|
public static inline function openUserGuideDialog(state:ChartEditorState):Dialog
|
||||||
{
|
{
|
||||||
|
@ -490,7 +574,7 @@ class ChartEditorDialogHandler
|
||||||
dialog.showDialog(modal);
|
dialog.showDialog(modal);
|
||||||
|
|
||||||
state.isHaxeUIDialogOpen = true;
|
state.isHaxeUIDialogOpen = true;
|
||||||
dialog.onDialogClosed = (_event) -> {
|
dialog.onDialogClosed = function(event:UIEvent) {
|
||||||
state.isHaxeUIDialogOpen = false;
|
state.isHaxeUIDialogOpen = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package funkin.ui.debug.charting;
|
package funkin.ui.debug.charting;
|
||||||
|
|
||||||
|
import funkin.ui.debug.charting.ChartEditorCommand;
|
||||||
|
import flixel.input.keyboard.FlxKey;
|
||||||
|
import funkin.input.TurboKeyHandler;
|
||||||
import haxe.ui.notifications.NotificationType;
|
import haxe.ui.notifications.NotificationType;
|
||||||
import haxe.ui.notifications.NotificationManager;
|
import haxe.ui.notifications.NotificationManager;
|
||||||
import haxe.DynamicAccess;
|
import haxe.DynamicAccess;
|
||||||
|
@ -18,7 +21,6 @@ import funkin.audio.visualize.PolygonSpectogram;
|
||||||
import funkin.audio.VocalGroup;
|
import funkin.audio.VocalGroup;
|
||||||
import funkin.input.Cursor;
|
import funkin.input.Cursor;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.modding.events.ScriptEventDispatcher;
|
|
||||||
import funkin.play.HealthIcon;
|
import funkin.play.HealthIcon;
|
||||||
import funkin.play.song.Song;
|
import funkin.play.song.Song;
|
||||||
import funkin.play.song.SongData.SongChartData;
|
import funkin.play.song.SongData.SongChartData;
|
||||||
|
@ -27,8 +29,6 @@ import funkin.play.song.SongData.SongEventData;
|
||||||
import funkin.play.song.SongData.SongMetadata;
|
import funkin.play.song.SongData.SongMetadata;
|
||||||
import funkin.play.song.SongData.SongNoteData;
|
import funkin.play.song.SongData.SongNoteData;
|
||||||
import funkin.play.song.SongDataUtils;
|
import funkin.play.song.SongDataUtils;
|
||||||
import funkin.play.song.SongSerializer;
|
|
||||||
import funkin.ui.debug.charting.ChartEditorCommand;
|
|
||||||
import funkin.ui.debug.charting.ChartEditorThemeHandler.ChartEditorTheme;
|
import funkin.ui.debug.charting.ChartEditorThemeHandler.ChartEditorTheme;
|
||||||
import funkin.ui.debug.charting.ChartEditorToolboxHandler.ChartEditorToolMode;
|
import funkin.ui.debug.charting.ChartEditorToolboxHandler.ChartEditorToolMode;
|
||||||
import funkin.ui.haxeui.components.CharacterPlayer;
|
import funkin.ui.haxeui.components.CharacterPlayer;
|
||||||
|
@ -37,23 +37,16 @@ import funkin.util.Constants;
|
||||||
import funkin.util.FileUtil;
|
import funkin.util.FileUtil;
|
||||||
import funkin.util.DateUtil;
|
import funkin.util.DateUtil;
|
||||||
import funkin.util.SerializerUtil;
|
import funkin.util.SerializerUtil;
|
||||||
import haxe.ui.components.Button;
|
|
||||||
import haxe.ui.components.CheckBox;
|
|
||||||
import haxe.ui.components.Label;
|
import haxe.ui.components.Label;
|
||||||
import haxe.ui.components.Slider;
|
import haxe.ui.components.Slider;
|
||||||
import haxe.ui.containers.dialogs.Dialog;
|
import haxe.ui.containers.dialogs.Dialog;
|
||||||
import haxe.ui.containers.dialogs.MessageBox;
|
|
||||||
import haxe.ui.containers.menus.MenuCheckBox;
|
|
||||||
import haxe.ui.containers.menus.MenuItem;
|
import haxe.ui.containers.menus.MenuItem;
|
||||||
import haxe.ui.containers.SideBar;
|
|
||||||
import haxe.ui.containers.TreeView;
|
import haxe.ui.containers.TreeView;
|
||||||
import haxe.ui.containers.TreeViewNode;
|
import haxe.ui.containers.TreeViewNode;
|
||||||
import haxe.ui.core.Component;
|
import haxe.ui.core.Component;
|
||||||
import haxe.ui.core.Screen;
|
import haxe.ui.core.Screen;
|
||||||
import haxe.ui.events.DragEvent;
|
import haxe.ui.events.DragEvent;
|
||||||
import haxe.ui.events.MouseEvent;
|
|
||||||
import haxe.ui.events.UIEvent;
|
import haxe.ui.events.UIEvent;
|
||||||
import lime.media.AudioBuffer;
|
|
||||||
import funkin.util.WindowUtil;
|
import funkin.util.WindowUtil;
|
||||||
import openfl.display.BitmapData;
|
import openfl.display.BitmapData;
|
||||||
import openfl.geom.Rectangle;
|
import openfl.geom.Rectangle;
|
||||||
|
@ -523,14 +516,34 @@ class ChartEditorState extends HaxeUIState
|
||||||
var redoHistory:Array<ChartEditorCommand> = [];
|
var redoHistory:Array<ChartEditorCommand> = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Variable used to track how long the user has been holding the undo keybind.
|
* Handler used to track how long the user has been holding the undo keybind.
|
||||||
*/
|
*/
|
||||||
var undoHeldTime:Float = 0.0;
|
var undoKeyHandler:TurboKeyHandler = TurboKeyHandler.build([FlxKey.CONTROL, FlxKey.Z]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Variable used to track how long the user has been holding the redo keybind.
|
* Variable used to track how long the user has been holding the redo keybind.
|
||||||
*/
|
*/
|
||||||
var redoHeldTime:Float = 0.0;
|
var redoKeyHandler:TurboKeyHandler = TurboKeyHandler.build([FlxKey.CONTROL, FlxKey.Y]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable used to track how long the user has been holding the up keybind.
|
||||||
|
*/
|
||||||
|
var upKeyHandler:TurboKeyHandler = TurboKeyHandler.build(FlxKey.UP);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable used to track how long the user has been holding the down keybind.
|
||||||
|
*/
|
||||||
|
var downKeyHandler:TurboKeyHandler = TurboKeyHandler.build(FlxKey.DOWN);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable used to track how long the user has been holding the page-up keybind.
|
||||||
|
*/
|
||||||
|
var pageUpKeyHandler:TurboKeyHandler = TurboKeyHandler.build(FlxKey.PAGEUP);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable used to track how long the user has been holding the page-down keybind.
|
||||||
|
*/
|
||||||
|
var pageDownKeyHandler:TurboKeyHandler = TurboKeyHandler.build(FlxKey.PAGEDOWN);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the undo/redo histories have changed since the last time the UI was updated.
|
* Whether the undo/redo histories have changed since the last time the UI was updated.
|
||||||
|
@ -728,8 +741,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
|
|
||||||
function set_currentSongChartEventData(value:Array<SongEventData>):Array<SongEventData>
|
function set_currentSongChartEventData(value:Array<SongEventData>):Array<SongEventData>
|
||||||
{
|
{
|
||||||
currentSongChartData.events = value;
|
return currentSongChartData.events = value;
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var currentSongNoteSkin(get, set):String;
|
public var currentSongNoteSkin(get, set):String;
|
||||||
|
@ -911,7 +923,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
super(CHART_EDITOR_LAYOUT);
|
super(CHART_EDITOR_LAYOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
override function create()
|
override function create():Void
|
||||||
{
|
{
|
||||||
// Get rid of any music from the previous state.
|
// Get rid of any music from the previous state.
|
||||||
FlxG.sound.music.stop();
|
FlxG.sound.music.stop();
|
||||||
|
@ -931,18 +943,14 @@ class ChartEditorState extends HaxeUIState
|
||||||
|
|
||||||
// Setup the onClick listeners for the UI after it's been created.
|
// Setup the onClick listeners for the UI after it's been created.
|
||||||
setupUIListeners();
|
setupUIListeners();
|
||||||
|
setupTurboKeyHandlers();
|
||||||
|
|
||||||
setupAutoSave();
|
setupAutoSave();
|
||||||
|
|
||||||
// TODO: We should be loading the music later when the user requests it.
|
ChartEditorDialogHandler.openWelcomeDialog(this, false);
|
||||||
// loadDefaultMusic();
|
|
||||||
|
|
||||||
// TODO: Change to false.
|
|
||||||
var canCloseInitialDialog = true;
|
|
||||||
ChartEditorDialogHandler.openWelcomeDialog(this, canCloseInitialDialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildDefaultSongData()
|
function buildDefaultSongData():Void
|
||||||
{
|
{
|
||||||
selectedVariation = Constants.DEFAULT_VARIATION;
|
selectedVariation = Constants.DEFAULT_VARIATION;
|
||||||
selectedDifficulty = Constants.DEFAULT_DIFFICULTY;
|
selectedDifficulty = Constants.DEFAULT_DIFFICULTY;
|
||||||
|
@ -959,7 +967,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Builds and displays the background sprite.
|
* Builds and displays the background sprite.
|
||||||
*/
|
*/
|
||||||
function buildBackground()
|
function buildBackground():Void
|
||||||
{
|
{
|
||||||
menuBG = new FlxSprite().loadGraphic(Paths.image('menuDesat'));
|
menuBG = new FlxSprite().loadGraphic(Paths.image('menuDesat'));
|
||||||
add(menuBG);
|
add(menuBG);
|
||||||
|
@ -973,7 +981,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Builds and displays the chart editor grid, including the playhead and cursor.
|
* Builds and displays the chart editor grid, including the playhead and cursor.
|
||||||
*/
|
*/
|
||||||
function buildGrid()
|
function buildGrid():Void
|
||||||
{
|
{
|
||||||
gridTiledSprite = new FlxTiledSprite(gridBitmap, gridBitmap.width, 1000, false, true);
|
gridTiledSprite = new FlxTiledSprite(gridBitmap, gridBitmap.width, 1000, false, true);
|
||||||
gridTiledSprite.x = FlxG.width / 2 - GRID_SIZE * STRUMLINE_SIZE; // Center the grid.
|
gridTiledSprite.x = FlxG.width / 2 - GRID_SIZE * STRUMLINE_SIZE; // Center the grid.
|
||||||
|
@ -1032,7 +1040,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
add(healthIconBF);
|
add(healthIconBF);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildSelectionBox()
|
function buildSelectionBox():Void
|
||||||
{
|
{
|
||||||
selectionBoxSprite.scrollFactor.set(0, 0);
|
selectionBoxSprite.scrollFactor.set(0, 0);
|
||||||
add(selectionBoxSprite);
|
add(selectionBoxSprite);
|
||||||
|
@ -1040,7 +1048,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
setSelectionBoxBounds();
|
setSelectionBoxBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSelectionBoxBounds(?bounds:FlxRect = null)
|
function setSelectionBoxBounds(?bounds:FlxRect = null):Void
|
||||||
{
|
{
|
||||||
if (bounds == null)
|
if (bounds == null)
|
||||||
{
|
{
|
||||||
|
@ -1058,7 +1066,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildSpectrogram(target:FlxSound)
|
function buildSpectrogram(target:FlxSound):Void
|
||||||
{
|
{
|
||||||
gridSpectrogram = new PolygonSpectogram(target, SPECTROGRAM_COLOR, FlxG.height / 2, Math.floor(FlxG.height / 2));
|
gridSpectrogram = new PolygonSpectogram(target, SPECTROGRAM_COLOR, FlxG.height / 2, Math.floor(FlxG.height / 2));
|
||||||
// Halfway through the grid.
|
// Halfway through the grid.
|
||||||
|
@ -1075,7 +1083,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Builds the group that will hold all the notes.
|
* Builds the group that will hold all the notes.
|
||||||
*/
|
*/
|
||||||
function buildNoteGroup()
|
function buildNoteGroup():Void
|
||||||
{
|
{
|
||||||
renderedNotes = new FlxTypedSpriteGroup<ChartEditorNoteSprite>();
|
renderedNotes = new FlxTypedSpriteGroup<ChartEditorNoteSprite>();
|
||||||
renderedNotes.setPosition(gridTiledSprite.x, gridTiledSprite.y);
|
renderedNotes.setPosition(gridTiledSprite.x, gridTiledSprite.y);
|
||||||
|
@ -1148,23 +1156,23 @@ class ChartEditorState extends HaxeUIState
|
||||||
{
|
{
|
||||||
// Add functionality to the playbar.
|
// Add functionality to the playbar.
|
||||||
|
|
||||||
addUIClickListener('playbarPlay', (event:MouseEvent) -> toggleAudioPlayback());
|
addUIClickListener('playbarPlay', _ -> toggleAudioPlayback());
|
||||||
addUIClickListener('playbarStart', (event:MouseEvent) -> playbarButtonPressed = 'playbarStart');
|
addUIClickListener('playbarStart', _ -> playbarButtonPressed = 'playbarStart');
|
||||||
addUIClickListener('playbarBack', (event:MouseEvent) -> playbarButtonPressed = 'playbarBack');
|
addUIClickListener('playbarBack', _ -> playbarButtonPressed = 'playbarBack');
|
||||||
addUIClickListener('playbarForward', (event:MouseEvent) -> playbarButtonPressed = 'playbarForward');
|
addUIClickListener('playbarForward', _ -> playbarButtonPressed = 'playbarForward');
|
||||||
addUIClickListener('playbarEnd', (event:MouseEvent) -> playbarButtonPressed = 'playbarEnd');
|
addUIClickListener('playbarEnd', _ -> playbarButtonPressed = 'playbarEnd');
|
||||||
|
|
||||||
// Add functionality to the menu items.
|
// Add functionality to the menu items.
|
||||||
|
|
||||||
addUIClickListener('menubarItemNewChart', (event:MouseEvent) -> ChartEditorDialogHandler.openWelcomeDialog(this, true));
|
addUIClickListener('menubarItemNewChart', _ -> ChartEditorDialogHandler.openWelcomeDialog(this, true));
|
||||||
addUIClickListener('menubarItemSaveChartAs', (event:MouseEvent) -> exportAllSongData());
|
addUIClickListener('menubarItemSaveChartAs', _ -> exportAllSongData());
|
||||||
addUIClickListener('menubarItemLoadInst', (event:MouseEvent) -> ChartEditorDialogHandler.openUploadInstDialog(this, true));
|
addUIClickListener('menubarItemLoadInst', _ -> ChartEditorDialogHandler.openUploadInstDialog(this, true));
|
||||||
|
|
||||||
addUIClickListener('menubarItemUndo', (event:MouseEvent) -> undoLastCommand());
|
addUIClickListener('menubarItemUndo', _ -> undoLastCommand());
|
||||||
|
|
||||||
addUIClickListener('menubarItemRedo', (event:MouseEvent) -> redoLastCommand());
|
addUIClickListener('menubarItemRedo', _ -> redoLastCommand());
|
||||||
|
|
||||||
addUIClickListener('menubarItemCopy', (event:MouseEvent) -> {
|
addUIClickListener('menubarItemCopy', function(_) {
|
||||||
// Doesn't use a command because it's not undoable.
|
// Doesn't use a command because it's not undoable.
|
||||||
SongDataUtils.writeItemsToClipboard(
|
SongDataUtils.writeItemsToClipboard(
|
||||||
{
|
{
|
||||||
|
@ -1173,15 +1181,11 @@ class ChartEditorState extends HaxeUIState
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addUIClickListener('menubarItemCut', (event:MouseEvent) -> {
|
addUIClickListener('menubarItemCut', _ -> performCommand(new CutItemsCommand(currentNoteSelection, currentEventSelection)));
|
||||||
performCommand(new CutItemsCommand(currentNoteSelection, currentEventSelection));
|
|
||||||
});
|
|
||||||
|
|
||||||
addUIClickListener('menubarItemPaste', (event:MouseEvent) -> {
|
addUIClickListener('menubarItemPaste', _ -> performCommand(new PasteItemsCommand(scrollPositionInMs + playheadPositionInMs)));
|
||||||
performCommand(new PasteItemsCommand(scrollPositionInMs + playheadPositionInMs));
|
|
||||||
});
|
|
||||||
|
|
||||||
addUIClickListener('menubarItemDelete', (event:MouseEvent) -> {
|
addUIClickListener('menubarItemDelete', function(_) {
|
||||||
if (currentNoteSelection.length > 0 && currentEventSelection.length > 0)
|
if (currentNoteSelection.length > 0 && currentEventSelection.length > 0)
|
||||||
{
|
{
|
||||||
performCommand(new RemoveItemsCommand(currentNoteSelection, currentEventSelection));
|
performCommand(new RemoveItemsCommand(currentNoteSelection, currentEventSelection));
|
||||||
|
@ -1200,84 +1204,60 @@ class ChartEditorState extends HaxeUIState
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
addUIClickListener('menubarItemSelectAll', (event:MouseEvent) -> {
|
addUIClickListener('menubarItemSelectAll', _ -> performCommand(new SelectAllItemsCommand(currentNoteSelection, currentEventSelection)));
|
||||||
performCommand(new SelectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
|
||||||
});
|
|
||||||
|
|
||||||
addUIClickListener('menubarItemSelectInverse', (event:MouseEvent) -> {
|
addUIClickListener('menubarItemSelectInverse', _ -> performCommand(new InvertSelectedItemsCommand(currentNoteSelection, currentEventSelection)));
|
||||||
performCommand(new InvertSelectedItemsCommand(currentNoteSelection, currentEventSelection));
|
|
||||||
});
|
|
||||||
|
|
||||||
addUIClickListener('menubarItemSelectNone', (event:MouseEvent) -> {
|
addUIClickListener('menubarItemSelectNone', _ -> performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection)));
|
||||||
performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
|
||||||
});
|
|
||||||
|
|
||||||
addUIClickListener('menubarItemSelectRegion', (event:MouseEvent) ->
|
// TODO: Implement these.
|
||||||
{
|
// addUIClickListener('menubarItemSelectRegion', _ -> doSomething());
|
||||||
// TODO: Implement this.
|
// addUIClickListener('menubarItemSelectBeforeCursor', _ -> doSomething());
|
||||||
});
|
// addUIClickListener('menubarItemSelectAfterCursor', _ -> doSomething());
|
||||||
|
|
||||||
addUIClickListener('menubarItemSelectBeforeCursor', (event:MouseEvent) ->
|
addUIClickListener('menubarItemAbout', _ -> ChartEditorDialogHandler.openAboutDialog(this));
|
||||||
{
|
|
||||||
// TODO: Implement this.
|
|
||||||
});
|
|
||||||
|
|
||||||
addUIClickListener('menubarItemSelectAfterCursor', (event:MouseEvent) ->
|
addUIClickListener('menubarItemUserGuide', _ -> ChartEditorDialogHandler.openUserGuideDialog(this));
|
||||||
{
|
|
||||||
// TODO: Implement this.
|
|
||||||
});
|
|
||||||
|
|
||||||
addUIClickListener('menubarItemAbout', (event:MouseEvent) -> ChartEditorDialogHandler.openAboutDialog(this));
|
addUIChangeListener('menubarItemDownscroll', event -> isViewDownscroll = event.value);
|
||||||
|
|
||||||
addUIClickListener('menubarItemUserGuide', (event:MouseEvent) -> ChartEditorDialogHandler.openUserGuideDialog(this));
|
|
||||||
|
|
||||||
addUIChangeListener('menubarItemDownscroll', (event:UIEvent) -> {
|
|
||||||
isViewDownscroll = event.value;
|
|
||||||
});
|
|
||||||
setUICheckboxSelected('menubarItemDownscroll', isViewDownscroll);
|
setUICheckboxSelected('menubarItemDownscroll', isViewDownscroll);
|
||||||
|
|
||||||
addUIChangeListener('menuBarItemThemeLight', (event:UIEvent) -> {
|
addUIChangeListener('menuBarItemThemeLight', function(event:UIEvent) {
|
||||||
if (event.target.value) currentTheme = ChartEditorTheme.Light;
|
if (event.target.value) currentTheme = ChartEditorTheme.Light;
|
||||||
});
|
});
|
||||||
setUICheckboxSelected('menuBarItemThemeLight', currentTheme == ChartEditorTheme.Light);
|
setUICheckboxSelected('menuBarItemThemeLight', currentTheme == ChartEditorTheme.Light);
|
||||||
|
|
||||||
addUIChangeListener('menuBarItemThemeDark', (event:UIEvent) -> {
|
addUIChangeListener('menuBarItemThemeDark', function(event:UIEvent) {
|
||||||
if (event.target.value) currentTheme = ChartEditorTheme.Dark;
|
if (event.target.value) currentTheme = ChartEditorTheme.Dark;
|
||||||
});
|
});
|
||||||
setUICheckboxSelected('menuBarItemThemeDark', currentTheme == ChartEditorTheme.Dark);
|
setUICheckboxSelected('menuBarItemThemeDark', currentTheme == ChartEditorTheme.Dark);
|
||||||
|
|
||||||
addUIChangeListener('menubarItemMetronomeEnabled', (event:UIEvent) -> {
|
addUIChangeListener('menubarItemMetronomeEnabled', event -> shouldPlayMetronome = event.value);
|
||||||
shouldPlayMetronome = event.value;
|
|
||||||
});
|
|
||||||
setUICheckboxSelected('menubarItemMetronomeEnabled', shouldPlayMetronome);
|
setUICheckboxSelected('menubarItemMetronomeEnabled', shouldPlayMetronome);
|
||||||
|
|
||||||
addUIChangeListener('menubarItemPlayerHitsounds', (event:UIEvent) -> {
|
addUIChangeListener('menubarItemPlayerHitsounds', event -> hitsoundsEnabledPlayer = event.value);
|
||||||
hitsoundsEnabledPlayer = event.value;
|
|
||||||
});
|
|
||||||
setUICheckboxSelected('menubarItemPlayerHitsounds', hitsoundsEnabledPlayer);
|
setUICheckboxSelected('menubarItemPlayerHitsounds', hitsoundsEnabledPlayer);
|
||||||
|
|
||||||
addUIChangeListener('menubarItemOpponentHitsounds', (event:UIEvent) -> {
|
addUIChangeListener('menubarItemOpponentHitsounds', event -> hitsoundsEnabledOpponent = event.value);
|
||||||
hitsoundsEnabledOpponent = event.value;
|
|
||||||
});
|
|
||||||
setUICheckboxSelected('menubarItemOpponentHitsounds', hitsoundsEnabledOpponent);
|
setUICheckboxSelected('menubarItemOpponentHitsounds', hitsoundsEnabledOpponent);
|
||||||
|
|
||||||
var instVolumeLabel:Label = findComponent('menubarLabelVolumeInstrumental', Label);
|
var instVolumeLabel:Label = findComponent('menubarLabelVolumeInstrumental', Label);
|
||||||
addUIChangeListener('menubarItemVolumeInstrumental', (event:UIEvent) -> {
|
addUIChangeListener('menubarItemVolumeInstrumental', function(event:UIEvent) {
|
||||||
var volume:Float = event.value / 100.0;
|
var volume:Float = event.value / 100.0;
|
||||||
if (audioInstTrack != null) audioInstTrack.volume = volume;
|
if (audioInstTrack != null) audioInstTrack.volume = volume;
|
||||||
instVolumeLabel.text = 'Instrumental - ${Std.int(event.value)}%';
|
instVolumeLabel.text = 'Instrumental - ${Std.int(event.value)}%';
|
||||||
});
|
});
|
||||||
|
|
||||||
var vocalsVolumeLabel:Label = findComponent('menubarLabelVolumeVocals', Label);
|
var vocalsVolumeLabel:Label = findComponent('menubarLabelVolumeVocals', Label);
|
||||||
addUIChangeListener('menubarItemVolumeVocals', (event:UIEvent) -> {
|
addUIChangeListener('menubarItemVolumeVocals', function(event:UIEvent) {
|
||||||
var volume:Float = event.value / 100.0;
|
var volume:Float = event.value / 100.0;
|
||||||
if (audioVocalTrackGroup != null) audioVocalTrackGroup.volume = volume;
|
if (audioVocalTrackGroup != null) audioVocalTrackGroup.volume = volume;
|
||||||
vocalsVolumeLabel.text = 'Vocals - ${Std.int(event.value)}%';
|
vocalsVolumeLabel.text = 'Vocals - ${Std.int(event.value)}%';
|
||||||
});
|
});
|
||||||
|
|
||||||
var playbackSpeedLabel:Label = findComponent('menubarLabelPlaybackSpeed', Label);
|
var playbackSpeedLabel:Label = findComponent('menubarLabelPlaybackSpeed', Label);
|
||||||
addUIChangeListener('menubarItemPlaybackSpeed', (event:UIEvent) -> {
|
addUIChangeListener('menubarItemPlaybackSpeed', function(event:UIEvent) {
|
||||||
var pitch = event.value * 2.0 / 100.0;
|
var pitch:Float = event.value * 2.0 / 100.0;
|
||||||
#if FLX_PITCH
|
#if FLX_PITCH
|
||||||
if (audioInstTrack != null) audioInstTrack.pitch = pitch;
|
if (audioInstTrack != null) audioInstTrack.pitch = pitch;
|
||||||
if (audioVocalTrackGroup != null) audioVocalTrackGroup.pitch = pitch;
|
if (audioVocalTrackGroup != null) audioVocalTrackGroup.pitch = pitch;
|
||||||
|
@ -1285,40 +1265,45 @@ class ChartEditorState extends HaxeUIState
|
||||||
playbackSpeedLabel.text = 'Playback Speed - ${Std.int(pitch * 100) / 100}x';
|
playbackSpeedLabel.text = 'Playback Speed - ${Std.int(pitch * 100) / 100}x';
|
||||||
});
|
});
|
||||||
|
|
||||||
addUIChangeListener('menubarItemToggleToolboxTools', (event:UIEvent) -> {
|
addUIChangeListener('menubarItemToggleToolboxTools',
|
||||||
ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_TOOLS_LAYOUT, event.value);
|
event -> ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_TOOLS_LAYOUT, event.value));
|
||||||
});
|
addUIChangeListener('menubarItemToggleToolboxNotes',
|
||||||
// setUICheckboxSelected('menubarItemToggleToolboxTools', true);
|
event -> ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT, event.value));
|
||||||
addUIChangeListener('menubarItemToggleToolboxNotes', (event:UIEvent) -> {
|
addUIChangeListener('menubarItemToggleToolboxEvents',
|
||||||
ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT, event.value);
|
event -> ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT, event.value));
|
||||||
});
|
addUIChangeListener('menubarItemToggleToolboxDifficulty',
|
||||||
addUIChangeListener('menubarItemToggleToolboxEvents', (event:UIEvent) -> {
|
event -> ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT, event.value));
|
||||||
ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT, event.value);
|
addUIChangeListener('menubarItemToggleToolboxMetadata',
|
||||||
});
|
event -> ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_METADATA_LAYOUT, event.value));
|
||||||
addUIChangeListener('menubarItemToggleToolboxDifficulty', (event:UIEvent) -> {
|
addUIChangeListener('menubarItemToggleToolboxCharacters',
|
||||||
ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT, event.value);
|
event -> ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_CHARACTERS_LAYOUT, event.value));
|
||||||
});
|
addUIChangeListener('menubarItemToggleToolboxPlayerPreview',
|
||||||
addUIChangeListener('menubarItemToggleToolboxMetadata', (event:UIEvent) -> {
|
event -> ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT, event.value));
|
||||||
ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_METADATA_LAYOUT, event.value);
|
addUIChangeListener('menubarItemToggleToolboxOpponentPreview',
|
||||||
});
|
event -> ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT, event.value));
|
||||||
addUIChangeListener('menubarItemToggleToolboxCharacters', (event:UIEvent) -> {
|
|
||||||
ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_CHARACTERS_LAYOUT, event.value);
|
|
||||||
});
|
|
||||||
addUIChangeListener('menubarItemToggleToolboxPlayerPreview', (event:UIEvent) -> {
|
|
||||||
ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT, event.value);
|
|
||||||
});
|
|
||||||
addUIChangeListener('menubarItemToggleToolboxOpponentPreview', (event:UIEvent) -> {
|
|
||||||
ChartEditorToolboxHandler.setToolboxState(this, CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT, event.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: Pass specific HaxeUI components to add context menus to them.
|
// TODO: Pass specific HaxeUI components to add context menus to them.
|
||||||
registerContextMenu(null, Paths.ui('chart-editor/context/test'));
|
registerContextMenu(null, Paths.ui('chart-editor/context/test'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize TurboKeyHandlers and add them to the state (so `update()` is called)
|
||||||
|
* We can then probe `keyHandler.activated` to see if the key combo's action should be taken.
|
||||||
|
*/
|
||||||
|
function setupTurboKeyHandlers():Void
|
||||||
|
{
|
||||||
|
add(undoKeyHandler);
|
||||||
|
add(redoKeyHandler);
|
||||||
|
add(upKeyHandler);
|
||||||
|
add(downKeyHandler);
|
||||||
|
add(pageUpKeyHandler);
|
||||||
|
add(pageDownKeyHandler);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup timers and listerners to handle auto-save.
|
* Setup timers and listerners to handle auto-save.
|
||||||
*/
|
*/
|
||||||
function setupAutoSave()
|
function setupAutoSave():Void
|
||||||
{
|
{
|
||||||
WindowUtil.windowExit.add(onWindowClose);
|
WindowUtil.windowExit.add(onWindowClose);
|
||||||
saveDataDirty = false;
|
saveDataDirty = false;
|
||||||
|
@ -1327,7 +1312,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Called after 5 minutes without saving.
|
* Called after 5 minutes without saving.
|
||||||
*/
|
*/
|
||||||
function autoSave()
|
function autoSave():Void
|
||||||
{
|
{
|
||||||
saveDataDirty = false;
|
saveDataDirty = false;
|
||||||
|
|
||||||
|
@ -1466,42 +1451,49 @@ class ChartEditorState extends HaxeUIState
|
||||||
var shouldPause:Bool = false;
|
var shouldPause:Bool = false;
|
||||||
|
|
||||||
// Up Arrow = Scroll Up
|
// Up Arrow = Scroll Up
|
||||||
if (FlxG.keys.justPressed.UP)
|
if (upKeyHandler.activated)
|
||||||
{
|
{
|
||||||
scrollAmount = -GRID_SIZE * 0.25 * 5;
|
scrollAmount = -GRID_SIZE * 0.25 * 5.0;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
// Down Arrow = Scroll Down
|
// Down Arrow = Scroll Down
|
||||||
if (FlxG.keys.justPressed.DOWN)
|
if (downKeyHandler.activated)
|
||||||
{
|
{
|
||||||
scrollAmount = GRID_SIZE * 0.25 * 5;
|
scrollAmount = GRID_SIZE * 0.25 * 5.0;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PAGE UP = Jump Up 1 Measure
|
// PAGE UP = Jump Up 1 Measure
|
||||||
if (FlxG.keys.justPressed.PAGEUP)
|
if (pageUpKeyHandler.activated)
|
||||||
{
|
{
|
||||||
scrollAmount = -GRID_SIZE * 4 * Conductor.beatsPerMeasure;
|
scrollAmount = -GRID_SIZE * 4 * Conductor.beatsPerMeasure;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
if (playbarButtonPressed == 'playbarBack')
|
if (playbarButtonPressed == 'playbarBack')
|
||||||
{
|
{
|
||||||
playbarButtonPressed = '';
|
playbarButtonPressed = '';
|
||||||
scrollAmount = -GRID_SIZE * 4 * Conductor.beatsPerMeasure;
|
scrollAmount = -GRID_SIZE * 4 * Conductor.beatsPerMeasure;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PAGE DOWN = Jump Down 1 Measure
|
// PAGE DOWN = Jump Down 1 Measure
|
||||||
if (FlxG.keys.justPressed.PAGEDOWN)
|
if (pageDownKeyHandler.activated)
|
||||||
{
|
{
|
||||||
scrollAmount = GRID_SIZE * 4 * Conductor.beatsPerMeasure;
|
scrollAmount = GRID_SIZE * 4 * Conductor.beatsPerMeasure;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
if (playbarButtonPressed == 'playbarForward')
|
if (playbarButtonPressed == 'playbarForward')
|
||||||
{
|
{
|
||||||
playbarButtonPressed = '';
|
playbarButtonPressed = '';
|
||||||
scrollAmount = GRID_SIZE * 4 * Conductor.beatsPerMeasure;
|
scrollAmount = GRID_SIZE * 4 * Conductor.beatsPerMeasure;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mouse Wheel = Scroll
|
// Mouse Wheel = Scroll
|
||||||
if (FlxG.mouse.wheel != 0 && !FlxG.keys.pressed.CONTROL)
|
if (FlxG.mouse.wheel != 0 && !FlxG.keys.pressed.CONTROL)
|
||||||
{
|
{
|
||||||
scrollAmount = -10 * FlxG.mouse.wheel;
|
scrollAmount = -10 * FlxG.mouse.wheel;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Middle Mouse + Drag = Scroll but move the playhead the same amount.
|
// Middle Mouse + Drag = Scroll but move the playhead the same amount.
|
||||||
|
@ -1532,6 +1524,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
{
|
{
|
||||||
playheadAmount = scrollAmount;
|
playheadAmount = scrollAmount;
|
||||||
scrollAmount = 0;
|
scrollAmount = 0;
|
||||||
|
shouldPause = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HOME = Scroll to Top
|
// HOME = Scroll to Top
|
||||||
|
@ -1540,12 +1533,14 @@ class ChartEditorState extends HaxeUIState
|
||||||
// Scroll amount is the difference between the current position and the top.
|
// Scroll amount is the difference between the current position and the top.
|
||||||
scrollAmount = 0 - this.scrollPositionInPixels;
|
scrollAmount = 0 - this.scrollPositionInPixels;
|
||||||
playheadAmount = 0 - this.playheadPositionInPixels;
|
playheadAmount = 0 - this.playheadPositionInPixels;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
if (playbarButtonPressed == 'playbarStart')
|
if (playbarButtonPressed == 'playbarStart')
|
||||||
{
|
{
|
||||||
playbarButtonPressed = '';
|
playbarButtonPressed = '';
|
||||||
scrollAmount = 0 - this.scrollPositionInPixels;
|
scrollAmount = 0 - this.scrollPositionInPixels;
|
||||||
playheadAmount = 0 - this.playheadPositionInPixels;
|
playheadAmount = 0 - this.playheadPositionInPixels;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// END = Scroll to Bottom
|
// END = Scroll to Bottom
|
||||||
|
@ -1553,11 +1548,13 @@ class ChartEditorState extends HaxeUIState
|
||||||
{
|
{
|
||||||
// Scroll amount is the difference between the current position and the bottom.
|
// Scroll amount is the difference between the current position and the bottom.
|
||||||
scrollAmount = this.songLengthInPixels - this.scrollPositionInPixels;
|
scrollAmount = this.songLengthInPixels - this.scrollPositionInPixels;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
if (playbarButtonPressed == 'playbarEnd')
|
if (playbarButtonPressed == 'playbarEnd')
|
||||||
{
|
{
|
||||||
playbarButtonPressed = '';
|
playbarButtonPressed = '';
|
||||||
scrollAmount = this.songLengthInPixels - this.scrollPositionInPixels;
|
scrollAmount = this.songLengthInPixels - this.scrollPositionInPixels;
|
||||||
|
shouldPause = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the scroll amount.
|
// Apply the scroll amount.
|
||||||
|
@ -1566,9 +1563,10 @@ class ChartEditorState extends HaxeUIState
|
||||||
|
|
||||||
// Resync the conductor and audio tracks.
|
// Resync the conductor and audio tracks.
|
||||||
if (scrollAmount != 0 || playheadAmount != 0) moveSongToScrollPosition();
|
if (scrollAmount != 0 || playheadAmount != 0) moveSongToScrollPosition();
|
||||||
|
if (shouldPause) stopAudioPlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleZoom()
|
function handleZoom():Void
|
||||||
{
|
{
|
||||||
if (FlxG.keys.justPressed.MINUS)
|
if (FlxG.keys.justPressed.MINUS)
|
||||||
{
|
{
|
||||||
|
@ -1591,7 +1589,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSnap()
|
function handleSnap():Void
|
||||||
{
|
{
|
||||||
if (FlxG.keys.justPressed.LEFT)
|
if (FlxG.keys.justPressed.LEFT)
|
||||||
{
|
{
|
||||||
|
@ -1607,7 +1605,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Handle display of the mouse cursor.
|
* Handle display of the mouse cursor.
|
||||||
*/
|
*/
|
||||||
function handleCursor()
|
function handleCursor():Void
|
||||||
{
|
{
|
||||||
// Note: If a menu is open in HaxeUI, don't handle cursor behavior.
|
// Note: If a menu is open in HaxeUI, don't handle cursor behavior.
|
||||||
var shouldHandleCursor = !isCursorOverHaxeUI || (selectionBoxStartPos != null);
|
var shouldHandleCursor = !isCursorOverHaxeUI || (selectionBoxStartPos != null);
|
||||||
|
@ -2330,7 +2328,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Handles display elements for the playbar at the bottom.
|
* Handles display elements for the playbar at the bottom.
|
||||||
*/
|
*/
|
||||||
function handlePlaybar()
|
function handlePlaybar():Void
|
||||||
{
|
{
|
||||||
// Make sure the playbar is never nudged out of the correct spot.
|
// Make sure the playbar is never nudged out of the correct spot.
|
||||||
playbarHeadLayout.x = 4;
|
playbarHeadLayout.x = 4;
|
||||||
|
@ -2362,7 +2360,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Handle keybinds for File menu items.
|
* Handle keybinds for File menu items.
|
||||||
*/
|
*/
|
||||||
function handleFileKeybinds()
|
function handleFileKeybinds():Void
|
||||||
{
|
{
|
||||||
// CTRL + Q = Quit to Menu
|
// CTRL + Q = Quit to Menu
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.Q)
|
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.Q)
|
||||||
|
@ -2374,48 +2372,20 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Handle keybinds for edit menu items.
|
* Handle keybinds for edit menu items.
|
||||||
*/
|
*/
|
||||||
function handleEditKeybinds()
|
function handleEditKeybinds():Void
|
||||||
{
|
{
|
||||||
// CTRL + Z = Undo
|
// CTRL + Z = Undo
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.Z)
|
if (undoKeyHandler.activated)
|
||||||
{
|
{
|
||||||
undoLastCommand();
|
undoLastCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.Z && !FlxG.keys.pressed.Y)
|
|
||||||
{
|
|
||||||
undoHeldTime += FlxG.elapsed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
undoHeldTime = 0;
|
|
||||||
}
|
|
||||||
if (undoHeldTime > RAPID_UNDO_DELAY + RAPID_UNDO_INTERVAL)
|
|
||||||
{
|
|
||||||
undoLastCommand();
|
|
||||||
undoHeldTime -= RAPID_UNDO_INTERVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CTRL + Y = Redo
|
// CTRL + Y = Redo
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.Y)
|
if (redoKeyHandler.activated)
|
||||||
{
|
{
|
||||||
redoLastCommand();
|
redoLastCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.Y && !FlxG.keys.pressed.Z)
|
|
||||||
{
|
|
||||||
redoHeldTime += FlxG.elapsed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
redoHeldTime = 0;
|
|
||||||
}
|
|
||||||
if (redoHeldTime > RAPID_UNDO_DELAY + RAPID_UNDO_INTERVAL)
|
|
||||||
{
|
|
||||||
redoLastCommand();
|
|
||||||
redoHeldTime -= RAPID_UNDO_INTERVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CTRL + C = Copy
|
// CTRL + C = Copy
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.C)
|
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.C)
|
||||||
{
|
{
|
||||||
|
@ -2485,25 +2455,25 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Handle keybinds for View menu items.
|
* Handle keybinds for View menu items.
|
||||||
*/
|
*/
|
||||||
function handleViewKeybinds() {}
|
function handleViewKeybinds():Void {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle keybinds for Help menu items.
|
* Handle keybinds for Help menu items.
|
||||||
*/
|
*/
|
||||||
function handleHelpKeybinds()
|
function handleHelpKeybinds():Void
|
||||||
{
|
{
|
||||||
// F1 = Open Help
|
// F1 = Open Help
|
||||||
if (FlxG.keys.justPressed.F1) ChartEditorDialogHandler.openUserGuideDialog(this);
|
if (FlxG.keys.justPressed.F1) ChartEditorDialogHandler.openUserGuideDialog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleToolboxes()
|
function handleToolboxes():Void
|
||||||
{
|
{
|
||||||
handleDifficultyToolbox();
|
handleDifficultyToolbox();
|
||||||
handlePlayerPreviewToolbox();
|
handlePlayerPreviewToolbox();
|
||||||
handleOpponentPreviewToolbox();
|
handleOpponentPreviewToolbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDifficultyToolbox()
|
function handleDifficultyToolbox():Void
|
||||||
{
|
{
|
||||||
if (difficultySelectDirty)
|
if (difficultySelectDirty)
|
||||||
{
|
{
|
||||||
|
@ -2552,7 +2522,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePlayerPreviewToolbox()
|
function handlePlayerPreviewToolbox():Void
|
||||||
{
|
{
|
||||||
// Manage the Select Difficulty tree view.
|
// Manage the Select Difficulty tree view.
|
||||||
var charPreviewToolbox = ChartEditorToolboxHandler.getToolbox(this, CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT);
|
var charPreviewToolbox = ChartEditorToolboxHandler.getToolbox(this, CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT);
|
||||||
|
@ -2564,7 +2534,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
currentPlayerCharacterPlayer = charPlayer;
|
currentPlayerCharacterPlayer = charPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleOpponentPreviewToolbox()
|
function handleOpponentPreviewToolbox():Void
|
||||||
{
|
{
|
||||||
// Manage the Select Difficulty tree view.
|
// Manage the Select Difficulty tree view.
|
||||||
var charPreviewToolbox = ChartEditorToolboxHandler.getToolbox(this, CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT);
|
var charPreviewToolbox = ChartEditorToolboxHandler.getToolbox(this, CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT);
|
||||||
|
@ -2576,7 +2546,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
currentOpponentCharacterPlayer = charPlayer;
|
currentOpponentCharacterPlayer = charPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
override function dispatchEvent(event:ScriptEvent)
|
override function dispatchEvent(event:ScriptEvent):Void
|
||||||
{
|
{
|
||||||
super.dispatchEvent(event);
|
super.dispatchEvent(event);
|
||||||
|
|
||||||
|
@ -2660,9 +2630,9 @@ class ChartEditorState extends HaxeUIState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDifficulty(variation:String) {}
|
function addDifficulty(variation:String):Void {}
|
||||||
|
|
||||||
function addVariation(variationId:String)
|
function addVariation(variationId:String):Void
|
||||||
{
|
{
|
||||||
// Create a new variation with the specified ID.
|
// Create a new variation with the specified ID.
|
||||||
songMetadata.set(variationId, currentSongMetadata.clone(variationId));
|
songMetadata.set(variationId, currentSongMetadata.clone(variationId));
|
||||||
|
@ -2673,7 +2643,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Handle the player preview/gameplay test area on the left side.
|
* Handle the player preview/gameplay test area on the left side.
|
||||||
*/
|
*/
|
||||||
function handlePlayerDisplay() {}
|
function handlePlayerDisplay():Void {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the note preview/scroll area on the right side.
|
* Handles the note preview/scroll area on the right side.
|
||||||
|
@ -2683,7 +2653,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
* - Scrolling the note preview area down if the note preview is taller than the screen,
|
* - Scrolling the note preview area down if the note preview is taller than the screen,
|
||||||
* and the viewport nears the end of the visible area.
|
* and the viewport nears the end of the visible area.
|
||||||
*/
|
*/
|
||||||
function handleNotePreview()
|
function handleNotePreview():Void
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
if (notePreviewDirty)
|
if (notePreviewDirty)
|
||||||
|
@ -2703,13 +2673,13 @@ class ChartEditorState extends HaxeUIState
|
||||||
* Perform a spot update on the note preview, by editing the note preview
|
* Perform a spot update on the note preview, by editing the note preview
|
||||||
* only where necessary. More efficient than a full update.
|
* only where necessary. More efficient than a full update.
|
||||||
*/
|
*/
|
||||||
function updateNotePreview(note:SongNoteData, ?deleteNote:Bool = false) {}
|
function updateNotePreview(note:SongNoteData, ?deleteNote:Bool = false):Void {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles passive behavior of the menu bar, such as updating labels or enabled/disabled status.
|
* Handles passive behavior of the menu bar, such as updating labels or enabled/disabled status.
|
||||||
* Does not handle onClick ACTIONS of the menubar.
|
* Does not handle onClick ACTIONS of the menubar.
|
||||||
*/
|
*/
|
||||||
function handleMenubar()
|
function handleMenubar():Void
|
||||||
{
|
{
|
||||||
if (commandHistoryDirty)
|
if (commandHistoryDirty)
|
||||||
{
|
{
|
||||||
|
@ -2765,7 +2735,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* Handle syncronizing the conductor with the music playback.
|
* Handle syncronizing the conductor with the music playback.
|
||||||
*/
|
*/
|
||||||
function handleMusicPlayback()
|
function handleMusicPlayback():Void
|
||||||
{
|
{
|
||||||
if (audioInstTrack != null && audioInstTrack.playing)
|
if (audioInstTrack != null && audioInstTrack.playing)
|
||||||
{
|
{
|
||||||
|
@ -2856,21 +2826,25 @@ class ChartEditorState extends HaxeUIState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startAudioPlayback()
|
function startAudioPlayback():Void
|
||||||
{
|
{
|
||||||
if (audioInstTrack != null) audioInstTrack.play();
|
if (audioInstTrack != null) audioInstTrack.play();
|
||||||
if (audioVocalTrackGroup != null) audioVocalTrackGroup.play();
|
if (audioVocalTrackGroup != null) audioVocalTrackGroup.play();
|
||||||
if (audioVocalTrackGroup != null) audioVocalTrackGroup.play();
|
if (audioVocalTrackGroup != null) audioVocalTrackGroup.play();
|
||||||
|
|
||||||
|
setComponentText('playbarPlay', '||');
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopAudioPlayback()
|
function stopAudioPlayback():Void
|
||||||
{
|
{
|
||||||
if (audioInstTrack != null) audioInstTrack.pause();
|
if (audioInstTrack != null) audioInstTrack.pause();
|
||||||
if (audioVocalTrackGroup != null) audioVocalTrackGroup.pause();
|
if (audioVocalTrackGroup != null) audioVocalTrackGroup.pause();
|
||||||
if (audioVocalTrackGroup != null) audioVocalTrackGroup.pause();
|
if (audioVocalTrackGroup != null) audioVocalTrackGroup.pause();
|
||||||
|
|
||||||
|
setComponentText('playbarPlay', '>');
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleAudioPlayback()
|
function toggleAudioPlayback():Void
|
||||||
{
|
{
|
||||||
if (audioInstTrack == null) return;
|
if (audioInstTrack == null) return;
|
||||||
|
|
||||||
|
@ -2884,7 +2858,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePlayhead()
|
function handlePlayhead():Void
|
||||||
{
|
{
|
||||||
// Place notes at the playhead.
|
// Place notes at the playhead.
|
||||||
// TODO: Add the ability to switch modes.
|
// TODO: Add the ability to switch modes.
|
||||||
|
@ -2973,52 +2947,64 @@ class ChartEditorState extends HaxeUIState
|
||||||
* Loads an instrumental from an absolute file path, replacing the current instrumental.
|
* Loads an instrumental from an absolute file path, replacing the current instrumental.
|
||||||
*
|
*
|
||||||
* @param path The absolute path to the audio file.
|
* @param path The absolute path to the audio file.
|
||||||
|
* @return Success or failure.
|
||||||
*/
|
*/
|
||||||
public function loadInstrumentalFromPath(path:String):Void
|
public function loadInstrumentalFromPath(path:Path):Bool
|
||||||
{
|
{
|
||||||
#if sys
|
#if sys
|
||||||
// Validate file extension.
|
// Validate file extension.
|
||||||
var fileExtension:String = Path.extension(path);
|
if (!SUPPORTED_MUSIC_FORMATS.contains(path.ext))
|
||||||
if (!SUPPORTED_MUSIC_FORMATS.contains(fileExtension))
|
|
||||||
{
|
{
|
||||||
trace('[WARN] Unsupported file extension: $fileExtension');
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileBytes:haxe.io.Bytes = sys.io.File.getBytes(path);
|
var fileBytes:haxe.io.Bytes = sys.io.File.getBytes(path.toString());
|
||||||
loadInstrumentalFromBytes(fileBytes);
|
return loadInstrumentalFromBytes(fileBytes, '${path.file}.${path.ext}');
|
||||||
#else
|
#else
|
||||||
trace("[WARN] This platform can't load audio from a file path, you'll need to fetch the bytes some other way.");
|
trace("[WARN] This platform can't load audio from a file path, you'll need to fetch the bytes some other way.");
|
||||||
|
return false;
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads an instrumental from audio byte data, replacing the current instrumental.
|
* Loads an instrumental from audio byte data, replacing the current instrumental.
|
||||||
|
* @param bytes The audio byte data.
|
||||||
|
* @param fileName The name of the file, if available. Used for notifications.
|
||||||
|
* @return Success or failure.
|
||||||
*/
|
*/
|
||||||
public function loadInstrumentalFromBytes(bytes:haxe.io.Bytes):Void
|
public function loadInstrumentalFromBytes(bytes:haxe.io.Bytes, fileName:String = null):Bool
|
||||||
{
|
{
|
||||||
var openflSound = new openfl.media.Sound();
|
var openflSound:openfl.media.Sound = new openfl.media.Sound();
|
||||||
openflSound.loadCompressedDataFromByteArray(openfl.utils.ByteArray.fromBytes(bytes), bytes.length);
|
openflSound.loadCompressedDataFromByteArray(openfl.utils.ByteArray.fromBytes(bytes), bytes.length);
|
||||||
audioInstTrack = FlxG.sound.load(openflSound, 1.0, false);
|
audioInstTrack = FlxG.sound.load(openflSound, 1.0, false);
|
||||||
audioInstTrack.autoDestroy = false;
|
audioInstTrack.autoDestroy = false;
|
||||||
audioInstTrack.pause();
|
audioInstTrack.pause();
|
||||||
|
|
||||||
// Tell the user the load was successful.
|
|
||||||
// TODO: Un-bork this.
|
|
||||||
// showNotification('Loaded instrumental track successfully.');
|
|
||||||
|
|
||||||
postLoadInstrumental();
|
postLoadInstrumental();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadInstrumentalFromAsset(path:String):Void
|
/**
|
||||||
|
* Loads an instrumental from an OpenFL asset, replacing the current instrumental.
|
||||||
|
* @param path The path to the asset. Use `Paths` to build this.
|
||||||
|
* @return Success or failure.
|
||||||
|
*/
|
||||||
|
public function loadInstrumentalFromAsset(path:String):Bool
|
||||||
{
|
{
|
||||||
var instTrack = FlxG.sound.load(path, 1.0, false);
|
var instTrack:FlxSound = FlxG.sound.load(path, 1.0, false);
|
||||||
audioInstTrack = instTrack;
|
if (instTrack != null)
|
||||||
|
{
|
||||||
|
audioInstTrack = instTrack;
|
||||||
|
|
||||||
postLoadInstrumental();
|
postLoadInstrumental();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function postLoadInstrumental()
|
function postLoadInstrumental():Void
|
||||||
{
|
{
|
||||||
// Prevent the time from skipping back to 0 when the song ends.
|
// Prevent the time from skipping back to 0 when the song ends.
|
||||||
audioInstTrack.onComplete = function() {
|
audioInstTrack.onComplete = function() {
|
||||||
|
@ -3042,42 +3028,47 @@ class ChartEditorState extends HaxeUIState
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a vocal track from an absolute file path.
|
* Loads a vocal track from an absolute file path.
|
||||||
|
* @param path The absolute path to the audio file.
|
||||||
|
* @param charKey The character to load the vocal track for.
|
||||||
*/
|
*/
|
||||||
public function loadVocalsFromPath(path:String, ?charKey:String):Void
|
public function loadVocalsFromPath(path:Path, charKey:String = null):Bool
|
||||||
{
|
{
|
||||||
#if sys
|
#if sys
|
||||||
var fileBytes:haxe.io.Bytes = sys.io.File.getBytes(path);
|
var fileBytes:haxe.io.Bytes = sys.io.File.getBytes(path.toString());
|
||||||
loadVocalsFromBytes(fileBytes, charKey);
|
return loadVocalsFromBytes(fileBytes, charKey);
|
||||||
#else
|
#else
|
||||||
trace("[WARN] This platform can't load audio from a file path, you'll need to fetch the bytes some other way.");
|
trace("[WARN] This platform can't load audio from a file path, you'll need to fetch the bytes some other way.");
|
||||||
|
return false;
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadVocalsFromAsset(path:String, ?charKey:String):Void
|
public function loadVocalsFromAsset(path:String, charKey:String = null):Bool
|
||||||
{
|
{
|
||||||
var vocalTrack:FlxSound = FlxG.sound.load(path, 1.0, false);
|
var vocalTrack:FlxSound = FlxG.sound.load(path, 1.0, false);
|
||||||
audioVocalTrackGroup.add(vocalTrack);
|
if (vocalTrack != null)
|
||||||
|
{
|
||||||
|
audioVocalTrackGroup.add(vocalTrack);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a vocal track from audio byte data.
|
* Loads a vocal track from audio byte data.
|
||||||
*/
|
*/
|
||||||
public function loadVocalsFromBytes(bytes:haxe.io.Bytes, ?charKey:String):Void
|
public function loadVocalsFromBytes(bytes:haxe.io.Bytes, charKey:String = null):Bool
|
||||||
{
|
{
|
||||||
var openflSound = new openfl.media.Sound();
|
var openflSound = new openfl.media.Sound();
|
||||||
openflSound.loadCompressedDataFromByteArray(openfl.utils.ByteArray.fromBytes(bytes), bytes.length);
|
openflSound.loadCompressedDataFromByteArray(openfl.utils.ByteArray.fromBytes(bytes), bytes.length);
|
||||||
var vocalTrack:FlxSound = FlxG.sound.load(openflSound, 1.0, false);
|
var vocalTrack:FlxSound = FlxG.sound.load(openflSound, 1.0, false);
|
||||||
audioVocalTrackGroup.add(vocalTrack);
|
audioVocalTrackGroup.add(vocalTrack);
|
||||||
|
return true;
|
||||||
// Tell the user the load was successful.
|
|
||||||
// TODO: Un-bork this.
|
|
||||||
// showNotification('Loaded instrumental track successfully.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch's a song's existing chart and audio and loads it, replacing the current song.
|
* Fetch's a song's existing chart and audio and loads it, replacing the current song.
|
||||||
*/
|
*/
|
||||||
public function loadSongAsTemplate(songId:String)
|
public function loadSongAsTemplate(songId:String):Void
|
||||||
{
|
{
|
||||||
var song:Song = SongDataParser.fetchSong(songId);
|
var song:Song = SongDataParser.fetchSong(songId);
|
||||||
|
|
||||||
|
@ -3089,6 +3080,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
|
|
||||||
// Load the song metadata.
|
// Load the song metadata.
|
||||||
var rawSongMetadata:Array<SongMetadata> = song.getRawMetadata();
|
var rawSongMetadata:Array<SongMetadata> = song.getRawMetadata();
|
||||||
|
var songName:String = rawSongMetadata[0].songName;
|
||||||
|
|
||||||
this.songMetadata = new Map<String, SongMetadata>();
|
this.songMetadata = new Map<String, SongMetadata>();
|
||||||
|
|
||||||
|
@ -3112,14 +3104,20 @@ class ChartEditorState extends HaxeUIState
|
||||||
loadInstrumentalFromAsset(Paths.inst(songId));
|
loadInstrumentalFromAsset(Paths.inst(songId));
|
||||||
loadVocalsFromAsset(Paths.voices(songId));
|
loadVocalsFromAsset(Paths.voices(songId));
|
||||||
|
|
||||||
// showNotification('Loaded song ${songId}.');
|
NotificationManager.instance.addNotification(
|
||||||
|
{
|
||||||
|
title: 'Success',
|
||||||
|
body: 'Loaded song ($songName)',
|
||||||
|
type: NotificationType.Success,
|
||||||
|
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When setting the scroll position, except when automatically scrolling during song playback,
|
* When setting the scroll position, except when automatically scrolling during song playback,
|
||||||
* we need to update the conductor's current step time and the timestamp of the audio tracks.
|
* we need to update the conductor's current step time and the timestamp of the audio tracks.
|
||||||
*/
|
*/
|
||||||
function moveSongToScrollPosition()
|
function moveSongToScrollPosition():Void
|
||||||
{
|
{
|
||||||
// Update the songPosition in the Conductor.
|
// Update the songPosition in the Conductor.
|
||||||
Conductor.update(scrollPositionInMs);
|
Conductor.update(scrollPositionInMs);
|
||||||
|
@ -3168,7 +3166,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var command = undoHistory.pop();
|
var command:ChartEditorCommand = undoHistory.pop();
|
||||||
undoCommand(command);
|
undoCommand(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3183,11 +3181,11 @@ class ChartEditorState extends HaxeUIState
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var command = redoHistory.pop();
|
var command:ChartEditorCommand = redoHistory.pop();
|
||||||
performCommand(command, false);
|
performCommand(command, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortChartData()
|
function sortChartData():Void
|
||||||
{
|
{
|
||||||
currentSongChartNoteData.sort(function(a:SongNoteData, b:SongNoteData):Int {
|
currentSongChartNoteData.sort(function(a:SongNoteData, b:SongNoteData):Int {
|
||||||
return FlxSort.byValues(FlxSort.ASCENDING, a.time, b.time);
|
return FlxSort.byValues(FlxSort.ASCENDING, a.time, b.time);
|
||||||
|
@ -3198,7 +3196,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function playMetronomeTick(?high:Bool = false)
|
function playMetronomeTick(?high:Bool = false):Void
|
||||||
{
|
{
|
||||||
playSound(Paths.sound('pianoStuff/piano-${high ? '001' : '008'}'));
|
playSound(Paths.sound('pianoStuff/piano-${high ? '001' : '008'}'));
|
||||||
}
|
}
|
||||||
|
@ -3217,7 +3215,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
* Play a sound effect.
|
* Play a sound effect.
|
||||||
* Automatically cleans up after itself and recycles previous FlxSound instances if available, for performance.
|
* Automatically cleans up after itself and recycles previous FlxSound instances if available, for performance.
|
||||||
*/
|
*/
|
||||||
function playSound(path:String)
|
function playSound(path:String):Void
|
||||||
{
|
{
|
||||||
var snd:FlxSound = FlxG.sound.list.recycle(FlxSound);
|
var snd:FlxSound = FlxG.sound.list.recycle(FlxSound);
|
||||||
snd.loadEmbedded(FlxG.sound.cache(path));
|
snd.loadEmbedded(FlxG.sound.cache(path));
|
||||||
|
@ -3226,7 +3224,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
snd.play();
|
snd.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
override function destroy()
|
override function destroy():Void
|
||||||
{
|
{
|
||||||
super.destroy();
|
super.destroy();
|
||||||
|
|
||||||
|
@ -3282,7 +3280,14 @@ class ChartEditorState extends HaxeUIState
|
||||||
|
|
||||||
if (force)
|
if (force)
|
||||||
{
|
{
|
||||||
var targetPath:String = tmp ? Path.join([FileUtil.getTempDir(), 'chart-editor-exit-${DateUtil.generateTimestamp()}.zip']) : Path.join(['./backups/', 'chart-editor-exit-${DateUtil.generateTimestamp()}.zip']);
|
var targetPath:String = if (tmp)
|
||||||
|
{
|
||||||
|
Path.join([FileUtil.getTempDir(), 'chart-editor-exit-${DateUtil.generateTimestamp()}.zip']);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Path.join(['./backups/', 'chart-editor-exit-${DateUtil.generateTimestamp()}.zip']);
|
||||||
|
}
|
||||||
|
|
||||||
// We have to force write because the program will die before the save dialog is closed.
|
// We have to force write because the program will die before the save dialog is closed.
|
||||||
trace('Force exporting to $targetPath...');
|
trace('Force exporting to $targetPath...');
|
||||||
|
@ -3291,11 +3296,11 @@ class ChartEditorState extends HaxeUIState
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prompt and save.
|
// Prompt and save.
|
||||||
var onSave:Array<String>->Void = (paths:Array<String>) -> {
|
var onSave:Array<String>->Void = function(paths:Array<String>) {
|
||||||
trace('Successfully exported files.');
|
trace('Successfully exported files.');
|
||||||
};
|
};
|
||||||
|
|
||||||
var onCancel:Void->Void = () -> {
|
var onCancel:Void->Void = function() {
|
||||||
trace('Export cancelled.');
|
trace('Export cancelled.');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
package funkin.ui.haxeui;
|
package funkin.ui.haxeui;
|
||||||
|
|
||||||
import haxe.ui.containers.menus.MenuCheckBox;
|
|
||||||
import haxe.ui.components.CheckBox;
|
import haxe.ui.components.CheckBox;
|
||||||
import haxe.ui.events.DragEvent;
|
import haxe.ui.containers.menus.MenuCheckBox;
|
||||||
import haxe.ui.events.MouseEvent;
|
|
||||||
import haxe.ui.events.UIEvent;
|
|
||||||
import haxe.ui.RuntimeComponentBuilder;
|
|
||||||
import haxe.ui.core.Component;
|
import haxe.ui.core.Component;
|
||||||
import haxe.ui.core.Screen;
|
import haxe.ui.core.Screen;
|
||||||
import haxe.ui.events.MouseEvent;
|
import haxe.ui.events.MouseEvent;
|
||||||
|
import haxe.ui.events.UIEvent;
|
||||||
|
import haxe.ui.RuntimeComponentBuilder;
|
||||||
import lime.app.Application;
|
import lime.app.Application;
|
||||||
|
|
||||||
class HaxeUIState extends MusicBeatState
|
class HaxeUIState extends MusicBeatState
|
||||||
|
@ -23,7 +21,7 @@ class HaxeUIState extends MusicBeatState
|
||||||
_componentKey = key;
|
_componentKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
override function create()
|
override function create():Void
|
||||||
{
|
{
|
||||||
super.create();
|
super.create();
|
||||||
|
|
||||||
|
@ -31,7 +29,7 @@ class HaxeUIState extends MusicBeatState
|
||||||
if (component != null) add(component);
|
if (component != null) add(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildComponent(assetPath:String)
|
public function buildComponent(assetPath:String):Component
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -81,15 +79,13 @@ class HaxeUIState extends MusicBeatState
|
||||||
{
|
{
|
||||||
if (target == null)
|
if (target == null)
|
||||||
{
|
{
|
||||||
Screen.instance.registerEvent(MouseEvent.RIGHT_CLICK, function(e:MouseEvent)
|
Screen.instance.registerEvent(MouseEvent.RIGHT_CLICK, function(e:MouseEvent) {
|
||||||
{
|
|
||||||
showContextMenu(assetPath, e.screenX, e.screenY);
|
showContextMenu(assetPath, e.screenX, e.screenY);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
target.registerEvent(MouseEvent.RIGHT_CLICK, function(e:MouseEvent)
|
target.registerEvent(MouseEvent.RIGHT_CLICK, function(e:MouseEvent) {
|
||||||
{
|
|
||||||
showContextMenu(assetPath, e.screenX, e.screenY);
|
showContextMenu(assetPath, e.screenX, e.screenY);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -98,7 +94,7 @@ class HaxeUIState extends MusicBeatState
|
||||||
/**
|
/**
|
||||||
* Add an onClick listener to a HaxeUI menu bar item.
|
* Add an onClick listener to a HaxeUI menu bar item.
|
||||||
*/
|
*/
|
||||||
function addUIClickListener(key:String, callback:MouseEvent->Void)
|
function addUIClickListener(key:String, callback:MouseEvent->Void):Void
|
||||||
{
|
{
|
||||||
var target:Component = findComponent(key);
|
var target:Component = findComponent(key);
|
||||||
if (target == null)
|
if (target == null)
|
||||||
|
@ -112,10 +108,24 @@ class HaxeUIState extends MusicBeatState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setComponentText(key:String, text:String):Void
|
||||||
|
{
|
||||||
|
var target:Component = findComponent(key);
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
// Gracefully handle the case where the item can't be located.
|
||||||
|
trace('WARN: Could not locate menu item: $key');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target.text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an onChange listener to a HaxeUI input component such as a slider or text field.
|
* Add an onChange listener to a HaxeUI input component such as a slider or text field.
|
||||||
*/
|
*/
|
||||||
function addUIChangeListener(key:String, callback:UIEvent->Void)
|
function addUIChangeListener(key:String, callback:UIEvent->Void):Void
|
||||||
{
|
{
|
||||||
var target:Component = findComponent(key);
|
var target:Component = findComponent(key);
|
||||||
if (target == null)
|
if (target == null)
|
||||||
|
@ -179,7 +189,7 @@ class HaxeUIState extends MusicBeatState
|
||||||
return component.findComponent(criteria, type, recursive, searchType);
|
return component.findComponent(criteria, type, recursive, searchType);
|
||||||
}
|
}
|
||||||
|
|
||||||
override function destroy()
|
override function destroy():Void
|
||||||
{
|
{
|
||||||
if (component != null) remove(component);
|
if (component != null) remove(component);
|
||||||
component = null;
|
component = null;
|
||||||
|
|
Loading…
Reference in a new issue