2023-12-12 10:24:43 +00:00
package funkin . ui . debug . charting . toolboxes ;
import funkin . play . character . BaseCharacter . CharacterType ;
import funkin . play . character . CharacterData ;
2024-01-16 21:49:15 +00:00
import funkin . data . stage . StageData ;
import funkin . data . stage . StageRegistry ;
2023-12-12 10:24:43 +00:00
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 ;
2024-01-16 21:49:15 +00:00
import funkin . play . stage . Stage ;
2023-12-12 10:24:43 +00:00
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 ( " a s s e t s / e x c l u d e / d a t a / u i / c h a r t - e d i t o r / t o o l b o x e s / m e t a d a t a . x m l " ) )
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 ;
2023-12-16 02:09:01 +00:00
public function n e w ( chartEditorState2 : ChartEditorState )
2023-12-12 10:24:43 +00:00
{
2023-12-16 02:09:01 +00:00
super ( chartEditorState2 ) ;
2023-12-12 10:24:43 +00:00
initialize ( ) ;
this . onDialogClosed = onClose ;
}
function onClose ( event : UIEvent )
{
2023-12-16 02:09:01 +00:00
chartEditorState . menubarItemToggleToolboxMetadata . selected = false ;
2023-12-12 10:24:43 +00:00
}
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 ( ' i n v a l i d - v a l u e ' ) ;
2023-12-16 02:09:01 +00:00
chartEditorState . currentSongMetadata . songName = event . target . text ;
2023-12-12 10:24:43 +00:00
}
e lse
{
2023-12-16 02:09:01 +00:00
chartEditorState . currentSongMetadata . songName = ' ' ;
2023-12-12 10:24:43 +00:00
}
} ;
inputSongArtist . onChange = function ( event : UIEvent ) {
var valid: Bool = event . target . text != null && event . target . text != ' ' ;
if ( valid )
{
inputSongArtist . removeClass ( ' i n v a l i d - v a l u e ' ) ;
2023-12-16 02:09:01 +00:00
chartEditorState . currentSongMetadata . artist = event . target . text ;
2023-12-12 10:24:43 +00:00
}
e lse
{
2023-12-16 02:09:01 +00:00
chartEditorState . currentSongMetadata . artist = ' ' ;
2023-12-12 10:24:43 +00:00
}
} ;
inputStage . onChange = function ( event : UIEvent ) {
var valid: Bool = event . data != null && event . data . id != null ;
if ( valid )
{
2023-12-16 02:09:01 +00:00
chartEditorState . currentSongMetadata . playData . stage = event . data . id ;
2023-12-12 10:24:43 +00:00
}
} ;
2023-12-16 02:09:01 +00:00
var startingValueStage = ChartEditorDropdowns . populateDropdownWithStages ( inputStage , chartEditorState . currentSongMetadata . playData . stage ) ;
2023-12-12 10:24:43 +00:00
inputStage . value = startingValueStage ;
inputNoteStyle . onChange = function ( event : UIEvent ) {
if ( event . data ? . id == null ) r e t u r n ;
2023-12-16 02:09:01 +00:00
chartEditorState . currentSongNoteStyle = event . data . id ;
2023-12-12 10:24:43 +00:00
} ;
inputBPM . onChange = function ( event : UIEvent ) {
if ( event . value == null || event . value <= 0 ) return ;
// Use a command so we can undo/redo this action.
2023-12-16 02:09:01 +00:00
var startingBPM = chartEditorState . currentSongMetadata . timeChanges [ 0 ] . bpm ;
2023-12-12 10:24:43 +00:00
if ( event . value != startingBPM )
{
2023-12-16 02:09:01 +00:00
chartEditorState . performCommand ( new ChangeStartingBPMCommand ( event . value ) ) ;
2023-12-12 10:24:43 +00:00
}
} ;
2024-01-05 07:35:41 +00:00
inputTimeSignature . onChange = function ( event : UIEvent ) {
var timeSignatureStr: String = event . data . text ;
var timeSignature = timeSignatureStr . split ( ' / ' ) ;
if ( timeSignature . length != 2 ) return ;
var timeSignatureNum: Int = Std . parseInt ( timeSignature [ 0 ] ) ;
var timeSignatureDen: Int = Std . parseInt ( timeSignature [ 1 ] ) ;
var previousTimeSignatureNum: Int = chartEditorState . currentSongMetadata . timeChanges [ 0 ] . timeSignatureNum ;
var previousTimeSignatureDen: Int = chartEditorState . currentSongMetadata . timeChanges [ 0 ] . timeSignatureDen ;
if ( timeSignatureNum == previousTimeSignatureNum && timeSignatureDen == previousTimeSignatureDen ) return ;
chartEditorState . currentSongMetadata . timeChanges [ 0 ] . timeSignatureNum = timeSignatureNum ;
chartEditorState . currentSongMetadata . timeChanges [ 0 ] . timeSignatureDen = timeSignatureDen ;
trace ( ' T i m e s i g n a t u r e c h a n g e d t o ${ timeSignatureNum } / ${ timeSignatureDen } ' ) ;
chartEditorState . updateTimeSignature ( ) ;
} ;
2023-12-12 10:24:43 +00:00
inputOffsetInst . onChange = function ( event : UIEvent ) {
if ( event . value == null ) return ;
2023-12-16 02:09:01 +00:00
chartEditorState . currentInstrumentalOffset = event . value ;
2023-12-14 21:56:20 +00:00
Conductor . instance . instrumentalOffset = event . value ;
2023-12-12 10:24:43 +00:00
// Update song length.
2024-01-02 19:14:26 +00:00
chartEditorState . songLengthInMs = ( chartEditorState . audioInstTrack ? . length ? ? 1000.0 ) + C o n d u c t o r . i n s t a n c e . i n s t r u m e n t a l O f f s e t ;
2023-12-12 10:24:43 +00:00
} ;
inputOffsetVocal . onChange = function ( event : UIEvent ) {
if ( event . value == null ) return ;
2023-12-16 02:09:01 +00:00
chartEditorState . currentSongMetadata . offsets . setVocalOffset ( chartEditorState . currentSongMetadata . playData . characters . player , event . value ) ;
2023-12-12 10:24:43 +00:00
} ;
inputScrollSpeed . onChange = function ( event : UIEvent ) {
var valid: Bool = event . target . value != null && event . target . value > 0 ;
if ( valid )
{
inputScrollSpeed . removeClass ( ' i n v a l i d - v a l u e ' ) ;
2023-12-16 02:09:01 +00:00
chartEditorState . currentSongChartScrollSpeed = event . target . value ;
2023-12-12 10:24:43 +00:00
}
e lse
{
2023-12-16 02:09:01 +00:00
chartEditorState . currentSongChartScrollSpeed = 1.0 ;
2023-12-12 10:24:43 +00:00
}
2023-12-16 02:09:01 +00:00
labelScrollSpeed . text = ' S c r o l l S p e e d : ${ chartEditorState . currentSongChartScrollSpeed } x ' ;
2023-12-12 10:24:43 +00:00
} ;
buttonCharacterOpponent . onClick = function ( _ ) {
2023-12-16 02:09:01 +00:00
chartEditorState . openCharacterDropdown ( CharacterType . DAD , false ) ;
2023-12-12 10:24:43 +00:00
} ;
buttonCharacterGirlfriend . onClick = function ( _ ) {
2023-12-16 02:09:01 +00:00
chartEditorState . openCharacterDropdown ( CharacterType . GF , false ) ;
2023-12-12 10:24:43 +00:00
} ;
buttonCharacterPlayer . onClick = function ( _ ) {
2023-12-16 02:09:01 +00:00
chartEditorState . openCharacterDropdown ( CharacterType . BF , false ) ;
2023-12-12 10:24:43 +00:00
} ;
refresh ( ) ;
}
public override function refresh ( ) : Void
{
2024-01-04 00:53:17 +00:00
super . refresh ( ) ;
2023-12-16 02:09:01 +00:00
inputSongName . value = chartEditorState . currentSongMetadata . songName ;
inputSongArtist . value = chartEditorState . currentSongMetadata . artist ;
inputStage . value = chartEditorState . currentSongMetadata . playData . stage ;
inputNoteStyle . value = chartEditorState . currentSongMetadata . playData . noteStyle ;
inputBPM . value = chartEditorState . currentSongMetadata . timeChanges [ 0 ] . bpm ;
inputScrollSpeed . value = chartEditorState . currentSongChartScrollSpeed ;
labelScrollSpeed . text = ' S c r o l l S p e e d : ${ chartEditorState . currentSongChartScrollSpeed } x ' ;
frameVariation . text = ' V a r i a t i o n : ${ chartEditorState . selectedVariation . toTitleCase ( ) } ' ;
frameDifficulty . text = ' D i f f i c u l t y : ${ chartEditorState . selectedDifficulty . toTitleCase ( ) } ' ;
2024-01-05 07:35:41 +00:00
var currentTimeSignature = ' ${ chartEditorState . currentSongMetadata . timeChanges [ 0 ] . timeSignatureNum } / ${ chartEditorState . currentSongMetadata . timeChanges [ 0 ] . timeSignatureDen } ' ;
trace ( ' S e t t i n g t i m e s i g n a t u r e t o ${ currentTimeSignature } ' ) ;
inputTimeSignature . value = { id : currentTimeSignature , text : currentTimeSignature } ;
2023-12-16 02:09:01 +00:00
var stageId: String = chartEditorState . currentSongMetadata . playData . stage ;
2024-01-16 21:49:15 +00:00
var stage: Null < Stage > = StageRegistry . instance . fetchEntry ( stageId ) ;
2023-12-12 10:24:43 +00:00
if ( inputStage != null )
{
2024-01-16 21:49:15 +00:00
inputStage . value = ( stage != null ) ?
{ id : stage . id , text : stage . stageName } :
2023-12-12 10:24:43 +00:00
{ id : " m a i n S t a g e " , text : " M a i n S t a g e " } ;
}
var LIMIT = 6 ;
2023-12-19 06:28:13 +00:00
var charDataOpponent: Null < CharacterData > = CharacterDataParser . fetchCharacterData ( chartEditorState . currentSongMetadata . playData . characters . opponent ) ;
if ( charDataOpponent != null )
{
buttonCharacterOpponent . icon = CharacterDataParser . getCharPixelIconAsset ( chartEditorState . currentSongMetadata . playData . characters . opponent ) ;
buttonCharacterOpponent . text = charDataOpponent . name . length > LIMIT ? ' ${ charDataOpponent . name . substr ( 0 , LIMIT ) } . ' : ' ${ charDataOpponent . name } ' ;
}
e lse
{
buttonCharacterOpponent . icon = null ;
buttonCharacterOpponent . text = " N o n e " ;
}
2023-12-12 10:24:43 +00:00
2023-12-19 06:28:13 +00:00
var charDataGirlfriend: Null < CharacterData > = CharacterDataParser . fetchCharacterData ( chartEditorState . currentSongMetadata . playData . characters . girlfriend ) ;
if ( charDataGirlfriend != null )
{
buttonCharacterGirlfriend . icon = CharacterDataParser . getCharPixelIconAsset ( chartEditorState . currentSongMetadata . playData . characters . girlfriend ) ;
buttonCharacterGirlfriend . text = charDataGirlfriend . name . length > LIMIT ? ' ${ charDataGirlfriend . name . substr ( 0 , LIMIT ) } . ' : ' ${ charDataGirlfriend . name } ' ;
}
e lse
{
buttonCharacterGirlfriend . icon = null ;
buttonCharacterGirlfriend . text = " N o n e " ;
}
2023-12-12 10:24:43 +00:00
2023-12-19 06:28:13 +00:00
var charDataPlayer: Null < CharacterData > = CharacterDataParser . fetchCharacterData ( chartEditorState . currentSongMetadata . playData . characters . player ) ;
if ( charDataPlayer != null )
{
buttonCharacterPlayer . icon = CharacterDataParser . getCharPixelIconAsset ( chartEditorState . currentSongMetadata . playData . characters . player ) ;
buttonCharacterPlayer . text = charDataPlayer . name . length > LIMIT ? ' ${ charDataPlayer . name . substr ( 0 , LIMIT ) } . ' : ' ${ charDataPlayer . name } ' ;
}
e lse
{
buttonCharacterPlayer . icon = null ;
buttonCharacterPlayer . text = " N o n e " ;
}
2023-12-12 10:24:43 +00:00
}
2023-12-16 02:09:01 +00:00
public static function build ( chartEditorState : ChartEditorState ) : ChartEditorMetadataToolbox
2023-12-12 10:24:43 +00:00
{
2023-12-16 02:09:01 +00:00
return new ChartEditorMetadataToolbox ( chartEditorState ) ;
2023-12-12 10:24:43 +00:00
}
}