2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
|
|
|
// Copyright (C) 2002-2011 Werner Schweer
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License version 2
|
|
|
|
// as published by the Free Software Foundation and appearing in
|
|
|
|
// the file LICENCE.GPL
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
#include <fenv.h>
|
|
|
|
#include "page.h"
|
|
|
|
#include "sig.h"
|
|
|
|
#include "key.h"
|
|
|
|
#include "clef.h"
|
|
|
|
#include "score.h"
|
|
|
|
#include "segment.h"
|
|
|
|
#include "text.h"
|
|
|
|
#include "staff.h"
|
|
|
|
#include "style.h"
|
|
|
|
#include "timesig.h"
|
|
|
|
#include "chord.h"
|
|
|
|
#include "note.h"
|
|
|
|
#include "slur.h"
|
2013-08-22 12:18:14 +02:00
|
|
|
#include "tie.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
#include "keysig.h"
|
|
|
|
#include "barline.h"
|
|
|
|
#include "repeat.h"
|
|
|
|
#include "box.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "part.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "measure.h"
|
|
|
|
#include "volta.h"
|
|
|
|
#include "beam.h"
|
|
|
|
#include "tuplet.h"
|
|
|
|
#include "sym.h"
|
|
|
|
#include "fingering.h"
|
|
|
|
#include "stem.h"
|
|
|
|
#include "layoutbreak.h"
|
|
|
|
#include "mscore.h"
|
|
|
|
#include "accidental.h"
|
|
|
|
#include "undo.h"
|
|
|
|
#include "layout.h"
|
2012-08-01 18:00:27 +02:00
|
|
|
#include "lyrics.h"
|
2013-03-13 11:13:33 +01:00
|
|
|
#include "harmony.h"
|
2013-07-16 09:03:47 +02:00
|
|
|
#include "ottava.h"
|
2014-02-22 11:19:44 +01:00
|
|
|
#include "notedot.h"
|
2014-03-05 23:45:58 +01:00
|
|
|
#include "element.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
namespace Ms {
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// rebuildBspTree
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::rebuildBspTree()
|
|
|
|
{
|
2012-12-06 12:46:05 +01:00
|
|
|
int n = _pages.size();
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
_pages.at(i)->rebuildBspTree();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// searchNote
|
|
|
|
// search for note or rest before or at tick position tick
|
|
|
|
// in staff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChordRest* Score::searchNote(int tick, int track) const
|
|
|
|
{
|
|
|
|
ChordRest* ipe = 0;
|
2012-12-06 09:19:59 +01:00
|
|
|
Segment::SegmentTypes st = Segment::SegChordRest;
|
|
|
|
for (Segment* segment = firstSegment(st); segment; segment = segment->next(st)) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(segment->element(track));
|
|
|
|
if (!cr)
|
|
|
|
continue;
|
|
|
|
if (cr->tick() == tick)
|
|
|
|
return cr;
|
|
|
|
if (cr->tick() > tick)
|
|
|
|
return ipe ? ipe : cr;
|
|
|
|
ipe = cr;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutChords1
|
2014-03-05 23:45:58 +01:00
|
|
|
// - layout upstem and downstem chords
|
|
|
|
// - offset as necessary to avoid conflict
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutChords1(Segment* segment, int staffIdx)
|
|
|
|
{
|
|
|
|
Staff* staff = Score::staff(staffIdx);
|
|
|
|
|
2013-05-23 15:39:14 +02:00
|
|
|
// if (staff->isDrumStaff() || staff->isTabStaff())
|
|
|
|
if (staff->isTabStaff())
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
|
|
|
|
2014-03-07 03:43:41 +01:00
|
|
|
int upVoices = 0, downVoices = 0;
|
2012-05-26 14:26:10 +02:00
|
|
|
int startTrack = staffIdx * VOICES;
|
|
|
|
int endTrack = startTrack + VOICES;
|
2014-03-05 23:45:58 +01:00
|
|
|
QList<Note*> upStemNotes, downStemNotes;
|
|
|
|
|
2014-03-08 07:43:24 +01:00
|
|
|
// dots can affect layout of notes as well as vice versa
|
|
|
|
int upDots = 0;
|
|
|
|
int downDots = 0;
|
|
|
|
qreal dotAdjust = 0.0; // additional chord offset to account for dots
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
for (int track = startTrack; track < endTrack; ++track) {
|
|
|
|
Element* e = segment->element(track);
|
2012-09-13 18:01:34 +02:00
|
|
|
if (e && (e->type() == Element::CHORD)) {
|
2013-06-10 21:13:04 +02:00
|
|
|
Chord* chord = static_cast<Chord*>(e);
|
2014-03-05 23:45:58 +01:00
|
|
|
for (Chord* c : chord->graceNotes()) {
|
|
|
|
// layout grace note noteheads
|
|
|
|
layoutChords2(c->notes(), c->up());
|
|
|
|
// layout grace note chords
|
|
|
|
layoutChords3(c->notes(), staff, 0);
|
|
|
|
}
|
2014-03-07 03:43:41 +01:00
|
|
|
if (chord->up()) {
|
|
|
|
++upVoices;
|
2014-03-05 23:45:58 +01:00
|
|
|
upStemNotes.append(chord->notes());
|
2014-03-08 07:43:24 +01:00
|
|
|
upDots = qMax(upDots, chord->dots());
|
2014-03-07 03:43:41 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
++downVoices;
|
2014-03-05 23:45:58 +01:00
|
|
|
downStemNotes.append(chord->notes());
|
2014-03-08 07:43:24 +01:00
|
|
|
downDots = qMax(downDots, chord->dots());
|
2014-03-07 03:43:41 +01:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
2014-03-05 23:45:58 +01:00
|
|
|
|
2014-03-10 04:24:54 +01:00
|
|
|
if (upVoices + downVoices == 0)
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
2014-03-05 23:45:58 +01:00
|
|
|
|
|
|
|
// TODO: use track as secondary sort criteria?
|
|
|
|
// otherwise there might be issues with unisons between voices
|
|
|
|
// in some corner cases
|
|
|
|
|
|
|
|
// layout upstem noteheads
|
2014-03-07 03:43:41 +01:00
|
|
|
if (upVoices > 1) {
|
2014-03-05 23:45:58 +01:00
|
|
|
qSort(upStemNotes.begin(), upStemNotes.end(),
|
|
|
|
[](Note* n1, const Note* n2) ->bool {return n1->line() > n2->line(); } );
|
|
|
|
}
|
2014-03-10 04:24:54 +01:00
|
|
|
if (upVoices)
|
2014-03-05 23:45:58 +01:00
|
|
|
layoutChords2(upStemNotes, true);
|
|
|
|
|
|
|
|
// layout downstem noteheads
|
2014-03-07 03:43:41 +01:00
|
|
|
if (downVoices > 1) {
|
2014-03-05 23:45:58 +01:00
|
|
|
qSort(downStemNotes.begin(), downStemNotes.end(),
|
|
|
|
[](Note* n1, const Note* n2) ->bool {return n1->line() > n2->line(); } );
|
|
|
|
}
|
2014-03-10 04:24:54 +01:00
|
|
|
if (downVoices)
|
2014-03-05 23:45:58 +01:00
|
|
|
layoutChords2(downStemNotes, false);
|
|
|
|
|
|
|
|
// handle conflict between upstem and downstem chords
|
|
|
|
|
2014-03-10 04:24:54 +01:00
|
|
|
if (upVoices && downVoices) {
|
2014-03-05 23:45:58 +01:00
|
|
|
Note* bottomUpNote = upStemNotes.first();
|
|
|
|
Note* topDownNote = downStemNotes.last();
|
|
|
|
int separation = topDownNote->line() - bottomUpNote->line();
|
|
|
|
qreal sp = staff->spatium();
|
|
|
|
qreal upOffset = 0.0;
|
2014-03-08 07:43:24 +01:00
|
|
|
qreal downOffset = 0.0;
|
2014-03-05 23:45:58 +01:00
|
|
|
|
|
|
|
// whole note and larger values are centered later on
|
|
|
|
// this throws off the chord offsets
|
|
|
|
// so account for the discrepancy as best we can
|
|
|
|
qreal qHw = segment->symWidth(SymId::noteheadBlack);
|
|
|
|
qreal wHw = segment->symWidth(SymId::noteheadWhole);
|
|
|
|
qreal wholeNoteAdjust = (wHw - qHw) / 2.0;
|
|
|
|
|
|
|
|
if (separation == 1) {
|
|
|
|
// second
|
|
|
|
downOffset = bottomUpNote->headWidth();
|
|
|
|
// align stem if present, leave extra room if not
|
|
|
|
if (topDownNote->chord()->stem())
|
2014-03-10 16:55:51 +01:00
|
|
|
downOffset -= topDownNote->chord()->stem()->lineWidth();
|
2014-03-05 23:45:58 +01:00
|
|
|
else
|
|
|
|
downOffset += 0.1 * sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (separation < 1) {
|
|
|
|
|
|
|
|
// overlap (possibly unison)
|
|
|
|
|
|
|
|
// build list of overlapping notes
|
|
|
|
QList<Note*> overlapNotes;
|
|
|
|
// upstem notes
|
|
|
|
qreal maxUpWidth = 0.0;
|
|
|
|
for (int i = 0, n = upStemNotes.size(); i < n; ++i) {
|
|
|
|
qreal w = upStemNotes[i]->headWidth();
|
|
|
|
if (upStemNotes[i]->chord()->durationType() >= TDuration::V_WHOLE)
|
|
|
|
w -= wholeNoteAdjust;
|
|
|
|
maxUpWidth = qMax(maxUpWidth, w);
|
|
|
|
if (upStemNotes[i]->line() >= topDownNote->line() - 1)
|
|
|
|
overlapNotes.append(upStemNotes[i]);
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// downstem notes
|
|
|
|
qreal maxDownWidth = 0.0;
|
|
|
|
for (int i = downStemNotes.size() - 1; i >= 0; --i) {
|
|
|
|
qreal w = downStemNotes[i]->headWidth();
|
|
|
|
if (downStemNotes[i]->chord()->durationType() >= TDuration::V_WHOLE)
|
|
|
|
w -= 0.2 * wholeNoteAdjust;
|
|
|
|
maxDownWidth = qMax(maxDownWidth, w);
|
|
|
|
if (downStemNotes[i]->line() <= bottomUpNote->line() + 1)
|
|
|
|
overlapNotes.append(downStemNotes[i]);
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
qSort(overlapNotes.begin(), overlapNotes.end(),
|
|
|
|
[](Note* n1, const Note* n2) ->bool {return n1->line() > n2->line(); } );
|
|
|
|
|
|
|
|
// determine nature of overlap
|
|
|
|
bool shareHeads = true; // can all overlapping notes share heads?
|
|
|
|
bool matchPending = false; // looking for a unison match
|
|
|
|
bool conflictUnison = false; // unison found
|
2014-03-07 03:43:41 +01:00
|
|
|
bool conflictSecondUpHigher = false; // second found
|
|
|
|
bool conflictSecondDownHigher = false; // second found
|
2014-03-05 23:45:58 +01:00
|
|
|
int lastLine = 1000;
|
|
|
|
Note* p = overlapNotes[0];
|
|
|
|
for (int i = 0, count = overlapNotes.size(); i < count; ++i) {
|
|
|
|
Note* n = overlapNotes[i];
|
|
|
|
if (n->mirror()) {
|
|
|
|
if (separation < 0) {
|
|
|
|
// don't try to share heads if there is any mirroring
|
|
|
|
shareHeads = false;
|
|
|
|
// don't worry about conflicts involving mirrored notes
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int line = n->line();
|
|
|
|
int d = lastLine - line;
|
|
|
|
switch (d) {
|
|
|
|
case 0:
|
|
|
|
// unison
|
|
|
|
conflictUnison = true;
|
|
|
|
matchPending = false;
|
|
|
|
if (n->headGroup() != p->headGroup() || n->headType() != p->headType() || n->chord()->durationType() != p->chord()->durationType()
|
|
|
|
|| n->tpc() != p->tpc() || n->mirror() || p->mirror())
|
|
|
|
shareHeads = false;
|
|
|
|
break;
|
|
|
|
case 1:
|
2014-03-07 03:43:41 +01:00
|
|
|
// second
|
|
|
|
// trust that this won't be a problem for single unison
|
2014-03-05 23:45:58 +01:00
|
|
|
if (separation < 0) {
|
2014-03-07 03:43:41 +01:00
|
|
|
if (n->chord()->up())
|
|
|
|
conflictSecondUpHigher = true;
|
|
|
|
else
|
|
|
|
conflictSecondDownHigher = true;
|
2014-03-05 23:45:58 +01:00
|
|
|
shareHeads = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// no conflict
|
|
|
|
if (matchPending)
|
|
|
|
shareHeads = false;
|
|
|
|
matchPending = true;
|
|
|
|
}
|
|
|
|
p = n;
|
|
|
|
lastLine = line;
|
|
|
|
}
|
|
|
|
if (matchPending)
|
|
|
|
shareHeads = false;
|
|
|
|
|
|
|
|
// calculate offsets
|
|
|
|
if (shareHeads) {
|
|
|
|
#if 0
|
|
|
|
// TODO: get accidentals right
|
|
|
|
// TODO: make sure we hide the note that would have been underneath
|
|
|
|
// otherwise nudge might not appear to work since you aren't moving the visible note
|
|
|
|
// do we really even *need* to hide noteheads of overlap?
|
|
|
|
for (int i = overlapNotes.size() - 1; i >= 1; i -= 2) {
|
|
|
|
Note* p = overlapNotes[i-1];
|
|
|
|
Note* n = overlapNotes[i];
|
|
|
|
if (!(p->chord()->isNudged() || n->chord()->isNudged())) {
|
|
|
|
if (n->chord()->actualTicks() > p->chord()->actualTicks()) {
|
|
|
|
p->setHidden(true);
|
|
|
|
if (n->chord()->dots() == p->chord()->dots())
|
|
|
|
p->setDotsHidden(true);
|
|
|
|
// TODO: p->setAccidentalType(ACC_NONE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
n->setHidden(true);
|
|
|
|
if (n->chord()->dots() == p->chord()->dots())
|
|
|
|
n->setDotsHidden(true);
|
|
|
|
// TODO: n->setAccidentalType(ACC_NONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else if (conflictUnison && separation == 0)
|
|
|
|
downOffset = maxUpWidth + 0.3 * sp;
|
|
|
|
else if (conflictUnison)
|
|
|
|
upOffset = maxDownWidth + 0.3 * sp;
|
2014-03-07 03:43:41 +01:00
|
|
|
else if (conflictSecondUpHigher)
|
2014-03-05 23:45:58 +01:00
|
|
|
upOffset = maxDownWidth + 0.2 * sp;
|
2014-03-08 07:43:24 +01:00
|
|
|
else if (conflictSecondDownHigher) {
|
|
|
|
if (downDots && !upDots)
|
|
|
|
downOffset = maxUpWidth + 0.3 * sp;
|
|
|
|
else
|
|
|
|
upOffset = maxDownWidth - 0.2 * sp;
|
|
|
|
}
|
2014-03-07 03:43:41 +01:00
|
|
|
else {
|
|
|
|
// no direct conflict, so parts can overlap (downstem on left)
|
|
|
|
// just be sure that stems clear opposing noteheads
|
|
|
|
qreal clearLeft = 0.0, clearRight = 0.0;
|
|
|
|
if (topDownNote->chord()->stem())
|
2014-03-10 16:55:51 +01:00
|
|
|
clearLeft = topDownNote->chord()->stem()->lineWidth() + 0.3 * sp;
|
2014-03-07 03:43:41 +01:00
|
|
|
if (bottomUpNote->chord()->stem())
|
|
|
|
clearRight = qMax(maxDownWidth - maxUpWidth, 0.0) + 0.3 * sp;
|
2014-03-08 07:43:24 +01:00
|
|
|
else
|
2014-03-08 17:13:06 +01:00
|
|
|
downDots = 0; // no need to adjust for dots in this case
|
2014-03-07 03:43:41 +01:00
|
|
|
upOffset = qMax(clearLeft, clearRight);
|
|
|
|
}
|
2014-03-08 07:43:24 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// adjust for dots
|
|
|
|
if ((upDots && !downDots) || (downDots && !upDots)) {
|
|
|
|
// only one sets of dots
|
|
|
|
// place between chords
|
|
|
|
int dots = qMax(upDots, downDots);
|
|
|
|
qreal dotWidth = segment->symWidth(SymId::augmentationDot);
|
|
|
|
// first dot
|
|
|
|
dotAdjust = point(styleS(ST_dotNoteDistance)) + dotWidth;
|
|
|
|
// additional dots
|
2014-03-08 17:13:06 +01:00
|
|
|
if (dots > 1)
|
|
|
|
dotAdjust += point(styleS(ST_dotDotDistance)) * (dots - 1);
|
2014-03-05 23:45:58 +01:00
|
|
|
}
|
2014-03-08 17:13:06 +01:00
|
|
|
if (separation == 1)
|
|
|
|
dotAdjust += 0.1 * sp;
|
2014-03-05 23:45:58 +01:00
|
|
|
|
2014-03-08 07:43:24 +01:00
|
|
|
// apply chord offset
|
2014-03-05 23:45:58 +01:00
|
|
|
for (int track = startTrack; track < endTrack; ++track) {
|
|
|
|
Element* e = segment->element(track);
|
|
|
|
if (e && (e->type() == Element::CHORD)) {
|
|
|
|
Chord* chord = static_cast<Chord*>(e);
|
|
|
|
if (chord->up() && upOffset != 0.0) {
|
|
|
|
chord->rxpos() += upOffset;
|
|
|
|
if (chord->durationType() >= TDuration::V_WHOLE)
|
|
|
|
chord->rxpos() += wholeNoteAdjust;
|
2014-03-08 07:43:24 +01:00
|
|
|
if (downDots && !upDots)
|
|
|
|
chord->rxpos() += dotAdjust;
|
2014-03-05 23:45:58 +01:00
|
|
|
}
|
|
|
|
else if (!chord->up() && downOffset != 0.0) {
|
|
|
|
chord->rxpos() += downOffset;
|
|
|
|
if (chord->durationType() >= TDuration::V_WHOLE)
|
|
|
|
chord->rxpos() += wholeNoteAdjust + 0.1 * sp; // a little extra to separate more from previous stem
|
2014-03-08 07:43:24 +01:00
|
|
|
if (upDots && !downDots)
|
|
|
|
chord->rxpos() += dotAdjust;
|
2014-03-05 23:45:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// layout chords
|
|
|
|
QList<Note*> notes;
|
2014-03-10 04:24:54 +01:00
|
|
|
if (upVoices)
|
|
|
|
notes.append(upStemNotes);
|
|
|
|
if (downVoices)
|
|
|
|
notes.append(downStemNotes);
|
2014-03-09 07:09:40 +01:00
|
|
|
if (upVoices + downVoices > 1)
|
2014-03-05 23:45:58 +01:00
|
|
|
qSort(notes.begin(), notes.end(),
|
|
|
|
[](Note* n1, const Note* n2) ->bool {return n1->line() > n2->line(); } );
|
|
|
|
layoutChords3(notes, staff, segment);
|
|
|
|
|
2013-06-10 21:13:04 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-03-05 23:45:58 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutChords2
|
2014-03-09 07:09:40 +01:00
|
|
|
// - determine which notes need mirroring
|
2014-03-05 23:45:58 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutChords2(QList<Note*>& notes, bool up)
|
2013-06-10 21:13:04 +02:00
|
|
|
{
|
2012-05-26 14:26:10 +02:00
|
|
|
int startIdx, endIdx, incIdx;
|
|
|
|
|
2014-03-05 23:45:58 +01:00
|
|
|
// loop in correct direction so that first encountered notehead wins conflict
|
|
|
|
if (up) {
|
|
|
|
// loop bottom up
|
2012-05-26 14:26:10 +02:00
|
|
|
startIdx = 0;
|
2014-03-05 23:45:58 +01:00
|
|
|
endIdx = notes.size();
|
|
|
|
incIdx = 1;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-03-05 23:45:58 +01:00
|
|
|
// loop top down
|
2012-05-26 14:26:10 +02:00
|
|
|
startIdx = notes.size() - 1;
|
2014-03-05 23:45:58 +01:00
|
|
|
endIdx = -1;
|
|
|
|
incIdx = -1;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-03-05 23:45:58 +01:00
|
|
|
int ll = 1000; // line distance to previous note head
|
|
|
|
// hack: start high so first note won't show as conflict
|
|
|
|
bool mirror = false; // do we need to mirror this notehead?
|
|
|
|
bool isLeft = notes[startIdx]->chord()->up(); // is note head on left?
|
|
|
|
int move1 = notes[startIdx]->chord()->staffMove(); // chord moved to staff above or below
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
for (int idx = startIdx; idx != endIdx; idx += incIdx) {
|
2014-03-05 23:45:58 +01:00
|
|
|
|
|
|
|
Note* note = notes[idx]; // current note
|
|
|
|
int line = note->line(); // line of current note
|
2012-05-26 14:26:10 +02:00
|
|
|
Chord* chord = note->chord();
|
2014-03-05 23:45:58 +01:00
|
|
|
int ticks = chord->actualTicks(); // duration of current note
|
2012-05-26 14:26:10 +02:00
|
|
|
int move = chord->staffMove();
|
|
|
|
|
2014-03-05 23:45:58 +01:00
|
|
|
//NoteHeadGroup headGroup = note->headGroup(); // head group of current note
|
|
|
|
// calculate head type of current note if group is AUTO
|
|
|
|
//NoteHeadType headType = (note->headType() == NoteHeadType::HEAD_AUTO)
|
|
|
|
// ? note->chord()->durationType().headType() : NoteHeadType(int(note->headType()) - 1);
|
|
|
|
|
|
|
|
// there is a conflict
|
|
|
|
// if this same or adjacent line as previous note
|
2012-05-26 14:26:10 +02:00
|
|
|
bool conflict = (qAbs(ll - line) < 2) && (move1 == move);
|
2014-03-05 23:45:58 +01:00
|
|
|
|
|
|
|
// this note is on opposite side of stem as previous note
|
|
|
|
// if there is a conflict
|
|
|
|
// or if this the first note *after* a conflict
|
|
|
|
if (conflict || (chord->up() != isLeft))
|
2012-05-26 14:26:10 +02:00
|
|
|
isLeft = !isLeft;
|
|
|
|
|
2014-03-05 23:45:58 +01:00
|
|
|
// we need to mirror this note
|
|
|
|
// if it's not on the correct side
|
|
|
|
// previously we also skipped the mirror
|
|
|
|
// if it shared a note head with previous note
|
|
|
|
// but it's been suggested that it would be better
|
|
|
|
// to show the unison more clearly in a single voice chord
|
|
|
|
bool nmirror = (chord->up() != isLeft);
|
|
|
|
|
|
|
|
// two notes can *possibly* share a notehead if on same line and have same group and type
|
|
|
|
// however, we will only actually do this if user mirror
|
|
|
|
bool sameHead = (ll == line) && (nmirror == mirror);
|
|
|
|
|
|
|
|
// we will potentially hide note and dots
|
|
|
|
// for notes sharing a head
|
|
|
|
// we will only show them if one is nudged
|
2012-05-26 14:26:10 +02:00
|
|
|
note->setHidden(false);
|
2014-02-22 11:19:44 +01:00
|
|
|
note->setDotsHidden(false);
|
|
|
|
|
2014-03-05 23:45:58 +01:00
|
|
|
// now start the actual layout
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
chord->rxpos() = 0.0;
|
|
|
|
|
2014-03-05 23:45:58 +01:00
|
|
|
// handle conflict
|
|
|
|
if (conflict && (nmirror == mirror)) { // && idx
|
2012-05-26 14:26:10 +02:00
|
|
|
if (sameHead) {
|
2014-03-05 23:45:58 +01:00
|
|
|
Note* pnote = notes[idx-incIdx]; // idx-1
|
2012-06-09 10:50:51 +02:00
|
|
|
if (!(pnote->parent()->isNudged() || note->parent()->isNudged())) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (ticks > pnote->chord()->actualTicks()) {
|
|
|
|
pnote->setHidden(true);
|
2014-02-22 11:19:44 +01:00
|
|
|
if (chord->dots() == pnote->chord()->dots())
|
|
|
|
pnote->setDotsHidden(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
// TODO: pnote->setAccidentalType(ACC_NONE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// TODO: note->setAccidentalType(ACC_NONE);
|
|
|
|
note->setHidden(true);
|
2014-02-22 11:19:44 +01:00
|
|
|
if (chord->dots() == pnote->chord()->dots())
|
|
|
|
note->setDotsHidden(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2013-07-15 19:41:14 +02:00
|
|
|
qreal x = note->headWidth() - note->point(styleS(ST_stemWidth));
|
|
|
|
if ((line > ll) || !chord->up())
|
|
|
|
note->chord()->rxpos() = x;
|
|
|
|
else
|
|
|
|
notes[idx-incIdx]->chord()->rxpos() = x;
|
|
|
|
note->rxpos() = 0.0;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
2012-08-04 15:46:43 +02:00
|
|
|
if (note->userMirror() == MScore::DH_AUTO) {
|
2012-05-26 14:26:10 +02:00
|
|
|
mirror = nmirror;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mirror = note->chord()->up();
|
2012-08-04 15:46:43 +02:00
|
|
|
if (note->userMirror() == MScore::DH_LEFT)
|
2012-05-26 14:26:10 +02:00
|
|
|
mirror = !mirror;
|
|
|
|
}
|
|
|
|
note->setMirror(mirror);
|
|
|
|
move1 = move;
|
|
|
|
ll = line;
|
2014-03-05 23:45:58 +01:00
|
|
|
// lastHeadGroup = headGroup;
|
|
|
|
// lastHeadType = headType;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-03-05 23:45:58 +01:00
|
|
|
}
|
|
|
|
|
2014-03-12 22:52:59 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// AcEl
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
struct AcEl {
|
|
|
|
Note* note;
|
|
|
|
qreal x; // actual x position of this accidental relative to origin
|
|
|
|
qreal top; // top of accidental bbox relative to staff
|
|
|
|
qreal bottom; // bottom of accidental bbox relative to staff
|
|
|
|
int line; // line of note
|
2014-03-14 01:19:36 +01:00
|
|
|
qreal width; // width of accidental
|
2014-03-12 22:52:59 +01:00
|
|
|
// TODO: the following could all be read from a static table to save time
|
|
|
|
qreal overlap; // number of lines below which this accidental can overlap something
|
|
|
|
qreal undercut; // number of lines above which this accidental can undercut something
|
|
|
|
qreal overOffset; // amount this accidental can overlap something
|
|
|
|
qreal underOffset; // amount this accidental can undercut something
|
|
|
|
};
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// resolveAccidentals
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static bool resolveAccidentals(AcEl* left, AcEl* right, qreal& lx)
|
|
|
|
{
|
|
|
|
AcEl* upper;
|
|
|
|
AcEl* lower;
|
|
|
|
if (left->line >= right->line) {
|
|
|
|
upper = right;
|
|
|
|
lower = left;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
upper = left;
|
|
|
|
lower = right;
|
|
|
|
}
|
|
|
|
|
|
|
|
// no conflict if accidentals do not overlap at all
|
2014-03-15 16:57:08 +01:00
|
|
|
if (lower->top - upper->bottom > 0.001)
|
2014-03-12 22:52:59 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// sevenths in either direction need only a slight offset
|
|
|
|
// the following code lets the calling code add the offset (pnd)
|
|
|
|
if (lower->line - upper->line == 6) {
|
|
|
|
qreal offset = qMin(left->width, right->width);
|
|
|
|
lx = qMin(lx, right->x + offset);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// left accidental may be able to undercut right
|
|
|
|
else if (left == lower && lower->line - upper->line > qRound(upper->undercut + lower->overlap)) {
|
|
|
|
qreal offset = qMin(upper->overOffset, lower->underOffset);
|
|
|
|
lx = qMin(lx, right->x + offset);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, there is conflict
|
|
|
|
lx = qMin(lx, right->x);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-03-14 01:19:36 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutAccidental
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void layoutAccidental(AcEl* me, AcEl* above, AcEl* below, QList<Note*>& leftNotes, qreal pnd, qreal pd, qreal sp)
|
|
|
|
{
|
|
|
|
qreal lx;
|
|
|
|
|
|
|
|
// extra space for ledger lines
|
2014-03-14 22:50:25 +01:00
|
|
|
if (me->line <= -2 || me->line >= me->note->staff()->lines() * 2)
|
2014-03-14 01:19:36 +01:00
|
|
|
lx = -0.2 * sp;
|
|
|
|
else
|
|
|
|
lx = 0.0;
|
|
|
|
|
|
|
|
// clear left notes
|
|
|
|
int lns = leftNotes.size();
|
|
|
|
for (int i = 0; i < lns; ++i) {
|
|
|
|
Note* ln = leftNotes[i];
|
|
|
|
int lnLine = ln->line();
|
|
|
|
qreal lnTop = lnLine * 0.5 * sp - 0.5;
|
|
|
|
qreal lnBottom = lnTop + sp;
|
|
|
|
if (lnBottom >= me->top && lnTop <= me->bottom) {
|
|
|
|
// undercut note above if possible
|
|
|
|
if (me->line - lnLine > qRound(me->undercut) + 1)
|
|
|
|
lx = qMin(lx, ln->x() + me->underOffset);
|
|
|
|
else
|
|
|
|
lx = qMin(lx, ln->x());
|
|
|
|
}
|
|
|
|
else if (lnTop > me->bottom)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear other accidentals
|
|
|
|
bool conflictAbove = false;
|
|
|
|
bool conflictBelow = false;
|
|
|
|
Accidental* acc = me->note->accidental();
|
|
|
|
|
|
|
|
if (above)
|
|
|
|
conflictAbove = resolveAccidentals(me, above, lx);
|
|
|
|
if (below)
|
|
|
|
conflictBelow = resolveAccidentals(me, below, lx);
|
|
|
|
if (conflictAbove || conflictBelow)
|
|
|
|
me->x = lx - pd * acc->mag() - acc->width();
|
|
|
|
else
|
|
|
|
me->x = lx - pnd * acc->mag() - acc->width() - acc->bbox().x();
|
|
|
|
}
|
|
|
|
|
2014-03-05 23:45:58 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutChords3
|
|
|
|
// - calculate positions of notes, accidentals, dots
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutChords3(QList<Note*>& notes, Staff* staff, Segment* segment)
|
|
|
|
{
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------
|
|
|
|
// layout accidentals
|
|
|
|
// find column for dots
|
|
|
|
//---------------------------------------------------
|
|
|
|
|
2013-05-22 14:12:47 +02:00
|
|
|
std::vector<AcEl> aclist;
|
2014-03-12 22:52:59 +01:00
|
|
|
QList<Note*> leftNotes; // notes to left of origin
|
2013-05-22 14:12:47 +02:00
|
|
|
|
2014-03-12 22:52:59 +01:00
|
|
|
qreal sp = staff->spatium();
|
|
|
|
qreal stepDistance = sp * .5;
|
2013-05-29 12:21:42 +02:00
|
|
|
int stepOffset = staff->staffType()->stepOffset();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-03-08 07:43:24 +01:00
|
|
|
qreal lx = 10000.0; // leftmost note head position
|
|
|
|
qreal dotPosX = 0.0;
|
|
|
|
qreal offsetDotPosX = 0.0;
|
|
|
|
bool offsetDots = false;
|
2013-06-27 15:00:08 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
int nNotes = notes.size();
|
|
|
|
for (int i = nNotes-1; i >= 0; --i) {
|
|
|
|
Note* note = notes[i];
|
|
|
|
Accidental* ac = note->accidental();
|
|
|
|
if (ac) {
|
|
|
|
ac->layout();
|
|
|
|
AcEl acel;
|
2014-03-12 22:52:59 +01:00
|
|
|
acel.note = note;
|
|
|
|
acel.line = note->line();
|
|
|
|
acel.x = 0.0;
|
|
|
|
acel.top = acel.line * 0.5 * sp + ac->bbox().top();
|
|
|
|
acel.bottom = acel.line * 0.5 * sp + ac->bbox().bottom();
|
|
|
|
qreal width = ac->width();
|
|
|
|
acel.width = width;
|
|
|
|
switch (ac->accidentalType()) {
|
|
|
|
case Accidental::ACC_FLAT:
|
|
|
|
acel.overlap = 1;
|
|
|
|
acel.undercut = 1;
|
|
|
|
acel.overOffset = width;
|
|
|
|
acel.underOffset = width * 0.5;
|
|
|
|
break;
|
|
|
|
case Accidental::ACC_FLAT2:
|
|
|
|
acel.overlap = 1;
|
|
|
|
acel.undercut = 1;
|
|
|
|
acel.overOffset = width;
|
|
|
|
acel.underOffset = width * 0.25;
|
|
|
|
break;
|
|
|
|
case Accidental::ACC_NATURAL:
|
|
|
|
acel.overlap = 1.6;
|
|
|
|
acel.undercut = 1.6;
|
|
|
|
acel.overOffset = width * 0.5;
|
|
|
|
acel.underOffset = acel.overOffset;
|
|
|
|
break;
|
2014-03-13 00:52:00 +01:00
|
|
|
case Accidental::ACC_SHARP:
|
2014-03-13 01:01:05 +01:00
|
|
|
acel.overlap = 2.6;
|
|
|
|
acel.undercut = 2.6;
|
2014-03-13 00:52:00 +01:00
|
|
|
acel.overOffset = width;
|
|
|
|
acel.underOffset = width;
|
|
|
|
break;
|
2014-03-12 22:52:59 +01:00
|
|
|
case Accidental::ACC_SHARP2:
|
|
|
|
acel.overlap = 1;
|
|
|
|
acel.undercut = 1;
|
|
|
|
acel.overOffset = width;
|
|
|
|
acel.underOffset = width;
|
|
|
|
default:
|
|
|
|
acel.overlap = 4;
|
|
|
|
acel.undercut = 4;
|
|
|
|
acel.overOffset = width;
|
|
|
|
acel.underOffset = width;
|
|
|
|
}
|
2013-05-22 14:12:47 +02:00
|
|
|
aclist.push_back(acel);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-05-22 14:12:47 +02:00
|
|
|
qreal hw = note->headWidth();
|
|
|
|
|
|
|
|
Chord* chord = note->chord();
|
2013-06-04 18:29:14 +02:00
|
|
|
bool _up = chord->up();
|
2013-07-29 11:12:32 +02:00
|
|
|
qreal stemX = chord->stemPosX();
|
2013-05-22 14:12:47 +02:00
|
|
|
|
|
|
|
qreal stemWidth5;
|
|
|
|
if (chord->stem()) {
|
|
|
|
stemWidth5 = chord->stem()->lineWidth() * .5;
|
2013-09-18 22:05:17 +02:00
|
|
|
chord->stem()->rxpos() = _up ? stemX - stemWidth5 : stemWidth5;
|
2013-05-22 14:12:47 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
stemWidth5 = 0.0;
|
|
|
|
|
|
|
|
qreal x;
|
|
|
|
if (note->mirror()) {
|
|
|
|
if (_up)
|
|
|
|
x = stemX - stemWidth5 * 2;
|
|
|
|
else
|
|
|
|
x = stemX - hw + stemWidth5 * 2;
|
|
|
|
}
|
|
|
|
else {
|
2013-11-25 15:02:23 +01:00
|
|
|
NoteHeadType ht = chord->durationType().headType();
|
|
|
|
if (ht == NoteHeadType::HEAD_WHOLE || ht == NoteHeadType::HEAD_BREVIS) {
|
2013-07-16 10:01:44 +02:00
|
|
|
// center whole note
|
2013-08-12 16:41:15 +02:00
|
|
|
qreal xd = (hw - noteHeadWidth() * chord->mag()) * .5;
|
2013-07-16 10:01:44 +02:00
|
|
|
if (_up)
|
|
|
|
x = stemX - hw + xd;
|
|
|
|
else
|
|
|
|
x = -xd;
|
2013-09-18 22:05:17 +02:00
|
|
|
|
|
|
|
if(chord->stem())
|
|
|
|
chord->stem()->rxpos() += (_up ? xd : -xd);
|
2013-07-16 10:01:44 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (_up)
|
|
|
|
x = stemX - hw;
|
|
|
|
else
|
|
|
|
x = 0.0;
|
|
|
|
}
|
2013-05-22 14:12:47 +02:00
|
|
|
}
|
|
|
|
note->rypos() = (note->line() + stepOffset) * stepDistance;
|
|
|
|
note->rxpos() = x;
|
2014-03-12 22:52:59 +01:00
|
|
|
|
|
|
|
// accidental x position calculated from leftmost notehead
|
|
|
|
// not counting mirrored noteheads on non-offset downstem chords
|
|
|
|
// the latter are recorded for use later
|
|
|
|
// to displace accidentals as necessary
|
|
|
|
if (note->mirror() && !chord->up() && chord->rxpos() == 0.0)
|
|
|
|
leftNotes.append(note);
|
|
|
|
else if (x < lx)
|
2013-06-27 15:00:08 +02:00
|
|
|
lx = x;
|
2013-06-04 18:29:14 +02:00
|
|
|
|
2013-09-18 22:05:17 +02:00
|
|
|
//if (chord->stem())
|
|
|
|
// chord->stem()->rxpos() = _up ? x + hw - stemWidth5 : x + stemWidth5;
|
2013-09-10 01:17:39 +02:00
|
|
|
|
2013-06-04 18:29:14 +02:00
|
|
|
qreal xx = x + hw + note->chord()->pos().x();
|
2014-03-08 07:43:24 +01:00
|
|
|
if (note->chord()->rxpos() == 0.0)
|
|
|
|
dotPosX = qMax(dotPosX, xx);
|
|
|
|
else {
|
|
|
|
offsetDotPosX = qMax(offsetDotPosX, xx);
|
|
|
|
if (note->chord()->dots())
|
|
|
|
offsetDots = true;
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-05-22 14:12:47 +02:00
|
|
|
|
2014-03-08 07:43:24 +01:00
|
|
|
if (segment) {
|
|
|
|
if (offsetDots)
|
|
|
|
dotPosX = qMax(dotPosX, offsetDotPosX);
|
2013-06-10 21:13:04 +02:00
|
|
|
segment->setDotPosX(staff->idx(), dotPosX);
|
2014-03-08 07:43:24 +01:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
int nAcc = aclist.size();
|
|
|
|
if (nAcc == 0)
|
|
|
|
return;
|
2014-03-14 01:19:36 +01:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
qreal pd = point(styleS(ST_accidentalDistance));
|
|
|
|
qreal pnd = point(styleS(ST_accidentalNoteDistance));
|
2013-06-27 15:00:08 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
2014-03-14 01:19:36 +01:00
|
|
|
// use zig zag approach
|
|
|
|
// layout in pairs: right to left, high then low
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
2014-03-15 16:57:08 +01:00
|
|
|
// TODO: we really need special handling
|
|
|
|
// for large chords with lots of accidentals
|
|
|
|
// to avoid the "wedge effect"
|
|
|
|
// (accidentals forming a wedge with empty space within)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-03-14 01:19:36 +01:00
|
|
|
// layout top accidental
|
|
|
|
layoutAccidental(&aclist[0], 0, 0, leftNotes, pnd, pd, sp);
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
// layout bottom accidental
|
2014-03-14 01:19:36 +01:00
|
|
|
if (nAcc > 1)
|
|
|
|
layoutAccidental(&aclist[nAcc-1], &aclist[0], 0, leftNotes, pnd, pd, sp);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
// layout middle accidentals
|
|
|
|
if (nAcc > 2) {
|
|
|
|
int n = nAcc - 1;
|
2014-03-13 07:52:59 +01:00
|
|
|
AcEl* me = &aclist[n];
|
|
|
|
AcEl* above = &aclist[0];
|
|
|
|
AcEl* below;
|
|
|
|
for (int i = 1; i < n; ++i, --n) {
|
|
|
|
// next highest
|
|
|
|
below = me;
|
|
|
|
me = &aclist[i];
|
2014-03-14 01:19:36 +01:00
|
|
|
layoutAccidental(me, above, below, leftNotes, pnd, pd, sp);
|
2014-03-13 07:52:59 +01:00
|
|
|
|
|
|
|
if (i == n - 1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// next lowest
|
|
|
|
above = me;
|
|
|
|
me = &aclist[n-1];
|
2014-03-14 01:19:36 +01:00
|
|
|
layoutAccidental(me, above, below, leftNotes, pnd, pd, sp);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-22 14:12:47 +02:00
|
|
|
for (const AcEl& e : aclist) {
|
|
|
|
Note* note = e.note;
|
2014-03-09 07:09:40 +01:00
|
|
|
qreal x = e.x + lx - (note->x() + note->chord()->x());
|
2012-05-26 14:26:10 +02:00
|
|
|
note->accidental()->setPos(x, 0);
|
|
|
|
note->accidental()->adjustReadPos();
|
|
|
|
}
|
2014-03-05 23:45:58 +01:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2013-06-16 23:33:37 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// beamGraceNotes
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::beamGraceNotes(Chord* mainNote)
|
|
|
|
{
|
2013-11-24 20:39:58 +01:00
|
|
|
ChordRest* a1 = 0; // start of (potential) beam
|
|
|
|
Beam* beam = 0; // current beam
|
|
|
|
BeamMode bm = BeamMode::AUTO;
|
2013-07-10 18:01:37 +02:00
|
|
|
foreach (ChordRest* cr, mainNote->graceNotes()) {
|
2013-11-24 20:39:58 +01:00
|
|
|
bm = Groups::endBeam(cr);
|
|
|
|
if ((cr->durationType().type() <= TDuration::V_QUARTER) || (bm == BeamMode::NONE)) {
|
|
|
|
if (beam) {
|
|
|
|
beam->layoutGraceNotes();
|
|
|
|
beam = 0;
|
|
|
|
}
|
|
|
|
if (a1) {
|
|
|
|
a1->removeDeleteBeam();
|
|
|
|
a1 = 0;
|
|
|
|
}
|
|
|
|
cr->removeDeleteBeam();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (beam) {
|
|
|
|
bool beamEnd = bm == BeamMode::BEGIN;
|
|
|
|
if (!beamEnd) {
|
|
|
|
cr->removeDeleteBeam(true);
|
|
|
|
beam->add(cr);
|
|
|
|
cr = 0;
|
|
|
|
beamEnd = (bm == BeamMode::END);
|
|
|
|
}
|
|
|
|
if (beamEnd) {
|
|
|
|
beam->layoutGraceNotes();
|
|
|
|
beam = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!cr)
|
|
|
|
continue;
|
|
|
|
if (a1 == 0)
|
|
|
|
a1 = cr;
|
|
|
|
else {
|
|
|
|
if (!beamModeMid(bm) && (bm == BeamMode::BEGIN)) {
|
|
|
|
a1->removeDeleteBeam();
|
|
|
|
a1 = cr;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
beam = a1->beam();
|
|
|
|
if (beam == 0 || beam->elements().front() != a1) {
|
|
|
|
beam = new Beam(this);
|
|
|
|
beam->setGenerated(true);
|
|
|
|
beam->setTrack(mainNote->track());
|
|
|
|
a1->removeDeleteBeam(true);
|
|
|
|
beam->add(a1);
|
|
|
|
}
|
|
|
|
cr->removeDeleteBeam(true);
|
|
|
|
beam->add(cr);
|
|
|
|
a1 = 0;
|
|
|
|
}
|
|
|
|
}
|
2013-07-10 18:01:37 +02:00
|
|
|
}
|
2013-11-24 20:39:58 +01:00
|
|
|
if (beam)
|
|
|
|
beam->layoutGraceNotes();
|
|
|
|
else if (a1)
|
|
|
|
a1->removeDeleteBeam();
|
2013-06-16 23:33:37 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutStage2
|
|
|
|
// auto - beamer
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutStage2()
|
|
|
|
{
|
|
|
|
int tracks = nstaves() * VOICES;
|
2013-05-12 12:51:42 +02:00
|
|
|
bool crossMeasure = styleB(ST_crossMeasureValues);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
for (int track = 0; track < tracks; ++track) {
|
2014-03-10 10:36:36 +01:00
|
|
|
if (!staff(track2staff(track))->show())
|
|
|
|
continue;
|
2012-05-26 14:26:10 +02:00
|
|
|
ChordRest* a1 = 0; // start of (potential) beam
|
|
|
|
Beam* beam = 0; // current beam
|
|
|
|
Measure* measure = 0;
|
|
|
|
|
2013-03-05 20:23:59 +01:00
|
|
|
BeamMode bm = BeamMode::AUTO;
|
2013-06-12 14:23:57 +02:00
|
|
|
Segment::SegmentTypes st = Segment::SegChordRest;
|
2012-05-26 14:26:10 +02:00
|
|
|
for (Segment* segment = firstSegment(st); segment; segment = segment->next1(st)) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(segment->element(track));
|
|
|
|
if (cr == 0)
|
|
|
|
continue;
|
2013-07-11 12:25:25 +02:00
|
|
|
if (cr->type() == Element::CHORD) {
|
|
|
|
Chord* chord = static_cast<Chord*>(cr);
|
|
|
|
beamGraceNotes(chord);
|
|
|
|
|
|
|
|
// set up for cross-measure values as soon as possible
|
|
|
|
// to have all computations (stems, hooks, ...) consistent with it
|
|
|
|
if (!chord->isGrace())
|
|
|
|
chord->crossMeasureSetup(crossMeasure);
|
|
|
|
}
|
2013-05-27 19:07:03 +02:00
|
|
|
|
|
|
|
bm = Groups::endBeam(cr);
|
|
|
|
|
2012-11-26 00:28:25 +01:00
|
|
|
// if chord has hooks and is 2nd element of a cross-measure value
|
|
|
|
// set beam mode to NONE (do not combine with following chord beam/hook, if any)
|
2013-05-27 19:07:03 +02:00
|
|
|
|
2013-05-23 12:32:40 +02:00
|
|
|
if (cr->durationType().hooks() > 0 && cr->crossMeasure() == CROSSMEASURE_SECOND)
|
2012-11-26 00:28:25 +01:00
|
|
|
bm = BeamMode::NONE;
|
2012-05-26 14:26:10 +02:00
|
|
|
if (cr->measure() != measure) {
|
|
|
|
if (measure && !beamModeMid(bm)) {
|
|
|
|
if (beam) {
|
|
|
|
beam->layout1();
|
|
|
|
beam = 0;
|
|
|
|
}
|
|
|
|
else if (a1) {
|
|
|
|
a1->removeDeleteBeam();
|
|
|
|
a1 = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
measure = cr->measure();
|
|
|
|
if (!beamModeMid(bm)) {
|
|
|
|
a1 = 0;
|
|
|
|
beam = 0;
|
|
|
|
}
|
|
|
|
}
|
2013-03-26 23:11:24 +01:00
|
|
|
if ((cr->durationType().type() <= TDuration::V_QUARTER) || (bm == BeamMode::NONE)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (beam) {
|
|
|
|
beam->layout1();
|
|
|
|
beam = 0;
|
|
|
|
}
|
|
|
|
if (a1) {
|
|
|
|
a1->removeDeleteBeam();
|
|
|
|
a1 = 0;
|
|
|
|
}
|
|
|
|
cr->removeDeleteBeam();
|
|
|
|
continue;
|
|
|
|
}
|
2013-05-27 19:07:03 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
if (beam) {
|
2013-05-27 19:07:03 +02:00
|
|
|
bool beamEnd = bm == BeamMode::BEGIN;
|
|
|
|
if (!beamEnd) {
|
2013-07-11 12:25:25 +02:00
|
|
|
cr->removeDeleteBeam(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
beam->add(cr);
|
|
|
|
cr = 0;
|
2013-05-27 19:07:03 +02:00
|
|
|
beamEnd = (bm == BeamMode::END);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-05-27 19:07:03 +02:00
|
|
|
if (beamEnd) {
|
2012-05-26 14:26:10 +02:00
|
|
|
beam->layout1();
|
|
|
|
beam = 0;
|
|
|
|
}
|
2013-05-27 19:07:03 +02:00
|
|
|
}
|
|
|
|
if (!cr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (a1 == 0)
|
|
|
|
a1 = cr;
|
|
|
|
else {
|
|
|
|
if (!beamModeMid(bm)
|
|
|
|
&&
|
|
|
|
(bm == BeamMode::BEGIN
|
|
|
|
|| (a1->segment()->segmentType() != cr->segment()->segmentType())
|
|
|
|
|| (a1->tick() + a1->actualTicks() < cr->tick())
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
a1->removeDeleteBeam();
|
|
|
|
a1 = cr;
|
|
|
|
}
|
|
|
|
else {
|
2012-05-26 14:26:10 +02:00
|
|
|
beam = a1->beam();
|
|
|
|
if (beam == 0 || beam->elements().front() != a1) {
|
|
|
|
beam = new Beam(this);
|
|
|
|
beam->setGenerated(true);
|
2013-05-27 19:07:03 +02:00
|
|
|
beam->setTrack(track);
|
2013-07-11 12:25:25 +02:00
|
|
|
a1->removeDeleteBeam(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
beam->add(a1);
|
|
|
|
}
|
2013-07-11 12:25:25 +02:00
|
|
|
cr->removeDeleteBeam(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
beam->add(cr);
|
|
|
|
a1 = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (beam)
|
|
|
|
beam->layout1();
|
2013-07-11 12:25:25 +02:00
|
|
|
else if (a1)
|
2012-05-26 14:26:10 +02:00
|
|
|
a1->removeDeleteBeam();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutStage3
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutStage3()
|
|
|
|
{
|
2013-06-12 14:23:57 +02:00
|
|
|
Segment::SegmentTypes st = Segment::SegChordRest;
|
2012-05-26 14:26:10 +02:00
|
|
|
for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
|
2014-03-10 10:36:36 +01:00
|
|
|
if (!staff(staffIdx)->show())
|
|
|
|
continue;
|
2012-05-26 14:26:10 +02:00
|
|
|
for (Segment* segment = firstSegment(st); segment; segment = segment->next1(st)) {
|
|
|
|
layoutChords1(segment, staffIdx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// layout
|
|
|
|
// - measures are akkumulated into systems
|
|
|
|
// - systems are akkumulated into pages
|
|
|
|
// already existent systems and pages are reused
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::doLayout()
|
|
|
|
{
|
2013-11-07 19:58:42 +01:00
|
|
|
_scoreFont = ScoreFont::fontFactory(_style.value(ST_MusicalSymbolFont).toString());
|
2013-11-11 15:11:28 +01:00
|
|
|
_noteHeadWidth = _scoreFont->width(SymId::noteheadBlack, spatium() / (MScore::DPI * SPATIUM20));
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
if (layoutFlags & LAYOUT_FIX_TICKS)
|
|
|
|
fixTicks();
|
|
|
|
if (layoutFlags & LAYOUT_FIX_PITCH_VELO)
|
|
|
|
updateVelo();
|
2012-11-21 13:49:08 +01:00
|
|
|
if (layoutFlags & LAYOUT_PLAY_EVENTS)
|
|
|
|
createPlayEvents();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-09-19 15:08:54 +02:00
|
|
|
int measureNo = 0;
|
2013-09-20 12:59:31 +02:00
|
|
|
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
|
|
|
|
Measure* measure = static_cast<Measure*>(m);
|
|
|
|
measureNo += measure->noOffset();
|
|
|
|
measure->setNo(measureNo);
|
|
|
|
if (measure->sectionBreak() && measure->sectionBreak()->startWithMeasureOne())
|
|
|
|
measureNo = 0;
|
|
|
|
else if (measure->irregular()) // dont count measure
|
|
|
|
;
|
|
|
|
else
|
|
|
|
++measureNo;
|
|
|
|
measure->setBreakMMRest(false);
|
2013-09-19 15:08:54 +02:00
|
|
|
}
|
|
|
|
|
2013-09-20 12:59:31 +02:00
|
|
|
for (MeasureBase* m = first(); m; m = m->next())
|
2012-05-26 14:26:10 +02:00
|
|
|
m->layout0();
|
|
|
|
|
|
|
|
layoutFlags = 0;
|
|
|
|
|
|
|
|
int nstaves = _staves.size();
|
|
|
|
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
|
|
|
|
Staff* st = _staves[staffIdx];
|
|
|
|
if (!st->updateKeymap())
|
|
|
|
continue;
|
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
st->keymap()->clear();
|
|
|
|
KeySig* key1 = 0;
|
|
|
|
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
|
|
|
|
for (Segment* s = m->first(); s; s = s->next()) {
|
|
|
|
Element* e = s->element(track);
|
|
|
|
if (e == 0 || e->generated())
|
|
|
|
continue;
|
2013-09-25 11:13:50 +02:00
|
|
|
if ((s->segmentType() == Segment::SegKeySig)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
KeySig* ks = static_cast<KeySig*>(e);
|
|
|
|
int naturals = key1 ? key1->keySigEvent().accidentalType() : 0;
|
|
|
|
ks->setOldSig(naturals);
|
|
|
|
st->setKey(s->tick(), ks->keySigEvent());
|
|
|
|
key1 = ks;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m->sectionBreak() && (_layoutMode != LayoutFloat))
|
|
|
|
key1 = 0;
|
|
|
|
}
|
|
|
|
st->setUpdateKeymap(false);
|
|
|
|
}
|
|
|
|
if (_staves.isEmpty() || first() == 0) {
|
|
|
|
// score is empty
|
2012-12-06 12:46:05 +01:00
|
|
|
qDeleteAll(_pages);
|
2012-05-26 14:26:10 +02:00
|
|
|
_pages.clear();
|
|
|
|
|
|
|
|
Page* page = addPage();
|
|
|
|
page->layout();
|
|
|
|
page->setNo(0);
|
|
|
|
page->setPos(0.0, 0.0);
|
|
|
|
page->rebuildBspTree();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-06 12:46:05 +01:00
|
|
|
for (Measure* m = firstMeasure(); m; m = m->nextMeasure())
|
|
|
|
m->layoutStage1();
|
2013-09-19 15:08:54 +02:00
|
|
|
if (styleB(ST_createMultiMeasureRests))
|
|
|
|
createMMRests();
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
layoutStage2(); // beam notes, finally decide if chord is up/down
|
|
|
|
layoutStage3(); // compute note head horizontal positions
|
|
|
|
|
|
|
|
if (layoutMode() == LayoutLine)
|
|
|
|
layoutLinear();
|
2012-12-10 17:44:57 +01:00
|
|
|
else
|
2012-05-26 14:26:10 +02:00
|
|
|
layoutSystems(); // create list of systems
|
|
|
|
|
|
|
|
//---------------------------------------------------
|
|
|
|
// place Spanner & beams
|
|
|
|
//---------------------------------------------------
|
|
|
|
|
|
|
|
int tracks = nstaves * VOICES;
|
|
|
|
for (int track = 0; track < tracks; ++track) {
|
2013-10-02 10:26:09 +02:00
|
|
|
for (Segment* segment = firstSegmentMM(); segment; segment = segment->next1MM()) {
|
2012-12-06 12:46:05 +01:00
|
|
|
if (track == tracks-1) {
|
2013-09-03 14:00:07 +02:00
|
|
|
for (Element* e : segment->annotations())
|
|
|
|
e->layout();
|
2012-12-06 12:46:05 +01:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
Element* e = segment->element(track);
|
2012-12-06 12:46:05 +01:00
|
|
|
if (!e)
|
|
|
|
continue;
|
|
|
|
if (e->isChordRest()) {
|
2014-03-10 10:36:36 +01:00
|
|
|
if (!staff(track2staff(track))->show())
|
|
|
|
continue;
|
2012-05-26 14:26:10 +02:00
|
|
|
ChordRest* cr = static_cast<ChordRest*>(e);
|
|
|
|
if (cr->beam() && cr->beam()->elements().front() == cr)
|
|
|
|
cr->beam()->layout();
|
|
|
|
|
2012-09-13 18:01:34 +02:00
|
|
|
if (cr->type() == Element::CHORD) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Chord* c = static_cast<Chord*>(cr);
|
2013-06-16 23:33:37 +02:00
|
|
|
for (Chord* cc : c->graceNotes()) {
|
2013-06-20 10:19:04 +02:00
|
|
|
if (cc->beam() && cc->beam()->elements().front() == cc)
|
2013-06-16 23:33:37 +02:00
|
|
|
cc->beam()->layout();
|
2013-06-20 17:23:24 +02:00
|
|
|
for (Element* e : cc->el()) {
|
|
|
|
if (e->type() == Element::SLUR)
|
|
|
|
e->layout();
|
|
|
|
}
|
2013-06-16 23:33:37 +02:00
|
|
|
}
|
2013-06-20 10:19:04 +02:00
|
|
|
c->layoutStem();
|
2012-05-26 14:26:10 +02:00
|
|
|
c->layoutArpeggio2();
|
2013-07-04 13:40:25 +02:00
|
|
|
for (Note* n : c->notes()) {
|
|
|
|
Tie* tie = n->tieFor();
|
2012-05-26 14:26:10 +02:00
|
|
|
if (tie)
|
|
|
|
tie->layout();
|
2013-07-04 13:40:25 +02:00
|
|
|
for (Spanner* sp : n->spannerFor())
|
|
|
|
sp->layout();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cr->layoutArticulations();
|
|
|
|
}
|
2012-12-06 12:46:05 +01:00
|
|
|
else if (e->type() == Element::BAR_LINE)
|
2012-05-26 14:26:10 +02:00
|
|
|
e->layout();
|
|
|
|
}
|
|
|
|
}
|
2013-07-23 19:08:24 +02:00
|
|
|
for (const std::pair<int,Spanner*>& s : _spanner.map()) {
|
|
|
|
Spanner* sp = s.second;
|
|
|
|
if (sp->type() == Element::OTTAVA && sp->tick2() == -1) {
|
|
|
|
sp->setTick2(lastMeasure()->endTick());
|
|
|
|
sp->staff()->updateOttava(static_cast<Ottava*>(sp));
|
|
|
|
}
|
2013-10-02 10:26:09 +02:00
|
|
|
// 1.3 scores can have ties in this list
|
|
|
|
if (sp->type() != Element::TIE) {
|
|
|
|
if (sp->tick() == -1) {
|
|
|
|
qDebug("bad spanner id %d %s %d - %d", sp->id(), sp->name(), sp->tick(), sp->tick2());
|
|
|
|
}
|
2014-02-24 13:53:43 +01:00
|
|
|
else
|
2013-10-02 10:26:09 +02:00
|
|
|
sp->layout();
|
2013-07-23 19:08:24 +02:00
|
|
|
}
|
|
|
|
}
|
2012-12-10 17:44:57 +01:00
|
|
|
if (layoutMode() != LayoutLine) {
|
|
|
|
layoutSystems2();
|
|
|
|
layoutPages(); // create list of pages
|
|
|
|
}
|
2013-09-19 15:08:54 +02:00
|
|
|
for (Measure* m = firstMeasureMM(); m; m = m->nextMeasureMM())
|
2012-05-26 14:26:10 +02:00
|
|
|
m->layout2();
|
|
|
|
|
2013-07-23 19:08:24 +02:00
|
|
|
rebuildBspTree();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2012-12-06 12:46:05 +01:00
|
|
|
int n = viewer.size();
|
2013-08-23 03:32:16 +02:00
|
|
|
for (int i = 0; i < n; ++i) {
|
2012-12-06 12:46:05 +01:00
|
|
|
viewer.at(i)->layoutChanged();
|
2013-08-23 03:32:16 +02:00
|
|
|
viewer.at(i)->updateLoopCursors();
|
|
|
|
}
|
|
|
|
|
2013-06-27 11:02:42 +02:00
|
|
|
_layoutAll = false;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2013-07-23 18:49:26 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutSpanner
|
2013-07-23 19:08:24 +02:00
|
|
|
// called after dragging a staff
|
2013-07-23 18:49:26 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutSpanner()
|
|
|
|
{
|
2013-07-23 19:08:24 +02:00
|
|
|
int tracks = ntracks();
|
|
|
|
for (int track = 0; track < tracks; ++track) {
|
|
|
|
for (Segment* segment = firstSegment(); segment; segment = segment->next1()) {
|
|
|
|
if (track == tracks-1) {
|
|
|
|
int n = segment->annotations().size();
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
segment->annotations().at(i)->layout();
|
|
|
|
}
|
|
|
|
Element* e = segment->element(track);
|
|
|
|
if (!e)
|
|
|
|
continue;
|
|
|
|
if (e->isChordRest()) {
|
|
|
|
Chord* c = static_cast<Chord*>(e);
|
|
|
|
if (c->type() == Element::CHORD) {
|
|
|
|
for (Chord* cc : c->graceNotes()) {
|
|
|
|
for (Element* e : cc->el()) {
|
|
|
|
if (e->type() == Element::SLUR)
|
|
|
|
e->layout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c->layoutStem();
|
|
|
|
for (Note* n : c->notes()) {
|
|
|
|
Tie* tie = n->tieFor();
|
|
|
|
if (tie)
|
|
|
|
tie->layout();
|
|
|
|
for (Spanner* sp : n->spannerFor())
|
|
|
|
sp->layout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-23 18:49:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
rebuildBspTree();
|
|
|
|
}
|
|
|
|
|
2012-08-02 18:33:43 +02:00
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// addSystemHeader
|
|
|
|
/// Add elements to make this measure suitable as the first measure
|
|
|
|
/// of a system.
|
|
|
|
// The system header can contain a Clef, a KeySig and a
|
|
|
|
// RepeatBarLine.
|
|
|
|
//-------------------------------------------------------------------
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2012-08-02 18:33:43 +02:00
|
|
|
void Score::addSystemHeader(Measure* m, bool isFirstSystem)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2012-08-02 18:33:43 +02:00
|
|
|
if (undoRedo()) // no change possible in this state
|
2012-06-10 10:35:17 +02:00
|
|
|
return;
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
int tick = m->tick();
|
2012-07-31 09:48:37 +02:00
|
|
|
int i = 0;
|
2012-05-26 14:26:10 +02:00
|
|
|
foreach (Staff* staff, _staves) {
|
|
|
|
if (!m->system()->staff(i)->show()) {
|
|
|
|
++i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeySig* keysig = 0;
|
|
|
|
Clef* clef = 0;
|
|
|
|
int strack = i * VOICES;
|
|
|
|
|
|
|
|
// we assume that keysigs and clefs are only in the first
|
|
|
|
// track (voice 0) of a staff
|
|
|
|
|
|
|
|
const KeySigEvent& keyIdx = staff->key(tick);
|
|
|
|
const KeySigEvent& oKeySigBefore = staff->key(tick-1);
|
|
|
|
|
|
|
|
for (Segment* seg = m->first(); seg; seg = seg->next()) {
|
|
|
|
// search only up to the first ChordRest
|
2013-03-05 20:23:59 +01:00
|
|
|
if (seg->segmentType() == Segment::SegChordRest)
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
Element* el = seg->element(strack);
|
|
|
|
if (!el)
|
|
|
|
continue;
|
|
|
|
switch (el->type()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
case Element::KEYSIG:
|
2012-05-26 14:26:10 +02:00
|
|
|
keysig = static_cast<KeySig*>(el);
|
|
|
|
keysig->changeKeySigEvent(keyIdx);
|
|
|
|
if (!keysig->isCustom() && oKeySigBefore.accidentalType() == keysig->keySignature())
|
|
|
|
keysig->setOldSig(0);
|
|
|
|
break;
|
2012-09-13 18:01:34 +02:00
|
|
|
case Element::CLEF:
|
2012-05-26 14:26:10 +02:00
|
|
|
clef = static_cast<Clef*>(el);
|
|
|
|
clef->setSmall(false);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-09-04 19:17:47 +02:00
|
|
|
bool needKeysig = /* !staff->isTabStaff() // keep key sigs in TABs: TABs themselves should hide them
|
|
|
|
&& */ keyIdx.isValid()
|
2012-07-31 09:48:37 +02:00
|
|
|
&& (isFirstSystem || styleB(ST_genKeysig));
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
if (needKeysig && !keysig) {
|
|
|
|
//
|
|
|
|
// create missing key signature
|
|
|
|
//
|
|
|
|
keysig = keySigFactory(keyIdx);
|
|
|
|
if (keysig) {
|
|
|
|
// if signature is not custom or prev. signature has same accid. as
|
|
|
|
// this one, reset naturals
|
|
|
|
if (!keysig->isCustom() && oKeySigBefore.accidentalType() == keysig->keySignature())
|
|
|
|
keysig->setOldSig(0);
|
|
|
|
keysig->setTrack(i * VOICES);
|
|
|
|
keysig->setGenerated(true);
|
2012-08-03 15:54:02 +02:00
|
|
|
Segment* seg = m->undoGetSegment(Segment::SegKeySig, tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
keysig->setParent(seg);
|
2012-07-31 09:48:37 +02:00
|
|
|
keysig->layout();
|
2012-05-26 14:26:10 +02:00
|
|
|
undoAddElement(keysig);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!needKeysig && keysig)
|
|
|
|
undoRemoveElement(keysig);
|
2013-09-25 11:13:50 +02:00
|
|
|
else if (keysig && keysig->keySigEvent() != keyIdx)
|
|
|
|
undo(new ChangeKeySig(keysig, keyIdx, keysig->showCourtesy(), keysig->showNaturals()));
|
2012-07-31 09:48:37 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
bool needClef = isFirstSystem || styleB(ST_genClef);
|
|
|
|
if (needClef) {
|
|
|
|
if (!clef) {
|
|
|
|
//
|
|
|
|
// create missing clef
|
|
|
|
//
|
|
|
|
clef = new Clef(this);
|
|
|
|
clef->setTrack(i * VOICES);
|
|
|
|
clef->setSmall(false);
|
2013-09-16 13:17:57 +02:00
|
|
|
clef->setGenerated(staff->clef(tick) == staff->clef(tick-1));
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2012-08-03 15:54:02 +02:00
|
|
|
Segment* s = m->undoGetSegment(Segment::SegClef, tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
clef->setParent(s);
|
2012-07-31 09:48:37 +02:00
|
|
|
clef->layout();
|
2013-03-08 19:33:30 +01:00
|
|
|
clef->setClefType(staff->clefTypeList(tick)); // set before add !
|
2012-05-26 14:26:10 +02:00
|
|
|
undoAddElement(clef);
|
|
|
|
}
|
2013-09-04 17:41:12 +02:00
|
|
|
else if (clef->generated()) {
|
|
|
|
ClefTypeList cl = staff->clefTypeList(tick);
|
|
|
|
if (cl != clef->clefTypeList())
|
|
|
|
undo(new ChangeClefType(clef, cl._concertClef, cl._transposingClef));
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (clef && clef->generated())
|
|
|
|
undoRemoveElement(clef);
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
2012-08-02 18:33:43 +02:00
|
|
|
m->setStartRepeatBarLine(m->repeatFlags() & RepeatStart);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// getNextSystem
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
System* Score::getNextSystem(bool isFirstSystem, bool isVbox)
|
|
|
|
{
|
|
|
|
System* system;
|
|
|
|
if (curSystem >= _systems.size()) {
|
|
|
|
system = new System(this);
|
|
|
|
_systems.append(system);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
system = _systems[curSystem];
|
|
|
|
system->clear(); // remove measures from system
|
|
|
|
}
|
|
|
|
system->setFirstSystem(isFirstSystem);
|
|
|
|
system->setVbox(isVbox);
|
|
|
|
if (!isVbox) {
|
|
|
|
int nstaves = Score::nstaves();
|
|
|
|
for (int i = system->staves()->size(); i < nstaves; ++i)
|
|
|
|
system->insertStaff(i);
|
|
|
|
int dn = system->staves()->size() - nstaves;
|
|
|
|
for (int i = 0; i < dn; ++i)
|
|
|
|
system->removeStaff(system->staves()->size()-1);
|
|
|
|
}
|
|
|
|
return system;
|
|
|
|
}
|
|
|
|
|
2013-10-15 15:39:01 +02:00
|
|
|
//---------------------------------------------------------
|
2013-10-15 16:42:22 +02:00
|
|
|
// validMMRestMeasure
|
|
|
|
// return true if this might be a measure in a
|
|
|
|
// multi measure rest
|
2013-10-15 15:39:01 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-10-15 16:42:22 +02:00
|
|
|
static bool validMMRestMeasure(Measure* m)
|
2013-10-15 15:39:01 +02:00
|
|
|
{
|
2013-10-15 16:42:22 +02:00
|
|
|
if (!m->isEmpty())
|
|
|
|
return false;
|
2014-02-24 13:53:43 +01:00
|
|
|
|
|
|
|
auto l = m->score()->spannerMap().findOverlapping(m->tick(), m->endTick());
|
|
|
|
for (::Interval<Spanner*> isp : l) {
|
|
|
|
Spanner* s = isp.value;
|
|
|
|
if (s->type() == Element::VOLTA && (s->tick() == m->tick() || s->tick2() == m->tick()))
|
|
|
|
return false;
|
|
|
|
}
|
2013-10-15 16:42:22 +02:00
|
|
|
for (Segment* s = m->first(); s; s = s->next()) {
|
2013-10-25 12:17:42 +02:00
|
|
|
for (Element* e : s->annotations()) {
|
2014-03-03 16:50:45 +01:00
|
|
|
if(e->type() != Element::REHEARSAL_MARK && e->type() != Element::TEMPO_TEXT && e->type() != Element::STAFF_TEXT)
|
2013-10-25 12:17:42 +02:00
|
|
|
return false;
|
|
|
|
}
|
2013-10-15 16:42:22 +02:00
|
|
|
}
|
|
|
|
return true;
|
2013-10-15 15:39:01 +02:00
|
|
|
}
|
|
|
|
|
2013-10-25 12:17:42 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// breakMultiMeasureRest
|
|
|
|
// return true if this measure should start a new
|
|
|
|
// multi measure rest
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static bool breakMultiMeasureRest(Measure* m)
|
|
|
|
{
|
|
|
|
if (m->breakMultiMeasureRest())
|
|
|
|
return true;
|
2013-10-30 09:42:08 +01:00
|
|
|
auto sl = m->score()->spannerMap().findOverlapping(m->tick(), m->endTick());
|
2014-02-12 10:58:00 +01:00
|
|
|
foreach (auto i, sl) {
|
|
|
|
Spanner* s = i.value;
|
2014-02-24 13:53:43 +01:00
|
|
|
if (s->type() == Element::VOLTA) {
|
|
|
|
if (s->tick() == m->tick() || s->tick2() == m->tick())
|
2014-02-12 10:58:00 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-25 12:17:42 +02:00
|
|
|
for (Segment* s = m->first(); s; s = s->next()) {
|
|
|
|
for (Element* e : s->annotations()) {
|
2014-02-13 16:45:10 +01:00
|
|
|
if (e->type() == Element::REHEARSAL_MARK ||
|
|
|
|
e->type() == Element::TEMPO_TEXT ||
|
2014-03-03 16:50:45 +01:00
|
|
|
(e->type() == Element::STAFF_TEXT && (e->systemFlag() || m->score()->staff(e->staffIdx())->show())))
|
2013-10-25 12:17:42 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
2013-09-19 15:08:54 +02:00
|
|
|
// createMMRests
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-09-19 15:08:54 +02:00
|
|
|
void Score::createMMRests()
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-09-19 15:08:54 +02:00
|
|
|
//
|
|
|
|
// create mm rest measures
|
|
|
|
//
|
|
|
|
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
|
|
|
|
Measure* nm = m;
|
|
|
|
Measure* lm = nm;
|
|
|
|
int n = 0;
|
|
|
|
Fraction len;
|
2013-10-15 16:42:22 +02:00
|
|
|
while (validMMRestMeasure(nm)) {
|
2013-09-27 18:43:25 +02:00
|
|
|
m->setMMRestCount(0);
|
2013-09-19 15:08:54 +02:00
|
|
|
MeasureBase* mb = _showVBox ? nm->next() : nm->nextMeasure();
|
2013-10-25 12:17:42 +02:00
|
|
|
if (breakMultiMeasureRest(nm) && n)
|
2013-09-19 15:08:54 +02:00
|
|
|
break;
|
|
|
|
++n;
|
|
|
|
len += nm->len();
|
|
|
|
lm = nm;
|
|
|
|
nm = static_cast<Measure*>(mb);
|
2013-10-28 15:52:32 +01:00
|
|
|
if (!nm || (nm->type() != Element::MEASURE))
|
2013-09-19 15:08:54 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n >= styleI(ST_minEmptyMeasures)) {
|
|
|
|
//
|
|
|
|
// create a multi measure rest from m to lm (inclusive)
|
|
|
|
// attach the measure to m
|
|
|
|
//
|
2013-10-28 15:52:32 +01:00
|
|
|
|
2013-09-27 18:43:25 +02:00
|
|
|
for (Measure* mm = m->nextMeasure(); mm; mm = mm->nextMeasure()) {
|
|
|
|
mm->setMMRestCount(-1);
|
|
|
|
if (mm == lm)
|
|
|
|
break;
|
|
|
|
}
|
2013-10-28 15:52:32 +01:00
|
|
|
|
2013-09-20 17:21:12 +02:00
|
|
|
Measure* mmr;
|
|
|
|
if (m->mmRest()) {
|
|
|
|
mmr = m->mmRest();
|
2013-10-28 15:52:32 +01:00
|
|
|
if (mmr->len() != len) {
|
2013-09-20 17:21:12 +02:00
|
|
|
Segment* s = mmr->findSegment(Segment::SegEndBarLine, mmr->endTick());
|
|
|
|
mmr->setLen(len);
|
2013-09-23 12:26:16 +02:00
|
|
|
if (s)
|
|
|
|
s->setTick(mmr->endTick());
|
2013-09-20 17:21:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mmr = new Measure(this);
|
|
|
|
mmr->setLen(len);
|
2013-10-30 14:21:08 +01:00
|
|
|
undo(new ChangeMMRest(m, mmr));
|
2013-09-20 17:21:12 +02:00
|
|
|
}
|
|
|
|
|
2013-09-19 15:08:54 +02:00
|
|
|
mmr->setMMRestCount(n);
|
|
|
|
mmr->setTick(m->tick());
|
|
|
|
mmr->setNo(m->no());
|
2013-09-27 18:43:25 +02:00
|
|
|
mmr->setPageBreak(lm->pageBreak());
|
|
|
|
mmr->setLineBreak(lm->lineBreak());
|
|
|
|
mmr->setSectionBreak(lm->sectionBreak());
|
2013-09-23 13:39:46 +02:00
|
|
|
mmr->setEndBarLineType(lm->endBarLineType(), false, lm->endBarLineVisible(), lm->endBarLineColor());
|
2014-02-12 17:47:57 +01:00
|
|
|
mmr->setRepeatFlags(lm->repeatFlags());
|
2013-10-30 14:21:08 +01:00
|
|
|
|
2013-09-27 18:43:25 +02:00
|
|
|
qDeleteAll(*mmr->el());
|
|
|
|
mmr->el()->clear();
|
|
|
|
for (Element* e : *lm->el())
|
|
|
|
mmr->add(e->clone());
|
|
|
|
|
2013-10-30 14:21:08 +01:00
|
|
|
Segment* s = mmr->undoGetSegment(Segment::SegChordRest, m->tick());
|
2013-09-19 15:08:54 +02:00
|
|
|
for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
|
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
if (s->element(track) == 0) {
|
|
|
|
Rest* r = new Rest(this);
|
|
|
|
r->setDurationType(TDuration::V_MEASURE);
|
|
|
|
r->setTrack(track);
|
2013-10-30 14:21:08 +01:00
|
|
|
r->setParent(s);
|
|
|
|
undo(new AddElement(r));
|
2013-09-19 15:08:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// check for clefs
|
|
|
|
//
|
|
|
|
Segment* cs = lm->findSegment(Segment::SegClef, lm->endTick());
|
2013-10-30 14:21:08 +01:00
|
|
|
Segment* ns = mmr->findSegment(Segment::SegClef, lm->endTick());
|
2013-09-19 15:08:54 +02:00
|
|
|
if (cs) {
|
2013-10-30 14:21:08 +01:00
|
|
|
if (ns == 0)
|
|
|
|
ns = mmr->undoGetSegment(Segment::SegClef, lm->endTick());
|
2013-09-19 15:08:54 +02:00
|
|
|
for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
|
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
Clef* clef = static_cast<Clef*>(cs->element(track));
|
|
|
|
if (clef) {
|
|
|
|
if (ns->element(track) == 0)
|
|
|
|
ns->add(clef->clone());
|
|
|
|
else {
|
|
|
|
//TODO: check if same clef
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-10-30 14:21:08 +01:00
|
|
|
else if (ns)
|
|
|
|
undo(new RemoveElement(ns));
|
2013-09-19 15:08:54 +02:00
|
|
|
//
|
|
|
|
// check for time signature
|
|
|
|
//
|
|
|
|
cs = m->findSegment(Segment::SegTimeSig, m->tick());
|
2013-10-30 14:21:08 +01:00
|
|
|
ns = mmr->findSegment(Segment::SegTimeSig, m->tick());
|
2013-09-19 15:08:54 +02:00
|
|
|
if (cs) {
|
2013-10-30 14:21:08 +01:00
|
|
|
if (ns == 0)
|
|
|
|
ns = mmr->undoGetSegment(Segment::SegTimeSig, m->tick());
|
2013-09-19 15:08:54 +02:00
|
|
|
for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
|
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
TimeSig* ts = static_cast<TimeSig*>(cs->element(track));
|
|
|
|
if (ts) {
|
2013-10-30 14:21:08 +01:00
|
|
|
if (ns->element(track) == 0) {
|
|
|
|
TimeSig* nts = ts->clone();
|
|
|
|
nts->setParent(ns);
|
|
|
|
undo(new AddElement(nts));
|
|
|
|
}
|
2013-09-19 15:08:54 +02:00
|
|
|
else {
|
|
|
|
//TODO: check if same time signature
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-10-30 14:21:08 +01:00
|
|
|
else if (ns)
|
|
|
|
undo(new RemoveElement(ns));
|
|
|
|
|
2013-09-19 17:17:22 +02:00
|
|
|
//
|
|
|
|
// check for key signature
|
|
|
|
//
|
|
|
|
cs = m->findSegment(Segment::SegKeySig, m->tick());
|
2013-10-30 14:21:08 +01:00
|
|
|
ns = mmr->findSegment(Segment::SegKeySig, m->tick());
|
2013-09-19 17:17:22 +02:00
|
|
|
if (cs) {
|
2013-10-30 14:21:08 +01:00
|
|
|
if (ns == 0)
|
|
|
|
ns = mmr->undoGetSegment(Segment::SegKeySig, m->tick());
|
2013-09-19 17:17:22 +02:00
|
|
|
for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
|
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
KeySig* ts = static_cast<KeySig*>(cs->element(track));
|
|
|
|
if (ts) {
|
|
|
|
if (ns->element(track) == 0)
|
|
|
|
ns->add(ts->clone());
|
|
|
|
else {
|
|
|
|
//TODO: check if same key signature
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-10-30 14:21:08 +01:00
|
|
|
else if (ns)
|
|
|
|
undo(new RemoveElement(ns));
|
|
|
|
|
2013-10-25 12:17:42 +02:00
|
|
|
//
|
|
|
|
// check for rehearsal mark and tempo text
|
|
|
|
//
|
|
|
|
cs = m->findSegment(Segment::SegChordRest, m->tick());
|
|
|
|
for (Element* e : cs->annotations()) {
|
2014-02-13 16:45:10 +01:00
|
|
|
if (e->type() != Element::REHEARSAL_MARK && e->type() != Element::TEMPO_TEXT && e->type() != Element::STAFF_TEXT)
|
2013-10-30 14:21:08 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
for (Element* ee : s->annotations()) {
|
|
|
|
if (ee->type() == e->type() && ee->track() == e->track()) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
2014-02-25 13:50:53 +01:00
|
|
|
Element* ne = e->linkedClone();
|
2013-10-30 14:21:08 +01:00
|
|
|
ne->setParent(s);
|
|
|
|
undo(new AddElement(ne));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (Element* e : s->annotations()) {
|
2014-02-13 16:45:10 +01:00
|
|
|
if (e->type() != Element::REHEARSAL_MARK && e->type() != Element::TEMPO_TEXT && e->type() != Element::STAFF_TEXT)
|
2013-10-30 14:21:08 +01:00
|
|
|
continue;
|
|
|
|
bool found = false;
|
|
|
|
for (Element* ee : cs->annotations()) {
|
|
|
|
if (ee->type() == e->type() && ee->track() == e->track()) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
2013-10-25 12:17:42 +02:00
|
|
|
}
|
2013-10-30 14:21:08 +01:00
|
|
|
if (!found)
|
|
|
|
undo(new RemoveElement(e));
|
2013-10-25 12:17:42 +02:00
|
|
|
}
|
|
|
|
|
2013-09-19 15:08:54 +02:00
|
|
|
mmr->setNext(nm);
|
|
|
|
mmr->setPrev(m->prev());
|
|
|
|
m = lm;
|
|
|
|
}
|
|
|
|
else if (m->mmRest()) {
|
2013-10-30 14:21:08 +01:00
|
|
|
undo(new ChangeMMRest(m, 0));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
2014-03-09 20:24:04 +01:00
|
|
|
/* Update Notes After creating mmRest Because on load, mmRest->next() was not set
|
|
|
|
on first pass in updateNotes() and break occur */
|
|
|
|
updateNotes();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2012-09-06 12:35:34 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// cautionaryWidth
|
2012-09-07 15:20:48 +02:00
|
|
|
// Compute the width difference of actual measure m
|
|
|
|
// and the width of m if it were the last measure in a
|
|
|
|
// staff. The reason for any difference are courtesy
|
|
|
|
// time signatures and key signatures.
|
2012-09-06 12:35:34 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
qreal Score::cautionaryWidth(Measure* m)
|
|
|
|
{
|
|
|
|
qreal w = 0.0;
|
|
|
|
if (m == 0)
|
|
|
|
return w;
|
|
|
|
Measure* nm = m ? m->nextMeasure() : 0;
|
|
|
|
if (nm == 0 || (m->sectionBreak() && _layoutMode != LayoutFloat))
|
|
|
|
return w;
|
|
|
|
|
|
|
|
int tick = m->tick() + m->ticks();
|
|
|
|
|
|
|
|
// locate a time sig. in the next measure and, if found,
|
|
|
|
// check if it has caut. sig. turned off
|
|
|
|
|
2012-09-07 15:20:48 +02:00
|
|
|
Segment* ns = nm->findSegment(Segment::SegTimeSig, tick);
|
|
|
|
TimeSig* ts = 0;
|
|
|
|
bool showCourtesy = styleB(ST_genCourtesyTimesig) && ns;
|
|
|
|
if (showCourtesy) {
|
|
|
|
ts = static_cast<TimeSig*>(ns->element(0));
|
2012-09-06 12:35:34 +02:00
|
|
|
if (ts && !ts->showCourtesySig())
|
2012-09-07 15:20:48 +02:00
|
|
|
showCourtesy = false; // this key change has court. sig turned off
|
2012-09-06 12:35:34 +02:00
|
|
|
}
|
|
|
|
Segment* s = m->findSegment(Segment::SegTimeSigAnnounce, tick);
|
|
|
|
|
2012-09-07 15:20:48 +02:00
|
|
|
if (showCourtesy && !s)
|
2012-09-06 12:35:34 +02:00
|
|
|
w += ts->space().width();
|
2012-09-07 15:20:48 +02:00
|
|
|
else if (!showCourtesy && s && s->element(0))
|
|
|
|
w -= static_cast<TimeSig*>(s->element(0))->space().width();
|
2012-09-06 12:35:34 +02:00
|
|
|
|
|
|
|
// courtesy key signatures
|
2012-09-07 15:20:48 +02:00
|
|
|
qreal wwMin = 0.0;
|
|
|
|
qreal wwMax = 0.0;
|
|
|
|
int n = _staves.size();
|
2012-09-06 12:35:34 +02:00
|
|
|
for (int staffIdx = 0; staffIdx < n; ++staffIdx) {
|
2012-09-07 15:20:48 +02:00
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
ns = nm->findSegment(Segment::SegKeySig, tick);
|
|
|
|
KeySig* ks = 0;
|
|
|
|
|
|
|
|
showCourtesy = styleB(ST_genCourtesyKeysig) && ns;
|
|
|
|
if (showCourtesy) {
|
|
|
|
ks = static_cast<KeySig*>(ns->element(track));
|
|
|
|
if (ks && !ks->showCourtesy())
|
|
|
|
showCourtesy = false;
|
2012-09-06 12:35:34 +02:00
|
|
|
}
|
2012-09-07 15:20:48 +02:00
|
|
|
Segment* s = m->findSegment(Segment::SegKeySigAnnounce, tick);
|
2012-09-06 12:35:34 +02:00
|
|
|
|
2012-09-08 21:15:18 +02:00
|
|
|
if (showCourtesy && !s && ks)
|
2012-09-07 15:20:48 +02:00
|
|
|
wwMax = qMax(wwMax, ks->space().width());
|
|
|
|
else if (!showCourtesy && s && s->element(track))
|
|
|
|
wwMin = qMin(wwMin, -static_cast<KeySig*>(s->element(track))->space().width());
|
2012-09-06 12:35:34 +02:00
|
|
|
}
|
2012-09-07 15:20:48 +02:00
|
|
|
if (wwMax > 0.0)
|
|
|
|
w += wwMax;
|
|
|
|
else
|
|
|
|
w += wwMin;
|
2012-09-06 12:35:34 +02:00
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutSystem
|
|
|
|
// return true if line continues
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Score::layoutSystem(qreal& minWidth, qreal w, bool isFirstSystem, bool longName)
|
|
|
|
{
|
2012-08-02 18:33:43 +02:00
|
|
|
if (undoRedo()) // no change possible in this state
|
|
|
|
return layoutSystem1(minWidth, isFirstSystem, longName);
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
System* system = getNextSystem(isFirstSystem, false);
|
|
|
|
|
|
|
|
qreal xo = 0;
|
2012-09-13 18:01:34 +02:00
|
|
|
if (curMeasure->type() == Element::HBOX)
|
2012-05-26 14:26:10 +02:00
|
|
|
xo = point(static_cast<Box*>(curMeasure)->boxWidth());
|
|
|
|
|
|
|
|
system->setInstrumentNames(longName);
|
|
|
|
system->layout(xo);
|
|
|
|
|
2012-07-31 09:48:37 +02:00
|
|
|
qreal minMeasureWidth = point(styleS(ST_minMeasureWidth));
|
2012-05-26 14:26:10 +02:00
|
|
|
minWidth = system->leftMargin();
|
|
|
|
qreal systemWidth = w;
|
|
|
|
bool continueFlag = false;
|
|
|
|
bool isFirstMeasure = true;
|
|
|
|
Measure* firstMeasure = 0;
|
|
|
|
Measure* lastMeasure = 0;
|
|
|
|
|
2012-09-06 12:35:34 +02:00
|
|
|
qreal measureSpacing = styleD(ST_measureSpacing);
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
for (; curMeasure;) {
|
|
|
|
MeasureBase* nextMeasure;
|
2013-09-19 15:08:54 +02:00
|
|
|
if (curMeasure->type() == Element::MEASURE && !_showVBox)
|
|
|
|
nextMeasure = curMeasure->nextMeasureMM();
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
2013-09-19 15:08:54 +02:00
|
|
|
nextMeasure = curMeasure->nextMM();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-12-31 12:33:30 +01:00
|
|
|
Q_ASSERT(nextMeasure != curMeasure);
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
System* oldSystem = curMeasure->system();
|
|
|
|
curMeasure->setSystem(system);
|
2012-08-01 18:00:27 +02:00
|
|
|
qreal ww = 0.0;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2012-09-06 12:35:34 +02:00
|
|
|
qreal cautionaryW = 0.0;
|
|
|
|
|
2012-09-13 18:01:34 +02:00
|
|
|
if (curMeasure->type() == Element::HBOX) {
|
2012-05-26 14:26:10 +02:00
|
|
|
ww = point(static_cast<Box*>(curMeasure)->boxWidth());
|
|
|
|
if (!isFirstMeasure) {
|
|
|
|
// try to put another system on current row
|
|
|
|
// if not a line break
|
|
|
|
switch(_layoutMode) {
|
|
|
|
case LayoutFloat:
|
|
|
|
break;
|
|
|
|
case LayoutLine:
|
|
|
|
case LayoutPage:
|
2012-12-04 15:28:26 +01:00
|
|
|
case LayoutSystem:
|
2012-05-26 14:26:10 +02:00
|
|
|
continueFlag = !(curMeasure->lineBreak() || curMeasure->pageBreak());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (curMeasure->type() == Element::MEASURE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Measure* m = static_cast<Measure*>(curMeasure);
|
2012-08-01 22:15:58 +02:00
|
|
|
m->createEndBarLines(); // TODO: type not set right here
|
|
|
|
if (isFirstMeasure) {
|
2012-05-26 14:26:10 +02:00
|
|
|
firstMeasure = m;
|
2013-01-28 18:05:38 +01:00
|
|
|
addSystemHeader(m, isFirstSystem);
|
2012-08-01 22:15:58 +02:00
|
|
|
ww = m->minWidth2();
|
2012-07-31 09:48:37 +02:00
|
|
|
}
|
2012-08-01 22:15:58 +02:00
|
|
|
else
|
|
|
|
ww = m->minWidth1();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2012-08-02 18:33:43 +02:00
|
|
|
Segment* s = m->last();
|
2013-03-05 20:23:59 +01:00
|
|
|
if ((s->segmentType() == Segment::SegEndBarLine) && s->element(0)) {
|
2012-08-02 18:33:43 +02:00
|
|
|
BarLine* bl = static_cast<BarLine*>(s->element(0));
|
2013-03-05 20:23:59 +01:00
|
|
|
BarLineType ot = bl->barLineType();
|
2012-08-10 10:14:17 +02:00
|
|
|
BarLineType nt = m->endBarLineType();
|
2012-08-02 18:33:43 +02:00
|
|
|
|
|
|
|
if (m->repeatFlags() & RepeatEnd)
|
|
|
|
nt = END_REPEAT;
|
|
|
|
else {
|
2013-09-19 15:08:54 +02:00
|
|
|
Measure* nm = m->nextMeasureMM();
|
2012-08-02 18:33:43 +02:00
|
|
|
if (nm && (nm->repeatFlags() & RepeatStart))
|
|
|
|
nt = START_REPEAT;
|
|
|
|
}
|
|
|
|
if (ot != nt) {
|
2013-05-29 11:49:58 +02:00
|
|
|
qreal mag = bl->magS();
|
|
|
|
ww += BarLine::layoutWidth(this, nt, mag)
|
|
|
|
- BarLine::layoutWidth(this, ot, mag);
|
2012-06-11 12:15:21 +02:00
|
|
|
}
|
|
|
|
}
|
2012-09-06 12:35:34 +02:00
|
|
|
qreal stretch = m->userStretch() * measureSpacing;
|
2012-10-08 09:34:46 +02:00
|
|
|
cautionaryW = 0.0; // TODO: cautionaryWidth(m) * stretch;
|
2012-09-06 12:35:34 +02:00
|
|
|
ww *= stretch;
|
2012-08-02 18:33:43 +02:00
|
|
|
|
2012-07-31 09:48:37 +02:00
|
|
|
if (ww < minMeasureWidth)
|
|
|
|
ww = minMeasureWidth;
|
2012-05-26 14:26:10 +02:00
|
|
|
isFirstMeasure = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// collect at least one measure
|
2012-09-06 12:35:34 +02:00
|
|
|
bool empty = system->measures().isEmpty();
|
|
|
|
if (!empty && (minWidth + ww + cautionaryW > systemWidth)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
curMeasure->setSystem(oldSystem);
|
|
|
|
break;
|
|
|
|
}
|
2012-09-13 18:01:34 +02:00
|
|
|
if (curMeasure->type() == Element::MEASURE)
|
2012-05-26 14:26:10 +02:00
|
|
|
lastMeasure = static_cast<Measure*>(curMeasure);
|
2012-07-31 09:48:37 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
system->measures().append(curMeasure);
|
2012-09-06 12:35:34 +02:00
|
|
|
|
2012-09-29 16:46:45 +02:00
|
|
|
Element::ElementType nt;
|
|
|
|
if (_showVBox)
|
2013-09-19 15:08:54 +02:00
|
|
|
nt = curMeasure->nextMM() ? curMeasure->nextMM()->type() : Element::INVALID;
|
2012-09-29 16:46:45 +02:00
|
|
|
else
|
2013-09-19 15:08:54 +02:00
|
|
|
nt = curMeasure->nextMeasureMM() ? curMeasure->nextMeasureMM()->type() : Element::INVALID;
|
2012-05-26 14:26:10 +02:00
|
|
|
int n = styleI(ST_FixMeasureNumbers);
|
|
|
|
bool pbreak;
|
|
|
|
switch (_layoutMode) {
|
|
|
|
case LayoutPage:
|
2012-12-04 15:28:26 +01:00
|
|
|
case LayoutSystem:
|
2012-05-26 14:26:10 +02:00
|
|
|
pbreak = curMeasure->pageBreak() || curMeasure->lineBreak();
|
|
|
|
break;
|
|
|
|
case LayoutFloat:
|
|
|
|
case LayoutLine:
|
|
|
|
pbreak = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((n && system->measures().size() >= n)
|
2012-09-13 18:01:34 +02:00
|
|
|
|| continueFlag
|
|
|
|
|| pbreak
|
|
|
|
|| (nt == Element::VBOX || nt == Element::TBOX || nt == Element::FBOX)
|
|
|
|
) {
|
2012-12-04 15:28:26 +01:00
|
|
|
if (_layoutMode != LayoutSystem)
|
|
|
|
system->setPageBreak(curMeasure->pageBreak());
|
2012-05-26 14:26:10 +02:00
|
|
|
curMeasure = nextMeasure;
|
|
|
|
break;
|
|
|
|
}
|
2012-08-02 18:33:43 +02:00
|
|
|
curMeasure = nextMeasure;
|
2012-09-06 12:35:34 +02:00
|
|
|
if (minWidth + minMeasureWidth > systemWidth)
|
|
|
|
break; // next measure will not fit
|
|
|
|
|
|
|
|
minWidth += ww;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2012-09-05 12:14:58 +02:00
|
|
|
//
|
|
|
|
// remember line breaks in list of measures
|
|
|
|
//
|
|
|
|
int n = system->measures().size() - 1;
|
|
|
|
if (n >= 0) {
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
undoChangeProperty(system->measure(i), P_BREAK_HINT, false);
|
|
|
|
undoChangeProperty(system->measures().last(), P_BREAK_HINT, true);
|
|
|
|
}
|
|
|
|
|
2012-08-01 22:15:58 +02:00
|
|
|
if (!undoRedo() && firstMeasure && lastMeasure && firstMeasure != lastMeasure)
|
2012-08-01 18:00:27 +02:00
|
|
|
removeGeneratedElements(firstMeasure, lastMeasure);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-03-29 15:01:21 +01:00
|
|
|
hideEmptyStaves(system, isFirstSystem);
|
|
|
|
|
|
|
|
return continueFlag && curMeasure;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Score::hideEmptyStaves(System* system, bool isFirstSystem)
|
|
|
|
{
|
|
|
|
//
|
2012-05-26 14:26:10 +02:00
|
|
|
// hide empty staves
|
|
|
|
//
|
|
|
|
int staves = _staves.size();
|
|
|
|
int staffIdx = 0;
|
|
|
|
foreach (Staff* staff, _staves) {
|
|
|
|
SysStaff* s = system->staff(staffIdx);
|
|
|
|
bool oldShow = s->show();
|
|
|
|
if (styleB(ST_hideEmptyStaves)
|
|
|
|
&& (staves > 1)
|
|
|
|
&& !(isFirstSystem && styleB(ST_dontHideStavesInFirstSystem))
|
|
|
|
) {
|
|
|
|
bool hideStaff = true;
|
|
|
|
foreach(MeasureBase* m, system->measures()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (m->type() != Element::MEASURE)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
Measure* measure = static_cast<Measure*>(m);
|
|
|
|
if (!measure->isMeasureRest(staffIdx)) {
|
|
|
|
hideStaff = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// check if notes moved into this staff
|
|
|
|
Part* part = staff->part();
|
|
|
|
int n = part->nstaves();
|
|
|
|
if (hideStaff && (n > 1)) {
|
|
|
|
int idx = part->staves()->front()->idx();
|
|
|
|
for (int i = 0; i < part->nstaves(); ++i) {
|
|
|
|
int st = idx + i;
|
|
|
|
|
|
|
|
foreach(MeasureBase* mb, system->measures()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (mb->type() != Element::MEASURE)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
Measure* m = static_cast<Measure*>(mb);
|
2012-08-03 15:54:02 +02:00
|
|
|
for (Segment* s = m->first(Segment::SegChordRest); s; s = s->next(Segment::SegChordRest)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
for (int voice = 0; voice < VOICES; ++voice) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(s->element(st * VOICES + voice));
|
2012-09-13 18:01:34 +02:00
|
|
|
if (cr == 0 || cr->type() == Element::REST)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
int staffMove = cr->staffMove();
|
|
|
|
if (staffIdx == st + staffMove) {
|
|
|
|
hideStaff = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!hideStaff)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!hideStaff)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s->setShow(hideStaff ? false : staff->show());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
s->setShow(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldShow != s->show()) {
|
|
|
|
foreach (MeasureBase* mb, system->measures()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (mb->type() != Element::MEASURE)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
static_cast<Measure*>(mb)->createEndBarLines();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++staffIdx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-02 18:33:43 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutSystem1
|
|
|
|
// used in undoRedo state
|
|
|
|
// return true if line continues
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Score::layoutSystem1(qreal& minWidth, bool isFirstSystem, bool longName)
|
|
|
|
{
|
|
|
|
System* system = getNextSystem(isFirstSystem, false);
|
|
|
|
|
|
|
|
qreal xo = 0;
|
2012-09-13 18:01:34 +02:00
|
|
|
if (curMeasure->type() == Element::HBOX)
|
2012-08-02 18:33:43 +02:00
|
|
|
xo = point(static_cast<Box*>(curMeasure)->boxWidth());
|
|
|
|
|
|
|
|
system->setInstrumentNames(longName);
|
|
|
|
system->layout(xo);
|
|
|
|
|
|
|
|
qreal minMeasureWidth = point(styleS(ST_minMeasureWidth));
|
|
|
|
minWidth = system->leftMargin();
|
|
|
|
bool continueFlag = false;
|
|
|
|
bool isFirstMeasure = true;
|
|
|
|
|
|
|
|
for (; curMeasure;) {
|
|
|
|
MeasureBase* nextMeasure;
|
2013-09-19 15:08:54 +02:00
|
|
|
if (curMeasure->type() == Element::MEASURE && !_showVBox)
|
2013-09-28 14:50:01 +02:00
|
|
|
nextMeasure = curMeasure->nextMeasureMM();
|
2012-08-02 18:33:43 +02:00
|
|
|
else
|
2013-09-28 14:50:01 +02:00
|
|
|
nextMeasure = curMeasure->nextMM();
|
2012-08-02 18:33:43 +02:00
|
|
|
|
|
|
|
// System* oldSystem = curMeasure->system();
|
|
|
|
curMeasure->setSystem(system);
|
|
|
|
qreal ww = 0.0;
|
|
|
|
|
2012-09-13 18:01:34 +02:00
|
|
|
if (curMeasure->type() == Element::HBOX) {
|
2012-08-02 18:33:43 +02:00
|
|
|
ww = point(static_cast<Box*>(curMeasure)->boxWidth());
|
|
|
|
if (!isFirstMeasure) {
|
|
|
|
// try to put another system on current row
|
|
|
|
// if not a line break
|
|
|
|
switch(_layoutMode) {
|
|
|
|
case LayoutFloat:
|
|
|
|
break;
|
|
|
|
case LayoutLine:
|
|
|
|
case LayoutPage:
|
2012-12-04 15:28:26 +01:00
|
|
|
case LayoutSystem:
|
2012-08-02 18:33:43 +02:00
|
|
|
continueFlag = !(curMeasure->lineBreak() || curMeasure->pageBreak());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (curMeasure->type() == Element::MEASURE) {
|
2012-08-02 18:33:43 +02:00
|
|
|
Measure* m = static_cast<Measure*>(curMeasure);
|
|
|
|
m->createEndBarLines(); // TODO: type not set right here
|
|
|
|
if (isFirstMeasure) {
|
2013-01-28 18:05:38 +01:00
|
|
|
addSystemHeader(m, isFirstSystem);
|
2012-08-02 18:33:43 +02:00
|
|
|
ww = m->minWidth2();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ww = m->minWidth1();
|
|
|
|
|
|
|
|
ww *= m->userStretch() * styleD(ST_measureSpacing);
|
|
|
|
if (ww < minMeasureWidth)
|
|
|
|
ww = minMeasureWidth;
|
|
|
|
isFirstMeasure = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
minWidth += ww;
|
|
|
|
|
|
|
|
system->measures().append(curMeasure);
|
2012-09-13 18:01:34 +02:00
|
|
|
Element::ElementType nt = curMeasure->next() ? curMeasure->next()->type() : Element::INVALID;
|
2012-08-02 18:33:43 +02:00
|
|
|
int n = styleI(ST_FixMeasureNumbers);
|
|
|
|
bool pbreak;
|
|
|
|
switch (_layoutMode) {
|
|
|
|
case LayoutPage:
|
2012-12-04 15:28:26 +01:00
|
|
|
case LayoutSystem:
|
2012-08-02 18:33:43 +02:00
|
|
|
pbreak = curMeasure->pageBreak() || curMeasure->lineBreak();
|
|
|
|
break;
|
|
|
|
case LayoutFloat:
|
|
|
|
case LayoutLine:
|
|
|
|
pbreak = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((n && system->measures().size() >= n)
|
2012-09-13 18:01:34 +02:00
|
|
|
|| continueFlag || pbreak || (nt == Element::VBOX || nt == Element::TBOX || nt == Element::FBOX)) {
|
2012-12-04 15:28:26 +01:00
|
|
|
if (_layoutMode != LayoutSystem)
|
|
|
|
system->setPageBreak(curMeasure->pageBreak());
|
2012-08-02 18:33:43 +02:00
|
|
|
curMeasure = nextMeasure;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// do not change line break
|
|
|
|
if (curMeasure->breakHint()) {
|
|
|
|
curMeasure = nextMeasure;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
curMeasure = nextMeasure;
|
|
|
|
}
|
|
|
|
|
2013-03-29 15:01:21 +01:00
|
|
|
hideEmptyStaves(system,isFirstSystem);
|
2012-08-02 18:33:43 +02:00
|
|
|
|
|
|
|
return continueFlag && curMeasure;
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
2012-08-01 18:00:27 +02:00
|
|
|
// removeGeneratedElements (System Header + TimeSig Announce)
|
2012-05-26 14:26:10 +02:00
|
|
|
// helper function
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-08-01 18:00:27 +02:00
|
|
|
void Score::removeGeneratedElements(Measure* sm, Measure* em)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-09-20 12:59:31 +02:00
|
|
|
for (Measure* m = sm; m; m = m->nextMeasureMM()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
// remove generated elements from all measures in [sm;em]
|
|
|
|
// assume: generated elements are only living in voice 0
|
|
|
|
// - do not remove end bar lines
|
|
|
|
// - set size of clefs to small
|
|
|
|
//
|
|
|
|
for (Segment* seg = m->first(); seg; seg = seg->next()) {
|
2013-03-05 20:23:59 +01:00
|
|
|
Segment::SegmentType st = seg->segmentType();
|
2012-08-03 15:54:02 +02:00
|
|
|
if (st == Segment::SegEndBarLine)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
2012-08-03 15:54:02 +02:00
|
|
|
if (st == Segment::SegStartRepeatBarLine && m != sm) {
|
2013-10-25 12:17:42 +02:00
|
|
|
if (!undoRedo())
|
|
|
|
undoRemoveElement(seg);
|
|
|
|
else
|
|
|
|
qDebug("remove repeat segment in undo/redo");
|
|
|
|
continue;
|
2012-08-02 18:33:43 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
|
|
|
|
Element* el = seg->element(staffIdx * VOICES);
|
|
|
|
if (el == 0)
|
|
|
|
continue;
|
|
|
|
|
2012-08-03 15:54:02 +02:00
|
|
|
if (el->generated() && ((st == Segment::SegTimeSigAnnounce && m != em)
|
2012-09-13 18:01:34 +02:00
|
|
|
|| (el->type() == Element::CLEF && seg->tick() != sm->tick())
|
|
|
|
|| (el->type() == Element::KEYSIG && seg->tick() != sm->tick())))
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2012-08-01 22:15:58 +02:00
|
|
|
undoRemoveElement(el);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (el->type() == Element::CLEF) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Clef* clef = static_cast<Clef*>(el);
|
|
|
|
System* s = m->system();
|
|
|
|
bool small = seg != m->first() || s->firstMeasure() != m;
|
|
|
|
if (clef->small() != small) {
|
|
|
|
clef->setSmall(small);
|
2012-08-01 18:00:27 +02:00
|
|
|
m->setDirty();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-09-16 18:32:59 +02:00
|
|
|
//
|
|
|
|
// if measure is not the first in the system, the clef at
|
|
|
|
// measure start has to be moved to the end of the previous measure
|
|
|
|
//
|
2013-09-16 13:17:57 +02:00
|
|
|
if (s->firstMeasure() != m && seg->tick() == m->tick()) {
|
|
|
|
undoRemoveElement(el);
|
|
|
|
Measure* pm = m->prevMeasure();
|
|
|
|
Segment* s = pm->undoGetSegment(Segment::SegClef, m->tick());
|
|
|
|
Clef* nc = clef->clone();
|
|
|
|
nc->setParent(s);
|
|
|
|
undoAddElement(nc);
|
2013-09-16 18:32:59 +02:00
|
|
|
m->setDirty();
|
|
|
|
pm->setDirty();
|
2013-09-16 13:17:57 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m == em)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// addPage
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Page* Score::addPage()
|
|
|
|
{
|
|
|
|
Page* page = new Page(this);
|
|
|
|
page->setNo(_pages.size());
|
|
|
|
_pages.push_back(page);
|
|
|
|
return page;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// connectTies
|
|
|
|
/// Rebuild tie connections.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::connectTies()
|
|
|
|
{
|
|
|
|
int tracks = nstaves() * VOICES;
|
|
|
|
Measure* m = firstMeasure();
|
|
|
|
if (!m)
|
|
|
|
return;
|
2013-06-12 14:23:57 +02:00
|
|
|
Segment::SegmentTypes st = Segment::SegChordRest;
|
2012-12-06 12:46:05 +01:00
|
|
|
for (Segment* s = m->first(st); s; s = s->next1(st)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
for (int i = 0; i < tracks; ++i) {
|
2012-12-06 12:46:05 +01:00
|
|
|
Chord* c = static_cast<Chord*>(s->element(i));
|
|
|
|
if (c == 0 || c->type() != Element::CHORD)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
2013-06-28 10:55:25 +02:00
|
|
|
for (Note* n : c->notes()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Tie* tie = n->tieFor();
|
2013-08-21 11:59:41 +02:00
|
|
|
if (!tie || tie->endNote())
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
2013-08-21 11:59:41 +02:00
|
|
|
Note* nnote;
|
|
|
|
if (_mscVersion <= 114)
|
|
|
|
nnote = searchTieNote114(n);
|
|
|
|
else
|
|
|
|
nnote = searchTieNote(n);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (nnote == 0) {
|
2013-06-10 11:03:34 +02:00
|
|
|
qDebug("next note at %d track %d for tie not found",
|
|
|
|
s->tick(), i);
|
2012-05-26 14:26:10 +02:00
|
|
|
// n->setTieFor(0); show short bow
|
|
|
|
// delete tie;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tie->setEndNote(nnote);
|
|
|
|
nnote->setTieBack(tie);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// add
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::add(Element* el)
|
|
|
|
{
|
|
|
|
switch(el->type()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
case Element::MEASURE:
|
|
|
|
case Element::HBOX:
|
|
|
|
case Element::VBOX:
|
|
|
|
case Element::TBOX:
|
|
|
|
case Element::FBOX:
|
2013-06-19 16:25:29 +02:00
|
|
|
measures()->add(static_cast<MeasureBase*>(el));
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2012-09-13 18:01:34 +02:00
|
|
|
case Element::BEAM:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
Beam* b = static_cast<Beam*>(el);
|
2012-12-06 12:46:05 +01:00
|
|
|
int n = b->elements().size();
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
b->elements().at(i)->setBeam(b);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
break;
|
2012-09-13 18:01:34 +02:00
|
|
|
case Element::TEXTLINE:
|
2013-07-04 13:40:25 +02:00
|
|
|
if (static_cast<Spanner*>(el)->anchor() == Spanner::ANCHOR_NOTE)
|
|
|
|
break;
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
case Element::SLUR:
|
2013-06-10 11:03:34 +02:00
|
|
|
case Element::VOLTA:
|
|
|
|
case Element::TRILL:
|
|
|
|
case Element::PEDAL:
|
|
|
|
case Element::HAIRPIN:
|
|
|
|
case Element::OTTAVA:
|
2013-06-20 13:57:15 +02:00
|
|
|
addSpanner(static_cast<Spanner*>(el));
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2012-09-12 16:19:03 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
default:
|
2014-03-14 12:08:12 +01:00
|
|
|
qFatal("Score::add() invalid element <%s>", el->name());
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// remove
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::remove(Element* el)
|
|
|
|
{
|
|
|
|
switch(el->type()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
case Element::MEASURE:
|
|
|
|
case Element::HBOX:
|
|
|
|
case Element::VBOX:
|
|
|
|
case Element::TBOX:
|
|
|
|
case Element::FBOX:
|
2012-05-26 14:26:10 +02:00
|
|
|
measures()->remove(static_cast<MeasureBase*>(el));
|
|
|
|
break;
|
2012-09-13 18:01:34 +02:00
|
|
|
case Element::BEAM:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
Beam* b = static_cast<Beam*>(el);
|
|
|
|
foreach(ChordRest* cr, b->elements())
|
|
|
|
cr->setBeam(0);
|
|
|
|
}
|
|
|
|
break;
|
2012-09-13 18:01:34 +02:00
|
|
|
case Element::SLUR:
|
|
|
|
case Element::TEXTLINE:
|
2013-06-10 11:03:34 +02:00
|
|
|
case Element::VOLTA:
|
|
|
|
case Element::TRILL:
|
|
|
|
case Element::PEDAL:
|
|
|
|
case Element::HAIRPIN:
|
|
|
|
case Element::OTTAVA:
|
2013-06-20 13:57:15 +02:00
|
|
|
removeSpanner(static_cast<Spanner*>(el));
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
default:
|
2013-06-10 11:03:34 +02:00
|
|
|
qDebug("Score::remove(): invalid element %s", el->name());
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutFingering
|
|
|
|
// - place numbers above a note execpt for the last
|
|
|
|
// staff in a multi stave part (piano)
|
|
|
|
// - does not handle chords
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutFingering(Fingering* f)
|
|
|
|
{
|
|
|
|
if (f == 0)
|
|
|
|
return;
|
|
|
|
Note* note = f->note();
|
|
|
|
Chord* chord = note->chord();
|
|
|
|
Staff* staff = chord->staff();
|
|
|
|
Part* part = staff->part();
|
|
|
|
int n = part->nstaves();
|
|
|
|
bool below = (n > 1) && (staff->rstaff() == n-1);
|
|
|
|
|
|
|
|
f->layout();
|
|
|
|
qreal x = 0.0;
|
|
|
|
qreal y = 0.0;
|
|
|
|
qreal headWidth = note->headWidth();
|
|
|
|
qreal headHeight = note->headHeight();
|
|
|
|
qreal fh = headHeight; // TODO: fingering number height
|
|
|
|
|
|
|
|
if (chord->notes().size() == 1) {
|
|
|
|
x = headWidth * .5;
|
|
|
|
if (below) {
|
|
|
|
// place fingering below note
|
|
|
|
y = fh + spatium() * .4;
|
|
|
|
if (chord->stem() && !chord->up()) {
|
|
|
|
// on stem side
|
|
|
|
y += chord->stem()->height();
|
|
|
|
x -= spatium() * .4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// place fingering above note
|
|
|
|
y = -headHeight - spatium() * .4;
|
|
|
|
if (chord->stem() && chord->up()) {
|
|
|
|
// on stem side
|
|
|
|
y -= chord->stem()->height();
|
|
|
|
x += spatium() * .4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f->setUserOff(QPointF(x, y));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutSystemRow
|
2012-10-08 08:28:19 +02:00
|
|
|
// return height in h
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QList<System*> Score::layoutSystemRow(qreal rowWidth, bool isFirstSystem, bool useLongName)
|
|
|
|
{
|
|
|
|
bool raggedRight = MScore::layoutDebug;
|
|
|
|
|
|
|
|
QList<System*> sl;
|
|
|
|
|
|
|
|
qreal ww = rowWidth;
|
|
|
|
qreal minWidth;
|
|
|
|
for (bool a = true; a;) {
|
|
|
|
a = layoutSystem(minWidth, ww, isFirstSystem, useLongName);
|
|
|
|
sl.append(_systems[curSystem]);
|
|
|
|
++curSystem;
|
|
|
|
ww -= minWidth;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// dont stretch last system row, if minWidth is <= lastSystemFillLimit
|
|
|
|
//
|
|
|
|
if (curMeasure == 0 && ((minWidth / rowWidth) <= styleD(ST_lastSystemFillLimit)))
|
|
|
|
raggedRight = true;
|
|
|
|
|
|
|
|
//-------------------------------------------------------
|
|
|
|
// Round II
|
|
|
|
// stretch measures
|
|
|
|
// "nm" measures fit on this line of score
|
|
|
|
//-------------------------------------------------------
|
|
|
|
|
|
|
|
bool needRelayout = false;
|
|
|
|
|
|
|
|
foreach (System* system, sl) {
|
|
|
|
//
|
|
|
|
// add cautionary time/key signatures if needed
|
|
|
|
//
|
|
|
|
|
|
|
|
if (system->measures().isEmpty()) {
|
2014-03-04 13:06:23 +01:00
|
|
|
qFatal("System %p is empty\n", system);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
Measure* m = system->lastMeasure();
|
|
|
|
bool hasCourtesyKeysig = false;
|
|
|
|
Measure* nm = m ? m->nextMeasure() : 0;
|
|
|
|
Segment* s;
|
|
|
|
|
|
|
|
if (m && nm && !(m->sectionBreak() && _layoutMode != LayoutFloat)) {
|
|
|
|
int tick = m->tick() + m->ticks();
|
|
|
|
|
|
|
|
// locate a time sig. in the next measure and, if found,
|
|
|
|
// check if it has cout. sig. turned off
|
|
|
|
TimeSig* ts;
|
2012-08-03 15:54:02 +02:00
|
|
|
Segment* tss = nm->findSegment(Segment::SegTimeSig, tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
bool showCourtesySig = tss && styleB(ST_genCourtesyTimesig);
|
|
|
|
if (showCourtesySig) {
|
|
|
|
ts = static_cast<TimeSig*>(tss->element(0));
|
|
|
|
if (ts && !ts->showCourtesySig())
|
|
|
|
showCourtesySig = false; // this key change has court. sig turned off
|
|
|
|
}
|
|
|
|
if (showCourtesySig) {
|
|
|
|
// if due, create a new courtesy time signature for each staff
|
2012-08-03 15:54:02 +02:00
|
|
|
s = m->undoGetSegment(Segment::SegTimeSigAnnounce, tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
int nstaves = Score::nstaves();
|
|
|
|
for (int track = 0; track < nstaves * VOICES; track += VOICES) {
|
|
|
|
TimeSig* nts = static_cast<TimeSig*>(tss->element(track));
|
|
|
|
if (!nts)
|
|
|
|
continue;
|
|
|
|
ts = static_cast<TimeSig*>(s->element(track));
|
|
|
|
if (ts == 0) {
|
|
|
|
ts = new TimeSig(this);
|
|
|
|
ts->setTrack(track);
|
|
|
|
ts->setGenerated(true);
|
|
|
|
ts->setParent(s);
|
|
|
|
undoAddElement(ts);
|
|
|
|
}
|
|
|
|
ts->setFrom(nts);
|
2012-07-31 09:48:37 +02:00
|
|
|
m->setDirty();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
2012-07-27 18:01:15 +02:00
|
|
|
else {
|
|
|
|
// remove any existing time signatures
|
2012-08-03 15:54:02 +02:00
|
|
|
Segment* tss = m->findSegment(Segment::SegTimeSigAnnounce, tick);
|
2012-07-27 18:01:15 +02:00
|
|
|
if (tss) {
|
|
|
|
undoRemoveElement(tss);
|
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
// courtesy key signatures
|
|
|
|
int n = _staves.size();
|
|
|
|
for (int staffIdx = 0; staffIdx < n; ++staffIdx) {
|
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
Staff* staff = _staves[staffIdx];
|
|
|
|
showCourtesySig = false;
|
|
|
|
|
|
|
|
KeySigEvent key1 = staff->key(tick - 1);
|
|
|
|
KeySigEvent key2 = staff->key(tick);
|
|
|
|
if (styleB(ST_genCourtesyKeysig) && (key1 != key2)) {
|
|
|
|
// locate a key sig. in next measure and, if found,
|
|
|
|
// check if it has court. sig turned off
|
2012-08-03 15:54:02 +02:00
|
|
|
s = nm->findSegment(Segment::SegKeySig, tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
showCourtesySig = true; // assume this key change has court. sig turned on
|
|
|
|
if (s) {
|
|
|
|
KeySig* ks = static_cast<KeySig*>(s->element(track));
|
2012-07-27 18:01:15 +02:00
|
|
|
if (ks && !ks->showCourtesy())
|
2012-05-26 14:26:10 +02:00
|
|
|
showCourtesySig = false; // this key change has court. sig turned off
|
|
|
|
}
|
|
|
|
|
|
|
|
if (showCourtesySig) {
|
|
|
|
hasCourtesyKeysig = true;
|
2012-08-03 15:54:02 +02:00
|
|
|
s = m->undoGetSegment(Segment::SegKeySigAnnounce, tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
KeySig* ks = static_cast<KeySig*>(s->element(track));
|
|
|
|
KeySigEvent ksv(key2);
|
|
|
|
ksv.setNaturalType(key1.accidentalType());
|
|
|
|
|
|
|
|
if (!ks) {
|
|
|
|
ks = new KeySig(this);
|
|
|
|
ks->setKeySigEvent(ksv);
|
|
|
|
ks->setTrack(track);
|
|
|
|
ks->setGenerated(true);
|
|
|
|
ks->setParent(s);
|
|
|
|
undoAddElement(ks);
|
|
|
|
}
|
|
|
|
else if (ks->keySigEvent() != ksv) {
|
|
|
|
undo(new ChangeKeySig(ks, ksv,
|
2012-07-27 18:01:15 +02:00
|
|
|
ks->showCourtesy(), ks->showNaturals()));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
// change bar line to qreal bar line
|
2012-11-22 11:24:37 +01:00
|
|
|
// m->setEndBarLineType(DOUBLE_BAR, true); // this caused issue #12918
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!showCourtesySig) {
|
|
|
|
// remove any existent courtesy key signature
|
2012-08-03 15:54:02 +02:00
|
|
|
Segment* s = m->findSegment(Segment::SegKeySigAnnounce, tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (s && s->element(track))
|
|
|
|
undoRemoveElement(s->element(track));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-24 20:11:51 +01:00
|
|
|
// courtesy clefs: show/hide of courtesy clefs moved to Clef::layout()
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// compute repeat bar lines
|
|
|
|
//
|
2013-10-25 12:17:42 +02:00
|
|
|
bool firstMeasure = true;
|
|
|
|
const QList<MeasureBase*>& ml = system->measures();
|
|
|
|
MeasureBase* lmb = ml.back();
|
2012-08-01 22:15:58 +02:00
|
|
|
|
2013-10-25 12:17:42 +02:00
|
|
|
for (MeasureBase* mb : ml) {
|
|
|
|
if (mb->type() != Element::MEASURE)
|
|
|
|
continue;
|
|
|
|
Measure* m = static_cast<Measure*>(mb);
|
|
|
|
// first measure repeat?
|
|
|
|
bool fmr = firstMeasure && (m->repeatFlags() & RepeatStart);
|
|
|
|
|
|
|
|
if (mb == lmb) { // last measure in system?
|
|
|
|
//
|
|
|
|
// if last bar has a courtesy key signature,
|
|
|
|
// create a double bar line as end bar line
|
|
|
|
//
|
|
|
|
BarLineType bl = hasCourtesyKeysig ? DOUBLE_BAR : NORMAL_BAR;
|
|
|
|
if (m->repeatFlags() & RepeatEnd)
|
2013-12-21 01:14:37 +01:00
|
|
|
m->setEndBarLineType(END_REPEAT, m->endBarLineGenerated());
|
2013-10-25 12:17:42 +02:00
|
|
|
else if (m->endBarLineGenerated())
|
|
|
|
m->setEndBarLineType(bl, true);
|
|
|
|
if (m->setStartRepeatBarLine(fmr))
|
2012-08-01 22:15:58 +02:00
|
|
|
m->setDirty();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-10-25 12:17:42 +02:00
|
|
|
else {
|
|
|
|
MeasureBase* mb = m->next();
|
|
|
|
while (mb && mb->type() != Element::MEASURE && (mb != lmb))
|
|
|
|
mb = mb->next();
|
|
|
|
|
|
|
|
Measure* nm = 0;
|
|
|
|
if (mb && mb->type() == Element::MEASURE)
|
|
|
|
nm = static_cast<Measure*>(mb);
|
|
|
|
|
|
|
|
needRelayout |= m->setStartRepeatBarLine(fmr);
|
|
|
|
if (m->repeatFlags() & RepeatEnd) {
|
|
|
|
if (nm && (nm->repeatFlags() & RepeatStart))
|
2013-12-21 01:14:37 +01:00
|
|
|
m->setEndBarLineType(END_START_REPEAT, m->endBarLineGenerated());
|
2013-10-25 12:17:42 +02:00
|
|
|
else
|
2013-12-21 01:14:37 +01:00
|
|
|
m->setEndBarLineType(END_REPEAT, m->endBarLineGenerated());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-10-25 12:17:42 +02:00
|
|
|
else if (nm && (nm->repeatFlags() & RepeatStart))
|
2013-12-21 01:14:37 +01:00
|
|
|
m->setEndBarLineType(START_REPEAT, m->endBarLineGenerated());
|
2013-10-25 12:17:42 +02:00
|
|
|
else if (m->endBarLineGenerated())
|
2013-12-21 01:14:37 +01:00
|
|
|
m->setEndBarLineType(NORMAL_BAR, m->endBarLineGenerated());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-10-25 12:17:42 +02:00
|
|
|
if (m->createEndBarLines())
|
|
|
|
m->setDirty();
|
|
|
|
firstMeasure = false;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-10-25 12:17:42 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
minWidth = 0.0;
|
|
|
|
qreal totalWeight = 0.0;
|
|
|
|
|
|
|
|
foreach(System* system, sl) {
|
|
|
|
foreach (MeasureBase* mb, system->measures()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (mb->type() == Element::HBOX)
|
2012-05-26 14:26:10 +02:00
|
|
|
minWidth += point(((Box*)mb)->boxWidth());
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (mb->type() == Element::MEASURE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Measure* m = (Measure*)mb;
|
2012-07-31 09:48:37 +02:00
|
|
|
if (needRelayout)
|
|
|
|
m->setDirty();
|
2012-08-01 22:15:58 +02:00
|
|
|
minWidth += m->minWidth2();
|
2012-05-26 14:26:10 +02:00
|
|
|
totalWeight += m->ticks() * m->userStretch();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
minWidth += system->leftMargin();
|
|
|
|
}
|
|
|
|
|
|
|
|
// stretch incomplete row
|
2012-06-10 10:35:17 +02:00
|
|
|
qreal rest;
|
|
|
|
if (MScore::layoutDebug)
|
|
|
|
rest = 0;
|
|
|
|
else {
|
|
|
|
rest = rowWidth - minWidth;
|
|
|
|
if (raggedRight) {
|
|
|
|
if (minWidth > rest)
|
|
|
|
rest = rest * .5;
|
|
|
|
else
|
|
|
|
rest = minWidth;
|
|
|
|
}
|
|
|
|
rest /= totalWeight;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
qreal xx = 0.0;
|
|
|
|
qreal y = 0.0;
|
|
|
|
|
|
|
|
foreach(System* system, sl) {
|
|
|
|
QPointF pos;
|
|
|
|
|
|
|
|
bool firstMeasure = true;
|
|
|
|
foreach(MeasureBase* mb, system->measures()) {
|
|
|
|
qreal ww = 0.0;
|
2012-09-13 18:01:34 +02:00
|
|
|
if (mb->type() == Element::MEASURE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (firstMeasure) {
|
|
|
|
pos.rx() += system->leftMargin();
|
|
|
|
firstMeasure = false;
|
|
|
|
}
|
|
|
|
mb->setPos(pos);
|
|
|
|
Measure* m = static_cast<Measure*>(mb);
|
|
|
|
if (styleB(ST_FixMeasureWidth)) {
|
|
|
|
ww = rowWidth / system->measures().size();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
qreal weight = m->ticks() * m->userStretch();
|
2012-08-01 22:15:58 +02:00
|
|
|
ww = m->minWidth2() + rest * weight;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
m->layout(ww);
|
|
|
|
}
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (mb->type() == Element::HBOX) {
|
2012-05-26 14:26:10 +02:00
|
|
|
mb->setPos(pos);
|
|
|
|
ww = point(static_cast<Box*>(mb)->boxWidth());
|
|
|
|
mb->layout();
|
|
|
|
}
|
|
|
|
pos.rx() += ww;
|
|
|
|
}
|
|
|
|
system->setPos(xx, y);
|
|
|
|
qreal w = pos.x();
|
|
|
|
system->setWidth(w);
|
|
|
|
system->layout2();
|
|
|
|
foreach(MeasureBase* mb, system->measures()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (mb->type() == Element::HBOX) {
|
2012-05-26 14:26:10 +02:00
|
|
|
mb->setHeight(system->height());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xx += w;
|
|
|
|
}
|
|
|
|
return sl;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutSystems
|
|
|
|
// create list of systems
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutSystems()
|
|
|
|
{
|
2013-09-20 12:59:31 +02:00
|
|
|
curMeasure = _showVBox ? firstMM() : firstMeasureMM();
|
2012-05-26 14:26:10 +02:00
|
|
|
curSystem = 0;
|
|
|
|
bool firstSystem = true;
|
|
|
|
bool startWithLongNames = true;
|
|
|
|
|
|
|
|
qreal w = pageFormat()->printableWidth() * MScore::DPI;
|
|
|
|
|
|
|
|
while (curMeasure) {
|
2012-09-13 18:01:34 +02:00
|
|
|
Element::ElementType t = curMeasure->type();
|
|
|
|
if (t == Element::VBOX || t == Element::TBOX || t == Element::FBOX) {
|
2012-05-26 14:26:10 +02:00
|
|
|
System* system = getNextSystem(false, true);
|
|
|
|
foreach(SysStaff* ss, *system->staves())
|
|
|
|
delete ss;
|
|
|
|
system->staves()->clear();
|
2013-06-28 17:46:24 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
system->setWidth(w);
|
|
|
|
VBox* vbox = static_cast<VBox*>(curMeasure);
|
|
|
|
vbox->setParent(system);
|
|
|
|
vbox->layout();
|
|
|
|
system->setHeight(vbox->height());
|
|
|
|
system->rxpos() = 0.0;
|
|
|
|
system->setPageBreak(vbox->pageBreak());
|
|
|
|
system->measures().push_back(vbox);
|
2013-09-20 12:59:31 +02:00
|
|
|
curMeasure = curMeasure->nextMM();
|
2012-05-26 14:26:10 +02:00
|
|
|
++curSystem;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
QList<System*> sl = layoutSystemRow(w, firstSystem, startWithLongNames);
|
|
|
|
for (int i = 0; i < sl.size(); ++i)
|
|
|
|
sl[i]->setSameLine(i != 0);
|
|
|
|
firstSystem = false;
|
|
|
|
startWithLongNames = false;
|
|
|
|
if (!sl.isEmpty()) {
|
|
|
|
Measure* lm = sl.back()->lastMeasure();
|
|
|
|
firstSystem = lm && lm->sectionBreak() && _layoutMode != LayoutFloat;
|
|
|
|
startWithLongNames = firstSystem && lm->sectionBreak()->startWithLongNames();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
qDebug("empty system!\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: make undoable:
|
|
|
|
while (_systems.size() > curSystem)
|
|
|
|
_systems.takeLast();
|
|
|
|
}
|
|
|
|
|
2012-12-10 17:44:57 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutSystems2
|
|
|
|
// update distanceUp, distanceDown
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutSystems2()
|
|
|
|
{
|
|
|
|
int n = _systems.size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
System* system = _systems.at(i);
|
|
|
|
if (!system->isVbox()) {
|
|
|
|
system->layout2();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutLinear
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutLinear()
|
|
|
|
{
|
|
|
|
curMeasure = first();
|
2013-04-29 16:34:05 +02:00
|
|
|
curSystem = 0;
|
2012-05-26 14:26:10 +02:00
|
|
|
System* system = getNextSystem(true, false);
|
|
|
|
system->setInstrumentNames(true);
|
2013-09-14 02:30:40 +02:00
|
|
|
qreal xo = 0;
|
|
|
|
|
|
|
|
Measure* fm = firstMeasure();
|
2013-10-07 18:39:14 +02:00
|
|
|
for (MeasureBase* m = first(); m != fm ; m = m->next()) {
|
2013-09-14 02:30:40 +02:00
|
|
|
if (m->type() == Element::HBOX)
|
|
|
|
xo += point(static_cast<Box*>(m)->boxWidth());
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
system->layout(xo);
|
|
|
|
system->setPos(0.0, spatium() * 10.0);
|
|
|
|
curPage = 0;
|
|
|
|
Page* page = getEmptyPage();
|
|
|
|
page->appendSystem(system);
|
|
|
|
|
|
|
|
for (MeasureBase* mb = _measures.first(); mb; mb = mb->next()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
Element::ElementType t = curMeasure->type();
|
|
|
|
if (t == Element::VBOX || t == Element::TBOX || t == Element::FBOX) {
|
2012-05-26 14:26:10 +02:00
|
|
|
curMeasure = curMeasure->next();
|
|
|
|
continue;
|
|
|
|
}
|
2013-10-07 18:39:14 +02:00
|
|
|
if (styleB(ST_createMultiMeasureRests) && t == Element::MEASURE) {
|
|
|
|
Measure* m = static_cast<Measure*>(mb);
|
|
|
|
if (m->hasMMRest())
|
|
|
|
mb = m->mmRest();
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
mb->setSystem(system);
|
|
|
|
system->measures().append(mb);
|
|
|
|
}
|
|
|
|
if (system->measures().isEmpty())
|
|
|
|
return;
|
2013-10-07 18:39:14 +02:00
|
|
|
addSystemHeader(firstMeasureMM(), true);
|
|
|
|
removeGeneratedElements(firstMeasureMM(), lastMeasureMM());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-09-14 02:30:40 +02:00
|
|
|
QPointF pos(0.0, 0.0);
|
|
|
|
bool isFirstMeasure = true;
|
2013-10-07 18:39:14 +02:00
|
|
|
foreach (MeasureBase* mb, system->measures()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
qreal w = 0.0;
|
2012-09-13 18:01:34 +02:00
|
|
|
if (mb->type() == Element::MEASURE) {
|
2013-09-14 02:30:40 +02:00
|
|
|
if(isFirstMeasure) {
|
|
|
|
pos.rx() += system->leftMargin();
|
|
|
|
isFirstMeasure = false;
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
Measure* m = static_cast<Measure*>(mb);
|
2013-09-16 18:32:25 +02:00
|
|
|
Measure* nm = m->nextMeasure();
|
|
|
|
if (m->repeatFlags() & RepeatEnd) {
|
|
|
|
if (nm && (nm->repeatFlags() & RepeatStart))
|
2013-12-21 01:14:37 +01:00
|
|
|
m->setEndBarLineType(END_START_REPEAT, m->endBarLineGenerated());
|
2013-09-16 18:32:25 +02:00
|
|
|
else
|
2013-12-21 01:14:37 +01:00
|
|
|
m->setEndBarLineType(END_REPEAT, m->endBarLineGenerated());
|
2013-09-16 18:32:25 +02:00
|
|
|
}
|
|
|
|
else if (nm && (nm->repeatFlags() & RepeatStart))
|
2013-12-21 01:14:37 +01:00
|
|
|
m->setEndBarLineType(START_REPEAT, m->endBarLineGenerated());
|
2013-09-16 18:32:25 +02:00
|
|
|
m->createEndBarLines();
|
2013-04-29 15:31:22 +02:00
|
|
|
w = m->minWidth1() * styleD(ST_linearStretch);
|
2012-05-26 14:26:10 +02:00
|
|
|
m->layout(w);
|
|
|
|
}
|
2013-09-16 18:32:25 +02:00
|
|
|
else {
|
|
|
|
mb->layout();
|
2012-05-26 14:26:10 +02:00
|
|
|
w = mb->width();
|
2013-09-16 18:32:25 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
mb->setPos(pos);
|
|
|
|
pos.rx() += w;
|
|
|
|
}
|
|
|
|
system->setWidth(pos.x());
|
|
|
|
page->setWidth(pos.x());
|
|
|
|
system->layout2();
|
|
|
|
|
|
|
|
while (_pages.size() > 1)
|
|
|
|
_pages.takeLast();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// getEmptyPage
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Page* Score::getEmptyPage()
|
|
|
|
{
|
|
|
|
Page* page = curPage >= _pages.size() ? addPage() : _pages[curPage];
|
|
|
|
page->setNo(curPage);
|
|
|
|
page->layout();
|
|
|
|
qreal x = (curPage == 0) ? 0.0 : _pages[curPage - 1]->pos().x()
|
|
|
|
+ page->width() + ((curPage & 1) ? 50.0 : 1.0);
|
|
|
|
++curPage;
|
|
|
|
page->setPos(x, 0.0);
|
|
|
|
page->systems()->clear();
|
|
|
|
return page;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// SystemRow
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
struct SystemRow {
|
|
|
|
QList<System*> systems;
|
|
|
|
|
|
|
|
qreal height() const {
|
|
|
|
qreal h = 0.0;
|
|
|
|
foreach(System* s, systems) {
|
|
|
|
if (s->height() > h)
|
|
|
|
h = s->height();
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
bool isVbox() const {
|
2013-05-06 21:35:08 +02:00
|
|
|
return (systems.size() > 0) ? systems.back()->isVbox() : false;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
VBox* vbox() const {
|
2013-05-06 21:35:08 +02:00
|
|
|
return (systems.size() > 0) ? systems.back()->vbox() : 0;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
bool pageBreak() const {
|
2013-05-06 21:35:08 +02:00
|
|
|
return (systems.size() > 0) ? systems.back()->pageBreak() : false;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
qreal tm() const {
|
|
|
|
qreal v = 0.0;
|
|
|
|
foreach(System* s, systems) {
|
|
|
|
if (!s->staves()->isEmpty())
|
|
|
|
v = qMax(s->distanceUp(0), v);
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
qreal bm() const {
|
|
|
|
qreal v = 0.0;
|
|
|
|
foreach(System* s, systems) {
|
|
|
|
int staffIdx = s->staves()->size() - 1;
|
|
|
|
if (staffIdx >= 0)
|
|
|
|
v = qMax(s->distanceDown(staffIdx), v);
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
void clear() {
|
|
|
|
systems.clear();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// PageContext
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
struct PageContext {
|
|
|
|
qreal _spatium;
|
|
|
|
qreal slb;
|
|
|
|
Score* score;
|
|
|
|
Page* page;
|
|
|
|
qreal ey;
|
|
|
|
qreal y;
|
|
|
|
int gaps;
|
|
|
|
SystemRow sr;
|
|
|
|
|
|
|
|
System* lastSystem;
|
|
|
|
qreal prevDist;
|
|
|
|
|
|
|
|
PageContext(Score* s) : score(s) {
|
|
|
|
_spatium = score->spatium();
|
|
|
|
slb = score->styleS(ST_staffLowerBorder).val() * _spatium;
|
|
|
|
}
|
|
|
|
void newPage() {
|
|
|
|
page = score->getEmptyPage();
|
|
|
|
ey = page->height() - page->bm();
|
|
|
|
y = page->tm();
|
|
|
|
gaps = 0;
|
|
|
|
lastSystem = 0;
|
|
|
|
prevDist = 0.0;
|
|
|
|
}
|
|
|
|
void layoutPage() {
|
|
|
|
qreal d = sr.isVbox() ? sr.vbox()->bottomGap() : slb;
|
|
|
|
score->layoutPage(*this, d);
|
|
|
|
}
|
|
|
|
qreal bm() const { return sr.bm(); }
|
|
|
|
qreal tm() const { return sr.tm(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutPages
|
|
|
|
// create list of pages
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutPages()
|
|
|
|
{
|
|
|
|
const qreal _spatium = spatium();
|
|
|
|
const qreal slb = styleS(ST_staffLowerBorder).val() * _spatium;
|
|
|
|
const qreal sub = styleS(ST_staffUpperBorder).val() * _spatium;
|
|
|
|
const qreal systemDist = styleS(ST_minSystemDistance).val() * _spatium;
|
|
|
|
const qreal systemFrameDistance = styleS(ST_systemFrameDistance).val() * _spatium;
|
|
|
|
const qreal frameSystemDistance = styleS(ST_frameSystemDistance).val() * _spatium;
|
|
|
|
|
|
|
|
curPage = 0;
|
|
|
|
|
|
|
|
PageContext pC(this);
|
|
|
|
pC.newPage();
|
|
|
|
|
|
|
|
int nSystems = _systems.size();
|
|
|
|
|
|
|
|
for (int i = 0; i < nSystems; ++i) {
|
|
|
|
//
|
|
|
|
// collect system row
|
|
|
|
//
|
|
|
|
pC.sr.clear();
|
|
|
|
for (;;) {
|
|
|
|
System* system = _systems[i];
|
|
|
|
pC.sr.systems.append(system);
|
|
|
|
if (i+1 == nSystems)
|
|
|
|
break;
|
|
|
|
if (!_systems[i+1]->sameLine())
|
|
|
|
break;
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
qreal tmargin = 0.0; // top system margin
|
|
|
|
qreal bmargin; // bottom system margin
|
|
|
|
|
|
|
|
if (pC.sr.isVbox()) {
|
|
|
|
VBox* vbox = pC.sr.vbox();
|
|
|
|
bmargin = vbox->bottomGap();
|
|
|
|
tmargin += vbox->topGap();
|
|
|
|
if (pC.lastSystem) {
|
|
|
|
if (pC.lastSystem->isVbox())
|
|
|
|
tmargin += pC.lastSystem->vbox()->bottomGap();
|
|
|
|
else
|
|
|
|
tmargin += systemFrameDistance;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pC.lastSystem) {
|
|
|
|
if (pC.lastSystem->isVbox())
|
|
|
|
tmargin = pC.lastSystem->vbox()->bottomGap() + frameSystemDistance;
|
|
|
|
else
|
|
|
|
tmargin = qMax(pC.tm(), systemDist);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tmargin = qMax(pC.tm(), sub);
|
2012-12-10 17:44:57 +01:00
|
|
|
bmargin = pC.bm();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
tmargin = qMax(tmargin, pC.prevDist);
|
|
|
|
pC.prevDist = bmargin;
|
|
|
|
|
|
|
|
qreal h = pC.sr.height();
|
2012-12-10 17:44:57 +01:00
|
|
|
if (pC.lastSystem && (pC.y + h + tmargin + qMax(bmargin, slb) > pC.ey)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
// prepare next page
|
|
|
|
//
|
|
|
|
qreal d;
|
|
|
|
if (pC.lastSystem->isVbox())
|
|
|
|
d = pC.lastSystem->vbox()->bottomGap();
|
|
|
|
else
|
|
|
|
d = slb;
|
|
|
|
layoutPage(pC, d);
|
|
|
|
pC.newPage();
|
|
|
|
if (pC.sr.isVbox())
|
|
|
|
tmargin = pC.sr.vbox()->topGap();
|
|
|
|
else
|
|
|
|
tmargin = qMax(pC.sr.tm(), sub);
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal x = pC.page->lm();
|
|
|
|
pC.y += tmargin;
|
|
|
|
|
|
|
|
foreach(System* system, pC.sr.systems) {
|
|
|
|
system->setPos(x, pC.y);
|
|
|
|
x += system->width();
|
|
|
|
pC.page->appendSystem(system);
|
|
|
|
system->setAddStretch(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pC.lastSystem) {
|
|
|
|
bool addStretch = !pC.lastSystem->isVbox() && !pC.sr.isVbox();
|
|
|
|
pC.lastSystem->setAddStretch(addStretch);
|
|
|
|
if (addStretch)
|
|
|
|
++pC.gaps;
|
|
|
|
}
|
|
|
|
|
|
|
|
pC.y += h;
|
|
|
|
if (pC.sr.pageBreak() && (_layoutMode == LayoutPage)) {
|
|
|
|
if ((i + 1) == nSystems)
|
|
|
|
break;
|
|
|
|
pC.layoutPage();
|
|
|
|
pC.newPage();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pC.lastSystem = pC.sr.systems.back();
|
|
|
|
}
|
|
|
|
if (pC.page)
|
|
|
|
pC.layoutPage();
|
|
|
|
|
|
|
|
// Remove not needed pages. TODO: make undoable:
|
|
|
|
while (_pages.size() > curPage)
|
|
|
|
_pages.takeLast();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// systemDistCompare
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static bool systemDistCompare(System* s1, System* s2)
|
|
|
|
{
|
|
|
|
return s1->distance() < s2->distance();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutPage
|
|
|
|
// increase system distance upto maxSystemDistance
|
|
|
|
// to fill page
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::layoutPage(const PageContext& pC, qreal d)
|
|
|
|
{
|
|
|
|
Page* page = pC.page;
|
|
|
|
int gaps = pC.gaps;
|
|
|
|
qreal restHeight = pC.ey - pC.y - d;
|
|
|
|
|
|
|
|
if (!gaps || MScore::layoutDebug) {
|
|
|
|
if (_layoutMode == LayoutFloat) {
|
|
|
|
qreal y = restHeight * .5;
|
|
|
|
int n = page->systems()->size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
System* system = page->systems()->at(i);
|
|
|
|
system->move(0, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const qreal maxStretch = styleP(ST_maxSystemDistance) - styleP(ST_minSystemDistance);
|
|
|
|
|
|
|
|
QList<System*> slist;
|
|
|
|
int n = page->systems()->size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
System* system = page->systems()->at(i);
|
|
|
|
qreal lastY1 = system->pos().y() + system->height();
|
|
|
|
|
|
|
|
if (system->addStretch()) {
|
|
|
|
System* ns = page->systems()->at(i + 1);
|
|
|
|
qreal dist = ns->pos().y() - lastY1;
|
|
|
|
system->setDistance(dist);
|
|
|
|
slist.append(system);
|
|
|
|
system->setStretchDistance(0.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qSort(slist.begin(), slist.end(), systemDistCompare);
|
|
|
|
|
|
|
|
n = slist.size();
|
|
|
|
for (int i = 0; i < (n-1); ++i) {
|
|
|
|
System* s1 = slist.at(i);
|
|
|
|
System* s2 = slist.at(i + 1);
|
|
|
|
qreal td = s2->distance() - s1->distance();
|
|
|
|
if (td > 0.001) {
|
|
|
|
int nn = i + 1;
|
|
|
|
qreal tdd = td * nn;
|
|
|
|
if (tdd > restHeight) {
|
|
|
|
tdd = restHeight;
|
|
|
|
td = tdd / nn;
|
|
|
|
}
|
|
|
|
if (s1->stretchDistance() + td > maxStretch) {
|
|
|
|
td = maxStretch - s1->stretchDistance();
|
|
|
|
tdd = td * nn;
|
|
|
|
}
|
|
|
|
for (int k = 0; k <= i; ++k)
|
|
|
|
slist.at(k)->addStretchDistance(td);
|
|
|
|
restHeight -= tdd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qreal td = restHeight / n;
|
|
|
|
if (td > 0.001) {
|
|
|
|
qreal sd = slist.at(0)->stretchDistance();
|
|
|
|
if (sd + td > maxStretch)
|
|
|
|
td = maxStretch - sd;
|
|
|
|
for (int k = 0; k < n; ++k)
|
|
|
|
slist.at(k)->addStretchDistance(td);
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal y = 0.0;
|
|
|
|
n = page->systems()->size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
System* system = page->systems()->at(i);
|
|
|
|
system->move(0, y);
|
|
|
|
if (system->addStretch())
|
|
|
|
y += system->stretchDistance();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// doLayoutSystems
|
|
|
|
// layout staves in a system
|
|
|
|
// layout pages
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::doLayoutSystems()
|
|
|
|
{
|
2013-06-05 15:47:34 +02:00
|
|
|
foreach(System* system, _systems)
|
|
|
|
system->layout2();
|
|
|
|
layoutPages();
|
|
|
|
rebuildBspTree();
|
|
|
|
_updateAll = true;
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
foreach(MuseScoreView* v, viewer)
|
|
|
|
v->layoutChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// doLayoutPages
|
|
|
|
// small wrapper for layoutPages()
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::doLayoutPages()
|
|
|
|
{
|
2013-06-05 15:47:34 +02:00
|
|
|
layoutPages();
|
|
|
|
rebuildBspTree();
|
|
|
|
_updateAll = true;
|
2012-05-26 14:26:10 +02:00
|
|
|
foreach(MuseScoreView* v, viewer)
|
|
|
|
v->layoutChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// sff
|
|
|
|
// compute 1/Force for a given Extend
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-08-01 18:00:27 +02:00
|
|
|
qreal sff(qreal x, qreal xMin, const SpringMap& springs)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
if (x <= xMin)
|
|
|
|
return 0.0;
|
|
|
|
iSpring i = springs.begin();
|
|
|
|
qreal c = i->second.stretch;
|
|
|
|
if (c == 0.0) //DEBUG
|
|
|
|
c = 1.1;
|
|
|
|
qreal f = 0.0;
|
|
|
|
for (; i != springs.end();) {
|
|
|
|
xMin -= i->second.fix;
|
|
|
|
f = (x - xMin) / c;
|
|
|
|
++i;
|
|
|
|
if (i == springs.end() || f <= i->first)
|
|
|
|
break;
|
|
|
|
c += i->second.stretch;
|
|
|
|
}
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// respace
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::respace(QList<ChordRest*>* elements)
|
|
|
|
{
|
|
|
|
ChordRest* cr1 = elements->front();
|
|
|
|
ChordRest* cr2 = elements->back();
|
|
|
|
int n = elements->size();
|
|
|
|
qreal x1 = cr1->segment()->pos().x();
|
|
|
|
qreal x2 = cr2->segment()->pos().x();
|
|
|
|
|
|
|
|
qreal width[n-1];
|
|
|
|
int ticksList[n-1];
|
|
|
|
int minTick = 100000;
|
|
|
|
|
|
|
|
for (int i = 0; i < n-1; ++i) {
|
|
|
|
ChordRest* cr = (*elements)[i];
|
|
|
|
ChordRest* ncr = (*elements)[i+1];
|
|
|
|
Space space(cr->space());
|
|
|
|
Space nspace(ncr->space());
|
|
|
|
width[i] = space.rw() + nspace.lw();
|
|
|
|
ticksList[i] = ncr->segment()->tick() - cr->segment()->tick();
|
|
|
|
minTick = qMin(ticksList[i], minTick);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------
|
|
|
|
// compute stretches
|
|
|
|
//---------------------------------------------------
|
|
|
|
|
|
|
|
SpringMap springs;
|
|
|
|
qreal minimum = 0.0;
|
|
|
|
for (int i = 0; i < n-1; ++i) {
|
|
|
|
qreal w = width[i];
|
|
|
|
int t = ticksList[i];
|
2012-12-06 12:46:05 +01:00
|
|
|
// qreal str = 1.0 + .6 * log(qreal(t) / qreal(minTick)) / log(2.0);
|
|
|
|
qreal str = 1.0 + 0.865617 * log(qreal(t) / qreal(minTick));
|
2012-05-26 14:26:10 +02:00
|
|
|
qreal d = w / str;
|
|
|
|
|
|
|
|
springs.insert(std::pair<qreal, Spring>(d, Spring(i, str, w)));
|
|
|
|
minimum += w;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------
|
|
|
|
// distribute stretch to elements
|
|
|
|
//---------------------------------------------------
|
|
|
|
|
|
|
|
qreal force = sff(x2 - x1, minimum, springs);
|
|
|
|
for (iSpring i = springs.begin(); i != springs.end(); ++i) {
|
|
|
|
qreal stretch = force * i->second.stretch;
|
|
|
|
if (stretch < i->second.fix)
|
|
|
|
stretch = i->second.fix;
|
|
|
|
width[i->second.seg] = stretch;
|
|
|
|
}
|
|
|
|
qreal x = x1;
|
|
|
|
for (int i = 1; i < n-1; ++i) {
|
|
|
|
x += width[i-1];
|
|
|
|
ChordRest* cr = (*elements)[i];
|
|
|
|
qreal dx = x - cr->segment()->pos().x();
|
|
|
|
cr->rxpos() += dx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-01 18:00:27 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// computeMinWidth
|
|
|
|
/// compute the minimum width of a measure with
|
|
|
|
/// segment list fs
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-05-22 14:12:47 +02:00
|
|
|
qreal Score::computeMinWidth(Segment* fs)
|
2012-08-01 18:00:27 +02:00
|
|
|
{
|
|
|
|
int _nstaves = nstaves();
|
2012-10-08 08:28:19 +02:00
|
|
|
if (_nstaves == 0)
|
2012-08-01 18:00:27 +02:00
|
|
|
return 1.0;
|
|
|
|
|
|
|
|
qreal _spatium = spatium();
|
|
|
|
qreal clefKeyRightMargin = styleS(ST_clefKeyRightMargin).val() * _spatium;
|
|
|
|
qreal minNoteDistance = styleS(ST_minNoteDistance).val() * _spatium;
|
2013-03-14 16:52:10 +01:00
|
|
|
qreal minHarmonyDistance = styleS(ST_minHarmonyDistance).val() * _spatium;
|
2012-08-01 18:00:27 +02:00
|
|
|
|
|
|
|
qreal rest[_nstaves]; // fixed space needed from previous segment
|
|
|
|
memset(rest, 0, _nstaves * sizeof(qreal));
|
|
|
|
|
2013-03-14 16:52:10 +01:00
|
|
|
qreal hRest[_nstaves]; // fixed space needed from previous harmony
|
|
|
|
memset(hRest, 0, _nstaves * sizeof(qreal));
|
|
|
|
|
2012-08-01 18:00:27 +02:00
|
|
|
qreal clefWidth[_nstaves];
|
|
|
|
memset(clefWidth, 0, _nstaves * sizeof(qreal));
|
|
|
|
|
2013-04-08 18:26:53 +02:00
|
|
|
std::vector<QRectF> hLastBbox(_nstaves); // bbox of previous harmony to test vertical separation
|
2013-03-26 16:25:07 +01:00
|
|
|
|
2012-08-01 18:00:27 +02:00
|
|
|
int segmentIdx = 0;
|
|
|
|
qreal x = 0.0;
|
|
|
|
|
2012-10-23 22:16:31 +02:00
|
|
|
const Segment* pSeg = 0;
|
2012-08-01 18:00:27 +02:00
|
|
|
for (Segment* s = fs; s; s = s->next(), ++segmentIdx) {
|
|
|
|
qreal elsp = s->extraLeadingSpace().val() * _spatium;
|
|
|
|
qreal etsp = s->extraTrailingSpace().val() * _spatium;
|
|
|
|
|
2013-03-05 20:23:59 +01:00
|
|
|
if ((s->segmentType() == Segment::SegClef) && (s != fs)) {
|
2012-08-01 18:00:27 +02:00
|
|
|
--segmentIdx;
|
|
|
|
for (int staffIdx = 0; staffIdx < _nstaves; ++staffIdx) {
|
2012-10-23 20:22:49 +02:00
|
|
|
if (!staff(staffIdx)->show())
|
|
|
|
continue;
|
2012-08-01 18:00:27 +02:00
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
Element* e = s->element(track);
|
|
|
|
if (e) {
|
|
|
|
e->layout();
|
|
|
|
clefWidth[staffIdx] = e->width() + _spatium + elsp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2013-03-14 16:52:10 +01:00
|
|
|
bool rest2[_nstaves];
|
|
|
|
bool hRest2[_nstaves];
|
2013-03-05 20:23:59 +01:00
|
|
|
Segment::SegmentType segType = s->segmentType();
|
2012-08-01 18:00:27 +02:00
|
|
|
qreal segmentWidth = 0.0;
|
|
|
|
qreal stretchDistance = 0.0;
|
2013-03-05 20:23:59 +01:00
|
|
|
int pt = pSeg ? pSeg->segmentType() : Segment::SegBarLine;
|
2012-08-01 18:00:27 +02:00
|
|
|
|
|
|
|
for (int staffIdx = 0; staffIdx < _nstaves; ++staffIdx) {
|
2012-08-01 22:15:58 +02:00
|
|
|
if (!staff(staffIdx)->show())
|
|
|
|
continue;
|
2012-08-01 18:00:27 +02:00
|
|
|
qreal minDistance = 0.0;
|
|
|
|
Space space;
|
2013-03-14 16:52:10 +01:00
|
|
|
Space hSpace;
|
2013-03-26 16:25:07 +01:00
|
|
|
QRectF hBbox;
|
2012-08-01 18:00:27 +02:00
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
bool found = false;
|
2013-03-14 16:52:10 +01:00
|
|
|
bool hFound = false;
|
2013-03-26 16:25:07 +01:00
|
|
|
bool eFound = false;
|
2013-06-12 14:23:57 +02:00
|
|
|
if (segType & (Segment::SegChordRest)) {
|
2012-08-01 18:00:27 +02:00
|
|
|
qreal llw = 0.0;
|
|
|
|
qreal rrw = 0.0;
|
|
|
|
Lyrics* lyrics = 0;
|
|
|
|
for (int voice = 0; voice < VOICES; ++voice) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(s->element(track+voice));
|
|
|
|
if (!cr)
|
|
|
|
continue;
|
|
|
|
found = true;
|
2012-08-03 15:54:02 +02:00
|
|
|
if (pt & (Segment::SegStartRepeatBarLine | Segment::SegBarLine)) {
|
2013-07-15 11:57:07 +02:00
|
|
|
// check for accidentals in chord
|
|
|
|
bool accidental = false;
|
|
|
|
if (cr->type() == Element::CHORD) {
|
|
|
|
Chord* c = static_cast<Chord*>(cr);
|
|
|
|
if (!c->graceNotes().empty())
|
|
|
|
accidental = true;
|
|
|
|
else {
|
|
|
|
for (Note* note : c->notes()) {
|
|
|
|
if (note->accidental()) {
|
|
|
|
accidental = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
StyleIdx si = accidental ? ST_barAccidentalDistance : ST_barNoteDistance;
|
|
|
|
qreal sp = styleS(si).val() * _spatium;
|
|
|
|
sp += elsp;
|
|
|
|
minDistance = qMax(minDistance, sp);
|
2012-08-01 18:00:27 +02:00
|
|
|
stretchDistance = sp * .7;
|
|
|
|
}
|
2013-06-12 14:23:57 +02:00
|
|
|
else if (pt & (Segment::SegChordRest)) {
|
2012-08-01 18:00:27 +02:00
|
|
|
minDistance = qMax(minDistance, minNoteDistance);
|
|
|
|
}
|
|
|
|
else {
|
2012-08-03 15:54:02 +02:00
|
|
|
// if (pt & (Segment::SegKeySig | Segment::SegClef))
|
|
|
|
bool firstClef = (segmentIdx == 1) && (pt == Segment::SegClef);
|
|
|
|
if ((pt & (Segment::SegKeySig | Segment::SegTimeSig)) || firstClef)
|
2012-08-01 18:00:27 +02:00
|
|
|
minDistance = qMax(minDistance, clefKeyRightMargin);
|
|
|
|
}
|
|
|
|
cr->layout();
|
|
|
|
space.max(cr->space());
|
|
|
|
foreach(Lyrics* l, cr->lyricsList()) {
|
|
|
|
if (!l)
|
|
|
|
continue;
|
|
|
|
if (!l->isEmpty()) {
|
|
|
|
l->layout();
|
|
|
|
lyrics = l;
|
|
|
|
if (!lyrics->isMelisma()) {
|
|
|
|
QRectF b(l->bbox().translated(l->pos()));
|
|
|
|
llw = qMax(llw, -b.left());
|
|
|
|
rrw = qMax(rrw, b.right());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lyrics)
|
|
|
|
space.max(Space(llw, rrw));
|
2013-03-13 11:13:33 +01:00
|
|
|
|
2013-03-14 16:52:10 +01:00
|
|
|
// add spacing for chord symbols
|
2013-03-13 11:13:33 +01:00
|
|
|
foreach (Element* e, s->annotations()) {
|
2013-03-14 16:52:10 +01:00
|
|
|
if (e->type() != Element::HARMONY || e->track() < track || e->track() >= track+VOICES)
|
2013-03-13 11:13:33 +01:00
|
|
|
continue;
|
|
|
|
Harmony* h = static_cast<Harmony*>(e);
|
2013-09-03 14:00:07 +02:00
|
|
|
//h->layout();
|
|
|
|
h->calculateBoundingRect();
|
2013-04-03 19:16:28 +02:00
|
|
|
QRectF b(h->bboxtight().translated(h->pos()));
|
2013-03-26 16:25:07 +01:00
|
|
|
if (hFound)
|
|
|
|
hBbox |= b;
|
|
|
|
else
|
|
|
|
hBbox = b;
|
|
|
|
hFound = true;
|
2013-03-13 11:13:33 +01:00
|
|
|
// allow chord at the beginning of a measure to be dragged left
|
2013-03-14 16:52:10 +01:00
|
|
|
hSpace.max(Space(s->rtick()?-b.left():0.0, b.right()));
|
2013-03-13 11:13:33 +01:00
|
|
|
}
|
2012-08-01 18:00:27 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
Element* e = s->element(track);
|
2012-08-03 15:54:02 +02:00
|
|
|
if ((segType == Segment::SegClef) && (pt != Segment::SegChordRest))
|
2012-08-01 18:00:27 +02:00
|
|
|
minDistance = styleP(ST_clefLeftMargin);
|
2012-08-03 15:54:02 +02:00
|
|
|
else if (segType == Segment::SegStartRepeatBarLine)
|
2012-08-01 18:00:27 +02:00
|
|
|
minDistance = .5 * _spatium;
|
2012-08-03 15:54:02 +02:00
|
|
|
else if ((segType == Segment::SegEndBarLine) && segmentIdx) {
|
2013-01-24 19:39:24 +01:00
|
|
|
if (pt == Segment::SegClef)
|
2012-08-01 18:00:27 +02:00
|
|
|
minDistance = styleP(ST_clefBarlineDistance);
|
|
|
|
else
|
|
|
|
stretchDistance = styleP(ST_noteBarDistance);
|
|
|
|
if (e == 0) {
|
|
|
|
// look for barline
|
|
|
|
for (int i = track - VOICES; i >= 0; i -= VOICES) {
|
|
|
|
e = s->element(i);
|
|
|
|
if (e)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (e) {
|
2013-03-26 16:25:07 +01:00
|
|
|
eFound = true;
|
2012-08-01 18:00:27 +02:00
|
|
|
e->layout();
|
|
|
|
space.max(e->space());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
space += Space(elsp, etsp);
|
2013-03-14 16:52:10 +01:00
|
|
|
|
2013-03-26 16:25:07 +01:00
|
|
|
if (found || eFound) {
|
2012-08-01 18:00:27 +02:00
|
|
|
space.rLw() += clefWidth[staffIdx];
|
2013-03-14 16:52:10 +01:00
|
|
|
qreal sp = minDistance + rest[staffIdx] + qMax(space.lw(), stretchDistance);
|
2012-08-01 18:00:27 +02:00
|
|
|
rest[staffIdx] = space.rw();
|
|
|
|
rest2[staffIdx] = false;
|
|
|
|
segmentWidth = qMax(segmentWidth, sp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rest2[staffIdx] = true;
|
2013-03-14 16:52:10 +01:00
|
|
|
|
|
|
|
// space chord symbols separately from segments
|
2013-03-26 16:25:07 +01:00
|
|
|
if (hFound || eFound) {
|
|
|
|
qreal sp = 0.0;
|
|
|
|
|
|
|
|
// space chord symbols unless they miss each other vertically
|
|
|
|
if (eFound || (hBbox.top() < hLastBbox[staffIdx].bottom() && hBbox.bottom() > hLastBbox[staffIdx].top()))
|
|
|
|
sp = hRest[staffIdx] + minHarmonyDistance + hSpace.lw();
|
|
|
|
hLastBbox[staffIdx] = hBbox;
|
|
|
|
|
2013-03-14 16:52:10 +01:00
|
|
|
hRest[staffIdx] = hSpace.rw();
|
|
|
|
hRest2[staffIdx] = false;
|
|
|
|
segmentWidth = qMax(segmentWidth, sp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
hRest2[staffIdx] = true;
|
|
|
|
|
2012-08-01 18:00:27 +02:00
|
|
|
clefWidth[staffIdx] = 0.0;
|
|
|
|
}
|
2013-03-26 16:25:07 +01:00
|
|
|
|
2012-08-01 18:00:27 +02:00
|
|
|
x += segmentWidth;
|
|
|
|
|
2012-10-23 22:16:31 +02:00
|
|
|
// if (segmentIdx && pSeg)
|
|
|
|
// pSeg->setbbox(QRectF(0.0, 0.0, segmentWidth, _spatium * 5)); //??
|
2012-08-01 18:00:27 +02:00
|
|
|
|
|
|
|
for (int staffIdx = 0; staffIdx < _nstaves; ++staffIdx) {
|
2012-08-01 22:15:58 +02:00
|
|
|
if (!staff(staffIdx)->show())
|
|
|
|
continue;
|
2012-08-01 18:00:27 +02:00
|
|
|
if (rest2[staffIdx])
|
2013-03-14 16:52:10 +01:00
|
|
|
rest[staffIdx] -= qMin(rest[staffIdx],segmentWidth);
|
|
|
|
if (hRest2[staffIdx])
|
|
|
|
hRest[staffIdx] -= qMin(hRest[staffIdx],segmentWidth);
|
2012-08-01 18:00:27 +02:00
|
|
|
}
|
2012-10-23 22:16:31 +02:00
|
|
|
//
|
|
|
|
// set pSeg only to used segments
|
|
|
|
//
|
|
|
|
for (int voice = 0; voice < _nstaves * VOICES; ++voice) {
|
|
|
|
if (!staff(voice/VOICES)->show()) {
|
|
|
|
voice += VOICES-1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (s->element(voice)) {
|
|
|
|
pSeg = s;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-08-01 18:00:27 +02:00
|
|
|
}
|
2012-10-23 22:16:31 +02:00
|
|
|
|
2012-08-01 18:00:27 +02:00
|
|
|
qreal segmentWidth = 0.0;
|
2012-08-01 22:15:58 +02:00
|
|
|
for (int staffIdx = 0; staffIdx < _nstaves; ++staffIdx) {
|
|
|
|
if (!staff(staffIdx)->show())
|
|
|
|
continue;
|
2012-08-01 18:00:27 +02:00
|
|
|
segmentWidth = qMax(segmentWidth, rest[staffIdx]);
|
2013-03-14 16:52:10 +01:00
|
|
|
segmentWidth = qMax(segmentWidth, hRest[staffIdx]);
|
2012-08-01 22:15:58 +02:00
|
|
|
}
|
2012-08-01 18:00:27 +02:00
|
|
|
x += segmentWidth;
|
|
|
|
return x;
|
|
|
|
}
|
2012-10-26 11:42:54 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// updateBarLineSpans
|
|
|
|
/// updates bar line span(s) when the number of lines of a staff changes
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-11-05 20:31:57 +01:00
|
|
|
void Score::updateBarLineSpans(int idx, int linesOld, int linesNew)
|
2012-10-26 11:42:54 +02:00
|
|
|
{
|
|
|
|
int nStaves = nstaves();
|
|
|
|
Staff* _staff;
|
|
|
|
|
|
|
|
// scan staves and check the destination staff of each bar line span
|
|
|
|
// barLineSpan is not changed; barLineFrom and barLineTo are changed if they occur in the bottom half of a staff
|
|
|
|
// in practice, a barLineFrom/To from/to the top half of the staff is linked to the staff top line,
|
|
|
|
// a barLineFrom/To from/to the bottom half of the staff is linked to staff bottom line;
|
2012-11-11 01:50:57 +01:00
|
|
|
// this ensures plainchant and mensurstrich special bar lines keep their relationships to the staff lines.
|
2012-12-21 01:09:29 +01:00
|
|
|
// 1-line staves are traited as a special case.
|
2012-10-26 11:42:54 +02:00
|
|
|
for(int sIdx = 0; sIdx < nStaves; sIdx++) {
|
|
|
|
_staff = staff(sIdx);
|
|
|
|
// if this is the modified staff
|
|
|
|
if(sIdx == idx) {
|
|
|
|
// if it has no bar line, set barLineTo to a default value
|
|
|
|
if(_staff->barLineSpan() == 0)
|
|
|
|
_staff->setBarLineTo( (linesNew-1) * 2);
|
2012-12-21 01:09:29 +01:00
|
|
|
// if new line number is 1, set default From for 1-line staves
|
|
|
|
else if(linesNew == 1)
|
|
|
|
_staff->setBarLineFrom(BARLINE_SPAN_1LINESTAFF_FROM);
|
2012-10-26 11:42:54 +02:00
|
|
|
// if barLineFrom was below the staff middle position
|
|
|
|
// raise or lower it to account for new number of lines
|
|
|
|
else if(_staff->barLineFrom() > linesOld - 1)
|
|
|
|
_staff->setBarLineFrom(_staff->barLineFrom() + (linesNew - linesOld)*2);
|
|
|
|
}
|
|
|
|
|
2012-12-21 01:09:29 +01:00
|
|
|
// if the modified staff is the destination of the current staff bar span:
|
|
|
|
if(sIdx + _staff->barLineSpan() - 1 == idx) {
|
|
|
|
// if new line number is 1, set default To for 1-line staves
|
|
|
|
if(linesNew == 1)
|
|
|
|
_staff->setBarLineTo(BARLINE_SPAN_1LINESTAFF_TO);
|
|
|
|
// if barLineTo was below its middle position, raise or lower it
|
|
|
|
else if(_staff->barLineTo() > linesOld - 1)
|
|
|
|
_staff->setBarLineTo(_staff->barLineTo() + (linesNew - linesOld)*2);
|
|
|
|
}
|
2012-10-26 11:42:54 +02:00
|
|
|
}
|
|
|
|
}
|
2013-05-13 18:49:17 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|