mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2024-08-19 23:15:15 +00:00
Merge pull request #275 from FunkinCrew/feature/chart-editor-drag-edit-holds
Click and drag on a sustain to edit it.
This commit is contained in:
commit
772c1b2626
4
hmm.json
4
hmm.json
|
@ -54,14 +54,14 @@
|
||||||
"name": "haxeui-core",
|
"name": "haxeui-core",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "5086e59e7551d775ed4d1fb0188e31de22d1312b",
|
"ref": "2561076c5abeee0a60f3a2a65a8ecb7832a6a62a",
|
||||||
"url": "https://github.com/haxeui/haxeui-core"
|
"url": "https://github.com/haxeui/haxeui-core"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "haxeui-flixel",
|
"name": "haxeui-flixel",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "2b9cff727999b53ed292b1675ac1c9089ac77600",
|
"ref": "9c8ab039524086f5a8c8f35b9fb14538b5bfba5d",
|
||||||
"url": "https://github.com/haxeui/haxeui-flixel"
|
"url": "https://github.com/haxeui/haxeui-flixel"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -826,7 +826,13 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
|
||||||
@:alias("l")
|
@:alias("l")
|
||||||
@:default(0)
|
@:default(0)
|
||||||
@:optional
|
@:optional
|
||||||
public var length:Float;
|
public var length(default, set):Float;
|
||||||
|
|
||||||
|
function set_length(value:Float):Float
|
||||||
|
{
|
||||||
|
_stepLength = null;
|
||||||
|
return length = value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The kind of the note.
|
* The kind of the note.
|
||||||
|
@ -883,6 +889,11 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
|
||||||
return _stepTime = Conductor.instance.getTimeInSteps(this.time);
|
return _stepTime = Conductor.instance.getTimeInSteps(this.time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of the note, if applicable, in steps.
|
||||||
|
* Calculated from the length and the BPM.
|
||||||
|
* Cached for performance. Set to `null` to recalculate.
|
||||||
|
*/
|
||||||
@:jignored
|
@:jignored
|
||||||
var _stepLength:Null<Float> = null;
|
var _stepLength:Null<Float> = null;
|
||||||
|
|
||||||
|
@ -907,9 +918,14 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var lengthMs:Float = Conductor.instance.getStepTimeInMs(value) - this.time;
|
var endStep:Float = getStepTime() + value;
|
||||||
|
var endMs:Float = Conductor.instance.getStepTimeInMs(endStep);
|
||||||
|
var lengthMs:Float = endMs - this.time;
|
||||||
|
|
||||||
this.length = lengthMs;
|
this.length = lengthMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recalculate the step length next time it's requested.
|
||||||
_stepLength = null;
|
_stepLength = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -980,6 +996,10 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw
|
||||||
@:op(A == B)
|
@:op(A == B)
|
||||||
public function op_equals(other:SongNoteData):Bool
|
public function op_equals(other:SongNoteData):Bool
|
||||||
{
|
{
|
||||||
|
// Handle the case where one value is null.
|
||||||
|
if (this == null) return other == null;
|
||||||
|
if (other == null) return false;
|
||||||
|
|
||||||
if (this.kind == '')
|
if (this.kind == '')
|
||||||
{
|
{
|
||||||
if (other.kind != '' && other.kind != 'normal') return false;
|
if (other.kind != '' && other.kind != 'normal') return false;
|
||||||
|
@ -995,6 +1015,10 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw
|
||||||
@:op(A != B)
|
@:op(A != B)
|
||||||
public function op_notEquals(other:SongNoteData):Bool
|
public function op_notEquals(other:SongNoteData):Bool
|
||||||
{
|
{
|
||||||
|
// Handle the case where one value is null.
|
||||||
|
if (this == null) return other == null;
|
||||||
|
if (other == null) return false;
|
||||||
|
|
||||||
if (this.kind == '')
|
if (this.kind == '')
|
||||||
{
|
{
|
||||||
if (other.kind != '' && other.kind != 'normal') return true;
|
if (other.kind != '' && other.kind != 'normal') return true;
|
||||||
|
@ -1010,24 +1034,32 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw
|
||||||
@:op(A > B)
|
@:op(A > B)
|
||||||
public function op_greaterThan(other:SongNoteData):Bool
|
public function op_greaterThan(other:SongNoteData):Bool
|
||||||
{
|
{
|
||||||
|
if (other == null) return false;
|
||||||
|
|
||||||
return this.time > other.time;
|
return this.time > other.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
@:op(A < B)
|
@:op(A < B)
|
||||||
public function op_lessThan(other:SongNoteData):Bool
|
public function op_lessThan(other:SongNoteData):Bool
|
||||||
{
|
{
|
||||||
|
if (other == null) return false;
|
||||||
|
|
||||||
return this.time < other.time;
|
return this.time < other.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
@:op(A >= B)
|
@:op(A >= B)
|
||||||
public function op_greaterThanOrEquals(other:SongNoteData):Bool
|
public function op_greaterThanOrEquals(other:SongNoteData):Bool
|
||||||
{
|
{
|
||||||
|
if (other == null) return false;
|
||||||
|
|
||||||
return this.time >= other.time;
|
return this.time >= other.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
@:op(A <= B)
|
@:op(A <= B)
|
||||||
public function op_lessThanOrEquals(other:SongNoteData):Bool
|
public function op_lessThanOrEquals(other:SongNoteData):Bool
|
||||||
{
|
{
|
||||||
|
if (other == null) return false;
|
||||||
|
|
||||||
return this.time <= other.time;
|
return this.time <= other.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,9 @@ class SustainTrail extends FlxSprite
|
||||||
|
|
||||||
public var isPixel:Bool;
|
public var isPixel:Bool;
|
||||||
|
|
||||||
|
var graphicWidth:Float = 0;
|
||||||
|
var graphicHeight:Float = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normally you would take strumTime:Float, noteData:Int, sustainLength:Float, parentNote:Note (?)
|
* Normally you would take strumTime:Float, noteData:Int, sustainLength:Float, parentNote:Note (?)
|
||||||
* @param NoteData
|
* @param NoteData
|
||||||
|
@ -110,8 +113,8 @@ class SustainTrail extends FlxSprite
|
||||||
zoom *= 0.7;
|
zoom *= 0.7;
|
||||||
|
|
||||||
// CALCULATE SIZE
|
// CALCULATE SIZE
|
||||||
width = graphic.width / 8 * zoom; // amount of notes * 2
|
graphicWidth = graphic.width / 8 * zoom; // amount of notes * 2
|
||||||
height = sustainHeight(sustainLength, getScrollSpeed());
|
graphicHeight = sustainHeight(sustainLength, getScrollSpeed());
|
||||||
// instead of scrollSpeed, PlayState.SONG.speed
|
// instead of scrollSpeed, PlayState.SONG.speed
|
||||||
|
|
||||||
flipY = Preferences.downscroll;
|
flipY = Preferences.downscroll;
|
||||||
|
@ -148,12 +151,21 @@ class SustainTrail extends FlxSprite
|
||||||
|
|
||||||
if (sustainLength == s) return s;
|
if (sustainLength == s) return s;
|
||||||
|
|
||||||
height = sustainHeight(s, getScrollSpeed());
|
graphicHeight = sustainHeight(s, getScrollSpeed());
|
||||||
this.sustainLength = s;
|
this.sustainLength = s;
|
||||||
updateClipping();
|
updateClipping();
|
||||||
|
updateHitbox();
|
||||||
return this.sustainLength;
|
return this.sustainLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override function updateHitbox():Void
|
||||||
|
{
|
||||||
|
width = graphicWidth;
|
||||||
|
height = graphicHeight;
|
||||||
|
offset.set(0, 0);
|
||||||
|
origin.set(width * 0.5, height * 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up new vertex and UV data to clip the trail.
|
* Sets up new vertex and UV data to clip the trail.
|
||||||
* If flipY is true, top and bottom bounds swap places.
|
* If flipY is true, top and bottom bounds swap places.
|
||||||
|
@ -161,7 +173,7 @@ class SustainTrail extends FlxSprite
|
||||||
*/
|
*/
|
||||||
public function updateClipping(songTime:Float = 0):Void
|
public function updateClipping(songTime:Float = 0):Void
|
||||||
{
|
{
|
||||||
var clipHeight:Float = FlxMath.bound(sustainHeight(sustainLength - (songTime - strumTime), getScrollSpeed()), 0, height);
|
var clipHeight:Float = FlxMath.bound(sustainHeight(sustainLength - (songTime - strumTime), getScrollSpeed()), 0, graphicHeight);
|
||||||
if (clipHeight <= 0.1)
|
if (clipHeight <= 0.1)
|
||||||
{
|
{
|
||||||
visible = false;
|
visible = false;
|
||||||
|
@ -178,10 +190,10 @@ class SustainTrail extends FlxSprite
|
||||||
// ===HOLD VERTICES==
|
// ===HOLD VERTICES==
|
||||||
// Top left
|
// Top left
|
||||||
vertices[0 * 2] = 0.0; // Inline with left side
|
vertices[0 * 2] = 0.0; // Inline with left side
|
||||||
vertices[0 * 2 + 1] = flipY ? clipHeight : height - clipHeight;
|
vertices[0 * 2 + 1] = flipY ? clipHeight : graphicHeight - clipHeight;
|
||||||
|
|
||||||
// Top right
|
// Top right
|
||||||
vertices[1 * 2] = width;
|
vertices[1 * 2] = graphicWidth;
|
||||||
vertices[1 * 2 + 1] = vertices[0 * 2 + 1]; // Inline with top left vertex
|
vertices[1 * 2 + 1] = vertices[0 * 2 + 1]; // Inline with top left vertex
|
||||||
|
|
||||||
// Bottom left
|
// Bottom left
|
||||||
|
@ -197,7 +209,7 @@ class SustainTrail extends FlxSprite
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom right
|
// Bottom right
|
||||||
vertices[3 * 2] = width;
|
vertices[3 * 2] = graphicWidth;
|
||||||
vertices[3 * 2 + 1] = vertices[2 * 2 + 1]; // Inline with bottom left vertex
|
vertices[3 * 2 + 1] = vertices[2 * 2 + 1]; // Inline with bottom left vertex
|
||||||
|
|
||||||
// ===HOLD UVs===
|
// ===HOLD UVs===
|
||||||
|
@ -233,7 +245,7 @@ class SustainTrail extends FlxSprite
|
||||||
|
|
||||||
// Bottom left
|
// Bottom left
|
||||||
vertices[6 * 2] = vertices[2 * 2]; // Inline with left side
|
vertices[6 * 2] = vertices[2 * 2]; // Inline with left side
|
||||||
vertices[6 * 2 + 1] = flipY ? (graphic.height * (-bottomClip + endOffset) * zoom) : (height + graphic.height * (bottomClip - endOffset) * zoom);
|
vertices[6 * 2 + 1] = flipY ? (graphic.height * (-bottomClip + endOffset) * zoom) : (graphicHeight + graphic.height * (bottomClip - endOffset) * zoom);
|
||||||
|
|
||||||
// Bottom right
|
// Bottom right
|
||||||
vertices[7 * 2] = vertices[3 * 2]; // Inline with right side
|
vertices[7 * 2] = vertices[3 * 2]; // Inline with right side
|
||||||
|
@ -277,6 +289,10 @@ class SustainTrail extends FlxSprite
|
||||||
getScreenPosition(_point, camera).subtractPoint(offset);
|
getScreenPosition(_point, camera).subtractPoint(offset);
|
||||||
camera.drawTriangles(processedGraphic, vertices, indices, uvtData, null, _point, blend, true, antialiasing);
|
camera.drawTriangles(processedGraphic, vertices, indices, uvtData, null, _point, blend, true, antialiasing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FLX_DEBUG
|
||||||
|
if (FlxG.debugger.drawDebug) drawDebug();
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function kill():Void
|
public override function kill():Void
|
||||||
|
|
|
@ -750,7 +750,14 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
* `null` if the user isn't currently placing a note.
|
* `null` if the user isn't currently placing a note.
|
||||||
* As the user drags, we will update this note's sustain length, and finalize the note when they release.
|
* As the user drags, we will update this note's sustain length, and finalize the note when they release.
|
||||||
*/
|
*/
|
||||||
var currentPlaceNoteData:Null<SongNoteData> = null;
|
var currentPlaceNoteData(default, set):Null<SongNoteData> = null;
|
||||||
|
|
||||||
|
function set_currentPlaceNoteData(value:Null<SongNoteData>):Null<SongNoteData>
|
||||||
|
{
|
||||||
|
noteDisplayDirty = true;
|
||||||
|
|
||||||
|
return currentPlaceNoteData = value;
|
||||||
|
}
|
||||||
|
|
||||||
// Note Movement
|
// Note Movement
|
||||||
|
|
||||||
|
@ -2321,7 +2328,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
bounds.height = MIN_HEIGHT;
|
bounds.height = MIN_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
trace('Note preview viewport bounds: ' + bounds.toString());
|
// trace('Note preview viewport bounds: ' + bounds.toString());
|
||||||
|
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
@ -3172,8 +3179,16 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
{
|
{
|
||||||
if (holdNoteSprite == null || holdNoteSprite.noteData == null || !holdNoteSprite.exists || !holdNoteSprite.visible) continue;
|
if (holdNoteSprite == null || holdNoteSprite.noteData == null || !holdNoteSprite.exists || !holdNoteSprite.visible) continue;
|
||||||
|
|
||||||
if (!holdNoteSprite.isHoldNoteVisible(FlxG.height - PLAYBAR_HEIGHT, MENU_BAR_HEIGHT))
|
if (holdNoteSprite.noteData == currentPlaceNoteData)
|
||||||
{
|
{
|
||||||
|
// This hold note is for the note we are currently dragging.
|
||||||
|
// It will be displayed by gridGhostHoldNoteSprite instead.
|
||||||
|
holdNoteSprite.kill();
|
||||||
|
}
|
||||||
|
else if (!holdNoteSprite.isHoldNoteVisible(FlxG.height - MENU_BAR_HEIGHT, GRID_TOP_PAD))
|
||||||
|
{
|
||||||
|
// This hold note is off-screen.
|
||||||
|
// Kill the hold note sprite and recycle it.
|
||||||
holdNoteSprite.kill();
|
holdNoteSprite.kill();
|
||||||
}
|
}
|
||||||
else if (!currentSongChartNoteData.fastContains(holdNoteSprite.noteData) || holdNoteSprite.noteData.length == 0)
|
else if (!currentSongChartNoteData.fastContains(holdNoteSprite.noteData) || holdNoteSprite.noteData.length == 0)
|
||||||
|
@ -3191,7 +3206,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
displayedHoldNoteData.push(holdNoteSprite.noteData);
|
displayedHoldNoteData.push(holdNoteSprite.noteData);
|
||||||
// Update the event sprite's position.
|
// Update the event sprite's height and position.
|
||||||
|
// var holdNoteHeight = holdNoteSprite.noteData.getStepLength() * GRID_SIZE;
|
||||||
|
// holdNoteSprite.setHeightDirectly(holdNoteHeight);
|
||||||
holdNoteSprite.updateHoldNotePosition(renderedNotes);
|
holdNoteSprite.updateHoldNotePosition(renderedNotes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3269,7 +3286,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
noteSprite.updateNotePosition(renderedNotes);
|
noteSprite.updateNotePosition(renderedNotes);
|
||||||
|
|
||||||
// Add hold notes that are now visible (and not already displayed).
|
// Add hold notes that are now visible (and not already displayed).
|
||||||
if (noteSprite.noteData != null && noteSprite.noteData.length > 0 && displayedHoldNoteData.indexOf(noteSprite.noteData) == -1)
|
if (noteSprite.noteData != null
|
||||||
|
&& noteSprite.noteData.length > 0
|
||||||
|
&& displayedHoldNoteData.indexOf(noteSprite.noteData) == -1
|
||||||
|
&& noteSprite.noteData != currentPlaceNoteData)
|
||||||
{
|
{
|
||||||
var holdNoteSprite:ChartEditorHoldNoteSprite = renderedHoldNotes.recycle(() -> new ChartEditorHoldNoteSprite(this));
|
var holdNoteSprite:ChartEditorHoldNoteSprite = renderedHoldNotes.recycle(() -> new ChartEditorHoldNoteSprite(this));
|
||||||
// trace('Creating new HoldNote... (${renderedHoldNotes.members.length})');
|
// trace('Creating new HoldNote... (${renderedHoldNotes.members.length})');
|
||||||
|
@ -3282,6 +3302,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
holdNoteSprite.setHeightDirectly(noteLengthPixels);
|
holdNoteSprite.setHeightDirectly(noteLengthPixels);
|
||||||
|
|
||||||
holdNoteSprite.updateHoldNotePosition(renderedHoldNotes);
|
holdNoteSprite.updateHoldNotePosition(renderedHoldNotes);
|
||||||
|
|
||||||
|
trace(holdNoteSprite.x + ', ' + holdNoteSprite.y + ', ' + holdNoteSprite.width + ', ' + holdNoteSprite.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3320,6 +3342,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
// Is the note a hold note?
|
// Is the note a hold note?
|
||||||
if (noteData == null || noteData.length <= 0) continue;
|
if (noteData == null || noteData.length <= 0) continue;
|
||||||
|
|
||||||
|
// Is the note the one we are dragging? If so, ghostHoldNoteSprite will handle it.
|
||||||
|
if (noteData == currentPlaceNoteData) continue;
|
||||||
|
|
||||||
// Is the hold note rendered already?
|
// Is the hold note rendered already?
|
||||||
if (displayedHoldNoteData.indexOf(noteData) != -1) continue;
|
if (displayedHoldNoteData.indexOf(noteData) != -1) continue;
|
||||||
|
|
||||||
|
@ -3409,7 +3434,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
selectionSquare.x = noteSprite.x;
|
selectionSquare.x = noteSprite.x;
|
||||||
selectionSquare.y = noteSprite.y;
|
selectionSquare.y = noteSprite.y;
|
||||||
selectionSquare.width = GRID_SIZE;
|
selectionSquare.width = GRID_SIZE;
|
||||||
selectionSquare.height = GRID_SIZE;
|
|
||||||
|
var stepLength = noteSprite.noteData.getStepLength();
|
||||||
|
selectionSquare.height = (stepLength <= 0) ? GRID_SIZE : ((stepLength + 1) * GRID_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3688,6 +3715,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
var overlapsGrid:Bool = FlxG.mouse.overlaps(gridTiledSprite);
|
var overlapsGrid:Bool = FlxG.mouse.overlaps(gridTiledSprite);
|
||||||
|
|
||||||
|
var overlapsRenderedNotes:Bool = FlxG.mouse.overlaps(renderedNotes);
|
||||||
|
var overlapsRenderedHoldNotes:Bool = FlxG.mouse.overlaps(renderedHoldNotes);
|
||||||
|
var overlapsRenderedEvents:Bool = FlxG.mouse.overlaps(renderedEvents);
|
||||||
|
|
||||||
// Cursor position relative to the grid.
|
// Cursor position relative to the grid.
|
||||||
var cursorX:Float = FlxG.mouse.screenX - gridTiledSprite.x;
|
var cursorX:Float = FlxG.mouse.screenX - gridTiledSprite.x;
|
||||||
var cursorY:Float = FlxG.mouse.screenY - gridTiledSprite.y;
|
var cursorY:Float = FlxG.mouse.screenY - gridTiledSprite.y;
|
||||||
|
@ -3929,12 +3960,18 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
return event.alive && FlxG.mouse.overlaps(event);
|
return event.alive && FlxG.mouse.overlaps(event);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
var highlightedHoldNote:Null<ChartEditorHoldNoteSprite> = null;
|
||||||
|
if (highlightedNote == null && highlightedEvent == null)
|
||||||
|
{
|
||||||
|
highlightedHoldNote = renderedHoldNotes.members.find(function(holdNote:ChartEditorHoldNoteSprite):Bool {
|
||||||
|
return holdNote.alive && FlxG.mouse.overlaps(holdNote);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (FlxG.keys.pressed.CONTROL)
|
if (FlxG.keys.pressed.CONTROL)
|
||||||
{
|
{
|
||||||
if (highlightedNote != null && highlightedNote.noteData != null)
|
if (highlightedNote != null && highlightedNote.noteData != null)
|
||||||
{
|
{
|
||||||
// TODO: Handle the case of clicking on a sustain piece.
|
|
||||||
// Control click to select/deselect an individual note.
|
// Control click to select/deselect an individual note.
|
||||||
if (isNoteSelected(highlightedNote.noteData))
|
if (isNoteSelected(highlightedNote.noteData))
|
||||||
{
|
{
|
||||||
|
@ -3957,6 +3994,18 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
performCommand(new SelectItemsCommand([], [highlightedEvent.eventData]));
|
performCommand(new SelectItemsCommand([], [highlightedEvent.eventData]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (highlightedHoldNote != null && highlightedHoldNote.noteData != null)
|
||||||
|
{
|
||||||
|
// Control click to select/deselect an individual note.
|
||||||
|
if (isNoteSelected(highlightedNote.noteData))
|
||||||
|
{
|
||||||
|
performCommand(new DeselectItemsCommand([highlightedHoldNote.noteData], []));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
performCommand(new SelectItemsCommand([highlightedHoldNote.noteData], []));
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Do nothing if you control-clicked on an empty space.
|
// Do nothing if you control-clicked on an empty space.
|
||||||
|
@ -3974,6 +4023,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
// Click an event to select it.
|
// Click an event to select it.
|
||||||
performCommand(new SetItemSelectionCommand([], [highlightedEvent.eventData]));
|
performCommand(new SetItemSelectionCommand([], [highlightedEvent.eventData]));
|
||||||
}
|
}
|
||||||
|
else if (highlightedHoldNote != null && highlightedHoldNote.noteData != null)
|
||||||
|
{
|
||||||
|
// Click a hold note to select it.
|
||||||
|
performCommand(new SetItemSelectionCommand([highlightedHoldNote.noteData], []));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Click on an empty space to deselect everything.
|
// Click on an empty space to deselect everything.
|
||||||
|
@ -4126,7 +4180,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
var dragLengthMs:Float = dragLengthSteps * Conductor.instance.stepLengthMs;
|
var dragLengthMs:Float = dragLengthSteps * Conductor.instance.stepLengthMs;
|
||||||
var dragLengthPixels:Float = dragLengthSteps * GRID_SIZE;
|
var dragLengthPixels:Float = dragLengthSteps * GRID_SIZE;
|
||||||
|
|
||||||
if (gridGhostNote != null && gridGhostNote.noteData != null && gridGhostHoldNote != null)
|
if (gridGhostHoldNote != null)
|
||||||
{
|
{
|
||||||
if (dragLengthSteps > 0)
|
if (dragLengthSteps > 0)
|
||||||
{
|
{
|
||||||
|
@ -4139,8 +4193,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
}
|
}
|
||||||
|
|
||||||
gridGhostHoldNote.visible = true;
|
gridGhostHoldNote.visible = true;
|
||||||
gridGhostHoldNote.noteData = gridGhostNote.noteData;
|
gridGhostHoldNote.noteData = currentPlaceNoteData;
|
||||||
gridGhostHoldNote.noteDirection = gridGhostNote.noteData.getDirection();
|
gridGhostHoldNote.noteDirection = currentPlaceNoteData.getDirection();
|
||||||
|
|
||||||
gridGhostHoldNote.setHeightDirectly(dragLengthPixels, true);
|
gridGhostHoldNote.setHeightDirectly(dragLengthPixels, true);
|
||||||
|
|
||||||
|
@ -4161,6 +4215,15 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
// Apply the new length.
|
// Apply the new length.
|
||||||
performCommand(new ExtendNoteLengthCommand(currentPlaceNoteData, dragLengthMs));
|
performCommand(new ExtendNoteLengthCommand(currentPlaceNoteData, dragLengthMs));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Apply the new (zero) length if we are changing the length.
|
||||||
|
if (currentPlaceNoteData.length > 0)
|
||||||
|
{
|
||||||
|
this.playSound(Paths.sound('chartingSounds/stretchSNAP_UI'));
|
||||||
|
performCommand(new ExtendNoteLengthCommand(currentPlaceNoteData, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Finished dragging. Release the note.
|
// Finished dragging. Release the note.
|
||||||
currentPlaceNoteData = null;
|
currentPlaceNoteData = null;
|
||||||
|
@ -4193,6 +4256,14 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
return event.alive && FlxG.mouse.overlaps(event);
|
return event.alive && FlxG.mouse.overlaps(event);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
var highlightedHoldNote:Null<ChartEditorHoldNoteSprite> = null;
|
||||||
|
if (highlightedNote == null && highlightedEvent == null)
|
||||||
|
{
|
||||||
|
highlightedHoldNote = renderedHoldNotes.members.find(function(holdNote:ChartEditorHoldNoteSprite):Bool {
|
||||||
|
// If holdNote.alive is false, the holdNote is dead and awaiting recycling.
|
||||||
|
return holdNote.alive && FlxG.mouse.overlaps(holdNote);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (FlxG.keys.pressed.CONTROL)
|
if (FlxG.keys.pressed.CONTROL)
|
||||||
{
|
{
|
||||||
|
@ -4219,6 +4290,17 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
performCommand(new SelectItemsCommand([], [highlightedEvent.eventData]));
|
performCommand(new SelectItemsCommand([], [highlightedEvent.eventData]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (highlightedHoldNote != null && highlightedHoldNote.noteData != null)
|
||||||
|
{
|
||||||
|
if (isNoteSelected(highlightedNote.noteData))
|
||||||
|
{
|
||||||
|
performCommand(new DeselectItemsCommand([highlightedHoldNote.noteData], []));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
performCommand(new SelectItemsCommand([highlightedHoldNote.noteData], []));
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Do nothing when control clicking nothing.
|
// Do nothing when control clicking nothing.
|
||||||
|
@ -4252,6 +4334,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
performCommand(new SetItemSelectionCommand([], [highlightedEvent.eventData]));
|
performCommand(new SetItemSelectionCommand([], [highlightedEvent.eventData]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (highlightedHoldNote != null && highlightedHoldNote.noteData != null)
|
||||||
|
{
|
||||||
|
// Clicked a hold note, start dragging TO EXTEND NOTE LENGTH.
|
||||||
|
currentPlaceNoteData = highlightedHoldNote.noteData;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Click a blank space to place a note and select it.
|
// Click a blank space to place a note and select it.
|
||||||
|
@ -4301,6 +4388,14 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
return event.alive && FlxG.mouse.overlaps(event);
|
return event.alive && FlxG.mouse.overlaps(event);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
var highlightedHoldNote:Null<ChartEditorHoldNoteSprite> = null;
|
||||||
|
if (highlightedNote == null && highlightedEvent == null)
|
||||||
|
{
|
||||||
|
highlightedHoldNote = renderedHoldNotes.members.find(function(holdNote:ChartEditorHoldNoteSprite):Bool {
|
||||||
|
// If holdNote.alive is false, the holdNote is dead and awaiting recycling.
|
||||||
|
return holdNote.alive && FlxG.mouse.overlaps(holdNote);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (highlightedNote != null && highlightedNote.noteData != null)
|
if (highlightedNote != null && highlightedNote.noteData != null)
|
||||||
{
|
{
|
||||||
|
@ -4352,13 +4447,40 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
performCommand(new RemoveEventsCommand([highlightedEvent.eventData]));
|
performCommand(new RemoveEventsCommand([highlightedEvent.eventData]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (highlightedHoldNote != null && highlightedHoldNote.noteData != null)
|
||||||
|
{
|
||||||
|
if (FlxG.keys.pressed.SHIFT)
|
||||||
|
{
|
||||||
|
// Shift + Right click opens the context menu.
|
||||||
|
// If we are clicking a large selection, open the Selection context menu, otherwise open the Note context menu.
|
||||||
|
var isHighlightedNoteSelected:Bool = isNoteSelected(highlightedHoldNote.noteData);
|
||||||
|
var useSingleNoteContextMenu:Bool = (!isHighlightedNoteSelected)
|
||||||
|
|| (isHighlightedNoteSelected && currentNoteSelection.length == 1);
|
||||||
|
// Show the context menu connected to the note.
|
||||||
|
if (useSingleNoteContextMenu)
|
||||||
|
{
|
||||||
|
this.openHoldNoteContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY, highlightedHoldNote.noteData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.openSelectionContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Right click removes hold from the note.
|
||||||
|
this.playSound(Paths.sound('chartingSounds/stretchSNAP_UI'));
|
||||||
|
performCommand(new ExtendNoteLengthCommand(highlightedHoldNote.noteData, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Right clicked on nothing.
|
// Right clicked on nothing.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var isOrWillSelect = overlapsSelection || dragTargetNote != null || dragTargetEvent != null;
|
var isOrWillSelect = overlapsSelection || dragTargetNote != null || dragTargetEvent != null || overlapsRenderedNotes || overlapsRenderedHoldNotes
|
||||||
|
|| overlapsRenderedEvents;
|
||||||
// Handle grid cursor.
|
// Handle grid cursor.
|
||||||
if (!isCursorOverHaxeUI && overlapsGrid && !isOrWillSelect && !overlapsSelectionBorder && !gridPlayheadScrollAreaPressed)
|
if (!isCursorOverHaxeUI && overlapsGrid && !isOrWillSelect && !overlapsSelectionBorder && !gridPlayheadScrollAreaPressed)
|
||||||
{
|
{
|
||||||
|
@ -4449,6 +4571,18 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
{
|
{
|
||||||
targetCursorMode = Crosshair;
|
targetCursorMode = Crosshair;
|
||||||
}
|
}
|
||||||
|
else if (overlapsRenderedNotes)
|
||||||
|
{
|
||||||
|
targetCursorMode = Pointer;
|
||||||
|
}
|
||||||
|
else if (overlapsRenderedHoldNotes)
|
||||||
|
{
|
||||||
|
targetCursorMode = Pointer;
|
||||||
|
}
|
||||||
|
else if (overlapsRenderedEvents)
|
||||||
|
{
|
||||||
|
targetCursorMode = Pointer;
|
||||||
|
}
|
||||||
else if (overlapsGrid)
|
else if (overlapsGrid)
|
||||||
{
|
{
|
||||||
targetCursorMode = Cell;
|
targetCursorMode = Cell;
|
||||||
|
@ -5177,7 +5311,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
throw "ERROR: Tried to build selection square, but selectionSquareBitmap is null! Check ChartEditorThemeHandler.updateSelectionSquare()";
|
throw "ERROR: Tried to build selection square, but selectionSquareBitmap is null! Check ChartEditorThemeHandler.updateSelectionSquare()";
|
||||||
|
|
||||||
// FlxG.bitmapLog.add(selectionSquareBitmap, "selectionSquareBitmap");
|
// FlxG.bitmapLog.add(selectionSquareBitmap, "selectionSquareBitmap");
|
||||||
var result = new ChartEditorSelectionSquareSprite();
|
var result = new ChartEditorSelectionSquareSprite(this);
|
||||||
result.loadGraphic(selectionSquareBitmap);
|
result.loadGraphic(selectionSquareBitmap);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -5510,7 +5644,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
/**
|
/**
|
||||||
* HAXEUI FUNCTIONS
|
* HAXEUI FUNCTIONS
|
||||||
*/
|
*/
|
||||||
// ====================
|
// ==================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the currently selected item in the Difficulty tree view to the node representing the current difficulty.
|
* Set the currently selected item in the Difficulty tree view to the node representing the current difficulty.
|
||||||
|
@ -5601,7 +5735,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
/**
|
/**
|
||||||
* STATIC FUNCTIONS
|
* STATIC FUNCTIONS
|
||||||
*/
|
*/
|
||||||
// ====================
|
// ==================
|
||||||
|
|
||||||
function handleNotePreview():Void
|
function handleNotePreview():Void
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,17 +13,25 @@ class ExtendNoteLengthCommand implements ChartEditorCommand
|
||||||
var note:SongNoteData;
|
var note:SongNoteData;
|
||||||
var oldLength:Float;
|
var oldLength:Float;
|
||||||
var newLength:Float;
|
var newLength:Float;
|
||||||
|
var unit:Unit;
|
||||||
|
|
||||||
public function new(note:SongNoteData, newLength:Float)
|
public function new(note:SongNoteData, newLength:Float, unit:Unit = MILLISECONDS)
|
||||||
{
|
{
|
||||||
this.note = note;
|
this.note = note;
|
||||||
this.oldLength = note.length;
|
this.oldLength = note.length;
|
||||||
this.newLength = newLength;
|
this.newLength = newLength;
|
||||||
|
this.unit = unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(state:ChartEditorState):Void
|
public function execute(state:ChartEditorState):Void
|
||||||
{
|
{
|
||||||
note.length = newLength;
|
switch (unit)
|
||||||
|
{
|
||||||
|
case MILLISECONDS:
|
||||||
|
this.note.length = newLength;
|
||||||
|
case STEPS:
|
||||||
|
this.note.setStepLength(newLength);
|
||||||
|
}
|
||||||
|
|
||||||
state.saveDataDirty = true;
|
state.saveDataDirty = true;
|
||||||
state.noteDisplayDirty = true;
|
state.noteDisplayDirty = true;
|
||||||
|
@ -36,7 +44,8 @@ class ExtendNoteLengthCommand implements ChartEditorCommand
|
||||||
{
|
{
|
||||||
state.playSound(Paths.sound('chartingSounds/undo'));
|
state.playSound(Paths.sound('chartingSounds/undo'));
|
||||||
|
|
||||||
note.length = oldLength;
|
// Always use milliseconds for undoing
|
||||||
|
this.note.length = oldLength;
|
||||||
|
|
||||||
state.saveDataDirty = true;
|
state.saveDataDirty = true;
|
||||||
state.noteDisplayDirty = true;
|
state.noteDisplayDirty = true;
|
||||||
|
@ -53,6 +62,23 @@ class ExtendNoteLengthCommand implements ChartEditorCommand
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'Extend Note Length';
|
if (oldLength == 0)
|
||||||
|
{
|
||||||
|
return 'Add Hold to Note';
|
||||||
|
}
|
||||||
|
else if (newLength == 0)
|
||||||
|
{
|
||||||
|
return 'Remove Hold from Note';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 'Extend Hold Note Length';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Unit
|
||||||
|
{
|
||||||
|
MILLISECONDS;
|
||||||
|
STEPS;
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,17 @@ class ChartEditorHoldNoteSprite extends SustainTrail
|
||||||
setup();
|
setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override function updateHitbox():Void
|
||||||
|
{
|
||||||
|
// Expand the clickable hitbox to the full column width, then nudge to the left to re-center it.
|
||||||
|
width = ChartEditorState.GRID_SIZE;
|
||||||
|
height = graphicHeight;
|
||||||
|
|
||||||
|
var xOffset = (ChartEditorState.GRID_SIZE - graphicWidth) / 2;
|
||||||
|
offset.set(-xOffset, 0);
|
||||||
|
origin.set(width * 0.5, height * 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the height directly, to a value in pixels.
|
* Set the height directly, to a value in pixels.
|
||||||
* @param h The desired height in pixels.
|
* @param h The desired height in pixels.
|
||||||
|
@ -52,6 +63,23 @@ class ChartEditorHoldNoteSprite extends SustainTrail
|
||||||
fullSustainLength = sustainLength;
|
fullSustainLength = sustainLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this to override how debug bounding boxes are drawn for this sprite.
|
||||||
|
*/
|
||||||
|
public override function drawDebugOnCamera(camera:flixel.FlxCamera):Void
|
||||||
|
{
|
||||||
|
if (!camera.visible || !camera.exists || !isOnScreen(camera)) return;
|
||||||
|
|
||||||
|
var rect = getBoundingBox(camera);
|
||||||
|
trace('hold note bounding box: ' + rect.x + ', ' + rect.y + ', ' + rect.width + ', ' + rect.height);
|
||||||
|
|
||||||
|
var gfx = beginDrawDebug(camera);
|
||||||
|
debugBoundingBoxColor = 0xffFF66FF;
|
||||||
|
gfx.lineStyle(2, color, 0.5); // thickness, color, alpha
|
||||||
|
gfx.drawRect(rect.x, rect.y, rect.width, rect.height);
|
||||||
|
endDrawDebug(camera);
|
||||||
|
}
|
||||||
|
|
||||||
function setup():Void
|
function setup():Void
|
||||||
{
|
{
|
||||||
strumTime = 999999999;
|
strumTime = 999999999;
|
||||||
|
@ -60,7 +88,9 @@ class ChartEditorHoldNoteSprite extends SustainTrail
|
||||||
active = true;
|
active = true;
|
||||||
visible = true;
|
visible = true;
|
||||||
alpha = 1.0;
|
alpha = 1.0;
|
||||||
width = graphic.width / 8 * zoom; // amount of notes * 2
|
graphicWidth = graphic.width / 8 * zoom; // amount of notes * 2
|
||||||
|
|
||||||
|
updateHitbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function revive():Void
|
public override function revive():Void
|
||||||
|
@ -154,7 +184,7 @@ class ChartEditorHoldNoteSprite extends SustainTrail
|
||||||
}
|
}
|
||||||
|
|
||||||
this.x += ChartEditorState.GRID_SIZE / 2;
|
this.x += ChartEditorState.GRID_SIZE / 2;
|
||||||
this.x -= this.width / 2;
|
this.x -= this.graphicWidth / 2;
|
||||||
|
|
||||||
this.y += ChartEditorState.GRID_SIZE / 2;
|
this.y += ChartEditorState.GRID_SIZE / 2;
|
||||||
|
|
||||||
|
@ -163,5 +193,8 @@ class ChartEditorHoldNoteSprite extends SustainTrail
|
||||||
this.x += origin.x;
|
this.x += origin.x;
|
||||||
this.y += origin.y;
|
this.y += origin.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Account for expanded clickable hitbox.
|
||||||
|
this.x += this.offset.x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,33 @@
|
||||||
package funkin.ui.debug.charting.components;
|
package funkin.ui.debug.charting.components;
|
||||||
|
|
||||||
|
import flixel.addons.display.FlxSliceSprite;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import funkin.data.song.SongData.SongNoteData;
|
import flixel.math.FlxRect;
|
||||||
import funkin.data.song.SongData.SongEventData;
|
import funkin.data.song.SongData.SongEventData;
|
||||||
|
import funkin.data.song.SongData.SongNoteData;
|
||||||
|
import funkin.ui.debug.charting.handlers.ChartEditorThemeHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sprite that can be used to display a square over a selected note or event in the chart.
|
* A sprite that can be used to display a square over a selected note or event in the chart.
|
||||||
* Designed to be used and reused efficiently. Has no gameplay functionality.
|
* Designed to be used and reused efficiently. Has no gameplay functionality.
|
||||||
*/
|
*/
|
||||||
class ChartEditorSelectionSquareSprite extends FlxSprite
|
@:nullSafety
|
||||||
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
|
class ChartEditorSelectionSquareSprite extends FlxSliceSprite
|
||||||
{
|
{
|
||||||
public var noteData:Null<SongNoteData>;
|
public var noteData:Null<SongNoteData>;
|
||||||
public var eventData:Null<SongEventData>;
|
public var eventData:Null<SongEventData>;
|
||||||
|
|
||||||
public function new()
|
public function new(chartEditorState:ChartEditorState)
|
||||||
{
|
{
|
||||||
super();
|
super(chartEditorState.selectionSquareBitmap,
|
||||||
|
new FlxRect(ChartEditorThemeHandler.SELECTION_SQUARE_BORDER_WIDTH
|
||||||
|
+ 4, ChartEditorThemeHandler.SELECTION_SQUARE_BORDER_WIDTH
|
||||||
|
+ 4,
|
||||||
|
ChartEditorState.GRID_SIZE
|
||||||
|
- (2 * ChartEditorThemeHandler.SELECTION_SQUARE_BORDER_WIDTH + 8),
|
||||||
|
ChartEditorState.GRID_SIZE
|
||||||
|
- (2 * ChartEditorThemeHandler.SELECTION_SQUARE_BORDER_WIDTH + 8)),
|
||||||
|
32, 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package funkin.ui.debug.charting.contextmenus;
|
||||||
|
|
||||||
|
import haxe.ui.containers.menus.Menu;
|
||||||
|
import haxe.ui.containers.menus.MenuItem;
|
||||||
|
import haxe.ui.core.Screen;
|
||||||
|
import funkin.data.song.SongData.SongNoteData;
|
||||||
|
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 contextmenuFlip:MenuItem;
|
||||||
|
var contextmenuDelete:MenuItem;
|
||||||
|
|
||||||
|
var data:SongNoteData;
|
||||||
|
|
||||||
|
public function new(chartEditorState2:ChartEditorState, xPos2:Float = 0, yPos2:Float = 0, data:SongNoteData)
|
||||||
|
{
|
||||||
|
super(chartEditorState2, xPos2, yPos2);
|
||||||
|
this.data = data;
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize():Void
|
||||||
|
{
|
||||||
|
// NOTE: Remember to use commands here to ensure undo/redo works properly
|
||||||
|
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]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import haxe.ui.core.Screen;
|
||||||
import funkin.data.song.SongData.SongNoteData;
|
import funkin.data.song.SongData.SongNoteData;
|
||||||
import funkin.ui.debug.charting.commands.FlipNotesCommand;
|
import funkin.ui.debug.charting.commands.FlipNotesCommand;
|
||||||
import funkin.ui.debug.charting.commands.RemoveNotesCommand;
|
import funkin.ui.debug.charting.commands.RemoveNotesCommand;
|
||||||
|
import funkin.ui.debug.charting.commands.ExtendNoteLengthCommand;
|
||||||
|
|
||||||
@:access(funkin.ui.debug.charting.ChartEditorState)
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/context-menus/note.xml"))
|
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/context-menus/note.xml"))
|
||||||
|
@ -31,6 +32,10 @@ class ChartEditorNoteContextMenu extends ChartEditorBaseContextMenu
|
||||||
chartEditorState.performCommand(new FlipNotesCommand([data]));
|
chartEditorState.performCommand(new FlipNotesCommand([data]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contextmenuAddHold.onClick = function(_) {
|
||||||
|
chartEditorState.performCommand(new ExtendNoteLengthCommand(data, 4, STEPS));
|
||||||
|
}
|
||||||
|
|
||||||
contextmenuDelete.onClick = function(_) {
|
contextmenuDelete.onClick = function(_) {
|
||||||
chartEditorState.performCommand(new RemoveNotesCommand([data]));
|
chartEditorState.performCommand(new RemoveNotesCommand([data]));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package funkin.ui.debug.charting.handlers;
|
||||||
|
|
||||||
import funkin.ui.debug.charting.contextmenus.ChartEditorDefaultContextMenu;
|
import funkin.ui.debug.charting.contextmenus.ChartEditorDefaultContextMenu;
|
||||||
import funkin.ui.debug.charting.contextmenus.ChartEditorEventContextMenu;
|
import funkin.ui.debug.charting.contextmenus.ChartEditorEventContextMenu;
|
||||||
|
import funkin.ui.debug.charting.contextmenus.ChartEditorHoldNoteContextMenu;
|
||||||
import funkin.ui.debug.charting.contextmenus.ChartEditorNoteContextMenu;
|
import funkin.ui.debug.charting.contextmenus.ChartEditorNoteContextMenu;
|
||||||
import funkin.ui.debug.charting.contextmenus.ChartEditorSelectionContextMenu;
|
import funkin.ui.debug.charting.contextmenus.ChartEditorSelectionContextMenu;
|
||||||
import haxe.ui.containers.menus.Menu;
|
import haxe.ui.containers.menus.Menu;
|
||||||
|
@ -23,16 +24,33 @@ class ChartEditorContextMenuHandler
|
||||||
displayMenu(state, new ChartEditorDefaultContextMenu(state, xPos, yPos));
|
displayMenu(state, new ChartEditorDefaultContextMenu(state, xPos, yPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opened when shift+right-clicking a selection of multiple items.
|
||||||
|
*/
|
||||||
public static function openSelectionContextMenu(state:ChartEditorState, xPos:Float, yPos:Float)
|
public static function openSelectionContextMenu(state:ChartEditorState, xPos:Float, yPos:Float)
|
||||||
{
|
{
|
||||||
displayMenu(state, new ChartEditorSelectionContextMenu(state, xPos, yPos));
|
displayMenu(state, new ChartEditorSelectionContextMenu(state, xPos, yPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opened when shift+right-clicking a single note.
|
||||||
|
*/
|
||||||
public static function openNoteContextMenu(state:ChartEditorState, xPos:Float, yPos:Float, data:SongNoteData)
|
public static function openNoteContextMenu(state:ChartEditorState, xPos:Float, yPos:Float, data:SongNoteData)
|
||||||
{
|
{
|
||||||
displayMenu(state, new ChartEditorNoteContextMenu(state, xPos, yPos, data));
|
displayMenu(state, new ChartEditorNoteContextMenu(state, xPos, yPos, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opened when shift+right-clicking a single hold note.
|
||||||
|
*/
|
||||||
|
public static function openHoldNoteContextMenu(state:ChartEditorState, xPos:Float, yPos:Float, data:SongNoteData)
|
||||||
|
{
|
||||||
|
displayMenu(state, new ChartEditorHoldNoteContextMenu(state, xPos, yPos, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opened when shift+right-clicking a single event.
|
||||||
|
*/
|
||||||
public static function openEventContextMenu(state:ChartEditorState, xPos:Float, yPos:Float, data:SongEventData)
|
public static function openEventContextMenu(state:ChartEditorState, xPos:Float, yPos:Float, data:SongEventData)
|
||||||
{
|
{
|
||||||
displayMenu(state, new ChartEditorEventContextMenu(state, xPos, yPos, data));
|
displayMenu(state, new ChartEditorEventContextMenu(state, xPos, yPos, data));
|
||||||
|
|
|
@ -52,7 +52,7 @@ class ChartEditorThemeHandler
|
||||||
// Border on the square highlighting selected notes.
|
// Border on the square highlighting selected notes.
|
||||||
static final SELECTION_SQUARE_BORDER_COLOR_LIGHT:FlxColor = 0xFF339933;
|
static final SELECTION_SQUARE_BORDER_COLOR_LIGHT:FlxColor = 0xFF339933;
|
||||||
static final SELECTION_SQUARE_BORDER_COLOR_DARK:FlxColor = 0xFF339933;
|
static final SELECTION_SQUARE_BORDER_COLOR_DARK:FlxColor = 0xFF339933;
|
||||||
static final SELECTION_SQUARE_BORDER_WIDTH:Int = 1;
|
public static final SELECTION_SQUARE_BORDER_WIDTH:Int = 1;
|
||||||
|
|
||||||
// Fill on the square highlighting selected notes.
|
// Fill on the square highlighting selected notes.
|
||||||
// Make sure this is transparent so you can see the notes underneath.
|
// Make sure this is transparent so you can see the notes underneath.
|
||||||
|
|
Loading…
Reference in a new issue