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));
      }
Exemple #2
0
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));
      }
Exemple #3
0
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));
      }