From 1f1a430efc5f97b9e2750d3dde243c43dfbb0a71 Mon Sep 17 00:00:00 2001 From: Hazel Date: Tue, 21 Nov 2023 18:54:46 +0000 Subject: [PATCH 01/22] add check whether submodules exist --- .github/workflows/build-shit.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-shit.yml b/.github/workflows/build-shit.yml index 22fccbf09..0b3cac25e 100644 --- a/.github/workflows/build-shit.yml +++ b/.github/workflows/build-shit.yml @@ -14,8 +14,19 @@ jobs: - name: ensure git cli is installed run: apt update && apt install sudo git -y - uses: actions/checkout@v3 - - name: print latest_commit - run: echo ${{ github.sha }} + with: + submodules: 'recursive' + token: ${{ secrets.GH_RO_PAT }} + - name: check whether submodules exist + run: + # debug output + echo gh=${{ github.sha }} + echo head=$(git rev-parse HEAD) + echo art=$(git -C art rev-parse HEAD) + echo assets=$(git -C assets rev-parse HEAD) + # checks if HEAD commit hash in submodules is diff from current repo, and therefore exists + test $(git rev-parse HEAD) != $(git -C art rev-parse HEAD) + test $(git rev-parse HEAD) != $(git -C assets rev-parse HEAD) - id: should_run continue-on-error: true name: check latest commit is less than a day From b6d7fc95e77d28be4a7b16b16ace1cfc71810c90 Mon Sep 17 00:00:00 2001 From: Hazel Date: Tue, 21 Nov 2023 18:55:45 +0000 Subject: [PATCH 02/22] yaml --- .github/workflows/build-shit.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-shit.yml b/.github/workflows/build-shit.yml index 0b3cac25e..fb3cd16a7 100644 --- a/.github/workflows/build-shit.yml +++ b/.github/workflows/build-shit.yml @@ -18,12 +18,13 @@ jobs: submodules: 'recursive' token: ${{ secrets.GH_RO_PAT }} - name: check whether submodules exist - run: + run: | # debug output echo gh=${{ github.sha }} echo head=$(git rev-parse HEAD) echo art=$(git -C art rev-parse HEAD) echo assets=$(git -C assets rev-parse HEAD) + # checks if HEAD commit hash in submodules is diff from current repo, and therefore exists test $(git rev-parse HEAD) != $(git -C art rev-parse HEAD) test $(git rev-parse HEAD) != $(git -C assets rev-parse HEAD) From 01019d1422638d32a596213fae33f8ab42aeef53 Mon Sep 17 00:00:00 2001 From: Hazel Date: Tue, 21 Nov 2023 18:59:41 +0000 Subject: [PATCH 03/22] update actions/checkout to v4 --- .github/workflows/build-shit.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-shit.yml b/.github/workflows/build-shit.yml index fb3cd16a7..9d73c8120 100644 --- a/.github/workflows/build-shit.yml +++ b/.github/workflows/build-shit.yml @@ -13,7 +13,7 @@ jobs: steps: - name: ensure git cli is installed run: apt update && apt install sudo git -y - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: 'recursive' token: ${{ secrets.GH_RO_PAT }} @@ -45,7 +45,7 @@ jobs: apt install sudo git curl unzip -y echo $GITHUB_WORKSPACE git config --global --add safe.directory $GITHUB_WORKSPACE - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: 'recursive' token: ${{ secrets.GH_RO_PAT }} @@ -68,7 +68,7 @@ jobs: contents: write actions: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: 'recursive' token: ${{ secrets.GH_RO_PAT }} @@ -103,7 +103,7 @@ jobs: # contents: write # actions: write # steps: -# - uses: actions/checkout@v3 +# - uses: actions/checkout@v4 # with: # submodules: 'recursive' # token: ${{ secrets.GH_RO_PAT }} From 6e6958a3bd306a41e0dde2751a2e9a37aeaa46ce Mon Sep 17 00:00:00 2001 From: Hazel Date: Tue, 21 Nov 2023 19:17:34 +0000 Subject: [PATCH 04/22] safe.directory moment --- .github/workflows/build-shit.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-shit.yml b/.github/workflows/build-shit.yml index 9d73c8120..be8bf6516 100644 --- a/.github/workflows/build-shit.yml +++ b/.github/workflows/build-shit.yml @@ -19,6 +19,8 @@ jobs: token: ${{ secrets.GH_RO_PAT }} - name: check whether submodules exist run: | + git config --global --add safe.directory $GITHUB_WORKSPACE + # debug output echo gh=${{ github.sha }} echo head=$(git rev-parse HEAD) From bab7d6cf531af9e7b15f0b883857a21bf04c1daa Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 24 Nov 2023 00:41:38 -0500 Subject: [PATCH 05/22] Reworks to dialogs --- .../dialogs/ChartEditorAboutDialog.hx | 25 ++ .../charting/dialogs/ChartEditorBaseDialog.hx | 69 +++ .../dialogs/ChartEditorUploadChartDialog.hx | 196 ++++++++ .../dialogs/ChartEditorWelcomeDialog.hx | 259 +++++++++++ .../handlers/ChartEditorDialogHandler.hx | 418 ++++-------------- 5 files changed, 628 insertions(+), 339 deletions(-) create mode 100644 source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx create mode 100644 source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx create mode 100644 source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx create mode 100644 source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx new file mode 100644 index 000000000..e6f57c49f --- /dev/null +++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorAboutDialog.hx @@ -0,0 +1,25 @@ +package funkin.ui.debug.charting.dialogs; + +import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogParams; + +@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/about.xml")) +class ChartEditorAboutDialog extends ChartEditorBaseDialog +{ + public function new(state2:ChartEditorState, params2:DialogParams) + { + super(state2, params2); + } + + public static function build(state:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorAboutDialog + { + var dialog = new ChartEditorAboutDialog(state, + { + closable: closable ?? true, + modal: modal ?? true + }); + + dialog.showDialog(modal ?? true); + + return dialog; + } +} diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx new file mode 100644 index 000000000..a180825a8 --- /dev/null +++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorBaseDialog.hx @@ -0,0 +1,69 @@ +package funkin.ui.debug.charting.dialogs; + +import haxe.ui.containers.dialogs.Dialog; +import haxe.ui.containers.dialogs.Dialog.DialogEvent; +import haxe.ui.core.Component; + +@:access(funkin.ui.debug.charting.ChartEditorState) +class ChartEditorBaseDialog extends Dialog +{ + var state:ChartEditorState; + var params:DialogParams; + + var locked:Bool = false; + + public function new(state:ChartEditorState, params:DialogParams) + { + super(); + + this.state = state; + this.params = params; + + this.destroyOnClose = true; + this.closable = params.closable ?? false; + + this.onDialogClosed = event -> onClose(event); + } + + /** + * Called when the dialog is closed. + * Override this to add custom behavior. + */ + public function onClose(event:DialogEvent):Void + { + state.isHaxeUIDialogOpen = false; + } + + /** + * Locks this dialog from interaction. + * Use this when you want to prevent dialog interaction while another dialog is open. + */ + public function lock():Void + { + this.locked = true; + + this.closable = false; + } + + /** + * Unlocks the dialog for interaction. + */ + public function unlock():Void + { + this.locked = false; + + this.closable = params.closable ?? false; + } +} + +typedef DialogParams = +{ + ?closable:Bool, + ?modal:Bool +}; + +typedef DialogDropTarget = +{ + component:Component, + handler:String->Void +} diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx new file mode 100644 index 000000000..aef5e9feb --- /dev/null +++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorUploadChartDialog.hx @@ -0,0 +1,196 @@ +package funkin.ui.debug.charting.dialogs; + +import funkin.input.Cursor; +import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogDropTarget; +import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogParams; +import funkin.util.FileUtil; +import haxe.io.Path; +import haxe.ui.containers.dialogs.Dialog.DialogButton; +import haxe.ui.containers.dialogs.Dialog.DialogEvent; +import haxe.ui.containers.dialogs.Dialogs; +import haxe.ui.notifications.NotificationManager; +import haxe.ui.notifications.NotificationType; + +@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/upload-chart.xml")) +class ChartEditorUploadChartDialog extends ChartEditorBaseDialog +{ + var dropHandlers:Array = []; + + public function new(state2:ChartEditorState, params2:DialogParams) + { + super(state2, params2); + + this.dialogCancel.onClick = (_) -> this.hideDialog(DialogButton.CANCEL); + + this.chartBox.onClick = (_) -> this.onClickChartBox(); + + this.chartBox.onMouseOver = function(_event) { + if (this.locked) return; + this.chartBox.swapClass('upload-bg', 'upload-bg-hover'); + Cursor.cursorMode = Pointer; + } + + this.chartBox.onMouseOut = function(_event) { + this.chartBox.swapClass('upload-bg-hover', 'upload-bg'); + Cursor.cursorMode = Default; + } + + dropHandlers.push({component: this.chartBox, handler: this.onDropFileChartBox}); + } + + public static function build(state:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorUploadChartDialog + { + var dialog = new ChartEditorUploadChartDialog(state, + { + closable: closable ?? false, + modal: modal ?? true + }); + + for (dropTarget in dialog.dropHandlers) + { + state.addDropHandler(dropTarget); + } + + dialog.showDialog(modal ?? true); + + return dialog; + } + + public override function onClose(event:DialogEvent):Void + { + super.onClose(event); + + if (event.button != DialogButton.APPLY && !this.closable) + { + // User cancelled the wizard! Back to the welcome dialog. + state.openWelcomeDialog(this.closable); + } + + for (dropTarget in dropHandlers) + { + state.removeDropHandler(dropTarget); + } + } + + public override function lock():Void + { + super.lock(); + this.dialogCancel.disabled = true; + } + + public override function unlock():Void + { + super.unlock(); + this.dialogCancel.disabled = false; + } + + /** + * Called when clicking the Upload Chart box. + */ + public function onClickChartBox():Void + { + if (this.locked) return; + + this.lock(); + FileUtil.browseForBinaryFile('Open Chart', [FileUtil.FILE_EXTENSION_INFO_FNFC], onSelectFile, onCancelBrowse); + } + + /** + * Called when a file is selected by dropping a file onto the Upload Chart box. + */ + function onDropFileChartBox(pathStr:String):Void + { + var path:Path = new Path(pathStr); + trace('Dropped file (${path})'); + + try + { + var result:Null> = ChartEditorImportExportHandler.loadFromFNFCPath(state, path.toString()); + if (result != null) + { + #if !mac + NotificationManager.instance.addNotification( + { + title: 'Success', + body: result.length == 0 ? 'Loaded chart (${path.toString()})' : 'Loaded chart (${path.toString()})\n${result.join("\n")}', + type: result.length == 0 ? NotificationType.Success : NotificationType.Warning, + expiryMs: Constants.NOTIFICATION_DISMISS_TIME + }); + #end + this.hideDialog(DialogButton.APPLY); + } + else + { + #if !mac + NotificationManager.instance.addNotification( + { + title: 'Failure', + body: 'Failed to load chart (${path.toString()})', + type: NotificationType.Error, + expiryMs: Constants.NOTIFICATION_DISMISS_TIME + }); + #end + } + } + catch (err) + { + #if !mac + NotificationManager.instance.addNotification( + { + title: 'Failure', + body: 'Failed to load chart (${path.toString()}): ${err}', + type: NotificationType.Error, + expiryMs: Constants.NOTIFICATION_DISMISS_TIME + }); + #end + } + } + + /** + * Called when a file is selected by the dialog displayed when clicking the Upload Chart box. + */ + function onSelectFile(selectedFile:SelectedFileInfo):Void + { + this.unlock(); + + if (selectedFile != null && selectedFile.bytes != null) + { + try + { + var result:Null> = ChartEditorImportExportHandler.loadFromFNFC(state, selectedFile.bytes); + if (result != null) + { + #if !mac + NotificationManager.instance.addNotification( + { + title: 'Success', + body: 'Loaded chart (${selectedFile.name})', + type: NotificationType.Success, + expiryMs: Constants.NOTIFICATION_DISMISS_TIME + }); + #end + + if (selectedFile.fullPath != null) state.currentWorkingFilePath = selectedFile.fullPath; + this.hideDialog(DialogButton.APPLY); + } + } + catch (err) + { + #if !mac + NotificationManager.instance.addNotification( + { + title: 'Failure', + body: 'Failed to load chart (${selectedFile.name}): ${err}', + type: NotificationType.Error, + expiryMs: Constants.NOTIFICATION_DISMISS_TIME + }); + #end + } + } + } + + function onCancelBrowse():Void + { + this.unlock(); + } +} diff --git a/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx b/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx new file mode 100644 index 000000000..0a0bb5064 --- /dev/null +++ b/source/funkin/ui/debug/charting/dialogs/ChartEditorWelcomeDialog.hx @@ -0,0 +1,259 @@ +package funkin.ui.debug.charting.dialogs; + +import funkin.data.song.SongRegistry; +import funkin.play.song.Song; +import funkin.ui.debug.charting.ChartEditorState; +import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog; +import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogParams; +import funkin.util.FileUtil; +import funkin.util.SortUtil; +import haxe.ui.components.Label; +import haxe.ui.components.Link; +import haxe.ui.containers.dialogs.Dialog.DialogButton; +import haxe.ui.containers.dialogs.Dialog.DialogEvent; +import haxe.ui.core.Component; +import haxe.ui.events.MouseEvent; +import haxe.ui.events.UIEvent; +import haxe.ui.notifications.NotificationManager; +import haxe.ui.notifications.NotificationType; + +/** + * Builds and opens a dialog letting the user create a new chart, open a recent chart, or load from a template. + * Opens when the chart editor first opens. + */ +@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/welcome.xml")) +@:access(funkin.ui.debug.charting.ChartEditorState) +class ChartEditorWelcomeDialog extends ChartEditorBaseDialog +{ + /** + * @param closable Whether the dialog can be closed by the user. + * @param modal Whether the dialog is locked to the center of the screen (with a dark overlay behind it). + */ + public function new(state2:ChartEditorState, params2:DialogParams) + { + super(state2, params2); + + this.splashBrowse.onClick = _ -> onClickButtonBrowse(); + this.splashCreateFromSongBasicOnly.onClick = _ -> onClickLinkCreateBasicOnly(); + this.splashCreateFromSongErectOnly.onClick = _ -> onClickLinkCreateErectOnly(); + this.splashCreateFromSongBasicErect.onClick = _ -> onClickLinkCreateBasicErect(); + this.splashImportChartLegacy.onClick = _ -> onClickLinkImportChartLegacy(); + + // Add items to the Recent Charts list + #if sys + for (chartPath in state.previousWorkingFilePaths) + { + if (chartPath == null) continue; + this.addRecentFilePath(state, chartPath); + } + #else + this.addHTML5RecentFileMessage(); + #end + + // Add items to the Load From Template list + this.buildTemplateSongList(state); + } + + /** + * @param state The current state of the chart editor. + * @return A newly created `ChartEditorWelcomeDialog`. + */ + public static function build(state:ChartEditorState, ?closable:Bool, ?modal:Bool):ChartEditorWelcomeDialog + { + var dialog = new ChartEditorWelcomeDialog(state, + { + closable: closable ?? false, + modal: modal ?? true + }); + + dialog.showDialog(modal ?? true); + + return dialog; + } + + public override function onClose(event:DialogEvent):Void + { + super.onClose(event); + state.stopWelcomeMusic(); + } + + /** + * Add a file path to the "Open Recent" scroll box on the left. + * @param path + */ + public function addRecentFilePath(state:ChartEditorState, chartPath:String):Void + { + var linkRecentChart:Link = new Link(); + linkRecentChart.text = chartPath; + linkRecentChart.onClick = function(_event) { + this.hideDialog(DialogButton.CANCEL); + state.stopWelcomeMusic(); + + // Load chart from file + var result:Null> = ChartEditorImportExportHandler.loadFromFNFCPath(state, chartPath); + if (result != null) + { + #if !mac + NotificationManager.instance.addNotification( + { + title: 'Success', + body: result.length == 0 ? 'Loaded chart (${chartPath.toString()})' : 'Loaded chart (${chartPath.toString()})\n${result.join("\n")}', + type: result.length == 0 ? NotificationType.Success : NotificationType.Warning, + expiryMs: Constants.NOTIFICATION_DISMISS_TIME + }); + #end + } + else + { + #if !mac + NotificationManager.instance.addNotification( + { + title: 'Failure', + body: 'Failed to load chart (${chartPath.toString()})', + type: NotificationType.Error, + expiryMs: Constants.NOTIFICATION_DISMISS_TIME + }); + #end + } + } + + if (!FileUtil.doesFileExist(chartPath)) + { + trace('Previously loaded chart file (${chartPath}) does not exist, disabling link...'); + linkRecentChart.disabled = true; + } + + splashRecentContainer.addComponent(linkRecentChart); + } + + /** + * Add a string message to the "Open Recent" scroll box on the left. + * Only displays on platforms which don't support direct file system access. + */ + public function addHTML5RecentFileMessage():Void + { + var webLoadLabel:Label = new Label(); + webLoadLabel.text = 'Click the button below to load a chart file (.fnfc) from your computer.'; + + splashRecentContainer.addComponent(webLoadLabel); + } + + /** + * Add all the links to the "Create From Template" scroll box on the right. + */ + public function buildTemplateSongList(state:ChartEditorState):Void + { + var songList:Array = SongRegistry.instance.listEntryIds(); + songList.sort(SortUtil.alphabetically); + + for (targetSongId in songList) + { + var songData:Null = SongRegistry.instance.fetchEntry(targetSongId); + if (songData == null) continue; + + var songName:Null = songData.getDifficulty('normal')?.songName; + if (songName == null) songName = songData.getDifficulty()?.songName; + if (songName == null) // Still null? + { + trace('[WARN] Could not fetch song name for ${targetSongId}'); + continue; + } + + this.addTemplateSong(songName, targetSongId, (_) -> { + this.hideDialog(DialogButton.CANCEL); + state.stopWelcomeMusic(); + + // Load song from template + state.loadSongAsTemplate(targetSongId); + }); + } + } + + /** + * @param loadTemplateCb The callback to call when the user clicks the link. The callback should load the song ID from the template. + */ + public function addTemplateSong(songName:String, songId:String, onClickCb:(MouseEvent) -> Void):Void + { + var linkTemplateSong:Link = new Link(); + linkTemplateSong.text = songName; + linkTemplateSong.onClick = onClickCb; + + this.splashTemplateContainer.addComponent(linkTemplateSong); + } + + /** + * Called when the user clicks the "Browse Chart" button in the dialog. + * Reassign this function to change the behavior. + */ + public function onClickButtonBrowse():Void + { + // Hide the welcome dialog + this.hideDialog(DialogButton.CANCEL); + state.stopWelcomeMusic(); + + // Open the "Open Chart" dialog + state.openBrowseFNFC(false); + } + + /** + * Called when the user clicks the "Create From Template: Easy/Normal/Hard Only" link in the dialog. + * Reassign this function to change the behavior. + */ + public function onClickLinkCreateBasicOnly():Void + { + // Hide the welcome dialog + this.hideDialog(DialogButton.CANCEL); + state.stopWelcomeMusic(); + + // + // Create Song Wizard + // + state.openCreateSongWizardBasicOnly(false); + } + + /** + * Called when the user clicks the "Create From Template: Erect/Nightmare Only" link in the dialog. + * Reassign this function to change the behavior. + */ + public function onClickLinkCreateErectOnly():Void + { + // Hide the welcome dialog + this.hideDialog(DialogButton.CANCEL); + state.stopWelcomeMusic(); + + // + // Create Song Wizard + // + state.openCreateSongWizardErectOnly(false); + } + + /** + * Called when the user clicks the "Create From Template: Easy/Normal/Hard/Erect/Nightmare" link in the dialog. + * Reassign this function to change the behavior. + */ + public function onClickLinkCreateBasicErect():Void + { + // Hide the welcome dialog + this.hideDialog(DialogButton.CANCEL); + state.stopWelcomeMusic(); + + // + // Create Song Wizard + // + state.openCreateSongWizardBasicErect(false); + } + + /** + * Called when the user clicks the "Import Chart: FNF Legacy" link in the dialog. + * Reassign this function to change the behavior. + */ + public function onClickLinkImportChartLegacy():Void + { + // Hide the welcome dialog + this.hideDialog(DialogButton.CANCEL); + state.stopWelcomeMusic(); + + // Open the "Import Chart" dialog + state.openImportChartWizard('legacy', false); + } +} diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx index 06da6ee12..a52828e35 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx @@ -14,6 +14,10 @@ import funkin.play.character.CharacterData; import funkin.play.character.CharacterData.CharacterDataParser; import funkin.play.song.Song; import funkin.play.stage.StageData; +import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogDropTarget; +import funkin.ui.debug.charting.dialogs.ChartEditorAboutDialog; +import funkin.ui.debug.charting.dialogs.ChartEditorUploadChartDialog; +import funkin.ui.debug.charting.dialogs.ChartEditorWelcomeDialog; import funkin.ui.debug.charting.util.ChartEditorDropdowns; import funkin.util.Constants; import funkin.util.FileUtil; @@ -38,6 +42,7 @@ import haxe.ui.core.Component; import haxe.ui.events.UIEvent; import haxe.ui.notifications.NotificationManager; import haxe.ui.notifications.NotificationType; +import haxe.ui.RuntimeComponentBuilder; import thx.semver.Version; using Lambda; @@ -50,8 +55,6 @@ using Lambda; class ChartEditorDialogHandler { // Paths to HaxeUI layout files for each dialog. - static final CHART_EDITOR_DIALOG_ABOUT_LAYOUT:String = Paths.ui('chart-editor/dialogs/about'); - static final CHART_EDITOR_DIALOG_WELCOME_LAYOUT:String = Paths.ui('chart-editor/dialogs/welcome'); static final CHART_EDITOR_DIALOG_UPLOAD_CHART_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-chart'); static final CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT:String = Paths.ui('chart-editor/dialogs/upload-inst'); static final CHART_EDITOR_DIALOG_SONG_METADATA_LAYOUT:String = Paths.ui('chart-editor/dialogs/song-metadata'); @@ -71,7 +74,12 @@ class ChartEditorDialogHandler */ public static function openAboutDialog(state:ChartEditorState):Null { - return openDialog(state, CHART_EDITOR_DIALOG_ABOUT_LAYOUT, true, true); + var dialog = ChartEditorAboutDialog.build(state); + + dialog.zIndex = 1000; + state.isHaxeUIDialogOpen = true; + + return dialog; } /** @@ -82,305 +90,28 @@ class ChartEditorDialogHandler */ public static function openWelcomeDialog(state:ChartEditorState, closable:Bool = true):Null { - var dialog:Null = openDialog(state, CHART_EDITOR_DIALOG_WELCOME_LAYOUT, true, closable); - if (dialog == null) throw 'Could not locate Welcome dialog'; + var dialog = ChartEditorWelcomeDialog.build(state, closable); + dialog.zIndex = 1000; 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 = dialog.findComponent('splashRecentContainer', VBox); - if (splashRecentContainer == null) throw 'Could not locate splashRecentContainer in Welcome dialog'; - - for (chartPath in state.previousWorkingFilePaths) - { - if (chartPath == null) continue; - - var linkRecentChart:Link = new Link(); - linkRecentChart.text = chartPath; - linkRecentChart.onClick = function(_event) { - dialog.hideDialog(DialogButton.CANCEL); - state.stopWelcomeMusic(); - - // Load chart from file - var result:Null> = ChartEditorImportExportHandler.loadFromFNFCPath(state, chartPath); - if (result != null) - { - #if !mac - NotificationManager.instance.addNotification( - { - title: 'Success', - body: result.length == 0 ? 'Loaded chart (${chartPath.toString()})' : 'Loaded chart (${chartPath.toString()})\n${result.join("\n")}', - type: result.length == 0 ? NotificationType.Success : NotificationType.Warning, - expiryMs: Constants.NOTIFICATION_DISMISS_TIME - }); - #end - } - else - { - #if !mac - NotificationManager.instance.addNotification( - { - title: 'Failure', - body: 'Failed to load chart (${chartPath.toString()})', - type: NotificationType.Error, - expiryMs: Constants.NOTIFICATION_DISMISS_TIME - }); - #end - } - } - - 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 = 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 = dialog.findComponent('splashCreateFromSongBasicOnly', Link); - if (linkCreateBasic == null) throw 'Could not locate splashCreateFromSongBasicOnly link in Welcome dialog'; - linkCreateBasic.onClick = function(_event) { - // Hide the welcome dialog - dialog.hideDialog(DialogButton.CANCEL); - state.stopWelcomeMusic(); - - // - // Create Song Wizard - // - openCreateSongWizardBasicOnly(state, false); - } - - // Create New Song "Erect/Nightmare" - var linkCreateErect:Null = dialog.findComponent('splashCreateFromSongErectOnly', Link); - if (linkCreateErect == null) throw 'Could not locate splashCreateFromSongErectOnly link in Welcome dialog'; - linkCreateErect.onClick = function(_event) { - // Hide the welcome dialog - dialog.hideDialog(DialogButton.CANCEL); - - // - // Create Song Wizard - // - openCreateSongWizardErectOnly(state, false); - } - - // Create New Song "Easy/Normal/Hard/Erect/Nightmare" - var linkCreateErect:Null = dialog.findComponent('splashCreateFromSongBasicErect', Link); - if (linkCreateErect == null) throw 'Could not locate splashCreateFromSongBasicErect link in Welcome dialog'; - linkCreateErect.onClick = function(_event) { - // Hide the welcome dialog - dialog.hideDialog(DialogButton.CANCEL); - - // - // Create Song Wizard - // - openCreateSongWizardBasicErect(state, false); - } - - var linkImportChartLegacy:Null = dialog.findComponent('splashImportChartLegacy', Link); - if (linkImportChartLegacy == null) throw 'Could not locate splashImportChartLegacy link in Welcome dialog'; - linkImportChartLegacy.onClick = function(_event) { - // Hide the welcome dialog - dialog.hideDialog(DialogButton.CANCEL); - state.stopWelcomeMusic(); - - // Open the "Import Chart" dialog - openImportChartWizard(state, 'legacy', false); - }; - - var buttonBrowse:Null