void Lyrics::layout() { // setPos(_textStyle.offset(spatium())); layout1(); QPointF rp(readPos()); if (!rp.isNull()) { if (score()->mscVersion() <= 114) { rp.ry() += lineSpacing() + 2; rp.rx() += bbox().width() * .5; } setUserOff(rp - ipos()); setReadPos(QPointF()); } }
void RehearsalMark::layout() { if (autoplace()) setUserOff(QPointF()); qreal y; if (placeAbove()) y = score()->styleP(StyleIdx::rehearsalMarkPosAbove); else { qreal sh = staff() ? staff()->height() : 0; y = score()->styleP(StyleIdx::rehearsalMarkPosBelow) + sh + lineSpacing(); } setPos(QPointF(0.0, y)); Text::layout1(); Segment* s = segment(); if (s) { if (!s->rtick()) { // first CR of measure, decide whether to align to barline if (!s->prev() && align() & Align::CENTER) { // measure with no clef / keysig / timesig rxpos() -= s->x(); } else if (align() & Align::RIGHT) { // measure with clef / keysig / timesig, rehearsal mark right aligned // align left edge of rehearsal to barline if that is further to left qreal leftX = bbox().x(); qreal barlineX = -s->x(); rxpos() += qMin(leftX, barlineX) + width(); } } if (autoplace()) { int firstStaffIdx = s->measure()->system()->firstVisibleStaff(); qreal minDistance = score()->styleP(StyleIdx::rehearsalMarkMinDistance); Shape s1 = s->measure()->staffShape(firstStaffIdx); Shape s2 = shape().translated(s->pos() + pos()); if (placeAbove()) { qreal d = s2.minVerticalDistance(s1); if (d > -minDistance) rUserYoffset() = -d - minDistance; } else { qreal d = s1.minVerticalDistance(s2); if (d > -minDistance) rUserYoffset() = d + minDistance; } } } }
void FiguredBass::layout() { if (!styled()) setTextStyle(TEXT_STYLE_FIGURED_BASS); Lyrics::layout(); qreal lh = lineSpacing() * score()->styleD(ST_figuredBassLineHeight); System* sys = measure()->system(); if (sys == 0) { qDebug("lyrics layout: no system!"); abort(); } const QList<Lyrics*>* ll = &(chordRest()->lyricsList()); int line = ll->indexOf(this); qreal y = lh * line + point(score()->styleS(ST_figuredBassDistance)) + sys->staff(staffIdx())->bbox().height(); QString s = getText(); qreal x = symbols[score()->symIdx()][quartheadSym].width(magS()) * .5; QFontMetricsF fm(style().font(spatium())); for (int i = 0; i < s.size(); ++i) { if (s[i].isNumber()) { if (i) x += -fm.width(s.left(i)); int startIdx = i; for (; i < s.size(); ++i) { if (!s[i].isNumber()) break; } x += -(fm.width(s.mid(startIdx, i - startIdx)) * .5); break; } } x -= spatium() * .25; // DEBUG setPos(x, y); }
void Lyrics::layout1() { setPos(textStyle().offset(spatium())); Text::layout1(); if (!parent()) // palette & clone trick return; ChordRest* cr = chordRest(); const QList<Lyrics*>* ll = &(cr->lyricsList()); qreal lh = lineSpacing() * score()->styleD(StyleIdx::lyricsLineHeight); int line = ll->indexOf(this); qreal y = lh * line + point(score()->styleS(StyleIdx::lyricsDistance)); qreal x = 0.0; // // parse leading verse number and/or punctuation, so we can factor it into layout separately // TODO: provide a way to disable this // bool hasNumber = false; // _verseNumber; qreal adjust = 0.0; QString s = plainText(true); // find: // 1) string of numbers and non-word characters at start of syllable // 2) at least one other character (indicating start of actual lyric) QRegularExpression leadingPattern("(^[\\d\\W]+)([^\\d\\W]+)"); QRegularExpressionMatch leadingMatch = leadingPattern.match(s); if (leadingMatch.hasMatch()) { // leading string QString s1 = leadingMatch.captured(1); // actual lyric //QString s2 = leadingMatch.captured(2); Text leading(*this); leading.setPlainText(s1); leading.layout1(); adjust = leading.width(); if (!s1.isEmpty() && s1[0].isDigit()) hasNumber = true; } if (textStyle().align() & AlignmentFlags::HCENTER) { // // center under notehead, not origin // however, lyrics that are melismas or have verse numbers will be forced to left alignment // TODO: provide a way to disable the automatic left alignment // qreal maxWidth; if (cr->type() == Element::Type::CHORD) maxWidth = static_cast<Chord*>(cr)->maxHeadWidth(); else maxWidth = cr->width(); // TODO: exclude ledger line for multivoice rest? qreal nominalWidth = symWidth(SymId::noteheadBlack); if (!isMelisma() && !hasNumber) // center under notehead x += nominalWidth * .5 - cr->x() - adjust * 0.5; else // force left alignment x += (width() + nominalWidth - maxWidth) * .5 - cr->x() - adjust; } else { // even for left aligned syllables, ignore leading verse numbers and/or punctuation x -= adjust; } rxpos() += x; rypos() += y; if (_ticks > 0 || _syllabic == Syllabic::BEGIN || _syllabic == Syllabic::MIDDLE) { if (_separator == nullptr) { _separator = new LyricsLine(score()); _separator->setTick(cr->tick()); score()->addUnmanagedSpanner(_separator); } _separator->setParent(this); _separator->setTick(cr->tick()); _separator->setTrack(track()); _separator->setTrack2(track()); #if defined(USE_FONT_DASH_METRIC) // if font parameters different from font cached values, compute new dash values from font metrics if (textStyle().family() != g_fontFamily && textStyle().size() != g_fontSize) { QFontMetricsF fm = textStyle().fontMetrics(spatium()); QRectF r = fm.tightBoundingRect("\u2013"); // U+2013 EN DASH g_cachedDashY = _dashY = r.y() + (r.height() * HALF); g_cachedDashLength = _dashLength = r.width(); #if defined(USE_FONT_DASH_TICKNESS) g_cachedDashThickness = _dashThickness = r.height(); #endif g_fontFamily = textStyle().family(); g_fontSize = textStyle().size(); } // if same font, use cached values else { _dashY = g_cachedDashY; _dashLength = g_cachedDashLength; #if defined(USE_FONT_DASH_TICKNESS) _dashThickness = g_cachedDashThickness; #endif } #endif } else if (_separator != nullptr) { _separator->unchain(); delete _separator; _separator = nullptr; } }