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() { qreal _spatium = spatium(); if (score() == gscore // for use in palettes || startElement() == nullptr || endElement() == nullptr) { // or while dragging if (spannerSegments().isEmpty()) add(createLineSegment()); LineSegment* s = frontSegment(); s->setPos(QPointF()); s->setPos2(QPointF(_spatium * GLISS_PALETTE_WIDTH, -_spatium * GLISS_PALETTE_HEIGHT)); s->layout(); return; } SLine::layout(); setPos(0.0, 0.0); adjustReadPos(); Note* anchor1 = static_cast<Note*>(startElement()); Note* anchor2 = static_cast<Note*>(endElement()); Chord* cr1 = anchor1->chord(); Chord* cr2 = anchor2->chord(); GlissandoSegment* segm1 = static_cast<GlissandoSegment*>(frontSegment()); GlissandoSegment* segm2 = static_cast<GlissandoSegment*>(backSegment()); // Note: line segments are defined by // initial point: ipos() (relative to system origin) // ending point: pos2() (relative to initial point) // LINE ENDING POINTS TO NOTE HEAD CENTRES // assume gliss. line goes from centre of initial note centre to centre of ending note: // move first segment origin and last segment ending point from note head origin to note head centre QPointF offs1 = QPointF(anchor1->headWidth() * 0.5, 0.0); QPointF offs2 = QPointF(anchor2->headWidth() * 0.5, 0.0); // AVOID HORIZONTAL LINES int upDown = (0 < (anchor2->pitch() - anchor1->pitch())) - ((anchor2->pitch() - anchor1->pitch()) < 0); // on TAB's, glissando are by necessity on the same string, this gives an horizontal glissando line; // make bottom end point lower and top ending point higher if (cr1->staff()->isTabStaff()) { qreal yOff = cr1->staff()->lineDistance() * 0.3 * _spatium; offs1.ry() += yOff * upDown; offs2.ry() -= yOff * upDown; } // if not TAB, angle glissando between notes on the same line else { if (anchor1->line() == anchor2->line()) { offs1.ry() += _spatium * 0.25 * upDown; offs2.ry() -= _spatium * 0.25 * upDown; } } // move initial point of first segment and adjust its length accordingly segm1->setPos (segm1->ipos() + offs1); segm1->setPos2(segm1->ipos2() - offs1); // adjust ending point of last segment segm2->setPos2(segm2->ipos2() + offs2); // FINAL SYSTEM-INITIAL NOTE // if the last gliss. segment attaches to a system-initial note, some extra width has to be added if (cr2->segment()->measure() == cr2->segment()->system()->firstMeasure() && cr2->rtick() == 0) { segm2->rxpos() -= GLISS_STARTOFSYSTEM_WIDTH * _spatium; segm2->rxpos2()+= GLISS_STARTOFSYSTEM_WIDTH * _spatium; } // INTERPOLATION OF INTERMEDIATE POINTS // This probably belongs to SLine class itself; currently it does not seem // to be needed for anything else than Glissando, though // get total x-width and total y-height of all segments qreal xTot = 0.0; for (SpannerSegment* segm : spannerSegments()) xTot += segm->ipos2().x(); qreal y0 = segm1->ipos().y(); qreal yTot = segm2->ipos().y() + segm2->ipos2().y() - y0; qreal ratio = yTot / xTot; // interpolate y-coord of intermediate points across total width and height qreal xCurr = 0.0; qreal yCurr; for (int i = 0; i < spannerSegments().count()-1; i++) { SpannerSegment* segm = segmentAt(i); xCurr += segm->ipos2().x(); yCurr = y0 + ratio * xCurr; segm->rypos2() = yCurr - segm->ipos().y(); // position segm. end point at yCurr // next segment shall start where this segment stopped segm = segmentAt(i+1); segm->rypos2() += segm->ipos().y() - yCurr; // adjust next segm. vertical length segm->rypos() = yCurr; // position next segm. start point at yCurr } // STAY CLEAR OF NOTE APPENDAGES // initial note dots / ledger line / note head offs1 *= -1.0; // discount changes already applied int dots = cr1->dots(); LedgerLine * ledLin = cr1->ledgerLines(); // if dots, start at right of last dot // if no dots, from right of ledger line, if any; from right of note head, if no ledger line offs1.rx() += (dots && anchor1->dot(dots-1) ? anchor1->dot(dots-1)->pos().x() + anchor1->dot(dots-1)->width() : (ledLin ? ledLin->pos().x() + ledLin->width() : anchor1->headWidth()) ); // final note arpeggio / accidental / ledger line / accidental / arpeggio (i.e. from outermost to innermost) offs2 *= -1.0; // discount changes already applied if (Arpeggio* a = cr2->arpeggio()) offs2.rx() += a->pos().x() + a->userOff().x(); else if (Accidental* a = anchor2->accidental()) offs2.rx() += a->pos().x() + a->userOff().x(); else if ( (ledLin = cr2->ledgerLines()) != nullptr) offs2.rx() += ledLin->pos().x(); // add another a quarter spatium of 'air' offs1.rx() += _spatium * 0.25; offs2.rx() -= _spatium * 0.25; // apply offsets: shorten first segment by x1 (and proportionally y) and adjust its length accordingly offs1.ry() = segm1->ipos2().y() * offs1.x() / segm1->ipos2().x(); segm1->setPos(segm1->ipos() + offs1); segm1->setPos2(segm1->ipos2() - offs1); // adjust last segment length by x2 (and proportionally y) offs2.ry() = segm2->ipos2().y() * offs2.x() / segm2->ipos2().x(); segm2->setPos2(segm2->ipos2() + offs2); for (SpannerSegment* segm : spannerSegments()) static_cast<GlissandoSegment*>(segm)->layout(); // compute glissando bbox as the bbox of the last segment, relative to the end anchor note QPointF anchor2PagePos = anchor2->pagePos(); QPointF system2PagePos = cr2->segment()->system()->pagePos(); QPointF anchor2SystPos = anchor2PagePos - system2PagePos; QRectF r = QRectF(anchor2SystPos - segm2->pos(), anchor2SystPos - segm2->pos() - segm2->pos2()).normalized(); qreal lw = _spatium * lineWidth().val() * .5; 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)); }