mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-12-02 01:00:21 +00:00
Several QOL features for chart editor, custom cursor logic
This commit is contained in:
parent
6e8feecef1
commit
ee89815981
|
|
@ -125,6 +125,8 @@ class InitState extends FlxTransitionableState
|
|||
ModuleHandler.buildModuleCallbacks();
|
||||
ModuleHandler.loadModuleCache();
|
||||
|
||||
FlxG.debugger.toggleKeys = [F2];
|
||||
|
||||
#if song
|
||||
var song = getSong();
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,10 @@ class LatencyState extends MusicBeatSubstate
|
|||
var offsetsPerBeat:Array<Int> = [];
|
||||
var swagSong:HomemadeMusic;
|
||||
|
||||
#if debug
|
||||
var funnyStatsGraph:CoolStatsGraph;
|
||||
var realStats:CoolStatsGraph;
|
||||
#end
|
||||
|
||||
override function create()
|
||||
{
|
||||
|
|
@ -42,11 +44,13 @@ class LatencyState extends MusicBeatSubstate
|
|||
FlxG.sound.music = swagSong;
|
||||
FlxG.sound.music.play();
|
||||
|
||||
#if debug
|
||||
funnyStatsGraph = new CoolStatsGraph(0, Std.int(FlxG.height / 2), FlxG.width, Std.int(FlxG.height / 2), FlxColor.PINK, "time");
|
||||
FlxG.addChildBelowMouse(funnyStatsGraph);
|
||||
|
||||
realStats = new CoolStatsGraph(0, Std.int(FlxG.height / 2), FlxG.width, Std.int(FlxG.height / 2), FlxColor.YELLOW, "REAL");
|
||||
FlxG.addChildBelowMouse(realStats);
|
||||
#end
|
||||
|
||||
FlxG.stage.addEventListener(KeyboardEvent.KEY_DOWN, key ->
|
||||
{
|
||||
|
|
@ -170,8 +174,10 @@ class LatencyState extends MusicBeatSubstate
|
|||
trace(FlxG.sound.music._channel.position);
|
||||
*/
|
||||
|
||||
#if debug
|
||||
funnyStatsGraph.update(FlxG.sound.music.time % 500);
|
||||
realStats.update(swagSong.getTimeWithDiff() % 500);
|
||||
#end
|
||||
|
||||
if (FlxG.keys.justPressed.S)
|
||||
{
|
||||
|
|
|
|||
112
source/funkin/input/Cursor.hx
Normal file
112
source/funkin/input/Cursor.hx
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
package funkin.input;
|
||||
|
||||
import openfl.utils.Assets;
|
||||
import lime.app.Future;
|
||||
import openfl.display.BitmapData;
|
||||
|
||||
class Cursor
|
||||
{
|
||||
public static var cursorMode(default, set):CursorMode;
|
||||
|
||||
static final ASSET_PATH_CURSOR_DEFAULT:String = "assets/images/cursor/cursor-default.png";
|
||||
static var ASSET_CURSOR_DEFAULT:BitmapData = null;
|
||||
static final ASSET_PATH_CURSOR_POINTER:String = "assets/images/cursor/cursor-pointer.png";
|
||||
static var ASSET_CURSOR_POINTER:BitmapData = null;
|
||||
static final ASSET_PATH_CURSOR_GRABBING:String = "assets/images/cursor/cursor-grabbing.png";
|
||||
static var ASSET_CURSOR_GRABBING:BitmapData = null;
|
||||
|
||||
static function set_cursorMode(value:CursorMode):CursorMode
|
||||
{
|
||||
if (cursorMode != value)
|
||||
{
|
||||
cursorMode = value;
|
||||
setCursorGraphic(cursorMode);
|
||||
}
|
||||
return cursorMode;
|
||||
}
|
||||
|
||||
public static function show():Void
|
||||
{
|
||||
FlxG.mouse.visible = true;
|
||||
}
|
||||
|
||||
public static function hide():Void
|
||||
{
|
||||
FlxG.mouse.visible = false;
|
||||
}
|
||||
|
||||
static function setCursorGraphic(?value:CursorMode = null):Void
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
FlxG.mouse.unload();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case Default:
|
||||
if (ASSET_CURSOR_DEFAULT == null)
|
||||
{
|
||||
var future:Future<BitmapData> = Assets.loadBitmapData(ASSET_PATH_CURSOR_DEFAULT);
|
||||
future.onComplete(function(bitmapData:BitmapData)
|
||||
{
|
||||
ASSET_CURSOR_DEFAULT = bitmapData;
|
||||
FlxG.mouse.load(ASSET_CURSOR_DEFAULT);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
FlxG.mouse.load(ASSET_CURSOR_DEFAULT);
|
||||
}
|
||||
|
||||
case Pointer:
|
||||
if (ASSET_CURSOR_POINTER == null)
|
||||
{
|
||||
var future:Future<BitmapData> = Assets.loadBitmapData(ASSET_PATH_CURSOR_POINTER);
|
||||
future.onComplete(function(bitmapData:BitmapData)
|
||||
{
|
||||
ASSET_CURSOR_POINTER = bitmapData;
|
||||
FlxG.mouse.load(ASSET_CURSOR_POINTER);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
FlxG.mouse.load(ASSET_CURSOR_POINTER);
|
||||
}
|
||||
case Grabbing:
|
||||
if (ASSET_CURSOR_GRABBING == null)
|
||||
{
|
||||
var future:Future<BitmapData> = Assets.loadBitmapData(ASSET_PATH_CURSOR_GRABBING);
|
||||
future.onComplete(function(bitmapData:BitmapData)
|
||||
{
|
||||
ASSET_CURSOR_GRABBING = bitmapData;
|
||||
FlxG.mouse.load(ASSET_CURSOR_GRABBING);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
FlxG.mouse.load(ASSET_CURSOR_GRABBING);
|
||||
}
|
||||
default:
|
||||
setCursorGraphic(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
|
||||
enum CursorMode
|
||||
{
|
||||
Default;
|
||||
Pointer;
|
||||
// Grab;
|
||||
Grabbing;
|
||||
// Help;
|
||||
// Progress;
|
||||
// Wait;
|
||||
// Crosshair;
|
||||
// Text;
|
||||
// Move;
|
||||
// ZoomIn;
|
||||
// ZoomOut;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package funkin.ui.debug.charting;
|
||||
|
||||
import funkin.input.Cursor;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.addons.display.FlxSliceSprite;
|
||||
import flixel.addons.display.FlxTiledSprite;
|
||||
|
|
@ -90,15 +91,26 @@ class ChartEditorState extends HaxeUIState
|
|||
// The amount of padding between the menu bar and the chart grid when fully scrolled up.
|
||||
static final GRID_TOP_PAD:Int = 8;
|
||||
|
||||
public static final PLAYHEAD_SCROLL_AREA_WIDTH:Int = 12;
|
||||
public static final PLAYHEAD_HEIGHT:Int = Std.int(GRID_SIZE / 8);
|
||||
|
||||
public static final GRID_SELECTION_BORDER_WIDTH:Int = 6;
|
||||
|
||||
// Duration until notifications are automatically hidden.
|
||||
static final NOTIFICATION_DISMISS_TIME:Float = 3.0;
|
||||
|
||||
// Start performing rapid undo after this many seconds.
|
||||
static final RAPID_UNDO_DELAY:Float = 0.4;
|
||||
// Perform a rapid undo every this many seconds.
|
||||
static final RAPID_UNDO_INTERVAL:Float = 0.1;
|
||||
|
||||
// UI Element Colors
|
||||
// Background color tint.
|
||||
static final CURSOR_COLOR:FlxColor = 0xC0FFFFFF;
|
||||
static final CURSOR_COLOR:FlxColor = 0xE0FFFFFF;
|
||||
static final PREVIEW_BG_COLOR:FlxColor = 0xFF303030;
|
||||
static final PLAYHEAD_COLOR:FlxColor = 0xC0808080;
|
||||
static final PLAYHEAD_SCROLL_AREA_COLOR:FlxColor = 0xFF682B2F;
|
||||
static final SPECTROGRAM_COLOR:FlxColor = 0xFFFF0000;
|
||||
static final PLAYHEAD_COLOR:FlxColor = 0xC0BD0231;
|
||||
|
||||
/**
|
||||
* How many pixels far the user needs to move the mouse before the cursor is considered to be dragged rather than clicked.
|
||||
|
|
@ -351,6 +363,10 @@ class ChartEditorState extends HaxeUIState
|
|||
*/
|
||||
var redoHistory:Array<ChartEditorCommand> = [];
|
||||
|
||||
var undoHeldTime:Float = 0.0;
|
||||
|
||||
var redoHeldTime:Float = 0.0;
|
||||
|
||||
/**
|
||||
* Whether the undo/redo histories have changed since the last time the UI was updated.
|
||||
*/
|
||||
|
|
@ -367,6 +383,11 @@ class ChartEditorState extends HaxeUIState
|
|||
*/
|
||||
var selectionBoxStartPos:FlxPoint = null;
|
||||
|
||||
/**
|
||||
* Whether the user's last mouse click was on the playhead scroll area.
|
||||
*/
|
||||
var gridPlayheadScrollAreaPressed:Bool = false;
|
||||
|
||||
/**
|
||||
* The SongNoteData which is currently being placed.
|
||||
* As the user drags, we will update this note's sustain length.
|
||||
|
|
@ -631,6 +652,8 @@ class ChartEditorState extends HaxeUIState
|
|||
*/
|
||||
var gridPlayhead:FlxSpriteGroup;
|
||||
|
||||
var gridPlayheadScrollArea:FlxSprite;
|
||||
|
||||
/**
|
||||
* A sprite used to highlight the grid square under the cursor.
|
||||
*/
|
||||
|
|
@ -704,7 +727,6 @@ class ChartEditorState extends HaxeUIState
|
|||
currentTheme = ChartEditorTheme.Light;
|
||||
|
||||
buildGrid();
|
||||
buildNoteGroup();
|
||||
buildSelectionBox();
|
||||
|
||||
// Add the HaxeUI components after the grid so they're on top.
|
||||
|
|
@ -759,21 +781,33 @@ class ChartEditorState extends HaxeUIState
|
|||
*/
|
||||
|
||||
// The cursor that appears when hovering over the grid.
|
||||
gridCursor = new FlxSprite().makeGraphic(GRID_SIZE, GRID_SIZE, CURSOR_COLOR);
|
||||
var gridCursorSize:Int = Std.int(GRID_SIZE - GRID_SELECTION_BORDER_WIDTH);
|
||||
gridCursor = new FlxSprite().makeGraphic(gridCursorSize, gridCursorSize, CURSOR_COLOR);
|
||||
add(gridCursor);
|
||||
|
||||
buildNoteGroup();
|
||||
|
||||
gridPlayheadScrollArea = new FlxSprite(gridTiledSprite.x - PLAYHEAD_SCROLL_AREA_WIDTH,
|
||||
MENU_BAR_HEIGHT).makeGraphic(PLAYHEAD_SCROLL_AREA_WIDTH, FlxG.height - MENU_BAR_HEIGHT, PLAYHEAD_SCROLL_AREA_COLOR);
|
||||
add(gridPlayheadScrollArea);
|
||||
|
||||
// The playhead that show the current position in the song.
|
||||
gridPlayhead = new FlxSpriteGroup();
|
||||
add(gridPlayhead);
|
||||
|
||||
var playheadWidth = GRID_SIZE * (STRUMLINE_SIZE * 2 + 1) + 10 + 10;
|
||||
var playheadWidth = GRID_SIZE * (STRUMLINE_SIZE * 2 + 1) + (PLAYHEAD_SCROLL_AREA_WIDTH * 2);
|
||||
var playheadBaseYPos = MENU_BAR_HEIGHT + GRID_TOP_PAD;
|
||||
gridPlayhead.setPosition(gridTiledSprite.x, playheadBaseYPos);
|
||||
var playheadSprite = new FlxSprite().makeGraphic(playheadWidth, Std.int(GRID_SIZE / 4), PLAYHEAD_COLOR);
|
||||
playheadSprite.x = -10;
|
||||
var playheadSprite = new FlxSprite().makeGraphic(playheadWidth, PLAYHEAD_HEIGHT, PLAYHEAD_COLOR);
|
||||
playheadSprite.x = -PLAYHEAD_SCROLL_AREA_WIDTH;
|
||||
playheadSprite.y = 0;
|
||||
gridPlayhead.add(playheadSprite);
|
||||
|
||||
var playheadBlock = ChartEditorThemeHandler.buildPlayheadBlock();
|
||||
playheadBlock.x = -PLAYHEAD_SCROLL_AREA_WIDTH;
|
||||
playheadBlock.y = -PLAYHEAD_HEIGHT / 2;
|
||||
gridPlayhead.add(playheadBlock);
|
||||
|
||||
// Character icons.
|
||||
healthIconDad = new HealthIcon('dad');
|
||||
healthIconDad.autoUpdate = false;
|
||||
|
|
@ -1096,7 +1130,7 @@ class ChartEditorState extends HaxeUIState
|
|||
handleMenubar();
|
||||
handleSidebar();
|
||||
handlePlaybar();
|
||||
handlePlayheadKeybinds();
|
||||
handlePlayhead();
|
||||
|
||||
handleFileKeybinds();
|
||||
handleEditKeybinds();
|
||||
|
|
@ -1159,6 +1193,10 @@ class ChartEditorState extends HaxeUIState
|
|||
**/
|
||||
function handleScrollKeybinds()
|
||||
{
|
||||
// Don't scroll when the cursor is over the UI.
|
||||
if (isCursorOverHaxeUI)
|
||||
return;
|
||||
|
||||
// Amount to scroll the grid.
|
||||
var scrollAmount:Float = 0;
|
||||
// Amount to scroll the playhead relative to the grid.
|
||||
|
|
@ -1218,7 +1256,7 @@ class ChartEditorState extends HaxeUIState
|
|||
// SHIFT + Scroll = Scroll Fast
|
||||
if (FlxG.keys.pressed.SHIFT)
|
||||
{
|
||||
scrollAmount *= 10;
|
||||
scrollAmount *= 5;
|
||||
}
|
||||
// CONTROL + Scroll = Scroll Precise
|
||||
if (FlxG.keys.pressed.CONTROL)
|
||||
|
|
@ -1238,11 +1276,13 @@ class ChartEditorState extends HaxeUIState
|
|||
{
|
||||
// Scroll amount is the difference between the current position and the top.
|
||||
scrollAmount = 0 - this.scrollPosition;
|
||||
playheadAmount = 0 - this.playheadPosition;
|
||||
}
|
||||
if (playbarButtonPressed == 'playbarStart')
|
||||
{
|
||||
playbarButtonPressed = '';
|
||||
scrollAmount = 0 - this.scrollPosition;
|
||||
playheadAmount = 0 - this.playheadPosition;
|
||||
}
|
||||
|
||||
// END = Scroll to Bottom
|
||||
|
|
@ -1276,13 +1316,53 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
if (shouldHandleCursor)
|
||||
{
|
||||
var overlapsGrid:Bool = FlxG.mouse.overlaps(gridTiledSprite);
|
||||
|
||||
// Cursor position relative to the grid.
|
||||
var cursorX:Float = FlxG.mouse.screenX - gridTiledSprite.x;
|
||||
var cursorY:Float = FlxG.mouse.screenY - gridTiledSprite.y;
|
||||
|
||||
if (FlxG.mouse.justPressed && (currentToolMode == ChartEditorToolMode.Select))
|
||||
var overlapsSelectionBorder = overlapsGrid
|
||||
&& (cursorX % 40) < (GRID_SELECTION_BORDER_WIDTH / 2)
|
||||
|| (cursorX % 40) > (40 - (GRID_SELECTION_BORDER_WIDTH / 2))
|
||||
|| (cursorY % 40) < (GRID_SELECTION_BORDER_WIDTH / 2) || (cursorY % 40) > (40 - (GRID_SELECTION_BORDER_WIDTH / 2));
|
||||
|
||||
if (FlxG.mouse.justPressed)
|
||||
{
|
||||
selectionBoxStartPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
|
||||
if (FlxG.mouse.overlaps(gridPlayheadScrollArea))
|
||||
{
|
||||
gridPlayheadScrollAreaPressed = true;
|
||||
}
|
||||
else if (!overlapsGrid || overlapsSelectionBorder)
|
||||
{
|
||||
selectionBoxStartPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
|
||||
}
|
||||
}
|
||||
|
||||
if (gridPlayheadScrollAreaPressed)
|
||||
{
|
||||
Cursor.cursorMode = Grabbing;
|
||||
}
|
||||
else if (FlxG.mouse.overlaps(gridPlayheadScrollArea))
|
||||
{
|
||||
Cursor.cursorMode = Pointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cursor.cursorMode = Default;
|
||||
}
|
||||
|
||||
if (gridPlayheadScrollAreaPressed && FlxG.mouse.released)
|
||||
{
|
||||
gridPlayheadScrollAreaPressed = false;
|
||||
}
|
||||
|
||||
if (gridPlayheadScrollAreaPressed)
|
||||
{
|
||||
// Clicked on the playhead scroll area.
|
||||
// Move the playhead to the cursor position.
|
||||
this.playheadPosition = FlxG.mouse.screenY - MENU_BAR_HEIGHT - GRID_TOP_PAD;
|
||||
moveSongToScrollPosition();
|
||||
}
|
||||
|
||||
// Cursor position snapped to the grid.
|
||||
|
|
@ -1313,7 +1393,7 @@ class ChartEditorState extends HaxeUIState
|
|||
}
|
||||
}
|
||||
|
||||
if ((currentToolMode == ChartEditorToolMode.Select) && selectionBoxStartPos != null)
|
||||
if (selectionBoxStartPos != null)
|
||||
{
|
||||
var cursorXStart:Float = selectionBoxStartPos.x - gridTiledSprite.x;
|
||||
var cursorYStart:Float = selectionBoxStartPos.y - gridTiledSprite.y;
|
||||
|
|
@ -1405,7 +1485,7 @@ class ChartEditorState extends HaxeUIState
|
|||
selectionBoxStartPos = null;
|
||||
setSelectionBoxBounds();
|
||||
|
||||
if (FlxG.mouse.overlaps(gridTiledSprite))
|
||||
if (overlapsGrid)
|
||||
{
|
||||
// We clicked on the grid without moving the mouse.
|
||||
|
||||
|
|
@ -1436,8 +1516,6 @@ class ChartEditorState extends HaxeUIState
|
|||
{
|
||||
if (highlightedNote != null)
|
||||
{
|
||||
// Handle the case of clicking on a sustain piece.
|
||||
highlightedNote = highlightedNote.getBaseNoteSprite();
|
||||
// Click to select an individual note and deselect everything else.
|
||||
if (isNoteSelected(highlightedNote.noteData))
|
||||
{
|
||||
|
|
@ -1471,7 +1549,7 @@ class ChartEditorState extends HaxeUIState
|
|||
}
|
||||
}
|
||||
}
|
||||
else if ((currentToolMode == ChartEditorToolMode.Place) && currentPlaceNoteData != null)
|
||||
else if (currentPlaceNoteData != null)
|
||||
{
|
||||
// Handle extending the note as you drag.
|
||||
|
||||
|
|
@ -1498,10 +1576,10 @@ class ChartEditorState extends HaxeUIState
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((currentToolMode == ChartEditorToolMode.Place) && FlxG.mouse.justPressed)
|
||||
if (FlxG.mouse.justPressed)
|
||||
{
|
||||
// Just clicked to place a note.
|
||||
if (FlxG.mouse.overlaps(gridTiledSprite))
|
||||
if (overlapsGrid && !overlapsSelectionBorder)
|
||||
{
|
||||
// We clicked on the grid without moving the mouse.
|
||||
|
||||
|
|
@ -1512,31 +1590,46 @@ class ChartEditorState extends HaxeUIState
|
|||
return note.alive && FlxG.mouse.overlaps(note);
|
||||
});
|
||||
|
||||
if (highlightedNote != null)
|
||||
if (FlxG.keys.pressed.CONTROL)
|
||||
{
|
||||
// We clicked an existing note.
|
||||
// Do nothing in Place mode so we don't accidentally double place a note.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Click to place a note and select it.
|
||||
var eventColumn = (STRUMLINE_SIZE * 2 + 1) - 1;
|
||||
if (cursorColumn == eventColumn)
|
||||
// Control click to select/deselect an individual note.
|
||||
if (isNoteSelected(highlightedNote.noteData))
|
||||
{
|
||||
// Create an event and place it in the chart.
|
||||
// TODO: Allow configuring the event to place from the sidebar.
|
||||
var newEventData:SongEventData = new SongEventData(cursorMs, "test", {});
|
||||
|
||||
performCommand(new AddEventsCommand([newEventData], FlxG.keys.pressed.CONTROL));
|
||||
performCommand(new DeselectNotesCommand([highlightedNote.noteData]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a note and place it in the chart.
|
||||
var newNoteData:SongNoteData = new SongNoteData(cursorMs, cursorColumn, 0, selectedNoteKind);
|
||||
performCommand(new SelectNotesCommand([highlightedNote.noteData]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (highlightedNote != null)
|
||||
{
|
||||
// Click a note to select it.
|
||||
performCommand(new SetNoteSelectionCommand([highlightedNote.noteData], currentSelection));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Click a blank space to place a note and select it.
|
||||
var eventColumn = (STRUMLINE_SIZE * 2 + 1) - 1;
|
||||
if (cursorColumn == eventColumn)
|
||||
{
|
||||
// Create an event and place it in the chart.
|
||||
// TODO: Allow configuring the event to place from the sidebar.
|
||||
var newEventData:SongEventData = new SongEventData(cursorMs, "test", {});
|
||||
|
||||
performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL));
|
||||
performCommand(new AddEventsCommand([newEventData], FlxG.keys.pressed.CONTROL));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a note and place it in the chart.
|
||||
var newNoteData:SongNoteData = new SongNoteData(cursorMs, cursorColumn, 0, selectedNoteKind);
|
||||
|
||||
currentPlaceNoteData = newNoteData;
|
||||
performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL));
|
||||
|
||||
currentPlaceNoteData = newNoteData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1546,7 +1639,9 @@ class ChartEditorState extends HaxeUIState
|
|||
}
|
||||
}
|
||||
|
||||
if (FlxG.mouse.justPressedRight && FlxG.mouse.overlaps(gridTiledSprite))
|
||||
var rightMouseUpdated:Bool = (FlxG.mouse.justPressedRight)
|
||||
|| (FlxG.mouse.pressedRight && (FlxG.mouse.deltaX > 0 || FlxG.mouse.deltaY > 0));
|
||||
if (rightMouseUpdated && overlapsGrid)
|
||||
{
|
||||
// We right clicked on the grid.
|
||||
|
||||
|
|
@ -1568,12 +1663,12 @@ class ChartEditorState extends HaxeUIState
|
|||
}
|
||||
|
||||
// Handle grid cursor.
|
||||
if (FlxG.mouse.overlaps(gridTiledSprite))
|
||||
if (overlapsGrid && !overlapsSelectionBorder && !gridPlayheadScrollAreaPressed)
|
||||
{
|
||||
gridCursor.visible = true;
|
||||
// X and Y are the cursor position relative to the grid, snapped to the top left of the grid square.
|
||||
gridCursor.x = Math.floor(cursorX / GRID_SIZE) * GRID_SIZE + gridTiledSprite.x;
|
||||
gridCursor.y = cursorStep * GRID_SIZE + gridTiledSprite.y;
|
||||
gridCursor.x = Math.floor(cursorX / GRID_SIZE) * GRID_SIZE + gridTiledSprite.x + (GRID_SELECTION_BORDER_WIDTH / 2);
|
||||
gridCursor.y = cursorStep * GRID_SIZE + gridTiledSprite.y + (GRID_SELECTION_BORDER_WIDTH / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1587,6 +1682,8 @@ class ChartEditorState extends HaxeUIState
|
|||
gridCursor.visible = false;
|
||||
gridCursor.x = -9999;
|
||||
gridCursor.y = -9999;
|
||||
|
||||
Cursor.cursorMode = Default;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1785,12 +1882,40 @@ class ChartEditorState extends HaxeUIState
|
|||
undoLastCommand();
|
||||
}
|
||||
|
||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.Z && !FlxG.keys.pressed.Y)
|
||||
{
|
||||
undoHeldTime += FlxG.elapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
undoHeldTime = 0;
|
||||
}
|
||||
if (undoHeldTime > RAPID_UNDO_DELAY + RAPID_UNDO_INTERVAL)
|
||||
{
|
||||
undoLastCommand();
|
||||
undoHeldTime -= RAPID_UNDO_INTERVAL;
|
||||
}
|
||||
|
||||
// CTRL + Y = Redo
|
||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.Y)
|
||||
{
|
||||
redoLastCommand();
|
||||
}
|
||||
|
||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.Y && !FlxG.keys.pressed.Z)
|
||||
{
|
||||
redoHeldTime += FlxG.elapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
redoHeldTime = 0;
|
||||
}
|
||||
if (redoHeldTime > RAPID_UNDO_DELAY + RAPID_UNDO_INTERVAL)
|
||||
{
|
||||
redoLastCommand();
|
||||
redoHeldTime -= RAPID_UNDO_INTERVAL;
|
||||
}
|
||||
|
||||
// CTRL + C = Copy
|
||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.C)
|
||||
{
|
||||
|
|
@ -2140,7 +2265,7 @@ class ChartEditorState extends HaxeUIState
|
|||
}
|
||||
}
|
||||
|
||||
function handlePlayheadKeybinds()
|
||||
function handlePlayhead()
|
||||
{
|
||||
// Place notes at the playhead.
|
||||
// TODO: Add the ability to switch modes.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package funkin.ui.debug.charting;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.addons.display.FlxGridOverlay;
|
||||
import flixel.addons.display.FlxSliceSprite;
|
||||
import flixel.math.FlxRect;
|
||||
|
|
@ -32,18 +33,24 @@ class ChartEditorThemeHandler
|
|||
static final GRID_COLOR_1_DARK:FlxColor = 0xFF181919;
|
||||
|
||||
// Color 2 of the grid pattern. Alternates with Color 1.
|
||||
static final GRID_COLOR_2_LIGHT:FlxColor = 0xFFD9D5D5;
|
||||
static final GRID_COLOR_2_DARK:FlxColor = 0xFF262A2A;
|
||||
static final GRID_COLOR_2_LIGHT:FlxColor = 0xFFF8F8F8;
|
||||
static final GRID_COLOR_2_DARK:FlxColor = 0xFF202020;
|
||||
|
||||
// Color 3 of the grid pattern. Borders the other colors.
|
||||
static final GRID_COLOR_3_LIGHT:FlxColor = 0xFFD9D5D5;
|
||||
static final GRID_COLOR_3_DARK:FlxColor = 0xFF262A2A;
|
||||
|
||||
// Vertical divider between characters.
|
||||
static final GRID_STRUMLINE_DIVIDER_COLOR_LIGHT:FlxColor = 0xFF000000;
|
||||
static final GRID_STRUMLINE_DIVIDER_COLOR_LIGHT:FlxColor = 0xFF111111;
|
||||
static final GRID_STRUMLINE_DIVIDER_COLOR_DARK:FlxColor = 0xFFC4C4C4;
|
||||
static final GRID_STRUMLINE_DIVIDER_WIDTH:Float = 2;
|
||||
// static final GRID_STRUMLINE_DIVIDER_WIDTH:Float = 2;
|
||||
static final GRID_STRUMLINE_DIVIDER_WIDTH:Float = ChartEditorState.GRID_SELECTION_BORDER_WIDTH;
|
||||
|
||||
// Horizontal divider between measures.
|
||||
static final GRID_MEASURE_DIVIDER_COLOR_LIGHT:FlxColor = 0xFF000000;
|
||||
static final GRID_MEASURE_DIVIDER_COLOR_LIGHT:FlxColor = 0xFF111111;
|
||||
static final GRID_MEASURE_DIVIDER_COLOR_DARK:FlxColor = 0xFFC4C4C4;
|
||||
static final GRID_MEASURE_DIVIDER_WIDTH:Float = 2;
|
||||
// static final GRID_MEASURE_DIVIDER_WIDTH:Float = 2;
|
||||
static final GRID_MEASURE_DIVIDER_WIDTH:Float = ChartEditorState.GRID_SELECTION_BORDER_WIDTH;
|
||||
|
||||
// Border on the square highlighting selected notes.
|
||||
static final SELECTION_SQUARE_BORDER_COLOR_LIGHT:FlxColor = 0xFF339933;
|
||||
|
|
@ -59,6 +66,10 @@ class ChartEditorThemeHandler
|
|||
static final STEPS_PER_BEAT:Int = 4;
|
||||
static final BEATS_PER_MEASURE:Int = 4;
|
||||
|
||||
static final PLAYHEAD_BLOCK_BORDER_WIDTH:Int = 2;
|
||||
static final PLAYHEAD_BLOCK_BORDER_COLOR:FlxColor = 0xFF9D0011;
|
||||
static final PLAYHEAD_BLOCK_FILL_COLOR:FlxColor = 0xFFBD0231;
|
||||
|
||||
public static function updateTheme(state:ChartEditorState):Void
|
||||
{
|
||||
updateBackground(state);
|
||||
|
|
@ -105,6 +116,65 @@ class ChartEditorThemeHandler
|
|||
state.gridBitmap = FlxGridOverlay.createGrid(ChartEditorState.GRID_SIZE, ChartEditorState.GRID_SIZE, gridWidth, gridHeight, true, gridColor1,
|
||||
gridColor2);
|
||||
|
||||
// Selection borders
|
||||
var selectionBorderColor:FlxColor = switch (state.currentTheme)
|
||||
{
|
||||
case Light: GRID_COLOR_3_LIGHT;
|
||||
case Dark: GRID_COLOR_3_DARK;
|
||||
default: GRID_COLOR_3_LIGHT;
|
||||
};
|
||||
|
||||
// Selection border at top.
|
||||
state.gridBitmap.fillRect(new Rectangle(0, -(ChartEditorState.GRID_SELECTION_BORDER_WIDTH / 2), state.gridBitmap.width,
|
||||
ChartEditorState.GRID_SELECTION_BORDER_WIDTH),
|
||||
selectionBorderColor);
|
||||
|
||||
// Selection borders in the middle.
|
||||
for (i in 1...(STEPS_PER_BEAT * BEATS_PER_MEASURE))
|
||||
{
|
||||
state.gridBitmap.fillRect(new Rectangle(0, (ChartEditorState.GRID_SIZE * i) - (ChartEditorState.GRID_SELECTION_BORDER_WIDTH / 2),
|
||||
state.gridBitmap.width, ChartEditorState.GRID_SELECTION_BORDER_WIDTH),
|
||||
selectionBorderColor);
|
||||
}
|
||||
|
||||
// Selection border at bottom.
|
||||
state.gridBitmap.fillRect(new Rectangle(0, state.gridBitmap.height - (ChartEditorState.GRID_SELECTION_BORDER_WIDTH / 2), state.gridBitmap.width,
|
||||
ChartEditorState.GRID_SELECTION_BORDER_WIDTH),
|
||||
selectionBorderColor);
|
||||
|
||||
// Selection border at left.
|
||||
state.gridBitmap.fillRect(new Rectangle(-(ChartEditorState.GRID_SELECTION_BORDER_WIDTH / 2), 0, ChartEditorState.GRID_SELECTION_BORDER_WIDTH,
|
||||
state.gridBitmap.height),
|
||||
selectionBorderColor);
|
||||
|
||||
// Selection borders across the middle.
|
||||
for (i in 1...(ChartEditorState.STRUMLINE_SIZE * 2 + 1))
|
||||
{
|
||||
state.gridBitmap.fillRect(new Rectangle((ChartEditorState.GRID_SIZE * i) - (ChartEditorState.GRID_SELECTION_BORDER_WIDTH / 2), 0,
|
||||
ChartEditorState.GRID_SELECTION_BORDER_WIDTH, state.gridBitmap.height),
|
||||
selectionBorderColor);
|
||||
}
|
||||
|
||||
// Selection border at right.
|
||||
state.gridBitmap.fillRect(new Rectangle(state.gridBitmap.width - (ChartEditorState.GRID_SELECTION_BORDER_WIDTH / 2), 0,
|
||||
ChartEditorState.GRID_SELECTION_BORDER_WIDTH, state.gridBitmap.height),
|
||||
selectionBorderColor);
|
||||
|
||||
// Draw dividers between the measures.
|
||||
|
||||
var gridMeasureDividerColor:FlxColor = switch (state.currentTheme)
|
||||
{
|
||||
case Light: GRID_MEASURE_DIVIDER_COLOR_LIGHT;
|
||||
case Dark: GRID_MEASURE_DIVIDER_COLOR_DARK;
|
||||
default: GRID_MEASURE_DIVIDER_COLOR_LIGHT;
|
||||
};
|
||||
|
||||
// Divider at top
|
||||
state.gridBitmap.fillRect(new Rectangle(0, 0, state.gridBitmap.width, GRID_MEASURE_DIVIDER_WIDTH / 2), gridMeasureDividerColor);
|
||||
// Divider at bottom
|
||||
var dividerLineBY = state.gridBitmap.height - (GRID_MEASURE_DIVIDER_WIDTH / 2);
|
||||
state.gridBitmap.fillRect(new Rectangle(0, dividerLineBY, state.gridBitmap.width, GRID_MEASURE_DIVIDER_WIDTH / 2), gridMeasureDividerColor);
|
||||
|
||||
// Draw dividers between the strumlines.
|
||||
|
||||
var gridStrumlineDividerColor:FlxColor = switch (state.currentTheme)
|
||||
|
|
@ -120,21 +190,6 @@ class ChartEditorThemeHandler
|
|||
// Divider at 2 * (Strumline Size)
|
||||
var dividerLineBX = ChartEditorState.GRID_SIZE * (ChartEditorState.STRUMLINE_SIZE * 2) - (GRID_STRUMLINE_DIVIDER_WIDTH / 2);
|
||||
state.gridBitmap.fillRect(new Rectangle(dividerLineBX, 0, GRID_STRUMLINE_DIVIDER_WIDTH, state.gridBitmap.height), gridStrumlineDividerColor);
|
||||
|
||||
// Draw dividers between the measures.
|
||||
|
||||
var gridMeasureDividerColor:FlxColor = switch (state.currentTheme)
|
||||
{
|
||||
case Light: GRID_MEASURE_DIVIDER_COLOR_LIGHT;
|
||||
case Dark: GRID_MEASURE_DIVIDER_COLOR_DARK;
|
||||
default: GRID_MEASURE_DIVIDER_COLOR_LIGHT;
|
||||
};
|
||||
|
||||
// Divider at top
|
||||
state.gridBitmap.fillRect(new Rectangle(0, 0, state.gridBitmap.width, GRID_MEASURE_DIVIDER_WIDTH / 2), gridMeasureDividerColor);
|
||||
// Divider at bottom
|
||||
var dividerLineBY = state.gridBitmap.height - (GRID_MEASURE_DIVIDER_WIDTH / 2);
|
||||
state.gridBitmap.fillRect(new Rectangle(0, dividerLineBY, GRID_MEASURE_DIVIDER_WIDTH / 2, state.gridBitmap.height), gridMeasureDividerColor);
|
||||
}
|
||||
|
||||
static function updateSelectionSquare(state:ChartEditorState):Void
|
||||
|
|
@ -169,4 +224,20 @@ class ChartEditorThemeHandler
|
|||
- (2 * SELECTION_SQUARE_BORDER_WIDTH + 8)),
|
||||
32, 32);
|
||||
}
|
||||
|
||||
public static function buildPlayheadBlock():FlxSprite
|
||||
{
|
||||
var playheadBlock:FlxSprite = new FlxSprite();
|
||||
|
||||
var playheadBlockBitmap:BitmapData = new BitmapData(ChartEditorState.PLAYHEAD_SCROLL_AREA_WIDTH, ChartEditorState.PLAYHEAD_HEIGHT * 2, true);
|
||||
|
||||
playheadBlockBitmap.fillRect(new Rectangle(0, 0, ChartEditorState.PLAYHEAD_SCROLL_AREA_WIDTH, ChartEditorState.PLAYHEAD_HEIGHT * 2),
|
||||
PLAYHEAD_BLOCK_BORDER_COLOR);
|
||||
playheadBlockBitmap.fillRect(new Rectangle(PLAYHEAD_BLOCK_BORDER_WIDTH, PLAYHEAD_BLOCK_BORDER_WIDTH,
|
||||
ChartEditorState.PLAYHEAD_SCROLL_AREA_WIDTH - (2 * PLAYHEAD_BLOCK_BORDER_WIDTH),
|
||||
ChartEditorState.PLAYHEAD_HEIGHT * 2 - (2 * PLAYHEAD_BLOCK_BORDER_WIDTH)),
|
||||
PLAYHEAD_BLOCK_FILL_COLOR);
|
||||
|
||||
return playheadBlock.loadGraphic(playheadBlockBitmap);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ class DataAssets
|
|||
{
|
||||
static function buildDataPath(path:String):String
|
||||
{
|
||||
return 'assets/data/${path}';
|
||||
return 'default:assets/data/${path}';
|
||||
}
|
||||
|
||||
public static function listDataFilesInPath(path:String, ?suffix:String = '.json'):Array<String>
|
||||
|
|
|
|||
Loading…
Reference in a new issue