void Fingering::layout() { TextBase::layout(); if (autoplace() && note()) { Chord* chord = note()->chord(); Staff* staff = chord->staff(); Part* part = staff->part(); int n = part->nstaves(); bool voices = chord->measure()->hasVoices(staff->idx()); bool below = voices ? !chord->up() : (n > 1) && (staff->rstaff() == n-1); bool tight = voices && !chord->beam(); qreal x = 0.0; qreal y = 0.0; qreal headWidth = note()->bboxRightPos(); qreal headHeight = note()->headHeight(); qreal fh = headHeight; // TODO: fingering number height if (chord->notes().size() == 1) { x = headWidth * .5; if (below) { // place fingering below note y = fh + spatium() * .4; if (tight) { y += 0.5 * spatium(); if (chord->stem()) x += 0.5 * spatium(); } else if (chord->stem() && !chord->up()) { // on stem side y += chord->stem()->height(); x -= spatium() * .4; } } else { // place fingering above note y = -headHeight - spatium() * .4; if (tight) { y -= 0.5 * spatium(); if (chord->stem()) x -= 0.5 * spatium(); } else if (chord->stem() && chord->up()) { // on stem side y -= chord->stem()->height(); x += spatium() * .4; } } } else { x -= spatium(); } setUserOff(QPointF(x, y)); } }
void Slur::slurPos(SlurPos* sp) { qreal _spatium = spatium(); Element* e1 = startElement(); Element* e2 = endElement(); if (e2 == 0) { sp->p1 = e1->pagePos(); sp->p1.rx() += e1->width(); sp->p2 = sp->p1; sp->p2.rx() += 5 * _spatium; sp->system1 = static_cast<ChordRest*>(e1)->measure()->system(); sp->system2 = sp->system1; return; } if ((e1->type() != CHORD) || (e2->type() != CHORD)) { sp->p1 = e1->pagePos(); sp->p2 = e2->pagePos(); sp->p1.rx() += e1->width(); sp->p2.rx() += e2->width(); sp->system1 = static_cast<ChordRest*>(e1)->measure()->system(); sp->system2 = static_cast<ChordRest*>(e2)->measure()->system(); return; } Chord* sc = static_cast<Chord*>(e1); Chord* ec = static_cast<Chord*>(e2); Note* note1 = _up ? sc->upNote() : sc->downNote(); Note* note2 = _up ? ec->upNote() : ec->downNote(); sp->system1 = sc->measure()->system(); sp->system2 = ec->measure()->system(); sp->p1 = sc->pagePos() - sp->system1->pagePos(); sp->p2 = ec->pagePos() - sp->system2->pagePos(); qreal xo, yo; Stem* stem1 = sc->stem(); Stem* stem2 = ec->stem(); enum SlurAnchor { SA_NONE, SA_STEM }; SlurAnchor sa1 = SA_NONE; SlurAnchor sa2 = SA_NONE; if ((sc->up() == ec->up()) && !sc->beam() && !ec->beam() && (_up == sc->up())) { if (stem1) sa1 = SA_STEM; if (stem2) sa2 = SA_STEM; } qreal __up = _up ? -1.0 : 1.0; qreal hw = note1->headWidth(); switch (sa1) { case SA_STEM: sp->p1 += sc->stemPosBeam() - sc->pagePos() + sc->stem()->p2(); sp->p1 += QPointF(0.35 * _spatium, 0.25 * _spatium); break; case SA_NONE: break; } switch(sa2) { case SA_STEM: sp->p2 += ec->stemPosBeam() - ec->pagePos() + ec->stem()->p2(); sp->p2 += QPointF(-0.35 * _spatium, 0.25 * _spatium); break; case SA_NONE: break; } // // default position: // horizontal: middle of note head // vertical: _spatium * .4 above/below note head // //------p1 bool stemPos = false; // p1 starts at chord stem side yo = note1->pos().y() + _spatium * .9 * __up; xo = hw * .5; if (stem1) { Beam* beam1 = sc->beam(); if (beam1 && (beam1->elements().back() != sc) && (sc->up() == _up)) { qreal sh = stem1->height() + _spatium; yo = sc->downNote()->pos().y() + sh * __up; xo = stem1->pos().x(); stemPos = true; } else { if (sc->up() && _up) xo = hw + _spatium * .3; // // handle case: stem up - stem down // stem down - stem up // if ((sc->up() != ec->up()) && (sc->up() == _up)) { Note* n1 = sc->up() ? sc->downNote() : sc->upNote(); Note* n2 = ec->up() ? ec->downNote() : ec->upNote(); qreal yd = n2->pos().y() - n1->pos().y(); yd *= .5; qreal sh = stem1->height(); // limit y move if (yd > 0.0) { if (yd > sh) yd = sh; } else { if (yd < - sh) yd = -sh; } stemPos = true; if ((_up && (yd < -_spatium)) || (!_up && (yd > _spatium))) yo += yd; } else if (sc->up() != _up) yo = fixArticulations(yo, sc, __up); } } if (sa1 == SA_NONE) sp->p1 += QPointF(xo, yo); //------p2 xo = hw * .5; yo = note2->pos().y() + _spatium * .9 * __up; if (stem2) { Beam* beam2 = ec->beam(); if ((stemPos && (sc->up() == ec->up())) || (beam2 && (!beam2->elements().isEmpty()) && (beam2->elements().front() != ec) && (ec->up() == _up) && (sc->noteType() == NOTE_NORMAL) ) ) { qreal sh = stem2->height() + _spatium; if (_up) yo = ec->downNote()->pos().y() - sh; else yo = ec->upNote()->pos().y() + sh; xo = stem2->pos().x(); } else if (!ec->up() && !_up) xo = -_spatium * .3 + note2->x(); // // handle case: stem up - stem down // stem down - stem up // if ((sc->up() != ec->up()) && (ec->up() == _up)) { Note* n1 = sc->up() ? sc->downNote() : sc->upNote(); Note* n2 = ec->up() ? ec->downNote() : ec->upNote(); qreal yd = n2->pos().y() - n1->pos().y(); yd *= .5; qreal mh = stem2->height(); // limit y move if (yd > 0.0) { if (yd > mh) yd = mh; } else { if (yd < - mh) yd = -mh; } if ((_up && (yd > _spatium)) || (!_up && (yd < -_spatium))) yo -= yd; } else if (ec->up() != _up) yo = fixArticulations(yo, ec, __up); } if (sa2 == SA_NONE) sp->p2 += QPointF(xo, yo); }
void Fingering::layout() { if (parent()) { Fraction tick = parent()->tick(); const Staff* st = staff(); if (st && st->isTabStaff(tick) && !st->staffType(tick)->showTabFingering()) { setbbox(QRectF()); return; } } TextBase::layout(); rypos() = 0.0; // handle placement below if (autoplace() && note()) { Note* n = note(); Chord* chord = n->chord(); bool voices = chord->measure()->hasVoices(chord->staffIdx()); bool tight = voices && chord->notes().size() == 1 && !chord->beam() && tid() != Tid::STRING_NUMBER; qreal headWidth = n->bboxRightPos(); // update offset after drag qreal rebase = 0.0; if (offsetChanged() != OffsetChange::NONE) rebase = rebaseOffset(); // temporarily exclude self from chord shape setAutoplace(false); if (layoutType() == ElementType::CHORD) { Stem* stem = chord->stem(); Segment* s = chord->segment(); Measure* m = s->measure(); qreal sp = spatium(); qreal md = minDistance().val() * sp; SysStaff* ss = m->system()->staff(chord->vStaffIdx()); Staff* vStaff = chord->staff(); // TODO: use current height at tick if (n->mirror()) rxpos() -= n->ipos().x(); rxpos() += headWidth * .5; if (placeAbove()) { if (tight) { if (chord->stem()) rxpos() -= 0.8 * sp; rypos() -= 1.5 * sp; } else { QRectF r = bbox().translated(m->pos() + s->pos() + chord->pos() + n->pos() + pos()); SkylineLine sk(false); sk.add(r.x(), r.bottom(), r.width()); qreal d = sk.minDistance(ss->skyline().north()); qreal yd = 0.0; if (d > 0.0 && isStyled(Pid::MIN_DISTANCE)) yd -= d + height() * .25; // force extra space above staff & chord (but not other fingerings) qreal top; if (chord->up() && chord->beam() && stem) { top = stem->y() + stem->bbox().top(); } else { Note* un = chord->upNote(); top = qMin(0.0, un->y() + un->bbox().top()); } top -= md; qreal diff = (bbox().bottom() + ipos().y() + yd + n->y()) - top; if (diff > 0.0) yd -= diff; if (offsetChanged() != OffsetChange::NONE) { // user moved element within the skyline // we may need to adjust minDistance, yd, and/or offset bool inStaff = placeAbove() ? r.bottom() + rebase > 0.0 : r.top() + rebase < staff()->height(); rebaseMinDistance(md, yd, sp, rebase, inStaff); } rypos() += yd; } } else { if (tight) { if (chord->stem()) rxpos() += 0.8 * sp; rypos() += 1.5 * sp; } else { QRectF r = bbox().translated(m->pos() + s->pos() + chord->pos() + n->pos() + pos()); SkylineLine sk(true); sk.add(r.x(), r.top(), r.width()); qreal d = ss->skyline().south().minDistance(sk); qreal yd = 0.0; if (d > 0.0 && isStyled(Pid::MIN_DISTANCE)) yd += d + height() * .25; // force extra space below staff & chord (but not other fingerings) qreal bottom; if (!chord->up() && chord->beam() && stem) { bottom = stem->y() + stem->bbox().bottom(); } else { Note* dn = chord->downNote(); bottom = qMax(vStaff->height(), dn->y() + dn->bbox().bottom()); } bottom += md; qreal diff = bottom - (bbox().top() + ipos().y() + yd + n->y()); if (diff > 0.0) yd += diff; if (offsetChanged() != OffsetChange::NONE) { // user moved element within the skyline // we may need to adjust minDistance, yd, and/or offset bool inStaff = placeAbove() ? r.bottom() + rebase > 0.0 : r.top() + rebase < staff()->height(); rebaseMinDistance(md, yd, sp, rebase, inStaff); } rypos() += yd; } } } else if (tid() == Tid::LH_GUITAR_FINGERING) { // place to left of note qreal left = n->shape().left(); if (left - n->x() > 0.0) rxpos() -= left; else rxpos() -= n->x(); } // for other fingering styles, do not autoplace // restore autoplace setAutoplace(true); } else if (offsetChanged() != OffsetChange::NONE) { // rebase horizontally too, as autoplace may have adjusted it rebaseOffset(false); } setOffsetChanged(false); }
void ChordRest::layoutArticulations() { if (parent() == 0 || _articulations.isEmpty()) return; qreal _spatium = spatium(); qreal _spStaff = _spatium * staff()->lineDistance(); // scaled to staff line distance for vert. pos. within a staff if (type() == Element::Type::CHORD) { if (_articulations.size() == 1) { static_cast<Chord*>(this)->layoutArticulation(_articulations[0]); return; } if (_articulations.size() == 2) { // // staccato | tenuto + marcato // Articulation* a1 = _articulations[0]; Articulation* a2 = _articulations[1]; ArticulationType st1 = a1->articulationType(); ArticulationType st2 = a2->articulationType(); if ((st2 == ArticulationType::Tenuto || st2 == ArticulationType::Staccato) && (st1 == ArticulationType::Marcato)) { qSwap(a1, a2); qSwap(st1, st2); } if ((st1 == ArticulationType::Tenuto || st1 == ArticulationType::Staccato) && (st2 == ArticulationType::Marcato)) { QPointF pt = static_cast<Chord*>(this)->layoutArticulation(a1); pt.ry() += a1->up() ? -_spStaff * .5 : _spStaff * .5; a2->layout(); a2->setUp(a1->up()); a2->setPos(pt); a2->adjustReadPos(); return; } // // staccato | tenuto + sforzato // if ((st2 == ArticulationType::Tenuto || st2 == ArticulationType::Staccato) && (st1 == ArticulationType::Sforzatoaccent)) { qSwap(a1, a2); qSwap(st1, st2); } if ((st1 == ArticulationType::Tenuto || st1 == ArticulationType::Staccato) && (st2 == ArticulationType::Sforzatoaccent)) { QPointF pt = static_cast<Chord*>(this)->layoutArticulation(a1); pt.ry() += a1->up() ? -_spStaff * .7 : _spStaff * .7; a2->layout(); a2->setUp(a1->up()); a2->setPos(pt); a2->adjustReadPos(); return; } } } qreal x = centerX(); qreal distance0 = score()->styleS(StyleIdx::propertyDistance).val() * _spatium; qreal distance1 = score()->styleS(StyleIdx::propertyDistanceHead).val() * _spatium; qreal distance2 = score()->styleS(StyleIdx::propertyDistanceStem).val() * _spatium; qreal chordTopY = upPos(); // note position of highest note qreal chordBotY = downPos(); // note position of lowest note qreal staffTopY = -distance2; qreal staffBotY = staff()->height() + distance2; // avoid collisions of staff articulations with chord notes: // gap between note and staff articulation is distance0 + 0.5 spatium if (type() == Element::Type::CHORD) { Chord* chord = static_cast<Chord*>(this); Stem* stem = chord->stem(); if (stem) { qreal y = stem->pos().y() + pos().y(); if (up() && stem->stemLen() < 0.0) y += stem->stemLen(); else if (!up() && stem->stemLen() > 0.0) y -= stem->stemLen(); if (beam()) { qreal bw = score()->styleS(StyleIdx::beamWidth).val() * _spatium; y += up() ? -bw : bw; } if (up()) staffTopY = qMin(staffTopY, qreal(y - 0.5 * _spatium)); else staffBotY = qMax(staffBotY, qreal(y + 0.5 * _spatium)); } } staffTopY = qMin(staffTopY, qreal(chordTopY - distance0 - 0.5 * _spatium)); staffBotY = qMax(staffBotY, qreal(chordBotY + distance0 + 0.5 * _spatium)); qreal dy = 0.0; int n = _articulations.size(); for (int i = 0; i < n; ++i) { Articulation* a = _articulations.at(i); // // determine MScore::Direction // if (a->direction() != MScore::Direction::AUTO) { a->setUp(a->direction() == MScore::Direction::UP); } else { if (a->anchor() == ArticulationAnchor::CHORD) a->setUp(!up()); else a->setUp(a->anchor() == ArticulationAnchor::TOP_STAFF || a->anchor() == ArticulationAnchor::TOP_CHORD); } } // // pass 1 // place tenuto and staccato // for (int i = 0; i < n; ++i) { Articulation* a = _articulations.at(i); a->layout(); ArticulationAnchor aa = a->anchor(); if ((a->articulationType() != ArticulationType::Tenuto) && (a->articulationType() != ArticulationType::Staccato)) continue; if (aa != ArticulationAnchor::CHORD && aa != ArticulationAnchor::TOP_CHORD && aa != ArticulationAnchor::BOTTOM_CHORD) continue; bool bottom; if ((aa == ArticulationAnchor::CHORD) && measure()->hasVoices(a->staffIdx())) bottom = !up(); else bottom = (aa == ArticulationAnchor::BOTTOM_CHORD) || (aa == ArticulationAnchor::CHORD && up()); bool headSide = bottom == up(); dy += distance1; qreal y; Chord* chord = static_cast<Chord*>(this); if (bottom) { int line = downLine(); y = chordBotY + dy; if (!headSide && type() == Element::Type::CHORD && chord->stem()) { Stem* stem = chord->stem(); y = chordTopY + stem->stemLen(); if (chord->beam()) y += score()->styleS(StyleIdx::beamWidth).val() * _spatium * .5; x = stem->pos().x(); int line = lrint((y+0.5*_spatium) / _spatium); if (line <= 4) // align between staff lines y = line * _spatium + _spatium * .5; else y += _spatium; } else { int lines = (staff()->lines() - 1) * 2; if (line < lines) y = (line & ~1) + 3; else y = line + 2; y *= _spatium * .5; } } else { int line = upLine(); y = chordTopY - dy; if (!headSide && type() == Element::Type::CHORD && chord->stem()) { Stem* stem = chord->stem(); y = chordBotY + stem->stemLen(); if (chord->beam()) y -= score()->styleS(StyleIdx::beamWidth).val() * _spatium * .5; x = stem->pos().x(); int line = lrint((y-0.5*_spatium) / _spatium); if (line >= 0) // align between staff lines y = line * _spatium - _spatium * .5; else y -= _spatium; } else { if (line > 0) y = ((line+1) & ~1) - 3; else y = line - 2; y *= _spatium * .5; } } dy += _spatium * .5; a->setPos(x, y); } // reserve space for slur bool botGap = false; bool topGap = false; #if 0 // TODO-S: optimize for (Spanner* sp = _spannerFor; sp; sp = sp->next()) { if (sp->type() != SLUR) continue; Slur* s = static_cast<Slur*>(sp); if (s->up()) topGap = true; else botGap = true; } for (Spanner* sp = _spannerBack; sp; sp = sp->next()) { if (sp->type() != SLUR) continue; Slur* s = static_cast<Slur*>(sp); if (s->up()) topGap = true; else botGap = true; } #endif if (botGap) chordBotY += _spatium; if (topGap) chordTopY -= _spatium; // // pass 2 // place all articulations with anchor at chord/rest // n = _articulations.size(); for (int i = 0; i < n; ++i) { Articulation* a = _articulations.at(i); a->layout(); ArticulationAnchor aa = a->anchor(); if ((a->articulationType() == ArticulationType::Tenuto) || (a->articulationType() == ArticulationType::Staccato)) continue; if (aa != ArticulationAnchor::CHORD && aa != ArticulationAnchor::TOP_CHORD && aa != ArticulationAnchor::BOTTOM_CHORD) continue; // for tenuto and staccate check for staff line collision bool staffLineCT = a->articulationType() == ArticulationType::Tenuto || a->articulationType() == ArticulationType::Staccato; // qreal sh = a->bbox().height() * mag(); bool bottom = (aa == ArticulationAnchor::BOTTOM_CHORD) || (aa == ArticulationAnchor::CHORD && up()); dy += distance1; if (bottom) { qreal y = chordBotY + dy; if (staffLineCT && (y <= staffBotY -.1 - dy)) { qreal l = y / _spatium; qreal delta = fabs(l - round(l)); if (delta < 0.4) { y += _spatium * .5; dy += _spatium * .5; } } a->setPos(x, y); // - a->bbox().y() + a->bbox().height() * .5); } else { qreal y = chordTopY - dy; if (staffLineCT && (y >= (staffTopY +.1 + dy))) { qreal l = y / _spatium; qreal delta = fabs(l - round(l)); if (delta < 0.4) { y -= _spatium * .5; dy += _spatium * .5; } } a->setPos(x, y); // + a->bbox().y() - a->bbox().height() * .5); } } // // pass 3 // now place all articulations with staff top or bottom anchor // qreal dyTop = staffTopY; qreal dyBot = staffBotY; /* if ((upPos() - _spatium) < dyTop) dyTop = upPos() - _spatium; if ((downPos() + _spatium) > dyBot) dyBot = downPos() + _spatium; */ for (int i = 0; i < n; ++i) { Articulation* a = _articulations.at(i); ArticulationAnchor aa = a->anchor(); if (aa == ArticulationAnchor::TOP_STAFF || aa == ArticulationAnchor::BOTTOM_STAFF) { if (a->up()) { a->setPos(x, dyTop); dyTop -= distance0; } else { a->setPos(x, dyBot); dyBot += distance0; } } a->adjustReadPos(); } }