void ScoreView::lyricsEndEdit() { Lyrics* lyrics = (Lyrics*)editObject; int endTick = lyrics->segment()->tick(); // search previous lyric: int verse = lyrics->no(); int staffIdx = lyrics->staffIdx(); // search previous lyric Lyrics* oldLyrics = 0; Segment* segment = lyrics->segment(); while (segment) { const QList<Lyrics*>* nll = segment->lyricsList(staffIdx); if (nll) { oldLyrics = nll->value(verse); if (oldLyrics) break; } segment = segment->prev1(Segment::SegChordRest | Segment::SegGrace); } // if (lyrics->isEmpty() && origL->isEmpty()) if (lyrics->isEmpty()) lyrics->parent()->remove(lyrics); else { if (oldLyrics && oldLyrics->syllabic() == Lyrics::END) { if (oldLyrics->endTick() >= endTick) oldLyrics->setTicks(0); } } }
void LyricsLineSegment::layout() { bool endOfSystem = false; bool isEndMelisma = lyricsLine()->lyrics()->ticks() > 0; Lyrics* lyr = 0; Lyrics* nextLyr = 0; qreal fromX = 0; qreal toX = 0; // start and end point of intra-lyrics room qreal sp = spatium(); System* sys; if (lyricsLine()->ticks() <= 0) { // if no span, _numOfDashes = 0; // nothing to draw return; // and do nothing } // HORIZONTAL POSITION // A) if line precedes a syllable, advance line end to right before the next syllable text // if not a melisma and there is a next syllable; if (!isEndMelisma && lyricsLine()->nextLyrics() && isSingleEndType()) { lyr = nextLyr = lyricsLine()->nextLyrics(); sys = lyr->segment()->system(); endOfSystem = (sys != system()); // if next lyrics is on a different system, this line segment is at the end of its system: // do not adjust for next lyrics position if (!endOfSystem) { qreal lyrX = lyr->bbox().x(); qreal lyrXp = lyr->pagePos().x(); qreal sysXp = sys->pagePos().x(); toX = lyrXp - sysXp + lyrX; // syst.rel. X pos. qreal offsetX = toX - pos().x() - pos2().x() - score()->styleP(Sid::lyricsDashPad); // delta from current end pos.| ending padding rxpos2() += offsetX; } } // B) if line follows a syllable, advance line start to after the syllable text lyr = lyricsLine()->lyrics(); sys = lyr->segment()->system(); if (sys && isSingleBeginType()) { qreal lyrX = lyr->bbox().x(); qreal lyrXp = lyr->pagePos().x(); qreal lyrW = lyr->bbox().width(); qreal sysXp = sys->pagePos().x(); fromX = lyrXp - sysXp + lyrX + lyrW; // syst.rel. X pos. | lyr.advance qreal offsetX = fromX - pos().x(); offsetX += score()->styleP(isEndMelisma ? Sid::lyricsMelismaPad : Sid::lyricsDashPad); // delta from curr.pos. | add initial padding rxpos() += offsetX; rxpos2() -= offsetX; } // VERTICAL POSITION: at the base line of the syllable text if (!isEndType()) rypos() = lyr->ipos().y(); else { // use Y position of *next* syllable if there is one on same system Lyrics* nextLyr = searchNextLyrics(lyr->segment(), lyr->staffIdx(), lyr->no(), lyr->placement()); if (nextLyr && nextLyr->segment()->system() == system()) rypos() = nextLyr->y(); else rypos() = lyr->y(); } // MELISMA vs. DASHES if (isEndMelisma) { // melisma _numOfDashes = 1; rypos() -= lyricsLine()->lineWidth() * .5; // let the line 'sit on' the base line qreal offsetX = score()->styleP(Sid::minNoteDistance) * mag(); // if final segment, extend slightly after the chord, otherwise shorten it rxpos2() += (isBeginType() || isEndType()) ? -offsetX : +offsetX; } else { // dash(es) // set conventional dash Y pos rypos() -= MScore::pixelRatio * lyr->fontMetrics().xHeight() * score()->styleD(Sid::lyricsDashYposRatio); _dashLength = score()->styleP(Sid::lyricsDashMaxLength) * mag(); // and dash length qreal len = pos2().x(); qreal minDashLen = score()->styleS(Sid::lyricsDashMinLength).val() * sp; qreal maxDashDist = score()->styleS(Sid::lyricsDashMaxDistance).val() * sp; if (len < minDashLen) { // if no room for a dash // if at end of system or dash is forced if (endOfSystem || score()->styleB(Sid::lyricsDashForce)) { rxpos2() = minDashLen; // draw minimal dash _numOfDashes = 1; _dashLength = minDashLen; } else // if within system or dash not forced _numOfDashes = 0; // draw no dash } else if (len < (maxDashDist * 2.0)) { // if no room for two dashes _numOfDashes = 1; // draw one dash if (_dashLength > len) // if no room for a full dash _dashLength = len; // shorten it } else _numOfDashes = len / (maxDashDist); // draw several dashes // adjust next lyrics horiz. position if too little a space forced to skip the dash if (_numOfDashes == 0 && nextLyr != nullptr && len > 0) nextLyr->rxpos() -= (toX - fromX); } // set bounding box QRectF r = QRectF(0.0, 0.0, pos2().x(), pos2().y()).normalized(); qreal lw = lyricsLine()->lineWidth() * .5; setbbox(r.adjusted(-lw, -lw, lw, lw)); }
void ScoreView::lyricsTab(bool back, bool end, bool moveOnly) { Lyrics* lyrics = (Lyrics*)editObject; int track = lyrics->track(); int staffIdx = lyrics->staffIdx(); Segment* segment = lyrics->segment(); int verse = lyrics->no(); Segment* nextSegment = segment; if (back) { // search prev chord while ((nextSegment = nextSegment->prev1(Segment::SegChordRest | Segment::SegGrace))) { Element* el = nextSegment->element(track); if (el && el->type() == Element::CHORD) break; } } else { // search next chord while ((nextSegment = nextSegment->next1(Segment::SegChordRest | Segment::SegGrace))) { Element* el = nextSegment->element(track); if (el && el->type() == Element::CHORD) break; } } if (nextSegment == 0) return; endEdit(); // search previous lyric Lyrics* oldLyrics = 0; if (!back) { while (segment) { const QList<Lyrics*>* nll = segment->lyricsList(staffIdx); if (nll) { oldLyrics = nll->value(verse); if (oldLyrics) break; } segment = segment->prev1(Segment::SegChordRest | Segment::SegGrace); } } const QList<Lyrics*>* ll = nextSegment->lyricsList(staffIdx); if (ll == 0) { qDebug("no next lyrics list: %s", nextSegment->element(track)->name()); return; } lyrics = ll->value(verse); bool newLyrics = false; if (!lyrics) { lyrics = new Lyrics(_score); lyrics->setTrack(track); ChordRest* cr = static_cast<ChordRest*>(nextSegment->element(track)); lyrics->setParent(cr); lyrics->setNo(verse); lyrics->setSyllabic(Lyrics::SINGLE); newLyrics = true; } _score->startCmd(); if (oldLyrics && !moveOnly) { switch(lyrics->syllabic()) { case Lyrics::SINGLE: case Lyrics::BEGIN: break; case Lyrics::END: lyrics->setSyllabic(Lyrics::SINGLE); break; case Lyrics::MIDDLE: lyrics->setSyllabic(Lyrics::BEGIN); break; } switch(oldLyrics->syllabic()) { case Lyrics::SINGLE: case Lyrics::END: break; case Lyrics::BEGIN: oldLyrics->setSyllabic(Lyrics::SINGLE); break; case Lyrics::MIDDLE: oldLyrics->setSyllabic(Lyrics::END); break; } } if (newLyrics) _score->undoAddElement(lyrics); _score->select(lyrics, SELECT_SINGLE, 0); startEdit(lyrics, -1); mscore->changeState(mscoreState()); adjustCanvasPosition(lyrics, false); if (end) ((Lyrics*)editObject)->moveCursorToEnd(); else ((Lyrics*)editObject)->moveCursorToStart(); _score->setLayoutAll(true); _score->end2(); _score->end1(); }
void ScoreView::lyricsUnderscore() { Lyrics* lyrics = static_cast<Lyrics*>(editObject); int track = lyrics->track(); int staffIdx = lyrics->staffIdx(); Segment* segment = lyrics->segment(); int verse = lyrics->no(); int endTick = segment->tick(); endEdit(); // search next chord Segment* nextSegment = segment; while ((nextSegment = nextSegment->next1(Segment::SegChordRest | Segment::SegGrace))) { Element* el = nextSegment->element(track); if (el && el->type() == Element::CHORD) break; } // search previous lyric Lyrics* oldLyrics = 0; while (segment) { const QList<Lyrics*>* nll = segment->lyricsList(staffIdx); if (nll) { oldLyrics = nll->value(verse); if (oldLyrics) break; } segment = segment->prev1(Segment::SegChordRest | Segment::SegGrace); } if (nextSegment == 0) { if (oldLyrics) { switch(oldLyrics->syllabic()) { case Lyrics::SINGLE: case Lyrics::END: break; default: oldLyrics->setSyllabic(Lyrics::END); break; } if (oldLyrics->segment()->tick() < endTick) oldLyrics->setTicks(endTick - oldLyrics->segment()->tick()); } return; } _score->startCmd(); const QList<Lyrics*>* ll = nextSegment->lyricsList(staffIdx); lyrics = ll->value(verse); bool newLyrics = (lyrics == 0); if (!lyrics) { lyrics = new Lyrics(_score); lyrics->setTrack(track); lyrics->setParent(nextSegment->element(track)); lyrics->setNo(verse); } lyrics->setSyllabic(Lyrics::SINGLE); if (oldLyrics) { switch(oldLyrics->syllabic()) { case Lyrics::SINGLE: case Lyrics::END: break; default: oldLyrics->setSyllabic(Lyrics::END); break; } if (oldLyrics->segment()->tick() < endTick) oldLyrics->setTicks(endTick - oldLyrics->segment()->tick()); } if (newLyrics) _score->undoAddElement(lyrics); _score->select(lyrics, SELECT_SINGLE, 0); startEdit(lyrics, -1); mscore->changeState(mscoreState()); adjustCanvasPosition(lyrics, false); ((Lyrics*)editObject)->moveCursorToEnd(); _score->setLayoutAll(true); _score->end2(); _score->end1(); }