diff --git a/Project.xml b/Project.xml
index a83db1677..ccf6c83a3 100644
--- a/Project.xml
+++ b/Project.xml
@@ -200,6 +200,12 @@
-->
-->
+
+
+
+
diff --git a/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx b/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx
index e5b2d332c..5c3f6cc2c 100644
--- a/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx
@@ -367,6 +367,15 @@ class ChartEditorDialogHandler
handler:(String->Void)
}> = [];
+ /**
+ * Add a callback for when a file is dropped on a component.
+ *
+ * On OS X you can’t drop on the application window, but rather only the app icon
+ * (either in the dock while running or the icon on the hard drive) so this must be disabled
+ * and UI updated appropriately.
+ * @param component
+ * @param handler
+ */
static function addDropHandler(component:Component, handler:String->Void):Void
{
#if desktop
@@ -613,7 +622,11 @@ class ChartEditorDialogHandler
var vocalsEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_UPLOAD_VOCALS_ENTRY_LAYOUT);
var vocalsEntryLabel:Label = vocalsEntry.findComponent('vocalsEntryLabel', Label);
+ #if FILE_DROP_SUPPORTED
vocalsEntryLabel.text = 'Drag and drop vocals for $charName here, or click to browse.';
+ #else
+ vocalsEntryLabel.text = 'Click to browse for vocals for $charName.';
+ #end
var onDropFile:String->Void = function(pathStr:String) {
trace('Selected file: $pathStr');
@@ -629,7 +642,12 @@ class ChartEditorDialogHandler
type: NotificationType.Success,
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
});
+ #if FILE_DROP_SUPPORTED
vocalsEntryLabel.text = 'Vocals for $charName (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
+ #else
+ vocalsEntryLabel.text = 'Vocals for $charName (click to browse)\n${path.file}.${path.ext}';
+ #end
+
dialogNoVocals.hidden = true;
removeDropHandler(onDropFile);
}
@@ -653,7 +671,11 @@ class ChartEditorDialogHandler
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
});
+ #if FILE_DROP_SUPPORTED
vocalsEntryLabel.text = 'Drag and drop vocals for $charName here, or click to browse.';
+ #else
+ vocalsEntryLabel.text = 'Click to browse for vocals for $charName.';
+ #end
}
};
@@ -663,7 +685,11 @@ class ChartEditorDialogHandler
if (selectedFile != null)
{
trace('Selected file: ' + selectedFile.name);
+ #if FILE_DROP_SUPPORTED
+ vocalsEntryLabel.text = 'Vocals for $charName (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}';
+ #else
vocalsEntryLabel.text = 'Vocals for $charName (click to browse)\n${selectedFile.name}';
+ #end
state.loadVocalsFromBytes(selectedFile.bytes, charKey);
dialogNoVocals.hidden = true;
removeDropHandler(onDropFile);
@@ -672,7 +698,9 @@ class ChartEditorDialogHandler
}
// onDropFile
+ #if FILE_DROP_SUPPORTED
addDropHandler(vocalsEntry, onDropFile);
+ #end
dialogContainer.addComponent(vocalsEntry);
}
@@ -729,7 +757,11 @@ class ChartEditorDialogHandler
// Build an entry for -chart.json.
var songDefaultChartDataEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_OPEN_CHART_ENTRY_LAYOUT);
var songDefaultChartDataEntryLabel:Label = songDefaultChartDataEntry.findComponent('chartEntryLabel', Label);
+ #if FILE_DROP_SUPPORTED
songDefaultChartDataEntryLabel.text = 'Drag and drop -chart.json file, or click to browse.';
+ #else
+ songDefaultChartDataEntryLabel.text = 'Click to browse for -chart.json file.';
+ #end
songDefaultChartDataEntry.onClick = onClickChartDataVariation.bind(Constants.DEFAULT_VARIATION).bind(songDefaultChartDataEntryLabel);
addDropHandler(songDefaultChartDataEntry, onDropFileChartDataVariation.bind(Constants.DEFAULT_VARIATION).bind(songDefaultChartDataEntryLabel));
@@ -740,19 +772,31 @@ class ChartEditorDialogHandler
// Build entries for -metadata-.json.
var songVariationMetadataEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_OPEN_CHART_ENTRY_LAYOUT);
var songVariationMetadataEntryLabel:Label = songVariationMetadataEntry.findComponent('chartEntryLabel', Label);
+ #if FILE_DROP_SUPPORTED
songVariationMetadataEntryLabel.text = 'Drag and drop -metadata-${variation}.json file, or click to browse.';
+ #else
+ songVariationMetadataEntryLabel.text = 'Click to browse for -metadata-${variation}.json file.';
+ #end
songVariationMetadataEntry.onClick = onClickMetadataVariation.bind(variation).bind(songVariationMetadataEntryLabel);
+ #if FILE_DROP_SUPPORTED
addDropHandler(songVariationMetadataEntry, onDropFileMetadataVariation.bind(variation).bind(songVariationMetadataEntryLabel));
+ #end
chartContainerB.addComponent(songVariationMetadataEntry);
// Build entries for -chart-.json.
var songVariationChartDataEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_OPEN_CHART_ENTRY_LAYOUT);
var songVariationChartDataEntryLabel:Label = songVariationChartDataEntry.findComponent('chartEntryLabel', Label);
+ #if FILE_DROP_SUPPORTED
songVariationChartDataEntryLabel.text = 'Drag and drop -chart-${variation}.json file, or click to browse.';
+ #else
+ songVariationChartDataEntryLabel.text = 'Click to browse for -chart-${variation}.json file.';
+ #end
songVariationChartDataEntry.onClick = onClickChartDataVariation.bind(variation).bind(songVariationChartDataEntryLabel);
+ #if FILE_DROP_SUPPORTED
addDropHandler(songVariationChartDataEntry, onDropFileChartDataVariation.bind(variation).bind(songVariationChartDataEntryLabel));
+ #end
chartContainerB.addComponent(songVariationChartDataEntry);
}
}
@@ -789,7 +833,11 @@ class ChartEditorDialogHandler
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
});
+ #if FILE_DROP_SUPPORTED
label.text = 'Metadata file (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
+ #else
+ label.text = 'Metadata file (click to browse)\n${path.file}.${path.ext}';
+ #end
if (variation == Constants.DEFAULT_VARIATION) constructVariationEntries(songMetadataVariation.playData.songVariations);
};
@@ -817,7 +865,11 @@ class ChartEditorDialogHandler
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
});
+ #if FILE_DROP_SUPPORTED
label.text = 'Metadata file (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}';
+ #else
+ label.text = 'Metadata file (click to browse)\n${selectedFile.name}';
+ #end
if (variation == Constants.DEFAULT_VARIATION) constructVariationEntries(songMetadataVariation.playData.songVariations);
}
@@ -846,7 +898,11 @@ class ChartEditorDialogHandler
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
});
+ #if FILE_DROP_SUPPORTED
label.text = 'Chart data file (drag and drop, or click to browse)\nSelected file: ${path.file}.${path.ext}';
+ #else
+ label.text = 'Chart data file (click to browse)\n${path.file}.${path.ext}';
+ #end
};
onClickChartDataVariation = function(variation:String, label:Label, _event:UIEvent) {
@@ -874,14 +930,28 @@ class ChartEditorDialogHandler
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
});
+ #if FILE_DROP_SUPPORTED
label.text = 'Chart data file (drag and drop, or click to browse)\nSelected file: ${selectedFile.name}';
+ #else
+ label.text = 'Chart data file (click to browse)\n${selectedFile.name}';
+ #end
}
});
}
var metadataEntry:Component = state.buildComponent(CHART_EDITOR_DIALOG_OPEN_CHART_ENTRY_LAYOUT);
var metadataEntryLabel:Label = metadataEntry.findComponent('chartEntryLabel', Label);
+ #if FILE_DROP_UNSUPPORTED
+ trace('File drop unsupported');
+ #elseif FILE_DROP_SUPPORTED
+ trace('File drop supported');
+ #end
+
+ #if FILE_DROP_SUPPORTED
metadataEntryLabel.text = 'Drag and drop -metadata.json file, or click to browse.';
+ #else
+ metadataEntryLabel.text = 'Click to browse for -metadata.json file.';
+ #end
metadataEntry.onClick = onClickMetadataVariation.bind(Constants.DEFAULT_VARIATION).bind(metadataEntryLabel);
addDropHandler(metadataEntry, onDropFileMetadataVariation.bind(Constants.DEFAULT_VARIATION).bind(metadataEntryLabel));
diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx
index f27fbb6c7..0fe6909e7 100644
--- a/source/funkin/ui/debug/charting/ChartEditorState.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorState.hx
@@ -2555,8 +2555,7 @@ class ChartEditorState extends HaxeUIState
if (gridGhostNote == null) throw "ERROR: Tried to handle cursor, but gridGhostNote is null! Check ChartEditorState.buildGrid()";
- var noteData:SongNoteData = gridGhostNote.noteData != null ? gridGhostNote.noteData : new SongNoteData(cursorMs, cursorColumn, 0,
- selectedNoteKind);
+ var noteData:SongNoteData = gridGhostNote.noteData != null ? gridGhostNote.noteData : new SongNoteData(cursorMs, cursorColumn, 0, selectedNoteKind);
if (cursorColumn != noteData.data || selectedNoteKind != noteData.kind)
{
@@ -2717,12 +2716,12 @@ class ChartEditorState extends HaxeUIState
trace('Creating new Note... (${renderedNotes.members.length})');
noteSprite.parentState = this;
- // The note sprite handles animation playback and positioning.
- noteSprite.noteData = noteData;
-
// Setting note data resets position relative to the grid so we fix that.
noteSprite.updateNotePosition(renderedNotes);
+ // The note sprite handles animation playback and positioning.
+ noteSprite.noteData = noteData;
+
// Add hold notes that are now visible (and not already displayed).
if (noteSprite.noteData != null && noteSprite.noteData.length > 0 && displayedHoldNoteData.indexOf(noteSprite.noteData) == -1)
{
diff --git a/source/funkin/util/FileUtil.hx b/source/funkin/util/FileUtil.hx
index 21c2920d9..3a6f4e330 100644
--- a/source/funkin/util/FileUtil.hx
+++ b/source/funkin/util/FileUtil.hx
@@ -240,6 +240,10 @@ class FileUtil
onSaveAll(paths);
}
+ trace('Browsing for directory to save individual files to...');
+ #if mac
+ defaultPath = null;
+ #end
browseForDirectory(null, onSelectDir, onCancel, defaultPath, 'Choose directory to save all files to...');
return true;