mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2024-12-27 07:27:12 +00:00
Merge pull request #20 from FunkinCrew/chart-editor-fixes-with-dave
Chart editor fixes with dave
This commit is contained in:
commit
bf7a42d143
|
@ -156,9 +156,13 @@
|
||||||
<haxeflag name="--macro" value="include('funkin')" />
|
<haxeflag name="--macro" value="include('funkin')" />
|
||||||
|
|
||||||
<!-- Ensure all UI components are available at runtime. -->
|
<!-- Ensure all UI components are available at runtime. -->
|
||||||
|
<haxeflag name="--macro" value="include('haxe.ui.backend.flixel.components')" />
|
||||||
|
<haxeflag name="--macro" value="include('haxe.ui.containers.dialogs')" />
|
||||||
|
<haxeflag name="--macro" value="include('haxe.ui.containers.menus')" />
|
||||||
|
<haxeflag name="--macro" value="include('haxe.ui.containers.properties')" />
|
||||||
|
<haxeflag name="--macro" value="include('haxe.ui.core')" />
|
||||||
<haxeflag name="--macro" value="include('haxe.ui.components')" />
|
<haxeflag name="--macro" value="include('haxe.ui.components')" />
|
||||||
<haxeflag name="--macro" value="include('haxe.ui.containers')" />
|
<haxeflag name="--macro" value="include('haxe.ui.containers')" />
|
||||||
<haxeflag name="--macro" value="include('haxe.ui.containers.menus')" />
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Ensure additional class packages are available at runtime (some only really used by scripts).
|
Ensure additional class packages are available at runtime (some only really used by scripts).
|
||||||
|
|
|
@ -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"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
3
haxe_libraries/README.md
Normal file
3
haxe_libraries/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# haxe_libraries
|
||||||
|
|
||||||
|
Used by Lix
|
6
hmm.json
6
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"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
"name": "hxcodec",
|
"name": "hxcodec",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "2c9a89a",
|
"ref": "d74c2aa",
|
||||||
"url": "https://github.com/polybiusproxy/hxCodec"
|
"url": "https://github.com/polybiusproxy/hxCodec"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -169,6 +169,7 @@ class PolymodHandler
|
||||||
// `polymod.*`
|
// `polymod.*`
|
||||||
for (cls in ClassMacro.listClassesInPackage('polymod'))
|
for (cls in ClassMacro.listClassesInPackage('polymod'))
|
||||||
{
|
{
|
||||||
|
if (cls == null) continue;
|
||||||
var className = Type.getClassName(cls);
|
var className = Type.getClassName(cls);
|
||||||
Polymod.blacklistImport(className);
|
Polymod.blacklistImport(className);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -60,7 +60,7 @@ class VanillaCutscenes
|
||||||
#if html5
|
#if html5
|
||||||
// Video displays OVER the FlxState.
|
// Video displays OVER the FlxState.
|
||||||
vid = new FlxVideo(path);
|
vid = new FlxVideo(path);
|
||||||
vid.finishCallback = finishCutscene;
|
vid.finishCallback = finishCutscene.bind(0.5);
|
||||||
#else
|
#else
|
||||||
// Video displays OVER the FlxState.
|
// Video displays OVER the FlxState.
|
||||||
// vid = new FlxVideoSprite(0, 0);
|
// vid = new FlxVideoSprite(0, 0);
|
||||||
|
|
|
@ -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,16 +1,16 @@
|
||||||
package funkin.ui.debug.charting;
|
package funkin.ui.debug.charting;
|
||||||
|
|
||||||
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.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;
|
||||||
|
@ -18,28 +18,34 @@ import haxe.ui.components.TextField;
|
||||||
import haxe.ui.containers.Box;
|
import haxe.ui.containers.Box;
|
||||||
import haxe.ui.containers.dialogs.Dialog;
|
import haxe.ui.containers.dialogs.Dialog;
|
||||||
import haxe.ui.containers.dialogs.Dialogs;
|
import haxe.ui.containers.dialogs.Dialogs;
|
||||||
import haxe.ui.containers.properties.Property;
|
|
||||||
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles dialogs for the new Chart Editor.
|
||||||
|
*/
|
||||||
class ChartEditorDialogHandler
|
class ChartEditorDialogHandler
|
||||||
{
|
{
|
||||||
static final CHART_EDITOR_DIALOG_ABOUT_LAYOUT = Paths.ui('chart-editor/dialogs/about');
|
static final CHART_EDITOR_DIALOG_ABOUT_LAYOUT:String = Paths.ui('chart-editor/dialogs/about');
|
||||||
static final CHART_EDITOR_DIALOG_WELCOME_LAYOUT = Paths.ui('chart-editor/dialogs/welcome');
|
static final CHART_EDITOR_DIALOG_WELCOME_LAYOUT:String = Paths.ui('chart-editor/dialogs/welcome');
|
||||||
static final CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT = Paths.ui('chart-editor/dialogs/upload-inst');
|
static final CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-inst');
|
||||||
static final CHART_EDITOR_DIALOG_SONG_METADATA_LAYOUT = Paths.ui('chart-editor/dialogs/song-metadata');
|
static final CHART_EDITOR_DIALOG_SONG_METADATA_LAYOUT:String = Paths.ui('chart-editor/dialogs/song-metadata');
|
||||||
static final CHART_EDITOR_DIALOG_SONG_METADATA_CHARGROUP_LAYOUT = Paths.ui('chart-editor/dialogs/song-metadata-chargroup');
|
static final CHART_EDITOR_DIALOG_SONG_METADATA_CHARGROUP_LAYOUT:String = Paths.ui('chart-editor/dialogs/song-metadata-chargroup');
|
||||||
static final CHART_EDITOR_DIALOG_UPLOAD_VOCALS_LAYOUT = Paths.ui('chart-editor/dialogs/upload-vocals');
|
static final CHART_EDITOR_DIALOG_UPLOAD_VOCALS_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-vocals');
|
||||||
static final CHART_EDITOR_DIALOG_UPLOAD_VOCALS_ENTRY_LAYOUT = Paths.ui('chart-editor/dialogs/upload-vocals-entry');
|
static final CHART_EDITOR_DIALOG_UPLOAD_VOCALS_ENTRY_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-vocals-entry');
|
||||||
static final CHART_EDITOR_DIALOG_USER_GUIDE_LAYOUT = Paths.ui('chart-editor/dialogs/user-guide');
|
static final CHART_EDITOR_DIALOG_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
|
||||||
{
|
{
|
||||||
|
@ -48,105 +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
|
|
||||||
|
|
||||||
// Switch the graphic for frames.
|
|
||||||
var bfSpritePlaceholder:Image = dialog.findComponent('bfSprite', Image);
|
|
||||||
|
|
||||||
// TODO: Replace this bullshit with a custom HaxeUI component that loads the sprite from the game's assets.
|
|
||||||
|
|
||||||
if (bfSpritePlaceholder != null)
|
|
||||||
{
|
|
||||||
var bfSprite:FlxSprite = new FlxSprite(0, 0);
|
|
||||||
|
|
||||||
bfSprite.visible = false;
|
|
||||||
|
|
||||||
var frames = Paths.getSparrowAtlas(bfSpritePlaceholder.resource);
|
|
||||||
bfSprite.frames = frames;
|
|
||||||
|
|
||||||
bfSprite.animation.addByPrefix('idle', 'Boyfriend DJ0', 24, true);
|
|
||||||
bfSprite.animation.play('idle');
|
|
||||||
|
|
||||||
bfSpritePlaceholder.rootComponent.add(bfSprite);
|
|
||||||
bfSpritePlaceholder.visible = false;
|
|
||||||
|
|
||||||
new FlxTimer().start(0.10, (_timer:FlxTimer) ->
|
|
||||||
{
|
|
||||||
bfSprite.x = bfSpritePlaceholder.screenLeft;
|
|
||||||
bfSprite.y = bfSpritePlaceholder.screenTop;
|
|
||||||
bfSprite.setGraphicSize(Std.int(bfSpritePlaceholder.width), Std.int(bfSpritePlaceholder.height));
|
|
||||||
bfSprite.visible = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add handlers to the "Create From Song" section.
|
// 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);
|
// 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
|
||||||
|
@ -159,78 +130,175 @@ 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:SelectedFileInfo) {
|
||||||
{label: "Audio File (.ogg)", extension: "ogg"}], function(selectedFile)
|
if (selectedFile != null)
|
||||||
{
|
{
|
||||||
if (selectedFile != null)
|
if (state.loadInstrumentalFromBytes(selectedFile.bytes))
|
||||||
{
|
{
|
||||||
trace('Selected file: ' + selectedFile);
|
trace('Selected file: ' + selectedFile.fullPath);
|
||||||
state.loadInstrumentalFromBytes(selectedFile.bytes);
|
NotificationManager.instance.addNotification(
|
||||||
dialog.hideDialog(DialogButton.APPLY);
|
{
|
||||||
removeDropHandler(onDropFile);
|
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) {
|
||||||
{
|
var path:Path = new Path(pathStr);
|
||||||
trace('Dropped file: ' + path);
|
trace('Dropped file (${path})');
|
||||||
state.loadInstrumentalFromPath(path);
|
if (state.loadInstrumentalFromPath(path))
|
||||||
dialog.hideDialog(DialogButton.APPLY);
|
{
|
||||||
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(onDropFile);
|
addDropHandler(instrumentalBox, onDropFile);
|
||||||
|
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function addDropHandler(handler:String->Void)
|
static var dropHandlers:Array<
|
||||||
|
{
|
||||||
|
component:Component,
|
||||||
|
handler:(String->Void)
|
||||||
|
}> = [];
|
||||||
|
|
||||||
|
static function addDropHandler(component:Component, handler:String->Void):Void
|
||||||
{
|
{
|
||||||
#if desktop
|
#if desktop
|
||||||
FlxG.stage.window.onDropFile.add(handler);
|
if (!FlxG.stage.window.onDropFile.has(onDropFile)) FlxG.stage.window.onDropFile.add(onDropFile);
|
||||||
|
|
||||||
|
dropHandlers.push(
|
||||||
|
{
|
||||||
|
component: component,
|
||||||
|
handler: handler
|
||||||
|
});
|
||||||
#else
|
#else
|
||||||
trace('addDropHandler not implemented for this platform');
|
trace('addDropHandler not implemented for this platform');
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
static function removeDropHandler(handler:String->Void)
|
static function removeDropHandler(handler:String->Void):Void
|
||||||
{
|
{
|
||||||
#if desktop
|
#if desktop
|
||||||
FlxG.stage.window.onDropFile.remove(handler);
|
FlxG.stage.window.onDropFile.remove(handler);
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function clearDropHandlers():Void
|
||||||
|
{
|
||||||
|
#if desktop
|
||||||
|
dropHandlers = [];
|
||||||
|
FlxG.stage.window.onDropFile.remove(onDropFile);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
static function onDropFile(path:String):Void
|
||||||
|
{
|
||||||
|
// a VERY short timer to wait for the mouse position to update
|
||||||
|
new FlxTimer().start(0.01, function(_) {
|
||||||
|
for (handler in dropHandlers)
|
||||||
|
{
|
||||||
|
if (handler.component.hitTest(FlxG.mouse.screenX, FlxG.mouse.screenY))
|
||||||
|
{
|
||||||
|
handler.handler(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the dialog in the wizard where the user can set song metadata like name and artist and BPM.
|
||||||
|
* @param state The ChartEditorState instance.
|
||||||
|
* @return The dialog to open.
|
||||||
|
*/
|
||||||
public static function openSongMetadataDialog(state:ChartEditorState):Dialog
|
public static function openSongMetadataDialog(state:ChartEditorState):Dialog
|
||||||
{
|
{
|
||||||
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 = (event:UIEvent) ->
|
dialogSongName.onChange = function(event:UIEvent) {
|
||||||
{
|
var valid:Bool = event.target.text != null && event.target.text != '';
|
||||||
var valid = event.target.text != null && event.target.text != "";
|
|
||||||
|
|
||||||
if (valid)
|
if (valid)
|
||||||
{
|
{
|
||||||
|
@ -245,9 +313,8 @@ class ChartEditorDialogHandler
|
||||||
state.currentSongMetadata.songName = null;
|
state.currentSongMetadata.songName = null;
|
||||||
|
|
||||||
var dialogSongArtist:TextField = dialog.findComponent('dialogSongArtist', TextField);
|
var dialogSongArtist:TextField = dialog.findComponent('dialogSongArtist', TextField);
|
||||||
dialogSongArtist.onChange = (event:UIEvent) ->
|
dialogSongArtist.onChange = function(event:UIEvent) {
|
||||||
{
|
var valid:Bool = event.target.text != null && event.target.text != '';
|
||||||
var valid = event.target.text != null && event.target.text != "";
|
|
||||||
|
|
||||||
if (valid)
|
if (valid)
|
||||||
{
|
{
|
||||||
|
@ -262,29 +329,24 @@ class ChartEditorDialogHandler
|
||||||
state.currentSongMetadata.artist = null;
|
state.currentSongMetadata.artist = null;
|
||||||
|
|
||||||
var dialogStage:DropDown = dialog.findComponent('dialogStage', DropDown);
|
var dialogStage:DropDown = dialog.findComponent('dialogStage', DropDown);
|
||||||
dialogStage.onChange = (event:UIEvent) ->
|
dialogStage.onChange = function(event:UIEvent) {
|
||||||
{
|
if (event.data == null && event.data.id == null) return;
|
||||||
var valid = event.data != null && event.data.id != null;
|
|
||||||
|
|
||||||
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])];
|
||||||
|
@ -301,13 +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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -317,20 +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);
|
||||||
|
@ -342,27 +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);
|
||||||
};
|
};
|
||||||
|
@ -374,22 +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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -398,22 +446,37 @@ 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 onDropFile:String->Void;
|
var buttonCancel:Button = dialog.findComponent('dialogCancel', Button);
|
||||||
|
buttonCancel.onClick = function(_event) {
|
||||||
|
dialog.hideDialog(DialogButton.CANCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dialogNoVocals:Button = dialog.findComponent('dialogNoVocals', Button);
|
||||||
|
dialogNoVocals.onClick = function(_event) {
|
||||||
|
// Dismiss
|
||||||
|
dialog.hideDialog(DialogButton.APPLY);
|
||||||
|
};
|
||||||
|
|
||||||
for (charKey in charIdsForVocals)
|
for (charKey in charIdsForVocals)
|
||||||
{
|
{
|
||||||
|
@ -421,49 +484,77 @@ 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.';
|
||||||
|
|
||||||
vocalsEntry.onClick = (_event) ->
|
var onDropFile:String->Void = function(pathStr:String) {
|
||||||
{
|
trace('Selected file: $pathStr');
|
||||||
Dialogs.openBinaryFile('Open $charName Vocals', [
|
var path:Path = new Path(pathStr);
|
||||||
{label: "Audio File (.ogg)", extension: "ogg"}], function(selectedFile)
|
|
||||||
|
if (state.loadVocalsFromPath(path, charKey))
|
||||||
{
|
{
|
||||||
if (selectedFile != null)
|
// Tell the user the load was successful.
|
||||||
{
|
NotificationManager.instance.addNotification(
|
||||||
trace('Selected file: ' + selectedFile.name + "~" + selectedFile.fullPath);
|
{
|
||||||
vocalsEntryLabel.text = 'Vocals for $charName (click to browse)\n${selectedFile.name}';
|
title: 'Success',
|
||||||
state.loadVocalsFromBytes(selectedFile.bytes);
|
body: 'Loaded vocal track for $charName (${path.file}.${path.ext})',
|
||||||
removeDropHandler(onDropFile);
|
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) {
|
||||||
|
Dialogs.openBinaryFile('Open $charName Vocals', [
|
||||||
|
{label: 'Audio File (.ogg)', extension: 'ogg'}], function(selectedFile) {
|
||||||
|
if (selectedFile != null)
|
||||||
|
{
|
||||||
|
trace('Selected file: ' + selectedFile.name);
|
||||||
|
vocalsEntryLabel.text = 'Vocals for $charName (click to browse)\n${selectedFile.name}';
|
||||||
|
state.loadVocalsFromBytes(selectedFile.bytes, charKey);
|
||||||
|
dialogNoVocals.hidden = true;
|
||||||
|
removeDropHandler(onDropFile);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// onDropFile
|
||||||
|
addDropHandler(vocalsEntry, onDropFile);
|
||||||
dialogContainer.addComponent(vocalsEntry);
|
dialogContainer.addComponent(vocalsEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
var dialogContinue:Button = dialog.findComponent('dialogContinue', Button);
|
var dialogContinue:Button = dialog.findComponent('dialogContinue', Button);
|
||||||
dialogContinue.onClick = (_event) ->
|
dialogContinue.onClick = function(_event) {
|
||||||
{
|
// Dismiss
|
||||||
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.
|
|
||||||
|
|
||||||
onDropFile = (path:String) ->
|
|
||||||
{
|
|
||||||
trace('Dropped file: ' + path);
|
|
||||||
};
|
|
||||||
addDropHandler(onDropFile);
|
|
||||||
|
|
||||||
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
|
||||||
{
|
{
|
||||||
|
@ -483,8 +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,7 +1,6 @@
|
||||||
package funkin.ui.debug.charting;
|
package funkin.ui.debug.charting;
|
||||||
|
|
||||||
import flixel.FlxObject;
|
import flixel.FlxObject;
|
||||||
import flixel.FlxBasic;
|
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.graphics.frames.FlxFramesCollection;
|
import flixel.graphics.frames.FlxFramesCollection;
|
||||||
import flixel.graphics.frames.FlxTileFrames;
|
import flixel.graphics.frames.FlxTileFrames;
|
||||||
|
@ -14,6 +13,14 @@ import funkin.play.song.SongData.SongNoteData;
|
||||||
*/
|
*/
|
||||||
class ChartEditorNoteSprite extends FlxSprite
|
class ChartEditorNoteSprite extends FlxSprite
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The list of available note skin to validate against.
|
||||||
|
*/
|
||||||
|
public static final NOTE_STYLES:Array<String> = ['Normal', 'Pixel'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ChartEditorState this note belongs to.
|
||||||
|
*/
|
||||||
public var parentState:ChartEditorState;
|
public var parentState:ChartEditorState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,6 +29,11 @@ class ChartEditorNoteSprite extends FlxSprite
|
||||||
*/
|
*/
|
||||||
public var noteData(default, set):SongNoteData;
|
public var noteData(default, set):SongNoteData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the note style currently in use.
|
||||||
|
*/
|
||||||
|
public var noteStyle(get, null):String;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This note is the previous sprite in a sustain chain.
|
* This note is the previous sprite in a sustain chain.
|
||||||
*/
|
*/
|
||||||
|
@ -222,14 +234,20 @@ class ChartEditorNoteSprite extends FlxSprite
|
||||||
return this.childNoteSprite;
|
return this.childNoteSprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function playNoteAnimation()
|
function get_noteStyle():String
|
||||||
|
{
|
||||||
|
// Fall back to 'Normal' if it's not a valid note style.
|
||||||
|
return if (NOTE_STYLES.contains(this.parentState.currentSongNoteSkin)) this.parentState.currentSongNoteSkin else 'Normal';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function playNoteAnimation():Void
|
||||||
{
|
{
|
||||||
// Decide whether to display a note or a sustain.
|
// Decide whether to display a note or a sustain.
|
||||||
var baseAnimationName:String = 'tap';
|
var baseAnimationName:String = 'tap';
|
||||||
if (this.parentNoteSprite != null) baseAnimationName = (this.childNoteSprite != null) ? 'hold' : 'holdEnd';
|
if (this.parentNoteSprite != null) baseAnimationName = (this.childNoteSprite != null) ? 'hold' : 'holdEnd';
|
||||||
|
|
||||||
// Play the appropriate animation for the type, direction, and skin.
|
// Play the appropriate animation for the type, direction, and skin.
|
||||||
var animationName = '${baseAnimationName}${this.noteData.getDirectionName()}${this.parentState.currentSongNoteSkin}';
|
var animationName:String = '${baseAnimationName}${this.noteData.getDirectionName()}${this.noteStyle}';
|
||||||
|
|
||||||
this.animation.play(animationName);
|
this.animation.play(animationName);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||||
|
|
|
@ -5,6 +5,10 @@ import lime.utils.Bytes;
|
||||||
import lime.ui.FileDialog;
|
import lime.ui.FileDialog;
|
||||||
import openfl.net.FileFilter;
|
import openfl.net.FileFilter;
|
||||||
import haxe.io.Path;
|
import haxe.io.Path;
|
||||||
|
#if html5
|
||||||
|
import openfl.net.FileReference;
|
||||||
|
import openfl.events.Event;
|
||||||
|
#end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for reading and writing files on various platforms.
|
* Utilities for reading and writing files on various platforms.
|
||||||
|
@ -141,8 +145,6 @@ class FileUtil
|
||||||
fileDialog.open(filter, defaultPath, dialogTitle);
|
fileDialog.open(filter, defaultPath, dialogTitle);
|
||||||
return true;
|
return true;
|
||||||
#elseif html5
|
#elseif html5
|
||||||
var filter = convertTypeFilter(typeFilter);
|
|
||||||
|
|
||||||
var onFileLoaded = function(event) {
|
var onFileLoaded = function(event) {
|
||||||
var loadedFileRef:FileReference = event.target;
|
var loadedFileRef:FileReference = event.target;
|
||||||
trace('Loaded file: ' + loadedFileRef.name);
|
trace('Loaded file: ' + loadedFileRef.name);
|
||||||
|
@ -157,8 +159,9 @@ class FileUtil
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileRef = new FileReference();
|
var fileRef = new FileReference();
|
||||||
file.addEventListener(Event.SELECT, onFileSelected);
|
fileRef.addEventListener(Event.SELECT, onFileSelected);
|
||||||
file.open(filter, defaultPath, dialogTitle);
|
fileRef.browse(typeFilter);
|
||||||
|
return true;
|
||||||
#else
|
#else
|
||||||
onCancel();
|
onCancel();
|
||||||
return false;
|
return false;
|
||||||
|
@ -169,7 +172,6 @@ class FileUtil
|
||||||
* Browses for a single file location, then writes the provided `haxe.io.Bytes` data and calls `onSave(path)` when done.
|
* Browses for a single file location, then writes the provided `haxe.io.Bytes` data and calls `onSave(path)` when done.
|
||||||
* Works great on desktop and HTML5.
|
* Works great on desktop and HTML5.
|
||||||
*
|
*
|
||||||
* @param typeFilter TODO What does this do?
|
|
||||||
* @return Whether the file dialog was opened successfully.
|
* @return Whether the file dialog was opened successfully.
|
||||||
*/
|
*/
|
||||||
public static function saveFile(data:Bytes, ?onSave:String->Void, ?onCancel:Void->Void, ?defaultFileName:String, ?dialogTitle:String):Bool
|
public static function saveFile(data:Bytes, ?onSave:String->Void, ?onCancel:Void->Void, ?defaultFileName:String, ?dialogTitle:String):Bool
|
||||||
|
@ -191,6 +193,7 @@ class FileUtil
|
||||||
if (onCancel != null) fileDialog.onCancel.add(onCancel);
|
if (onCancel != null) fileDialog.onCancel.add(onCancel);
|
||||||
|
|
||||||
fileDialog.save(data, filter, defaultFileName, dialogTitle);
|
fileDialog.save(data, filter, defaultFileName, dialogTitle);
|
||||||
|
return true;
|
||||||
#else
|
#else
|
||||||
onCancel();
|
onCancel();
|
||||||
return false;
|
return false;
|
||||||
|
@ -374,7 +377,11 @@ class FileUtil
|
||||||
*/
|
*/
|
||||||
public static function appendStringToPath(path:String, data:String)
|
public static function appendStringToPath(path:String, data:String)
|
||||||
{
|
{
|
||||||
|
#if sys
|
||||||
sys.io.File.append(path, false).writeString(data);
|
sys.io.File.append(path, false).writeString(data);
|
||||||
|
#else
|
||||||
|
throw 'Direct file writing by path not supported on this platform.';
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -410,7 +417,7 @@ class FileUtil
|
||||||
{
|
{
|
||||||
path = Sys.getEnv(envName);
|
path = Sys.getEnv(envName);
|
||||||
|
|
||||||
if (path == "") path = null;
|
if (path == '') path = null;
|
||||||
if (path != null) break;
|
if (path != null) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,13 @@
|
||||||
This needs to be done HERE and not via the `include` macro because `Toolkit.init()`
|
This needs to be done HERE and not via the `include` macro because `Toolkit.init()`
|
||||||
reads this to build the component registry.
|
reads this to build the component registry.
|
||||||
-->
|
-->
|
||||||
<class package="haxe.ui.core" loadAll="true" />
|
<class package="haxe.ui.backend.flixel.components" loadAll="true" />
|
||||||
|
|
||||||
<class package="haxe.ui.components" loadAll="true" />
|
<class package="haxe.ui.components" loadAll="true" />
|
||||||
|
|
||||||
<class package="haxe.ui.containers" loadAll="true" />
|
|
||||||
<class package="haxe.ui.containers.menus" loadAll="true" />
|
|
||||||
<class package="haxe.ui.containers.dialogs" loadAll="true" />
|
<class package="haxe.ui.containers.dialogs" loadAll="true" />
|
||||||
|
<class package="haxe.ui.containers.menus" loadAll="true" />
|
||||||
<class package="haxe.ui.containers.properties" loadAll="true" />
|
<class package="haxe.ui.containers.properties" loadAll="true" />
|
||||||
|
<class package="haxe.ui.containers" loadAll="true" />
|
||||||
|
<class package="haxe.ui.core" loadAll="true" />
|
||||||
|
|
||||||
<!-- Custom components. -->
|
<!-- Custom components. -->
|
||||||
<class package="funkin.ui.haxeui.components" loadAll="true" />
|
<class package="funkin.ui.haxeui.components" loadAll="true" />
|
||||||
|
|
Loading…
Reference in a new issue