void Image::layout() { qreal f = _sizeIsSpatium ? spatium() : MScore::DPMM; // if autoscale && inside a box, scale to box relevant size if (autoScale() && parent() && ((parent()->type() == HBOX || parent()->type() == VBOX))) { if (_lockAspectRatio) { QSizeF size(imageSize()); qreal ratio = size.width() / size.height(); qreal w = parent()->width(); qreal h = parent()->height(); if ((w / h) < ratio) { _size.setWidth(w / f); _size.setHeight((w / ratio) / f); } else { _size.setHeight(h / f); _size.setWidth(h * ratio / f); } } else _size = parent()->bbox().size() / f; } // in any case, adjust position relative to parent adjustReadPos(); setbbox(QRectF(0.0, 0.0, _size.width() * f, _size.height() * f)); }
void Dynamic::layout() { if (!readPos().isNull()) { if (score()->mscVersion() <= 114) { setReadPos(QPointF()); // hack: 1.2 boundingBoxes are a bit wider which results // in symbols moved right setUserXoffset(userOff().x() - spatium() * .6); } } setPos(textStyle().offset(spatium())); Text::layout1(); Segment* s = segment(); if (!s) return; for (int voice = 0; voice < VOICES; ++voice) { int t = (track() & ~0x3) + voice; Chord* c = static_cast<Chord*>(s->element(t)); if (!c) continue; if (c->type() == Element::Type::CHORD) { qreal noteHeadWidth = score()->noteHeadWidth() * c->mag(); if (c->stem() && !c->up()) // stem down rxpos() += noteHeadWidth * .25; // center on stem + optical correction else rxpos() += noteHeadWidth * .5; // center on notehead } else rxpos() += c->width() * .5; break; } adjustReadPos(); }
void Jump::layout() { setPos(QPointF(0.0, score()->styleP(Sid::jumpPosAbove))); TextBase::layout1(); if (parent() && autoplace()) { setUserOff(QPointF()); int si = staffIdx(); qreal minDistance = 0.5 * spatium(); // score()->styleP(Sid::tempoMinDistance); Shape& s1 = measure()->staffShape(si); Shape s2 = shape().translated(pos()); if (placeAbove()) { qreal d = s2.minVerticalDistance(s1); if (d > -minDistance) { qreal yd = -d - minDistance; rUserYoffset() = yd; s2.translate(QPointF(0.0, yd)); } } else { qreal d = s1.minVerticalDistance(s2); if (d > -minDistance) { qreal yd = d + minDistance; rUserYoffset() = yd; s2.translate(QPointF(0.0, yd)); } } s1.add(s2); } else { adjustReadPos(); } }
void StaffText::layout() { if (autoplace()) setUserOff(QPointF()); QPointF p(textStyle().offset(spatium())); if (placement() == Element::Placement::BELOW) p.ry() = - p.ry() + lineHeight(); setPos(p); Text::layout1(); if (!parent()) // palette & clone trick return; if (autoplace() && segment()) { qreal minDistance = score()->styleP(StyleIdx::dynamicsMinDistance); // TODO Shape s1 = segment()->staffShape(staffIdx()).translated(segment()->pos()); Shape s2 = shape().translated(segment()->pos()); if (placement() == Element::Placement::ABOVE) { qreal d = s2.minVerticalDistance(s1); if (d > -minDistance) rUserYoffset() = -d - minDistance; } else { qreal d = s1.minVerticalDistance(s2); if (d > -minDistance) rUserYoffset() = d + minDistance; } } adjustReadPos(); }
void PedalSegment::layout() { TextLineSegment::layout(); if (parent()) // for palette rypos() += score()->styleS(StyleIdx::pedalY).val() * spatium(); adjustReadPos(); }
void TextLineSegment::layout() { if (autoplace()) setUserOff(QPointF()); TextLineBaseSegment::layout(); if (parent()) { if (textLine()->placeBelow()) { qreal sh = staff() ? staff()->height() : 0.0; rypos() = sh + score()->styleP(StyleIdx::textLinePosBelow) * mag(); } else rypos() = score()->styleP(StyleIdx::textLinePosAbove) * mag(); if (autoplace()) { qreal minDistance = spatium() * .7; Shape s1 = shape().translated(pos()); if (textLine()->placeAbove()) { qreal d = system()->topDistance(staffIdx(), s1); if (d > -minDistance) rUserYoffset() = -d - minDistance; } else { qreal d = system()->bottomDistance(staffIdx(), s1); if (d > -minDistance) rUserYoffset() = d + minDistance; } } else adjustReadPos(); } }
void GlissandoSegment::layout() { QRectF r = QRectF(0.0, 0.0, pos2().x(), pos2().y()).normalized(); qreal lw = spatium() * glissando()->lineWidth().val() * .5; setbbox(r.adjusted(-lw, -lw, lw, lw)); adjustReadPos(); }
void OttavaSegment::layout() { if (autoplace()) setUserOff(QPointF()); TextLineSegment::layout(); if (parent()) { qreal yo = score()->styleP(StyleIdx::ottavaY) * mag(); if (ottava()->placement() == Element::Placement::BELOW) yo = -yo + staff()->height(); rypos() += yo; if (autoplace()) { qreal minDistance = spatium() * .7; Shape s1 = shape().translated(pos()); if (ottava()->placement() == Element::Placement::ABOVE) { qreal d = system()->topDistance(staffIdx(), s1); if (d > -minDistance) rUserYoffset() = -d - minDistance; } else { qreal d = system()->bottomDistance(staffIdx(), s1); if (d > -minDistance) rUserYoffset() = d + minDistance; } } else adjustReadPos(); } }
void PedalSegment::layout() { if (autoplace()) setUserOff(QPointF()); TextLineBaseSegment::layout(); if (parent()) { // for palette rypos() += score()->styleP(pedal()->placeBelow() ? StyleIdx::pedalPosBelow : StyleIdx::pedalPosAbove); if (autoplace()) { qreal minDistance = spatium() * .7; Shape s1 = shape().translated(pos()); if (pedal()->placeBelow()) { qreal d = system()->bottomDistance(staffIdx(), s1); if (d > -minDistance) rUserYoffset() = d + minDistance; } else { qreal d = system()->topDistance(staffIdx(), s1); if (d > -minDistance) rUserYoffset() = -(d + minDistance); } } else adjustReadPos(); } }
void OttavaSegment::layout() { TextLineSegment::layout1(); if (parent()) // for palette rypos() += score()->styleS(ST_ottavaY).val() * spatium(); adjustReadPos(); }
void SlurSegment::layout(const QPointF& p1, const QPointF& p2) { ups[GRIP_START].p = p1; ups[GRIP_END].p = p2; slurTie()->computeBezier(this); setbbox(path.boundingRect()); adjustReadPos(); }
void VoltaSegment::layout() { rypos() = 0.0; TextLineSegment::layout1(); if (parent()) // for palette rypos() += score()->styleS(ST_voltaY).val() * spatium(); adjustReadPos(); }
void Image::layout() { setPos(0.0, 0.0); if (imageType == ImageType::SVG && !svgDoc) { if (_storeItem) { svgDoc = new QSvgRenderer(_storeItem->buffer()); if (svgDoc->isValid()) { if (_size.isNull()) { _size = svgDoc->defaultSize(); if (_sizeIsSpatium) _size /= 10.0; // by convention } } } } else if (imageType == ImageType::RASTER && !rasterDoc) { if (_storeItem) { rasterDoc = new QImage; rasterDoc->loadFromData(_storeItem->buffer()); if (!rasterDoc->isNull()) { if (_size.isNull()) { _size = rasterDoc->size() * 0.4; if (_sizeIsSpatium) _size /= spatium(); else _size /= MScore::DPMM; } _dirty = true; } } } qreal f = _sizeIsSpatium ? spatium() : MScore::DPMM; // if autoscale && inside a box, scale to box relevant size if (autoScale() && parent() && ((parent()->type() == Element::Type::HBOX || parent()->type() == Element::Type::VBOX))) { if (_lockAspectRatio) { QSizeF size(imageSize()); qreal ratio = size.width() / size.height(); qreal w = parent()->width(); qreal h = parent()->height(); if ((w / h) < ratio) { _size.setWidth(w / f); _size.setHeight((w / ratio) / f); } else { _size.setHeight(h / f); _size.setWidth(h * ratio / f); } } else _size = parent()->bbox().size() / f; } // in any case, adjust position relative to parent adjustReadPos(); bbox().setRect(0.0, 0.0, _size.width() * f, _size.height() * f); }
void TrillSegment::layout() { QRectF b1(symbols[score()->symIdx()][trillSym].bbox(magS())); QRectF rr(b1.translated(-b1.x(), 0.0)); rr |= QRectF(0.0, rr.y(), pos2().x(), rr.height()); setbbox(rr); rypos() += score()->styleS(ST_trillY).val() * spatium(); adjustReadPos(); }
void HairpinSegment::layout() { QTransform t; qreal _spatium = spatium(); qreal h1 = score()->styleS(ST_hairpinHeight).val() * _spatium * .5; qreal h2 = score()->styleS(ST_hairpinContHeight).val() * _spatium * .5; rypos() = 0.0; qreal len; qreal x = pos2().x(); if (x < _spatium) // minimum size of hairpin x = _spatium; qreal y = pos2().y(); len = sqrt(x * x + y * y); t.rotateRadians(asin(y/len)); if (hairpin()->hairpinType() == 0) { // crescendo switch (spannerSegmentType()) { case SEGMENT_SINGLE: case SEGMENT_BEGIN: l1.setLine(.0, .0, len, h1); l2.setLine(.0, .0, len, - h1); break; case SEGMENT_MIDDLE: case SEGMENT_END: l1.setLine(.0, h2, len, h1); l2.setLine(.0, -h2, len, - h1); break; } } else { // decrescendo switch(spannerSegmentType()) { case SEGMENT_SINGLE: case SEGMENT_END: l1.setLine(.0, h1, len, 0.0); l2.setLine(.0, -h1, len, 0.0); break; case SEGMENT_BEGIN: case SEGMENT_MIDDLE: l1.setLine(.0, h1, len, + h2); l2.setLine(.0, -h1, len, - h2); break; } } l1 = t.map(l1); l2 = t.map(l2); QRectF r = QRectF(l1.p1(), l1.p2()).normalized() | QRectF(l2.p1(), l2.p2()).normalized(); qreal w = point(score()->styleS(ST_hairpinWidth)); setbbox(r.adjusted(-w*.5, -w*.5, w, w)); if (parent()) rypos() += score()->styleS(ST_hairpinY).val() * _spatium; adjustReadPos(); }
void Text::layout() { if (styled() && !_editMode) { SimpleText::layout(); } else { _doc->setDefaultFont(textStyle().font(spatium())); qreal w = -1.0; qreal x = 0.0; qreal y = 0.0; if (parent() && layoutToParentWidth()) { w = parent()->width(); if (parent()->type() == HBOX || parent()->type() == VBOX || parent()->type() == TBOX) { Box* box = static_cast<Box*>(parent()); x += box->leftMargin() * MScore::DPMM; y += box->topMargin() * MScore::DPMM; w = box->width() - ((box->leftMargin() + box->rightMargin()) * MScore::DPMM); } } QTextOption to = _doc->defaultTextOption(); to.setUseDesignMetrics(true); to.setWrapMode(w <= 0.0 ? QTextOption::NoWrap : QTextOption::WrapAtWordBoundaryOrAnywhere); _doc->setDefaultTextOption(to); if (w < 0.0) w = _doc->idealWidth(); _doc->setTextWidth(w); setbbox(QRectF(QPointF(0.0, 0.0), _doc->size())); if (hasFrame()) layoutFrame(); _doc->setModified(false); textStyle().layout(this); // process alignment #if 0 // TODO TEXT_STYLE_TEXTLINE if ((textStyle().align() & ALIGN_VCENTER) && (textStyle() == TEXT_STYLE_TEXTLINE)) { // special case: vertically centered text with TextLine needs to // take into account the line width TextLineSegment* tls = static_cast<TextLineSegment*>(parent()); TextLine* tl = tls->textLine(); if (tl) { qreal textlineLineWidth = point(tl->lineWidth()); rypos() -= textlineLineWidth * .5; } } #endif rxpos() += x; rypos() += y; } if (parent() && parent()->type() == SEGMENT) { Segment* s = static_cast<Segment*>(parent()); rypos() += s ? s->measure()->system()->staff(staffIdx())->y() : 0.0; } adjustReadPos(); }
void Marker::layout() { setPos(textStyle().offset(spatium())); Text::layout1(); // although normally laid out to parent (measure) width, // force to center over barline if left-aligned if (layoutToParentWidth() && !(textStyle().align() & (AlignmentFlags::RIGHT|AlignmentFlags::HCENTER))) rxpos() -= width() * 0.5; adjustReadPos(); }
void Marker::layout() { setPos(QPointF(0.0, score()->styleP(StyleIdx::markerPosAbove))); Text::layout1(); // although normally laid out to parent (measure) width, // force to center over barline if left-aligned if (layoutToParentWidth() && !(align() & (Align::RIGHT | Align::HCENTER))) rxpos() -= width() * 0.5; adjustReadPos(); }
void OttavaSegment::layout() { TextLineSegment::layout1(); if (parent()) { // for palette qreal yo(score()->styleS(StyleIdx::ottavaY).val() * spatium()); if (ottava()->placement() == Placement::BELOW) yo = -yo + staff()->height(); rypos() += yo; } adjustReadPos(); }
void FSymbol::layout() { QString s; if (_code & 0xffff0000) { s = QChar(QChar::highSurrogate(_code)); s += QChar(QChar::lowSurrogate(_code)); } else s = QChar(_code); QFontMetricsF fm(_font); setbbox(fm.boundingRect(s)); adjustReadPos(); }
void HBox::layout() { if (parent() && parent()->type() == VBOX) { VBox* vb = static_cast<VBox*>(parent()); qreal x = vb->leftMargin() * MScore::DPMM; qreal y = vb->topMargin() * MScore::DPMM; qreal w = point(boxWidth()); qreal h = vb->height() - (vb->topMargin() + vb->bottomMargin()) * MScore::DPMM; setPos(x, y); bbox().setRect(0.0, 0.0, w, h); } else { bbox().setRect(0.0, 0.0, point(boxWidth()), system()->height()); } Box::layout(); adjustReadPos(); }
void TrillSegment::layout() { if (parent()) rypos() += score()->styleS(StyleIdx::trillY).val() * spatium(); if (staff()) setMag(staff()->mag()); if (spannerSegmentType() == SpannerSegmentType::SINGLE || spannerSegmentType() == SpannerSegmentType::BEGIN) { Accidental* a = trill()->accidental(); if (a) { a->layout(); a->setMag(a->mag() * .6); qreal _spatium = spatium(); a->setPos(_spatium * 1.3, -2.2 * _spatium); a->adjustReadPos(); } switch (trill()->trillType()) { case Trill::Type::TRILL_LINE: symbolLine(SymId::ornamentTrill, SymId::wiggleTrill); break; case Trill::Type::PRALLPRALL_LINE: symbolLine(SymId::wiggleTrill, SymId::wiggleTrill); break; case Trill::Type::UPPRALL_LINE: if (score()->scoreFont()->isValid(SymId::ornamentBottomLeftConcaveStroke)) symbolLine(SymId::ornamentBottomLeftConcaveStroke, SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd); else symbolLine(SymId::ornamentUpPrall, // SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd); SymId::ornamentZigZagLineNoRightEnd); break; case Trill::Type::DOWNPRALL_LINE: if (score()->scoreFont()->isValid(SymId::ornamentLeftVerticalStroke)) symbolLine(SymId::ornamentLeftVerticalStroke, SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd); else symbolLine(SymId::ornamentDownPrall, // SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd); SymId::ornamentZigZagLineNoRightEnd); break; } } else symbolLine(SymId::wiggleTrill, SymId::wiggleTrill); adjustReadPos(); }
void VoltaSegment::layout() { if (autoplace()) setUserOff(QPointF()); TextLineBaseSegment::layout(); if (!parent()) return; rypos() = score()->styleP(StyleIdx::voltaY) * mag(); if (autoplace()) { qreal minDistance = spatium() * .7; Shape s1 = shape().translated(pos()); qreal d = system()->topDistance(staffIdx(), s1); if (d > -minDistance) rUserYoffset() = -d - minDistance; } else adjustReadPos(); }
void Stem::layout() { qreal l = _len + _userLen; qreal _up = up() ? -1.0 : 1.0; l *= _up; qreal y1 = 0.0; // vertical displacement to match note attach point Staff* stf = staff(); if (chord()) { int tick = chord()->tick(); StaffType* st = stf->staffType(tick); if (st->isTabStaff() ) { // TAB staves if (st->stemThrough()) { // if stems through staves, gets Y pos. of stem-side note relative to chord other side qreal lineDist = st->lineDistance().val() * spatium(); y1 = (chord()->downString() - chord()->upString()) * _up * lineDist; // if fret marks above lines, raise stem beginning by 1/2 line distance if (!st->onLines()) y1 -= lineDist * 0.5; // shorten stem by 1/2 lineDist to clear the note and a little more to keep 'air' betwen stem and note lineDist *= 0.7 * mag(); y1 += _up * lineDist; } // in other TAB types, no correction } else { // non-TAB // move stem start to note attach point Note* n = up() ? chord()->downNote() : chord()->upNote(); y1 += (up() ? n->stemUpSE().y() : n->stemDownNW().y()); rypos() = n->rypos(); } } qreal lw5 = _lineWidth * .5; line.setLine(0.0, y1, 0.0, l); // compute bounding rectangle QRectF r(line.p1(), line.p2()); setbbox(r.normalized().adjusted(-lw5, -lw5, lw5, lw5)); adjustReadPos(); // does not work if stem is layouted twice }
void TrillSegment::layout() { QRectF b1(symBbox(SymId::ornamentTrill)); QRectF rr(b1.translated(-b1.x(), 0.0)); rr |= QRectF(0.0, rr.y(), pos2().x(), rr.height()); setbbox(rr); if (parent()) rypos() += score()->styleS(ST_trillY).val() * spatium(); if (spannerSegmentType() == SEGMENT_SINGLE || spannerSegmentType() == SEGMENT_BEGIN) { Accidental* a = trill()->accidental(); if (a) { a->layout(); a->setMag(a->mag() * .6); qreal _spatium = spatium(); a->setPos(_spatium*1.3, -2.2*_spatium); a->adjustReadPos(); } } adjustReadPos(); }
void RehearsalMark::layout() { setPos(textStyle().offset(spatium())); Text::layout1(); Segment* s = segment(); if (s && !s->rtick()) { // first CR of measure, decide whether to align to barline if (!s->prev()) { // measure with no clef / keysig / timesig rxpos() -= s->x(); } else if (textStyle().align() & AlignmentFlags::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(); } } adjustReadPos(); }
void TempoText::layout() { setPos(textStyle().offset(spatium())); Text::layout1(); // tempo text on first chordrest of measure should align over time sig if present // Segment* s = segment(); if (s && !s->rtick()) { Segment* p = segment()->prev(Segment::Type::TimeSig); if (p) { rxpos() -= s->x() - p->x(); Element* e = p->element(staffIdx() * VOICES); if (e) rxpos() += e->x(); } } if (placement() == Element::Placement::BELOW) rypos() = -rypos() + 4 * spatium(); adjustReadPos(); }
void HairpinSegment::layout() { if (hairpin()->useTextLine()) { if (parent()) rypos() += score()->styleS(StyleIdx::hairpinY).val() * spatium(); TextLineSegment::layout(); return; } QTransform t; qreal _spatium = spatium(); qreal h1 = hairpin()->hairpinHeight().val() * spatium() * .5; qreal h2 = hairpin()->hairpinContHeight().val() * spatium() * .5; qreal len; qreal x = pos2().x(); if (x < _spatium) // minimum size of hairpin x = _spatium; qreal y = pos2().y(); len = sqrt(x * x + y * y); t.rotateRadians(asin(y/len)); drawCircledTip = hairpin()->hairpinCircledTip(); circledTipRadius = 0; if( drawCircledTip ) circledTipRadius = 0.6 * _spatium * .5; if (hairpin()->hairpinType() == Hairpin::Type::CRESCENDO) { // crescendo switch (spannerSegmentType()) { case SpannerSegmentType::SINGLE: case SpannerSegmentType::BEGIN: l1.setLine(.0 + circledTipRadius*2, .0, len, h1); l2.setLine(.0 + circledTipRadius*2, .0, len, -h1); circledTip.setX( 0 + circledTipRadius ); circledTip.setY( 0 ); break; case SpannerSegmentType::MIDDLE: case SpannerSegmentType::END: drawCircledTip = false; l1.setLine(.0, h2, len, h1); l2.setLine(.0, -h2, len, -h1); break; } } else { // decrescendo switch(spannerSegmentType()) { case SpannerSegmentType::SINGLE: case SpannerSegmentType::END: l1.setLine(.0, h1, len - circledTipRadius*2, 0.0); l2.setLine(.0, -h1, len - circledTipRadius*2, 0.0); circledTip.setX( len - circledTipRadius ); circledTip.setY( 0 ); break; case SpannerSegmentType::BEGIN: case SpannerSegmentType::MIDDLE: drawCircledTip = false; l1.setLine(.0, h1, len, + h2); l2.setLine(.0, -h1, len, - h2); break; } } // Do Coord rotation l1 = t.map(l1); l2 = t.map(l2); if( drawCircledTip ) circledTip = t.map(circledTip); QRectF r = QRectF(l1.p1(), l1.p2()).normalized() | QRectF(l2.p1(), l2.p2()).normalized(); qreal w = point(score()->styleS(StyleIdx::hairpinLineWidth)); setbbox(r.adjusted(-w*.5, -w*.5, w, w)); if (parent()) rypos() += score()->styleS(StyleIdx::hairpinY).val() * _spatium; adjustReadPos(); }
void Text::layout() { layout1(); adjustReadPos(); }
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)); }