void Glissando::layout() { Chord* chord = static_cast<Chord*>(parent()); if (chord == 0) { return; } Note* anchor2 = chord->upNote(); Segment* s = chord->segment(); s = s->prev1(); while (s) { if ((s->subtype() & (Segment::SegChordRestGrace)) && s->element(track())) break; s = s->prev1(); } if (s == 0) { qDebug("no segment for first note of glissando found\n"); return; } ChordRest* cr = static_cast<ChordRest*>(s->element(track())); if (cr == 0 || cr->type() != CHORD) { qDebug("no first note for glissando found, track %d\n", track()); return; } Note* anchor1 = static_cast<Chord*>(cr)->upNote(); setPos(0.0, 0.0); QPointF cp1 = anchor1->pagePos(); QPointF cp2 = anchor2->pagePos(); // construct line from notehead to notehead qreal x1 = (anchor1->headWidth()) - (cp2.x() - cp1.x()); qreal y1 = anchor1->pos().y(); qreal x2 = anchor2->pos().x(); qreal y2 = anchor2->pos().y(); // on TAB's, adjust lower end point from string line height to base of note height (= ca. half line spacing) if (chord->staff()->isTabStaff()) { qreal yOff = chord->staff()->lineDistance() * 0.5 * spatium(); if (anchor1->pitch() > anchor2->pitch()) // descending glissando: y2 += yOff; // move ending point to base of note else // ascending glissando: y1 += yOff; // move starting point to base of note } QLineF fullLine(x1, y1, x2, y2); // shorten line on each side by offsets qreal xo = spatium() * .5; qreal yo = xo; // spatium() * .5; QPointF p1 = fullLine.pointAt(xo / fullLine.length()); QPointF p2 = fullLine.pointAt(1 - (yo / fullLine.length())); line = QLineF(p1, p2); qreal lw = spatium() * .15 * .5; QRectF r = QRectF(line.p1(), line.p2()).normalized(); setbbox(r.adjusted(-lw, -lw, lw, lw)); }
void Glissando::layout() { Chord* chord = static_cast<Chord*>(parent()); if (chord == 0) { return; } Note* anchor2 = chord->upNote(); Segment* s = chord->segment(); s = s->prev1(); while (s) { if ((s->subtype() == SegChordRest || s->subtype() == SegGrace) && s->element(track())) break; s = s->prev1(); } if (s == 0) { qDebug("no segment for first note of glissando found\n"); return; } ChordRest* cr = static_cast<ChordRest*>(s->element(track())); if (cr == 0 || cr->type() != CHORD) { qDebug("no first note for glissando found, track %d\n", track()); return; } Note* anchor1 = static_cast<Chord*>(cr)->upNote(); setPos(0.0, 0.0); QPointF cp1 = anchor1->pagePos(); QPointF cp2 = anchor2->pagePos(); // construct line from notehead to notehead qreal x1 = (anchor1->headWidth()) - (cp2.x() - cp1.x()); qreal y1 = anchor1->pos().y(); qreal x2 = anchor2->pos().x(); qreal y2 = anchor2->pos().y(); QLineF fullLine(x1, y1, x2, y2); // shorten line on each side by offsets qreal xo = spatium() * .5; qreal yo = xo; // spatium() * .5; QPointF p1 = fullLine.pointAt(xo / fullLine.length()); QPointF p2 = fullLine.pointAt(1 - (yo / fullLine.length())); line = QLineF(p1, p2); qreal lw = spatium() * .15 * .5; QRectF r = QRectF(line.p1(), line.p2()).normalized(); setbbox(r.adjusted(-lw, -lw, lw, lw)); }
void Ambitus::layout() { int bottomLine, topLine; ClefType clf; qreal headWdt = headWidth(); Key key; qreal lineDist; int numOfLines; Segment* segm = segment(); qreal _spatium = spatium(); Staff* stf = nullptr; if (segm && track() > -1) { int tick = segm->tick(); stf = score()->staff(staffIdx()); lineDist = stf->lineDistance(tick) * _spatium; numOfLines = stf->lines(tick); clf = stf->clef(tick); } else { // for use in palettes lineDist = _spatium; numOfLines = 3; clf = ClefType::G; } // // NOTEHEADS Y POS // // if pitch == INVALID_PITCH oor tpc == INALID_TPC, set to some default: // for use in palettes and when actual range cannot be calculated (new ambitus or no notes in staff) // qreal xAccidOffTop = 0; qreal xAccidOffBottom = 0; if (stf) key = stf->key(segm->tick()); else key = Key::C; // top notehead if (_topPitch == INVALID_PITCH || _topTpc == Tpc::TPC_INVALID) _topPos.setY(0); // if uninitialized, set to top staff line else { topLine = absStep(_topTpc, _topPitch); topLine = relStep(topLine, clf); _topPos.setY(topLine * lineDist * 0.5); // compute accidental AccidentalType accidType; // if (13 <= (tpc - key) <= 19) there is no accidental) if (_topTpc - int(key) >= 13 && _topTpc - int(key) <= 19) accidType = AccidentalType::NONE; else { AccidentalVal accidVal = AccidentalVal( (_topTpc - Tpc::TPC_MIN) / TPC_DELTA_SEMITONE - 2 ); accidType = Accidental::value2subtype(accidVal); if (accidType == AccidentalType::NONE) accidType = AccidentalType::NATURAL; } _topAccid.setAccidentalType(accidType); if (accidType != AccidentalType::NONE) _topAccid.layout(); else _topAccid.setbbox(QRect()); _topAccid.rypos() = _topPos.y(); } // bottom notehead if (_bottomPitch == INVALID_PITCH || _bottomTpc == Tpc::TPC_INVALID) _bottomPos.setY( (numOfLines-1) * lineDist); // if uninitialized, set to last staff line else { bottomLine = absStep(_bottomTpc, _bottomPitch); bottomLine = relStep(bottomLine, clf); _bottomPos.setY(bottomLine * lineDist * 0.5); // compute accidental AccidentalType accidType; if (_bottomTpc - int(key) >= 13 && _bottomTpc - int(key) <= 19) accidType = AccidentalType::NONE; else { AccidentalVal accidVal = AccidentalVal( (_bottomTpc - Tpc::TPC_MIN) / TPC_DELTA_SEMITONE - 2 ); accidType = Accidental::value2subtype(accidVal); if (accidType == AccidentalType::NONE) accidType = AccidentalType::NATURAL; } _bottomAccid.setAccidentalType(accidType); if (accidType != AccidentalType::NONE) _bottomAccid.layout(); else _bottomAccid.setbbox(QRect()); _bottomAccid.rypos() = _bottomPos.y(); } // // NOTEHEAD X POS // // Note: manages colliding accidentals // qreal accNoteDist = point(score()->styleS(Sid::accidentalNoteDistance)); xAccidOffTop = _topAccid.width() + accNoteDist; xAccidOffBottom = _bottomAccid.width() + accNoteDist; // if top accidental extends down more than bottom accidental extends up, // AND ambitus is not leaning right, bottom accidental needs to be displaced bool collision = (_topAccid.ipos().y() + _topAccid.bbox().y() + _topAccid.height() > _bottomAccid.ipos().y() + _bottomAccid.bbox().y() ) && _dir != MScore::DirectionH::RIGHT; if (collision) { // displace bottom accidental (also attempting to 'undercut' flats) xAccidOffBottom = xAccidOffTop + ((_bottomAccid.accidentalType() == AccidentalType::FLAT || _bottomAccid.accidentalType() == AccidentalType::FLAT2 || _bottomAccid.accidentalType() == AccidentalType::NATURAL) ? _bottomAccid.width() * 0.5 : _bottomAccid.width()); } switch (_dir) { case MScore::DirectionH::AUTO: // noteheads one above the other // left align noteheads and right align accidentals 'hanging' on the left _topPos.setX(0.0); _bottomPos.setX(0.0); _topAccid.rxpos() = - xAccidOffTop; _bottomAccid.rxpos() = - xAccidOffBottom; break; case MScore::DirectionH::LEFT: // top notehead at the left of bottom notehead // place top notehead at left margin; bottom notehead at right of top head; // top accid. 'hanging' on left of top head and bottom accid. 'hanging' at left of bottom head _topPos.setX(0.0); _bottomPos.setX(headWdt); _topAccid.rxpos() = - xAccidOffTop; _bottomAccid.rxpos() = collision ? - xAccidOffBottom : headWdt - xAccidOffBottom; break; case MScore::DirectionH::RIGHT: // top notehead at the right of bottom notehead // bottom notehead at left margin; top notehead at right of bottomnotehead // top accid. 'hanging' on left of top head and bottom accid. 'hanging' at left of bottom head _bottomPos.setX(0.0); _topPos.setX(headWdt); _bottomAccid.rxpos() = - xAccidOffBottom; _topAccid.rxpos() = headWdt - xAccidOffTop; break; } // compute line from top note centre to bottom note centre QLineF fullLine(_topPos.x() + headWdt*0.5, _topPos.y(), _bottomPos.x() + headWdt*0.5, _bottomPos.y()); // shorten line on each side by offsets qreal yDelta = _bottomPos.y() - _topPos.y(); if (yDelta != 0.0) { qreal off = _spatium * LINEOFFSET_DEFAULT; QPointF p1 = fullLine.pointAt(off / yDelta); QPointF p2 = fullLine.pointAt(1 - (off / yDelta)); _line = QLineF(p1, p2); } else _line = fullLine; QRectF headRect = QRectF(0, -0.5*_spatium, headWdt, 1*_spatium); setbbox(headRect.translated(_topPos).united(headRect.translated(_bottomPos)) .united(_topAccid.bbox().translated(_topAccid.ipos())) .united(_bottomAccid.bbox().translated(_bottomAccid.ipos())) ); }
void Glissando::layout() { Chord* chord = static_cast<Chord*>(parent()); if (chord == 0) return; Note* anchor2 = chord->upNote(); Segment* s = chord->segment(); s = s->prev1(); while (s) { if ((s->segmentType() & (Segment::SegChordRest)) && s->element(track())) break; s = s->prev1(); } if (s == 0) { qDebug("no segment for first note of glissando found\n"); return; } ChordRest* cr = static_cast<ChordRest*>(s->element(track())); if (cr == 0 || cr->type() != CHORD) { qDebug("no first note for glissando found, track %d", track()); return; } qreal _spatium = spatium(); Note* anchor1 = static_cast<Chord*>(cr)->upNote(); setPos(0.0, 0.0); adjustReadPos(); QPointF cp1 = anchor1->pagePos(); QPointF cp2 = anchor2->pagePos(); // line starting point int dots = static_cast<Chord*>(cr)->dots(); LedgerLine * ledLin = static_cast<Chord*>(cr)->ledgerLines(); // if dots, from right of last dot (assume a standard dot with of 1/4 sp) // if no dots, from right of ledger line, if any; from right of note head, if no ledger line qreal x1 = (dots ? anchor1->dot(dots-1)->pos().x() + anchor1->dot(dots-1)->width() : (ledLin ? ledLin->pos().x() + ledLin->width() : anchor1->headWidth()) ) - (cp2.x() - cp1.x()); // make relative to end note qreal y1 = anchor1->pos().y(); // line end point: left of note head qreal x2 = anchor2->pos().x(); qreal y2 = anchor2->pos().y(); // angle glissando between notes with the same pitch letter if (anchor1->line() == anchor2->line()) { int upDown = anchor2->pitch() - anchor1->pitch(); if (upDown != 0) upDown /= abs(upDown); y1 += _spatium * 0.25 * upDown; y2 -= _spatium * 0.25 * upDown; } // on TAB's, adjust lower end point from string line height to base of note height (= ca. half line spacing) if (chord->staff()->isTabStaff()) { qreal yOff = chord->staff()->lineDistance() * 0.3 * _spatium; if (anchor1->pitch() > anchor2->pitch()) { // descending glissando: y2 += yOff; y1 -= yOff; } // move ending point to base of note else { // ascending glissando: y1 += yOff; // move starting point to base of note y2 -= yOff; } } // shorten line to avoid end note ledger line ledLin=anchor2->chord()->ledgerLines(); if (ledLin) x2 = ledLin->pos().x(); // shorten line so it doesn't go through end note accidental or arpeggio if (Accidental* a = anchor2->accidental()) { x2 = a->pos().x() + a->userOff().x(); } if (Arpeggio* a = chord->arpeggio()) { x2 = a->pos().x() + a->userOff().x(); } QLineF fullLine(x1, y1, x2, y2); // shorten line on each side by offsets qreal xo = _spatium * .5; qreal yo = xo; // spatium() * .5; QPointF p1 = fullLine.pointAt(xo / fullLine.length()); QPointF p2 = fullLine.pointAt(1 - (yo / fullLine.length())); line = QLineF(p1, p2); qreal lw = _spatium * .15 * .5; QRectF r = QRectF(line.p1(), line.p2()).normalized(); setbbox(r.adjusted(-lw, -lw, lw, lw)); }
void Glissando::layout() { Chord* chord = static_cast<Chord*>(parent()); if (chord == 0) return; Note* anchor2 = chord->upNote(); Segment* s2 = chord->segment(); Segment* s1 = s2->prev1(); while (s1) { if ((s1->segmentType() & (Segment::Type::ChordRest)) && s1->element(track())) break; s1 = s1->prev1(); } if (s1 == 0) { qDebug("no segment for first note of glissando found"); return; } ChordRest* cr = static_cast<ChordRest*>(s1->element(track())); if (cr == 0 || cr->type() != Element::Type::CHORD) { qDebug("no first note for glissando found, track %d", track()); return; } qreal _spatium = spatium(); Note* anchor1 = static_cast<Chord*>(cr)->upNote(); setPos(0.0, 0.0); adjustReadPos(); // since line will be drawn relative to end note, // calculate offsets for start note coordinates relative to end note qreal x1off = 0.0; qreal y1off = 0.0; QPointF cp1 = anchor1->pagePos(); QPointF cp2 = anchor2->pagePos(); // layout of glissandi happens before we have staff positions within the system // so these "page" positions are not accurate across different staves // cheap partial fix for cross-staff glissandi: adjust vertical position according to difference in staffMove int moveDiff = anchor2->chord()->staffMove() - anchor1->chord()->staffMove(); if (moveDiff) y1off = moveDiff * 4.0 * _spatium; // now calculate offsets if (s1->system() == s2->system()) { // normal case - start and end note in same system x1off = cp2.x() - cp1.x(); if (!moveDiff) y1off = cp2.y() - cp1.y(); } else { // cheap partial fix for cross system glissandi: just draw a short line into end note // TODO: draw line coming out of start note on previous system x1off = 4.0 * _spatium; if (!moveDiff) y1off = anchor2->pos().y() - anchor1->pos().y(); } // line starting point int dots = static_cast<Chord*>(cr)->dots(); LedgerLine * ledLin = static_cast<Chord*>(cr)->ledgerLines(); // if dots, from right of last dot (assume a standard dot with of 1/4 sp) // if no dots, from right of ledger line, if any; from right of note head, if no ledger line qreal x1 = (dots && anchor1->dot(dots-1) ? anchor1->dot(dots-1)->pos().x() + anchor1->dot(dots-1)->width() : (ledLin ? ledLin->pos().x() + ledLin->width() : anchor1->headWidth()) ) - x1off; // make relative to end note qreal y1 = anchor2->y() - y1off; // line end point: left of note head qreal x2 = anchor2->pos().x(); qreal y2 = anchor2->pos().y(); // angle glissando between notes with the same pitch letter if (anchor1->line() == anchor2->line()) { int upDown = anchor2->pitch() - anchor1->pitch(); if (upDown != 0) upDown /= abs(upDown); y1 += _spatium * 0.25 * upDown; y2 -= _spatium * 0.25 * upDown; } // on TAB's, adjust lower end point from string line height to base of note height (= ca. half line spacing) if (chord->staff()->isTabStaff()) { qreal yOff = chord->staff()->lineDistance() * 0.3 * _spatium; if (anchor1->pitch() > anchor2->pitch()) { // descending glissando: y2 += yOff; y1 -= yOff; } // move ending point to base of note else { // ascending glissando: y1 += yOff; // move starting point to base of note y2 -= yOff; } } // shorten line to avoid end note ledger line ledLin = anchor2->chord()->ledgerLines(); if (ledLin) x2 = ledLin->pos().x(); // shorten line so it doesn't go through end note accidental or arpeggio if (Accidental* a = anchor2->accidental()) { x2 = a->pos().x() + a->userOff().x(); } if (Arpeggio* a = chord->arpeggio()) { x2 = a->pos().x() + a->userOff().x(); } QLineF fullLine(x1, y1, x2, y2); // shorten line on each side by offsets qreal xo = _spatium * .5; qreal yo = xo; // spatium() * .5; QPointF p1 = fullLine.pointAt(xo / fullLine.length()); QPointF p2 = fullLine.pointAt(1 - (yo / fullLine.length())); line = QLineF(p1, p2); qreal lw = _spatium * .15 * .5; QRectF r = QRectF(line.p1(), line.p2()).normalized(); setbbox(r.adjusted(-lw, -lw, lw, lw)); }