diff --git a/Project.xml b/Project.xml
index 9fad26fd7..46ba7f155 100644
--- a/Project.xml
+++ b/Project.xml
@@ -162,7 +162,10 @@
+
+
+
diff --git a/assets b/assets
index 69283c667..fb7120cf3 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 69283c667d93e44da8d63f0588c7554f608575fb
+Subproject commit fb7120cf30d7accda049409b68d8daa0e1e7650f
diff --git a/source/Main.hx b/source/Main.hx
index 3a7d36178..5fbb6747b 100644
--- a/source/Main.hx
+++ b/source/Main.hx
@@ -111,5 +111,6 @@ class Main extends Sprite
Toolkit.init();
Toolkit.theme = 'dark'; // don't be cringe
Toolkit.autoScale = false;
+ funkin.input.Cursor.registerHaxeUICursors();
}
}
diff --git a/source/funkin/Conductor.hx b/source/funkin/Conductor.hx
index b79ae0fc4..10bf505f0 100644
--- a/source/funkin/Conductor.hx
+++ b/source/funkin/Conductor.hx
@@ -5,6 +5,7 @@ import flixel.util.FlxSignal;
import flixel.math.FlxMath;
import funkin.play.song.Song.SongDifficulty;
import funkin.data.song.SongData.SongTimeChange;
+import funkin.data.song.SongDataUtils;
/**
* A core class which handles musical timing throughout the game,
@@ -257,6 +258,9 @@ class Conductor
{
timeChanges = [];
+ // Sort in place just in case it's out of order.
+ SongDataUtils.sortTimeChanges(songTimeChanges);
+
for (currentTimeChange in songTimeChanges)
{
// TODO: Maybe handle this different?
diff --git a/source/funkin/data/event/SongEventData.hx b/source/funkin/data/event/SongEventData.hx
index 831a53fbd..7a167b031 100644
--- a/source/funkin/data/event/SongEventData.hx
+++ b/source/funkin/data/event/SongEventData.hx
@@ -208,25 +208,32 @@ typedef SongEventSchemaField =
type:SongEventFieldType,
/**
- * Used for ENUM values.
+ * Used only for ENUM values.
* The key is the display name and the value is the actual value.
*/
?keys:Map,
+
/**
* Used for INTEGER and FLOAT values.
* The minimum value that can be entered.
+ * @default No minimum
*/
?min:Float,
+
/**
* Used for INTEGER and FLOAT values.
* The maximum value that can be entered.
+ * @default No maximum
*/
?max:Float,
+
/**
* Used for INTEGER and FLOAT values.
* The step value that will be used when incrementing/decrementing the value.
+ * @default `0.1`
*/
?step:Float,
+
/**
* An optional default value for the field.
*/
diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx
index e8da2518c..e79e1a3f4 100644
--- a/source/funkin/data/song/SongData.hx
+++ b/source/funkin/data/song/SongData.hx
@@ -534,12 +534,22 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
public inline function getInt(key:String):Null
{
- return this.value == null ? null : cast Reflect.field(this.value, key);
+ if (this.value == null) return null;
+ var result = Reflect.field(this.value, key);
+ if (result == null) return null;
+ if (Std.isOfType(result, Int)) return result;
+ if (Std.isOfType(result, String)) return Std.parseInt(cast result);
+ return cast result;
}
public inline function getFloat(key:String):Null
{
- return this.value == null ? null : cast Reflect.field(this.value, key);
+ if (this.value == null) return null;
+ var result = Reflect.field(this.value, key);
+ if (result == null) return null;
+ if (Std.isOfType(result, Float)) return result;
+ if (Std.isOfType(result, String)) return Std.parseFloat(cast result);
+ return cast result;
}
public inline function getString(key:String):String
diff --git a/source/funkin/data/song/SongDataUtils.hx b/source/funkin/data/song/SongDataUtils.hx
index 984af18fa..b149a8855 100644
--- a/source/funkin/data/song/SongDataUtils.hx
+++ b/source/funkin/data/song/SongDataUtils.hx
@@ -3,6 +3,7 @@ package funkin.data.song;
import flixel.util.FlxSort;
import funkin.data.song.SongData.SongEventData;
import funkin.data.song.SongData.SongNoteData;
+import funkin.data.song.SongData.SongTimeChange;
import funkin.util.ClipboardUtil;
import funkin.util.SerializerUtil;
@@ -163,6 +164,18 @@ class SongDataUtils
return events;
}
+ /**
+ * Sort an array of notes by strum time.
+ */
+ public static function sortTimeChanges(timeChanges:Array, desc:Bool = false):Array
+ {
+ // TODO: Modifies the array in place. Is this okay?
+ timeChanges.sort(function(a:SongTimeChange, b:SongTimeChange):Int {
+ return FlxSort.byValues(desc ? FlxSort.DESCENDING : FlxSort.ASCENDING, a.timeStamp, b.timeStamp);
+ });
+ return timeChanges;
+ }
+
/**
* Serialize note and event data and write it to the clipboard.
*/
diff --git a/source/funkin/import.hx b/source/funkin/import.hx
index 8c7124da0..5ca6b03db 100644
--- a/source/funkin/import.hx
+++ b/source/funkin/import.hx
@@ -12,6 +12,7 @@ using Lambda;
using StringTools;
using funkin.util.tools.ArraySortTools;
using funkin.util.tools.ArrayTools;
+using funkin.util.tools.DynamicTools;
using funkin.util.tools.FloatTools;
using funkin.util.tools.Int64Tools;
using funkin.util.tools.IntTools;
diff --git a/source/funkin/input/Cursor.hx b/source/funkin/input/Cursor.hx
index edd9e70f3..c609c9e30 100644
--- a/source/funkin/input/Cursor.hx
+++ b/source/funkin/input/Cursor.hx
@@ -1,5 +1,6 @@
package funkin.input;
+import haxe.ui.backend.flixel.CursorHelper;
import openfl.utils.Assets;
import lime.app.Future;
import openfl.display.BitmapData;
@@ -33,7 +34,7 @@ class Cursor
Cursor.cursorMode = null;
}
- static final CURSOR_DEFAULT_PARAMS:CursorParams =
+ public static final CURSOR_DEFAULT_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-default.png",
scale: 1.0,
@@ -42,7 +43,7 @@ class Cursor
};
static var assetCursorDefault:Null = null;
- static final CURSOR_CROSS_PARAMS:CursorParams =
+ public static final CURSOR_CROSS_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-cross.png",
scale: 1.0,
@@ -51,7 +52,7 @@ class Cursor
};
static var assetCursorCross:Null = null;
- static final CURSOR_ERASER_PARAMS:CursorParams =
+ public static final CURSOR_ERASER_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-eraser.png",
scale: 1.0,
@@ -60,7 +61,7 @@ class Cursor
};
static var assetCursorEraser:Null = null;
- static final CURSOR_GRABBING_PARAMS:CursorParams =
+ public static final CURSOR_GRABBING_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-grabbing.png",
scale: 1.0,
@@ -69,7 +70,7 @@ class Cursor
};
static var assetCursorGrabbing:Null = null;
- static final CURSOR_HOURGLASS_PARAMS:CursorParams =
+ public static final CURSOR_HOURGLASS_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-hourglass.png",
scale: 1.0,
@@ -78,7 +79,7 @@ class Cursor
};
static var assetCursorHourglass:Null = null;
- static final CURSOR_POINTER_PARAMS:CursorParams =
+ public static final CURSOR_POINTER_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-pointer.png",
scale: 1.0,
@@ -87,7 +88,7 @@ class Cursor
};
static var assetCursorPointer:Null = null;
- static final CURSOR_TEXT_PARAMS:CursorParams =
+ public static final CURSOR_TEXT_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-text.png",
scale: 0.2,
@@ -96,7 +97,7 @@ class Cursor
};
static var assetCursorText:Null = null;
- static final CURSOR_TEXT_VERTICAL_PARAMS:CursorParams =
+ public static final CURSOR_TEXT_VERTICAL_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-text-vertical.png",
scale: 0.2,
@@ -105,7 +106,7 @@ class Cursor
};
static var assetCursorTextVertical:Null = null;
- static final CURSOR_ZOOM_IN_PARAMS:CursorParams =
+ public static final CURSOR_ZOOM_IN_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-zoom-in.png",
scale: 1.0,
@@ -114,7 +115,7 @@ class Cursor
};
static var assetCursorZoomIn:Null = null;
- static final CURSOR_ZOOM_OUT_PARAMS:CursorParams =
+ public static final CURSOR_ZOOM_OUT_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-zoom-out.png",
scale: 1.0,
@@ -123,7 +124,7 @@ class Cursor
};
static var assetCursorZoomOut:Null = null;
- static final CURSOR_CROSSHAIR_PARAMS:CursorParams =
+ public static final CURSOR_CROSSHAIR_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-crosshair.png",
scale: 1.0,
@@ -132,7 +133,7 @@ class Cursor
};
static var assetCursorCrosshair:Null = null;
- static final CURSOR_CELL_PARAMS:CursorParams =
+ public static final CURSOR_CELL_PARAMS:CursorParams =
{
graphic: "assets/images/cursor/cursor-cell.png",
scale: 1.0,
@@ -500,6 +501,28 @@ class Cursor
{
trace("Failed to load cursor graphic for cursor mode " + cursorMode + ": " + error);
}
+
+ public static function registerHaxeUICursors():Void
+ {
+ CursorHelper.useCustomCursors = true;
+ registerHaxeUICursor('default', CURSOR_DEFAULT_PARAMS);
+ registerHaxeUICursor('cross', CURSOR_CROSS_PARAMS);
+ registerHaxeUICursor('eraser', CURSOR_ERASER_PARAMS);
+ registerHaxeUICursor('grabbing', CURSOR_GRABBING_PARAMS);
+ registerHaxeUICursor('hourglass', CURSOR_HOURGLASS_PARAMS);
+ registerHaxeUICursor('pointer', CURSOR_POINTER_PARAMS);
+ registerHaxeUICursor('text', CURSOR_TEXT_PARAMS);
+ registerHaxeUICursor('text-vertical', CURSOR_TEXT_VERTICAL_PARAMS);
+ registerHaxeUICursor('zoom-in', CURSOR_ZOOM_IN_PARAMS);
+ registerHaxeUICursor('zoom-out', CURSOR_ZOOM_OUT_PARAMS);
+ registerHaxeUICursor('crosshair', CURSOR_CROSSHAIR_PARAMS);
+ registerHaxeUICursor('cell', CURSOR_CELL_PARAMS);
+ }
+
+ public static function registerHaxeUICursor(id:String, params:CursorParams):Void
+ {
+ CursorHelper.registerCursor(id, params.graphic, params.scale, params.offsetX, params.offsetY);
+ }
}
// https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
diff --git a/source/funkin/ui/MusicBeatState.hx b/source/funkin/ui/MusicBeatState.hx
index 6d592f438..328a26428 100644
--- a/source/funkin/ui/MusicBeatState.hx
+++ b/source/funkin/ui/MusicBeatState.hx
@@ -57,27 +57,45 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
Conductor.stepHit.remove(this.stepHit);
}
- override function update(elapsed:Float)
+ function handleControls():Void
{
- super.update(elapsed);
+ var isHaxeUIFocused:Bool = haxe.ui.focus.FocusManager.instance?.focus != null;
- // Rebindable volume keys.
- if (controls.VOLUME_MUTE) FlxG.sound.toggleMuted();
- else if (controls.VOLUME_UP) FlxG.sound.changeVolume(0.1);
- else if (controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1);
+ if (!isHaxeUIFocused)
+ {
+ // Rebindable volume keys.
+ if (controls.VOLUME_MUTE) FlxG.sound.toggleMuted();
+ else if (controls.VOLUME_UP) FlxG.sound.changeVolume(0.1);
+ else if (controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1);
+ }
+ }
+ function handleFunctionControls():Void
+ {
// Emergency exit button.
if (FlxG.keys.justPressed.F4) FlxG.switchState(new MainMenuState());
// This can now be used in EVERY STATE YAY!
if (FlxG.keys.justPressed.F5) debug_refreshModules();
+ }
+ function handleQuickWatch():Void
+ {
// Display Conductor info in the watch window.
FlxG.watch.addQuick("songPosition", Conductor.songPosition);
FlxG.watch.addQuick("bpm", Conductor.bpm);
FlxG.watch.addQuick("currentMeasureTime", Conductor.currentBeatTime);
FlxG.watch.addQuick("currentBeatTime", Conductor.currentBeatTime);
FlxG.watch.addQuick("currentStepTime", Conductor.currentStepTime);
+ }
+
+ override function update(elapsed:Float)
+ {
+ super.update(elapsed);
+
+ handleControls();
+ handleFunctionControls();
+ handleQuickWatch();
dispatchEvent(new UpdateScriptEvent(elapsed));
}
diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx
index aedabc956..382bab592 100644
--- a/source/funkin/ui/debug/charting/ChartEditorState.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorState.hx
@@ -91,6 +91,7 @@ import haxe.ui.core.Component;
import haxe.ui.core.Screen;
import haxe.ui.events.DragEvent;
import haxe.ui.events.UIEvent;
+import haxe.ui.focus.FocusManager;
import haxe.ui.notifications.NotificationManager;
import haxe.ui.notifications.NotificationType;
import openfl.display.BitmapData;
@@ -548,22 +549,14 @@ class ChartEditorState extends HaxeUIState
// HaxeUI
/**
- * Whether the user's mouse cursor is hovering over a SOLID component of the HaxeUI.
- * If so, ignore mouse events underneath as well as certain key events.
+ * Whether the user is focused on an input in the Haxe UI, and inputs are being fed into it.
+ * If the user clicks off the input, focus will leave.
*/
- var isCursorOverHaxeUI(get, never):Bool;
+ var isHaxeUIFocused(get, never):Bool;
- function get_isCursorOverHaxeUI():Bool
+ function get_isHaxeUIFocused():Bool
{
- return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
- }
-
- var isCursorOverHaxeUIButton(get, never):Bool;
-
- function get_isCursorOverHaxeUIButton():Bool
- {
- return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY, haxe.ui.components.Button)
- || Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY, haxe.ui.components.Link);
+ return FocusManager.instance.focus != null;
}
/**
@@ -2058,21 +2051,6 @@ class ChartEditorState extends HaxeUIState
#end
}
- function handleQuickWatch():Void
- {
- FlxG.watch.addQuick('scrollPosInPixels', scrollPositionInPixels);
- FlxG.watch.addQuick('playheadPosInPixels', playheadPositionInPixels);
-
- // Add a debug value which displays the current size of the note pool.
- // The pool will grow as more notes need to be rendered at once.
- // If this gets too big, something needs to be optimized somewhere! -Eric
- if (renderedNotes != null && renderedNotes.members != null) FlxG.watch.addQuick("tapNotesRendered", renderedNotes.members.length);
- if (renderedHoldNotes != null && renderedHoldNotes.members != null) FlxG.watch.addQuick("holdNotesRendered", renderedHoldNotes.members.length);
- if (renderedEvents != null && renderedEvents.members != null) FlxG.watch.addQuick("eventsRendered", renderedEvents.members.length);
- if (currentNoteSelection != null) FlxG.watch.addQuick("notesSelected", currentNoteSelection.length);
- if (currentEventSelection != null) FlxG.watch.addQuick("eventsSelected", currentEventSelection.length);
- }
-
/**
* Beat hit while the song is playing.
*/
@@ -2557,8 +2535,8 @@ class ChartEditorState extends HaxeUIState
*/
function handleScrollKeybinds():Void
{
- // Don't scroll when the cursor is over the UI, unless a playbar button (the << >> ones) is pressed.
- if (isCursorOverHaxeUI && playbarButtonPressed == null) return;
+ // Don't scroll when the user is interacting with the UI, unless a playbar button (the << >> ones) is pressed.
+ if (isHaxeUIFocused && 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.
@@ -2757,7 +2735,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 = !isCursorOverHaxeUI
+ var shouldHandleCursor:Bool = !isHaxeUIFocused
|| (selectionBoxStartPos != null)
|| (dragTargetNote != null || dragTargetEvent != null);
var eventColumn:Int = (STRUMLINE_SIZE * 2 + 1) - 1;
@@ -3317,14 +3295,14 @@ class ChartEditorState extends HaxeUIState
{
// Create an event and place it in the chart.
// TODO: Figure out configuring event data.
- var newEventData:SongEventData = new SongEventData(cursorSnappedMs, selectedEventKind, selectedEventData);
+ var newEventData:SongEventData = new SongEventData(cursorSnappedMs, selectedEventKind, selectedEventData.clone());
performCommand(new AddEventsCommand([newEventData], FlxG.keys.pressed.CONTROL));
}
else
{
// Create a note and place it in the chart.
- var newNoteData:SongNoteData = new SongNoteData(cursorSnappedMs, cursorColumn, 0, selectedNoteKind);
+ var newNoteData:SongNoteData = new SongNoteData(cursorSnappedMs, cursorColumn, 0, selectedNoteKind.clone());
performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL));
@@ -3989,7 +3967,7 @@ class ChartEditorState extends HaxeUIState
*/
function handleTestKeybinds():Void
{
- if (!isHaxeUIDialogOpen && !isCursorOverHaxeUI && FlxG.keys.justPressed.ENTER)
+ if (!isHaxeUIDialogOpen && !isHaxeUIFocused && FlxG.keys.justPressed.ENTER)
{
var minimal = FlxG.keys.pressed.SHIFT;
this.hideAllToolboxes();
@@ -4006,6 +3984,20 @@ class ChartEditorState extends HaxeUIState
if (FlxG.keys.justPressed.F1) this.openUserGuideDialog();
}
+ override function handleQuickWatch():Void
+ {
+ super.handleQuickWatch();
+
+ FlxG.watch.addQuick('scrollPosInPixels', scrollPositionInPixels);
+ FlxG.watch.addQuick('playheadPosInPixels', playheadPositionInPixels);
+
+ FlxG.watch.addQuick("tapNotesRendered", renderedNotes.members.length);
+ FlxG.watch.addQuick("holdNotesRendered", renderedHoldNotes.members.length);
+ FlxG.watch.addQuick("eventsRendered", renderedEvents.members.length);
+ FlxG.watch.addQuick("notesSelected", currentNoteSelection.length);
+ FlxG.watch.addQuick("eventsSelected", currentEventSelection.length);
+ }
+
/**
* PLAYTEST FUNCTIONS
*/
diff --git a/source/funkin/ui/debug/charting/components/ChartEditorEventSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorEventSprite.hx
index 2bd719df2..4c9d91407 100644
--- a/source/funkin/ui/debug/charting/components/ChartEditorEventSprite.hx
+++ b/source/funkin/ui/debug/charting/components/ChartEditorEventSprite.hx
@@ -134,21 +134,25 @@ class ChartEditorEventSprite extends FlxSprite
function set_eventData(value:Null):Null
{
- this.eventData = value;
-
- if (this.eventData == null)
+ if (value == null)
{
+ this.eventData = null;
// Disown parent. MAKE SURE TO REVIVE BEFORE REUSING
this.kill();
+ this.visible = false;
+ return null;
+ }
+ else
+ {
+ this.visible = true;
+ // Only play the animation if the event type has changed.
+ // if (this.eventData == null || this.eventData.event != value.event)
+ playAnimation(value.event);
+ this.eventData = value;
+ // Update the position to match the note data.
+ updateEventPosition();
return this.eventData;
}
-
- this.visible = true;
- playAnimation(this.eventData.event);
- // Update the position to match the note data.
- updateEventPosition();
-
- return this.eventData;
}
public function updateEventPosition(?origin:FlxObject)
diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx
index dba513c32..f5cbccff6 100644
--- a/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx
+++ b/source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx
@@ -15,8 +15,6 @@ import funkin.play.character.CharacterData.CharacterDataParser;
import funkin.play.song.Song;
import funkin.play.stage.StageData;
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
-import funkin.ui.haxeui.components.FunkinDropDown;
-import funkin.ui.haxeui.components.FunkinLink;
import funkin.util.Constants;
import funkin.util.FileUtil;
import funkin.util.SerializerUtil;
@@ -160,7 +158,7 @@ class ChartEditorDialogHandler
continue;
}
- var linkTemplateSong:Link = new FunkinLink();
+ var linkTemplateSong:Link = new Link();
linkTemplateSong.text = songName;
linkTemplateSong.onClick = function(_event) {
dialog.hideDialog(DialogButton.CANCEL);
@@ -687,7 +685,7 @@ class ChartEditorDialogHandler
var startingValueStage = ChartEditorDropdowns.populateDropdownWithStages(inputStage, newSongMetadata.playData.stage);
inputStage.value = startingValueStage;
- var inputNoteStyle:Null = dialog.findComponent('inputNoteStyle', FunkinDropDown);
+ var inputNoteStyle:Null = dialog.findComponent('inputNoteStyle', DropDown);
if (inputNoteStyle == null) throw 'Could not locate inputNoteStyle DropDown in Song Metadata dialog';
inputNoteStyle.onChange = function(event:UIEvent) {
if (event.data.id == null) return;
@@ -696,7 +694,7 @@ class ChartEditorDialogHandler
var startingValueNoteStyle = ChartEditorDropdowns.populateDropdownWithNoteStyles(inputNoteStyle, newSongMetadata.playData.noteStyle);
inputNoteStyle.value = startingValueNoteStyle;
- var inputCharacterPlayer:Null = dialog.findComponent('inputCharacterPlayer', FunkinDropDown);
+ var inputCharacterPlayer:Null = dialog.findComponent('inputCharacterPlayer', DropDown);
if (inputCharacterPlayer == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputCharacterPlayer component.';
inputCharacterPlayer.onChange = function(event:UIEvent) {
if (event.data?.id == null) return;
@@ -706,7 +704,7 @@ class ChartEditorDialogHandler
newSongMetadata.playData.characters.player);
inputCharacterPlayer.value = startingValuePlayer;
- var inputCharacterOpponent:Null = dialog.findComponent('inputCharacterOpponent', FunkinDropDown);
+ var inputCharacterOpponent:Null = dialog.findComponent('inputCharacterOpponent', DropDown);
if (inputCharacterOpponent == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputCharacterOpponent component.';
inputCharacterOpponent.onChange = function(event:UIEvent) {
if (event.data?.id == null) return;
@@ -716,7 +714,7 @@ class ChartEditorDialogHandler
newSongMetadata.playData.characters.opponent);
inputCharacterOpponent.value = startingValueOpponent;
- var inputCharacterGirlfriend:Null = dialog.findComponent('inputCharacterGirlfriend', FunkinDropDown);
+ var inputCharacterGirlfriend:Null = dialog.findComponent('inputCharacterGirlfriend', DropDown);
if (inputCharacterGirlfriend == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputCharacterGirlfriend component.';
inputCharacterGirlfriend.onChange = function(event:UIEvent) {
if (event.data?.id == null) return;
diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx
index f0c634666..a43dd2989 100644
--- a/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx
+++ b/source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx
@@ -1,5 +1,14 @@
package funkin.ui.debug.charting.handlers;
+import funkin.play.stage.StageData.StageDataParser;
+import funkin.play.stage.StageData;
+import funkin.play.character.CharacterData;
+import funkin.play.character.CharacterData.CharacterDataParser;
+import haxe.ui.components.HorizontalSlider;
+import haxe.ui.containers.TreeView;
+import haxe.ui.containers.TreeViewNode;
+import funkin.play.character.BaseCharacter.CharacterType;
+import funkin.play.event.SongEvent;
import funkin.data.event.SongEventData;
import funkin.data.song.SongData.SongTimeChange;
import funkin.play.character.BaseCharacter.CharacterType;
@@ -11,7 +20,6 @@ import funkin.play.stage.StageData;
import funkin.play.stage.StageData.StageDataParser;
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
import funkin.ui.haxeui.components.CharacterPlayer;
-import funkin.ui.haxeui.components.FunkinDropDown;
import funkin.util.FileUtil;
import haxe.ui.components.Button;
import haxe.ui.components.CheckBox;
@@ -292,6 +300,8 @@ class ChartEditorToolboxHandler
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event type changed: $eventType');
+ state.selectedEventKind = eventType;
+
var schema:SongEventSchema = SongEventParser.getEventSchema(eventType);
if (schema == null)
@@ -302,6 +312,7 @@ class ChartEditorToolboxHandler
buildEventDataFormFromSchema(state, toolboxEventsDataGrid, schema);
}
+ toolboxEventsEventKind.value = state.selectedEventKind;
return toolbox;
}
@@ -325,6 +336,7 @@ class ChartEditorToolboxHandler
// Add a label.
var label:Label = new Label();
label.text = field.title;
+ label.verticalAlign = "center";
target.addComponent(label);
var input:Component;
@@ -342,8 +354,8 @@ class ChartEditorToolboxHandler
var numberStepper:NumberStepper = new NumberStepper();
numberStepper.id = field.name;
numberStepper.step = field.step ?? 0.1;
- numberStepper.min = field.min ?? 0.0;
- numberStepper.max = field.max ?? 1.0;
+ if (field.min != null) numberStepper.min = field.min;
+ if (field.max != null) numberStepper.max = field.max;
if (field.defaultValue != null) numberStepper.value = field.defaultValue;
input = numberStepper;
case BOOL:
@@ -354,6 +366,7 @@ class ChartEditorToolboxHandler
case ENUM:
var dropDown:DropDown = new DropDown();
dropDown.id = field.name;
+ dropDown.width = 200.0;
dropDown.dataSource = new ArrayDataSource();
if (field.keys == null) throw 'Field "${field.name}" is of Enum type but has no keys.';
@@ -362,7 +375,7 @@ class ChartEditorToolboxHandler
for (optionName in field.keys.keys())
{
- var optionValue:Null = field.keys.get(optionName);
+ var optionValue:Null = field.keys.get(optionName);
trace('$optionName : $optionValue');
dropDown.dataSource.add({value: optionValue, text: optionName});
}
@@ -384,11 +397,21 @@ class ChartEditorToolboxHandler
target.addComponent(input);
input.onChange = function(event:UIEvent) {
- trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${event.target.value}');
+ var value = event.target.value;
+ if (field.type == ENUM)
+ {
+ value = event.target.value.value;
+ }
+ trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${value}');
- if (event.target.value == null) state.selectedEventData.remove(event.target.id);
+ if (value == null)
+ {
+ state.selectedEventData.remove(event.target.id);
+ }
else
- state.selectedEventData.set(event.target.id, event.target.value);
+ {
+ state.selectedEventData.set(event.target.id, value);
+ }
}
}
}
@@ -528,7 +551,7 @@ class ChartEditorToolboxHandler
};
inputSongArtist.value = state.currentSongMetadata.artist;
- var inputStage:Null = toolbox.findComponent('inputStage', FunkinDropDown);
+ var inputStage:Null = toolbox.findComponent('inputStage', DropDown);
if (inputStage == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputStage component.';
inputStage.onChange = function(event:UIEvent) {
var valid:Bool = event.data != null && event.data.id != null;
@@ -541,7 +564,7 @@ class ChartEditorToolboxHandler
var startingValueStage = ChartEditorDropdowns.populateDropdownWithStages(inputStage, state.currentSongMetadata.playData.stage);
inputStage.value = startingValueStage;
- var inputNoteStyle:Null = toolbox.findComponent('inputNoteStyle', FunkinDropDown);
+ var inputNoteStyle:Null = toolbox.findComponent('inputNoteStyle', DropDown);
if (inputNoteStyle == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputNoteStyle component.';
inputNoteStyle.onChange = function(event:UIEvent) {
if (event.data?.id == null) return;
@@ -551,7 +574,7 @@ class ChartEditorToolboxHandler
// By using this flag, we prevent the dropdown value from changing while it is being populated.
- var inputCharacterPlayer:Null = toolbox.findComponent('inputCharacterPlayer', FunkinDropDown);
+ var inputCharacterPlayer:Null = toolbox.findComponent('inputCharacterPlayer', DropDown);
if (inputCharacterPlayer == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputCharacterPlayer component.';
inputCharacterPlayer.onChange = function(event:UIEvent) {
if (event.data?.id == null) return;
@@ -561,7 +584,7 @@ class ChartEditorToolboxHandler
state.currentSongMetadata.playData.characters.player);
inputCharacterPlayer.value = startingValuePlayer;
- var inputCharacterOpponent:Null = toolbox.findComponent('inputCharacterOpponent', FunkinDropDown);
+ var inputCharacterOpponent:Null = toolbox.findComponent('inputCharacterOpponent', DropDown);
if (inputCharacterOpponent == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputCharacterOpponent component.';
inputCharacterOpponent.onChange = function(event:UIEvent) {
if (event.data?.id == null) return;
@@ -571,7 +594,7 @@ class ChartEditorToolboxHandler
state.currentSongMetadata.playData.characters.opponent);
inputCharacterOpponent.value = startingValueOpponent;
- var inputCharacterGirlfriend:Null = toolbox.findComponent('inputCharacterGirlfriend', FunkinDropDown);
+ var inputCharacterGirlfriend:Null = toolbox.findComponent('inputCharacterGirlfriend', DropDown);
if (inputCharacterGirlfriend == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputCharacterGirlfriend component.';
inputCharacterGirlfriend.onChange = function(event:UIEvent) {
if (event.data?.id == null) return;
diff --git a/source/funkin/ui/haxeui/components/FunkinButton.hx b/source/funkin/ui/haxeui/components/FunkinButton.hx
deleted file mode 100644
index 45987b9ec..000000000
--- a/source/funkin/ui/haxeui/components/FunkinButton.hx
+++ /dev/null
@@ -1,30 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-import haxe.ui.components.Button;
-
-/**
- * A HaxeUI button which:
- * - Changes the current cursor when hovered over.
- */
-class FunkinButton extends Button
-{
- public function new()
- {
- super();
-
- this.onMouseOver = handleMouseOver;
- this.onMouseOut = handleMouseOut;
- }
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Pointer;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/ui/haxeui/components/FunkinClickLabel.hx b/source/funkin/ui/haxeui/components/FunkinClickLabel.hx
deleted file mode 100644
index 77c9dbc0f..000000000
--- a/source/funkin/ui/haxeui/components/FunkinClickLabel.hx
+++ /dev/null
@@ -1,30 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import haxe.ui.components.Label;
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-
-/**
- * A HaxeUI label which:
- * - Changes the current cursor when hovered over (assume an onClick handler will be added!).
- */
-class FunkinClickLabel extends Label
-{
- public function new()
- {
- super();
-
- this.onMouseOver = handleMouseOver;
- this.onMouseOut = handleMouseOut;
- }
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Pointer;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/ui/haxeui/components/FunkinDropDown.hx b/source/funkin/ui/haxeui/components/FunkinDropDown.hx
deleted file mode 100644
index ad396856c..000000000
--- a/source/funkin/ui/haxeui/components/FunkinDropDown.hx
+++ /dev/null
@@ -1,30 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import haxe.ui.components.DropDown;
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-
-/**
- * A HaxeUI dropdown which:
- * - Changes the current cursor when hovered over.
- */
-class FunkinDropDown extends DropDown
-{
- public function new()
- {
- super();
-
- this.onMouseOver = handleMouseOver;
- this.onMouseOut = handleMouseOut;
- }
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Pointer;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/ui/haxeui/components/FunkinHorizontalSlider.hx b/source/funkin/ui/haxeui/components/FunkinHorizontalSlider.hx
deleted file mode 100644
index baf42aada..000000000
--- a/source/funkin/ui/haxeui/components/FunkinHorizontalSlider.hx
+++ /dev/null
@@ -1,30 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import haxe.ui.components.HorizontalSlider;
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-
-/**
- * A HaxeUI horizontal slider which:
- * - Changes the current cursor when hovered over.
- */
-class FunkinHorizontalSlider extends HorizontalSlider
-{
- public function new()
- {
- super();
-
- this.onMouseOver = handleMouseOver;
- this.onMouseOut = handleMouseOut;
- }
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Pointer;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/ui/haxeui/components/FunkinLink.hx b/source/funkin/ui/haxeui/components/FunkinLink.hx
deleted file mode 100644
index 74eb6e7c4..000000000
--- a/source/funkin/ui/haxeui/components/FunkinLink.hx
+++ /dev/null
@@ -1,30 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-import haxe.ui.components.Link;
-
-/**
- * A HaxeUI link which:
- * - Changes the current cursor when hovered over.
- */
-class FunkinLink extends Link
-{
- public function new()
- {
- super();
-
- this.onMouseOver = handleMouseOver;
- this.onMouseOut = handleMouseOut;
- }
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Pointer;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/ui/haxeui/components/FunkinMenuBar.hx b/source/funkin/ui/haxeui/components/FunkinMenuBar.hx
deleted file mode 100644
index 393372d74..000000000
--- a/source/funkin/ui/haxeui/components/FunkinMenuBar.hx
+++ /dev/null
@@ -1,32 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-import haxe.ui.containers.menus.MenuBar;
-import haxe.ui.core.CompositeBuilder;
-
-/**
- * A HaxeUI menu bar which:
- * - Changes the current cursor when each button is hovered over.
- */
-class FunkinMenuBar extends MenuBar
-{
- public function new()
- {
- super();
-
- registerListeners();
- }
-
- private function registerListeners():Void {}
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Pointer;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/ui/haxeui/components/FunkinMenuCheckBox.hx b/source/funkin/ui/haxeui/components/FunkinMenuCheckBox.hx
deleted file mode 100644
index 263277c6f..000000000
--- a/source/funkin/ui/haxeui/components/FunkinMenuCheckBox.hx
+++ /dev/null
@@ -1,30 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-import haxe.ui.containers.menus.MenuCheckBox;
-
-/**
- * A HaxeUI menu checkbox which:
- * - Changes the current cursor when hovered over.
- */
-class FunkinMenuCheckBox extends MenuCheckBox
-{
- public function new()
- {
- super();
-
- this.onMouseOver = handleMouseOver;
- this.onMouseOut = handleMouseOut;
- }
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Pointer;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/ui/haxeui/components/FunkinMenuItem.hx b/source/funkin/ui/haxeui/components/FunkinMenuItem.hx
deleted file mode 100644
index 2eb7db729..000000000
--- a/source/funkin/ui/haxeui/components/FunkinMenuItem.hx
+++ /dev/null
@@ -1,30 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-import haxe.ui.containers.menus.MenuItem;
-
-/**
- * A HaxeUI menu item which:
- * - Changes the current cursor when hovered over.
- */
-class FunkinMenuItem extends MenuItem
-{
- public function new()
- {
- super();
-
- this.onMouseOver = handleMouseOver;
- this.onMouseOut = handleMouseOut;
- }
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Pointer;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/ui/haxeui/components/FunkinMenuOptionBox.hx b/source/funkin/ui/haxeui/components/FunkinMenuOptionBox.hx
deleted file mode 100644
index d9985eede..000000000
--- a/source/funkin/ui/haxeui/components/FunkinMenuOptionBox.hx
+++ /dev/null
@@ -1,30 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import haxe.ui.containers.menus.MenuOptionBox;
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-
-/**
- * A HaxeUI menu option box which:
- * - Changes the current cursor when hovered over.
- */
-class FunkinMenuOptionBox extends MenuOptionBox
-{
- public function new()
- {
- super();
-
- this.onMouseOver = handleMouseOver;
- this.onMouseOut = handleMouseOut;
- }
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Pointer;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/ui/haxeui/components/FunkinNumberStepper.hx b/source/funkin/ui/haxeui/components/FunkinNumberStepper.hx
deleted file mode 100644
index db8d4fb7f..000000000
--- a/source/funkin/ui/haxeui/components/FunkinNumberStepper.hx
+++ /dev/null
@@ -1,30 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import haxe.ui.components.NumberStepper;
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-
-/**
- * A HaxeUI number stepper which:
- * - Changes the current cursor when hovered over.
- */
-class FunkinNumberStepper extends NumberStepper
-{
- public function new()
- {
- super();
-
- this.onMouseOver = handleMouseOver;
- this.onMouseOut = handleMouseOut;
- }
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Pointer;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/ui/haxeui/components/FunkinTextField.hx b/source/funkin/ui/haxeui/components/FunkinTextField.hx
deleted file mode 100644
index 3ecab0684..000000000
--- a/source/funkin/ui/haxeui/components/FunkinTextField.hx
+++ /dev/null
@@ -1,30 +0,0 @@
-package funkin.ui.haxeui.components;
-
-import haxe.ui.components.TextField;
-import funkin.input.Cursor;
-import haxe.ui.events.MouseEvent;
-
-/**
- * A HaxeUI text field which:
- * - Changes the current cursor when hovered over.
- */
-class FunkinTextField extends TextField
-{
- public function new()
- {
- super();
-
- this.onMouseOver = handleMouseOver;
- this.onMouseOut = handleMouseOut;
- }
-
- private function handleMouseOver(event:MouseEvent)
- {
- Cursor.cursorMode = Text;
- }
-
- private function handleMouseOut(event:MouseEvent)
- {
- Cursor.cursorMode = Default;
- }
-}
diff --git a/source/funkin/util/tools/DynamicTools.hx b/source/funkin/util/tools/DynamicTools.hx
new file mode 100644
index 000000000..47501ea22
--- /dev/null
+++ b/source/funkin/util/tools/DynamicTools.hx
@@ -0,0 +1,14 @@
+package funkin.util.tools;
+
+class DynamicTools
+{
+ /**
+ * Creates a full clone of the input `Dynamic`. Only guaranteed to work on anonymous structures.
+ * @param input The `Dynamic` to clone.
+ * @return A clone of the input `Dynamic`.
+ */
+ public static function clone(input:Dynamic):Dynamic
+ {
+ return Reflect.copy(input);
+ }
+}