LCOV - code coverage report
Current view: top level - src/engraving/dom - barline.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 41.5 % 518 215
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) 2021 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              : 
      23              : #include "barline.h"
      24              : 
      25              : #include "translation.h"
      26              : 
      27              : #include "../types/symnames.h"
      28              : 
      29              : #include "articulation.h"
      30              : #include "marker.h"
      31              : #include "masterscore.h"
      32              : #include "measure.h"
      33              : #include "part.h"
      34              : #include "playcounttext.h"
      35              : #include "score.h"
      36              : #include "segment.h"
      37              : #include "spanner.h"
      38              : #include "staff.h"
      39              : #include "stafflines.h"
      40              : #include "stafftype.h"
      41              : #include "system.h"
      42              : 
      43              : #include "log.h"
      44              : 
      45              : using namespace mu;
      46              : using namespace muse;
      47              : using namespace muse::draw;
      48              : using namespace mu::engraving;
      49              : using namespace mu::engraving::read400;
      50              : 
      51              : //---------------------------------------------------------
      52              : //   BarLineTable
      53              : //---------------------------------------------------------
      54              : 
      55              : const std::vector<BarLineTableItem> BarLine::barLineTable {
      56              :     { BarLineType::NORMAL,           SymNames::userNameForSymId(SymId::barlineSingle) },
      57              :     { BarLineType::DOUBLE,           SymNames::userNameForSymId(SymId::barlineDouble) },
      58              :     { BarLineType::START_REPEAT,     SymNames::userNameForSymId(SymId::repeatLeft) },
      59              :     { BarLineType::END_REPEAT,       SymNames::userNameForSymId(SymId::repeatRight) },
      60              :     { BarLineType::BROKEN,           SymNames::userNameForSymId(SymId::barlineDashed) },
      61              :     { BarLineType::END,              SymNames::userNameForSymId(SymId::barlineFinal) },
      62              :     { BarLineType::END_START_REPEAT, SymNames::userNameForSymId(SymId::repeatRightLeft) },
      63              :     { BarLineType::DOTTED,           SymNames::userNameForSymId(SymId::barlineDotted) },
      64              :     { BarLineType::REVERSE_END,      SymNames::userNameForSymId(SymId::barlineReverseFinal) },
      65              :     { BarLineType::HEAVY,            SymNames::userNameForSymId(SymId::barlineHeavy) },
      66              :     { BarLineType::DOUBLE_HEAVY,     SymNames::userNameForSymId(SymId::barlineHeavyHeavy) },
      67              : };
      68              : 
      69              : //---------------------------------------------------------
      70              : //   translatedUserTypeName
      71              : //---------------------------------------------------------
      72              : 
      73            0 : String BarLine::translatedUserTypeName(BarLineType t)
      74              : {
      75            0 :     for (const auto& i : barLineTable) {
      76            0 :         if (i.type == t) {
      77            0 :             return i.userName.translated();
      78              :         }
      79              :     }
      80            0 :     return String();
      81              : }
      82              : 
      83              : //---------------------------------------------------------
      84              : //   BarLine
      85              : //---------------------------------------------------------
      86              : 
      87        27880 : BarLine::BarLine(DummyParentOr<Segment> parent)
      88        27880 :     : EngravingItem(ElementType::BAR_LINE, parent)
      89              : {
      90        27880 :     setHeight(4 * spatium());   // for use in palettes
      91        27880 : }
      92              : 
      93          167 : BarLine::BarLine(const BarLine& bl)
      94          167 :     : EngravingItem(bl)
      95              : {
      96          167 :     m_spanStaff   = bl.m_spanStaff;
      97          167 :     m_spanFrom    = bl.m_spanFrom;
      98          167 :     m_spanTo      = bl.m_spanTo;
      99          167 :     m_barLineType = bl.m_barLineType;
     100          167 :     m_playCount   = bl.m_playCount;
     101              : 
     102          167 :     for (EngravingItem* e : bl.m_el) {
     103            0 :         add(e->clone());
     104              :     }
     105          167 : }
     106              : 
     107        52196 : BarLine::~BarLine()
     108              : {
     109        26098 :     muse::DeleteAll(m_el);
     110        52196 : }
     111              : 
     112           19 : void BarLine::setOwnershipParent(DummyParentOr<Segment> parent)
     113              : {
     114           19 :     EngravingItem::setOwnershipParent(parent);
     115           19 : }
     116              : 
     117              : //---------------------------------------------------------
     118              : //   canvasPos
     119              : //---------------------------------------------------------
     120              : 
     121            0 : PointF BarLine::canvasPos() const
     122              : {
     123            0 :     PointF pos = EngravingItem::canvasPos();
     124            0 :     if (ownershipParent()) {
     125            0 :         System* system = measure()->system();
     126            0 :         double yoff = system ? system->staff(staffIdx())->y() : 0.0;
     127            0 :         pos.ry() += yoff;
     128              :     }
     129            0 :     return pos;
     130              : }
     131              : 
     132              : //---------------------------------------------------------
     133              : //   pagePos
     134              : //---------------------------------------------------------
     135              : 
     136         8604 : PointF BarLine::pagePos() const
     137              : {
     138         8604 :     if (segment() == 0) {
     139            0 :         return pos();
     140              :     }
     141         8604 :     System* system = segment()->measure()->system();
     142              : 
     143         8604 :     double yp = y();
     144         8604 :     if (system) {
     145              :         // get first not hidden staff
     146         8604 :         staff_idx_t startIdx = staffIdx();
     147         8604 :         staff_idx_t endIdx = startIdx + (spanStaff() ? 1 : 0);
     148         8604 :         staff_idx_t staffIdx1 = startIdx;
     149         8604 :         Staff* staff1       = score()->staff(staffIdx1);
     150         8604 :         SysStaff* sysStaff1 = system->staff(staffIdx1);
     151              : 
     152         8604 :         while (staff1 && sysStaff1 && !(sysStaff1->show() && staff1->show())) {
     153            0 :             if (++staffIdx1 >= endIdx) {
     154              :                 // no visible staves spanned; just use first
     155            0 :                 staffIdx1 = startIdx;
     156            0 :                 break;
     157              :             }
     158            0 :             staff1 = score()->staff(staffIdx1);
     159            0 :             sysStaff1 = system->staff(staffIdx1);
     160              :         }
     161         8604 :         yp += system->staffYpage(staffIdx1);
     162              :     }
     163         8604 :     return PointF(pageX(), yp);
     164              : }
     165              : 
     166              : //---------------------------------------------------------
     167              : //   prevVisiblespannedStaff
     168              : //---------------------------------------------------------
     169              : 
     170           10 : static staff_idx_t prevVisibleSpannedStaff(const BarLine* bl)
     171              : {
     172           10 :     Score* score = bl->score();
     173           10 :     int staffIdx = static_cast<int>(bl->staffIdx());
     174           10 :     Segment* segment = bl->segment();
     175           10 :     for (int i = staffIdx - 1; i >= 0; --i) {
     176           10 :         BarLine* nbl = toBarLine(segment->element(i * VOICES));
     177           10 :         if (!nbl || !nbl->spanStaff()) {
     178            0 :             break;
     179              :         }
     180           10 :         Staff* s = score->staff(i);
     181           10 :         if (s->part()->show() && bl->measure()->visible(i)) {
     182           10 :             return i;
     183              :         }
     184              :     }
     185            0 :     return staffIdx;
     186              : }
     187              : 
     188              : //---------------------------------------------------------
     189              : //   nextVisiblespannedStaff
     190              : //---------------------------------------------------------
     191              : 
     192        15851 : static size_t nextVisibleSpannedStaff(const BarLine* bl)
     193              : {
     194        15851 :     Score* score = bl->score();
     195        15851 :     size_t nstaves = score->nstaves();
     196        15851 :     size_t staffIdx = bl->staffIdx();
     197        15851 :     Segment* segment = bl->segment();
     198        17037 :     for (size_t i = staffIdx + 1; i < nstaves; ++i) {
     199        12386 :         Staff* s = score->staff(i);
     200        12386 :         if (s->part()->show()) {
     201              :             // span/show bar line if this measure is visible
     202        10744 :             if (bl->measure()->visible(i)) {
     203        10336 :                 return i;
     204              :             }
     205              :             // or if this is an endBarLine and:
     206          408 :             if (segment && segment->isEndBarLineType()) {
     207              :                 // ...this measure contains a (cutaway) courtesy clef only
     208          286 :                 if (bl->measure()->isCutawayClef(i)) {
     209            0 :                     return i;
     210              :                 }
     211              :                 // ...or next measure is both visible and in the same system
     212          286 :                 Measure* nm = bl->measure()->nextMeasure();
     213          286 :                 if ((nm ? nm->visible(i) : false) && (nm ? nm->system() == bl->measure()->system() : false)) {
     214            0 :                     return i;
     215              :                 }
     216              :             }
     217              :         }
     218         2050 :         BarLine* nbl = toBarLine(segment->element(i * VOICES));
     219         2050 :         if (!nbl || !nbl->spanStaff()) {
     220          864 :             break;
     221              :         }
     222              :     }
     223         5515 :     return staffIdx;
     224              : }
     225              : 
     226              : //---------------------------------------------------------
     227              : //   calcY
     228              : //---------------------------------------------------------
     229              : 
     230        55635 : void BarLine::calcY()
     231              : {
     232        55635 :     BarLine::LayoutData* data = mutldata();
     233        55635 :     double _spatium = spatium();
     234        55635 :     if (!ownershipParent()) {
     235              :         // for use in palette
     236            0 :         data->y1 = m_spanFrom * _spatium * .5;
     237            0 :         data->y2 = (8 - m_spanTo) * _spatium * .5;
     238            0 :         return;
     239              :     }
     240        55635 :     staff_idx_t staffIdx1 = staffIdx();
     241        55635 :     staff_idx_t staffIdx2 = m_spanStaff ? nextVisibleSpannedStaff(this) : staffIdx1;
     242              : 
     243        55635 :     bool spanStaff = staffIdx2 != staffIdx1;
     244              : 
     245        55635 :     Measure* measure = segment()->measure();
     246        55635 :     System* system = measure->system();
     247        55635 :     if (!system) {
     248            0 :         return;
     249              :     }
     250              : 
     251        55635 :     Fraction tick = segment()->measure()->tick();
     252        55635 :     const Staff* staff1 = score()->staff(staffIdx1);
     253        55635 :     const StaffType* staffType1 = staff1->staffType(tick);
     254              : 
     255        55635 :     bool oneLine = staffType1->lines() <= 1;
     256              : 
     257        55635 :     int from = m_spanFrom;
     258        55635 :     int to = m_spanTo;
     259              : 
     260        55635 :     if (oneLine && m_spanFrom == 0 && m_spanTo == 0) {
     261           53 :         from = BARLINE_SPAN_1LINESTAFF_FROM;
     262           53 :         if (!spanStaff) {
     263           46 :             to = BARLINE_SPAN_1LINESTAFF_TO;
     264              :         }
     265              :     }
     266              : 
     267        55635 :     double spatium1 = staffType1->spatium();
     268        55635 :     double lineDistance = staffType1->lineDistance().val() * spatium1;
     269        55635 :     double offset = staffType1->yoffset().val() * spatium1;
     270        55635 :     double lineWidth = style().styleS(Sid::staffLineWidth).val() * spatium1 * .5;
     271              : 
     272        55635 :     double y1 = offset + from * lineDistance * .5 - lineWidth;
     273        55635 :     double y2 = offset + (staffType1->lines() * 2 - 2 + to) * lineDistance * .5 + lineWidth;
     274              : 
     275        55635 :     if (spanStaff) {
     276              :         // we need spatium and line distance of bottom staff
     277              :         // as it may be scalled diferently
     278        10326 :         const Staff* staff2 = score()->staff(staffIdx2);
     279        10326 :         const StaffType* staffType2 = staff2 ? staff2->staffType(tick) : staffType1;
     280        10326 :         double spatium2 = staffType2->spatium();
     281        10326 :         double lineDistance2 = staffType2->lineDistance().val() * spatium2;
     282        10326 :         double startStaffY = system->staff(staffIdx1)->y();
     283              : 
     284        10326 :         y2 = measure->staffLines(staffIdx2)->y1() - startStaffY - to * lineDistance2 * 0.5;
     285              : 
     286              :         // if bottom staff is single line, set span-to zeropoint to the top of the standard barline
     287        10326 :         if (staffType2->lines() <= 1) {
     288            8 :             y2 += BARLINE_SPAN_1LINESTAFF_FROM * lineDistance2 * 0.5;
     289              :         }
     290              :     }
     291              : 
     292              :     // if stafftype change in next measure, check new staff positions
     293        55635 :     Fraction tickNext = tick + measure->ticks();
     294        55635 :     if (staff1->isStaffTypeStartFrom(tickNext)) {
     295           19 :         Measure* measureNext = measure->nextMeasure();
     296           19 :         System* systemNext = measureNext ? measureNext->system() : nullptr;
     297           19 :         const StaffType* staffType1Next = staff1->staffType(tickNext);
     298           19 :         bool oneLineNext = staffType1Next->lines() <= 1;
     299           19 :         if (systemNext && systemNext == system && staffType1Next != staffType1) {
     300           19 :             if (oneLine && !oneLineNext) {
     301            0 :                 from = m_spanFrom;
     302            0 :                 to = m_spanTo;
     303              :             }
     304           19 :             if (oneLineNext && m_spanFrom == 0 && m_spanTo == 0) {
     305            0 :                 from = BARLINE_SPAN_1LINESTAFF_FROM;
     306            0 :                 if (!spanStaff) {
     307            0 :                     to = BARLINE_SPAN_1LINESTAFF_TO;
     308              :                 }
     309              :             }
     310           19 :             double spatium1Next = staffType1Next->spatium();
     311           19 :             double lineDistanceNext = staffType1Next->lineDistance().val() * spatium1Next;
     312           19 :             double offsetNext = staffType1Next->yoffset().val() * spatium1Next;
     313           19 :             double lineWidthNext = style().styleS(Sid::staffLineWidth).val() * spatium1Next * .5;
     314              : 
     315           19 :             int y1Next = offsetNext + from * lineDistanceNext * .5 - lineWidthNext;
     316              : 
     317              :             // change barline, only if it is not initial one
     318           19 :             if (rtick().isNotZero()) {
     319           19 :                 if (y1Next < y1) {
     320            0 :                     y1 = y1Next;
     321              :                 }
     322              : 
     323           19 :                 if (!spanStaff) {
     324            0 :                     double y2Next = offsetNext + (staffType1Next->lines() * 2 - 2 + to) * lineDistanceNext * .5 + lineWidthNext;
     325            0 :                     if (y2Next > y2) {
     326            0 :                         y2 = y2Next;
     327              :                     }
     328              :                 }
     329              :             }
     330              :         }
     331              :     }
     332              : 
     333        55635 :     data->y1 = y1;
     334        55635 :     data->y2 = y2;
     335              : }
     336              : 
     337              : //---------------------------------------------------------
     338              : //   isTop
     339              : //---------------------------------------------------------
     340              : 
     341           20 : bool BarLine::isTop() const
     342              : {
     343           20 :     staff_idx_t idx = staffIdx();
     344           20 :     if (idx == 0) {
     345           10 :         return true;
     346              :     } else {
     347           10 :         return prevVisibleSpannedStaff(this) == idx;
     348              :     }
     349              : }
     350              : 
     351              : //---------------------------------------------------------
     352              : //   isBottom
     353              : //---------------------------------------------------------
     354              : 
     355           20 : bool BarLine::isBottom() const
     356              : {
     357           20 :     if (!m_spanStaff) {
     358           10 :         return true;
     359              :     }
     360           10 :     size_t idx = staffIdx();
     361           10 :     if (idx == score()->nstaves() - 1) {
     362            0 :         return true;
     363              :     } else {
     364           10 :         return nextVisibleSpannedStaff(this) == idx;
     365              :     }
     366              : }
     367              : 
     368              : //---------------------------------------------------------
     369              : //   acceptDrop
     370              : //---------------------------------------------------------
     371              : 
     372            0 : bool BarLine::acceptDrop(EditData& data) const
     373              : {
     374            0 :     EngravingItem* e = data.dropElement;
     375              : 
     376            0 :     if (e->isBarLine()) {
     377            0 :         return true;
     378            0 :     } else if (e->isFermata() || e->isSymbol() || e->isImage()) {
     379            0 :         return segment() && segment()->isEndBarLineType();
     380            0 :     } else if (e->isMeasureNumber() || e->isJump() || e->isMarker() || e->isLayoutBreak()) {
     381            0 :         if (Measure* m = measure()) {
     382            0 :             bool left = (e->isMarker() && !toMarker(e)->isRightMarker()) || e->isMeasureNumber();
     383            0 :             if (left && segment()->isEndBarLineType() && m->nextMeasureMM()) {
     384            0 :                 m = m->nextMeasureMM();
     385              :             }
     386            0 :             return m->acceptDrop(data);
     387              :         }
     388              :     }
     389            0 :     return false;
     390              : }
     391              : 
     392              : //---------------------------------------------------------
     393              : //   drop
     394              : //---------------------------------------------------------
     395              : 
     396           12 : EngravingItem* BarLine::drop(Transaction& tx, EditData& data)
     397              : {
     398           12 :     EngravingItem* e = data.dropElement;
     399              : 
     400           12 :     if (e->isBarLine()) {
     401           12 :         BarLine* bl    = toBarLine(e);
     402           12 :         BarLineType st = bl->barLineType();
     403              : 
     404           12 :         if (segment()->segmentType() == SegmentType::BarLine) {
     405              :             // barline exists mid measure
     406            0 :             undoChangeProperty(Pid::BARLINE_TYPE, st);
     407            0 :             undoChangeProperty(Pid::BARLINE_SPAN, false);
     408            0 :             undoChangeProperty(Pid::BARLINE_SPAN_FROM, bl->spanFrom());
     409            0 :             undoChangeProperty(Pid::BARLINE_SPAN_TO, bl->spanTo());
     410              :         } else {
     411              :             // check if the new property can apply to this single bar line
     412           12 :             BarLineType bt = BarLineType::START_REPEAT | BarLineType::END_REPEAT | BarLineType::END_START_REPEAT;
     413           12 :             bool oldRepeat = barLineType() & bt;
     414           12 :             bool newRepeat = bl->barLineType() & bt;
     415              : 
     416           12 :             Measure* m = measure();
     417           12 :             if (bl->playCount() != -1) {
     418            0 :                 m->undoChangeProperty(Pid::REPEAT_COUNT, bl->playCount());
     419              :             }
     420              : 
     421              :             // if ctrl was used and repeats are not involved,
     422              :             // or if drop refers to span rather than subtype =>
     423              :             // single bar line drop
     424              : 
     425           12 :             if ((data.control() && !oldRepeat && !newRepeat) || (bl->spanFrom() || bl->spanTo())) {
     426              :                 // if drop refers to span, update this bar line span
     427            0 :                 if (bl->spanFrom() || bl->spanTo()) {
     428              :                     // if dropped spanFrom or spanTo are below the middle of standard staff (5 lines)
     429              :                     // adjust to the number of staff lines
     430            0 :                     int spanFrom   = bl->spanFrom();
     431            0 :                     int spanTo     = bl->spanTo();
     432            0 :                     undoChangeProperty(Pid::BARLINE_SPAN, false);
     433            0 :                     undoChangeProperty(Pid::BARLINE_SPAN_FROM, spanFrom);
     434            0 :                     undoChangeProperty(Pid::BARLINE_SPAN_TO, spanTo);
     435              :                 }
     436              :                 // if drop refers to subtype, update this bar line subtype
     437              :                 else {
     438            0 :                     score()->undoChangeBarLineType(this, st, false);
     439              :                 }
     440              :             } else {
     441           12 :                 score()->undoChangeBarLineType(this, st, true);
     442              :             }
     443           12 :             score()->undoUpdatePlayCountText(m);
     444              :         }
     445           12 :         delete e;
     446            0 :     } else if (e->isArticulationFamily()) {
     447            0 :         Articulation* atr = toArticulation(e);
     448            0 :         atr->setOwnershipParent(this);
     449            0 :         atr->setTrack(track());
     450            0 :         score()->undoAddElement(atr);
     451            0 :         return atr;
     452            0 :     } else if (e->isSymbol() || e->isImage()) {
     453            0 :         e->setOwnershipParent(this);
     454            0 :         e->setTrack(track());
     455            0 :         score()->undoAddElement(e);
     456            0 :         return e;
     457            0 :     } else if (e->isFermata()) {
     458            0 :         e->setPlacement(track() & 1 ? PlacementV::BELOW : PlacementV::ABOVE);
     459            0 :         for (EngravingItem* el: segment()->annotations()) {
     460            0 :             if (el->isFermata() && (el->track() == track())) {
     461            0 :                 if (el->subtype() == e->subtype()) {
     462            0 :                     delete e;
     463            0 :                     return el;
     464              :                 } else {
     465            0 :                     e->setPlacement(el->placement());
     466            0 :                     e->setTrack(track());
     467            0 :                     e->setOwnershipParent(segment());
     468            0 :                     score()->undoChangeElement(el, e);
     469            0 :                     return e;
     470              :                 }
     471              :             }
     472              :         }
     473            0 :         e->setTrack(track());
     474            0 :         e->setOwnershipParent(segment());
     475            0 :         score()->undoAddElement(e);
     476            0 :         return e;
     477            0 :     } else if (e->isMeasureNumber() || e->isJump() || e->isMarker() || e->isLayoutBreak()) {
     478            0 :         if (Measure* m = measure()) {
     479            0 :             bool left = (e->isMarker() && !toMarker(e)->isRightMarker()) || e->isMeasureNumber();
     480            0 :             if (left && segment()->isEndBarLineType() && m->nextMeasureMM()) {
     481            0 :                 m = m->nextMeasureMM();
     482              :             }
     483            0 :             return m->drop(tx, data);
     484              :         }
     485              :     }
     486           12 :     return nullptr;
     487              : }
     488              : 
     489              : //---------------------------------------------------------
     490              : //   setShowTips
     491              : //---------------------------------------------------------
     492              : 
     493            0 : void BarLine::setShowTips(bool val)
     494              : {
     495            0 :     if (!score()) {
     496            0 :         return;
     497              :     }
     498              : 
     499            0 :     score()->undoChangeStyleVal(Sid::repeatBarTips, val);
     500              : }
     501              : 
     502              : //---------------------------------------------------------
     503              : //   showTips
     504              : //---------------------------------------------------------
     505              : 
     506            0 : bool BarLine::showTips() const
     507              : {
     508            0 :     if (!score()) {
     509            0 :         return false;
     510              :     }
     511              : 
     512            0 :     return style().styleB(Sid::repeatBarTips);
     513              : }
     514              : 
     515            0 : void BarLine::setSelected(bool f)
     516              : {
     517            0 :     if (f == selected()) {
     518            0 :         return;
     519              :     }
     520              : 
     521            0 :     if (playCountText()) {
     522            0 :         playCountText()->setSelected(f);
     523              :     }
     524            0 :     EngravingItem::setSelected(f);
     525              : }
     526              : 
     527              : //---------------------------------------------------------
     528              : //   gripsPositions
     529              : //---------------------------------------------------------
     530              : 
     531            0 : std::vector<PointF> BarLine::gripsPositions(const EditData& ed) const
     532              : {
     533            0 :     const BarLineEditData* bed = static_cast<const BarLineEditData*>(ed.getData(this).get());
     534              : 
     535            0 :     double lw = style().styleAbsolute(Sid::barWidth) * staff()->staffMag(tick());
     536            0 :     const_cast<BarLine*>(this)->calcY();
     537              : 
     538            0 :     const PointF pp = pagePos();
     539              : 
     540              :     return {
     541              :         //PointF(lw * .5, y1 + bed->yoff1) + pp,
     542            0 :         PointF(lw * .5, ldata()->y2 + bed->yoff2) + pp
     543            0 :     };
     544              : }
     545              : 
     546         1794 : void BarLine::styleChanged()
     547              : {
     548         1794 :     if (ownershipParent() && m_barLineType == BarLineType::END_REPEAT) {
     549            2 :         score()->undoUpdatePlayCountText(measure());
     550              :     }
     551         1794 :     EngravingItem::styleChanged();
     552         1794 : }
     553              : 
     554              : //---------------------------------------------------------
     555              : //   startEdit
     556              : //---------------------------------------------------------
     557              : 
     558            0 : void BarLine::startEdit(EditData& ed)
     559              : {
     560            0 :     std::shared_ptr<BarLineEditData> bed = std::make_shared<BarLineEditData>();
     561            0 :     bed->e     = this;
     562            0 :     bed->yoff1 = 0;
     563            0 :     bed->yoff2 = 0;
     564            0 :     ed.addData(bed);
     565            0 : }
     566              : 
     567            0 : bool BarLine::isEditAllowed(EditData& ed) const
     568              : {
     569            0 :     return (ed.key == Key_Up && spanStaff()) || (ed.key == Key_Down && !spanStaff())
     570            0 :            || EngravingItem::isEditAllowed(ed);
     571              : }
     572              : 
     573            0 : bool BarLine::edit(EditData& ed)
     574              : {
     575            0 :     if (!isEditAllowed(ed)) {
     576            0 :         return false;
     577              :     }
     578              : 
     579            0 :     bool local = ed.control() || segment()->isBarLineType() || spanStaff() != score()->staff(staffIdx())->barLineSpan();
     580            0 :     if ((ed.key == Key_Up && spanStaff()) || (ed.key == Key_Down && !spanStaff())) {
     581            0 :         if (local) {
     582            0 :             BarLine* b = toBarLine(segment()->element(staffIdx() * VOICES));
     583            0 :             if (b) {
     584            0 :                 b->undoChangeProperty(Pid::BARLINE_SPAN, !spanStaff());
     585              :             }
     586              :         } else {
     587            0 :             score()->staff(staffIdx())->undoChangeProperty(Pid::STAFF_BARLINE_SPAN, !spanStaff());
     588              :         }
     589            0 :         return true;
     590              :     }
     591            0 :     return EngravingItem::edit(ed);
     592              : }
     593              : 
     594              : //---------------------------------------------------------
     595              : //   dragGrip
     596              : //---------------------------------------------------------
     597              : 
     598            0 : void BarLine::dragGrip(EditData& ed)
     599              : {
     600            0 :     IF_ASSERT_FAILED(ed.curGrip == Grip::START) {
     601            0 :         return;
     602              :     }
     603              : 
     604            0 :     BarLineEditData* bed = static_cast<BarLineEditData*>(ed.getData(this).get());
     605              : 
     606            0 :     double lineDist = staff()->lineDistance(tick()) * spatium();
     607            0 :     calcY();
     608              : 
     609              :     // min for bottom grip is 1 line below top grip
     610            0 :     const double min = ldata()->y1 - ldata()->y2 + lineDist;
     611              :     // max is the bottom of the system
     612            0 :     const System* system = segment() ? segment()->system() : nullptr;
     613            0 :     const staff_idx_t st = staffIdx();
     614            0 :     const double max = (system && st != muse::nidx)
     615            0 :                        ? (system->height() - ldata()->y2 - system->staff(st)->y())
     616            0 :                        : std::numeric_limits<double>::max();
     617              :     // update yoff2 and bring it within limit
     618            0 :     bed->yoff2 += ed.delta.y();
     619            0 :     if (bed->yoff2 < min) {
     620            0 :         bed->yoff2 = min;
     621              :     }
     622            0 :     if (bed->yoff2 > max) {
     623            0 :         bed->yoff2 = max;
     624              :     }
     625              : }
     626              : 
     627              : //---------------------------------------------------------
     628              : //   endDragGrip
     629              : //    snap to nearest staff / staff line
     630              : //---------------------------------------------------------
     631              : 
     632            0 : void BarLine::endDragGrip(EditData& ed)
     633              : {
     634            0 :     calcY();
     635            0 :     BarLineEditData* bed = static_cast<BarLineEditData*>(ed.getData(this).get());
     636              : 
     637            0 :     double ay0      = pagePos().y();
     638            0 :     double ay2      = ay0 + ldata()->y2 + bed->yoff2;             // absolute (page-relative) bar line bottom coord
     639            0 :     staff_idx_t staffIdx1 = staffIdx();
     640            0 :     System* syst   = segment()->measure()->system();
     641            0 :     double systTopY = syst->pagePos().y();
     642              : 
     643              :     // determine new span value
     644              :     staff_idx_t staffIdx2;
     645            0 :     size_t numOfStaves = syst->staves().size();
     646            0 :     if (staffIdx1 + 1 >= numOfStaves) {
     647              :         // if initial staff is last staff, ending staff must be the same
     648            0 :         staffIdx2 = staffIdx1;
     649              :     } else {
     650              :         // if there are other staves after it, look for staff nearest to bar line bottom coord
     651            0 :         double staff1TopY = syst->staff(staffIdx1)->y() + systTopY;
     652              : 
     653            0 :         for (staffIdx2 = staffIdx1 + 1; staffIdx2 < numOfStaves; ++staffIdx2) {
     654              :             // compute 1st staff height, absolute top Y of 2nd staff and height of blank between the staves
     655            0 :             Staff* staff1      = score()->staff(staffIdx2 - 1);
     656            0 :             double staff1Hght    = staff1->staffHeight(tick());
     657            0 :             double staff2TopY    = systTopY + syst->staff(staffIdx2)->y();
     658            0 :             double blnkBtwnStaff = staff2TopY - staff1TopY - staff1Hght;
     659              :             // if bar line bottom coord is above than mid-way of blank between staves...
     660            0 :             if (ay2 < (staff1TopY + staff1Hght + blnkBtwnStaff * .5)) {
     661            0 :                 break;                          // ...staff 1 is ending staff
     662              :             }
     663              :             // if bar line is below, advance to next staff
     664            0 :             staff1TopY = staff2TopY;
     665              :         }
     666            0 :         staffIdx2 -= 1;
     667              :     }
     668              : 
     669              :     // determine new spanFrom and spanTo values
     670            0 :     int newSpanFrom = 0;
     671            0 :     int newSpanTo = 0;
     672              : 
     673            0 :     bool localDrag = ed.control() || segment()->isBarLineType() || spanStaff() != score()->staff(staffIdx())->barLineSpan();
     674            0 :     if (localDrag) {
     675            0 :         Segment* s = segment();
     676            0 :         bool breakLast = staffIdx1 == staffIdx2;
     677            0 :         for (staff_idx_t staffIdx = staffIdx1; staffIdx < staffIdx2; ++staffIdx) {
     678            0 :             BarLine* b = toBarLine(s->element(staffIdx * VOICES));
     679            0 :             if (!b) {
     680            0 :                 b = toBarLine(linkedClone());
     681            0 :                 b->setSpanStaff(true);
     682            0 :                 b->setTrack(staffIdx * VOICES);
     683            0 :                 b->setOwnershipParent(s);
     684            0 :                 score()->undoAddElement(b);
     685              :             }
     686            0 :             breakLast = b->spanTo();
     687            0 :             b->undoChangeProperty(Pid::BARLINE_SPAN, true);
     688              :         }
     689            0 :         if (breakLast) {
     690            0 :             BarLine* b = toBarLine(s->element(staffIdx2 * VOICES));
     691            0 :             if (b) {
     692            0 :                 b->undoChangeProperty(Pid::BARLINE_SPAN, false);
     693              :             }
     694              :         }
     695              :     } else {
     696            0 :         bool breakLast = staffIdx1 == staffIdx2;
     697            0 :         for (staff_idx_t staffIdx = staffIdx1; staffIdx < staffIdx2; ++staffIdx) {
     698            0 :             breakLast = score()->staff(staffIdx)->barLineSpan();
     699            0 :             score()->staff(staffIdx)->undoChangeProperty(Pid::STAFF_BARLINE_SPAN, true);
     700              :         }
     701            0 :         if (breakLast) {
     702            0 :             score()->staff(staffIdx2)->undoChangeProperty(Pid::STAFF_BARLINE_SPAN, false);
     703              :         }
     704            0 :         staff()->undoChangeProperty(Pid::STAFF_BARLINE_SPAN_FROM, newSpanFrom);
     705            0 :         staff()->undoChangeProperty(Pid::STAFF_BARLINE_SPAN_TO,   newSpanTo);
     706              :     }
     707              : 
     708            0 :     bed->yoff1 = 0.0;
     709            0 :     bed->yoff2 = 0.0;
     710            0 : }
     711              : 
     712              : //---------------------------------------------------------
     713              : //   scanElements
     714              : //---------------------------------------------------------
     715              : 
     716         3937 : void BarLine::scanElements(std::function<void(EngravingItem*)> func)
     717              : {
     718         3937 :     func(this);
     719         3937 :     for (EngravingItem* e : m_el) {
     720            0 :         e->scanElements(func);
     721              :     }
     722         3937 : }
     723              : 
     724              : //---------------------------------------------------------
     725              : //   setTrack
     726              : //---------------------------------------------------------
     727              : 
     728        29945 : void BarLine::setTrack(track_idx_t t)
     729              : {
     730        29945 :     EngravingItem::setTrack(t);
     731        29945 :     for (EngravingItem* e : m_el) {
     732            0 :         e->setTrack(t);
     733              :     }
     734        29945 : }
     735              : 
     736              : //---------------------------------------------------------
     737              : //   add
     738              : //---------------------------------------------------------
     739              : 
     740            0 : void BarLine::add(EngravingItem* e)
     741              : {
     742            0 :     e->setOwnershipParent(this);
     743            0 :     switch (e->type()) {
     744            0 :     case ElementType::ARTICULATION:
     745              :     case ElementType::SYMBOL:
     746              :     case ElementType::IMAGE:
     747            0 :         m_el.push_back(e);
     748            0 :         setGenerated(false);
     749            0 :         e->added();
     750            0 :         break;
     751            0 :     default:
     752            0 :         LOGD("BarLine::add() not impl. %s", e->typeName());
     753            0 :         break;
     754              :     }
     755            0 : }
     756              : 
     757              : //---------------------------------------------------------
     758              : //   remove
     759              : //---------------------------------------------------------
     760              : 
     761            0 : void BarLine::remove(EngravingItem* e)
     762              : {
     763            0 :     switch (e->type()) {
     764            0 :     case ElementType::ARTICULATION:
     765              :     case ElementType::SYMBOL:
     766              :     case ElementType::IMAGE:
     767            0 :         if (!m_el.remove(e)) {
     768            0 :             LOGD("BarLine::remove(): cannot find %s", e->typeName());
     769              :         } else {
     770            0 :             e->removed();
     771              :         }
     772            0 :         break;
     773            0 :     default:
     774            0 :         LOGD("BarLine::remove() not impl. %s", e->typeName());
     775            0 :         return;
     776              :     }
     777              : }
     778              : 
     779              : //---------------------------------------------------------
     780              : //   getProperty
     781              : //---------------------------------------------------------
     782              : 
     783        19491 : PropertyValue BarLine::getProperty(Pid id) const
     784              : {
     785        19491 :     if (EngravingObject* e = const_cast<BarLine*>(this)->propertyDelegate(id)) {
     786            0 :         return e->getProperty(id);
     787              :     }
     788              : 
     789        19491 :     switch (id) {
     790         1497 :     case Pid::BARLINE_TYPE:
     791         1497 :         return PropertyValue::fromValue(m_barLineType);
     792         1491 :     case Pid::BARLINE_SPAN:
     793         1491 :         return spanStaff();
     794         1491 :     case Pid::BARLINE_SPAN_FROM:
     795         1491 :         return spanFrom();
     796         1491 :     case Pid::BARLINE_SPAN_TO:
     797         1491 :         return spanTo();
     798            0 :     case Pid::BARLINE_SHOW_TIPS:
     799            0 :         return showTips();
     800        13521 :     default:
     801        13521 :         break;
     802              :     }
     803        13521 :     return EngravingItem::getProperty(id);
     804              : }
     805              : 
     806              : //---------------------------------------------------------
     807              : //   setProperty
     808              : //---------------------------------------------------------
     809              : 
     810         2685 : bool BarLine::setProperty(Pid id, const PropertyValue& v)
     811              : {
     812         2685 :     if (EngravingObject* e = propertyDelegate(id)) {
     813            0 :         return e->setProperty(id, v);
     814              :     }
     815              : 
     816         2685 :     switch (id) {
     817            9 :     case Pid::BARLINE_TYPE:
     818            9 :         setBarLineType(v.value<BarLineType>());
     819            9 :         break;
     820          860 :     case Pid::BARLINE_SPAN:
     821          860 :         setSpanStaff(v.toBool());
     822          860 :         break;
     823          890 :     case Pid::BARLINE_SPAN_FROM:
     824          890 :         setSpanFrom(v.toInt());
     825          890 :         break;
     826          890 :     case Pid::BARLINE_SPAN_TO:
     827          890 :         setSpanTo(v.toInt());
     828          890 :         break;
     829            0 :     case Pid::BARLINE_SHOW_TIPS:
     830            0 :         setShowTips(v.toBool());
     831            0 :         break;
     832           36 :     default:
     833           36 :         return EngravingItem::setProperty(id, v);
     834              :     }
     835         2649 :     setGenerated(false);
     836         2649 :     triggerLayout();
     837         2649 :     return true;
     838              : }
     839              : 
     840              : //---------------------------------------------------------
     841              : //   undoChangeProperty
     842              : //---------------------------------------------------------
     843              : 
     844           36 : void BarLine::undoChangeProperty(Pid id, const PropertyValue& v, PropertyFlags ps)
     845              : {
     846           36 :     if (EngravingObject* e = propertyDelegate(id)) {
     847            0 :         e->undoChangeProperty(id, v, ps);
     848            0 :         return;
     849              :     }
     850              : 
     851           36 :     if (id == Pid::BARLINE_TYPE && segment() && segment()->segmentType() != SegmentType::BarLine) {
     852            9 :         score()->undoChangeBarLineType(this, v.value<BarLineType>(), true, true);
     853              :     } else {
     854           27 :         EngravingObject::undoChangeProperty(id, v, ps);
     855              :     }
     856              : }
     857              : 
     858        72297 : EngravingObject* BarLine::propertyDelegate(Pid pid) const
     859              : {
     860        72297 :     if (pid == Pid::REPEAT_COUNT) {
     861            0 :         return measure();
     862        72297 :     } else if (pid == Pid::PLAY_COUNT_TEXT || pid == Pid::PLAY_COUNT_TEXT_SETTING) {
     863            0 :         return playCountText();
     864              :     }
     865              : 
     866        72297 :     return EngravingItem::propertyDelegate(pid);
     867              : }
     868              : 
     869            0 : PlayCountText* BarLine::playCountText() const
     870              : {
     871            0 :     Segment* endBarSeg = segment();
     872            0 :     if (!endBarSeg) {
     873            0 :         return nullptr;
     874              :     }
     875            0 :     PlayCountText* playCountText = toPlayCountText(endBarSeg->findAnnotation(ElementType::PLAY_COUNT_TEXT, track(), track()));
     876              : 
     877            0 :     return playCountText;
     878              : }
     879              : 
     880              : //---------------------------------------------------------
     881              : //   propertyDefault
     882              : //---------------------------------------------------------
     883              : 
     884        22006 : PropertyValue BarLine::propertyDefault(Pid propertyId) const
     885              : {
     886        22006 :     if (EngravingObject* e = const_cast<BarLine*>(this)->propertyDelegate(propertyId)) {
     887            0 :         return e->propertyDefault(propertyId);
     888              :     }
     889              : 
     890        22006 :     switch (propertyId) {
     891         1488 :     case Pid::BARLINE_TYPE:
     892              : // dynamic default values are a bad idea: writing to xml the value maybe omitted resulting in
     893              : //    wrong values on read (as the default may be different on read)
     894              : //                  if (segment() && segment()->measure() && !segment()->measure()->nextMeasure())
     895              : //                        return QVariant::fromValue(BarLineType::END);
     896         2976 :         return PropertyValue::fromValue(BarLineType::NORMAL);
     897              : 
     898         2347 :     case Pid::BARLINE_SPAN:
     899         2347 :         return staff() ? staff()->barLineSpan() : false;
     900              : 
     901         2377 :     case Pid::BARLINE_SPAN_FROM:
     902         2377 :         return staff() ? staff()->barLineFrom() : 0;
     903              : 
     904         2377 :     case Pid::BARLINE_SPAN_TO:
     905         2377 :         return staff() ? staff()->barLineTo() : 0;
     906              : 
     907            0 :     case Pid::BARLINE_SHOW_TIPS:
     908            0 :         return false;
     909              : 
     910        13417 :     default:
     911        13417 :         break;
     912              :     }
     913        13417 :     return EngravingItem::propertyDefault(propertyId);
     914              : }
     915              : 
     916              : //---------------------------------------------------------
     917              : //   nextSegmentElement
     918              : //---------------------------------------------------------
     919              : 
     920            0 : EngravingItem* BarLine::nextSegmentElement()
     921              : {
     922            0 :     return segment()->firstInNextSegments(staffIdx());      //score()->inputState().prevTrack() / VOICES);
     923              : }
     924              : 
     925              : //---------------------------------------------------------
     926              : //   prevSegmentElement
     927              : //---------------------------------------------------------
     928              : 
     929            0 : EngravingItem* BarLine::prevSegmentElement()
     930              : {
     931            0 :     return segment()->lastInPrevSegments(staffIdx());       //score()->inputState().prevTrack() / VOICES);
     932              : }
     933              : 
     934              : //---------------------------------------------------------
     935              : //   subtypeUserName
     936              : //---------------------------------------------------------
     937              : 
     938            5 : muse::TranslatableString BarLine::subtypeUserName() const
     939              : {
     940           10 :     for (const auto& i : barLineTable) {
     941           10 :         if (i.type == barLineType()) {
     942            5 :             return i.userName;
     943              :         }
     944              :     }
     945            0 :     return TranslatableString();
     946              : }
     947              : 
     948              : //---------------------------------------------------------
     949              : //   accessibleInfo
     950              : //---------------------------------------------------------
     951              : 
     952            0 : String BarLine::accessibleInfo() const
     953              : {
     954            0 :     return String(u"%1: %2").arg(EngravingItem::accessibleInfo(), BarLine::translatedUserTypeName(barLineType()));
     955              : }
     956              : 
     957              : //---------------------------------------------------------
     958              : //   accessibleExtraInfo
     959              : //---------------------------------------------------------
     960              : 
     961            0 : String BarLine::accessibleExtraInfo() const
     962              : {
     963            0 :     Segment* seg = segment();
     964            0 :     String rez;
     965              : 
     966            0 :     for (const EngravingItem* e : *el()) {
     967            0 :         if (!score()->selectionFilter().canSelect(e)) {
     968            0 :             continue;
     969              :         }
     970            0 :         rez = String(u"%1 %2").arg(rez, e->screenReaderInfo());
     971              :     }
     972              : 
     973            0 :     for (const EngravingItem* e : seg->annotations()) {
     974            0 :         if (!score()->selectionFilter().canSelect(e)) {
     975            0 :             continue;
     976              :         }
     977            0 :         if (e->track() == track()) {
     978            0 :             rez = String(u"%1 %2").arg(rez, e->screenReaderInfo());
     979              :         }
     980              :     }
     981            0 :     Measure* m = seg->measure();
     982              : 
     983            0 :     if (m) {      // always true?
     984              :         //jumps
     985            0 :         for (const EngravingItem* e : m->el()) {
     986            0 :             if (!score()->selectionFilter().canSelect(e)) {
     987            0 :                 continue;
     988              :             }
     989            0 :             if (e->isJump()) {
     990            0 :                 rez= String(u"%1 %2").arg(rez, e->screenReaderInfo());
     991              :             }
     992            0 :             if (e->isMarker()) {
     993            0 :                 const Marker* m1 = toMarker(e);
     994            0 :                 if (m1->markerType() == MarkerType::FINE) {
     995            0 :                     rez = String(u"%1 %2").arg(rez, e->screenReaderInfo());
     996              :                 }
     997              :             }
     998              :         }
     999              :         //markers
    1000            0 :         Measure* nextM = m->nextMeasureMM();
    1001            0 :         if (nextM) {
    1002            0 :             for (const EngravingItem* e : nextM->el()) {
    1003            0 :                 if (!score()->selectionFilter().canSelect(e)) {
    1004            0 :                     continue;
    1005              :                 }
    1006            0 :                 if (e->isMarker()) {
    1007            0 :                     if (toMarker(e)->markerType() == MarkerType::FINE) {
    1008            0 :                         continue;             //added above^
    1009              :                     }
    1010            0 :                     rez = String(u"%1 %2").arg(rez, e->screenReaderInfo());
    1011              :                 }
    1012              :             }
    1013              :         }
    1014              :     }
    1015              : 
    1016            0 :     Fraction tick = seg->tick();
    1017              : 
    1018            0 :     auto spanners = score()->spannerMap().findOverlapping(tick.ticks(), tick.ticks());
    1019            0 :     for (auto interval : spanners) {
    1020            0 :         Spanner* s = interval.value;
    1021            0 :         if (!score()->selectionFilter().canSelect(s)) {
    1022            0 :             continue;
    1023              :         }
    1024            0 :         if (s->isVolta()) {
    1025            0 :             if (s->tick() == tick) {
    1026            0 :                 rez += u"; " + muse::mtrc("engraving", "Start of %1").arg(s->screenReaderInfo());
    1027              :             }
    1028            0 :             if (s->tick2() == tick) {
    1029            0 :                 rez += u"; " + muse::mtrc("engraving", "End of %1").arg(s->screenReaderInfo());
    1030              :             }
    1031              :         }
    1032              :     }
    1033            0 :     return rez;
    1034            0 : }
        

Generated by: LCOV version 2.0-1