void Glissando::draw(QPainter* painter) const { painter->save(); qreal _spatium = spatium(); QPen pen(curColor()); pen.setWidthF(_spatium * .15); pen.setCapStyle(Qt::RoundCap); painter->setPen(pen); qreal w = line.dx(); qreal h = line.dy(); qreal l = sqrt(w * w + h * h); painter->translate(line.p1()); qreal wi = asin(-h / l) * 180.0 / M_PI; painter->rotate(-wi); if (glissandoType() == Type::STRAIGHT) { painter->drawLine(QLineF(0.0, 0.0, l, 0.0)); } else if (glissandoType() == Type::WAVY) { QRectF b = symBbox(SymId::wiggleTrill); qreal w = symWidth(SymId::wiggleTrill); int n = (int)(l / w); // always round down (truncate) to avoid overlap qreal x = (l - n*w) * 0.5; // centre line in available space drawSymbol(SymId::wiggleTrill, painter, QPointF(x, b.height()*.5), n); } if (_showText) { const TextStyle& st = score()->textStyle(TextStyleType::GLISSANDO); QFont f = st.fontPx(_spatium); QRectF r = QFontMetricsF(f).boundingRect(_text); // if text longer than available space, skip it if (r.width() < l) { qreal yOffset = r.height() + r.y(); // find text descender height // raise text slightly above line and slightly more with WAVY than with STRAIGHT yOffset += _spatium * (glissandoType() == Type::WAVY ? 0.75 : 0.05); painter->setFont(f); qreal x = (l - r.width()) * 0.5; painter->drawText(QPointF(x, -yOffset), _text); } } painter->restore(); }
void ShadowNote::draw(QPainter* painter) const { if (!visible() || sym == SymId::noSym) return; QPointF ap(pagePos()); #if 0 // yet(?) unused QRect r(abbox().toRect()); #endif painter->translate(ap); qreal lw = point(score()->styleS(StyleIdx::ledgerLineWidth)); InputState ps = score()->inputState(); int voice; if (ps.drumNote() != -1 && ps.drumset() && ps.drumset()->isValid(ps.drumNote())) voice = ps.drumset()->voice(ps.drumNote()); else voice = ps.voice(); QPen pen(MScore::selectColor[voice].lighter(140), lw); painter->setPen(pen); drawSymbol(sym, painter); qreal ms = spatium(); qreal x1 = symWidth(sym) * .5 - (ms * mag()); qreal x2 = x1 + 2 * ms * mag(); ms *= .5; if (_line < 100 && _line > -100 && !ps.rest()) { for (int i = -2; i >= _line; i -= 2) { qreal y = ms * mag() * (i - _line); painter->drawLine(QLineF(x1, y, x2, y)); } for (int i = 10; i <= _line; i += 2) { qreal y = ms * mag() * (i - _line); painter->drawLine(QLineF(x1, y, x2, y)); } } painter->translate(-ap); }
void ShadowNote::layout() { if (sym == SymId::noSym) { setbbox(QRectF()); return; } QRectF b(symBbox(sym)); qreal _spatium = spatium(); qreal lw = point(score()->styleS(StyleIdx::ledgerLineWidth)); qreal x1 = symWidth(sym) * .5 - (_spatium * mag()) - lw * .5; qreal x2 = x1 + 2 * _spatium * mag() + lw * .5; InputState ps = score()->inputState(); QRectF r(x1, -lw * .5, x2 - x1, lw); if (_line < 100 && _line > -100 && !ps.rest()) { for (int i = -2; i >= _line; i -= 2) b |= r.translated(QPointF(0, _spatium * .5 * (i - _line))); for (int i = 10; i <= _line; i += 2) b |= r.translated(QPointF(0, _spatium * .5 * (i - _line))); } setbbox(b); }
void BarLine::layout() { qreal y1, y2; getY(&y1, &y2); // if bar line does not belong to a system, has a staff and staff is set to hide bar lines, set null bbox if (parent() && parent()->type() != Element::Type::SYSTEM && staff() && !staff()->staffType()->showBarlines()) setbbox(QRectF()); // bar lines not hidden else { qreal dw = layoutWidth(score(), barLineType(), magS()); QRectF r(0.0, y1, dw, y2-y1); if (score()->styleB(StyleIdx::repeatBarTips)) { switch (barLineType()) { case BarLineType::START_REPEAT: r |= symBbox(SymId::bracketTop).translated(0, y1); r |= symBbox(SymId::bracketBottom).translated(0, y2); break; case BarLineType::END_REPEAT: { qreal w1 = symBbox(SymId::reversedBracketTop).width(); r |= symBbox(SymId::reversedBracketTop).translated(dw - w1, y1); r |= symBbox(SymId::reversedBracketBottom).translated(dw - w1, y2); break; } case BarLineType::END_START_REPEAT: { qreal lw = point(score()->styleS(StyleIdx::barWidth)); qreal lw2 = point(score()->styleS(StyleIdx::endBarWidth)); qreal d1 = point(score()->styleS(StyleIdx::endBarDistance)); qreal dotw = symWidth(SymId::repeatDot); qreal x = dotw + 2 * d1 + lw + lw2 * .5; // thick bar qreal w1 = symBbox(SymId::reversedBracketTop).width(); r |= symBbox(SymId::bracketTop).translated(x, y1); r |= symBbox(SymId::bracketBottom).translated(x, y2); r |= symBbox(SymId::reversedBracketTop).translated(x - w1 , y1); r |= symBbox(SymId::reversedBracketBottom).translated(x - w1, y2); } break; default: break; } } setbbox(r); } // in any case, lay out attached elements foreach(Element* e, _el) { e->layout(); if (e->type() == Element::Type::ARTICULATION) { Articulation* a = static_cast<Articulation*>(e); MScore::Direction dir = a->direction(); qreal distance = 0.5 * spatium(); qreal x = width() * .5; if (dir == MScore::Direction::DOWN) { qreal botY = y2 + distance; a->setPos(QPointF(x, botY)); } else { qreal topY = y1 - distance; a->setPos(QPointF(x, topY)); } } }
void BarLine::draw(QPainter* painter) const { // get line length and do nothing if 0 (or near enough) qreal y1, y2; getY(&y1, &y2); if (y2-y1 < 0.1) return; qreal _spatium = score()->spatium(); qreal lw = score()->styleS(StyleIdx::barWidth).val() * _spatium; QPen pen(curColor(), lw, Qt::SolidLine, Qt::FlatCap); painter->setPen(pen); switch(barLineType()) { case BarLineType::BROKEN: pen.setStyle(Qt::DashLine); painter->setPen(pen); painter->drawLine(QLineF(lw * .5, y1, lw * .5, y2)); break; case BarLineType::DOTTED: pen.setStyle(Qt::DotLine); painter->setPen(pen); case BarLineType::NORMAL: painter->drawLine(QLineF(lw * .5, y1, lw * .5, y2)); break; case BarLineType::END: { qreal lw2 = score()->styleS(StyleIdx::endBarWidth).val() * _spatium; qreal d = score()->styleS(StyleIdx::endBarDistance).val() * _spatium; painter->drawLine(QLineF(lw * .5, y1, lw * .5, y2)); pen.setWidthF(lw2); painter->setPen(pen); qreal x = d + lw2 * .5 + lw; painter->drawLine(QLineF(x, y1, x, y2)); } break; case BarLineType::DOUBLE: { lw = point(score()->styleS(StyleIdx::doubleBarWidth)); qreal d = point(score()->styleS(StyleIdx::doubleBarDistance)); pen.setWidthF(lw); painter->setPen(pen); qreal x = lw * .5; painter->drawLine(QLineF(x, y1, x, y2)); x += d + lw; painter->drawLine(QLineF(x, y1, x, y2)); } break; case BarLineType::START_REPEAT: { qreal lw2 = point(score()->styleS(StyleIdx::endBarWidth)); qreal d1 = point(score()->styleS(StyleIdx::endBarDistance)); qreal x2 = lw2 * .5; // thick line (lw2) qreal x1 = lw2 + d1 + lw * .5; // thin line (lw) qreal x0 = lw2 + d1 + lw + d1; // dot position drawDots(painter, x0); painter->drawLine(QLineF(x1, y1, x1, y2)); pen.setWidthF(lw2); painter->setPen(pen); painter->drawLine(QLineF(x2, y1, x2, y2)); if (score()->styleB(StyleIdx::repeatBarTips)) { drawSymbol(SymId::bracketTop, painter, QPointF(0.0, y1)); drawSymbol(SymId::bracketBottom, painter, QPointF(0.0, y2)); } } break; case BarLineType::END_REPEAT: { qreal lw2 = point(score()->styleS(StyleIdx::endBarWidth)); qreal d1 = point(score()->styleS(StyleIdx::endBarDistance)); qreal dotw = symWidth(SymId::repeatDot); qreal x1 = dotw + d1 + lw * .5; qreal x2 = dotw + d1 + lw + d1 + lw2 * .5; drawDots(painter, 0.0); painter->drawLine(QLineF(x1, y1, x1, y2)); pen.setWidthF(lw2); painter->setPen(pen); painter->drawLine(QLineF(x2, y1, x2, y2)); if (score()->styleB(StyleIdx::repeatBarTips)) { qreal x = x2 + lw2 * .5; qreal w1 = symBbox(SymId::reversedBracketTop).width(); drawSymbol(SymId::reversedBracketTop, painter, QPointF(x - w1, y1)); drawSymbol(SymId::reversedBracketBottom, painter, QPointF(x - w1, y2)); } } break; case BarLineType::END_START_REPEAT: { qreal lw2 = point(score()->styleS(StyleIdx::endBarWidth)); qreal d1 = point(score()->styleS(StyleIdx::endBarDistance)); qreal dotw = symWidth(SymId::repeatDot); qreal x1 = dotw + d1 + lw * .5; // thin bar qreal x2 = dotw + d1 + lw + d1 + lw2 * .5; // thick bar qreal x3 = dotw + d1 + lw + d1 + lw2 + d1 + lw * .5; // thin bar qreal x4 = dotw + d1 + lw + d1 + lw2 + d1 + lw + d1; // dot position drawDots(painter, .0); drawDots(painter, x4); painter->drawLine(QLineF(x1, y1, x1, y2)); pen.setWidthF(lw2); painter->setPen(pen); painter->drawLine(QLineF(x2, y1, x2, y2)); pen.setWidthF(lw); painter->setPen(pen); painter->drawLine(QLineF(x3, y1, x3, y2)); if (score()->styleB(StyleIdx::repeatBarTips)) { qreal x = x2; qreal w1 = symBbox(SymId::reversedBracketTop).width(); drawSymbol(SymId::bracketTop, painter, QPointF(x, y1)); drawSymbol(SymId::bracketBottom, painter, QPointF(x, y2)); drawSymbol(SymId::reversedBracketTop, painter, QPointF(x - w1, y1)); drawSymbol(SymId::reversedBracketBottom, painter, QPointF(x - w1, y2)); } } break; } }
void Bracket::layout() { path = QPainterPath(); if (h2 == 0.0) return; if (bracketType() == BRACKET_BRACE) { qreal w = point(score()->styleS(ST_akkoladeWidth)); #define XM(a) (a+700)*w/700 #define YM(a) (a+7100)*h2/7100 path.moveTo( XM( -8), YM(-2048)); path.cubicTo(XM( -8), YM(-3192), XM(-360), YM(-4304), XM( -360), YM(-5400)); // c 0 path.cubicTo(XM( -360), YM(-5952), XM(-264), YM(-6488), XM( 32), YM(-6968)); // c 1 path.cubicTo(XM( 40), YM(-6976), XM( 40), YM(-6976), XM( 40), YM(-6984)); // c 0 path.cubicTo(XM( 40), YM(-7000), XM( 16), YM(-7024), XM( 0), YM(-7024)); // c 0 path.cubicTo(XM( -8), YM(-7024), XM( -24), YM(-7024), XM( -32), YM(-7008)); // c 1 path.cubicTo(XM( -416), YM(-6392), XM(-544), YM(-5680), XM( -544), YM(-4960)); // c 0 path.cubicTo(XM( -544), YM(-3800), XM(-168), YM(-2680), XM( -168), YM(-1568)); // c 0 path.cubicTo(XM( -168), YM(-1016), XM(-264), YM( -496), XM( -560), YM( -16)); // c 1 path.lineTo( XM( -560), YM( 0)); // l 1 path.lineTo( XM( -560), YM( 16)); // l 1 path.cubicTo(XM( -264), YM( 496), XM(-168), YM( 1016), XM( -168), YM( 1568)); // c 0 path.cubicTo(XM( -168), YM( 2680), XM(-544), YM( 3800), XM( -544), YM( 4960)); // c 0 path.cubicTo(XM( -544), YM( 5680), XM(-416), YM( 6392), XM( -32), YM( 7008)); // c 1 path.cubicTo(XM( -24), YM( 7024), XM( -8), YM( 7024), XM( 0), YM( 7024)); // c 0 path.cubicTo(XM( 16), YM( 7024), XM( 40), YM( 7000), XM( 40), YM( 6984)); // c 0 path.cubicTo(XM( 40), YM( 6976), XM( 40), YM( 6976), XM( 32), YM( 6968)); // c 1 path.cubicTo(XM( -264), YM( 6488), XM(-360), YM( 5952), XM( -360), YM( 5400)); // c 0 path.cubicTo(XM( -360), YM( 4304), XM( -8), YM( 3192), XM( -8), YM( 2048)); // c 0 path.cubicTo(XM( - 8), YM( 1320), XM(-136), YM( 624), XM( -512), YM( 0)); // c 1 path.cubicTo(XM( -136), YM( -624), XM( -8), YM(-1320), XM( -8), YM(-2048)); // c 0 setbbox(path.boundingRect()); } else if (bracketType() == BRACKET_NORMAL) { qreal _spatium = spatium(); qreal w = score()->styleS(ST_bracketWidth).val() * _spatium * .5; qreal x = -w; w += symWidth(SymId::bracketTop); qreal bd = _spatium * .25; qreal y = - symHeight(SymId::bracketTop) - bd; qreal h = (-y + h2) * 2; bbox().setRect(x, y, w, h); } else if (bracketType() == BRACKET_SQUARE) { qreal _spatium = spatium(); qreal w = score()->styleS(ST_staffLineWidth).val() * _spatium * .5; qreal x = -w; qreal y = -w; qreal h = (h2 + w) * 2 ; w += (.5 * spatium() + 3* w); bbox().setRect(x, y, w, h); } else if (bracketType() == BRACKET_LINE) { qreal _spatium = spatium(); qreal w = 0.67 * score()->styleS(ST_bracketWidth).val() * _spatium * .5; qreal x = -w; qreal bd = _spatium * .25; qreal y = -bd; qreal h = (-y + h2) * 2; bbox().setRect(x, y, w, h); } }
void TrillSegment::draw(QPainter* painter) const { QRectF b2(symBbox(SymId::wiggleTrill)); qreal w2 = symWidth(SymId::wiggleTrill); qreal x2 = pos2().x(); QColor color; if (flag(ELEMENT_DROP_TARGET)) color = MScore::dropColor; else if (selected() && !(score() && score()->printing())) color = MScore::selectColor[0]; else if (!visible()) color = Qt::gray; else { color = trill()->curColor(); } painter->setPen(color); if (spannerSegmentType() == SEGMENT_SINGLE || spannerSegmentType() == SEGMENT_BEGIN) { SymId sym = SymId::noSym; qreal x0 = 0.0, x1 = 0.0, y = 0.0; int n = 0; QRectF b1; switch(trill()->trillType()) { case Trill::TRILL_LINE: sym = SymId::ornamentTrill; b1 = symBbox(sym); x0 = -b1.x(); x1 = x0 + b1.width(); n = int(floor((x2-x1) / w2)); y = 0.0; break; #if 0 // TODO-smufl case Trill::UPPRALL_LINE: sym = SymId(upprallSym); b1 = score()->sym(sym).bbox(mag); x0 = -b1.x(); x1 = b1.width(); n = int(floor((x2-x1) / w2)); y = -b1.height(); break; case Trill::DOWNPRALL_LINE: sym = SymId(downprallSym); b1 = score()->sym(sym).bbox(mag); x0 = -b1.x(); x1 = b1.width(); n = int(floor((x2-x1) / w2)); y = -b1.height(); break; case Trill::PRALLPRALL_LINE: sym = SymId(prallprallSym); b1 = score()->sym(sym).bbox(mag); x0 = -b1.x(); x1 = b1.width(); n = int(floor((x2-x1) / w2)); y = -b1.height(); break; #endif case Trill::PURE_LINE: sym = SymId::noSym; x0 = 0; x1 = 0; n = int(floor((x2-x1) / w2)); y = 0.0; } if (n <= 0) n = 1; if (sym != SymId::noSym) drawSymbol(sym, painter, QPointF(x0, y)); drawSymbol(SymId::wiggleTrill, painter, QPointF(x1, b2.y() * .9), n); } else { qreal x1 = 0.0; int n = int(floor((x2-x1) / w2)); drawSymbol(SymId::wiggleTrill, painter, QPointF(x1, b2.y() * .9), n); } }
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; } }
qreal Rest::centerX() const { return symWidth(_sym) * .5; }