package funkin.ui.debug.charting.contextmenus; #if FEATURE_CHART_EDITOR import haxe.ui.containers.menus.MenuItem; import haxe.ui.components.NumberStepper; import haxe.ui.components.DropDown; import haxe.ui.components.Label; import haxe.ui.core.Screen; import haxe.ui.events.UIEvent; import funkin.data.song.SongData.SongNoteData; import funkin.ui.debug.charting.commands.MoveNotesCommand; import funkin.ui.debug.charting.commands.FlipNotesCommand; import funkin.ui.debug.charting.commands.MirrorNotesCommand; import funkin.ui.debug.charting.commands.RemoveNotesCommand; import funkin.ui.debug.charting.commands.ExtendNoteLengthCommand; @:access(funkin.ui.debug.charting.ChartEditorState) @:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/context-menus/note.xml")) class ChartEditorNoteContextMenu extends ChartEditorBaseContextMenu { var contextmenuNoteKind:Label; var contextmenuPosition:NumberStepper; var contextmenuUnit:DropDown; var contextmenuEdit:MenuItem; var contextmenuFlip:MenuItem; var contextmenuMirrorX:MenuItem; var contextmenuDelete:MenuItem; public var selectedUnit:Int; public var data:SongNoteData; public function new(chartEditorState2:ChartEditorState, xPos2:Float = 0, yPos2:Float = 0, data:SongNoteData, selectedUnit:Int = 0) { super(chartEditorState2, xPos2, yPos2); this.data = data; contextmenuPosition.value = data.time; if (data.kind == null) contextmenuNoteKind.text = 'Default'; else contextmenuNoteKind.text = data.kind; this.selectedUnit = selectedUnit; contextmenuUnit.selectedIndex = selectedUnit; contextmenuUnit.value = contextmenuUnit.dataSource.get(contextmenuUnit.selectedIndex); initialize(); } public function initialize():Void { if (contextmenuNoteKind.text != data.kind) { if (data.kind == null) contextmenuNoteKind.text = 'Default'; else contextmenuNoteKind.text = data.kind; } // NOTE: Remember to use commands here to ensure undo/redo works properly contextmenuUnit.onChange = function(_) { // Why does the dropdown do this after I specifically set the value of the damn thing? if (contextmenuUnit.selectedIndex == -1) { contextmenuUnit.pauseEvent(UIEvent.CHANGE, true); contextmenuUnit.selectedIndex = selectedUnit; contextmenuUnit.resumeEvent(UIEvent.CHANGE, true, true); } switch (contextmenuUnit.value.id) { // Ugh, I hate this code. Surely there's a way to make this cleaner, right? case "MILLISECONDS": contextmenuUnit.text = "Time (MS)"; if (contextmenuPosition.value != data.time) { contextmenuPosition.pauseEvent(UIEvent.CHANGE, true); contextmenuPosition.value = data.time; contextmenuPosition.resumeEvent(UIEvent.CHANGE, true, true); } case "STEPS": contextmenuUnit.text = "Time (Steps)"; if (contextmenuPosition.value != (Math.round(data.getStepTime() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio)) { contextmenuPosition.pauseEvent(UIEvent.CHANGE, true); contextmenuPosition.value = Math.round(data.getStepTime() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio; contextmenuPosition.resumeEvent(UIEvent.CHANGE, true, true); } default: contextmenuUnit.text = "Time (MS)"; if (contextmenuPosition.value != data.time) { contextmenuPosition.pauseEvent(UIEvent.CHANGE, true); contextmenuPosition.value = data.time; contextmenuPosition.resumeEvent(UIEvent.CHANGE, true, true); } } } var id:String = contextmenuUnit.dataSource.get(contextmenuUnit.selectedIndex).id; contextmenuPosition.onChange = function(_) { var newTime:Float = contextmenuPosition.value; if (contextmenuUnit.selectedIndex == -1) { contextmenuUnit.pauseEvent(UIEvent.CHANGE, true); contextmenuUnit.selectedIndex = selectedUnit; contextmenuUnit.resumeEvent(UIEvent.CHANGE, true, true); } switch (contextmenuUnit.value.id) { case "MILLISECONDS": // Don't move the note if we don't have to if (newTime != 0 || data.time != 0) { if (newTime != data.time) { data.time = newTime; chartEditorState.performCommand(new MoveNotesCommand(chartEditorState.currentNoteSelection, newTime, 0, true)); } } case "STEPS": if (newTime != 0 || data.time != 0) { newTime = Math.round(newTime / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio; if (newTime != (Math.round(data.getStepTime() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio)) { data.time = Conductor.instance.getStepTimeInMs(newTime); // There isn't a function for this in the SongData sadly chartEditorState.performCommand(new MoveNotesCommand(chartEditorState.currentNoteSelection, newTime, 0, true, true)); // update the value because it was actually valid contextmenuPosition.pauseEvent(UIEvent.CHANGE, true); contextmenuPosition.value = Math.round(data.getStepTime() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio; contextmenuPosition.resumeEvent(UIEvent.CHANGE, true, true); } } default: if (newTime != 0 || data.time != 0) { if (newTime != data.time) { data.time = newTime; chartEditorState.performCommand(new MoveNotesCommand(chartEditorState.currentNoteSelection, newTime, 0, true)); } } } } // Update the value without triggering the event, though only if it's necessary if (id == "MILLISECONDS" && contextmenuPosition.value != data.time) { contextmenuPosition.pauseEvent(UIEvent.CHANGE, true); contextmenuPosition.value = data.time; contextmenuPosition.resumeEvent(UIEvent.CHANGE, true, true); } else if (id == "STEPS" && contextmenuPosition.value != (Math.round(data.getStepTime() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio)) { contextmenuPosition.pauseEvent(UIEvent.CHANGE, true); contextmenuPosition.value = Math.round(data.getStepTime() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio; contextmenuPosition.resumeEvent(UIEvent.CHANGE, true, true); } contextmenuEdit.onClick = function(_) { chartEditorState.showToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_NOTE_DATA_LAYOUT); } contextmenuFlip.onClick = function(_) { chartEditorState.performCommand(new FlipNotesCommand([data])); } contextmenuMirrorX.onClick = function(_) { chartEditorState.performCommand(new MirrorNotesCommand([data], true, false, true, true)); } contextmenuAddHold.onClick = function(_) { chartEditorState.performCommand(new ExtendNoteLengthCommand(data, 4, STEPS)); } contextmenuDelete.onClick = function(_) { chartEditorState.performCommand(new RemoveNotesCommand([data])); } } } #end