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.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/hold-note.xml")) class ChartEditorHoldNoteContextMenu extends ChartEditorBaseContextMenu { var contextmenuNoteKind:Label; var contextmenuPosition:NumberStepper; var contextmenuLength:NumberStepper; var contextmenuPosUnit:DropDown; var contextmenuLengthUnit:DropDown; var contextmenuEdit:MenuItem; var contextmenuFlip: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; contextmenuPosUnit.selectedIndex = selectedUnit; contextmenuPosUnit.value = contextmenuPosUnit.dataSource.get(contextmenuPosUnit.selectedIndex); contextmenuLengthUnit.selectedIndex = selectedUnit; contextmenuLengthUnit.value = contextmenuLengthUnit.dataSource.get(contextmenuLengthUnit.selectedIndex); contextmenuLength.value = data.length; 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 contextmenuPosUnit.onChange = function(_) { // Why does the dropdown do this after I specifically set the value of the damn thing? if (contextmenuPosUnit.selectedIndex == -1) { contextmenuPosUnit.pauseEvent(UIEvent.CHANGE, true); contextmenuPosUnit.selectedIndex = selectedUnit; contextmenuPosUnit.resumeEvent(UIEvent.CHANGE, true, true); } switch (contextmenuPosUnit.value.id) { case "MILLISECONDS": contextmenuPosUnit.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": contextmenuPosUnit.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: contextmenuPosUnit.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 = contextmenuPosUnit.dataSource.get(contextmenuPosUnit.selectedIndex).id; contextmenuPosition.onChange = function(_) { var newTime:Float = contextmenuPosition.value; if (contextmenuPosUnit.selectedIndex == -1) { contextmenuPosUnit.pauseEvent(UIEvent.CHANGE, true); contextmenuPosUnit.selectedIndex = selectedUnit; contextmenuPosUnit.resumeEvent(UIEvent.CHANGE, true); } switch (contextmenuPosUnit.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); } // Considered just making a label but this is probably better contextmenuLengthUnit.onChange = function(_) { if (contextmenuLengthUnit.selectedIndex == -1) { contextmenuLengthUnit.pauseEvent(UIEvent.CHANGE, true); contextmenuLengthUnit.selectedIndex = selectedUnit; contextmenuLengthUnit.resumeEvent(UIEvent.CHANGE, true, true); } switch (contextmenuLengthUnit.value.id) { case "MILLISECONDS": contextmenuLengthUnit.text = "Length (MS)"; if (contextmenuLength.value != data.length) { contextmenuLength.pauseEvent(UIEvent.CHANGE, true); contextmenuLength.value = data.length; contextmenuLength.resumeEvent(UIEvent.CHANGE, true, true); } case "STEPS": contextmenuLengthUnit.text = "Length (Steps)"; if (contextmenuLength.value != (Math.round(data.getStepLength() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio)) { contextmenuLength.pauseEvent(UIEvent.CHANGE, true); contextmenuLength.value = Math.round(data.getStepLength() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio; contextmenuLength.resumeEvent(UIEvent.CHANGE, true, true); } default: contextmenuLengthUnit.text = "Length (MS)"; if (contextmenuLength.value != data.length) { contextmenuLength.pauseEvent(UIEvent.CHANGE, true); contextmenuLength.value = data.length; contextmenuLength.resumeEvent(UIEvent.CHANGE, true, true); } } } id = contextmenuLengthUnit.dataSource.get(contextmenuLengthUnit.selectedIndex).id; contextmenuLength.onChange = function(_) { var newLength:Float = contextmenuLength.value; if (contextmenuLengthUnit.selectedIndex == -1) { contextmenuLengthUnit.pauseEvent(UIEvent.CHANGE, true); contextmenuLengthUnit.selectedIndex = selectedUnit; contextmenuLengthUnit.resumeEvent(UIEvent.CHANGE, true, true); } switch (contextmenuLengthUnit.value.id) { case "MILLISECONDS": // Don't change the length of the hold note if we don't have to if (newLength != 0 || data.length != 0) if (newLength != data.length) { data.length = newLength; chartEditorState.performCommand(new ExtendNoteLengthCommand(data, data.length, MILLISECONDS)); } case "STEPS": if (newLength != 0 || data.length != 0) { newLength = Math.round(newLength / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio; if (newLength != (Math.round(data.getStepLength() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio)) { data.setStepLength(newLength); chartEditorState.performCommand(new ExtendNoteLengthCommand(data, newLength, STEPS)); contextmenuLength.pauseEvent(UIEvent.CHANGE, true); contextmenuLength.value = Math.round(data.getStepLength() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio; contextmenuLength.resumeEvent(UIEvent.CHANGE, true, true); } } default: if (newLength != 0 || data.length != 0) if (newLength != data.length) { data.length = newLength; chartEditorState.performCommand(new ExtendNoteLengthCommand(data, data.length, MILLISECONDS)); } } } if (id == "MILLISECONDS" && contextmenuLength.value != data.length) { contextmenuLength.pauseEvent(UIEvent.CHANGE, true); contextmenuLength.value = data.length; contextmenuLength.resumeEvent(UIEvent.CHANGE, true, true); } else if (id == "STEPS" && contextmenuLength.value != (Math.round(data.getStepLength() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio)) { contextmenuLength.pauseEvent(UIEvent.CHANGE, true); contextmenuLength.value = Math.round(data.getStepLength() / chartEditorState.noteSnapRatio) * chartEditorState.noteSnapRatio; contextmenuLength.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])); } contextmenuRemoveHold.onClick = function(_) { chartEditorState.performCommand(new ExtendNoteLengthCommand(data, 0)); } contextmenuDelete.onClick = function(_) { chartEditorState.performCommand(new RemoveNotesCommand([data])); } } } #end