LCOV - code coverage report
Current view: top level - src/engraving/rendering/score - guitardivelayout.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 17.7 % 317 56
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2023 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include "guitardivelayout.h"
      23              : 
      24              : #include "dom/guitarbend.h"
      25              : #include "dom/note.h"
      26              : #include "dom/staff.h"
      27              : #include "dom/stafftype.h"
      28              : #include "dom/system.h"
      29              : #include "dom/whammybar.h"
      30              : 
      31              : #include "horizontalspacing.h"
      32              : #include "textlayout.h"
      33              : #include "tlayout.h"
      34              : 
      35              : using namespace mu::engraving;
      36              : using namespace muse::draw;
      37              : using namespace mu::engraving::rendering::score;
      38              : 
      39         7388 : void GuitarDiveLayout::updateDiveSequences(const std::vector<GuitarBend*>& bends, const LayoutContext& ctx)
      40              : {
      41         7388 :     std::vector<GuitarBend*> dives;
      42         7814 :     for (GuitarBend* bend : bends) {
      43          426 :         if ((bend->bendType() == GuitarBendType::DIVE || bend->bendType() == GuitarBendType::PRE_DIVE) && bend->staffType()->isTabStaff()) {
      44            0 :             dives.push_back(bend);
      45              :         }
      46              :     }
      47              : 
      48         7388 :     for (GuitarBend* dive : dives) {
      49            0 :         dive->computeBendAmount();
      50            0 :         dive->mutldata()->resetDiveLevels();
      51              :     }
      52              : 
      53         7388 :     for (auto riter = dives.rbegin(); riter != dives.rend(); ++riter) {
      54            0 :         GuitarBend* dive = *riter;
      55            0 :         if (!dive->ldata()->diveLevels().empty()) {
      56            0 :             continue;
      57              :         }
      58              : 
      59              :         // On-staff vs above-staff layout
      60            0 :         DirectionV tabPos = dive->diveTabPos();
      61              : 
      62            0 :         std::set<int> diveLevels;
      63            0 :         std::unordered_set<GuitarBend*> diveSequence;
      64              : 
      65            0 :         diveLevels.insert(dive->totBendAmountIncludingPrecedingBends());
      66            0 :         diveSequence.insert(dive);
      67              : 
      68              :         // Consider dives part of the same sequence if they are directly connected
      69              :         // or if they are spanned by the same whammy bar line
      70              : 
      71            0 :         if (WhammyBar* whammyBar = dive->findOverlappingWhammyBar(dive->tick(), dive->tick2())) {
      72            0 :             for (auto riter2 = riter + 1; riter2 != dives.rend(); ++riter2) {
      73            0 :                 GuitarBend* earlierDive = *riter2;
      74            0 :                 if (earlierDive->tick() >= whammyBar->tick()) {
      75            0 :                     diveLevels.insert(earlierDive->totBendAmountIncludingPrecedingBends());
      76            0 :                     diveSequence.insert(earlierDive);
      77            0 :                     if (earlierDive->diveTabPos() != DirectionV::AUTO) {
      78            0 :                         tabPos = earlierDive->diveTabPos();
      79              :                     }
      80              :                 }
      81              :             }
      82              :         }
      83              : 
      84            0 :         GuitarBend* prevDive = dive->findPrecedingBend();
      85            0 :         while (prevDive) {
      86            0 :             diveLevels.insert(prevDive->totBendAmountIncludingPrecedingBends());
      87            0 :             diveSequence.insert(prevDive);
      88            0 :             if (prevDive->diveTabPos() != DirectionV::AUTO) {
      89            0 :                 tabPos = prevDive->diveTabPos();
      90              :             }
      91            0 :             prevDive = prevDive->findPrecedingBend();
      92              :         }
      93              : 
      94            0 :         bool layoutAboveStaff = tabPos == DirectionV::UP || (tabPos == DirectionV::AUTO && ctx.conf().styleB(Sid::guitarDivesAboveStaff));
      95              : 
      96            0 :         for (GuitarBend* d : diveSequence) {
      97            0 :             d->mutldata()->setDiveLevels(diveLevels);
      98            0 :             d->mutldata()->setAboveStaff(layoutAboveStaff);
      99              :         }
     100            0 :     }
     101         7388 : }
     102              : 
     103            0 : void GuitarDiveLayout::layoutDiveTabStaff(GuitarBendSegment* item, LayoutContext& ctx)
     104              : {
     105            0 :     GuitarBend* bend = item->guitarBend();
     106            0 :     if (bend->bendType() == GuitarBendType::DIP) {
     107            0 :         layoutDip(item, ctx);
     108            0 :         return;
     109              :     }
     110            0 :     if (bend->bendType() == GuitarBendType::SCOOP) {
     111            0 :         layoutScoop(item);
     112            0 :         return;
     113              :     }
     114              : 
     115            0 :     GuitarBendSegment::LayoutData* ldata = item->mutldata();
     116              : 
     117            0 :     Note* startNote = bend->startNote();
     118            0 :     Note* endNote = bend->endNote();
     119            0 :     if (!startNote || !endNote) {
     120            0 :         return;
     121              :     }
     122              : 
     123            0 :     Chord* startChord = startNote->chord();
     124            0 :     Chord* endChord = endNote->chord();
     125            0 :     if (startNote->string() != startChord->upString() || endNote->string() != endChord->upString()) {
     126            0 :         return; // On TAB only one dive line can exist and only from the top note
     127              :     }
     128              : 
     129            0 :     if (bend->bendType() == GuitarBendType::PRE_DIVE) {
     130            0 :         bool alignToGrace = ctx.conf().styleB(Sid::alignPreBendAndPreDiveToGraceNote);
     131            0 :         for (Note* note : startChord->notes()) {
     132            0 :             if (!note->overrideBendVisibilityRules()) {
     133            0 :                 note->setVisible(alignToGrace);
     134              :             }
     135              :         }
     136            0 :         for (Note* note : endChord->notes()) {
     137            0 :             if (!note->overrideBendVisibilityRules()) {
     138            0 :                 note->setVisible(!alignToGrace);
     139              :             }
     140              :         }
     141            0 :     } else if (bend->isFullReleaseDive() || item->isEndType()) {
     142            0 :         for (Note* note : endChord->notes()) {
     143            0 :             if (!note->overrideBendVisibilityRules()) {
     144            0 :                 note->setVisible(true);
     145              :             }
     146            0 :             note->setGhost(true);
     147            0 :             note->mutldata()->reset();
     148              :         }
     149            0 :         TLayout::layoutChord(endNote->chord(), ctx);
     150            0 :     } else if (!bend->isFullReleaseDive() || !ctx.conf().styleB(Sid::showFretOnFullBendRelease)) {
     151            0 :         for (Note* note : endChord->notes()) {
     152            0 :             if (!note->overrideBendVisibilityRules()) {
     153            0 :                 note->setVisible(false);
     154              :             }
     155              :         }
     156              :     }
     157              : 
     158            0 :     bool aboveStaff = bend->ldata()->aboveStaff();
     159            0 :     if (aboveStaff) {
     160            0 :         item->setPos(computeStartPosAboveStaff(item, ctx));
     161            0 :         item->setPos2(computeEndPosAboveStaff(item, ctx) - item->ldata()->pos());
     162              :     } else {
     163            0 :         item->setPos(computeStartPosOnStaff(item, ctx));
     164            0 :         item->setPos2(computeEndPosOnStaff(item, ctx) - item->ldata()->pos());
     165              :     }
     166              : 
     167            0 :     GuitarBendText* bendText = item->bendText();
     168            0 :     if (item->isSingleEndType()) {
     169            0 :         bendText->setXmlText(bend->ldata()->bendDigit());
     170            0 :         TextLayout::layoutBaseTextBase(bendText, ctx);
     171            0 :         double verticalTextPad = 0.35 * item->spatium();
     172            0 :         PointF bendTextPos = item->pos2();
     173            0 :         if (aboveStaff) {
     174            0 :             if (bend->bendType() == GuitarBendType::PRE_DIVE && bend->bendAmountInQuarterTones() < 0) {
     175            0 :                 bendTextPos = PointF(); // If predive is downwards the text must be above the start
     176              :             }
     177            0 :             bendTextPos += PointF(-0.5 * bendText->width(), -bendText->height() - verticalTextPad);
     178              :         } else {
     179            0 :             bendTextPos += PointF(-0.5 * bendText->width(),
     180            0 :                                   item->pos().y() + item->pos2().y() > 0 ? verticalTextPad : -bendText->height() - verticalTextPad);
     181              :         }
     182            0 :         bendText->setPos(bendTextPos);
     183              :     } else {
     184            0 :         bendText->mutldata()->reset();
     185              :     }
     186              : 
     187            0 :     PainterPath path;
     188            0 :     if (bend->isSlack()) {
     189            0 :         const double slackLineLen = 2 * item->spatium();
     190            0 :         PointF vertexPoint = item->pos2() - PointF(0.5 * slackLineLen, 0.0);
     191            0 :         path.lineTo(vertexPoint);
     192            0 :         item->setPos2(item->pos2() + PointF(0.5 * slackLineLen, 0.0));
     193              :     }
     194            0 :     path.lineTo(item->pos2());
     195            0 :     ldata->setPath(path);
     196              : 
     197            0 :     const double lineWidth = item->lineWidth();
     198            0 :     RectF r = RectF(PointF(), item->pos2()).normalized();
     199            0 :     if (muse::RealIsNull(r.height())) {
     200            0 :         r.setHeight(lineWidth);
     201              :     }
     202            0 :     if (muse::RealIsNull(r.width())) {
     203            0 :         r.setWidth(lineWidth);
     204              :     }
     205            0 :     item->mutldata()->setBbox(r);
     206            0 : }
     207              : 
     208            0 : PointF GuitarDiveLayout::computeStartPosOnStaff(GuitarBendSegment* item, LayoutContext& ctx)
     209              : {
     210            0 :     GuitarBend* bend = item->guitarBend();
     211              : 
     212            0 :     if (bend->bendType() == GuitarBendType::PRE_DIVE) {
     213            0 :         Note* note = ctx.conf().styleB(Sid::alignPreBendAndPreDiveToGraceNote) ? bend->startNote() : bend->endNote();
     214            0 :         if (bend->bendAmountInQuarterTones() > 0) {
     215            0 :             note = note->chord()->upNote();
     216              :         } else {
     217            0 :             note = note->chord()->downNote();
     218              :         }
     219            0 :         PointF notePos = note->systemPos();
     220            0 :         RectF noteBbox = getNoteAndParenthesesShape(note);
     221            0 :         double verticalPadding = 0.25 * item->spatium();
     222            0 :         notePos += PointF(0.5 * noteBbox.width(), bend->bendAmountInQuarterTones() > 0
     223            0 :                           ? noteBbox.top() - verticalPadding
     224            0 :                           : noteBbox.bottom() + verticalPadding);
     225            0 :         return notePos;
     226              :     }
     227              : 
     228            0 :     LineSegment* prevSegment = findPrevHoldOrBendSegment(item, /*excludeFullReleaseDive*/ true);
     229            0 :     if (prevSegment) {
     230            0 :         return prevSegment->pos() + prevSegment->pos2();
     231              :     }
     232              : 
     233            0 :     PointF startPos;
     234            0 :     Note* startNote = bend->startNote();
     235            0 :     RectF startNoteBbox = getNoteAndParenthesesShape(startNote);
     236            0 :     if (item->isSingleBeginType()) {
     237            0 :         startPos = startNote->systemPos();
     238            0 :         double horizontalIndent = 0.25 * item->spatium();
     239            0 :         startPos += PointF(startNoteBbox.right() + horizontalIndent, -0.5 * startNoteBbox.height() + 0.5 * item->lineWidth());
     240              :     } else {
     241            0 :         startPos.setX(item->system()->firstNoteRestSegmentX(true));
     242            0 :         startPos.setY(bend->frontSegment()->ldata()->pos().y() + bend->frontSegment()->ipos2().y());
     243              :     }
     244              : 
     245            0 :     return startPos;
     246              : }
     247              : 
     248            0 : PointF GuitarDiveLayout::computeEndPosOnStaff(GuitarBendSegment* item, LayoutContext&)
     249              : {
     250            0 :     GuitarBend* bend = item->guitarBend();
     251            0 :     double spatium = item->spatium();
     252              : 
     253            0 :     double x = 0.0;
     254            0 :     if (item->isSingleEndType()) {
     255            0 :         Note* endNote = bend->endNote();
     256            0 :         PointF endNotePos = endNote->systemPos();
     257            0 :         RectF endNoteBbox = getNoteAndParenthesesShape(endNote);
     258              : 
     259            0 :         if (bend->isFullReleaseDive()) {
     260            0 :             x = endNotePos.x() + endNoteBbox.left() - 0.25 * spatium;
     261            0 :             double y = endNotePos.y() + endNoteBbox.top() + 0.5 * item->lineWidth();
     262            0 :             return PointF(x, y);
     263              :         }
     264              : 
     265            0 :         x = bend->bendType() == GuitarBendType::PRE_DIVE ? item->pos().x() : endNotePos.x() + 0.5 * endNoteBbox.width();
     266              :     } else {
     267            0 :         x = item->system()->endingXForOpenEndedLines();
     268              : 
     269            0 :         if (bend->isFullReleaseDive()) {
     270              :             /* Full release dives end at the same y as they started, so we can use the startNote's position
     271              :              * here in the case that the segment is BEGIN type (bc its endNote hasn't been laid out yet) */
     272            0 :             Note* startNote = bend->startNote();
     273            0 :             PointF startNotePos = startNote->systemPos();
     274            0 :             RectF startNoteBbox = getNoteAndParenthesesShape(startNote);
     275            0 :             double y = startNotePos.y() + startNoteBbox.top() + 0.5 * item->lineWidth();
     276            0 :             return PointF(x, y);
     277              :         }
     278              :     }
     279              : 
     280            0 :     if (bend->bendType() == GuitarBendType::PRE_DIVE) {
     281            0 :         LineSegment* prevSegment = findPrevHoldOrBendSegment(item);
     282            0 :         if (prevSegment && prevSegment->isGuitarBendHoldSegment()) {
     283            0 :             double y = prevSegment->pos().y() + prevSegment->pos2().y();
     284            0 :             return PointF(x, y);
     285              :         }
     286              :     }
     287              : 
     288            0 :     int diveLevel = bend->totBendAmountIncludingPrecedingBends();
     289            0 :     bool aboveStaff = diveLevel > 0;
     290              : 
     291            0 :     const StaffType* staffType = item->staffType();
     292            0 :     IF_ASSERT_FAILED(staffType) {
     293            0 :         return PointF(x, 0.0);
     294              :     }
     295            0 :     int staffLines = staffType->lines();
     296            0 :     double lineDist = item->absoluteFromSpatium(staffType->lineDistance());
     297              : 
     298            0 :     if (!item->isSingleEndType()) {
     299            0 :         double y = aboveStaff ? -lineDist : staffLines * lineDist;
     300            0 :         return PointF(x, y);
     301              :     }
     302              : 
     303            0 :     const std::set<int>& diveLevels = bend->ldata()->diveLevels();
     304            0 :     std::deque<int> diveLevelsInThisDirection;
     305            0 :     for (int level : diveLevels) {
     306            0 :         if (aboveStaff && level > 0) {
     307            0 :             diveLevelsInThisDirection.push_back(level);
     308            0 :         } else if (!aboveStaff && level < 0) {
     309            0 :             diveLevelsInThisDirection.push_front(level);
     310              :         }
     311              :     }
     312              : 
     313            0 :     size_t levelNumber = muse::indexOf(diveLevelsInThisDirection, diveLevel);
     314            0 :     IF_ASSERT_FAILED(levelNumber != muse::nidx) {
     315            0 :         return PointF(x, 0.0);
     316              :     }
     317              : 
     318            0 :     double zeroDiveLevel = aboveStaff ? -1.5 * lineDist : lineDist * (staffLines + 0.5);
     319            0 :     double increment = spatium;
     320              : 
     321            0 :     double y = zeroDiveLevel + (aboveStaff ? -1 : 1) * (increment * levelNumber);
     322              : 
     323            0 :     return PointF(x, y);
     324            0 : }
     325              : 
     326            0 : PointF GuitarDiveLayout::computeStartPosAboveStaff(GuitarBendSegment* item, LayoutContext& ctx)
     327              : {
     328            0 :     GuitarBend* bend = item->guitarBend();
     329              : 
     330            0 :     LineSegment* prevSegment = findPrevHoldOrBendSegment(item);
     331            0 :     if (prevSegment) {
     332            0 :         return prevSegment->pos() + prevSegment->pos2();
     333              :     }
     334              : 
     335            0 :     PointF startPos;
     336              : 
     337            0 :     if (item->isSingleBeginType()) {
     338            0 :         Note* note = bend->bendType() == GuitarBendType::PRE_BEND && !ctx.conf().styleB(Sid::alignPreBendAndPreDiveToGraceNote)
     339            0 :                      ? bend->endNote() : bend->startNote();
     340            0 :         RectF noteBbox = getNoteAndParenthesesShape(note);
     341            0 :         startPos.setX(note->systemPos().x() + 0.5 * noteBbox.width());
     342              : 
     343            0 :         const StaffType* staffType = item->staffType();
     344            0 :         IF_ASSERT_FAILED(staffType) {
     345            0 :             startPos.setY(0.0);
     346              :         } else {
     347            0 :             double spatium = item->spatium();
     348            0 :             double lineDist = item->absoluteFromSpatium(staffType->lineDistance());
     349            0 :             const double baseLine = -1.5 * lineDist;
     350            0 :             const double increment = spatium;
     351            0 :             std::set<int> diveLevels = bend->mutldata()->diveLevels();
     352            0 :             diveLevels.insert(0); // Because for dives above the staff we need the zero level too
     353            0 :             size_t zeroLevel = muse::indexOf(diveLevels, 0);
     354            0 :             double totIncrement = increment * zeroLevel;
     355            0 :             startPos.setY(baseLine - totIncrement);
     356            0 :         }
     357              :     } else {
     358            0 :         startPos.setX(item->system()->firstNoteRestSegmentX(true));
     359            0 :         startPos.setY(bend->frontSegment()->ldata()->pos().y());
     360              :     }
     361              : 
     362            0 :     return startPos;
     363              : }
     364              : 
     365            0 : PointF GuitarDiveLayout::computeEndPosAboveStaff(GuitarBendSegment* item, LayoutContext&)
     366              : {
     367            0 :     GuitarBend* bend = item->guitarBend();
     368            0 :     double spatium = item->spatium();
     369              : 
     370            0 :     double x = 0.0;
     371            0 :     if (item->isSingleEndType()) {
     372            0 :         Note* endNote = bend->endNote();
     373            0 :         PointF endNotePos = endNote->systemPos();
     374            0 :         RectF endNoteBbox = getNoteAndParenthesesShape(endNote);
     375            0 :         x = bend->bendType() == GuitarBendType::PRE_DIVE
     376            0 :             ? item->pos().x() : endNotePos.x() + 0.5 * endNoteBbox.width();
     377              :     } else {
     378            0 :         x = item->system()->endingXForOpenEndedLines();
     379              :     }
     380              : 
     381            0 :     if (bend->bendType() == GuitarBendType::PRE_DIVE) {
     382            0 :         LineSegment* prevSegment = findPrevHoldOrBendSegment(item);
     383            0 :         if (prevSegment && prevSegment->isGuitarBendHoldSegment()) {
     384            0 :             double y = prevSegment->pos().y() + prevSegment->pos2().y();
     385            0 :             return PointF(x, y);
     386              :         }
     387              :     }
     388              : 
     389            0 :     int endingLevel = bend->totBendAmountIncludingPrecedingBends();
     390            0 :     int startingLevel = endingLevel - bend->bendAmountInQuarterTones();
     391              : 
     392            0 :     std::set<int> diveLevels = bend->ldata()->diveLevels();
     393            0 :     diveLevels.insert(0); // Because for dives above the staff we need the zero level too
     394              : 
     395            0 :     size_t endingIdx = muse::indexOf(diveLevels, endingLevel);
     396            0 :     size_t startingIdx = muse::indexOf(diveLevels, startingLevel);
     397            0 :     IF_ASSERT_FAILED(endingIdx != muse::nidx && startingIdx != muse::nidx && endingIdx != startingIdx) {
     398            0 :         return PointF(x, 0.0);
     399              :     }
     400              : 
     401            0 :     int steps = static_cast<int>(endingIdx) - static_cast<int>(startingIdx);
     402            0 :     double increment = spatium;
     403              : 
     404            0 :     double y = item->ldata()->pos().y() - steps * increment;
     405              : 
     406            0 :     return PointF(x, y);
     407            0 : }
     408              : 
     409            0 : LineSegment* GuitarDiveLayout::findPrevHoldOrBendSegment(GuitarBendSegment* item, bool excludeFullReleaseDive)
     410              : {
     411            0 :     GuitarBend* bend = item->guitarBend();
     412            0 :     GuitarBend* prevBend = item->guitarBend()->findPrecedingBend();
     413            0 :     if (!prevBend) {
     414            0 :         return nullptr;
     415              :     }
     416              : 
     417            0 :     GuitarBendHold* hold = prevBend->holdLine();
     418            0 :     if (hold && !hold->segmentsEmpty() && prevBend->endNote() != bend->startNote() && hold->backSegment()->system() == item->system()) {
     419            0 :         return hold->backSegment();
     420              :     }
     421              : 
     422            0 :     if (!prevBend->segmentsEmpty() && !(excludeFullReleaseDive && prevBend->isFullReleaseDive())
     423            0 :         && prevBend->backSegment()->system() == item->system()) {
     424            0 :         return prevBend->backSegment();
     425              :     }
     426              : 
     427            0 :     return nullptr;
     428              : }
     429              : 
     430            6 : void GuitarDiveLayout::layoutDip(GuitarBendSegment* item, LayoutContext& ctx)
     431              : {
     432            6 :     GuitarBend* bend = item->guitarBend();
     433            6 :     Note* startNote = bend->startNote();
     434            6 :     IF_ASSERT_FAILED(startNote) {
     435            0 :         return;
     436              :     }
     437              : 
     438            6 :     PointF notePos = startNote->systemPos();
     439            6 :     double centerX = notePos.x() + 0.5 * startNote->width();
     440            6 :     double spatium = item->spatium();
     441            6 :     double baseY = std::min(-spatium, notePos.y() - 0.5 * startNote->height() - spatium);
     442              : 
     443            6 :     const double vHeight = 2 * spatium;
     444            6 :     const double vWidth = 2 * spatium;
     445              : 
     446            6 :     bool upwards = bend->bendAmountInQuarterTones() > 0;
     447            6 :     PointF start = PointF(centerX - 0.5 * vWidth, upwards ? baseY : baseY - vHeight);
     448            6 :     PointF vertex = PointF(centerX, upwards ? baseY - vHeight : baseY) - start;
     449            6 :     PointF end = PointF(centerX + 0.5 * vWidth, upwards ? baseY : baseY - vHeight) - start;
     450              : 
     451            6 :     item->setPos(start);
     452            6 :     item->setPos2(end);
     453              : 
     454            6 :     PainterPath path;
     455            6 :     path.lineTo(vertex);
     456            6 :     path.lineTo(end);
     457            6 :     item->mutldata()->setPath(path);
     458              : 
     459            6 :     RectF bbox = RectF(PointF(), vertex).normalized().united(RectF(vertex, end).normalized());
     460            6 :     item->mutldata()->setBbox(bbox);
     461              : 
     462            6 :     GuitarBendText* bendText = item->bendText();
     463            6 :     bendText->setXmlText(bend->ldata()->bendDigit());
     464            6 :     TextLayout::layoutBaseTextBase(bendText, ctx);
     465            6 :     double verticalTextPad = 0.35 * item->spatium();
     466            6 :     bendText->setPos(PointF(vertex.x() - 0.5 * bendText->width(), bbox.top() - verticalTextPad - bendText->height()));
     467            6 : }
     468              : 
     469            3 : void GuitarDiveLayout::layoutScoop(GuitarBendSegment* item)
     470              : {
     471            3 :     GuitarBend* bend = item->guitarBend();
     472            3 :     Note* startNote = bend->startNote();
     473            3 :     IF_ASSERT_FAILED(startNote) {
     474            0 :         return;
     475              :     }
     476              : 
     477            3 :     const SymId scoopSym = SymId::guitarVibratoBarScoop;
     478            3 :     RectF bbox = item->symBbox(scoopSym);
     479            3 :     item->setbbox(bbox);
     480              : 
     481            3 :     PointF pos = startNote->systemPos();
     482            3 :     const double spatium = item->spatium();
     483            3 :     const double leftPad = 0.25 * spatium;
     484            3 :     const double downPad = 0.35 * spatium;
     485              : 
     486            3 :     double yMove = bbox.height();
     487            3 :     if (item->staffType() && item->staffType()->isTabStaff()) {
     488            0 :         yMove -= 0.5 * startNote->height();
     489              :     } else {
     490            3 :         yMove += startNote->line() % 2 ? 0.0 : downPad;
     491              :     }
     492              : 
     493            3 :     Shape chordShape = startNote->chord()->shape();
     494            6 :     chordShape.removeTypes({ ElementType::GUITAR_BEND, ElementType::GUITAR_BEND_SEGMENT, ElementType::BEAM });
     495              : 
     496            3 :     double xMove = -HorizontalSpacing::minHorizontalDistance(Shape(bbox.translated(0.0, startNote->y())), chordShape, spatium) - leftPad;
     497              : 
     498            3 :     startNote->chord()->segment()->staffShape(startNote->staffIdx()).add(bbox.translated(xMove, yMove + startNote->y()));
     499              : 
     500            3 :     item->setPos(pos + PointF(xMove, yMove));
     501            3 :     item->setPos2(PointF());
     502            3 : }
     503              : 
     504            0 : RectF GuitarDiveLayout::getNoteAndParenthesesShape(const Note* note)
     505              : {
     506            0 :     const NoteParenthesisInfo* parenInfo = note->parenthesisInfo();
     507            0 :     RectF noteBbox = note->ldata()->bbox();
     508              : 
     509            0 :     if (!parenInfo) {
     510            0 :         return noteBbox;
     511              :     }
     512              : 
     513            0 :     const Parenthesis* leftParen = parenInfo->leftParen();
     514            0 :     const Parenthesis* rightParen = parenInfo->rightParen();
     515              : 
     516            0 :     noteBbox.unite(leftParen->ldata()->bbox().translated(leftParen->pos() - note->pos()));
     517            0 :     noteBbox.unite(rightParen->ldata()->bbox().translated(rightParen->pos() - note->pos()));
     518              : 
     519            0 :     return noteBbox;
     520              : }
        

Generated by: LCOV version 2.0-1