import { StaffLine } from "./StaffLine" ; import { Instrument } from "../Instrument" ; import { BoundingBox } from "./BoundingBox" ; import { Fraction } from "../../Common/DataObjects/Fraction" ; import { SourceMeasure } from "../VoiceData/SourceMeasure" ; import { InstrumentalGroup } from "../InstrumentalGroup" ; import { TextAlignmentEnum } from "../../Common/Enums/TextAlignment" ; import { GraphicalMusicPage } from "./GraphicalMusicPage" ; import { GraphicalLabel } from "./GraphicalLabel" ; import { GraphicalMeasure } from "./GraphicalMeasure" ; import { GraphicalObject } from "./GraphicalObject" ; import { EngravingRules } from "./EngravingRules" ; import { PointF2D } from "../../Common/DataObjects/PointF2D" ; import { GraphicalStaffEntry } from "./GraphicalStaffEntry" ; import { SystemLinesEnum } from "./SystemLinesEnum" ; import { Dictionary } from "typescript-collections" ; import { GraphicalComment } from "./GraphicalComment" ; import { GraphicalMarkedArea } from "./GraphicalMarkedArea" ; import { SystemLine } from "./SystemLine" ; import { SystemLinePosition } from "./SystemLinePosition" ; import { Staff } from "../VoiceData/Staff" ; import { Label } from "../Label" ; /**
 * A MusicSystem contains the [[StaffLine]]s for all instruments, until a line break
 */ export abstract class MusicSystem extends GraphicalObject { public needsToBeRedrawn : boolean = true ; public rules : EngravingRules ; protected parent : GraphicalMusicPage ; protected id : number ; protected staffLines : StaffLine [ ] = [ ] ; protected graphicalMeasures : GraphicalMeasure [ ] [ ] = [ ] ; /** Dictionary of (Instruments and) labels.
     * note that the key needs to be unique, GraphicalLabel is not unique yet.
     * That is why the labels are labels.values() and not labels.keys().
     */ protected labels : Dictionary < Instrument , GraphicalLabel > = new Dictionary < Instrument , GraphicalLabel > ( ) ; protected measureNumberLabels : GraphicalLabel [ ] = [ ] ; protected maxLabelLength : number ; protected objectsToRedraw : [ Object [ ] , Object ] [ ] = [ ] ; protected instrumentBrackets : GraphicalObject [ ] = [ ] ; protected groupBrackets : GraphicalObject [ ] = [ ] ; protected graphicalMarkedAreas : GraphicalMarkedArea [ ] = [ ] ; protected graphicalComments : GraphicalComment [ ] = [ ] ; protected systemLines : SystemLine [ ] = [ ] ; public breaksPage : boolean = false ; constructor ( id ) { super ( ) ; this . id = id ; this . boundingBox = new BoundingBox ( this ) ; this . maxLabelLength = 0.0 ; } public get Parent ( ) : GraphicalMusicPage { return this . parent ; } public set Parent ( value ) { if ( this . parent ) { const index = this . parent . MusicSystems . indexOf ( this , 0 ) ; if ( index > - 1 ) { this . parent . MusicSystems . splice ( index , 1 ) ; } } this . parent = value ; this . boundingBox . Parent = value . PositionAndShape ; } public get NextSystem ( ) : MusicSystem { const idxInParent = this . Parent . MusicSystems . indexOf ( this ) ; return idxInParent !== this . Parent . MusicSystems . length ? this . Parent . MusicSystems [ idxInParent + 1 ] : undefined ; } public get StaffLines ( ) : StaffLine [ ] { return this . staffLines ; } public get GraphicalMeasures ( ) : GraphicalMeasure [ ] [ ] { return this . graphicalMeasures ; } public get MeasureNumberLabels ( ) : GraphicalLabel [ ] { return this . measureNumberLabels ; } public get Labels ( ) : GraphicalLabel [ ] { return this . labels . values ( ) ; } public get ObjectsToRedraw ( ) : [ Object [ ] , Object ] [ ] { return this . objectsToRedraw ; } public get InstrumentBrackets ( ) : GraphicalObject [ ] { return this . instrumentBrackets ; } public get GroupBrackets ( ) : GraphicalObject [ ] { return this . groupBrackets ; } public get GraphicalMarkedAreas ( ) : GraphicalMarkedArea [ ] { return this . graphicalMarkedAreas ; } public get GraphicalComments ( ) : GraphicalComment [ ] { return this . graphicalComments ; } public get SystemLines ( ) : SystemLine [ ] { return this . systemLines ; } public get Id ( ) : number { return this . id ; } param lineWidth param systemLabelsRightMargin public createSystemLeftLine ( lineWidth , systemLabelsRightMargin , isFirstSystem ) { let xPosition = - lineWidth / 2 ; if ( isFirstSystem ) { xPosition = this . maxLabelLength + systemLabelsRightMargin - lineWidth / 2 ; } const top = this . staffLines [ 0 ] . Measures [ 0 ] ; let bottom = undefined ; if ( this . staffLines . length > 1 ) { bottom = this . staffLines [ this . staffLines . length - 1 ] . Measures [ 0 ] ; } const leftSystemLine = this . createSystemLine ( xPosition , lineWidth , SystemLinesEnum . SingleThin , SystemLinePosition . MeasureBegin , this , top , bottom ) ; this . SystemLines . push ( leftSystemLine ) ; leftSystemLine . PositionAndShape . RelativePosition = new PointF2D ( xPosition , 0 ) ; leftSystemLine . PositionAndShape . BorderLeft = 0 ; leftSystemLine . PositionAndShape . BorderRight = lineWidth ; leftSystemLine . PositionAndShape . BorderTop = 0 ; leftSystemLine . PositionAndShape . BorderBottom = this . boundingBox . Size . height ; this . createLinesForSystemLine ( leftSystemLine ) ; } param xPosition param lineWidth param lineType param linePosition param measureIndex param measure public createVerticalLineForMeasure ( xPosition , lineWidth , lineType , linePosition , measureIndex , measure ) { const staffLine = measure . ParentStaffLine ; const staffLineRelative = new PointF2D ( staffLine . PositionAndShape . RelativePosition . x , staffLine . PositionAndShape . RelativePosition . y ) ; const staves = staffLine . ParentStaff . ParentInstrument . Staves ; if ( staffLine . ParentStaff === staves [ 0 ] ) { let bottomMeasure = undefined ; if ( staves . length > 1 ) { bottomMeasure = this . getBottomStaffLine ( staffLine ) . Measures [ measureIndex ] ; } const singleVerticalLineAfterMeasure = this . createSystemLine ( xPosition , lineWidth , lineType , linePosition , this , measure , bottomMeasure ) ; const systemXPosition = staffLineRelative . x + xPosition ; singleVerticalLineAfterMeasure . PositionAndShape . RelativePosition = new PointF2D ( systemXPosition , 0 ) ; singleVerticalLineAfterMeasure . PositionAndShape . BorderLeft = 0 ; singleVerticalLineAfterMeasure . PositionAndShape . BorderRight = lineWidth ; this . SystemLines . push ( singleVerticalLineAfterMeasure ) ; } } param rules public setYPositionsToVerticalLineObjectsAndCreateLines ( rules ) { } public calculateBorders ( rules ) { } public alignBeginInstructions ( ) { } public GetLeftBorderAbsoluteXPosition ( ) { return this . StaffLines [ 0 ] . PositionAndShape . AbsolutePosition . x + this . StaffLines [ 0 ] . Measures [ 0 ] . beginInstructionsWidth ; } public GetRightBorderAbsoluteXPosition ( ) { return this . StaffLines [ 0 ] . PositionAndShape . AbsolutePosition . x + this . StaffLines [ 0 ] . StaffLines [ 0 ] . End . x ; } public AddGraphicalMeasures ( graphicalMeasures ) { for ( let idx = 0 , len = graphicalMeasures . length ; idx < len ; ++ idx ) { const graphicalMeasure = graphicalMeasures [ idx ] ; graphicalMeasure . ParentMusicSystem = this ; } this . graphicalMeasures . push ( graphicalMeasures ) ; } public GetSystemsFirstTimeStamp ( ) { return this . graphicalMeasures [ 0 ] [ 0 ] . parentSourceMeasure . AbsoluteTimestamp ; } public GetSystemsLastTimeStamp ( ) { const m = this . graphicalMeasures [ this . graphicalMeasures . length - 1 ] [ 0 ] . parentSourceMeasure ; return Fraction . plus ( m . AbsoluteTimestamp , m . Duration ) ; } param instruments param staffHeight public createInstrumentBrackets ( instruments , staffHeight ) { for ( let idx = 0 , len = instruments . length ; idx < len ; ++ idx ) { const instrument = instruments [ idx ] ; if ( instrument . Staves . length > 1 ) { let firstStaffLine = undefined , lastStaffLine = undefined ; for ( let idx2 = 0 , len2 = this . staffLines . length ; idx2 < len2 ; ++ idx2 ) { const staffLine = this . staffLines [ idx2 ] ; if ( staffLine . ParentStaff === instrument . Staves [ 0 ] ) { firstStaffLine = staffLine ; } if ( staffLine . ParentStaff === instrument . Staves [ instrument . Staves . length - 1 ] ) { lastStaffLine = staffLine ; } } if ( firstStaffLine && lastStaffLine ) { this . createInstrumentBracket ( firstStaffLine , lastStaffLine ) ; } } } } param instrumentGroups param staffHeight param recursionDepth public createGroupBrackets ( instrumentGroups , staffHeight , recursionDepth ) { for ( let idx = 0 , len = instrumentGroups . length ; idx < len ; ++ idx ) { const instrumentGroup = instrumentGroups [ idx ] ; if ( instrumentGroup . InstrumentalGroups . length < 1 ) { continue ; } const instrument1 = this . findFirstVisibleInstrumentInInstrumentalGroup ( instrumentGroup ) ; const instrument2 = this . findLastVisibleInstrumentInInstrumentalGroup ( instrumentGroup ) ; if ( ! instrument1 || ! instrument2 ) { continue ; } let firstStaffLine = undefined ; let lastStaffLine = undefined ; for ( let idx2 = 0 , len2 = this . staffLines . length ; idx2 < len2 ; ++ idx2 ) { const staffLine = this . staffLines [ idx2 ] ; if ( staffLine . ParentStaff === instrument1 . Staves [ 0 ] ) { firstStaffLine = staffLine ; } if ( staffLine . ParentStaff === instrument2 . Staves [ 0 ] ) { lastStaffLine = staffLine ; } } if ( firstStaffLine && lastStaffLine ) { this . createGroupBracket ( firstStaffLine , lastStaffLine , recursionDepth ) ; } if ( instrumentGroup . InstrumentalGroups . length < 1 ) { continue ; } this . createGroupBrackets ( instrumentGroup . InstrumentalGroups , staffHeight , recursionDepth + 1 ) ; } } param instrumentLabelTextHeight param systemLabelsRightMargin param labelMarginBorderFactor public createMusicSystemLabel ( instrumentLabelTextHeight , systemLabelsRightMargin , labelMarginBorderFactor , isFirstSystem = false ) { const originalSystemLabelsRightMargin = systemLabelsRightMargin ; for ( let idx = 0 , len = this . staffLines . length ; idx < len ; ++ idx ) { const instrument = this . staffLines [ idx ] . ParentStaff . ParentInstrument ; let instrNameLabel ; if ( isFirstSystem ) { instrNameLabel = instrument . NameLabel ; if ( ! this . rules . RenderPartNames || ! instrNameLabel ?. print ) { instrNameLabel = new Label ( "" , instrument . NameLabel . textAlignment , instrument . NameLabel . font ) ; systemLabelsRightMargin = 0 ; } } else { if ( ! this . rules . RenderPartAbbreviations || ! this . rules . RenderPartNames || this . staffLines . length === 1 || ! instrument . PartAbbreviation || instrument . PartAbbreviation === "" ) { return ; } const labelText = instrument . PartAbbreviation ; instrNameLabel = new Label ( labelText , instrument . NameLabel . textAlignment , instrument . NameLabel . font ) ; } if ( instrument ?. NameLabel ?. print ) { const graphicalLabel = new GraphicalLabel ( instrNameLabel , instrumentLabelTextHeight , TextAlignmentEnum . LeftCenter , this . rules , this . boundingBox ) ; graphicalLabel . setLabelPositionAndShapeBorders ( ) ; this . labels . setValue ( instrument , graphicalLabel ) ; } else { systemLabelsRightMargin = 0 ; } } this . maxLabelLength = 0.0 ; const labels = this . labels . values ( ) ; for ( let idx = 0 , len = labels . length ; idx < len ; ++ idx ) { const label = labels [ idx ] ; if ( ! label . Label . print ) { continue ; } if ( label . PositionAndShape . Size . width > this . maxLabelLength ) { this . maxLabelLength = label . PositionAndShape . Size . width ; systemLabelsRightMargin = originalSystemLabelsRightMargin ; } } this . updateMusicSystemStaffLineXPosition ( systemLabelsRightMargin ) ; } /**
     * Set the Y-Positions for the MusicSystem's Labels.
     */ public setMusicSystemLabelsYPosition ( ) { this . labels . forEach ( ( key , value ) : void => { let ypositionSum = 0 ; let staffCounter = 0 ; for ( let i = 0 ; i < this . staffLines . length ; i ++ ) { if ( this . staffLines [ i ] . ParentStaff . ParentInstrument === key ) { for ( let j = i ; j < this . staffLines . length ; j ++ ) { const staffLine = this . staffLines [ j ] ; if ( staffLine . ParentStaff . ParentInstrument !== key ) { break ; } ypositionSum += staffLine . PositionAndShape . RelativePosition . y ; staffCounter ++ ; } break ; } } if ( staffCounter > 0 ) { value . PositionAndShape . RelativePosition = new PointF2D ( 0.0 , ypositionSum / staffCounter + 2.0 ) ; } } ) ; } returns { boolean } public checkStaffEntriesForStaffEntryLink ( ) { let first = false ; let second = false ; for ( let i = 0 ; i < this . staffLines . length - 1 ; i ++ ) { for ( let idx = 0 , len = this . staffLines [ i ] . Measures . length ; idx < len ; ++ idx ) { const measure = this . staffLines [ i ] . Measures [ idx ] ; for ( let idx2 = 0 , len2 = measure . staffEntries . length ; idx2 < len2 ; ++ idx2 ) { const staffEntry = measure . staffEntries [ idx2 ] ; if ( staffEntry . sourceStaffEntry . Link ) { first = true ; } } } for ( let idx = 0 , len = this . staffLines [ i + 1 ] . Measures . length ; idx < len ; ++ idx ) { const measure = this . staffLines [ i + 1 ] . Measures [ idx ] ; for ( let idx2 = 0 , len2 = measure . staffEntries . length ; idx2 < len2 ; ++ idx2 ) { const staffEntry = measure . staffEntries [ idx2 ] ; if ( staffEntry . sourceStaffEntry . Link ) { second = true ; } } } } if ( first && second ) { return true ; } return false ; } public getBottomStaffLine ( topStaffLine ) { const staves = topStaffLine . ParentStaff . ParentInstrument . Staves ; const last = staves [ staves . length - 1 ] ; for ( const line of topStaffLine . ParentMusicSystem . staffLines ) { if ( line . ParentStaff === last ) { return line ; } } return undefined ; } param xPosition param lineWidth param lineType param linePosition param musicSystem param topMeasure param bottomMeasure protected createSystemLine ( xPosition , lineWidth , lineType , linePosition , musicSystem , topMeasure , bottomMeasure = undefined ) { throw new Error ( "not implemented" ) ; } param systemLine protected createLinesForSystemLine ( systemLine ) { } returns { number } protected calcBracketsWidth ( ) { let width = 0 ; for ( let idx = 0 , len = this . GroupBrackets . length ; idx < len ; ++ idx ) { const groupBracket = this . GroupBrackets [ idx ] ; width = Math . max ( width , groupBracket . PositionAndShape . Size . width ) ; } for ( let idx2 = 0 , len2 = this . InstrumentBrackets . length ; idx2 < len2 ; ++ idx2 ) { const instrumentBracket = this . InstrumentBrackets [ idx2 ] ; width = Math . max ( width , instrumentBracket . PositionAndShape . Size . width ) ; } return width ; } protected createInstrumentBracket ( firstStaffLine , lastStaffLine ) { } protected createGroupBracket ( firstStaffLine , lastStaffLine , recursionDepth ) { } private findFirstVisibleInstrumentInInstrumentalGroup ( instrumentalGroup ) { for ( let idx = 0 , len = instrumentalGroup . InstrumentalGroups . length ; idx < len ; ++ idx ) { const groupOrInstrument = instrumentalGroup . InstrumentalGroups [ idx ] ; if ( groupOrInstrument instanceof Instrument ) { if ( ( < Instrument > groupOrInstrument ) . Visible === true ) { return < Instrument > groupOrInstrument ; } continue ; } return this . findFirstVisibleInstrumentInInstrumentalGroup ( groupOrInstrument ) ; } return undefined ; } private findLastVisibleInstrumentInInstrumentalGroup ( instrumentalGroup ) { let groupOrInstrument ; for ( let i = instrumentalGroup . InstrumentalGroups . length - 1 ; i >= 0 ; i -- ) { groupOrInstrument = instrumentalGroup . InstrumentalGroups [ i ] ; if ( groupOrInstrument instanceof Instrument ) { if ( ( < Instrument > groupOrInstrument ) . Visible === true ) { return < Instrument > groupOrInstrument ; } continue ; } return this . findLastVisibleInstrumentInInstrumentalGroup ( groupOrInstrument ) ; } return undefined ; } param systemLabelsRightMargin private updateMusicSystemStaffLineXPosition ( systemLabelsRightMargin ) { for ( let idx = 0 , len = this . StaffLines . length ; idx < len ; ++ idx ) { const staffLine = this . StaffLines [ idx ] ; const relative = staffLine . PositionAndShape . RelativePosition ; relative . x = this . maxLabelLength + systemLabelsRightMargin ; staffLine . PositionAndShape . RelativePosition = relative ; staffLine . PositionAndShape . BorderRight = this . boundingBox . Size . width - this . maxLabelLength - systemLabelsRightMargin ; for ( let i = 0 ; i < staffLine . StaffLines . length ; i ++ ) { const lineEnd = new PointF2D ( staffLine . PositionAndShape . Size . width , staffLine . StaffLines [ i ] . End . y ) ; staffLine . StaffLines [ i ] . End = lineEnd ; } } } }