Merge remote-tracking branch 'upstream/main' into new-editors-main
# Conflicts: # commandline/commands/Compiler.hx # source/funkin/backend/FunkinSprite.hx # source/funkin/backend/MusicBeatState.hx # source/funkin/backend/MusicBeatSubstate.hx # source/funkin/backend/chart/Chart.hx # source/funkin/backend/chart/EventsData.hx # source/funkin/backend/scripting/GlobalScript.hx # source/funkin/backend/system/Controls.hx # source/funkin/backend/system/MainState.hx # source/funkin/backend/utils/AudioAnalyzer.hx # source/funkin/backend/utils/CoolUtil.hx # source/funkin/editors/character/CharacterInfoScreen.hx # source/funkin/editors/charter/Charter.hx # source/funkin/editors/charter/CharterSelection.hx # source/funkin/editors/charter/CharterStrumline.hx # source/funkin/editors/charter/CharterStrumlineButton.hx # source/funkin/editors/charter/SongCreationScreen.hx # source/funkin/editors/ui/UIDropDown.hx # source/funkin/editors/ui/UIFileExplorer.hx # source/funkin/game/Note.hx # source/funkin/game/PlayState.hx # source/funkin/game/SplashGroup.hx # source/funkin/game/Stage.hx # source/funkin/game/Strum.hx # source/funkin/menus/FreeplayState.hx # source/funkin/options/Options.hx # source/funkin/options/keybinds/KeybindsOptions.hx
This commit is contained in:
@@ -7,6 +7,7 @@ import funkin.options.*;
|
||||
class EditorTreeMenu extends TreeMenu {
|
||||
public var bg:FlxBackdrop;
|
||||
public var bgType:String = "default";
|
||||
public var bgMovement:FlxPoint = new FlxPoint();
|
||||
|
||||
public override function create() {
|
||||
super.create();
|
||||
@@ -18,16 +19,16 @@ class EditorTreeMenu extends TreeMenu {
|
||||
bg = new FlxBackdrop();
|
||||
bg.loadGraphic(Paths.image('editors/bgs/${bgType}'));
|
||||
bg.antialiasing = true;
|
||||
setBackgroundRotation(-5);
|
||||
add(bg);
|
||||
}
|
||||
|
||||
public inline function setBackgroundRotation(rotation:Float) {
|
||||
bg.rotation = rotation;
|
||||
bg.velocity.set(85, 0).degrees = bg.rotation;
|
||||
}
|
||||
|
||||
public override function exit() {
|
||||
FlxG.switchState(new MainMenuState());
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
bg.x += elapsed * 125;
|
||||
bg.y += elapsed * 125;
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ class SaveWarning {
|
||||
if (closingWindow) WindowUtils.resetClosing();
|
||||
} else {
|
||||
WindowUtils.preventClosing = false; WindowUtils.resetClosing();
|
||||
Sys.exit(0);
|
||||
openfl.system.System.exit(0);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -51,7 +51,7 @@ class SaveWarning {
|
||||
if (closingWindow) WindowUtils.resetClosing();
|
||||
} else {
|
||||
WindowUtils.preventClosing = false; WindowUtils.resetClosing();
|
||||
Sys.exit(0);
|
||||
openfl.system.System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import openfl.geom.Point;
|
||||
import openfl.geom.Rectangle;
|
||||
import openfl.display.BitmapData;
|
||||
import funkin.game.Character;
|
||||
import funkin.game.HealthIcon;
|
||||
import haxe.xml.Access;
|
||||
|
||||
using funkin.backend.utils.BitmapUtil;
|
||||
|
||||
@@ -22,6 +24,12 @@ class CharacterInfoScreen extends UISubstateWindow {
|
||||
public var character:Character;
|
||||
|
||||
public var iconColorPicker:UIIconColorPicker;
|
||||
public var spriteTextBox:UITextBox;
|
||||
public var iconTextBox:UITextBox;
|
||||
public var iconSprite:HealthIcon;
|
||||
public var gameOverCharTextBox:UITextBox;
|
||||
public var antialiasingCheckbox:UICheckbox;
|
||||
public var flipXCheckbox:UICheckbox;
|
||||
public var iconColorWheel:UIColorwheel;
|
||||
|
||||
public var useDurationCheckbox:UICheckbox;
|
||||
@@ -101,17 +109,58 @@ class CharacterInfoScreen extends UISubstateWindow {
|
||||
closeButton.color = 0xFFFF0000;
|
||||
}
|
||||
|
||||
public function saveCharacterInfo() {
|
||||
function updateIcon(icon:String) {
|
||||
if (iconSprite == null) add(iconSprite = new HealthIcon());
|
||||
|
||||
iconSprite.setIcon(icon);
|
||||
var size = Std.int(150 * 0.5);
|
||||
iconSprite.setUnstretchedGraphicSize(size, size, true);
|
||||
iconSprite.updateHitbox();
|
||||
iconSprite.setPosition(iconTextBox.x + iconTextBox.bWidth + 8, iconTextBox.y + (iconTextBox.bHeight / 2) - (iconSprite.height / 2));
|
||||
iconSprite.scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
function saveCharacterInfo() {
|
||||
UIUtil.confirmUISelections(this);
|
||||
|
||||
if (onSave != null) onSave({
|
||||
icon: iconColorPicker.iconTextBox.label.text,
|
||||
iconColor: iconColorWheel.curColor,
|
||||
holdTime: useDurationCheckbox.checked ? durationStepper.value : -1,
|
||||
customProperties: [
|
||||
for (val in customPropertiesButtonList.buttons.members)
|
||||
val.propertyText.label.text => val.valueText.label.text
|
||||
]
|
||||
});
|
||||
//for (stepper in [positionXStepper, positionYStepper, cameraXStepper, cameraYStepper, singTimeStepper, scaleStepper])
|
||||
// @:privateAccess stepper.__onChange(stepper.label.text);
|
||||
|
||||
var xml = Xml.createElement("character");
|
||||
xml.set("isPlayer", isPlayerCheckbox.checked ? "true" : "false");
|
||||
xml.set("x", Std.string(positionXStepper.value));
|
||||
xml.set("y", Std.string(positionYStepper.value));
|
||||
xml.set("gameOverChar", gameOverCharTextBox.label.text);
|
||||
xml.set("camx", Std.string(cameraXStepper.value));
|
||||
xml.set("camy", Std.string(cameraYStepper.value));
|
||||
xml.set("holdTime", Std.string(singTimeStepper.value));
|
||||
xml.set("flipX", Std.string(flipXCheckbox.checked));
|
||||
xml.set("icon", iconTextBox.label.text);
|
||||
xml.set("scale", Std.string(scaleStepper.value));
|
||||
xml.set("antialiasing", antialiasingCheckbox.checked ? "true" : "false");
|
||||
xml.set("sprite", spriteTextBox.label.text);
|
||||
if (iconColorWheel.colorChanged)
|
||||
xml.set("color", iconColorWheel.curColor.toWebString());
|
||||
for (val in customPropertiesButtonList.buttons.members)
|
||||
xml.set(val.propertyText.label.text, val.valueText.label.text);
|
||||
|
||||
for (anim in character.animDatas)
|
||||
{
|
||||
var animXml:Xml = Xml.createElement('anim');
|
||||
animXml.set("name", anim.name);
|
||||
animXml.set("anim", anim.anim);
|
||||
animXml.set("loop", Std.string(anim.loop));
|
||||
animXml.set("fps", Std.string(anim.fps));
|
||||
var offset:FlxPoint = character.getAnimOffset(anim.name);
|
||||
animXml.set("x", Std.string(offset.x));
|
||||
animXml.set("y", Std.string(offset.y));
|
||||
offset.put();
|
||||
|
||||
if (anim.indices.length > 0)
|
||||
animXml.set("indices", CoolUtil.formatNumberRange(anim.indices));
|
||||
xml.addChild(animXml);
|
||||
}
|
||||
|
||||
if (onSave != null) onSave(xml);
|
||||
}
|
||||
}
|
||||
@@ -318,7 +318,8 @@ class CompactCharacterButton extends UIButton {
|
||||
autoAlpha = false;
|
||||
|
||||
charIcon = new HealthIcon(funkin.game.Character.getIconFromCharName(char));
|
||||
charIcon.scale.set(0.2, 0.2);
|
||||
var size = Std.int(150 * 0.2);
|
||||
charIcon.setUnstretchedGraphicSize(size, size, true);
|
||||
charIcon.updateHitbox();
|
||||
charIcon.setPosition(10, bHeight/2 - charIcon.height / 2);
|
||||
charIcon.scrollFactor.set(1,1);
|
||||
@@ -330,11 +331,10 @@ class CompactCharacterButton extends UIButton {
|
||||
textBox.antialiasing = true;
|
||||
textBox.onChange = function(char:String) {
|
||||
char = funkin.game.Character.getIconFromCharName(char);
|
||||
var image = Paths.image("icons/" + char);
|
||||
if(!Assets.exists(image))
|
||||
image = Paths.image("icons/" + Flags.DEFAULT_HEALTH_ICON);
|
||||
charIcon.loadGraphic(image, true, 150, 150);
|
||||
charIcon.setIcon(char);
|
||||
charIcon.setUnstretchedGraphicSize(size, size, true);
|
||||
charIcon.updateHitbox();
|
||||
charIcon.setPosition(10, bHeight/2 - charIcon.height / 2);
|
||||
}
|
||||
|
||||
deleteButton = new UIButton(textBox.x + 115 + 16, bHeight/2 - (32/2), null, function () {
|
||||
|
||||
@@ -1423,8 +1423,11 @@ class Charter extends UIState {
|
||||
for(id=>str in strumLines.members)
|
||||
if (str != null) str.y = strumlineInfoBG.y;
|
||||
|
||||
strumlineAddButton.x = 0;
|
||||
strumlineAddButton.y = strumlineInfoBG.y;
|
||||
strumlineLockButton.y = strumlineInfoBG.y;
|
||||
|
||||
strumlineLockButton.text.visible = strumlineLockButton.button.selectable = strumlineLockButton.button.visible = strumLines.members.length > 0;
|
||||
}
|
||||
|
||||
public override function onResize(width:Int, height:Int) {
|
||||
@@ -1558,7 +1561,7 @@ class Charter extends UIState {
|
||||
#if REGION
|
||||
function _file_exit(_) {
|
||||
if (undos.unsaved) SaveWarning.triggerWarning();
|
||||
else {undos = null; FlxG.switchState(new CharterSelection()); PlayState.resetSongInfos(); Charter.instance.__clearStatics();}
|
||||
else {undos = null; FlxG.switchState(new CharterSelection()); Charter.instance.__clearStatics();}
|
||||
}
|
||||
|
||||
function _file_save_all(_) saveEverything();
|
||||
@@ -2145,7 +2148,7 @@ class Charter extends UIState {
|
||||
}
|
||||
|
||||
@:noCompletion public function __clearStatics() {
|
||||
selection = null; undos = null; clipboard = null; playtestInfo = null;
|
||||
selection = null; undos = null; clipboard = null; playtestInfo = null;
|
||||
waveformHandler.destroy(); Charter.waveformHandler = null; autoSaveTimer = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ class CharterAutoSaveUI extends UISliceSprite {
|
||||
bar.follow(this, 10, bHeight-20);
|
||||
bar.alpha = alpha;
|
||||
}
|
||||
progressBar.clipRect = progressBar.clipRect.set(0, 0, progressBar.width*progress,progressBar.height);
|
||||
progressBar.rawClipRect = progressBar.rawClipRect.set(0, 0, progressBar.frameWidth*progress,progressBar.frameHeight);
|
||||
}
|
||||
|
||||
public function appearAnimation() {
|
||||
|
||||
@@ -202,11 +202,11 @@ class CharterEventScreen extends UISubstateWindow {
|
||||
public function saveCurTab() {
|
||||
if (curEvent < 0) return;
|
||||
|
||||
events[curEvent].params = [
|
||||
for(p in paramsFields) {
|
||||
var dataParams = EventsData.getEventParams(events[curEvent].name);
|
||||
var params:Array<Dynamic> = [
|
||||
for (i => p in paramsFields) {
|
||||
if (p is UIDropDown) {
|
||||
var dataParams = EventsData.getEventParams(events[curEvent].name);
|
||||
if (dataParams[paramsFields.indexOf(p)].type == TStrumLine) cast(p, UIDropDown).index;
|
||||
if (dataParams[i].type == TStrumLine) cast(p, UIDropDown).index;
|
||||
else cast(p, UIDropDown).label.text;
|
||||
}
|
||||
else if (p is UINumericStepper) {
|
||||
@@ -227,6 +227,14 @@ class CharterEventScreen extends UISubstateWindow {
|
||||
null;
|
||||
}
|
||||
];
|
||||
|
||||
while(dataParams.length > 0 && {
|
||||
var index = params.length - 1;
|
||||
var dataParam = dataParams[index];
|
||||
dataParam.saveIfDefault == false && params[index] == dataParam.defValue;
|
||||
}) params.pop();
|
||||
|
||||
events[curEvent].params = params;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package funkin.editors.charter;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.backend.chart.ChartData.ChartMetaData;
|
||||
import funkin.editors.extra.PropertyButton;
|
||||
import funkin.game.HealthIcon;
|
||||
|
||||
using StringTools;
|
||||
|
||||
@@ -19,7 +20,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
|
||||
public var displayNameTextBox:UITextBox;
|
||||
public var iconTextBox:UITextBox;
|
||||
public var iconSprite:FlxSprite;
|
||||
public var iconSprite:HealthIcon;
|
||||
public var opponentModeCheckbox:UICheckbox;
|
||||
public var coopAllowedCheckbox:UICheckbox;
|
||||
public var colorWheel:UIColorwheel;
|
||||
@@ -84,7 +85,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
coopAllowedCheckbox = new UICheckbox(opponentModeCheckbox.x + 150 + 26, opponentModeCheckbox.y, "Co-op Mode", metadata.coopAllowed);
|
||||
add(coopAllowedCheckbox);
|
||||
|
||||
colorWheel = new UIColorwheel(iconTextBox.x, coopAllowedCheckbox.y, metadata.parsedColor);
|
||||
colorWheel = new UIColorwheel(iconTextBox.x, coopAllowedCheckbox.y, metadata.color);
|
||||
add(colorWheel);
|
||||
addLabelOn(colorWheel, "Color");
|
||||
|
||||
@@ -124,22 +125,14 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
}
|
||||
|
||||
function updateIcon(icon:String) {
|
||||
if (iconSprite == null) add(iconSprite = new FlxSprite());
|
||||
if (iconSprite == null) add(iconSprite = new HealthIcon());
|
||||
|
||||
if (iconSprite.animation.exists(icon)) return;
|
||||
@:privateAccess iconSprite.animation.clearAnimations();
|
||||
|
||||
var path:String = Paths.image('icons/$icon');
|
||||
if (!Assets.exists(path)) path = Paths.image('icons/' + Flags.DEFAULT_HEALTH_ICON);
|
||||
|
||||
iconSprite.loadGraphic(path, true, 150, 150);
|
||||
iconSprite.animation.add(icon, [0], 0, false);
|
||||
iconSprite.antialiasing = true;
|
||||
iconSprite.animation.play(icon);
|
||||
|
||||
iconSprite.scale.set(0.5, 0.5);
|
||||
iconSprite.setIcon(icon);
|
||||
var size = Std.int(150 * 0.5);
|
||||
iconSprite.setUnstretchedGraphicSize(size, size, true);
|
||||
iconSprite.updateHitbox();
|
||||
iconSprite.setPosition(iconTextBox.x + 150 + 8, (iconTextBox.y + 16) - (iconSprite.height/2));
|
||||
iconSprite.setPosition(iconTextBox.x + iconTextBox.bWidth + 8, iconTextBox.y + (iconTextBox.bHeight / 2) - (iconSprite.height / 2));
|
||||
iconSprite.scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
public function saveMeta() {
|
||||
@@ -157,8 +150,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
stepsPerBeat: Std.int(stepsPerBeatStepper.value),
|
||||
displayName: displayNameTextBox.label.text,
|
||||
icon: iconTextBox.label.text,
|
||||
color: colorWheel.curColorString,
|
||||
parsedColor: colorWheel.curColor,
|
||||
color: colorWheel.curColor,
|
||||
opponentModeAllowed: opponentModeCheckbox.checked,
|
||||
coopAllowed: coopAllowedCheckbox.checked,
|
||||
difficulties: [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package funkin.editors.charter;
|
||||
|
||||
import funkin.backend.chart.Chart;
|
||||
import funkin.backend.chart.ChartData.ChartMetaData;
|
||||
import funkin.backend.chart.ChartData;
|
||||
import funkin.backend.system.framerate.Framerate;
|
||||
@@ -34,16 +35,20 @@ class CharterSelection extends EditorTreeMenu {
|
||||
FlxG.switchState(new Charter(s.name, d));
|
||||
})
|
||||
];
|
||||
list.push(new NewOption("New Difficulty", "Press ACCEPT to create a new difficulty.", function() {
|
||||
#if sys
|
||||
list.push(new NewOption("New Difficulty", "New Difficulty", function() {
|
||||
FlxG.state.openSubState(new ChartCreationScreen(saveChart));
|
||||
}));
|
||||
#end
|
||||
optionsTree.add(new OptionsScreen(s.name, "Select a difficulty to continue.", list));
|
||||
}, s.parsedColor.getDefault(0xFFFFFFFF))
|
||||
}, s.color.getDefault(0xFFFFFFFF))
|
||||
];
|
||||
|
||||
list.insert(0, new NewOption("New Song", "Press ACCEPT to create a new song.", function() {
|
||||
#if sys
|
||||
list.insert(0, new NewOption("New Song", "New Song", function() {
|
||||
FlxG.state.openSubState(new SongCreationScreen(saveSong));
|
||||
}));
|
||||
#end
|
||||
|
||||
main = new OptionsScreen("Chart Editor", "Select a song to modify the charts from.", list);
|
||||
|
||||
@@ -88,11 +93,12 @@ class CharterSelection extends EditorTreeMenu {
|
||||
}
|
||||
}
|
||||
|
||||
public function saveSong(creation:SongCreationData) {
|
||||
#if sys
|
||||
public function saveSong(creation:SongCreationData, ?callback:String -> SongCreationData -> Void) {
|
||||
var songAlreadyExists:Bool = [for (s in freeplayList.songs) s.name.toLowerCase()].contains(creation.meta.name.toLowerCase());
|
||||
|
||||
if (songAlreadyExists) {
|
||||
openSubState(new UIWarningSubstate("Creating Song: Error!", "The song you are trying to create already exists, if you would like to override it delete the song first!", [
|
||||
openSubState(new UIWarningSubstate("Creating Song: Error!", "The song you are trying to create Already exists, if you would like to override it delete the song first!", [
|
||||
{label: "Ok", color: 0xFFFF0000, onClick: function(t) {}}
|
||||
]));
|
||||
return;
|
||||
@@ -109,11 +115,17 @@ class CharterSelection extends EditorTreeMenu {
|
||||
sys.FileSystem.createDirectory('$songFolder/charts');
|
||||
|
||||
// Save Files
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Json.stringify(creation.meta, Flags.JSON_PRETTY_PRINT));
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Chart.makeMetaSaveable(creation.meta));
|
||||
if (creation.instBytes != null) sys.io.File.saveBytes('$songFolder/song/Inst.${Flags.SOUND_EXT}', creation.instBytes);
|
||||
if (creation.voicesBytes != null) sys.io.File.saveBytes('$songFolder/song/Voices.${Flags.SOUND_EXT}', creation.voicesBytes);
|
||||
|
||||
if (creation.playerVocals != null) sys.io.File.saveBytes('$songFolder/song/Voices-Player.${Flags.SOUND_EXT}', creation.playerVocals);
|
||||
if (creation.oppVocals != null) sys.io.File.saveBytes('$songFolder/song/Voices-Opponent.${Flags.SOUND_EXT}', creation.oppVocals);
|
||||
#end
|
||||
|
||||
if (callback != null)
|
||||
callback(songFolder, creation);
|
||||
|
||||
var option = new EditorIconOption(creation.meta.name, "Press ACCEPT to choose a difficulty to edit.", creation.meta.icon, function() {
|
||||
curSong = creation.meta;
|
||||
var list:Array<OptionType> = [
|
||||
@@ -122,11 +134,11 @@ class CharterSelection extends EditorTreeMenu {
|
||||
FlxG.switchState(new Charter(creation.meta.name, d));
|
||||
})
|
||||
];
|
||||
list.push(new NewOption("New Difficulty", "Press ACCEPT to create a new difficulty.", function() {
|
||||
list.push(new NewOption("New Difficulty", "New Difficulty", function() {
|
||||
FlxG.state.openSubState(new ChartCreationScreen(saveChart));
|
||||
}));
|
||||
optionsTree.insert(1, new OptionsScreen(creation.meta.name, "Select a difficulty to continue.", list));
|
||||
}, creation.meta.parsedColor.getDefault(0xFFFFFFFF));
|
||||
}, creation.meta.color.getDefault(0xFFFFFFFF));
|
||||
|
||||
// Add to List
|
||||
freeplayList.songs.insert(0, creation.meta);
|
||||
@@ -160,7 +172,8 @@ class CharterSelection extends EditorTreeMenu {
|
||||
var meta = Json.parse(sys.io.File.getContent('$songFolder/meta.json'));
|
||||
if (meta.difficulties != null && !meta.difficulties.contains(name)) {
|
||||
meta.difficulties.push(name);
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Json.stringify(meta));
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Chart.makeMetaSaveable(meta));
|
||||
}
|
||||
}
|
||||
#end
|
||||
}
|
||||
@@ -88,8 +88,7 @@ class CharterStrumline extends UISprite {
|
||||
button = new CharterStrumlineOptions(this);
|
||||
members.push(button);
|
||||
|
||||
vocals = strumLine.vocalsSuffix.length > 0 ? FlxG.sound.load(Paths.voices(PlayState.SONG.meta.name, PlayState.difficulty, strumLine.vocalsSuffix)) : new FlxSound();
|
||||
vocals.group = FlxG.sound.defaultMusicGroup;
|
||||
updateInfo();
|
||||
|
||||
selectedWaveform = -1;
|
||||
}
|
||||
|
||||
@@ -58,8 +58,8 @@ class CharterStrumlineButton extends UISprite {
|
||||
|
||||
super.update(elapsed);
|
||||
|
||||
button.updateSpriteRect();
|
||||
if(UIState.state.curContextMenu == null && UIState.state.isOverlapping(button, button.__rect)) {
|
||||
if (UIState.state.curContextMenu == null && UIState.state.isOverlapping(button, button.__rect) && button.visible) {
|
||||
UIState.state.updateSpriteRect(button);
|
||||
buttonScale.set(0.95, 0.95);
|
||||
if (FlxG.mouse.justPressed && onClick != null) {
|
||||
onClick();
|
||||
|
||||
@@ -242,7 +242,8 @@ class CharacterButton extends UIButton {
|
||||
super(x, y, null, null, 250, 54);
|
||||
|
||||
charIcon = new HealthIcon(Character.getIconFromCharName(char));
|
||||
charIcon.scale.set(0.3, 0.3);
|
||||
var size = Std.int(150 * 0.3);
|
||||
charIcon.setUnstretchedGraphicSize(size, size, true);
|
||||
charIcon.updateHitbox();
|
||||
charIcon.setPosition(x + 10, bHeight/2 - charIcon.height / 2);
|
||||
charIcon.scrollFactor.set(1,1);
|
||||
@@ -254,11 +255,10 @@ class CharacterButton extends UIButton {
|
||||
textBox.antialiasing = true;
|
||||
textBox.onChange = function(char:String) {
|
||||
char = Character.getIconFromCharName(char);
|
||||
var image = Paths.image("icons/" + char);
|
||||
if(!Assets.exists(image))
|
||||
image = Paths.image("icons/" + Flags.DEFAULT_HEALTH_ICON);
|
||||
charIcon.loadGraphic(image, true, 150, 150);
|
||||
charIcon.setIcon(char);
|
||||
charIcon.setUnstretchedGraphicSize(size, size, true);
|
||||
charIcon.updateHitbox();
|
||||
charIcon.setPosition(x + 10, bHeight/2 - charIcon.height / 2);
|
||||
}
|
||||
|
||||
deleteButton = new UIButton(textBox.x + 115 + 16, bHeight/2 - (32/2), null, function () {
|
||||
|
||||
@@ -3,17 +3,26 @@ package funkin.editors.charter;
|
||||
import flixel.group.FlxGroup;
|
||||
import flixel.text.FlxText.FlxTextFormat;
|
||||
import flixel.text.FlxText.FlxTextFormatMarkerPair;
|
||||
import funkin.backend.chart.ChartData.ChartMetaData;
|
||||
import funkin.backend.chart.ChartData;
|
||||
import funkin.backend.chart.FNFLegacyParser.SwagSong;
|
||||
import funkin.backend.chart.PsychParser;
|
||||
import funkin.backend.chart.VSliceParser;
|
||||
import funkin.backend.utils.ZipUtil.ZipReader;
|
||||
import funkin.game.HealthIcon;
|
||||
import haxe.Json;
|
||||
import haxe.io.Bytes;
|
||||
import haxe.io.BytesInput;
|
||||
|
||||
typedef SongCreationData = {
|
||||
var meta:ChartMetaData;
|
||||
var instBytes:Bytes;
|
||||
var voicesBytes:Bytes;
|
||||
@:optional var playerVocals:Bytes;
|
||||
@:optional var oppVocals:Bytes;
|
||||
}
|
||||
|
||||
class SongCreationScreen extends UISubstateWindow {
|
||||
private var onSave:Null<SongCreationData> -> Void = null;
|
||||
private var onSave:Null<SongCreationData> -> Null<String -> SongCreationData -> Void> -> Void = null;
|
||||
|
||||
public var songNameTextBox:UITextBox;
|
||||
public var bpmStepper:UINumericStepper;
|
||||
@@ -21,15 +30,26 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
public var stepsPerBeatStepper :UINumericStepper;
|
||||
public var instExplorer:UIFileExplorer;
|
||||
public var voicesExplorer:UIFileExplorer;
|
||||
public var importFrom:UIButton;
|
||||
|
||||
public var displayNameTextBox:UITextBox;
|
||||
public var iconTextBox:UITextBox;
|
||||
public var iconSprite:FlxSprite;
|
||||
public var iconSprite:HealthIcon;
|
||||
public var opponentModeCheckbox:UICheckbox;
|
||||
public var coopAllowedCheckbox:UICheckbox;
|
||||
public var colorWheel:UIColorwheel;
|
||||
public var difficultiesTextBox:UITextBox;
|
||||
|
||||
public var engineDropdown:UIDropDown;
|
||||
public var createSong:UIButton;
|
||||
|
||||
public var importInstExplorer:UIFileExplorer;
|
||||
public var importVoicesExplorer:UIFileExplorer;
|
||||
|
||||
public var importIdTextBox:UITextBox;
|
||||
public var importChartFile:UIFileExplorer;
|
||||
public var importMetaFile:UIFileExplorer;
|
||||
|
||||
public var backButton:UIButton;
|
||||
public var saveButton:UIButton;
|
||||
public var closeButton:UIButton;
|
||||
@@ -37,11 +57,21 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
public var songDataGroup:FlxGroup = new FlxGroup();
|
||||
public var menuDataGroup:FlxGroup = new FlxGroup();
|
||||
|
||||
public var selectFormatGroup:FlxGroup = new FlxGroup();
|
||||
public var importAudioGroup:FlxGroup = new FlxGroup();
|
||||
public var importDataGroup:FlxGroup = new FlxGroup();
|
||||
|
||||
public var pages:Array<FlxGroup> = [];
|
||||
public var pageSizes:Array<FlxPoint> = [];
|
||||
|
||||
public var importPages:Array<FlxGroup> = [];
|
||||
public var importPageSizes:Array<FlxPoint> = [];
|
||||
|
||||
public var isImporting = false;
|
||||
|
||||
public var curPage:Int = 0;
|
||||
|
||||
public function new(?onSave:SongCreationData->Void) {
|
||||
public function new(?onSave:SongCreationData -> Null<String -> SongCreationData -> Void> -> Void) {
|
||||
super();
|
||||
if (onSave != null) this.onSave = onSave;
|
||||
}
|
||||
@@ -80,10 +110,7 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, 4, 1, 0, 1, null, 54);
|
||||
songDataGroup.add(stepsPerBeatStepper);
|
||||
|
||||
var voicesUIText:UIText = null;
|
||||
|
||||
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Flags.SOUND_EXT, function (path, res) {
|
||||
if (path == null || res == null) return;
|
||||
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Flags.SOUND_EXT, function (res) {
|
||||
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(instExplorer.x + 8, instExplorer.y + 8, res);
|
||||
instExplorer.members.push(audioPlayer);
|
||||
instExplorer.uiElement = audioPlayer;
|
||||
@@ -102,6 +129,14 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
songDataGroup.add(voicesExplorer);
|
||||
addLabelOn(voicesExplorer, "Vocal Audio File");
|
||||
|
||||
importFrom = new UIButton(windowSpr.x + 20, windowSpr.y + windowSpr.bHeight - 16 - 32, "Import From...", function() {
|
||||
winTitle = "Importing Song";
|
||||
isImporting = true;
|
||||
updatePagesTexts();
|
||||
refreshPages();
|
||||
}, 150);
|
||||
songDataGroup.add(importFrom);
|
||||
|
||||
var menuTitle:UIText;
|
||||
menuDataGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Menus Data (Freeplay/Story)", 28));
|
||||
|
||||
@@ -134,7 +169,64 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
for (checkbox in [opponentModeCheckbox, coopAllowedCheckbox])
|
||||
{checkbox.y += 6; checkbox.x += 4;}
|
||||
|
||||
var menuTitle:UIText;
|
||||
selectFormatGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Import From:", 28));
|
||||
|
||||
selectFormatGroup.add(engineDropdown);
|
||||
addLabelOn(engineDropdown, "Chart Format");
|
||||
|
||||
createSong = new UIButton(windowSpr.x + 20, windowSpr.y + windowSpr.bHeight - 16 - 32, "< Back", function() {
|
||||
winTitle = "Creating New Song";
|
||||
isImporting = false;
|
||||
updatePagesTexts();
|
||||
refreshPages();
|
||||
}, 120);
|
||||
selectFormatGroup.add(createSong);
|
||||
|
||||
var menuTitle:UIText;
|
||||
importAudioGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Add Audios", 28));
|
||||
|
||||
importInstExplorer = new UIFileExplorer(menuTitle.x, menuTitle.y + menuTitle.height + 36, null, null, Flags.SOUND_EXT, function (res) {
|
||||
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(importInstExplorer.x + 8, importInstExplorer.y + 8, res);
|
||||
importInstExplorer.members.push(audioPlayer);
|
||||
importInstExplorer.uiElement = audioPlayer;
|
||||
});
|
||||
importAudioGroup.add(importInstExplorer);
|
||||
addLabelOn(importInstExplorer, "Inst Audio File").applyMarkup(
|
||||
"Inst Audio File $* Required$",
|
||||
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
|
||||
|
||||
importVoicesExplorer = new UIFileExplorer(importInstExplorer.x + 320 + 26, importInstExplorer.y, null, null, Flags.SOUND_EXT, function (res) {
|
||||
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(importVoicesExplorer.x + 8, importVoicesExplorer.y + 8, res);
|
||||
importVoicesExplorer.members.push(audioPlayer);
|
||||
importVoicesExplorer.uiElement = audioPlayer;
|
||||
});
|
||||
importAudioGroup.add(importVoicesExplorer);
|
||||
addLabelOn(importVoicesExplorer, "Vocal Audio File");
|
||||
|
||||
var menuTitle:UIText;
|
||||
importDataGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Add Data", 28));
|
||||
|
||||
importDataGroup.add(importIdTextBox = new UITextBox(menuTitle.x, menuTitle.y + menuTitle.height + 36));
|
||||
addLabelOn(importIdTextBox, "Song file name").applyMarkup(
|
||||
"Song file name $* Required$",
|
||||
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
|
||||
|
||||
importChartFile = new UIFileExplorer(importIdTextBox.x, importIdTextBox.y + importIdTextBox.height + 56, null, null, "fnfc", function (_) importIdTextBox.label.text = new haxe.io.Path(importChartFile.filePath).file);
|
||||
importDataGroup.add(importChartFile);
|
||||
addLabelOn(importChartFile, "Data/Chart File").applyMarkup(
|
||||
"Data/Chart File $* Required$",
|
||||
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
|
||||
|
||||
importMetaFile = new UIFileExplorer(importChartFile.x + 320 + 26, importChartFile.y, null, null, "json");
|
||||
importDataGroup.add(importMetaFile);
|
||||
addLabelOn(importMetaFile, "Meta File").applyMarkup(
|
||||
"Meta File $* Required$",
|
||||
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
|
||||
|
||||
engineDropdown = new UIDropDown(menuTitle.x, menuTitle.y + menuTitle.height + 36, 480, 32, ["Psych/Legacy FNF", "V-Slice", "V-Slice Project (.fnfc)"]);
|
||||
saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20 - 125, windowSpr.y + windowSpr.bHeight - 16 - 32, "Save & Close", function() {
|
||||
var pages = isImporting ? importPages : pages;
|
||||
if (curPage == pages.length-1) {
|
||||
saveSongInfo();
|
||||
close();
|
||||
@@ -167,17 +259,41 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
pages.push(cast add(menuDataGroup));
|
||||
pageSizes.push(FlxPoint.get(748 - 32 + 40, 400));
|
||||
|
||||
importPages.push(cast add(selectFormatGroup));
|
||||
importPageSizes.push(FlxPoint.get(500, 250));
|
||||
|
||||
importPages.push(cast add(importAudioGroup));
|
||||
importPageSizes.push(FlxPoint.get(705, 250));
|
||||
|
||||
importPages.push(cast add(importDataGroup));
|
||||
importPageSizes.push(FlxPoint.get(705, 300));
|
||||
|
||||
refreshPages();
|
||||
updatePagesTexts();
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float) {
|
||||
if (curPage == 0) {
|
||||
if (instExplorer.file != null)
|
||||
if (isImporting)
|
||||
{
|
||||
var name = engineDropdown.options[engineDropdown.index];
|
||||
var project = name == "V-Slice Project (.fnfc)";
|
||||
|
||||
if (curPage == 1) {
|
||||
importInstExplorer.selectable = importVoicesExplorer.selectable = !project;
|
||||
saveButton.selectable = project ? true : (importInstExplorer.file != null);
|
||||
} else if (curPage == 2) {
|
||||
importIdTextBox.selectable = !project;
|
||||
importChartFile.fileType = project ? "fnfc" : "json";
|
||||
importMetaFile.selectable = name == "V-Slice";
|
||||
saveButton.selectable = importChartFile.file != null && (!importMetaFile.selectable || importMetaFile.file != null) && (!importIdTextBox.selectable || importIdTextBox.label.text.trim().length > 0);
|
||||
} else
|
||||
saveButton.selectable = true;
|
||||
else saveButton.selectable = false;
|
||||
} else
|
||||
saveButton.selectable = true;
|
||||
} else {
|
||||
if (curPage == 0)
|
||||
saveButton.selectable = (instExplorer.file != null);
|
||||
else
|
||||
saveButton.selectable = true;
|
||||
}
|
||||
|
||||
saveButton.alpha = saveButton.field.alpha = saveButton.selectable ? 1 : 0.4;
|
||||
super.update(elapsed);
|
||||
@@ -185,10 +301,15 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
|
||||
function refreshPages() {
|
||||
for (i=>page in pages)
|
||||
page.visible = page.exists = i == curPage;
|
||||
page.visible = page.exists = i == curPage && !isImporting;
|
||||
|
||||
for (i=>page in importPages)
|
||||
page.visible = page.exists = i == curPage && isImporting;
|
||||
}
|
||||
|
||||
function updatePagesTexts() {
|
||||
var pageSizes = isImporting ? importPageSizes : pageSizes;
|
||||
var pages = isImporting ? importPages : pages;
|
||||
windowSpr.bWidth = Std.int(pageSizes[curPage].x);
|
||||
windowSpr.bHeight = Std.int(pageSizes[curPage].y);
|
||||
|
||||
@@ -196,7 +317,7 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
titleSpr.y = windowSpr.y + ((30 - titleSpr.height) / 2);
|
||||
|
||||
saveButton.field.text = curPage == pages.length-1 ? "Save & Close" : 'Next >';
|
||||
titleSpr.text = 'Creating New Song (${curPage+1}/${pages.length})';
|
||||
titleSpr.text = '$winTitle (${curPage+1}/${pages.length})';
|
||||
|
||||
backButton.field.text = '< Back';
|
||||
backButton.visible = backButton.exists = curPage > 0;
|
||||
@@ -204,51 +325,121 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
backButton.x = (saveButton.x = windowSpr.x + windowSpr.bWidth - 20 - 125) - 20 - saveButton.bWidth;
|
||||
closeButton.x = (curPage > 0 ? backButton : saveButton).x - 20 - saveButton.bWidth;
|
||||
|
||||
for (button in [saveButton, backButton, closeButton])
|
||||
for (button in [saveButton, backButton, closeButton, importFrom, createSong])
|
||||
button.y = windowSpr.y + windowSpr.bHeight - 16 - 32;
|
||||
}
|
||||
|
||||
function updateIcon(icon:String) {
|
||||
if (iconSprite == null) menuDataGroup.add(iconSprite = new FlxSprite());
|
||||
if (iconSprite == null) menuDataGroup.add(iconSprite = new HealthIcon());
|
||||
|
||||
if (iconSprite.animation.exists(icon)) return;
|
||||
@:privateAccess iconSprite.animation.clearAnimations();
|
||||
|
||||
var path:String = Paths.image('icons/$icon');
|
||||
if (!Assets.exists(path)) path = Paths.image('icons/' + Flags.DEFAULT_HEALTH_ICON);
|
||||
|
||||
iconSprite.loadGraphic(path, true, 150, 150);
|
||||
iconSprite.animation.add(icon, [0], 0, false);
|
||||
iconSprite.antialiasing = true;
|
||||
iconSprite.animation.play(icon);
|
||||
|
||||
iconSprite.scale.set(0.5, 0.5);
|
||||
iconSprite.setIcon(icon);
|
||||
var size = Std.int(150 * 0.5);
|
||||
iconSprite.setUnstretchedGraphicSize(size, size, true);
|
||||
iconSprite.updateHitbox();
|
||||
iconSprite.setPosition(iconTextBox.x + 150 + 8, (iconTextBox.y + 16) - (iconSprite.height/2));
|
||||
iconSprite.setPosition(iconTextBox.x + iconTextBox.bWidth + 8, iconTextBox.y + (iconTextBox.bHeight / 2) - (iconSprite.height / 2));
|
||||
iconSprite.scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
function saveSongInfo() {
|
||||
UIUtil.confirmUISelections(this);
|
||||
if (isImporting)
|
||||
{
|
||||
try switch(engineDropdown.options[engineDropdown.index])
|
||||
{
|
||||
case "V-Slice Project (.fnfc)":
|
||||
var files:Map<String, Any> = [];
|
||||
for (field in new ZipReader(new BytesInput(importChartFile.file)).read()) {
|
||||
var fileName = field.fileName;
|
||||
var fileContent = field.data;
|
||||
files.set(fileName, fileContent);
|
||||
}
|
||||
saveFromVSlice(files);
|
||||
case "V-Slice":
|
||||
var songId = importIdTextBox.label.text;
|
||||
var files:Map<String, Any> = [];
|
||||
files.set('${songId}-metadata.json', importMetaFile.file);
|
||||
files.set('${songId}-chart.json', importChartFile.file);
|
||||
files.set('Inst.${Flags.SOUND_EXT}', importInstExplorer.file);
|
||||
files.set('Voices.${Flags.SOUND_EXT}', importVoicesExplorer.file);
|
||||
saveFromVSlice(files, songId);
|
||||
default /*"Psych/Legacy FNF"*/:
|
||||
var songId = importIdTextBox.label.text;
|
||||
var oldChart:SwagSong = Json.parse(cast importChartFile.file);
|
||||
var base:ChartData = {
|
||||
strumLines: [],
|
||||
noteTypes: [],
|
||||
events: [],
|
||||
meta: {name: null},
|
||||
scrollSpeed: Flags.DEFAULT_SCROLL_SPEED,
|
||||
stage: Flags.DEFAULT_STAGE,
|
||||
codenameChart: true
|
||||
};
|
||||
PsychParser.parse(oldChart, base);
|
||||
if (onSave != null) onSave({
|
||||
meta: {
|
||||
name: songId,
|
||||
difficulties: [songId],
|
||||
bpm: oldChart.bpm,
|
||||
beatsPerMeasure: oldChart.beatsPerMeasure,
|
||||
stepsPerBeat: oldChart.stepsPerBeat,
|
||||
displayName: oldChart.song
|
||||
},
|
||||
instBytes: importInstExplorer.file,
|
||||
voicesBytes: importVoicesExplorer.file,
|
||||
}, (songFolder:String, creation:SongCreationData) -> {
|
||||
#if sys
|
||||
CoolUtil.safeSaveFile('$songFolder/charts/${songId}.json', Json.stringify(base, Flags.JSON_PRETTY_PRINT));
|
||||
#end
|
||||
});
|
||||
} catch (e) {
|
||||
openSubState(new UIWarningSubstate("Importing Song/Charts: Error!", Std.string(e), [
|
||||
{label: "Ok", color: 0xFFFF0000, onClick: function(t) {}}
|
||||
]));
|
||||
}
|
||||
} else {
|
||||
for (stepper in [bpmStepper, beatsPerMeasureStepper, stepsPerBeatStepper])
|
||||
@:privateAccess stepper.__onChange(stepper.label.text);
|
||||
|
||||
var meta:ChartMetaData = {
|
||||
name: songNameTextBox.label.text,
|
||||
bpm: bpmStepper.value,
|
||||
beatsPerMeasure: Std.int(beatsPerMeasureStepper.value),
|
||||
stepsPerBeat: Std.int(stepsPerBeatStepper.value),
|
||||
displayName: displayNameTextBox.label.text,
|
||||
icon: iconTextBox.label.text,
|
||||
color: colorWheel.curColorString,
|
||||
parsedColor: colorWheel.curColor,
|
||||
opponentModeAllowed: opponentModeCheckbox.checked,
|
||||
coopAllowed: coopAllowedCheckbox.checked,
|
||||
difficulties: [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()],
|
||||
};
|
||||
var meta:ChartMetaData = {
|
||||
name: songNameTextBox.label.text,
|
||||
bpm: bpmStepper.value,
|
||||
beatsPerMeasure: Std.int(beatsPerMeasureStepper.value),
|
||||
stepsPerBeat: Std.int(stepsPerBeatStepper.value),
|
||||
displayName: displayNameTextBox.label.text,
|
||||
icon: iconTextBox.label.text,
|
||||
color: colorWheel.curColor,
|
||||
opponentModeAllowed: opponentModeCheckbox.checked,
|
||||
coopAllowed: coopAllowedCheckbox.checked,
|
||||
difficulties: [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()],
|
||||
};
|
||||
|
||||
if (onSave != null) onSave({
|
||||
meta: meta,
|
||||
instBytes: instExplorer.file,
|
||||
voicesBytes: voicesExplorer.file
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
function saveFromVSlice(files:Map<String, Any>, ?name:String) {
|
||||
var songId = name == null && files.exists("manifest.json") ? Json.parse(files.get("manifest.json")).songId : name;
|
||||
var vslicemeta:SwagMetadata = Json.parse(files.get('${songId}-metadata.json'));
|
||||
var vslicechart:NewSwagSong = Json.parse(files.get('${songId}-chart.json'));
|
||||
var playData = vslicemeta.playData;
|
||||
|
||||
var meta:ChartMetaData = {name: songId};
|
||||
var diffCharts:Array<ChartDataWithInfo> = [];
|
||||
VSliceParser.parse(vslicemeta, vslicechart, meta, diffCharts, songId);
|
||||
|
||||
if (onSave != null) onSave({
|
||||
meta: meta,
|
||||
instBytes: instExplorer.file,
|
||||
voicesBytes: voicesExplorer.file
|
||||
instBytes: files.get('Inst.${Flags.SOUND_EXT}'),
|
||||
voicesBytes: files.get('Voices.${Flags.SOUND_EXT}'), //it may exist
|
||||
playerVocals: files.get('Voices-${playData.characters.playerVocals != null ? playData.characters.playerVocals[0] : playData.characters.player}.${Flags.SOUND_EXT}'),
|
||||
oppVocals: files.get('Voices-${playData.characters.opponentVocals != null ? playData.characters.opponentVocals[0] : playData.characters.opponent}.${Flags.SOUND_EXT}'),
|
||||
}, (songFolder:String, creation:SongCreationData) -> {
|
||||
#if sys
|
||||
for (diff in diffCharts) CoolUtil.safeSaveFile('$songFolder/charts/${diff.diffName}.json', Json.stringify(diff.chart, Flags.JSON_PRETTY_PRINT));
|
||||
#end
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,6 +54,7 @@ class UIAudioPlayer extends UIButton {
|
||||
timeBarPlayer = new FlxSprite(timeBar.x, timeBar.y).loadGraphic(Paths.image('editors/ui/audio-time-empty'));
|
||||
timeBarPlayer.colorTransform.color = 0x440364;
|
||||
timeBarPlayer.scale.y = (timeBarPlayer.frameHeight + 2) / timeBarPlayer.frameHeight;
|
||||
timeBarPlayer.pixelPerfectRender = true;
|
||||
members.push(timeBarPlayer);
|
||||
|
||||
timeBarSpr = cast new UISprite(timeBar.x, timeBar.y).makeSolid(timeBar.barWidth, timeBar.barHeight, 0x00FFFFFF);
|
||||
@@ -87,13 +88,13 @@ class UIAudioPlayer extends UIButton {
|
||||
playingSprite.animation.play(sound.playing ? "playing" : "paused");
|
||||
timeText.text = '${FlxStringUtil.formatTime(sound.time/1000, true)} / ${FlxStringUtil.formatTime(sound.length/1000)}';
|
||||
|
||||
if(timeBarPlayer.clipRect == null)
|
||||
timeBarPlayer.clipRect = new FlxRect(0, 0, timeBarPlayer.frameWidth, timeBarPlayer.frameHeight);
|
||||
if(timeBarPlayer.rawClipRect == null)
|
||||
timeBarPlayer.rawClipRect = new FlxRect(0, 0, timeBarPlayer.frameWidth, timeBarPlayer.frameHeight);
|
||||
|
||||
timeBarPlayer.clipRect.x = timeBarPlayer.frameWidth * (sound.time/sound.length);
|
||||
timeBarPlayer.clipRect.width = 2;
|
||||
timeBarPlayer.rawClipRect.x = timeBarPlayer.frameWidth * (sound.time/sound.length);
|
||||
timeBarPlayer.rawClipRect.width = 2;
|
||||
|
||||
timeBarPlayer.clipRect = timeBarPlayer.clipRect;
|
||||
timeBarPlayer.rawClipRect = timeBarPlayer.rawClipRect;
|
||||
|
||||
nextPlayerColor = sound.playing ? 0x732D95 : 0x440364;
|
||||
timeBarPlayer.colorTransform.color = FlxColor.interpolate(timeBarPlayer.colorTransform.color, nextPlayerColor, 1/14);
|
||||
|
||||
@@ -15,16 +15,19 @@ class UIFileExplorer extends UISliceSprite {
|
||||
public var onFile:(String, Bytes)->Void;
|
||||
|
||||
public var uiElement:FlxSprite;
|
||||
|
||||
public var fileType:String = "txt";
|
||||
|
||||
public function new(x:Float, y:Float, ?w:Int, ?h:Int, fileType:String = "txt", ?onFile:(String, Bytes)->Void) {
|
||||
super(x, y, (w != null ? w : 320), (h != null ? h : 58), 'editors/ui/inputbox');
|
||||
this.fileType = fileType;
|
||||
|
||||
if (onFile != null) this.onFile = onFile;
|
||||
|
||||
uploadButton = new UIButton(x + 8, y+ 8, null, function () {
|
||||
var fileDialog = new FileDialog();
|
||||
fileDialog.onSelect.add(loadFile);
|
||||
fileDialog.browse(OPEN, fileType);
|
||||
fileDialog.browse(OPEN, this.fileType);
|
||||
}, bWidth - 16, bHeight - 16);
|
||||
members.push(uploadButton);
|
||||
|
||||
@@ -66,6 +69,7 @@ class UIFileExplorer extends UISliceSprite {
|
||||
}
|
||||
|
||||
public function removeFile() {
|
||||
if (!selectable) return;
|
||||
if (uiElement != null) {
|
||||
members.remove(uiElement);
|
||||
uiElement.destroy();
|
||||
|
||||
Reference in New Issue
Block a user