LCOV - code coverage report
Current view: top level - src/engraving/dom - spacer.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 8.7 % 103 9
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 "spacer.h"
      24              : 
      25              : #include "../editing/editdata.h"
      26              : #include "../editing/elementeditdata.h"
      27              : 
      28              : #include "measure.h"
      29              : #include "score.h"
      30              : #include "system.h"
      31              : 
      32              : using namespace mu;
      33              : using namespace muse::draw;
      34              : using namespace mu::engraving;
      35              : 
      36              : namespace mu::engraving {
      37              : //---------------------------------------------------------
      38              : //   LayoutBreak
      39              : //---------------------------------------------------------
      40              : 
      41            1 : Spacer::Spacer(DummyParentOr<Measure> parent)
      42            1 :     : EngravingItem(ElementType::SPACER, parent)
      43              : {
      44            1 :     m_spacerType = SpacerType::UP;
      45            1 :     m_gap = 0.0_sp;
      46            1 :     m_z = -10; // Ensure behind notation
      47            1 : }
      48              : 
      49            0 : Spacer::Spacer(const Spacer& s)
      50            0 :     : EngravingItem(s)
      51              : {
      52            0 :     m_gap        = s.m_gap;
      53            0 :     m_spacerType = s.m_spacerType;
      54            0 : }
      55              : 
      56              : //---------------------------------------------------------
      57              : //   setGap
      58              : //---------------------------------------------------------
      59              : 
      60            2 : void Spacer::setGap(Spatium sp)
      61              : {
      62            2 :     m_gap = sp;
      63            2 : }
      64              : 
      65              : //---------------------------------------------------------
      66              : //   startDragGrip
      67              : //---------------------------------------------------------
      68              : 
      69            0 : void Spacer::startDragGrip(EditData& ed)
      70              : {
      71            0 :     ElementEditDataPtr eed = ed.getData(this);
      72            0 :     eed->pushProperty(Pid::SPACE);
      73            0 : }
      74              : 
      75              : //---------------------------------------------------------
      76              : //   dragGrip
      77              : //---------------------------------------------------------
      78              : 
      79            0 : void Spacer::dragGrip(EditData& ed)
      80              : {
      81            0 :     double s = ed.delta.y();
      82              : 
      83            0 :     switch (spacerType()) {
      84            0 :     case SpacerType::DOWN:
      85              :     case SpacerType::FIXED:
      86            0 :         m_gap += Spatium::fromAbsolute(s, spatium());
      87            0 :         break;
      88            0 :     case SpacerType::UP:
      89            0 :         m_gap -= Spatium::fromAbsolute(s, spatium());
      90            0 :         break;
      91              :     }
      92            0 :     m_gap = std::max(m_gap, 2.0_sp);
      93            0 :     triggerLayout();
      94            0 : }
      95              : 
      96              : //---------------------------------------------------------
      97              : //   gripsPositions
      98              : //---------------------------------------------------------
      99              : 
     100            0 : std::vector<PointF> Spacer::gripsPositions(const EditData&) const
     101              : {
     102            0 :     double _spatium = spatium();
     103            0 :     PointF p;
     104            0 :     switch (spacerType()) {
     105            0 :     case SpacerType::DOWN:
     106              :     case SpacerType::FIXED:
     107            0 :         p = PointF(_spatium * .5, absoluteGap());
     108            0 :         break;
     109            0 :     case SpacerType::UP:
     110            0 :         p = PointF(_spatium * .5, 0.0);
     111            0 :         break;
     112              :     }
     113            0 :     return { pagePos() + p };
     114              : }
     115              : 
     116              : //---------------------------------------------------------
     117              : //   getProperty
     118              : //---------------------------------------------------------
     119              : 
     120            0 : PropertyValue Spacer::getProperty(Pid propertyId) const
     121              : {
     122            0 :     switch (propertyId) {
     123            0 :     case Pid::SPACE:
     124            0 :         return gap();
     125            0 :     default:
     126            0 :         return EngravingItem::getProperty(propertyId);
     127              :     }
     128              : }
     129              : 
     130              : //---------------------------------------------------------
     131              : //   setProperty
     132              : //---------------------------------------------------------
     133              : 
     134            0 : bool Spacer::setProperty(Pid propertyId, const PropertyValue& v)
     135              : {
     136            0 :     switch (propertyId) {
     137            0 :     case Pid::SPACE:
     138            0 :         setGap(v.value<Spatium>());
     139            0 :         break;
     140            0 :     default:
     141            0 :         if (!EngravingItem::setProperty(propertyId, v)) {
     142            0 :             return false;
     143              :         }
     144            0 :         break;
     145              :     }
     146            0 :     triggerLayout();
     147            0 :     setGenerated(false);
     148            0 :     return true;
     149              : }
     150              : 
     151              : //---------------------------------------------------------
     152              : //   propertyDefault
     153              : //---------------------------------------------------------
     154              : 
     155            0 : PropertyValue Spacer::propertyDefault(Pid id) const
     156              : {
     157            0 :     switch (id) {
     158            0 :     case Pid::SPACE:
     159            0 :         return 0.0_sp;
     160            0 :     default:
     161            0 :         return EngravingItem::propertyDefault(id);
     162              :     }
     163              : }
     164              : 
     165              : //---------------------------------------------------------
     166              : //   triggerLayout
     167              : //---------------------------------------------------------
     168              : 
     169            0 : void Spacer::triggerLayout() const
     170              : {
     171            0 :     if (!ownershipParent()) {
     172            0 :         return;
     173              :     }
     174              : 
     175            0 :     Measure* m = measure();
     176            0 :     if (!m) {
     177            0 :         EngravingItem::triggerLayout();
     178            0 :         return;
     179              :     }
     180              : 
     181            0 :     Score* s = score();
     182            0 :     System* system = m->system();
     183            0 :     if (!s || !system || s->nstaves() == 0) {
     184            0 :         m->triggerLayout();
     185            0 :         return;
     186              :     }
     187              : 
     188              :     // Most spacer edits can stay local to the measure and are much cheaper.
     189              :     // Escalate only for down/fixed spacers on the last non-vbox system of the page,
     190              :     // where edits can repaginate and affect page-end spacing.
     191            0 :     if (spacerType() == SpacerType::UP) {
     192            0 :         m->triggerLayout();
     193            0 :         return;
     194              :     }
     195              : 
     196            0 :     System* nextSystem = m->nextNonVBoxSystem();
     197            0 :     if (nextSystem && nextSystem->page() == system->page()) {
     198            0 :         m->triggerLayout();
     199            0 :         return;
     200              :     }
     201              : 
     202              :     // For the last notation system on a page, include the next system boundary
     203              :     // so page-end spacing can be recomputed without relaying out the whole score.
     204            0 :     Measure* firstMeasure = system->firstMeasure();
     205            0 :     if (!firstMeasure) {
     206            0 :         m->triggerLayout();
     207            0 :         return;
     208              :     }
     209              : 
     210            0 :     Fraction startTick = firstMeasure->tick();
     211            0 :     Fraction endTick = s->endTick();
     212            0 :     if (nextSystem) {
     213            0 :         if (Measure* nextFirstMeasure = nextSystem->firstMeasure()) {
     214            0 :             endTick = nextFirstMeasure->tick();
     215              :         }
     216              :     }
     217              : 
     218            0 :     s->setLayout(startTick, endTick, 0, s->nstaves() - 1, this);
     219              : }
     220              : 
     221              : //---------------------------------------------------------
     222              : //   subtypeUserName
     223              : //---------------------------------------------------------
     224              : 
     225            0 : muse::TranslatableString Spacer::subtypeUserName() const
     226              : {
     227            0 :     switch (m_spacerType) {
     228            0 :     case SpacerType::UP:
     229            0 :         return TranslatableString("engraving/spacertype", "Staff spacer up");
     230            0 :     case SpacerType::DOWN:
     231            0 :         return TranslatableString("engraving/spacertype", "Staff spacer down");
     232            0 :     case SpacerType::FIXED:
     233            0 :         return TranslatableString("engraving/spacertype", "Staff spacer fixed down");
     234              :     }
     235            0 :     return TranslatableString::untranslatable("Unknown spacer");
     236              : }
     237              : }
        

Generated by: LCOV version 2.0-1