浏览代码

Merge pull request #492 from opensheetmusicdisplay/feat/labelAbbr

feat(Instrument label abbreviations): Added instrument label abbrevia…
Simon 6 年之前
父节点
当前提交
605342b1cb

+ 1 - 1
src/MusicalScore/Graphical/DrawingParameters.ts

@@ -175,7 +175,7 @@ export class DrawingParameters {
 
     public set DrawPartNames(value: boolean) {
         this.drawPartNames = value;
-        EngravingRules.Rules.RenderInstrumentNames = value;
+        EngravingRules.Rules.RenderPartNames = value;
     }
 
     public get FingeringPosition(): PlacementEnum {

+ 14 - 6
src/MusicalScore/Graphical/EngravingRules.ts

@@ -190,7 +190,8 @@ export class EngravingRules {
     private renderTitle: boolean;
     private renderSubtitle: boolean;
     private renderLyricist: boolean;
-    private renderInstrumentNames: boolean;
+    private renderPartNames: boolean;
+    private renderPartAbbreviations: boolean;
     private renderFingerings: boolean;
     private dynamicExpressionMaxDistance: number;
     private dynamicExpressionSpacer: number;
@@ -403,7 +404,8 @@ export class EngravingRules {
         this.renderTitle = true;
         this.renderSubtitle = true;
         this.renderLyricist = true;
-        this.renderInstrumentNames = true;
+        this.renderPartNames = true;
+        this.renderPartAbbreviations = true;
         this.renderFingerings = true;
         this.fingeringPosition = PlacementEnum.Left; // easier to get bounding box, and safer for vertical layout
         this.fingeringInsideStafflines = false;
@@ -1408,11 +1410,17 @@ export class EngravingRules {
     public set RenderLyricist(value: boolean) {
         this.renderLyricist = value;
     }
-    public get RenderInstrumentNames(): boolean {
-        return this.renderInstrumentNames;
+    public get RenderPartNames(): boolean {
+        return this.renderPartNames;
     }
-    public set RenderInstrumentNames(value: boolean) {
-        this.renderInstrumentNames = value;
+    public set RenderPartNames(value: boolean) {
+        this.renderPartNames = value;
+    }
+    public get RenderPartAbbreviations(): boolean {
+        return this.renderPartAbbreviations;
+    }
+    public set RenderPartAbbreviations(value: boolean) {
+        this.renderPartAbbreviations = value;
     }
     public get RenderFingerings(): boolean {
         return this.renderFingerings;

+ 7 - 7
src/MusicalScore/Graphical/GraphicalLabel.ts

@@ -1,9 +1,9 @@
-import {Label} from "../Label";
-import {TextAlignmentEnum} from "../../Common/Enums/TextAlignment";
-import {Clickable} from "./Clickable";
-import {BoundingBox} from "./BoundingBox";
-import {EngravingRules} from "./EngravingRules";
-import {MusicSheetCalculator} from "./MusicSheetCalculator";
+import { TextAlignmentEnum } from "../../Common/Enums/TextAlignment";
+import { Label } from "../Label";
+import { BoundingBox } from "./BoundingBox";
+import { Clickable } from "./Clickable";
+import { EngravingRules } from "./EngravingRules";
+import { MusicSheetCalculator } from "./MusicSheetCalculator";
 
 /**
  * The graphical counterpart of a Label
@@ -31,7 +31,7 @@ export class GraphicalLabel extends Clickable {
     }
 
     public toString(): string {
-        return this.label.text;
+        return `${this.label.text} (${this.boundingBox.RelativePosition.x},${this.boundingBox.RelativePosition.y})`;
     }
 
     /**

+ 4 - 1
src/MusicalScore/Graphical/MusicSheetCalculator.ts

@@ -1591,7 +1591,7 @@ export abstract class MusicSheetCalculator {
     }
 
     protected maxInstrNameLabelLength(): number {
-        if (!EngravingRules.Rules.RenderInstrumentNames) {
+        if (!EngravingRules.Rules.RenderPartNames) {
             return 0;
         }
         let maxLabelLength: number = 0.0;
@@ -1845,6 +1845,9 @@ export abstract class MusicSheetCalculator {
         for (let i: number = 1; i < tie.Notes.length; i++) {
             startNote = startGse.findEndTieGraphicalNoteFromNote(tie.Notes[i - 1]);
             endGse = this.graphicalMusicSheet.GetGraphicalFromSourceStaffEntry(tie.Notes[i].ParentStaffEntry);
+            if (!endGse) {
+                continue;
+            }
             endNote = endGse.findEndTieGraphicalNoteFromNote(tie.Notes[i]);
             if (startNote !== undefined && endNote !== undefined && endGse !== undefined) {
                 if (!startNote.sourceNote.PrintObject || !endNote.sourceNote.PrintObject) {

+ 1 - 1
src/MusicalScore/Graphical/MusicSheetDrawer.ts

@@ -308,7 +308,7 @@ export abstract class MusicSheetDrawer {
         for (const systemLine of musicSystem.SystemLines) {
             this.drawSystemLineObject(systemLine);
         }
-        if (musicSystem === musicSystem.Parent.MusicSystems[0] && musicSystem.Parent === musicSystem.Parent.Parent.MusicPages[0]) {
+        if (musicSystem.Parent === musicSystem.Parent.Parent.MusicPages[0]) {
             for (const label of musicSystem.Labels) {
                 this.drawLabel(label, <number>GraphicalLayers.Notes);
             }

+ 31 - 11
src/MusicalScore/Graphical/MusicSystem.ts

@@ -19,6 +19,7 @@ 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
@@ -29,7 +30,11 @@ export abstract class MusicSystem extends GraphicalObject {
     protected id: number;
     protected staffLines: StaffLine[] = [];
     protected graphicalMeasures: GraphicalMeasure[][] = [];
-    protected labels: Dictionary<GraphicalLabel, Instrument> = new Dictionary<GraphicalLabel, Instrument>();
+    /** 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][] = [];
@@ -75,7 +80,7 @@ export abstract class MusicSystem extends GraphicalObject {
     }
 
     public get Labels(): GraphicalLabel[] {
-        return this.labels.keys();
+        return this.labels.values();
     }
 
     public get ObjectsToRedraw(): [Object[], Object][] {
@@ -274,15 +279,30 @@ export abstract class MusicSystem extends GraphicalObject {
      * @param labelMarginBorderFactor
      */
     public createMusicSystemLabel(instrumentLabelTextHeight: number, systemLabelsRightMargin: number, labelMarginBorderFactor: number): void {
-        if (this.parent === this.parent.Parent.MusicPages[0] && this === this.parent.MusicSystems[0]) {
+        if (this.parent === this.parent.Parent.MusicPages[0]) {
             const instruments: Instrument[] = this.parent.Parent.ParentMusicSheet.getVisibleInstruments();
             for (let idx: number = 0, len: number = instruments.length; idx < len; ++idx) {
                 const instrument: Instrument = instruments[idx];
+                let instrNameLabel: Label;
+                if (this !== this.parent.MusicSystems[0]) {
+                    if (!EngravingRules.Rules.RenderPartAbbreviations
+                        // don't render part abbreviations if there's only one instrument/part (could be an option in the future)
+                        || this.Parent.Parent.ParentMusicSheet.Instruments.length === 1
+                        || !instrument.PartAbbreviation
+                        || instrument.PartAbbreviation === "") {
+                        return;
+                    }
+                    const labelText: string = instrument.PartAbbreviation;
+                    // const labelText: string = instrument.NameLabel.text[0] + ".";
+                    instrNameLabel = new Label(labelText, instrument.NameLabel.textAlignment, instrument.NameLabel.font);
+                } else {
+                    instrNameLabel = instrument.NameLabel;
+                }
                 const graphicalLabel: GraphicalLabel = new GraphicalLabel(
-                    instrument.NameLabel, instrumentLabelTextHeight, TextAlignmentEnum.LeftCenter, this.boundingBox
+                    instrNameLabel, instrumentLabelTextHeight, TextAlignmentEnum.LeftCenter, this.boundingBox
                 );
                 graphicalLabel.setLabelPositionAndShapeBorders();
-                this.labels.setValue(graphicalLabel, instrument);
+                this.labels.setValue(instrument, graphicalLabel);
                 // X-Position will be 0 (Label starts at the same PointF_2D with MusicSystem)
                 // Y-Position will be calculated after the y-Spacing
                 // graphicalLabel.PositionAndShape.RelativePosition = new PointF2D(0.0, 0.0);
@@ -290,7 +310,7 @@ export abstract class MusicSystem extends GraphicalObject {
 
             // calculate maxLabelLength (needed for X-Spacing)
             this.maxLabelLength = 0.0;
-            const labels: GraphicalLabel[] = this.labels.keys();
+            const labels: GraphicalLabel[] = this.labels.values();
             for (let idx: number = 0, len: number = labels.length; idx < len; ++idx) {
                 const label: GraphicalLabel = labels[idx];
                 if (label.PositionAndShape.Size.width > this.maxLabelLength) {
@@ -305,15 +325,15 @@ export abstract class MusicSystem extends GraphicalObject {
      * Set the Y-Positions for the MusicSystem's Labels.
      */
     public setMusicSystemLabelsYPosition(): void {
-        if (this.parent === this.parent.Parent.MusicPages[0] && this === this.parent.MusicSystems[0]) {
-            this.labels.forEach((key: GraphicalLabel, value: Instrument): void => {
+        if (this.parent === this.parent.Parent.MusicPages[0]) {
+            this.labels.forEach((key: Instrument, value: GraphicalLabel): void => {
                 let ypositionSum: number = 0;
                 let staffCounter: number = 0;
                 for (let i: number = 0; i < this.staffLines.length; i++) {
-                    if (this.staffLines[i].ParentStaff.ParentInstrument === value) {
+                    if (this.staffLines[i].ParentStaff.ParentInstrument === key) {
                         for (let j: number = i; j < this.staffLines.length; j++) {
                             const staffLine: StaffLine = this.staffLines[j];
-                            if (staffLine.ParentStaff.ParentInstrument !== value) {
+                            if (staffLine.ParentStaff.ParentInstrument !== key) {
                                 break;
                             }
                             ypositionSum += staffLine.PositionAndShape.RelativePosition.y;
@@ -323,7 +343,7 @@ export abstract class MusicSystem extends GraphicalObject {
                     }
                 }
                 if (staffCounter > 0) {
-                    key.PositionAndShape.RelativePosition = new PointF2D(0.0, ypositionSum / staffCounter + 2.0);
+                    value.PositionAndShape.RelativePosition = new PointF2D(0.0, ypositionSum / staffCounter + 2.0);
                 }
             });
         }

+ 12 - 7
src/MusicalScore/Graphical/MusicSystemBuilder.ts

@@ -65,13 +65,7 @@ export class MusicSystemBuilder {
         // the first System - create also its Labels
         this.currentSystemParams.currentSystem = this.initMusicSystem();
         this.layoutSystemStaves();
-        if (EngravingRules.Rules.RenderInstrumentNames) {
-            this.currentSystemParams.currentSystem.createMusicSystemLabel(
-                this.rules.InstrumentLabelTextHeight,
-                this.rules.SystemLabelsRightMargin,
-                this.rules.LabelMarginBorderFactor
-            );
-        }
+        this.addSystemLabels();
         this.currentPageHeight += this.currentSystemParams.currentSystem.PositionAndShape.RelativePosition.y;
 
         let numberOfMeasures: number = 0;
@@ -191,6 +185,7 @@ export class MusicSystemBuilder {
         if (this.measureListIndex < this.measureList.length) {
             this.currentSystemParams.currentSystem = this.initMusicSystem();
             this.layoutSystemStaves();
+            this.addSystemLabels();
         }
     }
 
@@ -234,6 +229,16 @@ export class MusicSystemBuilder {
         this.currentSystemParams.systemMeasureIndex++;
     }
 
+    private addSystemLabels(): void {
+        if (EngravingRules.Rules.RenderPartNames) {
+            this.currentSystemParams.currentSystem.createMusicSystemLabel(
+                this.rules.InstrumentLabelTextHeight,
+                this.rules.SystemLabelsRightMargin,
+                this.rules.LabelMarginBorderFactor
+            );
+        }
+    }
+
     /**
      * Create a new [[GraphicalMusicPage]]
      * (for now only one long page is used per music sheet, as we scroll down and have no page flips)

+ 12 - 0
src/MusicalScore/Instrument.ts

@@ -29,6 +29,7 @@ export class Instrument extends InstrumentalGroup {
 
     private lyricVersesNumbers: number[] = [];
     private subInstruments: SubInstrument[] = [];
+    private partAbbreviation: string;
 
     public get Voices(): Voice[] {
         return this.voices;
@@ -103,6 +104,13 @@ export class Instrument extends InstrumentalGroup {
         }
         return undefined;
     }
+    public get PartAbbreviation(): string {
+        return this.partAbbreviation;
+    }
+    public set PartAbbreviation(value: string) {
+        this.partAbbreviation = value;
+    }
+
     public get Visible(): boolean {
         if (this.voices.length > 0) {
             return this.Voices[0].Visible;
@@ -242,4 +250,8 @@ export class Instrument extends InstrumentalGroup {
         }
     }
 
+    // necessary to be unique for MusicSystem.labels Dictionary
+    public toString(): string {
+        return `${this.Name} , id: ${this.id}, idstring: ${this.idString}`;
+    }
 }

+ 2 - 0
src/MusicalScore/ScoreIO/MusicSheetReader.ts

@@ -719,6 +719,8 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                         try {
                             if (partElement.name === "part-name") {
                                 instrument.Name = partElement.value;
+                            } else if (partElement.name === "part-abbreviation") {
+                                instrument.PartAbbreviation = partElement.value;
                             } else if (partElement.name === "score-instrument") {
                                 const subInstrument: SubInstrument = new SubInstrument(instrument);
                                 subInstrument.idString = partElement.firstAttribute.value;

+ 3 - 1
src/OpenSheetMusicDisplay/OSMDOptions.ts

@@ -36,7 +36,9 @@ export interface IOSMDOptions {
     drawLyricist?: boolean;
     /** Whether to draw part (instrument) names. */
     drawPartNames?: boolean;
-    /** Whether to draw fingerings (only left to the note for now). Default true. */
+    /** Whether to draw part (instrument) name abbreviations each system after the first. Only draws if drawPartNames. Default true. */
+    drawPartAbbreviations?: boolean;
+    /** Whether to draw fingerings (only left to the note for now). Default true (unless solo part). */
     drawFingerings?: boolean;
     /** Where to draw fingerings (left, right, above, below, auto).
      * Default left. Auto, above, below experimental (potential collisions because bounding box not correct)

+ 7 - 2
src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts

@@ -193,7 +193,9 @@ export class OpenSheetMusicDisplay {
      *  For example, setOptions({autoResize: false}) will disable autoResize even during runtime.
      */
     public setOptions(options: IOSMDOptions): void {
-        this.drawingParameters = new DrawingParameters();
+        if (!this.drawingParameters) {
+            this.drawingParameters = new DrawingParameters();
+        }
         if (options.drawingParameters) {
             this.drawingParameters.DrawingParametersEnum =
                 (<any>DrawingParametersEnum)[options.drawingParameters.toLowerCase()];
@@ -268,7 +270,10 @@ export class OpenSheetMusicDisplay {
             this.drawingParameters.drawCredits = options.drawCredits;
         }
         if (options.drawPartNames !== undefined) {
-            this.drawingParameters.DrawPartNames = options.drawPartNames;
+            this.drawingParameters.DrawPartNames = options.drawPartNames; // indirectly writes to EngravingRules
+        }
+        if (options.drawPartAbbreviations !== undefined) {
+            EngravingRules.Rules.RenderPartAbbreviations = options.drawPartAbbreviations;
         }
         if (options.drawFingerings === false) {
             EngravingRules.Rules.RenderFingerings = false;