mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-02-09 13:07:10 +00:00
Several UI tweaks and usability fixes. (#224)
Co-authored-by: Cameron Taylor <cameron.taylor.ninja@gmail.com>
This commit is contained in:
parent
e2250b18ff
commit
95b43cce55
2
assets
2
assets
|
@ -1 +1 @@
|
|||
Subproject commit c3ce920f162ad53cb510557b3bc69ab9805f48d7
|
||||
Subproject commit 4ed2b3084d54899e10d10a97eaafe210158768be
|
|
@ -1,5 +1,6 @@
|
|||
package funkin.ui.debug.charting;
|
||||
|
||||
import haxe.ui.containers.menus.MenuBar;
|
||||
import flixel.addons.display.FlxSliceSprite;
|
||||
import flixel.addons.display.FlxTiledSprite;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
|
@ -565,6 +566,23 @@ class ChartEditorState extends HaxeUIState
|
|||
return FocusManager.instance.focus != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user's mouse cursor is hovering over a SOLID component of the HaxeUI.
|
||||
* If so, we can ignore certain mouse events underneath.
|
||||
*/
|
||||
var isCursorOverHaxeUI(get, never):Bool;
|
||||
|
||||
function get_isCursorOverHaxeUI():Bool
|
||||
{
|
||||
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of `isCursorOverHaxeUI` from the previous frame.
|
||||
* This is useful because we may have just clicked a menu item, causing the menu to disappear.
|
||||
*/
|
||||
var wasCursorOverHaxeUI:Bool = false;
|
||||
|
||||
/**
|
||||
* Set by ChartEditorDialogHandler, used to prevent background interaction while the dialog is open.
|
||||
*/
|
||||
|
@ -1009,7 +1027,7 @@ class ChartEditorState extends HaxeUIState
|
|||
{
|
||||
// Initialize to the default value if not set.
|
||||
result = [];
|
||||
trace('Initializing blank note data for difficulty ' + selectedDifficulty);
|
||||
trace('Initializing blank chart for difficulty ' + selectedDifficulty);
|
||||
currentSongChartData.notes.set(selectedDifficulty, result);
|
||||
currentSongMetadata.playData.difficulties.pushUnique(selectedDifficulty);
|
||||
return result;
|
||||
|
@ -1941,8 +1959,10 @@ class ChartEditorState extends HaxeUIState
|
|||
playbarHead.onDragEnd = function(_:DragEvent) {
|
||||
playbarHeadDragging = false;
|
||||
|
||||
var value:Null<Float> = playbarHead?.value;
|
||||
|
||||
// Set the song position to where the playhead was moved to.
|
||||
scrollPositionInPixels = songLengthInPixels * (playbarHead?.value ?? 0 / 100);
|
||||
scrollPositionInPixels = songLengthInPixels * ((value ?? 0.0) / 100);
|
||||
// Update the conductor and audio tracks to match.
|
||||
moveSongToScrollPosition();
|
||||
|
||||
|
@ -1963,6 +1983,10 @@ class ChartEditorState extends HaxeUIState
|
|||
menubarItemSaveChart = findComponent('menubarItemSaveChart', MenuItem);
|
||||
if (menubarItemSaveChart == null) throw "Could not find menubarItemSaveChart!";
|
||||
|
||||
var menubar = findComponent('menubar', MenuBar);
|
||||
if (menubar == null) throw "Could not find menubar!";
|
||||
if (!Preferences.debugDisplay) menubar.paddingLeft = null;
|
||||
|
||||
// Setup notifications.
|
||||
@:privateAccess
|
||||
NotificationManager.GUTTER_SIZE = 20;
|
||||
|
@ -2280,6 +2304,8 @@ class ChartEditorState extends HaxeUIState
|
|||
#if debug
|
||||
handleQuickWatch();
|
||||
#end
|
||||
|
||||
handlePostUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2724,7 +2750,7 @@ class ChartEditorState extends HaxeUIState
|
|||
function handleScrollKeybinds():Void
|
||||
{
|
||||
// Don't scroll when the user is interacting with the UI, unless a playbar button (the << >> ones) is pressed.
|
||||
if (isHaxeUIFocused && playbarButtonPressed == null) return;
|
||||
if ((isHaxeUIFocused || isCursorOverHaxeUI) && playbarButtonPressed == null) return;
|
||||
|
||||
var scrollAmount:Float = 0; // Amount to scroll the grid.
|
||||
var playheadAmount:Float = 0; // Amount to scroll the playhead relative to the grid.
|
||||
|
@ -2925,7 +2951,7 @@ class ChartEditorState extends HaxeUIState
|
|||
if (FlxG.mouse.justReleased) FlxG.sound.play(Paths.sound("chartingSounds/ClickUp"));
|
||||
|
||||
// Note: If a menu is open in HaxeUI, don't handle cursor behavior.
|
||||
var shouldHandleCursor:Bool = !isHaxeUIFocused
|
||||
var shouldHandleCursor:Bool = !(isHaxeUIFocused || playbarHeadDragging)
|
||||
|| (selectionBoxStartPos != null)
|
||||
|| (dragTargetNote != null || dragTargetEvent != null);
|
||||
var eventColumn:Int = (STRUMLINE_SIZE * 2 + 1) - 1;
|
||||
|
@ -3095,9 +3121,9 @@ class ChartEditorState extends HaxeUIState
|
|||
if (!FlxG.keys.pressed.CONTROL)
|
||||
{
|
||||
// Deselect all items.
|
||||
if (currentNoteSelection.length > 0 || currentEventSelection.length > 0)
|
||||
var shouldDeselect:Bool = !wasCursorOverHaxeUI && (currentNoteSelection.length > 0 || currentEventSelection.length > 0);
|
||||
if (shouldDeselect)
|
||||
{
|
||||
trace('Clicked and dragged outside grid, deselecting all items.');
|
||||
performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
||||
}
|
||||
}
|
||||
|
@ -3213,7 +3239,11 @@ class ChartEditorState extends HaxeUIState
|
|||
else
|
||||
{
|
||||
// Click on an empty space to deselect everything.
|
||||
performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
||||
var shouldDeselect:Bool = !wasCursorOverHaxeUI && (currentNoteSelection.length > 0 || currentEventSelection.length > 0);
|
||||
if (shouldDeselect)
|
||||
{
|
||||
performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3224,9 +3254,9 @@ class ChartEditorState extends HaxeUIState
|
|||
if (!FlxG.keys.pressed.CONTROL)
|
||||
{
|
||||
// Deselect all items.
|
||||
if (currentNoteSelection.length > 0 || currentEventSelection.length > 0)
|
||||
var shouldDeselect:Bool = !wasCursorOverHaxeUI && (currentNoteSelection.length > 0 || currentEventSelection.length > 0);
|
||||
if (shouldDeselect)
|
||||
{
|
||||
trace('Clicked outside grid, deselecting all items.');
|
||||
performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
||||
}
|
||||
}
|
||||
|
@ -3295,7 +3325,6 @@ class ChartEditorState extends HaxeUIState
|
|||
if (FlxG.mouse.screenY < MENU_BAR_HEIGHT)
|
||||
{
|
||||
// Scroll up.
|
||||
trace('Scroll up!');
|
||||
var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.screenY;
|
||||
scrollPositionInPixels -= diff * 0.5; // Too fast!
|
||||
moveSongToScrollPosition();
|
||||
|
@ -3303,7 +3332,6 @@ class ChartEditorState extends HaxeUIState
|
|||
else if (FlxG.mouse.screenY > (playbarHeadLayout?.y ?? 0.0))
|
||||
{
|
||||
// Scroll down.
|
||||
trace('Scroll down!');
|
||||
var diff:Float = FlxG.mouse.screenY - (playbarHeadLayout?.y ?? 0.0);
|
||||
scrollPositionInPixels += diff * 0.5; // Too fast!
|
||||
moveSongToScrollPosition();
|
||||
|
@ -3454,7 +3482,6 @@ class ChartEditorState extends HaxeUIState
|
|||
if (isNoteSelected(highlightedNote.noteData))
|
||||
{
|
||||
// Clicked a selected event, start dragging.
|
||||
trace('Ready to drag!');
|
||||
dragTargetNote = highlightedNote;
|
||||
}
|
||||
else
|
||||
|
@ -3468,7 +3495,6 @@ class ChartEditorState extends HaxeUIState
|
|||
if (isEventSelected(highlightedEvent.eventData))
|
||||
{
|
||||
// Clicked a selected event, start dragging.
|
||||
trace('Ready to drag!');
|
||||
dragTargetEvent = highlightedEvent;
|
||||
}
|
||||
else
|
||||
|
@ -3682,6 +3708,7 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
for (curVariation in availableVariations)
|
||||
{
|
||||
trace('DIFFICULTY TOOLBOX: Variation ${curVariation}');
|
||||
var variationMetadata:Null<SongMetadata> = songMetadata.get(curVariation);
|
||||
if (variationMetadata == null) continue;
|
||||
|
||||
|
@ -3696,6 +3723,7 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
for (difficulty in difficultyList)
|
||||
{
|
||||
trace('DIFFICULTY TOOLBOX: Difficulty ${curVariation}_$difficulty');
|
||||
var _treeDifficulty:TreeViewNode = treeVariation.addNode(
|
||||
{
|
||||
id: 'stv_difficulty_${curVariation}_$difficulty',
|
||||
|
@ -4042,6 +4070,13 @@ class ChartEditorState extends HaxeUIState
|
|||
}
|
||||
}
|
||||
|
||||
// CTRL + F = Flip Notes
|
||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.F)
|
||||
{
|
||||
// Flip selected notes.
|
||||
performCommand(new FlipNotesCommand(currentNoteSelection));
|
||||
}
|
||||
|
||||
// CTRL + A = Select All
|
||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.A)
|
||||
{
|
||||
|
@ -4119,6 +4154,11 @@ class ChartEditorState extends HaxeUIState
|
|||
FlxG.watch.addQuick("eventsSelected", currentEventSelection.length);
|
||||
}
|
||||
|
||||
function handlePostUpdate():Void
|
||||
{
|
||||
wasCursorOverHaxeUI = isCursorOverHaxeUI;
|
||||
}
|
||||
|
||||
/**
|
||||
* PLAYTEST FUNCTIONS
|
||||
*/
|
||||
|
|
|
@ -153,8 +153,8 @@ class ChartEditorDialogHandler
|
|||
#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';
|
||||
var linkCreateBasic:Null<Link> = 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);
|
||||
|
@ -163,12 +163,12 @@ class ChartEditorDialogHandler
|
|||
//
|
||||
// Create Song Wizard
|
||||
//
|
||||
openCreateSongWizardBasic(state, false);
|
||||
openCreateSongWizardBasicOnly(state, false);
|
||||
}
|
||||
|
||||
// Create New Song "Erect/Nightmare"
|
||||
var linkCreateErect:Null<Link> = dialog.findComponent('splashCreateFromSongErect', Link);
|
||||
if (linkCreateErect == null) throw 'Could not locate splashCreateFromSongErect link in Welcome dialog';
|
||||
var linkCreateErect:Null<Link> = 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);
|
||||
|
@ -176,7 +176,20 @@ class ChartEditorDialogHandler
|
|||
//
|
||||
// Create Song Wizard
|
||||
//
|
||||
openCreateSongWizardErect(state, false);
|
||||
openCreateSongWizardErectOnly(state, false);
|
||||
}
|
||||
|
||||
// Create New Song "Easy/Normal/Hard/Erect/Nightmare"
|
||||
var linkCreateErect:Null<Link> = 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<Link> = dialog.findComponent('splashImportChartLegacy', Link);
|
||||
|
@ -458,10 +471,10 @@ class ChartEditorDialogHandler
|
|||
};
|
||||
}
|
||||
|
||||
public static function openCreateSongWizardBasic(state:ChartEditorState, closable:Bool):Void
|
||||
public static function openCreateSongWizardBasicOnly(state:ChartEditorState, closable:Bool):Void
|
||||
{
|
||||
// Step 1. Song Metadata
|
||||
var songMetadataDialog:Dialog = openSongMetadataDialog(state);
|
||||
var songMetadataDialog:Dialog = openSongMetadataDialog(state, false, Constants.DEFAULT_VARIATION);
|
||||
songMetadataDialog.onDialogClosed = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
if (_event.button == DialogButton.APPLY)
|
||||
|
@ -497,10 +510,49 @@ class ChartEditorDialogHandler
|
|||
};
|
||||
}
|
||||
|
||||
public static function openCreateSongWizardErect(state:ChartEditorState, closable:Bool):Void
|
||||
public static function openCreateSongWizardErectOnly(state:ChartEditorState, closable:Bool):Void
|
||||
{
|
||||
// Step 1. Song Metadata
|
||||
var songMetadataDialog:Dialog = openSongMetadataDialog(state);
|
||||
var songMetadataDialog:Dialog = openSongMetadataDialog(state, true, Constants.DEFAULT_VARIATION);
|
||||
songMetadataDialog.onDialogClosed = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
if (_event.button == DialogButton.APPLY)
|
||||
{
|
||||
// Step 2. Upload Instrumental
|
||||
var uploadInstDialog:Dialog = openUploadInstDialog(state, closable);
|
||||
uploadInstDialog.onDialogClosed = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
if (_event.button == DialogButton.APPLY)
|
||||
{
|
||||
// Step 3. Upload Vocals
|
||||
// NOTE: Uploading vocals is optional, so we don't need to check if the user cancelled the wizard.
|
||||
var uploadVocalsDialog:Dialog = openUploadVocalsDialog(state, closable); // var uploadVocalsDialog:Dialog
|
||||
uploadVocalsDialog.onDialogClosed = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
state.currentWorkingFilePath = null; // New file, so no path.
|
||||
state.switchToCurrentInstrumental();
|
||||
state.postLoadInstrumental();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// User cancelled the wizard at Step 2! Back to the welcome dialog.
|
||||
openWelcomeDialog(state);
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// User cancelled the wizard at Step 1! Back to the welcome dialog.
|
||||
openWelcomeDialog(state);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static function openCreateSongWizardBasicErect(state:ChartEditorState, closable:Bool):Void
|
||||
{
|
||||
// Step 1. Song Metadata
|
||||
var songMetadataDialog:Dialog = openSongMetadataDialog(state, false, Constants.DEFAULT_VARIATION);
|
||||
songMetadataDialog.onDialogClosed = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
if (_event.button == DialogButton.APPLY)
|
||||
|
@ -517,7 +569,7 @@ class ChartEditorDialogHandler
|
|||
uploadVocalsDialog.onDialogClosed = function(_event) {
|
||||
state.switchToCurrentInstrumental();
|
||||
// Step 4. Song Metadata (Erect)
|
||||
var songMetadataDialogErect:Dialog = openSongMetadataDialog(state, 'erect');
|
||||
var songMetadataDialogErect:Dialog = openSongMetadataDialog(state, true, 'erect');
|
||||
songMetadataDialogErect.onDialogClosed = function(_event) {
|
||||
state.isHaxeUIDialogOpen = false;
|
||||
if (_event.button == DialogButton.APPLY)
|
||||
|
@ -699,10 +751,8 @@ class ChartEditorDialogHandler
|
|||
* @return The dialog to open.
|
||||
*/
|
||||
@:haxe.warning("-WVarInit")
|
||||
public static function openSongMetadataDialog(state:ChartEditorState, ?targetVariation:String):Dialog
|
||||
public static function openSongMetadataDialog(state:ChartEditorState, erect:Bool, targetVariation:String):Dialog
|
||||
{
|
||||
if (targetVariation == null) targetVariation = Constants.DEFAULT_VARIATION;
|
||||
|
||||
var dialog:Null<Dialog> = openDialog(state, CHART_EDITOR_DIALOG_SONG_METADATA_LAYOUT, true, false);
|
||||
if (dialog == null) throw 'Could not locate Song Metadata dialog';
|
||||
|
||||
|
@ -719,13 +769,10 @@ class ChartEditorDialogHandler
|
|||
dialog.hideDialog(DialogButton.CANCEL);
|
||||
}
|
||||
|
||||
var newSongMetadata:SongMetadata = new SongMetadata('', '', 'default');
|
||||
var newSongMetadata:SongMetadata = new SongMetadata('', '', Constants.DEFAULT_VARIATION);
|
||||
|
||||
newSongMetadata.playData.difficulties = switch (targetVariation)
|
||||
{
|
||||
case 'erect': ['erect', 'nightmare'];
|
||||
default: ['easy', 'normal', 'hard'];
|
||||
};
|
||||
newSongMetadata.variation = targetVariation;
|
||||
newSongMetadata.playData.difficulties = (erect) ? ['erect', 'nightmare'] : ['easy', 'normal', 'hard'];
|
||||
|
||||
var inputSongName:Null<TextField> = dialog.findComponent('inputSongName', TextField);
|
||||
if (inputSongName == null) throw 'Could not locate inputSongName TextField in Song Metadata dialog';
|
||||
|
@ -830,11 +877,14 @@ class ChartEditorDialogHandler
|
|||
var dialogContinue:Null<Button> = dialog.findComponent('dialogContinue', Button);
|
||||
if (dialogContinue == null) throw 'Could not locate dialogContinue button in Song Metadata dialog';
|
||||
dialogContinue.onClick = (_event) -> {
|
||||
state.songMetadata.clear();
|
||||
if (targetVariation == Constants.DEFAULT_VARIATION) state.songMetadata.clear();
|
||||
|
||||
state.songMetadata.set(targetVariation, newSongMetadata);
|
||||
|
||||
Conductor.mapTimeChanges(state.currentSongMetadata.timeChanges);
|
||||
|
||||
state.difficultySelectDirty = true;
|
||||
|
||||
dialog.hideDialog(DialogButton.APPLY);
|
||||
}
|
||||
|
||||
|
|
|
@ -375,14 +375,15 @@ class ChartEditorImportExportHandler
|
|||
// We have to force write because the program will die before the save dialog is closed.
|
||||
trace('Force exporting to $targetPath...');
|
||||
FileUtil.saveFilesAsZIPToPath(zipEntries, targetPath, targetMode);
|
||||
// state.saveDataDirty = false; // Don't edit the saveData flag because the app might be closing.
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Force writing to the specific path (user pressed CTRL-SHIFT-S)
|
||||
// Force write since we know what file the user wants to overwrite.
|
||||
trace('Force exporting to $targetPath...');
|
||||
FileUtil.saveFilesAsZIPToPath(zipEntries, targetPath, targetMode);
|
||||
state.saveDataDirty = false; // Don't edit the saveData flag because the app might be closing.
|
||||
state.saveDataDirty = false;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -155,6 +155,20 @@ class HaxeUIState extends MusicBeatState
|
|||
}
|
||||
}
|
||||
|
||||
function addTooltip(key:String, text:String):Void
|
||||
{
|
||||
var target:Component = findComponent(key);
|
||||
if (target == null)
|
||||
{
|
||||
// Gracefully handle the case where the item can't be located.
|
||||
trace('WARN: Could not locate menu item: $key');
|
||||
}
|
||||
else
|
||||
{
|
||||
target.tooltip = text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an onChange listener to a HaxeUI input component such as a slider or text field.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue