MuseScore/libmscore/system.cpp

988 lines
34 KiB
C++
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
// $Id: system.cpp 5656 2012-05-21 15:36:47Z wschweer $
//
// 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
//=============================================================================
/**
\file
Implementation of classes SysStaff and System.
*/
#include "system.h"
#include "measure.h"
#include "segment.h"
#include "score.h"
#include "sig.h"
#include "key.h"
#include "xml.h"
#include "clef.h"
#include "text.h"
#include "navigate.h"
#include "select.h"
#include "staff.h"
#include "part.h"
#include "page.h"
#include "style.h"
#include "bracket.h"
#include "mscore.h"
#include "barline.h"
#include "lyrics.h"
#include "system.h"
#include "box.h"
#include "chordrest.h"
#include "iname.h"
#include "spanner.h"
//---------------------------------------------------------
// SysStaff
//---------------------------------------------------------
SysStaff::SysStaff()
{
idx = 0;
_show = true;
}
//---------------------------------------------------------
// ~SysStaff
//---------------------------------------------------------
SysStaff::~SysStaff()
{
qDeleteAll(instrumentNames);
}
//---------------------------------------------------------
// System
//---------------------------------------------------------
System::System(Score* s)
: Element(s)
{
2012-10-17 20:22:24 +02:00
_barLine = 0;
2012-05-26 14:26:10 +02:00
_leftMargin = 0.0;
_pageBreak = false;
_firstSystem = false;
_vbox = false;
_sameLine = false;
_addStretch = false;
}
//---------------------------------------------------------
// ~System
//---------------------------------------------------------
System::~System()
{
2012-10-17 20:22:24 +02:00
delete _barLine;
2012-05-26 14:26:10 +02:00
qDeleteAll(_staves);
2012-10-12 15:36:57 +02:00
qDeleteAll(_brackets);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// insertStaff
//---------------------------------------------------------
SysStaff* System::insertStaff(int idx)
{
SysStaff* staff = new SysStaff;
if (idx) {
// HACK: guess position
staff->rbb().setY(_staves[idx-1]->y() + 6 * spatium());
}
_staves.insert(idx, staff);
return staff;
}
//---------------------------------------------------------
// removeStaff
//---------------------------------------------------------
void System::removeStaff(int idx)
{
_staves.takeAt(idx);
}
//---------------------------------------------------------
// layout
/// Layout the System
// If first MeasureBase is a HBOX, then xo1 is the
// width of this box.
//---------------------------------------------------------
void System::layout(qreal xo1)
{
if (isVbox()) // ignore vbox
return;
static const Spatium instrumentNameOffset(1.0);
int nstaves = _staves.size();
if (nstaves != score()->nstaves())
2012-10-12 15:36:57 +02:00
qDebug("System::layout: nstaves %d != %d", nstaves, score()->nstaves());
2012-05-26 14:26:10 +02:00
//---------------------------------------------------
// find x position of staves
// create brackets
//---------------------------------------------------
qreal xoff2 = 0.0; // x offset for instrument name
int bracketLevels = 0;
2012-10-12 15:36:57 +02:00
for (int idx = 0; idx < nstaves; ++idx)
bracketLevels = qMax(bracketLevels, score()->staff(idx)->bracketLevels());
2012-05-26 14:26:10 +02:00
qreal bracketWidth[bracketLevels];
for (int i = 0; i < bracketLevels; ++i)
bracketWidth[i] = 0.0;
2012-10-12 15:36:57 +02:00
QList<Bracket*> bl = _brackets;
_brackets.clear();
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
2012-10-12 15:36:57 +02:00
Staff* s = score()->staff(staffIdx);
for (int i = 0; i < bracketLevels; ++i) {
if (s->bracket(i) == NO_BRACKET)
continue;
int firstStaff = staffIdx;
int lastStaff = staffIdx + s->bracketSpan(i) - 1;
if (lastStaff >= nstaves)
lastStaff = nstaves - 1;
2012-05-26 14:26:10 +02:00
2012-10-12 15:36:57 +02:00
for (; firstStaff <= lastStaff; ++firstStaff) {
if (score()->staff(firstStaff)->show())
break;
2012-05-26 14:26:10 +02:00
}
2012-10-12 15:36:57 +02:00
for (; lastStaff >= firstStaff; --lastStaff) {
if (score()->staff(lastStaff)->show())
break;
2012-05-26 14:26:10 +02:00
}
2012-10-12 15:36:57 +02:00
int span = lastStaff - firstStaff + 1;
//
// do not show bracket, if it only spans one
// system due to some invisible staves
//
if ((span > 1) || (s->bracketSpan(i) == span)) {
//
// this bracket is visible
//
Bracket* b = 0;
int track = staffIdx * VOICES;
for (int k = 0; k < bl.size(); ++k) {
if (bl[k]->track() == track && bl[k]->level() == i) {
b = bl.takeAt(k);
break;
}
}
2012-05-26 14:26:10 +02:00
if (b == 0) {
2012-10-12 15:36:57 +02:00
b = new Bracket(score());
b->setGenerated(true);
2012-05-26 14:26:10 +02:00
b->setParent(this);
2012-10-12 15:36:57 +02:00
b->setTrack(track);
b->setLevel(i);
b->setSubtype(s->bracket(i));
b->setSpan(s->bracketSpan(i));
score()->undoAddElement(b);
}
else {
_brackets.append(b);
2012-05-26 14:26:10 +02:00
}
2012-10-12 15:36:57 +02:00
b->setFirstStaff(firstStaff);
b->setLastStaff(lastStaff);
bracketWidth[i] = qMax(bracketWidth[i], b->width());
2012-05-26 14:26:10 +02:00
}
}
2012-10-12 15:36:57 +02:00
if (!s->show())
continue;
foreach(InstrumentName* t, _staves[staffIdx]->instrumentNames) {
2012-05-26 14:26:10 +02:00
t->layout();
qreal w = t->width() + point(instrumentNameOffset);
if (w > xoff2)
xoff2 = w;
}
}
2012-10-12 15:36:57 +02:00
_brackets.append(bl);
foreach(Bracket* b, bl)
score()->undoRemoveElement(b);
2012-05-26 14:26:10 +02:00
//---------------------------------------------------
// layout SysStaff and StaffLines
//---------------------------------------------------
// xoff2 += xo1;
_leftMargin = xoff2;
2012-10-12 15:36:57 +02:00
qreal bd = point(score()->styleS(ST_bracketDistance));
2012-05-26 14:26:10 +02:00
for (int i = 0; i < bracketLevels; ++i)
2012-10-12 15:36:57 +02:00
_leftMargin += bracketWidth[i] + bd;
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
SysStaff* s = _staves[staffIdx];
Staff* staff = score()->staff(staffIdx);
if (!staff->show() || !s->show()) {
2012-05-26 14:26:10 +02:00
s->setbbox(QRectF());
continue;
}
qreal staffMag = staff->mag();
s->setbbox(QRectF(_leftMargin + xo1, 0.0, 0.0,
(staff->lines()-1) * staff->lineDistance() * spatium() * staffMag));
2012-05-26 14:26:10 +02:00
}
if ((nstaves > 1 && score()->styleB(ST_startBarlineMultiple)) || (nstaves <= 1 && score()->styleB(ST_startBarlineSingle))) {
2012-10-17 20:22:24 +02:00
if (_barLine == 0) {
_barLine = new BarLine(score());
_barLine->setParent(this);
_barLine->setTrack(0);
_barLine->setGenerated(true);
score()->undoAddElement(_barLine);
2012-05-26 14:26:10 +02:00
}
}
2012-10-17 20:22:24 +02:00
else if (_barLine)
score()->undoRemoveElement(_barLine);
if (_barLine)
_barLine->rxpos() = _leftMargin + xo1;
2012-05-26 14:26:10 +02:00
//---------------------------------------------------
// layout brackets
//---------------------------------------------------
2012-10-12 15:36:57 +02:00
foreach (Bracket* b, _brackets) {
qreal xo = -xo1;
int level = b->level();
for (int i = 0; i < level; ++i)
xo += bracketWidth[i] + bd;
b->rxpos() = _leftMargin - xo - b->width();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------
// layout instrument names x position
//---------------------------------------------------
int idx = 0;
foreach (Part* p, score()->parts()) {
SysStaff* s = staff(idx);
int nstaves = p->nstaves();
if (s->show() && p->show()) {
foreach(InstrumentName* t, s->instrumentNames) {
qreal d = point(instrumentNameOffset) + t->bbox().width();
t->rxpos() = xoff2 - d + xo1;
}
2012-05-26 14:26:10 +02:00
}
idx += nstaves;
}
}
//---------------------------------------------------------
// layout2
// called after measure layout
// adjusts staff distance
//---------------------------------------------------------
void System::layout2()
{
if (isVbox()) // ignore vbox
return;
int nstaves = _staves.size();
2012-05-26 14:26:10 +02:00
qreal _spatium = spatium();
qreal y = 0.0;
int lastStaffIdx = 0; // last visible staff
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
Staff* staff = score()->staff(staffIdx);
StyleIdx downDistance;
qreal userDist = 0.0;
if ((staffIdx + 1) == nstaves) {
//
// last staff in system
//
MeasureBase* mb = ml.last();
bool nextMeasureIsVBOX = false;
if (mb->next()) {
int type = mb->next()->type();
if (type == VBOX || type == TBOX || type == FBOX)
nextMeasureIsVBOX = true;
}
downDistance = nextMeasureIsVBOX ? ST_systemFrameDistance : ST_minSystemDistance;
}
else if (staff->rstaff() < (staff->part()->staves()->size()-1)) {
//
// staff is not last staff in a part
//
downDistance = ST_akkoladeDistance;
userDist = score()->staff(staffIdx + 1)->userDist();
}
else {
downDistance = ST_staffDistance;
userDist = score()->staff(staffIdx + 1)->userDist();
}
SysStaff* s = _staves[staffIdx];
qreal distDown = score()->styleS(downDistance).val() * _spatium + userDist;
qreal distUp = 0.0;
foreach(MeasureBase* m, ml) {
distDown = qMax(distDown, m->distanceDown(staffIdx));
distDown = qMax(distDown, m->userDistanceDown(staffIdx));
distUp = qMax(distUp, m->distanceUp(staffIdx));
distUp = qMax(distUp, m->userDistanceUp(staffIdx));
}
s->setDistanceDown(distDown);
s->setDistanceUp(distUp);
if (!staff->show() || !s->show()) {
2012-05-26 14:26:10 +02:00
s->setbbox(QRectF()); // already done in layout() ?
continue;
}
qreal sHeight = staff->height(); // (staff->lines() - 1) * _spatium * staffMag;
2012-11-08 12:59:30 +01:00
qreal dup = staffIdx == 0 ? 0.0 : s->distanceUp();
s->setbbox(QRectF(_leftMargin, y + dup, width() - _leftMargin, sHeight));
y += dup + sHeight + s->distanceDown();
2012-05-26 14:26:10 +02:00
lastStaffIdx = staffIdx;
}
2012-05-26 14:26:10 +02:00
qreal systemHeight = staff(lastStaffIdx)->bbox().bottom();
setHeight(systemHeight);
foreach(MeasureBase* m, ml) {
if (m->type() == MEASURE) {
m->setbbox(QRectF(0.0, -_spatium, m->width(), systemHeight + 2 * _spatium));
}
else if (m->type() == HBOX) {
m->setbbox(QRectF(0.0, 0.0, m->width(), systemHeight));
static_cast<HBox*>(m)->layout2();
}
}
2012-10-17 20:22:24 +02:00
if (_barLine) {
_barLine->setSpan(lastStaffIdx + 1);
_barLine->setSpanTo( (score()->staff(lastStaffIdx)->lines()-1)*2 );
2012-10-17 20:22:24 +02:00
_barLine->layout();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------
// layout brackets vertical position
//---------------------------------------------------
2012-10-12 15:36:57 +02:00
foreach (Bracket* b, _brackets) {
qreal sy = _staves[b->firstStaff()]->bbox().top();
qreal ey = _staves[b->lastStaff()]->bbox().bottom();
2012-10-17 18:53:26 +02:00
b->rypos() = sy;
b->setHeight(ey - sy);
2012-10-12 15:36:57 +02:00
b->layout();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------
// layout instrument names
//---------------------------------------------------
int staffIdx = 0;
foreach(Part* p, score()->parts()) {
SysStaff* s = staff(staffIdx);
int nstaves = p->nstaves();
foreach (InstrumentName* t, s->instrumentNames) {
2012-05-26 14:26:10 +02:00
//
// override Text->layout()
//
qreal y1, y2;
switch(t->layoutPos()) {
default:
case 0: // center at part
y1 = s->bbox().top();
y2 = staff(staffIdx + nstaves - 1)->bbox().bottom();
break;
case 1: // center at first staff
y1 = s->bbox().top();
y2 = s->bbox().bottom();
break;
case 2: // center between first and second staff
y1 = s->bbox().top();
y2 = staff(staffIdx + 1)->bbox().bottom();
break;
case 3: // center at second staff
y1 = staff(staffIdx + 1)->bbox().top();
y2 = staff(staffIdx + 1)->bbox().bottom();
break;
case 4: // center between first and second staff
y1 = staff(staffIdx + 1)->bbox().top();
y2 = staff(staffIdx + 2)->bbox().bottom();
break;
case 5: // center at third staff
y1 = staff(staffIdx + 2)->bbox().top();
y2 = staff(staffIdx + 2)->bbox().bottom();
break;
}
qreal y = y1 + (y2 - y1) * .5 - t->bbox().height() * .5;
t->rypos() = y;
}
staffIdx += nstaves;
}
}
//---------------------------------------------------------
/// clear
/// Clear layout of System
//---------------------------------------------------------
void System::clear()
{
ml.clear();
_spannerSegments.clear();
_vbox = false;
_firstSystem = false;
_pageBreak = false;
}
//---------------------------------------------------------
// setInstrumentNames
//---------------------------------------------------------
void System::setInstrumentNames(bool longName)
{
if (isVbox()) // ignore vbox
return;
2012-09-22 11:59:33 +02:00
if (!score()->showInstrumentNames()) {
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
SysStaff* staff = _staves[staffIdx];
foreach(InstrumentName* t, staff->instrumentNames)
score()->undoRemoveElement(t);
}
return;
}
2012-05-26 14:26:10 +02:00
int tick = ml.isEmpty() ? 0 : ml.front()->tick();
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
SysStaff* staff = _staves[staffIdx];
Staff* s = score()->staff(staffIdx);
if (!s->isTop()) {
foreach(InstrumentName* t, staff->instrumentNames)
score()->undoRemoveElement(t);
continue;
}
Part* part = s->part();
const QList<StaffNameDoc>& names = longName? part->longNames(tick) : part->shortNames(tick);
int idx = 0;
foreach(const StaffNameDoc& sn, names) {
2012-05-26 14:26:10 +02:00
InstrumentName* iname = staff->instrumentNames.value(idx);
if (iname == 0) {
iname = new InstrumentName(score());
iname->setGenerated(true);
iname->setParent(this);
iname->setTrack(staffIdx * VOICES);
iname->setSubtype(longName ? INSTRUMENT_NAME_LONG : INSTRUMENT_NAME_SHORT);
2012-05-26 14:26:10 +02:00
score()->undoAddElement(iname);
}
iname->setText(sn.name);
iname->setLayoutPos(sn.pos);
++idx;
}
for (; idx < staff->instrumentNames.size(); ++idx)
score()->undoRemoveElement(staff->instrumentNames[idx]);
}
}
//---------------------------------------------------------
// y2staff
//---------------------------------------------------------
/**
Return staff number for canvas relative y position \a y
or -1 if not found.
To allow drag and drop above and below the staff, the actual y range
considered "inside" the staff is increased a bit.
TODO: replace magic number "0.6" by something more appropriate.
*/
int System::y2staff(qreal y) const
{
y -= pos().y();
int idx = 0;
foreach(SysStaff* s, _staves) {
qreal t = s->bbox().top();
qreal b = s->bbox().bottom();
qreal y1 = t - 0.6 * (b - t);
qreal y2 = b + 0.6 * (b - t);
if (y >= y1 && y < y2)
return idx;
++idx;
}
return -1;
}
//---------------------------------------------------------
// add
//---------------------------------------------------------
void System::add(Element* el)
{
2012-10-12 15:36:57 +02:00
// qDebug("System::add: %s", el->name());
2012-05-26 14:26:10 +02:00
el->setParent(this);
switch(el->type()) {
case INSTRUMENT_NAME:
_staves[el->staffIdx()]->instrumentNames.append(static_cast<InstrumentName*>(el));
break;
case BEAM:
score()->add(el);
break;
2012-10-12 15:36:57 +02:00
2012-05-26 14:26:10 +02:00
case BRACKET:
{
Bracket* b = static_cast<Bracket*>(el);
2012-10-12 15:36:57 +02:00
int staffIdx = b->staffIdx();
2012-05-26 14:26:10 +02:00
int level = b->level();
if (level == -1) {
2012-10-12 15:36:57 +02:00
level = 0;
foreach(Bracket* bb, _brackets) {
if (staffIdx >= bb->firstStaff() && staffIdx <= bb->lastStaff())
++level;
2012-05-26 14:26:10 +02:00
}
b->setLevel(level);
b->setSpan(1);
2012-05-26 14:26:10 +02:00
}
2012-10-12 15:36:57 +02:00
b->staff()->setBracket(level, b->subtype());
2012-05-26 14:26:10 +02:00
b->staff()->setBracketSpan(level, b->span());
2012-10-12 15:36:57 +02:00
_brackets.append(b);
2012-05-26 14:26:10 +02:00
}
break;
2012-10-12 15:36:57 +02:00
2012-05-26 14:26:10 +02:00
case MEASURE:
case HBOX:
case VBOX:
case TBOX:
case FBOX:
score()->add(static_cast<MeasureBase*>(el));
break;
case TEXTLINE_SEGMENT:
case HAIRPIN_SEGMENT:
case OTTAVA_SEGMENT:
case TRILL_SEGMENT:
case VOLTA_SEGMENT:
case SLUR_SEGMENT:
2012-11-07 16:47:42 +01:00
case PEDAL_SEGMENT:
2012-05-26 14:26:10 +02:00
{
2012-10-12 15:36:57 +02:00
// qDebug("System::add: %p %s spanner %p %s", el, el->name(),
2012-05-26 14:26:10 +02:00
// ((SpannerSegment*)el)->spanner(), ((SpannerSegment*)el)->spanner()->name());
SpannerSegment* ss = static_cast<SpannerSegment*>(el);
if (!_spannerSegments.contains(ss))
_spannerSegments.append(ss);
else {
2012-10-12 15:36:57 +02:00
// qDebug("System::add() spanner already there");
2012-05-26 14:26:10 +02:00
}
}
break;
2012-10-17 20:22:24 +02:00
case BAR_LINE:
_barLine = static_cast<BarLine*>(el);
break;
2012-05-26 14:26:10 +02:00
default:
2012-10-12 15:36:57 +02:00
qDebug("System::add(%s) not implemented", el->name());
2012-05-26 14:26:10 +02:00
break;
}
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void System::remove(Element* el)
{
2012-10-12 15:36:57 +02:00
// qDebug("System::remove: %s", el->name());
2012-05-26 14:26:10 +02:00
switch (el->type()) {
case INSTRUMENT_NAME:
_staves[el->staffIdx()]->instrumentNames.removeOne(static_cast<InstrumentName*>(el));
break;
case BEAM:
score()->remove(el);
break;
case BRACKET:
{
2012-10-12 15:36:57 +02:00
Bracket* b = static_cast<Bracket*>(el);
if (!_brackets.removeOne(b))
qDebug("System::remove: bracket not found");
b->staff()->setBracket(b->level(), NO_BRACKET);
2012-05-26 14:26:10 +02:00
}
break;
case MEASURE:
case HBOX:
case VBOX:
case TBOX:
case FBOX:
score()->remove(el);
break;
case TEXTLINE_SEGMENT:
case HAIRPIN_SEGMENT:
case OTTAVA_SEGMENT:
case TRILL_SEGMENT:
case VOLTA_SEGMENT:
case SLUR_SEGMENT:
2012-11-07 16:47:42 +01:00
case PEDAL_SEGMENT:
2012-10-12 15:36:57 +02:00
// qDebug("System::remove: %p %s spanner %p %s", el, el->name(),
2012-05-26 14:26:10 +02:00
// ((SpannerSegment*)el)->spanner(), ((SpannerSegment*)el)->spanner()->name());
if (!_spannerSegments.removeOne(static_cast<SpannerSegment*>(el))) {
2012-10-12 15:36:57 +02:00
// qDebug("System::remove: %p(%s) not found, score %p == %p", el, el->name(), score(), el->score());
2012-05-26 14:26:10 +02:00
Q_ASSERT(score() == el->score());
}
break;
2012-10-17 20:22:24 +02:00
case BAR_LINE:
_barLine = 0;
break;
2012-05-26 14:26:10 +02:00
default:
2012-10-12 15:36:57 +02:00
qDebug("System::remove(%s) not implemented", el->name());
2012-05-26 14:26:10 +02:00
break;
}
}
//---------------------------------------------------------
// change
//---------------------------------------------------------
void System::change(Element* o, Element* n)
{
if (o->type() == VBOX || o->type() == HBOX || o->type() == TBOX || o->type() == FBOX) {
int idx = ml.indexOf((MeasureBase*)o);
if (idx != -1)
ml.removeAt(idx);
ml.insert(idx, (MeasureBase*)n);
score()->measures()->change((MeasureBase*)o, (MeasureBase*)n);
}
else {
remove(o);
add(n);
}
}
//---------------------------------------------------------
// snap
//---------------------------------------------------------
int System::snap(int tick, const QPointF p) const
{
foreach(const MeasureBase* m, ml) {
if (p.x() < m->x() + m->width())
return ((Measure*)m)->snap(tick, p - m->pos()); //TODO: MeasureBase
}
return ((Measure*)ml.back())->snap(tick, p-pos()); //TODO: MeasureBase
}
//---------------------------------------------------------
// snap
//---------------------------------------------------------
int System::snapNote(int tick, const QPointF p, int staff) const
{
foreach(const MeasureBase* m, ml) {
if (p.x() < m->x() + m->width())
return ((Measure*)m)->snapNote(tick, p - m->pos(), staff); //TODO: MeasureBase
}
return ((Measure*)ml.back())->snap(tick, p-pos()); // TODO: MeasureBase
}
//---------------------------------------------------------
// firstMeasure
//---------------------------------------------------------
Measure* System::firstMeasure() const
{
if (ml.isEmpty())
return 0;
for (MeasureBase* mb = ml.front(); mb; mb = mb->next()) {
if (mb->type() != MEASURE)
continue;
return static_cast<Measure*>(mb);
}
return 0;
}
//---------------------------------------------------------
// lastMeasure
//---------------------------------------------------------
Measure* System::lastMeasure() const
{
if (ml.isEmpty())
return 0;
for (MeasureBase* mb = ml.back(); mb; mb = mb->prev()) {
if (mb->type() != MEASURE)
continue;
return static_cast<Measure*>(mb);
}
return 0;
}
//---------------------------------------------------------
// prevMeasure
//---------------------------------------------------------
MeasureBase* System::prevMeasure(const MeasureBase* m) const
{
if (m == ml.front())
return 0;
return m->prev();
}
//---------------------------------------------------------
// nextMeasure
//---------------------------------------------------------
MeasureBase* System::nextMeasure(const MeasureBase* m) const
{
if (m == ml.back())
return 0;
return m->next();
}
//---------------------------------------------------------
// searchNextLyrics
//---------------------------------------------------------
static Lyrics* searchNextLyrics(Segment* s, int staffIdx, int verse)
{
Lyrics* l = 0;
while ((s = s->next1(Segment::SegChordRest | Segment::SegGrace))) {
2012-05-26 14:26:10 +02:00
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
QList<Lyrics*>* nll = 0;
for (int track = strack; track < etrack; ++track) {
ChordRest* cr = static_cast<ChordRest*>(s->element(track));
if (cr && !cr->lyricsList().isEmpty()) {
nll = &cr->lyricsList();
break;
}
}
if (!nll)
continue;
l = nll->value(verse);
if (l)
break;
}
return l;
}
//---------------------------------------------------------
// layoutLyrics
// layout lyrics separator
//---------------------------------------------------------
void System::layoutLyrics(Lyrics* l, Segment* s, int staffIdx)
{
if ((l->syllabic() == Lyrics::SINGLE || l->syllabic() == Lyrics::END) && (l->ticks() == 0)) {
l->clearSeparator();
return;
}
qreal _spatium = spatium();
const TextStyle& ts = l->textStyle();
qreal lmag = qreal(ts.size()) / 11.0;
if (l->ticks()) {
// melisma
Segment* seg = score()->tick2segment(l->endTick());
if (seg == 0) {
2012-10-12 15:36:57 +02:00
qDebug("System::layoutLyrics: no segment found for tick %d", l->endTick());
2012-05-26 14:26:10 +02:00
return;
}
QList<Line*>* sl = l->separatorList();
QList<System*>* systems = score()->systems();
System* s1 = this;
System* s2 = seg->measure()->system();
int sysIdx1 = systems->indexOf(s1);
int sysIdx2 = systems->indexOf(s2);
qreal x1 = l->bbox().right(); // lyrics width
QPointF p1(x1, 0); // melisma y is at base line
2012-05-26 14:26:10 +02:00
int segIdx = 0;
for (int i = sysIdx1; i <= sysIdx2; ++i, ++segIdx) {
System* system = (*systems)[i];
Line* line = sl->value(segIdx);
if (line == 0) {
line = new Line(l->score(), false);
l->add(line);
}
line->setLineWidth(Spatium(0.1 * lmag));
line->setPos(p1);
if (sysIdx1 == sysIdx2) {
// single segment
qreal headWidth = symbols[0][quartheadSym].width(1.0);
qreal len = seg->pagePos().x() - l->pagePos().x() - x1 + headWidth;
line->setLen(Spatium(len / _spatium));
Lyrics* nl = searchNextLyrics(seg, staffIdx, l->no());
// small correction if next lyrics is moved? not needed if on another system
if (nl && nl->measure()->system() == s1) {
qreal x2 = nl->bbox().left() + nl->pagePos().x();
qreal lx2 = line->pagePos().x() + len;
2012-09-03 21:15:38 +02:00
// printf("line %f text %f\n", lx2, x2);
2012-05-26 14:26:10 +02:00
if (lx2 > x2)
len -= (lx2 - x2);
}
line->setLen(Spatium(len / _spatium));
}
else if (i == sysIdx1) {
// start segment
qreal w = system->staff(l->staffIdx())->right();
qreal x = system->pagePos().x() + w;
qreal len = x - l->pagePos().x() - x1;
line->setLen(Spatium(len / _spatium));
}
else if (i > 0 && i != sysIdx2) {
qDebug("Lyrics: melisma middle segment not implemented");
// middle segment
}
else if (i == sysIdx2) {
// end segment
qDebug("Lyrics: melisma end segment not implemented");
}
line->layout();
}
return;
}
//
// we have to layout a separator to the next
// Lyric syllable
//
int verse = l->no();
Segment* ns = s;
// TODO: the next two values should be style parameters
// TODO: as well as the 0.3 factor a few lines below
2012-05-26 14:26:10 +02:00
const qreal maxl = 0.5 * _spatium * lmag; // lyrics hyphen length
const Spatium hlw(0.14 * lmag); // hyphen line width
Lyrics* nl = searchNextLyrics(ns, staffIdx, verse);
if (!nl) {
l->clearSeparator();
return;
}
QList<Line*>* sl = l->separatorList();
Line* line;
if (sl->isEmpty()) {
line = new Line(l->score(), false);
l->add(line);
}
else {
line = (*sl)[0];
}
qreal x = l->bbox().right();
// convert font size to raster units, scaling if spatium-dependent
qreal size = ts.size();
if(ts.sizeIsSpatiumDependent())
size *= _spatium / (SPATIUM20 * PPI); // <= (MScore::DPI / PPI) * (_spatium / (SPATIUM20 * Mscore::DPI))
else
size *= MScore::DPI / PPI;
qreal y = -size * 0.3; // a conventional percentage of the whole font height
2012-05-26 14:26:10 +02:00
qreal x1 = x + l->pagePos().x();
qreal x2 = nl->bbox().left() + nl->pagePos().x();
qreal len;
if (x2 < x1 || s->measure()->system()->page() != ns->measure()->system()->page()) {
System* system = s->measure()->system();
x2 = system->pagePos().x() + system->bbox().width();
}
qreal gap = x2 - x1;
len = gap;
if (len > maxl)
len = maxl;
qreal xo = (gap - len) * .5;
line->setLineWidth(hlw);
line->setPos(QPointF(x + xo, y));
line->setLen(Spatium(len / _spatium));
line->layout();
}
//---------------------------------------------------------
// scanElements
// collect all visible elements
//---------------------------------------------------------
void System::scanElements(void* data, void (*func)(void*, Element*), bool all)
2012-05-26 14:26:10 +02:00
{
if (isVbox())
return;
2012-10-17 20:22:24 +02:00
if (_barLine)
func(data, _barLine);
2012-10-12 15:36:57 +02:00
foreach(Bracket* b, _brackets)
func(data, b);
int idx = 0;
2012-05-26 14:26:10 +02:00
foreach (SysStaff* st, _staves) {
if (!all && !(st->show() && score()->staff(idx)->show())) {
++idx;
2012-05-26 14:26:10 +02:00
continue;
}
foreach (InstrumentName* t, st->instrumentNames)
2012-05-26 14:26:10 +02:00
func(data, t);
++idx;
2012-05-26 14:26:10 +02:00
}
foreach(SpannerSegment* ss, _spannerSegments) {
int staffIdx;
if (ss->spanner()->type() == SLUR)
staffIdx = ss->spanner()->startElement()->staffIdx();
else
staffIdx = ss->spanner()->staffIdx();
if (all || score()->staff(staffIdx)->show())
func(data, ss);
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// staffY
//---------------------------------------------------------
qreal System::staffY(int staffIdx) const
{
if (_staves.size() <= staffIdx) {
2012-10-12 15:36:57 +02:00
qDebug("staffY: staves %d <= staff %d, vbox %d",
2012-05-26 14:26:10 +02:00
_staves.size(), staffIdx, _vbox);
return pagePos().y();
}
2012-10-26 20:44:13 +02:00
return _staves[staffIdx]->y() + y(); // pagePos().y();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void System::write(Xml& xml) const
{
xml.stag("System");
2012-10-17 20:22:24 +02:00
if (_barLine && !_barLine->generated())
_barLine->write(xml);
2012-05-26 14:26:10 +02:00
xml.etag();
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void System::read(const QDomElement& de)
{
for (QDomElement e = de.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
const QString& tag(e.tagName());
2012-10-17 20:22:24 +02:00
if (tag == "BarLine") {
_barLine = new BarLine(score());
_barLine->read(e);
_barLine->setTrack(0);
_barLine->setParent(this);
2012-05-26 14:26:10 +02:00
}
else
domError(e);
}
}