mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-23 16:17:53 -05:00
Merge remote-tracking branch 'origin/rewrite/master' into feature/chart-waveform
This commit is contained in:
commit
b740fbf028
15 changed files with 645 additions and 297 deletions
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit 3c8ac202bbb93bf84c7dcd0697a9d7121d3c5283
|
Subproject commit 7d59681870d2b73417a9f5b553720e8b7120bbde
|
4
hmm.json
4
hmm.json
|
@ -49,14 +49,14 @@
|
||||||
"name": "haxeui-core",
|
"name": "haxeui-core",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "5d4ac180f85b39e72624f4b8d17925d91ebe4278",
|
"ref": "032192e849cdb7d1070c0a3241c58ee555ffaccc",
|
||||||
"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": "89a4cf621e5c204922f7a12fbde5d1d84f8b47f5",
|
"ref": "d90758b229d05206400df867d333c79d9fdbd478",
|
||||||
"url": "https://github.com/haxeui/haxeui-flixel"
|
"url": "https://github.com/haxeui/haxeui-flixel"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -280,6 +280,36 @@ class CharacterDataParser
|
||||||
return characterCache.keys().array();
|
return characterCache.keys().array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Hardcode this.
|
||||||
|
*/
|
||||||
|
public static function getCharPixelIconAsset(char:String):String
|
||||||
|
{
|
||||||
|
var icon:String = char;
|
||||||
|
|
||||||
|
switch (icon)
|
||||||
|
{
|
||||||
|
case "bf-christmas" | "bf-car" | "bf-pixel" | "bf-holding-gf":
|
||||||
|
icon = "bf";
|
||||||
|
case "monster-christmas":
|
||||||
|
icon = "monster";
|
||||||
|
case "mom" | "mom-car":
|
||||||
|
icon = "mommy";
|
||||||
|
case "pico-blazin" | "pico-playable" | "pico-speaker":
|
||||||
|
icon = "pico";
|
||||||
|
case "gf-christmas" | "gf-car" | "gf-pixel" | "gf-tankmen":
|
||||||
|
icon = "gf";
|
||||||
|
case "dad":
|
||||||
|
icon = "daddy";
|
||||||
|
case "darnell-blazin":
|
||||||
|
icon = "darnell";
|
||||||
|
case "senpai-angry":
|
||||||
|
icon = "senpai";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Paths.image("freeplay/icons/" + icon + "pixel");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the character data cache.
|
* Clears the character data cache.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package funkin.ui.debug.charting;
|
package funkin.ui.debug.charting;
|
||||||
|
|
||||||
import funkin.util.logging.CrashHandler;
|
import funkin.util.logging.CrashHandler;
|
||||||
|
import haxe.ui.containers.HBox;
|
||||||
|
import haxe.ui.containers.Grid;
|
||||||
|
import haxe.ui.containers.ScrollView;
|
||||||
import haxe.ui.containers.menus.MenuBar;
|
import haxe.ui.containers.menus.MenuBar;
|
||||||
import flixel.addons.display.FlxSliceSprite;
|
import flixel.addons.display.FlxSliceSprite;
|
||||||
import flixel.addons.display.FlxTiledSprite;
|
import flixel.addons.display.FlxTiledSprite;
|
||||||
|
@ -106,6 +109,8 @@ import haxe.ui.containers.menus.MenuItem;
|
||||||
import haxe.ui.containers.menus.MenuCheckBox;
|
import haxe.ui.containers.menus.MenuCheckBox;
|
||||||
import haxe.ui.containers.TreeView;
|
import haxe.ui.containers.TreeView;
|
||||||
import haxe.ui.containers.TreeViewNode;
|
import haxe.ui.containers.TreeViewNode;
|
||||||
|
import haxe.ui.components.Image;
|
||||||
|
import funkin.ui.debug.charting.toolboxes.ChartEditorBaseToolbox;
|
||||||
import haxe.ui.core.Component;
|
import haxe.ui.core.Component;
|
||||||
import haxe.ui.core.Screen;
|
import haxe.ui.core.Screen;
|
||||||
import haxe.ui.events.DragEvent;
|
import haxe.ui.events.DragEvent;
|
||||||
|
@ -117,6 +122,7 @@ import openfl.display.BitmapData;
|
||||||
import funkin.audio.visualize.PolygonSpectogram;
|
import funkin.audio.visualize.PolygonSpectogram;
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import funkin.audio.visualize.PolygonVisGroup;
|
import funkin.audio.visualize.PolygonVisGroup;
|
||||||
|
import flixel.input.mouse.FlxMouseEvent;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
|
|
||||||
using Lambda;
|
using Lambda;
|
||||||
|
@ -142,6 +148,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
public static final CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/notedata');
|
public static final CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/notedata');
|
||||||
|
|
||||||
public static final CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/eventdata');
|
public static final CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/eventdata');
|
||||||
|
public static final CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT:String = Paths.ui('chart-editor/toolbox/playtest-properties');
|
||||||
public static final CHART_EDITOR_TOOLBOX_METADATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/metadata');
|
public static final CHART_EDITOR_TOOLBOX_METADATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/metadata');
|
||||||
public static final CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT:String = Paths.ui('chart-editor/toolbox/difficulty');
|
public static final CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT:String = Paths.ui('chart-editor/toolbox/difficulty');
|
||||||
public static final CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT:String = Paths.ui('chart-editor/toolbox/player-preview');
|
public static final CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT:String = Paths.ui('chart-editor/toolbox/player-preview');
|
||||||
|
@ -532,6 +539,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
*/
|
*/
|
||||||
var playtestStartTime:Bool = false;
|
var playtestStartTime:Bool = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, playtesting a chart will let you "gameover" / die when you lose ur health!
|
||||||
|
*/
|
||||||
|
var playtestPracticeMode:Bool = false;
|
||||||
|
|
||||||
// Visuals
|
// Visuals
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2336,6 +2348,21 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
if (!Preferences.debugDisplay) menubar.paddingLeft = null;
|
if (!Preferences.debugDisplay) menubar.paddingLeft = null;
|
||||||
|
|
||||||
this.setupNotifications();
|
this.setupNotifications();
|
||||||
|
|
||||||
|
// Setup character dropdowns.
|
||||||
|
FlxMouseEvent.add(healthIconDad, function(_) {
|
||||||
|
if (!isCursorOverHaxeUI)
|
||||||
|
{
|
||||||
|
this.openCharacterDropdown(CharacterType.DAD, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
FlxMouseEvent.add(healthIconBF, function(_) {
|
||||||
|
if (!isCursorOverHaxeUI)
|
||||||
|
{
|
||||||
|
this.openCharacterDropdown(CharacterType.BF, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2376,13 +2403,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Conductor.currentTimeChange.bpm += 1;
|
Conductor.currentTimeChange.bpm += 1;
|
||||||
refreshMetadataToolbox();
|
this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playbarBPM.onRightClick = _ -> {
|
playbarBPM.onRightClick = _ -> {
|
||||||
Conductor.currentTimeChange.bpm -= 1;
|
Conductor.currentTimeChange.bpm -= 1;
|
||||||
refreshMetadataToolbox();
|
this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add functionality to the menu items.
|
// Add functionality to the menu items.
|
||||||
|
@ -2507,9 +2534,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
menubarItemDifficultyUp.onClick = _ -> incrementDifficulty(1);
|
menubarItemDifficultyUp.onClick = _ -> incrementDifficulty(1);
|
||||||
menubarItemDifficultyDown.onClick = _ -> incrementDifficulty(-1);
|
menubarItemDifficultyDown.onClick = _ -> incrementDifficulty(-1);
|
||||||
|
|
||||||
menubarItemPlaytestStartTime.onChange = event -> playtestStartTime = event.value;
|
|
||||||
menubarItemPlaytestStartTime.selected = playtestStartTime;
|
|
||||||
|
|
||||||
menuBarItemThemeLight.onChange = function(event:UIEvent) {
|
menuBarItemThemeLight.onChange = function(event:UIEvent) {
|
||||||
if (event.target.value) currentTheme = ChartEditorTheme.Light;
|
if (event.target.value) currentTheme = ChartEditorTheme.Light;
|
||||||
};
|
};
|
||||||
|
@ -2576,6 +2600,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
menubarItemToggleToolboxMetadata.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT, event.value);
|
menubarItemToggleToolboxMetadata.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT, event.value);
|
||||||
menubarItemToggleToolboxNotes.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT, event.value);
|
menubarItemToggleToolboxNotes.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT, event.value);
|
||||||
menubarItemToggleToolboxEvents.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT, event.value);
|
menubarItemToggleToolboxEvents.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT, event.value);
|
||||||
|
menubarItemToggleToolboxPlaytestProperties.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT, event.value);
|
||||||
menubarItemToggleToolboxPlayerPreview.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT, event.value);
|
menubarItemToggleToolboxPlayerPreview.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT, event.value);
|
||||||
menubarItemToggleToolboxOpponentPreview.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT, event.value);
|
menubarItemToggleToolboxOpponentPreview.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT, event.value);
|
||||||
|
|
||||||
|
@ -2650,7 +2675,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
* Open the backups folder in the file explorer.
|
* Open the backups folder in the file explorer.
|
||||||
* Don't call this on HTML5.
|
* Don't call this on HTML5.
|
||||||
*/
|
*/
|
||||||
function openBackupsFolder():Void
|
function openBackupsFolder(?_):Void
|
||||||
{
|
{
|
||||||
#if sys
|
#if sys
|
||||||
// TODO: Is there a way to open a folder and highlight a file in it?
|
// TODO: Is there a way to open a folder and highlight a file in it?
|
||||||
|
@ -3439,6 +3464,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
var overlapsSelection:Bool = FlxG.mouse.overlaps(renderedSelectionSquares);
|
var overlapsSelection:Bool = FlxG.mouse.overlaps(renderedSelectionSquares);
|
||||||
|
|
||||||
|
var overlapsHealthIcons:Bool = FlxG.mouse.overlaps(healthIconBF) || FlxG.mouse.overlaps(healthIconDad);
|
||||||
|
|
||||||
if (FlxG.mouse.justPressedMiddle)
|
if (FlxG.mouse.justPressedMiddle)
|
||||||
{
|
{
|
||||||
if (scrollAnchorScreenPos == null)
|
if (scrollAnchorScreenPos == null)
|
||||||
|
@ -3458,11 +3485,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
{
|
{
|
||||||
scrollAnchorScreenPos = null;
|
scrollAnchorScreenPos = null;
|
||||||
}
|
}
|
||||||
else if (gridPlayheadScrollArea != null && FlxG.mouse.overlaps(gridPlayheadScrollArea))
|
else if (gridPlayheadScrollArea != null && FlxG.mouse.overlaps(gridPlayheadScrollArea) && !isCursorOverHaxeUI)
|
||||||
{
|
{
|
||||||
gridPlayheadScrollAreaPressed = true;
|
gridPlayheadScrollAreaPressed = true;
|
||||||
}
|
}
|
||||||
else if (notePreview != null && FlxG.mouse.overlaps(notePreview))
|
else if (notePreview != null && FlxG.mouse.overlaps(notePreview) && !isCursorOverHaxeUI)
|
||||||
{
|
{
|
||||||
// Clicked note preview
|
// Clicked note preview
|
||||||
notePreviewScrollAreaStartPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
|
notePreviewScrollAreaStartPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
|
||||||
|
@ -3914,7 +3941,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
if (FlxG.mouse.justPressed)
|
if (FlxG.mouse.justPressed)
|
||||||
{
|
{
|
||||||
// Just clicked to place a note.
|
// Just clicked to place a note.
|
||||||
if (overlapsGrid && !overlapsSelectionBorder)
|
if (!isCursorOverHaxeUI && overlapsGrid && !overlapsSelectionBorder)
|
||||||
{
|
{
|
||||||
// We clicked on the grid without moving the mouse.
|
// We clicked on the grid without moving the mouse.
|
||||||
|
|
||||||
|
@ -4059,7 +4086,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
var isOrWillSelect = overlapsSelection || dragTargetNote != null || dragTargetEvent != null;
|
var isOrWillSelect = overlapsSelection || dragTargetNote != null || dragTargetEvent != null;
|
||||||
// Handle grid cursor.
|
// Handle grid cursor.
|
||||||
if (overlapsGrid && !isOrWillSelect && !overlapsSelectionBorder && !gridPlayheadScrollAreaPressed)
|
if (!isCursorOverHaxeUI && overlapsGrid && !isOrWillSelect && !overlapsSelectionBorder && !gridPlayheadScrollAreaPressed)
|
||||||
{
|
{
|
||||||
// Indicate that we can place a note here.
|
// Indicate that we can place a note here.
|
||||||
|
|
||||||
|
@ -4130,26 +4157,33 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (notePreview != null && FlxG.mouse.overlaps(notePreview))
|
if (!isCursorOverHaxeUI)
|
||||||
|
{
|
||||||
|
if (notePreview != null && FlxG.mouse.overlaps(notePreview))
|
||||||
|
{
|
||||||
|
targetCursorMode = Pointer;
|
||||||
|
}
|
||||||
|
else if (gridPlayheadScrollArea != null && FlxG.mouse.overlaps(gridPlayheadScrollArea))
|
||||||
|
{
|
||||||
|
targetCursorMode = Pointer;
|
||||||
|
}
|
||||||
|
else if (overlapsSelection)
|
||||||
|
{
|
||||||
|
targetCursorMode = Pointer;
|
||||||
|
}
|
||||||
|
else if (overlapsSelectionBorder)
|
||||||
|
{
|
||||||
|
targetCursorMode = Crosshair;
|
||||||
|
}
|
||||||
|
else if (overlapsGrid)
|
||||||
|
{
|
||||||
|
targetCursorMode = Cell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (overlapsHealthIcons)
|
||||||
{
|
{
|
||||||
targetCursorMode = Pointer;
|
targetCursorMode = Pointer;
|
||||||
}
|
}
|
||||||
else if (gridPlayheadScrollArea != null && FlxG.mouse.overlaps(gridPlayheadScrollArea))
|
|
||||||
{
|
|
||||||
targetCursorMode = Pointer;
|
|
||||||
}
|
|
||||||
else if (overlapsSelection)
|
|
||||||
{
|
|
||||||
targetCursorMode = Pointer;
|
|
||||||
}
|
|
||||||
else if (overlapsSelectionBorder)
|
|
||||||
{
|
|
||||||
targetCursorMode = Crosshair;
|
|
||||||
}
|
|
||||||
else if (overlapsGrid)
|
|
||||||
{
|
|
||||||
targetCursorMode = Cell;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4180,7 +4214,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
difficultySelectDirty = false;
|
difficultySelectDirty = false;
|
||||||
|
|
||||||
// Manage the Select Difficulty tree view.
|
// Manage the Select Difficulty tree view.
|
||||||
var difficultyToolbox:Null<CollapsibleDialog> = this.getToolbox(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT);
|
var difficultyToolbox:Null<CollapsibleDialog> = this.getToolbox_OLD(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT);
|
||||||
if (difficultyToolbox == null) return;
|
if (difficultyToolbox == null) return;
|
||||||
|
|
||||||
var treeView:Null<TreeView> = difficultyToolbox.findComponent('difficultyToolboxTree');
|
var treeView:Null<TreeView> = difficultyToolbox.findComponent('difficultyToolboxTree');
|
||||||
|
@ -4227,7 +4261,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
function handlePlayerPreviewToolbox():Void
|
function handlePlayerPreviewToolbox():Void
|
||||||
{
|
{
|
||||||
// Manage the Select Difficulty tree view.
|
// Manage the Select Difficulty tree view.
|
||||||
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolbox(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT);
|
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolbox_OLD(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT);
|
||||||
if (charPreviewToolbox == null) return;
|
if (charPreviewToolbox == null) return;
|
||||||
|
|
||||||
// TODO: Re-enable the player preview once we figure out the performance issues.
|
// TODO: Re-enable the player preview once we figure out the performance issues.
|
||||||
|
@ -4263,7 +4297,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
function handleOpponentPreviewToolbox():Void
|
function handleOpponentPreviewToolbox():Void
|
||||||
{
|
{
|
||||||
// Manage the Select Difficulty tree view.
|
// Manage the Select Difficulty tree view.
|
||||||
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolbox(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT);
|
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolbox_OLD(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT);
|
||||||
if (charPreviewToolbox == null) return;
|
if (charPreviewToolbox == null) return;
|
||||||
|
|
||||||
// TODO: Re-enable the player preview once we figure out the performance issues.
|
// TODO: Re-enable the player preview once we figure out the performance issues.
|
||||||
|
@ -4581,7 +4615,14 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE = Delete
|
// DELETE = Delete
|
||||||
if (FlxG.keys.justPressed.DELETE)
|
var delete:Bool = FlxG.keys.justPressed.DELETE;
|
||||||
|
|
||||||
|
// on macbooks, Delete == backspace
|
||||||
|
#if mac
|
||||||
|
delete = delete || FlxG.keys.justPressed.BACKSPACE;
|
||||||
|
#end
|
||||||
|
|
||||||
|
if (delete)
|
||||||
{
|
{
|
||||||
// Delete selected items.
|
// Delete selected items.
|
||||||
if (currentNoteSelection.length > 0 && currentEventSelection.length > 0)
|
if (currentNoteSelection.length > 0 && currentEventSelection.length > 0)
|
||||||
|
@ -4758,7 +4799,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
targetDifficulty: selectedDifficulty,
|
targetDifficulty: selectedDifficulty,
|
||||||
// TODO: Add this.
|
// TODO: Add this.
|
||||||
// targetCharacter: targetCharacter,
|
// targetCharacter: targetCharacter,
|
||||||
practiceMode: true,
|
practiceMode: playtestPracticeMode,
|
||||||
minimalMode: minimal,
|
minimalMode: minimal,
|
||||||
startTimestamp: startTimestamp,
|
startTimestamp: startTimestamp,
|
||||||
overrideMusic: true,
|
overrideMusic: true,
|
||||||
|
@ -5013,7 +5054,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
Conductor.mapTimeChanges(this.currentSongMetadata.timeChanges);
|
Conductor.mapTimeChanges(this.currentSongMetadata.timeChanges);
|
||||||
|
|
||||||
refreshDifficultyTreeSelection();
|
refreshDifficultyTreeSelection();
|
||||||
refreshMetadataToolbox();
|
this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -5022,7 +5063,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
selectedDifficulty = prevDifficulty;
|
selectedDifficulty = prevDifficulty;
|
||||||
|
|
||||||
refreshDifficultyTreeSelection();
|
refreshDifficultyTreeSelection();
|
||||||
refreshMetadataToolbox();
|
this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -5041,7 +5082,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
selectedDifficulty = nextDifficulty;
|
selectedDifficulty = nextDifficulty;
|
||||||
|
|
||||||
refreshDifficultyTreeSelection();
|
refreshDifficultyTreeSelection();
|
||||||
refreshMetadataToolbox();
|
this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -5050,7 +5091,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
selectedDifficulty = nextDifficulty;
|
selectedDifficulty = nextDifficulty;
|
||||||
|
|
||||||
refreshDifficultyTreeSelection();
|
refreshDifficultyTreeSelection();
|
||||||
refreshMetadataToolbox();
|
this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5163,7 +5204,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
if (treeView == null)
|
if (treeView == null)
|
||||||
{
|
{
|
||||||
// Manage the Select Difficulty tree view.
|
// Manage the Select Difficulty tree view.
|
||||||
var difficultyToolbox:Null<CollapsibleDialog> = this.getToolbox(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT);
|
var difficultyToolbox:Null<CollapsibleDialog> = this.getToolbox_OLD(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT);
|
||||||
if (difficultyToolbox == null) return;
|
if (difficultyToolbox == null) return;
|
||||||
|
|
||||||
treeView = difficultyToolbox.findComponent('difficultyToolboxTree');
|
treeView = difficultyToolbox.findComponent('difficultyToolboxTree');
|
||||||
|
@ -5183,7 +5224,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
{
|
{
|
||||||
if (treeView == null)
|
if (treeView == null)
|
||||||
{
|
{
|
||||||
var difficultyToolbox:Null<CollapsibleDialog> = this.getToolbox(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT);
|
var difficultyToolbox:Null<CollapsibleDialog> = this.getToolbox_OLD(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT);
|
||||||
if (difficultyToolbox == null) return null;
|
if (difficultyToolbox == null) return null;
|
||||||
|
|
||||||
treeView = difficultyToolbox.findComponent('difficultyToolboxTree');
|
treeView = difficultyToolbox.findComponent('difficultyToolboxTree');
|
||||||
|
@ -5227,8 +5268,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
trace('Changing difficulty to "$variation:$difficulty"');
|
trace('Changing difficulty to "$variation:$difficulty"');
|
||||||
selectedVariation = variation;
|
selectedVariation = variation;
|
||||||
selectedDifficulty = difficulty;
|
selectedDifficulty = difficulty;
|
||||||
// refreshDifficultyTreeSelection(treeView);
|
this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
refreshMetadataToolbox();
|
|
||||||
}
|
}
|
||||||
// case 'song':
|
// case 'song':
|
||||||
// case 'variation':
|
// case 'variation':
|
||||||
|
@ -5237,82 +5277,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
trace('Selected wrong node type, resetting selection.');
|
trace('Selected wrong node type, resetting selection.');
|
||||||
var currentTreeDifficultyNode = getCurrentTreeDifficultyNode(treeView);
|
var currentTreeDifficultyNode = getCurrentTreeDifficultyNode(treeView);
|
||||||
if (currentTreeDifficultyNode != null) treeView.selectedNode = currentTreeDifficultyNode;
|
if (currentTreeDifficultyNode != null) treeView.selectedNode = currentTreeDifficultyNode;
|
||||||
refreshMetadataToolbox();
|
this.refreshToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the difficulty changes, update the song metadata toolbox to reflect the new data.
|
|
||||||
*/
|
|
||||||
function refreshMetadataToolbox():Void
|
|
||||||
{
|
|
||||||
var toolbox:Null<CollapsibleDialog> = this.getToolbox(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
|
||||||
if (toolbox == null) return;
|
|
||||||
|
|
||||||
var inputSongName:Null<TextField> = toolbox.findComponent('inputSongName', TextField);
|
|
||||||
if (inputSongName != null) inputSongName.value = currentSongMetadata.songName;
|
|
||||||
|
|
||||||
var inputSongArtist:Null<TextField> = toolbox.findComponent('inputSongArtist', TextField);
|
|
||||||
if (inputSongArtist != null) inputSongArtist.value = currentSongMetadata.artist;
|
|
||||||
|
|
||||||
var inputStage:Null<DropDown> = toolbox.findComponent('inputStage', DropDown);
|
|
||||||
if (inputStage != null) inputStage.value = currentSongMetadata.playData.stage;
|
|
||||||
|
|
||||||
var inputNoteStyle:Null<DropDown> = toolbox.findComponent('inputNoteStyle', DropDown);
|
|
||||||
if (inputNoteStyle != null) inputNoteStyle.value = currentSongMetadata.playData.noteStyle;
|
|
||||||
|
|
||||||
var inputBPM:Null<NumberStepper> = toolbox.findComponent('inputBPM', NumberStepper);
|
|
||||||
if (inputBPM != null) inputBPM.value = currentSongMetadata.timeChanges[0].bpm;
|
|
||||||
|
|
||||||
var labelScrollSpeed:Null<Label> = toolbox.findComponent('labelScrollSpeed', Label);
|
|
||||||
if (labelScrollSpeed != null) labelScrollSpeed.text = 'Scroll Speed: ${currentSongChartScrollSpeed}x';
|
|
||||||
|
|
||||||
var inputScrollSpeed:Null<Slider> = toolbox.findComponent('inputScrollSpeed', Slider);
|
|
||||||
if (inputScrollSpeed != null) inputScrollSpeed.value = currentSongChartScrollSpeed;
|
|
||||||
|
|
||||||
var frameVariation:Null<Frame> = toolbox.findComponent('frameVariation', Frame);
|
|
||||||
if (frameVariation != null) frameVariation.text = 'Variation: ${selectedVariation.toTitleCase()}';
|
|
||||||
var frameDifficulty:Null<Frame> = toolbox.findComponent('frameDifficulty', Frame);
|
|
||||||
if (frameDifficulty != null) frameDifficulty.text = 'Difficulty: ${selectedDifficulty.toTitleCase()}';
|
|
||||||
|
|
||||||
var inputStage:Null<DropDown> = toolbox.findComponent('inputStage', DropDown);
|
|
||||||
var stageId:String = currentSongMetadata.playData.stage;
|
|
||||||
var stageData:Null<StageData> = StageDataParser.parseStageData(stageId);
|
|
||||||
if (inputStage != null)
|
|
||||||
{
|
|
||||||
inputStage.value = (stageData != null) ?
|
|
||||||
{id: stageId, text: stageData.name} :
|
|
||||||
{id: "mainStage", text: "Main Stage"};
|
|
||||||
}
|
|
||||||
|
|
||||||
var inputCharacterPlayer:Null<DropDown> = toolbox.findComponent('inputCharacterPlayer', DropDown);
|
|
||||||
var charIdPlayer:String = currentSongMetadata.playData.characters.player;
|
|
||||||
var charDataPlayer:Null<CharacterData> = CharacterDataParser.fetchCharacterData(charIdPlayer);
|
|
||||||
if (inputCharacterPlayer != null)
|
|
||||||
{
|
|
||||||
inputCharacterPlayer.value = (charDataPlayer != null) ?
|
|
||||||
{id: charIdPlayer, text: charDataPlayer.name} :
|
|
||||||
{id: "bf", text: "Boyfriend"};
|
|
||||||
}
|
|
||||||
|
|
||||||
var inputCharacterOpponent:Null<DropDown> = toolbox.findComponent('inputCharacterOpponent', DropDown);
|
|
||||||
var charIdOpponent:String = currentSongMetadata.playData.characters.opponent;
|
|
||||||
var charDataOpponent:Null<CharacterData> = CharacterDataParser.fetchCharacterData(charIdOpponent);
|
|
||||||
if (inputCharacterOpponent != null)
|
|
||||||
{
|
|
||||||
inputCharacterOpponent.value = (charDataOpponent != null) ?
|
|
||||||
{id: charIdOpponent, text: charDataOpponent.name} :
|
|
||||||
{id: "dad", text: "Dad"};
|
|
||||||
}
|
|
||||||
|
|
||||||
var inputCharacterGirlfriend:Null<DropDown> = toolbox.findComponent('inputCharacterGirlfriend', DropDown);
|
|
||||||
var charIdGirlfriend:String = currentSongMetadata.playData.characters.girlfriend;
|
|
||||||
var charDataGirlfriend:Null<CharacterData> = CharacterDataParser.fetchCharacterData(charIdGirlfriend);
|
|
||||||
if (inputCharacterGirlfriend != null)
|
|
||||||
{
|
|
||||||
inputCharacterGirlfriend.value = (charDataGirlfriend != null) ?
|
|
||||||
{id: charIdGirlfriend, text: charDataGirlfriend.name} :
|
|
||||||
{id: "none", text: "None"};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,12 @@ package funkin.ui.debug.charting.dialogs;
|
||||||
|
|
||||||
import haxe.ui.containers.dialogs.Dialog;
|
import haxe.ui.containers.dialogs.Dialog;
|
||||||
import haxe.ui.containers.dialogs.Dialog.DialogEvent;
|
import haxe.ui.containers.dialogs.Dialog.DialogEvent;
|
||||||
|
import haxe.ui.animation.AnimationBuilder;
|
||||||
|
import haxe.ui.styles.EasingFunction;
|
||||||
import haxe.ui.core.Component;
|
import haxe.ui.core.Component;
|
||||||
|
|
||||||
|
// @:nullSafety // TODO: Fix null safety when used with HaxeUI build macros.
|
||||||
|
|
||||||
@:access(funkin.ui.debug.charting.ChartEditorState)
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
class ChartEditorBaseDialog extends Dialog
|
class ChartEditorBaseDialog extends Dialog
|
||||||
{
|
{
|
||||||
|
@ -25,6 +29,18 @@ class ChartEditorBaseDialog extends Dialog
|
||||||
this.onDialogClosed = event -> onClose(event);
|
this.onDialogClosed = event -> onClose(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override function showDialog(modal:Bool = true):Void
|
||||||
|
{
|
||||||
|
super.showDialog(modal);
|
||||||
|
fadeInComponent(this, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private override function onReady():Void
|
||||||
|
{
|
||||||
|
_overlay.opacity = 0;
|
||||||
|
fadeInDialogOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the dialog is closed.
|
* Called when the dialog is closed.
|
||||||
* Override this to add custom behavior.
|
* Override this to add custom behavior.
|
||||||
|
@ -54,6 +70,36 @@ class ChartEditorBaseDialog extends Dialog
|
||||||
|
|
||||||
this.closable = params.closable ?? false;
|
this.closable = params.closable ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final OVERLAY_EASE_DURATION:Float = 0.2;
|
||||||
|
static final OVERLAY_EASE_TYPE:String = "easeOut";
|
||||||
|
|
||||||
|
function fadeInDialogOverlay():Void
|
||||||
|
{
|
||||||
|
if (!modal)
|
||||||
|
{
|
||||||
|
trace('Dialog is not modal, skipping overlay fade...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_overlay == null)
|
||||||
|
{
|
||||||
|
trace('[WARN] Dialog overlay is null, skipping overlay fade...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fadeInComponent(_overlay, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fadeInComponent(component:Component, fadeTo:Float = 1):Void
|
||||||
|
{
|
||||||
|
var builder = new AnimationBuilder(component, OVERLAY_EASE_DURATION, OVERLAY_EASE_TYPE);
|
||||||
|
builder.setPosition(0, "opacity", 0, true); // 0% absolute
|
||||||
|
builder.setPosition(100, "opacity", fadeTo, true);
|
||||||
|
|
||||||
|
trace('Fading in dialog component...');
|
||||||
|
builder.play();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef DialogParams =
|
typedef DialogParams =
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package funkin.ui.debug.charting.dialogs;
|
||||||
|
|
||||||
|
import haxe.ui.containers.dialogs.Dialog;
|
||||||
|
import haxe.ui.containers.dialogs.Dialog.DialogEvent;
|
||||||
|
import haxe.ui.animation.AnimationBuilder;
|
||||||
|
import haxe.ui.styles.EasingFunction;
|
||||||
|
import haxe.ui.core.Component;
|
||||||
|
import haxe.ui.containers.menus.Menu;
|
||||||
|
|
||||||
|
// @:nullSafety // TODO: Fix null safety when used with HaxeUI build macros.
|
||||||
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
|
class ChartEditorBaseMenu extends Menu
|
||||||
|
{
|
||||||
|
var state:ChartEditorState;
|
||||||
|
|
||||||
|
public function new(state:ChartEditorState)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.state = state;
|
||||||
|
|
||||||
|
// this.destroyOnClose = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
package funkin.ui.debug.charting.dialogs;
|
||||||
|
|
||||||
|
import flixel.math.FlxPoint;
|
||||||
|
import funkin.play.character.BaseCharacter.CharacterType;
|
||||||
|
import funkin.play.character.CharacterData;
|
||||||
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
|
import funkin.play.components.HealthIcon;
|
||||||
|
import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogParams;
|
||||||
|
import funkin.util.SortUtil;
|
||||||
|
import haxe.ui.components.Label;
|
||||||
|
import haxe.ui.containers.Grid;
|
||||||
|
import haxe.ui.containers.HBox;
|
||||||
|
import haxe.ui.containers.ScrollView;
|
||||||
|
import haxe.ui.containers.ScrollView;
|
||||||
|
import haxe.ui.core.Screen;
|
||||||
|
|
||||||
|
// @:nullSafety // TODO: Fix null safety when used with HaxeUI build macros.
|
||||||
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
|
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/character-icon-selector.xml"))
|
||||||
|
class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu
|
||||||
|
{
|
||||||
|
public var charSelectScroll:ScrollView;
|
||||||
|
public var charIconName:Label;
|
||||||
|
|
||||||
|
public function new(state2:ChartEditorState, charType:CharacterType, lockPosition:Bool = false)
|
||||||
|
{
|
||||||
|
super(state2);
|
||||||
|
|
||||||
|
initialize(charType, lockPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize(charType:CharacterType, lockPosition:Bool)
|
||||||
|
{
|
||||||
|
var currentCharId:String = switch (charType)
|
||||||
|
{
|
||||||
|
case BF: state.currentSongMetadata.playData.characters.player;
|
||||||
|
case GF: state.currentSongMetadata.playData.characters.girlfriend;
|
||||||
|
case DAD: state.currentSongMetadata.playData.characters.opponent;
|
||||||
|
default: throw 'Invalid charType: ' + charType;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Position this menu.
|
||||||
|
var targetHealthIcon:Null<HealthIcon> = switch (charType)
|
||||||
|
{
|
||||||
|
case BF: state.healthIconBF;
|
||||||
|
case DAD: state.healthIconDad;
|
||||||
|
default: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lockPosition && targetHealthIcon != null)
|
||||||
|
{
|
||||||
|
var healthIconBottomCenter:FlxPoint = new FlxPoint(targetHealthIcon.x + targetHealthIcon.width / 2, targetHealthIcon.y + targetHealthIcon.height);
|
||||||
|
|
||||||
|
this.x = healthIconBottomCenter.x - this.width / 2;
|
||||||
|
this.y = healthIconBottomCenter.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.x = Screen.instance.currentMouseX;
|
||||||
|
this.y = Screen.instance.currentMouseY;
|
||||||
|
}
|
||||||
|
|
||||||
|
var charGrid = new Grid();
|
||||||
|
charGrid.columns = 5;
|
||||||
|
charGrid.width = 100;
|
||||||
|
charSelectScroll.addComponent(charGrid);
|
||||||
|
|
||||||
|
var charIds:Array<String> = CharacterDataParser.listCharacterIds();
|
||||||
|
charIds.sort(SortUtil.alphabetically);
|
||||||
|
|
||||||
|
var defaultText:String = '(choose a character)';
|
||||||
|
|
||||||
|
for (charIndex => charId in charIds)
|
||||||
|
{
|
||||||
|
var charData:CharacterData = CharacterDataParser.fetchCharacterData(charId);
|
||||||
|
|
||||||
|
var charButton = new haxe.ui.components.Button();
|
||||||
|
charButton.width = 70;
|
||||||
|
charButton.height = 70;
|
||||||
|
charButton.padding = 8;
|
||||||
|
charButton.iconPosition = "top";
|
||||||
|
|
||||||
|
if (charId == currentCharId)
|
||||||
|
{
|
||||||
|
// Scroll to the character if it is already selected.
|
||||||
|
charSelectScroll.hscrollPos = Math.floor(charIndex / 5) * 80;
|
||||||
|
charButton.selected = true;
|
||||||
|
|
||||||
|
defaultText = '${charData.name} [${charId}]';
|
||||||
|
}
|
||||||
|
|
||||||
|
var LIMIT = 6;
|
||||||
|
charButton.icon = CharacterDataParser.getCharPixelIconAsset(charId);
|
||||||
|
charButton.text = charData.name.length > LIMIT ? '${charData.name.substr(0, LIMIT)}.' : '${charData.name}';
|
||||||
|
|
||||||
|
charButton.onClick = _ -> {
|
||||||
|
switch (charType)
|
||||||
|
{
|
||||||
|
case BF: state.currentSongMetadata.playData.characters.player = charId;
|
||||||
|
case GF: state.currentSongMetadata.playData.characters.girlfriend = charId;
|
||||||
|
case DAD: state.currentSongMetadata.playData.characters.opponent = charId;
|
||||||
|
default: throw 'Invalid charType: ' + charType;
|
||||||
|
};
|
||||||
|
|
||||||
|
state.healthIconsDirty = true;
|
||||||
|
state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
|
};
|
||||||
|
|
||||||
|
charButton.onMouseOver = _ -> {
|
||||||
|
charIconName.text = '${charData.name} [${charId}]';
|
||||||
|
};
|
||||||
|
charButton.onMouseOut = _ -> {
|
||||||
|
charIconName.text = defaultText;
|
||||||
|
};
|
||||||
|
charGrid.addComponent(charButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
charIconName.text = defaultText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function build(state2:ChartEditorState, charType:CharacterType, lockPosition:Bool = false):ChartEditorCharacterIconSelectorMenu
|
||||||
|
{
|
||||||
|
var menu = new ChartEditorCharacterIconSelectorMenu(state2, charType, lockPosition);
|
||||||
|
|
||||||
|
Screen.instance.addComponent(menu);
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import haxe.ui.containers.dialogs.Dialogs;
|
||||||
import haxe.ui.notifications.NotificationManager;
|
import haxe.ui.notifications.NotificationManager;
|
||||||
import haxe.ui.notifications.NotificationType;
|
import haxe.ui.notifications.NotificationType;
|
||||||
|
|
||||||
|
// @:nullSafety // TODO: Fix null safety when used with HaxeUI build macros.
|
||||||
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/upload-chart.xml"))
|
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/dialogs/upload-chart.xml"))
|
||||||
class ChartEditorUploadChartDialog extends ChartEditorBaseDialog
|
class ChartEditorUploadChartDialog extends ChartEditorBaseDialog
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@ import funkin.play.song.Song;
|
||||||
import funkin.play.stage.StageData;
|
import funkin.play.stage.StageData;
|
||||||
import funkin.ui.debug.charting.dialogs.ChartEditorAboutDialog;
|
import funkin.ui.debug.charting.dialogs.ChartEditorAboutDialog;
|
||||||
import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogDropTarget;
|
import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogDropTarget;
|
||||||
|
import funkin.ui.debug.charting.dialogs.ChartEditorCharacterIconSelectorMenu;
|
||||||
import funkin.ui.debug.charting.dialogs.ChartEditorUploadChartDialog;
|
import funkin.ui.debug.charting.dialogs.ChartEditorUploadChartDialog;
|
||||||
import funkin.ui.debug.charting.dialogs.ChartEditorWelcomeDialog;
|
import funkin.ui.debug.charting.dialogs.ChartEditorWelcomeDialog;
|
||||||
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
|
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
|
||||||
|
@ -39,6 +40,7 @@ import haxe.ui.containers.dialogs.Dialog;
|
||||||
import haxe.ui.containers.dialogs.Dialog.DialogButton;
|
import haxe.ui.containers.dialogs.Dialog.DialogButton;
|
||||||
import haxe.ui.containers.dialogs.Dialogs;
|
import haxe.ui.containers.dialogs.Dialogs;
|
||||||
import haxe.ui.containers.Form;
|
import haxe.ui.containers.Form;
|
||||||
|
import haxe.ui.containers.menus.Menu;
|
||||||
import haxe.ui.containers.VBox;
|
import haxe.ui.containers.VBox;
|
||||||
import haxe.ui.core.Component;
|
import haxe.ui.core.Component;
|
||||||
import haxe.ui.events.UIEvent;
|
import haxe.ui.events.UIEvent;
|
||||||
|
@ -286,6 +288,15 @@ class ChartEditorDialogHandler
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function openCharacterDropdown(state:ChartEditorState, charType:CharacterType, lockPosition:Bool = false):Null<Menu>
|
||||||
|
{
|
||||||
|
var menu = ChartEditorCharacterIconSelectorMenu.build(state, charType, lockPosition);
|
||||||
|
|
||||||
|
menu.zIndex = 1000;
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
public static function openCreateSongWizardBasicOnly(state:ChartEditorState, closable:Bool):Void
|
public static function openCreateSongWizardBasicOnly(state:ChartEditorState, closable:Bool):Void
|
||||||
{
|
{
|
||||||
// Step 1. Song Metadata
|
// Step 1. Song Metadata
|
||||||
|
|
|
@ -99,7 +99,7 @@ class ChartEditorImportExportHandler
|
||||||
state.switchToCurrentInstrumental();
|
state.switchToCurrentInstrumental();
|
||||||
state.postLoadInstrumental();
|
state.postLoadInstrumental();
|
||||||
|
|
||||||
state.refreshMetadataToolbox();
|
state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
||||||
|
|
||||||
state.success('Success', 'Loaded song (${rawSongMetadata[0].songName})');
|
state.success('Success', 'Loaded song (${rawSongMetadata[0].songName})');
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import haxe.ui.containers.HBox;
|
||||||
import haxe.ui.notifications.Notification;
|
import haxe.ui.notifications.Notification;
|
||||||
import haxe.ui.notifications.NotificationManager;
|
import haxe.ui.notifications.NotificationManager;
|
||||||
import haxe.ui.notifications.NotificationType;
|
import haxe.ui.notifications.NotificationType;
|
||||||
|
import haxe.ui.notifications.NotificationData.NotificationActionData;
|
||||||
|
|
||||||
class ChartEditorNotificationHandler
|
class ChartEditorNotificationHandler
|
||||||
{
|
{
|
||||||
|
@ -77,7 +78,7 @@ class ChartEditorNotificationHandler
|
||||||
* @param actions The actions to add to the notification.
|
* @param actions The actions to add to the notification.
|
||||||
* @return The notification that was sent.
|
* @return The notification that was sent.
|
||||||
*/
|
*/
|
||||||
public static function infoWithActions(state:ChartEditorState, title:String, body:String, actions:Array<NotificationAction>):Notification
|
public static function infoWithActions(state:ChartEditorState, title:String, body:String, actions:Array<NotificationActionData>):Notification
|
||||||
{
|
{
|
||||||
return sendNotification(state, title, body, NotificationType.Info, actions);
|
return sendNotification(state, title, body, NotificationType.Info, actions);
|
||||||
}
|
}
|
||||||
|
@ -101,7 +102,8 @@ class ChartEditorNotificationHandler
|
||||||
NotificationManager.instance.removeNotification(notif);
|
NotificationManager.instance.removeNotification(notif);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function sendNotification(state:ChartEditorState, title:String, body:String, ?type:NotificationType, ?actions:Array<NotificationAction>):Notification
|
static function sendNotification(state:ChartEditorState, title:String, body:String, ?type:NotificationType,
|
||||||
|
?actions:Array<NotificationActionData>):Notification
|
||||||
{
|
{
|
||||||
var actionNames:Array<String> = actions == null ? [] : actions.map(action -> action.text);
|
var actionNames:Array<String> = actions == null ? [] : actions.map(action -> action.text);
|
||||||
|
|
||||||
|
@ -111,10 +113,10 @@ class ChartEditorNotificationHandler
|
||||||
body: body,
|
body: body,
|
||||||
type: type ?? NotificationType.Default,
|
type: type ?? NotificationType.Default,
|
||||||
expiryMs: Constants.NOTIFICATION_DISMISS_TIME,
|
expiryMs: Constants.NOTIFICATION_DISMISS_TIME,
|
||||||
actions: actionNames
|
actions: actions
|
||||||
});
|
});
|
||||||
|
|
||||||
if (actionNames.length > 0)
|
if (actions != null && actions.length > 0)
|
||||||
{
|
{
|
||||||
// TODO: Tell Ian that this is REALLY dumb.
|
// TODO: Tell Ian that this is REALLY dumb.
|
||||||
var actionsContainer:HBox = notif.findComponent('actionsContainer', HBox);
|
var actionsContainer:HBox = notif.findComponent('actionsContainer', HBox);
|
||||||
|
@ -122,13 +124,13 @@ class ChartEditorNotificationHandler
|
||||||
if (Std.isOfType(component, Button))
|
if (Std.isOfType(component, Button))
|
||||||
{
|
{
|
||||||
var button:Button = cast component;
|
var button:Button = cast component;
|
||||||
var action:Null<NotificationAction> = actions.find(action -> action.text == button.text);
|
var action:Null<NotificationActionData> = actions.find(action -> action.text == button.text);
|
||||||
if (action != null && action.callback != null)
|
if (action != null && action.callback != null)
|
||||||
{
|
{
|
||||||
button.onClick = function(_) {
|
button.onClick = function(_) {
|
||||||
// Don't allow actions to be clicked while the playtest is open.
|
// Don't allow actions to be clicked while the playtest is open.
|
||||||
if (state.subState != null) return;
|
if (state.subState != null) return;
|
||||||
action.callback();
|
action.callback(action);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import funkin.play.character.BaseCharacter.CharacterType;
|
||||||
import funkin.play.event.SongEvent;
|
import funkin.play.event.SongEvent;
|
||||||
import funkin.data.event.SongEventData;
|
import funkin.data.event.SongEventData;
|
||||||
import funkin.data.song.SongData.SongTimeChange;
|
import funkin.data.song.SongData.SongTimeChange;
|
||||||
import funkin.ui.debug.charting.commands.ChangeStartingBPMCommand;
|
|
||||||
import funkin.play.character.BaseCharacter.CharacterType;
|
import funkin.play.character.BaseCharacter.CharacterType;
|
||||||
import funkin.play.character.CharacterData;
|
import funkin.play.character.CharacterData;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
|
@ -35,6 +34,8 @@ import haxe.ui.containers.Box;
|
||||||
import haxe.ui.containers.dialogs.CollapsibleDialog;
|
import haxe.ui.containers.dialogs.CollapsibleDialog;
|
||||||
import haxe.ui.containers.dialogs.Dialog.DialogButton;
|
import haxe.ui.containers.dialogs.Dialog.DialogButton;
|
||||||
import haxe.ui.containers.dialogs.Dialog.DialogEvent;
|
import haxe.ui.containers.dialogs.Dialog.DialogEvent;
|
||||||
|
import funkin.ui.debug.charting.toolboxes.ChartEditorBaseToolbox;
|
||||||
|
import funkin.ui.debug.charting.toolboxes.ChartEditorMetadataToolbox;
|
||||||
import haxe.ui.containers.Frame;
|
import haxe.ui.containers.Frame;
|
||||||
import haxe.ui.containers.Grid;
|
import haxe.ui.containers.Grid;
|
||||||
import haxe.ui.containers.TreeView;
|
import haxe.ui.containers.TreeView;
|
||||||
|
@ -80,10 +81,13 @@ class ChartEditorToolboxHandler
|
||||||
onShowToolboxNoteData(state, toolbox);
|
onShowToolboxNoteData(state, toolbox);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT:
|
||||||
onShowToolboxEventData(state, toolbox);
|
onShowToolboxEventData(state, toolbox);
|
||||||
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT:
|
||||||
|
onShowToolboxPlaytestProperties(state, toolbox);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT:
|
||||||
onShowToolboxDifficulty(state, toolbox);
|
onShowToolboxDifficulty(state, toolbox);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT:
|
||||||
onShowToolboxMetadata(state, toolbox);
|
// TODO: Fix this.
|
||||||
|
cast(toolbox, ChartEditorBaseToolbox).refresh();
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT:
|
||||||
onShowToolboxPlayerPreview(state, toolbox);
|
onShowToolboxPlayerPreview(state, toolbox);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT:
|
||||||
|
@ -117,6 +121,8 @@ class ChartEditorToolboxHandler
|
||||||
onHideToolboxNoteData(state, toolbox);
|
onHideToolboxNoteData(state, toolbox);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT:
|
||||||
onHideToolboxEventData(state, toolbox);
|
onHideToolboxEventData(state, toolbox);
|
||||||
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT:
|
||||||
|
onHideToolboxPlaytestProperties(state, toolbox);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT:
|
||||||
onHideToolboxDifficulty(state, toolbox);
|
onHideToolboxDifficulty(state, toolbox);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT:
|
||||||
|
@ -136,6 +142,22 @@ class ChartEditorToolboxHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function refreshToolbox(state:ChartEditorState, id:String):Void
|
||||||
|
{
|
||||||
|
var toolbox:Null<ChartEditorBaseToolbox> = cast state.activeToolboxes.get(id);
|
||||||
|
|
||||||
|
if (toolbox == null) return;
|
||||||
|
|
||||||
|
if (toolbox != null)
|
||||||
|
{
|
||||||
|
toolbox.refresh();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace('ChartEditorToolboxHandler.refreshToolbox() - Could not retrieve toolbox: $id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function rememberOpenToolboxes(state:ChartEditorState):Void {}
|
public static function rememberOpenToolboxes(state:ChartEditorState):Void {}
|
||||||
|
|
||||||
public static function openRememberedToolboxes(state:ChartEditorState):Void {}
|
public static function openRememberedToolboxes(state:ChartEditorState):Void {}
|
||||||
|
@ -175,6 +197,8 @@ class ChartEditorToolboxHandler
|
||||||
toolbox = buildToolboxNoteDataLayout(state);
|
toolbox = buildToolboxNoteDataLayout(state);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_EVENTDATA_LAYOUT:
|
||||||
toolbox = buildToolboxEventDataLayout(state);
|
toolbox = buildToolboxEventDataLayout(state);
|
||||||
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT:
|
||||||
|
toolbox = buildToolboxPlaytestPropertiesLayout(state);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT:
|
||||||
toolbox = buildToolboxDifficultyLayout(state);
|
toolbox = buildToolboxDifficultyLayout(state);
|
||||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT:
|
case ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT:
|
||||||
|
@ -205,7 +229,19 @@ class ChartEditorToolboxHandler
|
||||||
* @param id The asset ID of the toolbox layout.
|
* @param id The asset ID of the toolbox layout.
|
||||||
* @return The toolbox.
|
* @return The toolbox.
|
||||||
*/
|
*/
|
||||||
public static function getToolbox(state:ChartEditorState, id:String):Null<CollapsibleDialog>
|
public static function getToolbox_OLD(state:ChartEditorState, id:String):Null<CollapsibleDialog>
|
||||||
|
{
|
||||||
|
var toolbox:Null<CollapsibleDialog> = state.activeToolboxes.get(id);
|
||||||
|
|
||||||
|
// Initialize the toolbox without showing it.
|
||||||
|
if (toolbox == null) toolbox = initToolbox(state, id);
|
||||||
|
|
||||||
|
if (toolbox == null) throw 'ChartEditorToolboxHandler.getToolbox_OLD() - Could not retrieve or build toolbox: $id';
|
||||||
|
|
||||||
|
return toolbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getToolbox(state:ChartEditorState, id:String):Null<ChartEditorBaseToolbox>
|
||||||
{
|
{
|
||||||
var toolbox:Null<CollapsibleDialog> = state.activeToolboxes.get(id);
|
var toolbox:Null<CollapsibleDialog> = state.activeToolboxes.get(id);
|
||||||
|
|
||||||
|
@ -214,7 +250,7 @@ class ChartEditorToolboxHandler
|
||||||
|
|
||||||
if (toolbox == null) throw 'ChartEditorToolboxHandler.getToolbox() - Could not retrieve or build toolbox: $id';
|
if (toolbox == null) throw 'ChartEditorToolboxHandler.getToolbox() - Could not retrieve or build toolbox: $id';
|
||||||
|
|
||||||
return toolbox;
|
return cast toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildToolboxNoteDataLayout(state:ChartEditorState):Null<CollapsibleDialog>
|
static function buildToolboxNoteDataLayout(state:ChartEditorState):Null<CollapsibleDialog>
|
||||||
|
@ -321,8 +357,12 @@ class ChartEditorToolboxHandler
|
||||||
|
|
||||||
static function onShowToolboxEventData(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
static function onShowToolboxEventData(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||||
|
|
||||||
|
static function onShowToolboxPlaytestProperties(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||||
|
|
||||||
static function onHideToolboxEventData(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
static function onHideToolboxEventData(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||||
|
|
||||||
|
static function onHideToolboxPlaytestProperties(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||||
|
|
||||||
static function buildEventDataFormFromSchema(state:ChartEditorState, target:Box, schema:SongEventSchema):Void
|
static function buildEventDataFormFromSchema(state:ChartEditorState, target:Box, schema:SongEventSchema):Void
|
||||||
{
|
{
|
||||||
trace(schema);
|
trace(schema);
|
||||||
|
@ -418,6 +458,39 @@ class ChartEditorToolboxHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function buildToolboxPlaytestPropertiesLayout(state:ChartEditorState):Null<CollapsibleDialog>
|
||||||
|
{
|
||||||
|
// fill with playtest properties
|
||||||
|
var toolbox:CollapsibleDialog = cast RuntimeComponentBuilder.fromAsset(ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT);
|
||||||
|
|
||||||
|
if (toolbox == null) return null;
|
||||||
|
|
||||||
|
toolbox.onDialogClosed = function(_) {
|
||||||
|
state.menubarItemToggleToolboxPlaytestProperties.selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkboxPracticeMode:Null<CheckBox> = toolbox.findComponent('practiceModeCheckbox', CheckBox);
|
||||||
|
if (checkboxPracticeMode == null) throw 'ChartEditorToolboxHandler.buildToolboxPlaytestPropertiesLayout() - Could not find practiceModeCheckbox component.';
|
||||||
|
|
||||||
|
checkboxPracticeMode.selected = state.playtestPracticeMode;
|
||||||
|
|
||||||
|
checkboxPracticeMode.onClick = _ -> {
|
||||||
|
state.playtestPracticeMode = checkboxPracticeMode.selected;
|
||||||
|
};
|
||||||
|
|
||||||
|
var checkboxStartTime:Null<CheckBox> = toolbox.findComponent('playtestStartTimeCheckbox', CheckBox);
|
||||||
|
if (checkboxStartTime == null)
|
||||||
|
throw 'ChartEditorToolboxHandler.buildToolboxPlaytestPropertiesLayout() - Could not find playtestStartTimeCheckbox component.';
|
||||||
|
|
||||||
|
checkboxStartTime.selected = state.playtestStartTime;
|
||||||
|
|
||||||
|
checkboxStartTime.onClick = _ -> {
|
||||||
|
state.playtestStartTime = checkboxStartTime.selected;
|
||||||
|
};
|
||||||
|
|
||||||
|
return toolbox;
|
||||||
|
}
|
||||||
|
|
||||||
static function buildToolboxDifficultyLayout(state:ChartEditorState):Null<CollapsibleDialog>
|
static function buildToolboxDifficultyLayout(state:ChartEditorState):Null<CollapsibleDialog>
|
||||||
{
|
{
|
||||||
var toolbox:CollapsibleDialog = cast RuntimeComponentBuilder.fromAsset(ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT);
|
var toolbox:CollapsibleDialog = cast RuntimeComponentBuilder.fromAsset(ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT);
|
||||||
|
@ -505,180 +578,15 @@ class ChartEditorToolboxHandler
|
||||||
|
|
||||||
static function onHideToolboxDifficulty(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
static function onHideToolboxDifficulty(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||||
|
|
||||||
static function buildToolboxMetadataLayout(state:ChartEditorState):Null<CollapsibleDialog>
|
static function buildToolboxMetadataLayout(state:ChartEditorState):Null<ChartEditorBaseToolbox>
|
||||||
{
|
{
|
||||||
var toolbox:CollapsibleDialog = cast RuntimeComponentBuilder.fromAsset(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
|
var toolbox:ChartEditorBaseToolbox = ChartEditorMetadataToolbox.build(state);
|
||||||
|
|
||||||
if (toolbox == null) return null;
|
if (toolbox == null) return null;
|
||||||
|
|
||||||
// Starting position.
|
|
||||||
toolbox.x = 150;
|
|
||||||
toolbox.y = 250;
|
|
||||||
|
|
||||||
toolbox.onDialogClosed = function(event:UIEvent) {
|
|
||||||
state.menubarItemToggleToolboxMetadata.selected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var inputSongName:Null<TextField> = toolbox.findComponent('inputSongName', TextField);
|
|
||||||
if (inputSongName == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputSongName component.';
|
|
||||||
inputSongName.onChange = function(event:UIEvent) {
|
|
||||||
var valid:Bool = event.target.text != null && event.target.text != '';
|
|
||||||
|
|
||||||
if (valid)
|
|
||||||
{
|
|
||||||
inputSongName.removeClass('invalid-value');
|
|
||||||
state.currentSongMetadata.songName = event.target.text;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state.currentSongMetadata.songName = '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inputSongName.value = state.currentSongMetadata.songName;
|
|
||||||
|
|
||||||
var inputSongArtist:Null<TextField> = toolbox.findComponent('inputSongArtist', TextField);
|
|
||||||
if (inputSongArtist == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputSongArtist component.';
|
|
||||||
inputSongArtist.onChange = function(event:UIEvent) {
|
|
||||||
var valid:Bool = event.target.text != null && event.target.text != '';
|
|
||||||
|
|
||||||
if (valid)
|
|
||||||
{
|
|
||||||
inputSongArtist.removeClass('invalid-value');
|
|
||||||
state.currentSongMetadata.artist = event.target.text;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state.currentSongMetadata.artist = '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inputSongArtist.value = state.currentSongMetadata.artist;
|
|
||||||
|
|
||||||
var inputStage:Null<DropDown> = 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;
|
|
||||||
|
|
||||||
if (valid)
|
|
||||||
{
|
|
||||||
state.currentSongMetadata.playData.stage = event.data.id;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var startingValueStage = ChartEditorDropdowns.populateDropdownWithStages(inputStage, state.currentSongMetadata.playData.stage);
|
|
||||||
inputStage.value = startingValueStage;
|
|
||||||
|
|
||||||
var inputNoteStyle:Null<DropDown> = 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;
|
|
||||||
state.currentSongNoteStyle = event.data.id;
|
|
||||||
};
|
|
||||||
inputNoteStyle.value = state.currentSongNoteStyle;
|
|
||||||
|
|
||||||
// By using this flag, we prevent the dropdown value from changing while it is being populated.
|
|
||||||
|
|
||||||
var inputCharacterPlayer:Null<DropDown> = 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;
|
|
||||||
state.currentSongMetadata.playData.characters.player = event.data.id;
|
|
||||||
};
|
|
||||||
var startingValuePlayer = ChartEditorDropdowns.populateDropdownWithCharacters(inputCharacterPlayer, CharacterType.BF,
|
|
||||||
state.currentSongMetadata.playData.characters.player);
|
|
||||||
inputCharacterPlayer.value = startingValuePlayer;
|
|
||||||
|
|
||||||
var inputCharacterOpponent:Null<DropDown> = 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;
|
|
||||||
state.currentSongMetadata.playData.characters.opponent = event.data.id;
|
|
||||||
};
|
|
||||||
var startingValueOpponent = ChartEditorDropdowns.populateDropdownWithCharacters(inputCharacterOpponent, CharacterType.DAD,
|
|
||||||
state.currentSongMetadata.playData.characters.opponent);
|
|
||||||
inputCharacterOpponent.value = startingValueOpponent;
|
|
||||||
|
|
||||||
var inputCharacterGirlfriend:Null<DropDown> = 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;
|
|
||||||
state.currentSongMetadata.playData.characters.girlfriend = event.data.id == "none" ? "" : event.data.id;
|
|
||||||
};
|
|
||||||
var startingValueGirlfriend = ChartEditorDropdowns.populateDropdownWithCharacters(inputCharacterGirlfriend, CharacterType.GF,
|
|
||||||
state.currentSongMetadata.playData.characters.girlfriend);
|
|
||||||
inputCharacterGirlfriend.value = startingValueGirlfriend;
|
|
||||||
|
|
||||||
var inputBPM:Null<NumberStepper> = toolbox.findComponent('inputBPM', NumberStepper);
|
|
||||||
if (inputBPM == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputBPM component.';
|
|
||||||
inputBPM.onChange = function(event:UIEvent) {
|
|
||||||
if (event.value == null || event.value <= 0) return;
|
|
||||||
|
|
||||||
// Use a command so we can undo/redo this action.
|
|
||||||
var startingBPM = state.currentSongMetadata.timeChanges[0].bpm;
|
|
||||||
if (event.value != startingBPM)
|
|
||||||
{
|
|
||||||
state.performCommand(new ChangeStartingBPMCommand(event.value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inputBPM.value = state.currentSongMetadata.timeChanges[0].bpm;
|
|
||||||
|
|
||||||
var inputOffsetInst:Null<NumberStepper> = toolbox.findComponent('inputOffsetInst', NumberStepper);
|
|
||||||
if (inputOffsetInst == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputOffsetInst component.';
|
|
||||||
inputOffsetInst.onChange = function(event:UIEvent) {
|
|
||||||
if (event.value == null) return;
|
|
||||||
|
|
||||||
state.currentInstrumentalOffset = event.value;
|
|
||||||
Conductor.instrumentalOffset = event.value;
|
|
||||||
// Update song length.
|
|
||||||
state.songLengthInMs = (state.audioInstTrack?.length ?? 1000.0) + Conductor.instrumentalOffset;
|
|
||||||
};
|
|
||||||
inputOffsetInst.value = state.currentInstrumentalOffset;
|
|
||||||
|
|
||||||
var inputOffsetVocal:Null<NumberStepper> = toolbox.findComponent('inputOffsetVocal', NumberStepper);
|
|
||||||
if (inputOffsetVocal == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputOffsetVocal component.';
|
|
||||||
inputOffsetVocal.onChange = function(event:UIEvent) {
|
|
||||||
if (event.value == null) return;
|
|
||||||
|
|
||||||
state.currentSongMetadata.offsets.setVocalOffset(state.currentSongMetadata.playData.characters.player, event.value);
|
|
||||||
};
|
|
||||||
inputOffsetVocal.value = state.currentSongMetadata.offsets.getVocalOffset(state.currentSongMetadata.playData.characters.player);
|
|
||||||
|
|
||||||
var labelScrollSpeed:Null<Label> = toolbox.findComponent('labelScrollSpeed', Label);
|
|
||||||
if (labelScrollSpeed == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find labelScrollSpeed component.';
|
|
||||||
|
|
||||||
var inputScrollSpeed:Null<Slider> = toolbox.findComponent('inputScrollSpeed', Slider);
|
|
||||||
if (inputScrollSpeed == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputScrollSpeed component.';
|
|
||||||
inputScrollSpeed.onChange = function(event:UIEvent) {
|
|
||||||
var valid:Bool = event.target.value != null && event.target.value > 0;
|
|
||||||
|
|
||||||
if (valid)
|
|
||||||
{
|
|
||||||
inputScrollSpeed.removeClass('invalid-value');
|
|
||||||
state.currentSongChartScrollSpeed = event.target.value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state.currentSongChartScrollSpeed = 1.0;
|
|
||||||
}
|
|
||||||
labelScrollSpeed.text = 'Scroll Speed: ${state.currentSongChartScrollSpeed}x';
|
|
||||||
};
|
|
||||||
inputScrollSpeed.value = state.currentSongChartScrollSpeed;
|
|
||||||
labelScrollSpeed.text = 'Scroll Speed: ${state.currentSongChartScrollSpeed}x';
|
|
||||||
|
|
||||||
var frameVariation:Null<Frame> = toolbox.findComponent('frameVariation', Frame);
|
|
||||||
if (frameVariation == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find frameVariation component.';
|
|
||||||
frameVariation.text = 'Variation: ${state.selectedVariation.toTitleCase()}';
|
|
||||||
|
|
||||||
var frameDifficulty:Null<Frame> = toolbox.findComponent('frameDifficulty', Frame);
|
|
||||||
if (frameDifficulty == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find frameDifficulty component.';
|
|
||||||
frameDifficulty.text = 'Difficulty: ${state.selectedDifficulty.toTitleCase()}';
|
|
||||||
|
|
||||||
return toolbox;
|
return toolbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function onShowToolboxMetadata(state:ChartEditorState, toolbox:CollapsibleDialog):Void
|
|
||||||
{
|
|
||||||
state.refreshMetadataToolbox();
|
|
||||||
}
|
|
||||||
|
|
||||||
static function onHideToolboxMetadata(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
static function onHideToolboxMetadata(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||||
|
|
||||||
static function buildToolboxPlayerPreviewLayout(state:ChartEditorState):Null<CollapsibleDialog>
|
static function buildToolboxPlayerPreviewLayout(state:ChartEditorState):Null<CollapsibleDialog>
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package funkin.ui.debug.charting.toolboxes;
|
||||||
|
|
||||||
|
import haxe.ui.containers.dialogs.Dialog;
|
||||||
|
import haxe.ui.containers.dialogs.CollapsibleDialog;
|
||||||
|
import haxe.ui.containers.dialogs.Dialog.DialogEvent;
|
||||||
|
import haxe.ui.core.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base class for the Toolboxes (manipulatable, arrangeable control windows) in the Chart Editor.
|
||||||
|
*/
|
||||||
|
// @:nullSafety // TODO: Fix null safety when used with HaxeUI build macros.
|
||||||
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
|
class ChartEditorBaseToolbox extends CollapsibleDialog
|
||||||
|
{
|
||||||
|
var state:ChartEditorState;
|
||||||
|
|
||||||
|
private function new(state:ChartEditorState)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override to implement this.
|
||||||
|
*/
|
||||||
|
public function refresh() {}
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
package funkin.ui.debug.charting.toolboxes;
|
||||||
|
|
||||||
|
import funkin.play.character.BaseCharacter.CharacterType;
|
||||||
|
import funkin.play.character.CharacterData;
|
||||||
|
import funkin.play.stage.StageData;
|
||||||
|
import funkin.ui.debug.charting.commands.ChangeStartingBPMCommand;
|
||||||
|
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
|
||||||
|
import haxe.ui.components.Button;
|
||||||
|
import haxe.ui.components.CheckBox;
|
||||||
|
import haxe.ui.components.DropDown;
|
||||||
|
import haxe.ui.components.HorizontalSlider;
|
||||||
|
import haxe.ui.components.Label;
|
||||||
|
import haxe.ui.components.NumberStepper;
|
||||||
|
import haxe.ui.components.Slider;
|
||||||
|
import haxe.ui.components.TextField;
|
||||||
|
import haxe.ui.containers.Box;
|
||||||
|
import haxe.ui.containers.Frame;
|
||||||
|
import haxe.ui.events.UIEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The toolbox which allows modifying information like Song Title, Scroll Speed, Characters/Stages, and starting BPM.
|
||||||
|
*/
|
||||||
|
// @:nullSafety // TODO: Fix null safety when used with HaxeUI build macros.
|
||||||
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
|
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/toolboxes/metadata.xml"))
|
||||||
|
class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
|
||||||
|
{
|
||||||
|
var inputSongName:TextField;
|
||||||
|
var inputSongArtist:TextField;
|
||||||
|
var inputStage:DropDown;
|
||||||
|
var inputNoteStyle:DropDown;
|
||||||
|
var buttonCharacterPlayer:Button;
|
||||||
|
var buttonCharacterGirlfriend:Button;
|
||||||
|
var buttonCharacterOpponent:Button;
|
||||||
|
var inputBPM:NumberStepper;
|
||||||
|
var inputOffsetInst:NumberStepper;
|
||||||
|
var inputOffsetVocal:NumberStepper;
|
||||||
|
var labelScrollSpeed:Label;
|
||||||
|
var inputScrollSpeed:Slider;
|
||||||
|
var frameVariation:Frame;
|
||||||
|
var frameDifficulty:Frame;
|
||||||
|
|
||||||
|
public function new(state2:ChartEditorState)
|
||||||
|
{
|
||||||
|
super(state2);
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
this.onDialogClosed = onClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClose(event:UIEvent)
|
||||||
|
{
|
||||||
|
state.menubarItemToggleToolboxMetadata.selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize():Void
|
||||||
|
{
|
||||||
|
// Starting position.
|
||||||
|
// TODO: Save and load this.
|
||||||
|
this.x = 150;
|
||||||
|
this.y = 250;
|
||||||
|
|
||||||
|
inputSongName.onChange = function(event:UIEvent) {
|
||||||
|
var valid:Bool = event.target.text != null && event.target.text != '';
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
inputSongName.removeClass('invalid-value');
|
||||||
|
state.currentSongMetadata.songName = event.target.text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.currentSongMetadata.songName = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inputSongArtist.onChange = function(event:UIEvent) {
|
||||||
|
var valid:Bool = event.target.text != null && event.target.text != '';
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
inputSongArtist.removeClass('invalid-value');
|
||||||
|
state.currentSongMetadata.artist = event.target.text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.currentSongMetadata.artist = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inputStage.onChange = function(event:UIEvent) {
|
||||||
|
var valid:Bool = event.data != null && event.data.id != null;
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
state.currentSongMetadata.playData.stage = event.data.id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var startingValueStage = ChartEditorDropdowns.populateDropdownWithStages(inputStage, state.currentSongMetadata.playData.stage);
|
||||||
|
inputStage.value = startingValueStage;
|
||||||
|
|
||||||
|
inputNoteStyle.onChange = function(event:UIEvent) {
|
||||||
|
if (event.data?.id == null) return;
|
||||||
|
state.currentSongNoteStyle = event.data.id;
|
||||||
|
};
|
||||||
|
|
||||||
|
inputBPM.onChange = function(event:UIEvent) {
|
||||||
|
if (event.value == null || event.value <= 0) return;
|
||||||
|
|
||||||
|
// Use a command so we can undo/redo this action.
|
||||||
|
var startingBPM = state.currentSongMetadata.timeChanges[0].bpm;
|
||||||
|
if (event.value != startingBPM)
|
||||||
|
{
|
||||||
|
state.performCommand(new ChangeStartingBPMCommand(event.value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inputOffsetInst.onChange = function(event:UIEvent) {
|
||||||
|
if (event.value == null) return;
|
||||||
|
|
||||||
|
state.currentInstrumentalOffset = event.value;
|
||||||
|
Conductor.instrumentalOffset = event.value;
|
||||||
|
// Update song length.
|
||||||
|
state.songLengthInMs = (state.audioInstTrack?.length ?? 1000.0) + Conductor.instrumentalOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
inputOffsetVocal.onChange = function(event:UIEvent) {
|
||||||
|
if (event.value == null) return;
|
||||||
|
|
||||||
|
state.currentSongMetadata.offsets.setVocalOffset(state.currentSongMetadata.playData.characters.player, event.value);
|
||||||
|
};
|
||||||
|
inputScrollSpeed.onChange = function(event:UIEvent) {
|
||||||
|
var valid:Bool = event.target.value != null && event.target.value > 0;
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
inputScrollSpeed.removeClass('invalid-value');
|
||||||
|
state.currentSongChartScrollSpeed = event.target.value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.currentSongChartScrollSpeed = 1.0;
|
||||||
|
}
|
||||||
|
labelScrollSpeed.text = 'Scroll Speed: ${state.currentSongChartScrollSpeed}x';
|
||||||
|
};
|
||||||
|
|
||||||
|
buttonCharacterOpponent.onClick = function(_) {
|
||||||
|
state.openCharacterDropdown(CharacterType.DAD, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
buttonCharacterGirlfriend.onClick = function(_) {
|
||||||
|
state.openCharacterDropdown(CharacterType.GF, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
buttonCharacterPlayer.onClick = function(_) {
|
||||||
|
state.openCharacterDropdown(CharacterType.BF, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function refresh():Void
|
||||||
|
{
|
||||||
|
inputSongName.value = state.currentSongMetadata.songName;
|
||||||
|
inputSongArtist.value = state.currentSongMetadata.artist;
|
||||||
|
inputStage.value = state.currentSongMetadata.playData.stage;
|
||||||
|
inputNoteStyle.value = state.currentSongMetadata.playData.noteStyle;
|
||||||
|
inputBPM.value = state.currentSongMetadata.timeChanges[0].bpm;
|
||||||
|
inputScrollSpeed.value = state.currentSongChartScrollSpeed;
|
||||||
|
labelScrollSpeed.text = 'Scroll Speed: ${state.currentSongChartScrollSpeed}x';
|
||||||
|
frameVariation.text = 'Variation: ${state.selectedVariation.toTitleCase()}';
|
||||||
|
frameDifficulty.text = 'Difficulty: ${state.selectedDifficulty.toTitleCase()}';
|
||||||
|
|
||||||
|
var stageId:String = state.currentSongMetadata.playData.stage;
|
||||||
|
var stageData:Null<StageData> = StageDataParser.parseStageData(stageId);
|
||||||
|
if (inputStage != null)
|
||||||
|
{
|
||||||
|
inputStage.value = (stageData != null) ?
|
||||||
|
{id: stageId, text: stageData.name} :
|
||||||
|
{id: "mainStage", text: "Main Stage"};
|
||||||
|
}
|
||||||
|
|
||||||
|
var LIMIT = 6;
|
||||||
|
|
||||||
|
var charDataOpponent:CharacterData = CharacterDataParser.fetchCharacterData(state.currentSongMetadata.playData.characters.opponent);
|
||||||
|
buttonCharacterOpponent.icon = CharacterDataParser.getCharPixelIconAsset(state.currentSongMetadata.playData.characters.opponent);
|
||||||
|
buttonCharacterOpponent.text = charDataOpponent.name.length > LIMIT ? '${charDataOpponent.name.substr(0, LIMIT)}.' : '${charDataOpponent.name}';
|
||||||
|
|
||||||
|
var charDataGirlfriend:CharacterData = CharacterDataParser.fetchCharacterData(state.currentSongMetadata.playData.characters.girlfriend);
|
||||||
|
buttonCharacterGirlfriend.icon = CharacterDataParser.getCharPixelIconAsset(state.currentSongMetadata.playData.characters.girlfriend);
|
||||||
|
buttonCharacterGirlfriend.text = charDataGirlfriend.name.length > LIMIT ? '${charDataGirlfriend.name.substr(0, LIMIT)}.' : '${charDataGirlfriend.name}';
|
||||||
|
|
||||||
|
var charDataPlayer:CharacterData = CharacterDataParser.fetchCharacterData(state.currentSongMetadata.playData.characters.player);
|
||||||
|
buttonCharacterPlayer.icon = CharacterDataParser.getCharPixelIconAsset(state.currentSongMetadata.playData.characters.player);
|
||||||
|
buttonCharacterPlayer.text = charDataPlayer.name.length > LIMIT ? '${charDataPlayer.name.substr(0, LIMIT)}.' : '${charDataPlayer.name}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function build(state:ChartEditorState):ChartEditorMetadataToolbox
|
||||||
|
{
|
||||||
|
return new ChartEditorMetadataToolbox(state);
|
||||||
|
}
|
||||||
|
}
|
|
@ -175,6 +175,7 @@ class SongMenuItem extends FlxSpriteGroup
|
||||||
trace(char);
|
trace(char);
|
||||||
|
|
||||||
// TODO: Put this in the character metadata where it belongs.
|
// TODO: Put this in the character metadata where it belongs.
|
||||||
|
// TODO: Also, can use CharacterDataParser.getCharPixelIconAsset()
|
||||||
switch (char)
|
switch (char)
|
||||||
{
|
{
|
||||||
case "monster-christmas":
|
case "monster-christmas":
|
||||||
|
|
Loading…
Reference in a new issue