mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2025-03-21 20:39:52 -04:00
Implement "Open Recent" menu
This commit is contained in:
parent
ffd0a98393
commit
8664aed4cc
6 changed files with 527 additions and 62 deletions
2
assets
2
assets
|
@ -1 +1 @@
|
|||
Subproject commit 118b622953171aaf127cb160538e21bc468620e2
|
||||
Subproject commit c1cea20513dfa93e3e74a0db98498b2fd8da50fc
|
|
@ -1,16 +1,19 @@
|
|||
package funkin.save;
|
||||
|
||||
import flixel.util.FlxSave;
|
||||
import funkin.save.migrator.SaveDataMigrator;
|
||||
import thx.semver.Version;
|
||||
import funkin.Controls.Device;
|
||||
import funkin.save.migrator.RawSaveData_v1_0_0;
|
||||
import funkin.save.migrator.SaveDataMigrator;
|
||||
import funkin.ui.debug.charting.ChartEditorState.LiveInputStyle;
|
||||
import funkin.ui.debug.charting.ChartEditorThemeHandler.ChartEditorTheme;
|
||||
import thx.semver.Version;
|
||||
|
||||
@:nullSafety
|
||||
@:forward(volume, mute)
|
||||
abstract Save(RawSaveData)
|
||||
{
|
||||
public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.0";
|
||||
// Version 2.0.1 adds attributes to `optionsChartEditor`, that should return default values if they are null.
|
||||
public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.1";
|
||||
public static final SAVE_DATA_VERSION_RULE:thx.semver.VersionRule = "2.0.x";
|
||||
|
||||
// We load this version's saves from a new save path, to maintain SOME level of backwards compatibility.
|
||||
|
@ -94,6 +97,18 @@ abstract Save(RawSaveData)
|
|||
optionsChartEditor:
|
||||
{
|
||||
// Reasonable defaults.
|
||||
previousFiles: [],
|
||||
noteQuant: 3,
|
||||
liveInputStyle: LiveInputStyle.None,
|
||||
theme: ChartEditorTheme.Light,
|
||||
playtestStartTime: false,
|
||||
downscroll: false,
|
||||
metronomeEnabled: true,
|
||||
hitsoundsEnabledPlayer: true,
|
||||
hitsoundsEnabledOpponent: true,
|
||||
instVolume: 1.0,
|
||||
voicesVolume: 1.0,
|
||||
playbackSpeed: 1.0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -124,7 +139,9 @@ abstract Save(RawSaveData)
|
|||
|
||||
function set_ngSessionId(value:Null<String>):Null<String>
|
||||
{
|
||||
return this.api.newgrounds.sessionId = value;
|
||||
this.api.newgrounds.sessionId = value;
|
||||
flush();
|
||||
return this.api.newgrounds.sessionId;
|
||||
}
|
||||
|
||||
public var enabledModIds(get, set):Array<String>;
|
||||
|
@ -136,7 +153,213 @@ abstract Save(RawSaveData)
|
|||
|
||||
function set_enabledModIds(value:Array<String>):Array<String>
|
||||
{
|
||||
return this.mods.enabledMods = value;
|
||||
this.mods.enabledMods = value;
|
||||
flush();
|
||||
return this.mods.enabledMods;
|
||||
}
|
||||
|
||||
public var chartEditorPreviousFiles(get, set):Array<String>;
|
||||
|
||||
function get_chartEditorPreviousFiles():Array<String>
|
||||
{
|
||||
if (this.optionsChartEditor.previousFiles == null) this.optionsChartEditor.previousFiles = [];
|
||||
|
||||
return this.optionsChartEditor.previousFiles;
|
||||
}
|
||||
|
||||
function set_chartEditorPreviousFiles(value:Array<String>):Array<String>
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.previousFiles = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.previousFiles;
|
||||
}
|
||||
|
||||
public var chartEditorNoteQuant(get, set):Int;
|
||||
|
||||
function get_chartEditorNoteQuant():Int
|
||||
{
|
||||
if (this.optionsChartEditor.noteQuant == null) this.optionsChartEditor.noteQuant = 3;
|
||||
|
||||
return this.optionsChartEditor.noteQuant;
|
||||
}
|
||||
|
||||
function set_chartEditorNoteQuant(value:Int):Int
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.noteQuant = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.noteQuant;
|
||||
}
|
||||
|
||||
public var chartEditorLiveInputStyle(get, set):LiveInputStyle;
|
||||
|
||||
function get_chartEditorLiveInputStyle():LiveInputStyle
|
||||
{
|
||||
if (this.optionsChartEditor.liveInputStyle == null) this.optionsChartEditor.liveInputStyle = LiveInputStyle.None;
|
||||
|
||||
return this.optionsChartEditor.liveInputStyle;
|
||||
}
|
||||
|
||||
function set_chartEditorLiveInputStyle(value:LiveInputStyle):LiveInputStyle
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.liveInputStyle = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.liveInputStyle;
|
||||
}
|
||||
|
||||
public var chartEditorDownscroll(get, set):Bool;
|
||||
|
||||
function get_chartEditorDownscroll():Bool
|
||||
{
|
||||
if (this.optionsChartEditor.downscroll == null) this.optionsChartEditor.downscroll = false;
|
||||
|
||||
return this.optionsChartEditor.downscroll;
|
||||
}
|
||||
|
||||
function set_chartEditorDownscroll(value:Bool):Bool
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.downscroll = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.downscroll;
|
||||
}
|
||||
|
||||
public var chartEditorPlaytestStartTime(get, set):Bool;
|
||||
|
||||
function get_chartEditorPlaytestStartTime():Bool
|
||||
{
|
||||
if (this.optionsChartEditor.playtestStartTime == null) this.optionsChartEditor.playtestStartTime = false;
|
||||
|
||||
return this.optionsChartEditor.playtestStartTime;
|
||||
}
|
||||
|
||||
function set_chartEditorPlaytestStartTime(value:Bool):Bool
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.playtestStartTime = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.playtestStartTime;
|
||||
}
|
||||
|
||||
public var chartEditorTheme(get, set):ChartEditorTheme;
|
||||
|
||||
function get_chartEditorTheme():ChartEditorTheme
|
||||
{
|
||||
if (this.optionsChartEditor.theme == null) this.optionsChartEditor.theme = ChartEditorTheme.Light;
|
||||
|
||||
return this.optionsChartEditor.theme;
|
||||
}
|
||||
|
||||
function set_chartEditorTheme(value:ChartEditorTheme):ChartEditorTheme
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.theme = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.theme;
|
||||
}
|
||||
|
||||
public var chartEditorMetronomeEnabled(get, set):Bool;
|
||||
|
||||
function get_chartEditorMetronomeEnabled():Bool
|
||||
{
|
||||
if (this.optionsChartEditor.metronomeEnabled == null) this.optionsChartEditor.metronomeEnabled = true;
|
||||
|
||||
return this.optionsChartEditor.metronomeEnabled;
|
||||
}
|
||||
|
||||
function set_chartEditorMetronomeEnabled(value:Bool):Bool
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.metronomeEnabled = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.metronomeEnabled;
|
||||
}
|
||||
|
||||
public var chartEditorHitsoundsEnabledPlayer(get, set):Bool;
|
||||
|
||||
function get_chartEditorHitsoundsEnabledPlayer():Bool
|
||||
{
|
||||
if (this.optionsChartEditor.hitsoundsEnabledPlayer == null) this.optionsChartEditor.hitsoundsEnabledPlayer = true;
|
||||
|
||||
return this.optionsChartEditor.hitsoundsEnabledPlayer;
|
||||
}
|
||||
|
||||
function set_chartEditorHitsoundsEnabledPlayer(value:Bool):Bool
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.hitsoundsEnabledPlayer = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.hitsoundsEnabledPlayer;
|
||||
}
|
||||
|
||||
public var chartEditorHitsoundsEnabledOpponent(get, set):Bool;
|
||||
|
||||
function get_chartEditorHitsoundsEnabledOpponent():Bool
|
||||
{
|
||||
if (this.optionsChartEditor.hitsoundsEnabledOpponent == null) this.optionsChartEditor.hitsoundsEnabledOpponent = true;
|
||||
|
||||
return this.optionsChartEditor.hitsoundsEnabledOpponent;
|
||||
}
|
||||
|
||||
function set_chartEditorHitsoundsEnabledOpponent(value:Bool):Bool
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.hitsoundsEnabledOpponent = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.hitsoundsEnabledOpponent;
|
||||
}
|
||||
|
||||
public var chartEditorInstVolume(get, set):Float;
|
||||
|
||||
function get_chartEditorInstVolume():Float
|
||||
{
|
||||
if (this.optionsChartEditor.instVolume == null) this.optionsChartEditor.instVolume = 1.0;
|
||||
|
||||
return this.optionsChartEditor.instVolume;
|
||||
}
|
||||
|
||||
function set_chartEditorInstVolume(value:Float):Float
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.instVolume = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.instVolume;
|
||||
}
|
||||
|
||||
public var chartEditorVoicesVolume(get, set):Float;
|
||||
|
||||
function get_chartEditorVoicesVolume():Float
|
||||
{
|
||||
if (this.optionsChartEditor.voicesVolume == null) this.optionsChartEditor.voicesVolume = 1.0;
|
||||
|
||||
return this.optionsChartEditor.voicesVolume;
|
||||
}
|
||||
|
||||
function set_chartEditorVoicesVolume(value:Float):Float
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.voicesVolume = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.voicesVolume;
|
||||
}
|
||||
|
||||
public var chartEditorPlaybackSpeed(get, set):Float;
|
||||
|
||||
function get_chartEditorPlaybackSpeed():Float
|
||||
{
|
||||
if (this.optionsChartEditor.playbackSpeed == null) this.optionsChartEditor.playbackSpeed = 1.0;
|
||||
|
||||
return this.optionsChartEditor.playbackSpeed;
|
||||
}
|
||||
|
||||
function set_chartEditorPlaybackSpeed(value:Float):Float
|
||||
{
|
||||
// Set and apply.
|
||||
this.optionsChartEditor.playbackSpeed = value;
|
||||
flush();
|
||||
return this.optionsChartEditor.playbackSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -699,4 +922,77 @@ typedef SaveControlsData =
|
|||
/**
|
||||
* An anonymous structure containing all the user's options and preferences, specific to the Chart Editor.
|
||||
*/
|
||||
typedef SaveDataChartEditorOptions = {};
|
||||
typedef SaveDataChartEditorOptions =
|
||||
{
|
||||
/**
|
||||
* Previous files opened in the Chart Editor.
|
||||
* @default `[]`
|
||||
*/
|
||||
var ?previousFiles:Array<String>;
|
||||
|
||||
/**
|
||||
* Note snapping level in the Chart Editor.
|
||||
* @default `3`
|
||||
*/
|
||||
var ?noteQuant:Int;
|
||||
|
||||
/**
|
||||
* Live input style in the Chart Editor.
|
||||
* @default `LiveInputStyle.None`
|
||||
*/
|
||||
var ?liveInputStyle:LiveInputStyle;
|
||||
|
||||
/**
|
||||
* Theme in the Chart Editor.
|
||||
* @default `ChartEditorTheme.Light`
|
||||
*/
|
||||
var ?theme:ChartEditorTheme;
|
||||
|
||||
/**
|
||||
* Downscroll in the Chart Editor.
|
||||
* @default `false`
|
||||
*/
|
||||
var ?downscroll:Bool;
|
||||
|
||||
/**
|
||||
* Metronome sounds in the Chart Editor.
|
||||
* @default `true`
|
||||
*/
|
||||
var ?metronomeEnabled:Bool;
|
||||
|
||||
/**
|
||||
* If true, playtest songs from the current position in the Chart Editor.
|
||||
* @default `false`
|
||||
*/
|
||||
var ?playtestStartTime:Bool;
|
||||
|
||||
/**
|
||||
* Player note hit sounds in the Chart Editor.
|
||||
* @default `true`
|
||||
*/
|
||||
var ?hitsoundsEnabledPlayer:Bool;
|
||||
|
||||
/**
|
||||
* Opponent note hit sounds in the Chart Editor.
|
||||
* @default `true`
|
||||
*/
|
||||
var ?hitsoundsEnabledOpponent:Bool;
|
||||
|
||||
/**
|
||||
* Instrumental volume in the Chart Editor.
|
||||
* @default `1.0`
|
||||
*/
|
||||
var ?instVolume:Float;
|
||||
|
||||
/**
|
||||
* Voices volume in the Chart Editor.
|
||||
* @default `1.0`
|
||||
*/
|
||||
var ?voicesVolume:Float;
|
||||
|
||||
/**
|
||||
* Playback speed in the Chart Editor.
|
||||
* @default `1.0`
|
||||
*/
|
||||
var ?playbackSpeed:Float;
|
||||
};
|
||||
|
|
|
@ -84,11 +84,47 @@ class ChartEditorDialogHandler
|
|||
var dialog:Null<Dialog> = openDialog(state, CHART_EDITOR_DIALOG_WELCOME_LAYOUT, true, closable);
|
||||
if (dialog == null) throw 'Could not locate Welcome dialog';
|
||||
|
||||
state.isHaxeUIDialogOpen = true;
|
||||
dialog.onDialogClosed = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
// Called when the Welcome dialog is closed while it is closable.
|
||||
state.stopWelcomeMusic();
|
||||
}
|
||||
|
||||
#if sys
|
||||
var splashRecentContainer:Null<VBox> = dialog.findComponent('splashRecentContainer', VBox);
|
||||
if (splashRecentContainer == null) throw 'Could not locate splashRecentContainer in Welcome dialog';
|
||||
|
||||
for (chartPath in state.previousWorkingFilePaths)
|
||||
{
|
||||
var linkRecentChart:Link = new FunkinLink();
|
||||
linkRecentChart.text = chartPath;
|
||||
linkRecentChart.onClick = function(_event) {
|
||||
dialog.hideDialog(DialogButton.CANCEL);
|
||||
state.stopWelcomeMusic();
|
||||
|
||||
// Load chart from file
|
||||
ChartEditorImportExportHandler.loadFromFNFCPath(state, chartPath);
|
||||
}
|
||||
|
||||
if (!FileUtil.doesFileExist(chartPath))
|
||||
{
|
||||
trace('Previously loaded chart file (${chartPath}) does not exist, disabling link...');
|
||||
linkRecentChart.disabled = true;
|
||||
}
|
||||
|
||||
splashRecentContainer.addComponent(linkRecentChart);
|
||||
}
|
||||
#else
|
||||
var splashRecentContainer:Null<VBox> = dialog.findComponent('splashRecentContainer', VBox);
|
||||
if (splashRecentContainer == null) throw 'Could not locate splashRecentContainer in Welcome dialog';
|
||||
|
||||
var webLoadLabel:Label = new Label();
|
||||
webLoadLabel.text = 'Click the button below to load a chart file (.fnfc) from your computer.';
|
||||
|
||||
splashRecentContainer.add(webLoadLabel);
|
||||
#end
|
||||
|
||||
// Create New Song "Easy/Normal/Hard"
|
||||
var linkCreateBasic:Null<Link> = dialog.findComponent('splashCreateFromSongBasic', Link);
|
||||
if (linkCreateBasic == null) throw 'Could not locate splashCreateFromSongBasic link in Welcome dialog';
|
||||
|
@ -180,6 +216,7 @@ class ChartEditorDialogHandler
|
|||
if (dialog == null) throw 'Could not locate Upload Chart dialog';
|
||||
|
||||
dialog.onDialogClosed = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
if (_event.button == DialogButton.APPLY)
|
||||
{
|
||||
// Simply let the dialog close.
|
||||
|
@ -194,6 +231,7 @@ class ChartEditorDialogHandler
|
|||
var buttonCancel:Null<Button> = dialog.findComponent('dialogCancel', Button);
|
||||
if (buttonCancel == null) throw 'Could not locate dialogCancel button in Upload Chart dialog';
|
||||
|
||||
state.isHaxeUIDialogOpen = true;
|
||||
buttonCancel.onClick = function(_event) {
|
||||
dialog.hideDialog(DialogButton.CANCEL);
|
||||
}
|
||||
|
@ -232,6 +270,10 @@ class ChartEditorDialogHandler
|
|||
});
|
||||
#end
|
||||
|
||||
trace(selectedFile.name);
|
||||
trace(selectedFile.text);
|
||||
trace(selectedFile.isBinary);
|
||||
trace(selectedFile.fullPath);
|
||||
if (selectedFile.fullPath != null) state.currentWorkingFilePath = selectedFile.fullPath;
|
||||
dialog.hideDialog(DialogButton.APPLY);
|
||||
removeDropHandler(onDropFile);
|
||||
|
@ -689,7 +731,9 @@ class ChartEditorDialogHandler
|
|||
|
||||
var buttonCancel:Null<Button> = dialog.findComponent('dialogCancel', Button);
|
||||
if (buttonCancel == null) throw 'Could not locate dialogCancel button in Song Metadata dialog';
|
||||
state.isHaxeUIDialogOpen = true;
|
||||
buttonCancel.onClick = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
dialog.hideDialog(DialogButton.CANCEL);
|
||||
}
|
||||
|
||||
|
@ -1411,7 +1455,9 @@ class ChartEditorDialogHandler
|
|||
var buttonCancel:Null<Button> = dialog.findComponent('dialogCancel', Button);
|
||||
if (buttonCancel == null) throw 'Could not locate dialogCancel button in Import Chart dialog';
|
||||
|
||||
state.isHaxeUIDialogOpen = true;
|
||||
buttonCancel.onClick = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
dialog.hideDialog(DialogButton.CANCEL);
|
||||
}
|
||||
|
||||
|
@ -1596,7 +1642,9 @@ class ChartEditorDialogHandler
|
|||
|
||||
// If all validators succeeded, this callback is called.
|
||||
|
||||
state.isHaxeUIDialogOpen = true;
|
||||
variationForm.onSubmit = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
trace('Add Variation dialog submitted, validation succeeded!');
|
||||
|
||||
var dialogVariationName:Null<TextField> = dialog.findComponent('dialogVariationName', TextField);
|
||||
|
|
|
@ -1,25 +1,18 @@
|
|||
package funkin.ui.debug.charting;
|
||||
|
||||
import funkin.play.stage.StageData;
|
||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
import funkin.play.character.CharacterData;
|
||||
import flixel.system.FlxAssets.FlxSoundAsset;
|
||||
import flixel.math.FlxMath;
|
||||
import haxe.ui.components.TextField;
|
||||
import haxe.ui.components.DropDown;
|
||||
import haxe.ui.components.NumberStepper;
|
||||
import haxe.ui.containers.Frame;
|
||||
import flixel.addons.display.FlxSliceSprite;
|
||||
import flixel.addons.display.FlxTiledSprite;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.FlxCamera;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.FlxSubState;
|
||||
import flixel.group.FlxSpriteGroup;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.input.keyboard.FlxKey;
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.math.FlxRect;
|
||||
import flixel.sound.FlxSound;
|
||||
import flixel.system.FlxAssets.FlxSoundAsset;
|
||||
import flixel.tweens.FlxEase;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.tweens.misc.VarTween;
|
||||
|
@ -29,28 +22,31 @@ import flixel.util.FlxTimer;
|
|||
import funkin.audio.visualize.PolygonSpectogram;
|
||||
import funkin.audio.VoicesGroup;
|
||||
import funkin.data.notestyle.NoteStyleRegistry;
|
||||
import funkin.data.notestyle.NoteStyleRegistry;
|
||||
import funkin.data.song.SongData.SongCharacterData;
|
||||
import funkin.data.song.SongData.SongChartData;
|
||||
import funkin.data.song.SongData.SongEventData;
|
||||
import funkin.data.song.SongData.SongMetadata;
|
||||
import funkin.data.song.SongData.SongNoteData;
|
||||
import funkin.data.song.SongDataUtils;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.input.Cursor;
|
||||
import funkin.input.TurboKeyHandler;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
import funkin.play.character.BaseCharacter.CharacterType;
|
||||
import funkin.play.character.CharacterData;
|
||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
import funkin.play.HealthIcon;
|
||||
import funkin.play.notes.NoteSprite;
|
||||
import funkin.play.notes.Strumline;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.play.song.Song;
|
||||
import funkin.data.song.SongData.SongChartData;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.data.song.SongData.SongEventData;
|
||||
import funkin.data.song.SongData.SongMetadata;
|
||||
import funkin.data.song.SongData.SongNoteData;
|
||||
import funkin.data.song.SongData.SongCharacterData;
|
||||
import funkin.data.song.SongDataUtils;
|
||||
import funkin.ui.debug.charting.ChartEditorCommand;
|
||||
import funkin.play.stage.StageData;
|
||||
import funkin.save.Save;
|
||||
import funkin.ui.debug.charting.ChartEditorCommand;
|
||||
import funkin.ui.debug.charting.ChartEditorThemeHandler.ChartEditorTheme;
|
||||
import funkin.ui.debug.charting.ChartEditorToolboxHandler.ChartEditorToolMode;
|
||||
import funkin.ui.haxeui.components.CharacterPlayer;
|
||||
import funkin.ui.haxeui.components.FunkinMenuItem;
|
||||
import funkin.ui.haxeui.HaxeUIState;
|
||||
import funkin.util.Constants;
|
||||
import funkin.util.DateUtil;
|
||||
|
@ -61,10 +57,14 @@ import funkin.util.WindowUtil;
|
|||
import haxe.DynamicAccess;
|
||||
import haxe.io.Bytes;
|
||||
import haxe.io.Path;
|
||||
import haxe.ui.components.DropDown;
|
||||
import haxe.ui.components.Label;
|
||||
import haxe.ui.components.NumberStepper;
|
||||
import haxe.ui.components.Slider;
|
||||
import haxe.ui.components.TextField;
|
||||
import haxe.ui.containers.dialogs.CollapsibleDialog;
|
||||
import haxe.ui.containers.menus.MenuItem;
|
||||
import haxe.ui.containers.Frame;
|
||||
import haxe.ui.containers.menus.Menu;
|
||||
import haxe.ui.containers.TreeView;
|
||||
import haxe.ui.containers.TreeViewNode;
|
||||
import haxe.ui.core.Component;
|
||||
|
@ -594,27 +594,6 @@ class ChartEditorState extends HaxeUIState
|
|||
return selectedCharacter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user is currently in Pattern Mode.
|
||||
* This overrides the chart editor's normal behavior.
|
||||
*/
|
||||
var isInPatternMode(default, set):Bool = false;
|
||||
|
||||
function set_isInPatternMode(value:Bool):Bool
|
||||
{
|
||||
isInPatternMode = value;
|
||||
|
||||
// Make sure view is updated when we change modes.
|
||||
noteDisplayDirty = true;
|
||||
notePreviewDirty = true;
|
||||
notePreviewViewportBoundsDirty = true;
|
||||
this.scrollPositionInPixels = 0;
|
||||
|
||||
return isInPatternMode;
|
||||
}
|
||||
|
||||
var currentPattern:String = '';
|
||||
|
||||
/**
|
||||
* Whether the note display render group has been modified and needs to be updated.
|
||||
* This happens when we scroll or add/remove notes, and need to update what notes are displayed and where.
|
||||
|
@ -1183,6 +1162,11 @@ class ChartEditorState extends HaxeUIState
|
|||
*/
|
||||
var playbarHeadLayout:Null<Component> = null;
|
||||
|
||||
/**
|
||||
* The submenu in the menubar containing recently opened files.
|
||||
*/
|
||||
var menubarOpenRecent:Null<Menu> = null;
|
||||
|
||||
/**
|
||||
* The playbar head slider.
|
||||
*/
|
||||
|
@ -1237,10 +1221,50 @@ class ChartEditorState extends HaxeUIState
|
|||
*/
|
||||
var params:Null<ChartEditorParams>;
|
||||
|
||||
/**
|
||||
* A list of previous working file paths.
|
||||
* Also known as the "recent files" list.
|
||||
*/
|
||||
public var previousWorkingFilePaths:Array<String> = [];
|
||||
|
||||
/**
|
||||
* The current file path which the chart editor is working with.
|
||||
*/
|
||||
public var currentWorkingFilePath:Null<String>;
|
||||
public var currentWorkingFilePath(get, set):Null<String>;
|
||||
|
||||
function get_currentWorkingFilePath():Null<String>
|
||||
{
|
||||
return previousWorkingFilePaths[0];
|
||||
}
|
||||
|
||||
function set_currentWorkingFilePath(value:Null<String>):Null<String>
|
||||
{
|
||||
if (value == null) return null;
|
||||
|
||||
if (value == previousWorkingFilePaths[0]) return value;
|
||||
|
||||
if (previousWorkingFilePaths.contains(value))
|
||||
{
|
||||
// Move the path to the front of the list.
|
||||
previousWorkingFilePaths.remove(value);
|
||||
previousWorkingFilePaths.unshift(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the path to the front of the list.
|
||||
previousWorkingFilePaths.unshift(value);
|
||||
}
|
||||
|
||||
while (previousWorkingFilePaths.length > Constants.MAX_PREVIOUS_WORKING_FILES)
|
||||
{
|
||||
// Remove the oldest path.
|
||||
previousWorkingFilePaths.pop();
|
||||
}
|
||||
|
||||
populateOpenRecentMenu();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public function new(?params:ChartEditorParams)
|
||||
{
|
||||
|
@ -1260,6 +1284,8 @@ class ChartEditorState extends HaxeUIState
|
|||
// Show the mouse cursor.
|
||||
Cursor.show();
|
||||
|
||||
loadPreferences();
|
||||
|
||||
fixCamera();
|
||||
|
||||
// Get rid of any music from the previous state.
|
||||
|
@ -1280,6 +1306,7 @@ class ChartEditorState extends HaxeUIState
|
|||
buildSelectionBox();
|
||||
|
||||
buildAdditionalUI();
|
||||
populateOpenRecentMenu();
|
||||
|
||||
// Setup the onClick listeners for the UI after it's been created.
|
||||
setupUIListeners();
|
||||
|
@ -1322,8 +1349,80 @@ class ChartEditorState extends HaxeUIState
|
|||
{
|
||||
this.welcomeMusic.loadEmbedded(Paths.music('chartEditorLoop/chartEditorLoop'));
|
||||
this.welcomeMusic.looped = true;
|
||||
// this.welcomeMusic.play();
|
||||
// fadeInWelcomeMusic();
|
||||
}
|
||||
|
||||
public function loadPreferences():Void
|
||||
{
|
||||
var save:Save = Save.get();
|
||||
|
||||
previousWorkingFilePaths = save.chartEditorPreviousFiles;
|
||||
noteSnapQuantIndex = save.chartEditorNoteQuant;
|
||||
currentLiveInputStyle = save.chartEditorLiveInputStyle;
|
||||
isViewDownscroll = save.chartEditorDownscroll;
|
||||
playtestStartTime = save.chartEditorPlaytestStartTime;
|
||||
currentTheme = save.chartEditorTheme;
|
||||
isMetronomeEnabled = save.chartEditorMetronomeEnabled;
|
||||
hitsoundsEnabledPlayer = save.chartEditorHitsoundsEnabledPlayer;
|
||||
hitsoundsEnabledOpponent = save.chartEditorHitsoundsEnabledOpponent;
|
||||
|
||||
// audioInstTrack.volume = save.chartEditorInstVolume;
|
||||
// audioInstTrack.pitch = save.chartEditorPlaybackSpeed;
|
||||
// audioVocalTrackGroup.volume = save.chartEditorVoicesVolume;
|
||||
// audioVocalTrackGroup.pitch = save.chartEditorPlaybackSpeed;
|
||||
}
|
||||
|
||||
public function writePreferences():Void
|
||||
{
|
||||
var save:Save = Save.get();
|
||||
|
||||
save.chartEditorPreviousFiles = previousWorkingFilePaths;
|
||||
save.chartEditorNoteQuant = noteSnapQuantIndex;
|
||||
save.chartEditorLiveInputStyle = currentLiveInputStyle;
|
||||
save.chartEditorDownscroll = isViewDownscroll;
|
||||
save.chartEditorPlaytestStartTime = playtestStartTime;
|
||||
save.chartEditorTheme = currentTheme;
|
||||
save.chartEditorMetronomeEnabled = isMetronomeEnabled;
|
||||
save.chartEditorHitsoundsEnabledPlayer = hitsoundsEnabledPlayer;
|
||||
save.chartEditorHitsoundsEnabledOpponent = hitsoundsEnabledOpponent;
|
||||
|
||||
// save.chartEditorInstVolume = audioInstTrack.volume;
|
||||
// save.chartEditorVoicesVolume = audioVocalTrackGroup.volume;
|
||||
// save.chartEditorPlaybackSpeed = audioInstTrack.pitch;
|
||||
}
|
||||
|
||||
public function populateOpenRecentMenu():Void
|
||||
{
|
||||
if (menubarOpenRecent == null) return;
|
||||
|
||||
#if sys
|
||||
menubarOpenRecent.clear();
|
||||
|
||||
for (chartPath in previousWorkingFilePaths)
|
||||
{
|
||||
var menuItemRecentChart:FunkinMenuItem = new FunkinMenuItem();
|
||||
menuItemRecentChart.text = chartPath;
|
||||
menuItemRecentChart.onClick = function(_event) {
|
||||
stopWelcomeMusic();
|
||||
|
||||
// Load chart from file
|
||||
ChartEditorImportExportHandler.loadFromFNFCPath(this, chartPath);
|
||||
}
|
||||
|
||||
if (!FileUtil.doesFileExist(chartPath))
|
||||
{
|
||||
trace('Previously loaded chart file (${chartPath}) does not exist, disabling link...');
|
||||
menuItemRecentChart.disabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
menuItemRecentChart.disabled = false;
|
||||
}
|
||||
|
||||
menubarOpenRecent.addComponent(menuItemRecentChart);
|
||||
}
|
||||
#else
|
||||
menubarOpenRecent.hide();
|
||||
#end
|
||||
}
|
||||
|
||||
public function fadeInWelcomeMusic():Void
|
||||
|
@ -1540,7 +1639,10 @@ class ChartEditorState extends HaxeUIState
|
|||
function setNotePreviewViewportBounds(bounds:FlxRect = null):Void
|
||||
{
|
||||
if (notePreviewViewport == null)
|
||||
throw 'ERROR: Tried to set note preview viewport bounds, but notePreviewViewport is null! Check ChartEditorThemeHandler.updateTheme().';
|
||||
{
|
||||
trace('[WARN] Tried to set note preview viewport bounds, but notePreviewViewport is null!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (bounds == null)
|
||||
{
|
||||
|
@ -1646,9 +1748,11 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
add(playbarHeadLayout);
|
||||
|
||||
menubarOpenRecent = findComponent('menubarOpenRecent', Menu);
|
||||
if (menubarOpenRecent == null) throw "Could not find menubarOpenRecent!";
|
||||
|
||||
// Setup notifications.
|
||||
@:privateAccess
|
||||
// NotificationManager.GUTTER_SIZE = 56;
|
||||
NotificationManager.GUTTER_SIZE = 20;
|
||||
}
|
||||
|
||||
|
@ -1886,10 +1990,13 @@ class ChartEditorState extends HaxeUIState
|
|||
{
|
||||
saveDataDirty = false;
|
||||
|
||||
// Auto-save the chart.
|
||||
// Auto-save preferences.
|
||||
writePreferences();
|
||||
|
||||
// Auto-save the chart.
|
||||
#if html5
|
||||
// Auto-save to local storage.
|
||||
// TODO: Implement this.
|
||||
#else
|
||||
// Auto-save to temp file.
|
||||
ChartEditorImportExportHandler.exportAllSongData(this, true);
|
||||
|
@ -3835,7 +3942,7 @@ class ChartEditorState extends HaxeUIState
|
|||
commandHistoryDirty = false;
|
||||
|
||||
// Update the Undo and Redo buttons.
|
||||
var undoButton:Null<MenuItem> = findComponent('menubarItemUndo', MenuItem);
|
||||
var undoButton:Null<FunkinMenuItem> = findComponent('menubarItemUndo', FunkinMenuItem);
|
||||
|
||||
if (undoButton != null)
|
||||
{
|
||||
|
@ -3857,7 +3964,7 @@ class ChartEditorState extends HaxeUIState
|
|||
trace('undoButton is null');
|
||||
}
|
||||
|
||||
var redoButton:Null<MenuItem> = findComponent('menubarItemRedo', MenuItem);
|
||||
var redoButton:Null<FunkinMenuItem> = findComponent('menubarItemRedo', FunkinMenuItem);
|
||||
|
||||
if (redoButton != null)
|
||||
{
|
||||
|
|
|
@ -391,6 +391,11 @@ class Constants
|
|||
*/
|
||||
public static final GHOST_TAPPING:Bool = false;
|
||||
|
||||
/**
|
||||
* The maximum number of previous file paths for the Chart Editor to remember.
|
||||
*/
|
||||
public static final MAX_PREVIOUS_WORKING_FILES:Int = 10;
|
||||
|
||||
/**
|
||||
* The separator between an asset library and the asset path.
|
||||
*/
|
||||
|
|
|
@ -344,13 +344,22 @@ class FileUtil
|
|||
public static function readBytesFromPath(path:String):Bytes
|
||||
{
|
||||
#if sys
|
||||
if (!sys.FileSystem.exists(path)) return null;
|
||||
if (!doesFileExist(path)) return null;
|
||||
return sys.io.File.getBytes(path);
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
}
|
||||
|
||||
public static function doesFileExist(path:String):Bool
|
||||
{
|
||||
#if sys
|
||||
return sys.FileSystem.exists(path);
|
||||
#else
|
||||
return false;
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse for a file to read and execute a callback once we have a file reference.
|
||||
* Works great on HTML5 or desktop.
|
||||
|
@ -434,7 +443,7 @@ class FileUtil
|
|||
case Force:
|
||||
sys.io.File.saveContent(path, data);
|
||||
case Skip:
|
||||
if (!sys.FileSystem.exists(path))
|
||||
if (!doesFileExist(path))
|
||||
{
|
||||
sys.io.File.saveContent(path, data);
|
||||
}
|
||||
|
@ -443,7 +452,7 @@ class FileUtil
|
|||
throw 'File already exists: $path';
|
||||
}
|
||||
case Ask:
|
||||
if (sys.FileSystem.exists(path))
|
||||
if (doesFileExist(path))
|
||||
{
|
||||
// TODO: We don't have the technology to use native popups yet.
|
||||
}
|
||||
|
@ -475,7 +484,7 @@ class FileUtil
|
|||
case Force:
|
||||
sys.io.File.saveBytes(path, data);
|
||||
case Skip:
|
||||
if (!sys.FileSystem.exists(path))
|
||||
if (!doesFileExist(path))
|
||||
{
|
||||
sys.io.File.saveBytes(path, data);
|
||||
}
|
||||
|
@ -484,7 +493,7 @@ class FileUtil
|
|||
throw 'File already exists: $path';
|
||||
}
|
||||
case Ask:
|
||||
if (sys.FileSystem.exists(path))
|
||||
if (doesFileExist(path))
|
||||
{
|
||||
// TODO: We don't have the technology to use native popups yet.
|
||||
}
|
||||
|
@ -523,7 +532,7 @@ class FileUtil
|
|||
public static function createDirIfNotExists(dir:String):Void
|
||||
{
|
||||
#if sys
|
||||
if (!sys.FileSystem.exists(dir))
|
||||
if (!doesFileExist(dir))
|
||||
{
|
||||
sys.FileSystem.createDirectory(dir);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue