diff --git a/Filters/VLMusicXMLType.reader b/Filters/VLMusicXMLType.reader index 77fc881..49f3e14 100755 --- a/Filters/VLMusicXMLType.reader +++ b/Filters/VLMusicXMLType.reader @@ -158,6 +158,13 @@ class MusicXMLListener 'melody' => [] } end + when 'print' + if attrs['new-system'] == 'yes' + @meas['new-system'] = true + end + if attrs['new-page'] == 'yes' + @meas['new-page'] = true + end when 'barline' @times = nil @type = nil @@ -178,7 +185,7 @@ class MusicXMLListener @meas['coda'] = true end if attrs['tempo'] - OUTPUT['tempo'] = attrs['tempo'].to_i + OUTPUT['tempo'] = attrs['tempo'].to_i end when 'divisions' @kind = 'prop' diff --git a/Filters/VLMusicXMLType.writer b/Filters/VLMusicXMLType.writer index 0d129f7..cc5e57d 100755 --- a/Filters/VLMusicXMLType.writer +++ b/Filters/VLMusicXMLType.writer @@ -310,6 +310,11 @@ def _melody lastProp = meas['properties'] m.add_element(_attributes(INPUT['properties'][lastProp])) end + if meas['new-page'] + m.add_element 'print', {'new-page' => 'yes'} + elsif meas['new-system'] + m.add_element 'print', {'new-system' => 'yes'} + end if meas['coda'] m.add_element 'sound', {'coda' => 'A'} end diff --git a/Sources/VLLayout.cpp b/Sources/VLLayout.cpp index 3021d79..3bd720b 100644 --- a/Sources/VLLayout.cpp +++ b/Sources/VLLayout.cpp @@ -15,21 +15,34 @@ #include #include -VLSystemLayout::VLSystemLayout(const VLProperties & prop, float width) +VLSystemLayout::VLSystemLayout(const VLProperties & prop, float width, int maxMeas) { fDivisions = prop.fDivisions; fNumGroups = prop.fTime.fNum / std::max(prop.fTime.fDenom / 4, 1); fDivPerGroup = fDivisions * prop.fTime.fNum * 4 / (prop.fTime.fDenom * fNumGroups); fClefKeyWidth = kClefX+kClefW+(std::labs(prop.fKey)+1)*kKeyW; fMeasureWidth = fNumGroups*(fDivPerGroup+1)*kNoteW; - fNumMeasures= std::max(1, std::floor((width-fClefKeyWidth) / fMeasureWidth)); + fNumMeasures = std::min(maxMeas, + std::max(1, + std::floor((width-fClefKeyWidth) / fMeasureWidth))); +} + +static size_t NextBreak(const VLSong & song, size_t after=0) +{ + while (++after < song.fMeasures.size()) + if (song.fMeasures[after].fBreak) + return after; + return song.fMeasures.size(); } VLLayout::VLLayout(const VLSong & song, float width) { + size_t nextBreak = NextBreak(song); for (size_t meas = 0; meas= nextBreak) + nextBreak = NextBreak(song, nextBreak); } } diff --git a/Sources/VLLayout.h b/Sources/VLLayout.h index fc00ba3..9ce72d3 100644 --- a/Sources/VLLayout.h +++ b/Sources/VLLayout.h @@ -13,7 +13,7 @@ class VLSystemLayout { public: - VLSystemLayout(const VLProperties & prop, float width); + VLSystemLayout(const VLProperties & prop, float width, int maxMeas); float ClefKeyWidth() const { return fClefKeyWidth; } float MeasureWidth() const { return fMeasureWidth; } diff --git a/Sources/VLModel.cpp b/Sources/VLModel.cpp index de1ea95..af22716 100644 --- a/Sources/VLModel.cpp +++ b/Sources/VLModel.cpp @@ -376,7 +376,7 @@ void VLChord::Name(std::string & base, std::string & ext, std::string & root, bo } VLMeasure::VLMeasure() - : fPropIdx(0) + : fBreak(0), fPropIdx(0) { } diff --git a/Sources/VLModel.h b/Sources/VLModel.h index 325c1f8..de71176 100644 --- a/Sources/VLModel.h +++ b/Sources/VLModel.h @@ -239,6 +239,11 @@ typedef std::list VLChordList; typedef std::list VLNoteList; struct VLMeasure { + enum { + kNewSystem = 1, + kNewPage = 2 + }; + uint8_t fBreak; int8_t fPropIdx; VLChordList fChords; VLNoteList fMelody; diff --git a/Sources/VLPListDocument.mm b/Sources/VLPListDocument.mm index 9ef4b9a..0fda0f5 100644 --- a/Sources/VLPListDocument.mm +++ b/Sources/VLPListDocument.mm @@ -119,6 +119,10 @@ void VLPlistVisitor::VisitMeasure(size_t m, VLProperties & p, VLMeasure & meas) [md setObject:[NSNumber numberWithBool:YES] forKey:@"tocoda"]; if (fSong->fCoda == m) [md setObject:[NSNumber numberWithBool:YES] forKey:@"coda"]; + if (meas.fBreak & VLMeasure::kNewSystem) + [md setObject:[NSNumber numberWithBool:YES] forKey:@"new-system"]; + if (meas.fBreak & VLMeasure::kNewPage) + [md setObject:[NSNumber numberWithBool:YES] forKey:@"new-page"]; [fMeasures addObject:md]; } @@ -313,6 +317,10 @@ advanceAt: song->fGoToCoda = measNo+1; if ([[mdict objectForKey:@"coda"] boolValue]) song->fCoda = measNo; + if ([[mdict objectForKey:@"new-system"] boolValue]) + song->fMeasures[measNo].fBreak |= VLMeasure::kNewSystem; + if ([[mdict objectForKey:@"new-page"] boolValue]) + song->fMeasures[measNo].fBreak |= VLMeasure::kNewPage; if (NSDictionary * beginRep = [mdict objectForKey:@"begin-repeat"]) { VLRepeat rep; VLRepeat::Ending ending(measNo, measNo, 0); diff --git a/Sources/VLSheetView.mm b/Sources/VLSheetView.mm index 23759eb..a745ca6 100644 --- a/Sources/VLSheetView.mm +++ b/Sources/VLSheetView.mm @@ -263,7 +263,7 @@ VLMusicElement sSemi2Accidental[12][12] = { delete fLayout; fLayout = new VLLayout(*[self song], sz.width / fDisplayScale); - sz.height = fLayout->NumSystems()*kSystemH; + sz.height = std::max(2, fLayout->NumSystems())*kSystemH; NSSize boundsSz = {sz.width / fDisplayScale, sz.height / fDisplayScale}; @@ -283,15 +283,24 @@ VLMusicElement sSemi2Accidental[12][12] = { fNeedsRecalc = kNoRecalc; } +const char * sBreak[3] = {"", "\xE2\xA4\xBE", "\xE2\x8E\x98"}; + - (void)drawGridForSystem:(int)system { static NSDictionary * sMeasNoFont = nil; + static NSDictionary * sBreakFont = nil; if (!sMeasNoFont) sMeasNoFont = [[NSDictionary alloc] initWithObjectsAndKeys: [NSFont fontWithName: @"Helvetica" size: 10], NSFontAttributeName, nil]; + if (!sBreakFont) + sBreakFont = + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSFont fontWithName: @"Symbol" size: 30], + NSFontAttributeName, + nil]; const VLSystemLayout & kLayout = (*fLayout)[system]; const VLSong * song = [self song]; @@ -468,6 +477,17 @@ VLMusicElement sSemi2Accidental[12][12] = { x += kAccW; } } + // + // Draw break character + // + int breakType = 0; + int nextMeasure = fLayout->FirstMeasure(system+1); + if (nextMeasure < song->fMeasures.size()) + breakType = song->fMeasures[nextMeasure].fBreak; + if (breakType) + [[NSString stringWithUTF8String:sBreak[breakType]] + drawAtPoint: NSMakePoint(kLineX+kLineW+kBreakX, kSystemY+kBreakY) + withAttributes: sBreakFont]; } - (void)drawBackgroundForSystem:(int)system @@ -721,15 +741,19 @@ static int8_t sSharpAcc[] = { { fCursorPitch = VLNote::kNoPitch; - NSPoint loc = [event locationInWindow]; - loc = [self convertPoint:loc fromView:nil]; + NSPoint loc = [event locationInWindow]; + loc = [self convertPoint:loc fromView:nil]; + const int kNumSystems = std::max(2, fLayout->NumSystems()); - if (loc.y < 0.0f || loc.y >= fLayout->NumSystems()*kSystemH) + if (loc.y < 0.0f || loc.y >= kNumSystems*kSystemH) return fCursorRegion = kRegionNowhere; const VLSong * song = [self song]; - int system = - fLayout->NumSystems() - static_cast(loc.y / kSystemH) - 1; + int system = + kNumSystems - static_cast(loc.y / kSystemH) - 1; + if (system >= fLayout->NumSystems()) + return fCursorRegion = kRegionNowhere; + const VLSystemLayout & kLayout = (*fLayout)[system]; const float kMeasureW = kLayout.MeasureWidth(); loc.y = fmodf(loc.y, kSystemH); diff --git a/Sources/VLSheetViewChords.mm b/Sources/VLSheetViewChords.mm index 208d464..d24ed9c 100644 --- a/Sources/VLSheetViewChords.mm +++ b/Sources/VLSheetViewChords.mm @@ -248,7 +248,7 @@ std::string NormalizeName(NSString* rawName) ) { NSAttributedString * chordName = [self stringWithChord:*chord]; NSPoint chordLoc = - NSMakePoint([self noteXInMeasure:m at:at], kSystemY+kChordY); + NSMakePoint([self noteXInMeasure:measIdx at:at], kSystemY+kChordY); [chordName drawAtPoint:chordLoc]; at += chord->fDuration; } diff --git a/Sources/VLSheetViewInternal.h b/Sources/VLSheetViewInternal.h index c8c0c71..b7ff594 100644 --- a/Sources/VLSheetViewInternal.h +++ b/Sources/VLSheetViewInternal.h @@ -19,6 +19,8 @@ const float kClefW = 30.0f; const float kMeasTol = 3.5f; const float kMeasNoX = 10.0f; const float kMeasNoY = 4.5f*kLineH; +const float kBreakX = 5.0f; +const float kBreakY = 0.0f*kLineH; const float kNoteW = 12.0f; const float kKeyW = 10.0f; const float kAccW = 10.0f; diff --git a/Sources/VLSheetViewLyrics.mm b/Sources/VLSheetViewLyrics.mm index 5c4f727..7dfd454 100644 --- a/Sources/VLSheetViewLyrics.mm +++ b/Sources/VLSheetViewLyrics.mm @@ -142,7 +142,7 @@ NSSize sz = [syll sizeWithAttributes:sLyricsFont]; NSPoint syllLoc = - NSMakePoint([self noteXInMeasure:m at:at] + NSMakePoint([self noteXInMeasure:measIdx at:at] - 0.5f*sz.width, kSystemY+kLyricsY-stanza*kLyricsH); if (note->fLyrics[stanza-1].fKind & VLSyllable::kHasNext) diff --git a/Sources/VLSheetViewNotes.mm b/Sources/VLSheetViewNotes.mm index e0b4868..af82fe9 100644 --- a/Sources/VLSheetViewNotes.mm +++ b/Sources/VLSheetViewNotes.mm @@ -302,10 +302,10 @@ int pitch = note->fPitch; if (pitch != VLNote::kNoPitch) { [self drawLedgerLinesWithPitch:pitch - at:NSMakePoint([self noteXInMeasure:m at:at], kSystemY)]; + at:NSMakePoint([self noteXInMeasure:measIdx at:at], kSystemY)]; VLMusicElement accidental; NSPoint pos = - NSMakePoint([self noteXInMeasure:m at:at], + NSMakePoint([self noteXInMeasure:measIdx at:at], kSystemY+[self noteYWithPitch:pitch accidental:&accidental]); VLMusicElement acc = accidental; @@ -325,7 +325,7 @@ } else { VLMusicElement accidental; NSPoint pos = - NSMakePoint([self noteXInMeasure:m at:at], + NSMakePoint([self noteXInMeasure:measIdx at:at], kSystemY+[self noteYWithPitch:65 accidental:&accidental]); [self drawRest:note->fVisual & VLNote::kNoteHead at: pos];