bool Articulation::setProperty(P_ID propertyId, const QVariant& v) { score()->addRefresh(canvasBoundingRect()); switch (propertyId) { case P_DIRECTION: setDirection(MScore::Direction(v.toInt())); break; case P_ARTICULATION_ANCHOR: anchorStyle = PropertyStyle::UNSTYLED; setAnchor(ArticulationAnchor(v.toInt())); break; case P_TIME_STRETCH: setTimeStretch(v.toDouble()); score()->fixTicks(); break; default: return Element::setProperty(propertyId, v); } score()->addRefresh(canvasBoundingRect()); // layout: if (chordRest()) chordRest()->layoutArticulations(); else if (parent() && parent()->type() == BAR_LINE) static_cast<BarLine*>(parent())->layout(); score()->addRefresh(canvasBoundingRect()); score()->setLayoutAll(false); //DEBUG return true; }
void Articulation::reset() { if (_direction != MScore::AUTO) score()->undoChangeProperty(this, P_DIRECTION, int(MScore::AUTO)); ArticulationAnchor a = score()->style()->articulationAnchor(articulationType()); if (_anchor != a) score()->undoChangeProperty(this, P_ARTICULATION_ANCHOR, int(a)); Element::reset(); if (chordRest()) chordRest()->layoutArticulations(); score()->addRefresh(canvasBoundingRect()); }
bool Articulation::setProperty(P_ID propertyId, const QVariant& v) { score()->addRefresh(canvasBoundingRect()); switch (propertyId) { case P_ID::DIRECTION: setDirection(MScore::Direction(v.toInt())); break; case P_ID::ARTICULATION_ANCHOR: anchorStyle = PropertyStyle::UNSTYLED; setAnchor(ArticulationAnchor(v.toInt())); break; case P_ID::PLAY: setPlayArticulation(v.toBool()); break; case P_ID::ORNAMENT_STYLE: setOrnamentStyle(MScore::OrnamentStyle(v.toInt())); break; case P_ID::TIME_STRETCH: setTimeStretch(v.toDouble()); score()->fixTicks(); break; case P_ID::USER_OFF: setUserOff(v.toPointF()); if (_articulationType == ArticulationType::Tenuto) { // moving a tenuto may move slurs: score()->setLayoutAll(true); } return true; default: return Element::setProperty(propertyId, v); } // layout: if (chordRest()) chordRest()->layoutArticulations(); else if (parent() && parent()->type() == Element::Type::BAR_LINE) static_cast<BarLine*>(parent())->layout(); score()->addRefresh(canvasBoundingRect()); score()->setLayoutAll(false); // DEBUG canvasBoundingRectChanged(); // rebuild bsp tree return true; }
Segment* Articulation::segment() const { ChordRest* cr = chordRest(); if (!cr) return 0; Segment* s = 0; if (cr->isGrace()) { if (cr->parent()) s = toSegment(cr->parent()->parent()); } else s = toSegment(cr->parent()); return s; }
bool Lyrics::isMelisma() const { // entered as melisma using underscore? if (_ticks > 0) return true; // hyphenated? // if so, it is a melisma only if there is no lyric in same verse on next CR if (_syllabic == Syllabic::BEGIN || _syllabic == Syllabic::MIDDLE) { // find next CR on same track and check for existence of lyric in same verse ChordRest* cr = chordRest(); Segment* s = cr->segment()->next1(); ChordRest* ncr = s ? s->nextChordRest(cr->track()) : nullptr; if (ncr && !ncr->lyrics(_no)) return true; } // default - not a melisma return false; }
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); }
Segment* Articulation::segment() const { ChordRest* cr = chordRest(); return static_cast<Segment*>(cr ? cr->parent() : 0); }
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; } }