Explorar o código

fix(StaveRepetitions): Fix To Coda, D.S. etc. not positioned correctly (#920). Add EngravingRule RepetitionSymbolsYOffset

add vexflow patches to prevent NaNs for positioning values (x) in Vexflow
add TO_CODA as Vex.Flow.Repetition.type

add test for stave repetitions

add EngravingRule RepetitionSymbolsYOffset
sschmid %!s(int64=4) %!d(string=hai) anos
pai
achega
06a86b0757

+ 2 - 1
src/MusicalScore/Graphical/EngravingRules.ts

@@ -100,6 +100,7 @@ export class EngravingRules {
     public ChordSymbolXSpacing: number;
     public ChordSymbolYOffset: number;
     public ChordSymbolLabelTexts: Dictionary<ChordSymbolEnum, string>;
+    public RepetitionSymbolsYOffset: number;
     public MeasureNumberLabelHeight: number;
     public MeasureNumberLabelOffset: number;
     public MeasureNumberLabelXOffset: number;
@@ -389,7 +390,7 @@ export class EngravingRules {
         this.ChordSymbolYOffset = 2.0;
         this.ChordSymbolLabelTexts = new Dictionary<ChordSymbolEnum, string>();
         this.resetChordSymbolLabelTexts(this.ChordSymbolLabelTexts);
-
+        this.RepetitionSymbolsYOffset = 0;
 
         // Tuplets, MeasureNumber and TupletNumber Labels
         this.MeasureNumberLabelHeight = 1.5 * EngravingRules.unit;

+ 3 - 2
src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts

@@ -388,7 +388,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
             instruction = Vex.Flow.Repetition.type.FINE;
             break;
           case RepetitionInstructionEnum.ToCoda:
-            //instruction = "To Coda";
+            instruction = (Vex.Flow.Repetition as any).type.TO_CODA;
             break;
           case RepetitionInstructionEnum.DaCapoAlFine:
             instruction = Vex.Flow.Repetition.type.DC_AL_FINE;
@@ -406,7 +406,8 @@ export class VexFlowMeasure extends GraphicalMeasure {
             break;
         }
         if (instruction) {
-            this.stave.addModifier(new Vex.Flow.Repetition(instruction, 0, 0), position);
+            const repetition: Vex.Flow.Repetition = new Vex.Flow.Repetition(instruction, 0, -this.rules.RepetitionSymbolsYOffset);
+            this.stave.addModifier(repetition, position);
             return;
         }
 

+ 3 - 3
src/VexFlowPatch/src/stave.js

@@ -531,12 +531,12 @@ export class Stave extends Element {
           widths.paddingLeft = 0;
         }
       } else {
-        widths.paddingRight = modifier.getPadding(i - lastBarlineIdx);
+        widths.paddingRight = modifier.getPadding(i - lastBarlineIdx) || 0; // can be null too
         if (i !== 0) {
-          widths.right = modifier.getWidth();
+          widths.right = modifier.getWidth() || 0;
         }
         if (i === 0) {
-          widths.left = modifier.getWidth();
+          widths.left = modifier.getWidth() || 0;
         }
       }
       x -= widths.paddingRight;

+ 140 - 0
src/VexFlowPatch/src/staverepetition.js

@@ -0,0 +1,140 @@
+// [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
+// Author Larry Kuhns 2011
+
+import { StaveModifier } from './stavemodifier';
+import { Glyph } from './glyph';
+
+export class Repetition extends StaveModifier {
+  static get CATEGORY() { return 'repetitions'; }
+  static get type() {
+    return {
+      NONE: 1,         // no coda or segno
+      CODA_LEFT: 2,    // coda at beginning of stave
+      CODA_RIGHT: 3,   // coda at end of stave
+      SEGNO_LEFT: 4,   // segno at beginning of stave
+      SEGNO_RIGHT: 5,  // segno at end of stave
+      DC: 6,           // D.C. at end of stave
+      DC_AL_CODA: 7,   // D.C. al coda at end of stave
+      DC_AL_FINE: 8,   // D.C. al Fine end of stave
+      DS: 9,           // D.S. at end of stave
+      DS_AL_CODA: 10,  // D.S. al coda at end of stave
+      DS_AL_FINE: 11,  // D.S. al Fine at end of stave
+      FINE: 12,        // Fine at end of stave
+      TO_CODA: 13,     // To Coda at end of stave
+    };
+  }
+
+  constructor(type, x, y_shift) {
+    super();
+    this.setAttribute('type', 'Repetition');
+
+    this.symbol_type = type;
+    this.x = x;
+    this.x_shift = 0;
+    this.y_shift = y_shift;
+    this.font = {
+      family: 'times',
+      size: 12,
+      weight: 'bold italic',
+    };
+  }
+
+  getCategory() { return Repetition.CATEGORY; }
+  setShiftX(x) { this.x_shift = x; return this; }
+  setShiftY(y) { this.y_shift = y; return this; }
+
+  setX(x) { 
+    this.x = x; return this;
+  }
+
+  draw(stave, x) {
+    this.setRendered();
+    
+    switch (this.symbol_type) {
+      case Repetition.type.CODA_RIGHT:
+        this.drawCodaFixed(stave, x + stave.width);
+        break;
+      case Repetition.type.CODA_LEFT:
+        this.drawSymbolText(stave, x, 'Coda', true);
+        break;
+      case Repetition.type.SEGNO_LEFT:
+        this.drawSignoFixed(stave, x);
+        break;
+      case Repetition.type.SEGNO_RIGHT:
+        this.drawSignoFixed(stave, x + stave.width);
+        break;
+      case Repetition.type.DC:
+        this.drawSymbolText(stave, x, 'D.C.', false);
+        break;
+      case Repetition.type.DC_AL_CODA:
+        this.drawSymbolText(stave, x, 'D.C. al', true);
+        break;
+      case Repetition.type.DC_AL_FINE:
+        this.drawSymbolText(stave, x, 'D.C. al Fine', false);
+        break;
+      case Repetition.type.DS:
+        this.drawSymbolText(stave, x, 'D.S.', false);
+        break;
+      case Repetition.type.DS_AL_CODA:
+        this.drawSymbolText(stave, x, 'D.S. al', true);
+        break;
+      case Repetition.type.DS_AL_FINE:
+        this.drawSymbolText(stave, x, 'D.S. al Fine', false);
+        break;
+      case Repetition.type.FINE:
+        this.drawSymbolText(stave, x, 'Fine', false);
+        break;
+      case Repetition.type.TO_CODA:
+        this.drawSymbolText(stave, x, 'To', true);
+        break;
+      default:
+        break;
+    }
+
+    return this;
+  }
+
+  drawCodaFixed(stave, x) {
+    const y = stave.getYForTopText(stave.options.num_lines) + this.y_shift;
+    Glyph.renderGlyph(stave.context, this.x + x + this.x_shift, y + 25, 40, 'v4d', true);
+    return this;
+  }
+
+  drawSignoFixed(stave, x) {
+    const y = stave.getYForTopText(stave.options.num_lines) + this.y_shift;
+    Glyph.renderGlyph(stave.context, this.x + x + this.x_shift, y + 25, 30, 'v8c', true);
+    return this;
+  }
+
+  drawSymbolText(stave, x, text, draw_coda) {
+    const ctx = stave.checkContext();
+
+    ctx.save();
+    ctx.setFont(this.font.family, this.font.size, this.font.weight);
+    // Default to right symbol
+    let text_x = 0 + this.x_shift;
+    let symbol_x = x + this.x_shift;
+    if (this.symbol_type === Repetition.type.CODA_LEFT) {
+      // Offset Coda text to right of stave beginning
+      text_x = this.x + stave.options.vertical_bar_width;
+      symbol_x = text_x + ctx.measureText(text).width + 12;
+    } else if (this.symbol_type === Repetition.type.TO_CODA) {
+      text_x = this.x + stave.options.vertical_bar_width;
+      symbol_x = text_x + ctx.measureText(text).width + 12;
+    } else {
+      // Offset Signo text to left stave end
+      symbol_x = this.x + x + stave.width - 5 + this.x_shift;
+      text_x = symbol_x - + ctx.measureText(text).width - 12;
+    }
+
+    const y = stave.getYForTopText(stave.options.num_lines) + this.y_shift + 25;
+    if (draw_coda) {
+      Glyph.renderGlyph(ctx, symbol_x, y, 40, 'v4d', true);
+    }
+
+    ctx.fillText(text, text_x, y + 5);
+    ctx.restore();
+
+    return this;
+  }
+}

+ 359 - 0
test/data/test_staverepetitions_coda_etc.musicxml

@@ -0,0 +1,359 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 2.0 Partwise//EN"
+  "http://www.musicxml.org/dtds/partwise.dtd">
+<score-partwise version="2.0">
+  <work>
+    <work-title>Test - StaveRepetitions (Coda etc)</work-title>
+  </work>
+  <identification>
+    <creator type="composer"/>
+    <creator type="lyricist"/>
+    <rights/>
+    <encoding>
+      <software>Noteflight version 0.3.2</software>
+      <encoding-date>2013-06-03</encoding-date>
+      <supports attribute="new-system" element="print" type="no" value="no"/>
+      <supports attribute="new-page" element="print" type="no" value="no"/>
+    </encoding>
+  </identification>
+  <defaults>
+    <scaling>
+      <millimeters>2.1166666679999997</millimeters>
+      <tenths>10</tenths>
+    </scaling>
+    <page-layout>
+      <page-height>1320</page-height>
+      <page-width>1020</page-width>
+      <page-margins type="both">
+        <left-margin>59.583333333333336</left-margin>
+        <right-margin>56.66666666666667</right-margin>
+        <top-margin>96.66666666666667</top-margin>
+        <bottom-margin>80</bottom-margin>
+      </page-margins>
+    </page-layout>
+    <system-layout>
+      <system-margins>
+        <left-margin>59.583333333333336</left-margin>
+        <right-margin>26.666666666666668</right-margin>
+      </system-margins>
+      <system-distance>92.5</system-distance>
+      <top-system-distance>145.83333333333334</top-system-distance>
+    </system-layout>
+    <staff-layout>
+      <staff-distance>55</staff-distance>
+    </staff-layout>
+  </defaults>
+  <part-list>
+    <score-part id="P1">
+      <part-name>Piano</part-name>
+      <part-abbreviation>Pno</part-abbreviation>
+      <score-instrument id="P1I1">
+        <instrument-name>Piano</instrument-name>
+      </score-instrument>
+      <midi-instrument id="P1I1">
+        <midi-channel>1</midi-channel>
+        <midi-program>1</midi-program>
+      </midi-instrument>
+    </score-part>
+  </part-list>
+  <part id="P1">
+    <measure number="1">
+      <attributes>
+        <divisions>64</divisions>
+        <key>
+          <fifths>0</fifths>
+          <mode>major</mode>
+        </key>
+        <time>
+          <beats>4</beats>
+          <beat-type>4</beat-type>
+        </time>
+        <staves>2</staves>
+        <clef number="1">
+          <sign>G</sign>
+          <line>2</line>
+        </clef>
+      </attributes>
+      <direction placement="above">
+        <direction-type>
+          <metronome>
+            <beat-unit>quarter</beat-unit>
+            <per-minute>120</per-minute>
+          </metronome>
+        </direction-type>
+        <sound tempo="120"/>
+      </direction>
+      <direction placement="above">
+        <direction-type>
+          <metronome>
+            <beat-unit>quarter</beat-unit>
+            <per-minute>120</per-minute>
+          </metronome>
+        </direction-type>
+        <sound tempo="120"/>
+      </direction>
+      <direction placement="above">
+        <direction-type>
+          <segno/>
+        </direction-type>
+      </direction>
+      <note>
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <backup>
+        <duration>256</duration>
+      </backup>
+      <attributes>
+        <clef number="2">
+          <sign>F</sign>
+          <line>4</line>
+        </clef>
+      </attributes>
+      <note>
+        <rest/>
+        <duration>256</duration>
+        <voice>3</voice>
+        <type>whole</type>
+        <staff>2</staff>
+      </note>
+    </measure>
+    <measure number="2">
+      <attributes/>
+      <direction placement="above">
+        <direction-type>
+          <words>to coda</words>
+        </direction-type>
+      </direction>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <backup>
+        <duration>256</duration>
+      </backup>
+      <attributes/>
+      <note>
+        <rest/>
+        <duration>256</duration>
+        <voice>3</voice>
+        <type>whole</type>
+        <staff>2</staff>
+      </note>
+    </measure>
+    <measure number="3">
+      <attributes/>
+      <note>
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <direction placement="above">
+        <direction-type>
+          <words>D.S. al Coda</words>
+        </direction-type>
+      </direction>
+      <backup>
+        <duration>256</duration>
+      </backup>
+      <attributes/>
+      <note>
+        <rest/>
+        <duration>256</duration>
+        <voice>3</voice>
+        <type>whole</type>
+        <staff>2</staff>
+      </note>
+    </measure>
+    <measure number="4">
+      <attributes/>
+      <direction placement="above">
+        <direction-type>
+          <coda/>
+        </direction-type>
+      </direction>
+      <note>
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note>
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>64</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <backup>
+        <duration>256</duration>
+      </backup>
+      <attributes/>
+      <note>
+        <rest/>
+        <duration>256</duration>
+        <voice>3</voice>
+        <type>whole</type>
+        <staff>2</staff>
+      </note>
+    </measure>
+    <measure number="5">
+      <attributes/>
+      <note>
+        <rest/>
+        <duration>256</duration>
+        <voice>1</voice>
+        <type>whole</type>
+        <staff>1</staff>
+      </note>
+      <backup>
+        <duration>256</duration>
+      </backup>
+      <attributes/>
+      <note>
+        <rest/>
+        <duration>256</duration>
+        <voice>3</voice>
+        <type>whole</type>
+        <staff>2</staff>
+      </note>
+      <barline location="right">
+        <bar-style>light-heavy</bar-style>
+      </barline>
+    </measure>
+  </part>
+</score-partwise>