LCOV - code coverage report
Current view: top level - src/engraving/dom - dynamichairpingroup.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 121 0
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 "dynamichairpingroup.h"
      24              : 
      25              : #include "dynamic.h"
      26              : #include "expression.h"
      27              : #include "hairpin.h"
      28              : #include "score.h"
      29              : #include "segment.h"
      30              : 
      31              : using namespace mu;
      32              : 
      33              : namespace mu::engraving {
      34            0 : static std::pair<Hairpin*, Hairpin*> findAdjacentHairpins(Dynamic* d)
      35              : {
      36            0 :     EngravingItem* itemSnappedBefore = d->ldata()->itemSnappedBefore();
      37            0 :     EngravingItem* itemSnappedAfter = d->ldata()->itemSnappedAfter();
      38              : 
      39            0 :     Hairpin* leftHairpin = itemSnappedBefore && itemSnappedBefore->isHairpinSegment()
      40            0 :                            ? toHairpinSegment(itemSnappedBefore)->hairpin() : nullptr;
      41            0 :     Hairpin* rightHairpin = itemSnappedAfter && itemSnappedAfter->isHairpinSegment()
      42            0 :                             ? toHairpinSegment(itemSnappedAfter)->hairpin() : nullptr;
      43              : 
      44            0 :     return { leftHairpin, rightHairpin };
      45              : }
      46              : 
      47            0 : std::unique_ptr<ElementGroup> HairpinWithDynamicsDragGroup::detectFor(HairpinSegment* hs,
      48              :                                                                       std::function<bool(const EngravingItem*)> isDragged)
      49              : {
      50            0 :     if (!hs->isSingleType()) {
      51            0 :         return nullptr;
      52              :     }
      53              : 
      54            0 :     EngravingItem* itemSnappedBefore = hs->ldata()->itemSnappedBefore();
      55            0 :     EngravingItem* itemSnappedAfter = hs->ldata()->itemSnappedAfter();
      56              : 
      57            0 :     Dynamic* startDynamic = itemSnappedBefore && itemSnappedBefore->isDynamic() ? toDynamic(itemSnappedBefore) : nullptr;
      58            0 :     Dynamic* endDynamic = itemSnappedAfter && itemSnappedAfter->isDynamic() ? toDynamic(itemSnappedAfter) : nullptr;
      59              : 
      60              :     // Include only dragged dynamics to this group
      61            0 :     if (!isDragged(startDynamic)) {
      62            0 :         startDynamic = nullptr;
      63              :     }
      64            0 :     if (!isDragged(endDynamic)) {
      65            0 :         endDynamic = nullptr;
      66              :     }
      67              : 
      68            0 :     if (startDynamic || endDynamic) {
      69            0 :         return std::unique_ptr<ElementGroup>(new HairpinWithDynamicsDragGroup(startDynamic, hs, endDynamic));
      70              :     }
      71            0 :     return nullptr;
      72              : }
      73              : 
      74            0 : std::unique_ptr<ElementGroup> HairpinWithDynamicsDragGroup::detectFor(Dynamic* d, std::function<bool(const EngravingItem*)> isDragged)
      75              : {
      76            0 :     Hairpin* leftHairpin = nullptr;
      77            0 :     Hairpin* rightHairpin = nullptr;
      78              : 
      79            0 :     std::tie(leftHairpin, rightHairpin) = findAdjacentHairpins(d);
      80              : 
      81              :     // Dynamic will be governed bt HairpinWithDynamicsDragGroup if any of adjacent
      82              :     // hairpins is dragged, disable separate drag logic for dynamic in this case.
      83            0 :     if (isDragged(leftHairpin)) {
      84            0 :         return std::unique_ptr<ElementGroup>(new DisabledElementGroup());
      85              :     }
      86            0 :     if (isDragged(rightHairpin)) {
      87            0 :         return std::unique_ptr<ElementGroup>(new DisabledElementGroup());
      88              :     }
      89              : 
      90            0 :     return nullptr;
      91              : }
      92              : 
      93            0 : void HairpinWithDynamicsDragGroup::startDrag(EditData& ed)
      94              : {
      95            0 :     if (m_startDynamic) {
      96            0 :         m_startDynamic->startDrag(ed);
      97              :     }
      98            0 :     static_cast<EngravingItem*>(m_hairpinSegment)->startDrag(ed);
      99            0 :     if (m_endDynamic) {
     100            0 :         m_endDynamic->startDrag(ed);
     101              :     }
     102            0 : }
     103              : 
     104            0 : RectF HairpinWithDynamicsDragGroup::drag(EditData& ed)
     105              : {
     106            0 :     RectF r;
     107              : 
     108            0 :     if (m_startDynamic) {
     109            0 :         r.unite(static_cast<EngravingItem*>(m_startDynamic)->drag(ed));
     110              :     }
     111            0 :     r.unite(m_hairpinSegment->drag(ed));
     112            0 :     if (m_endDynamic) {
     113            0 :         r.unite(static_cast<EngravingItem*>(m_endDynamic)->drag(ed));
     114              :     }
     115              : 
     116            0 :     Hairpin* h = m_hairpinSegment->hairpin();
     117              : 
     118            0 :     const Fraction startTick = m_startDynamic ? m_startDynamic->segment()->tick() : h->tick();
     119            0 :     const Fraction endTick = m_endDynamic ? m_endDynamic->segment()->tick() : h->tick2();
     120              : 
     121            0 :     if (endTick > startTick) {
     122            0 :         if (h->tick() != startTick) {
     123            0 :             h->undoChangeProperty(Pid::SPANNER_TICK, startTick);
     124              :         }
     125            0 :         if (h->tick2() != endTick) {
     126            0 :             h->undoChangeProperty(Pid::SPANNER_TICKS, endTick - startTick);
     127              :         }
     128              :     }
     129              : 
     130            0 :     return r;
     131              : }
     132              : 
     133            0 : void HairpinWithDynamicsDragGroup::endDrag(EditData& ed)
     134              : {
     135            0 :     if (m_startDynamic) {
     136            0 :         m_startDynamic->endDrag(ed);
     137            0 :         m_startDynamic->triggerLayout();
     138              :     }
     139              : 
     140            0 :     m_hairpinSegment->endDrag(ed);
     141            0 :     m_hairpinSegment->triggerLayout();
     142              : 
     143            0 :     if (m_endDynamic) {
     144            0 :         m_endDynamic->endDrag(ed);
     145            0 :         m_endDynamic->triggerLayout();
     146              :     }
     147            0 : }
     148              : 
     149            0 : std::unique_ptr<ElementGroup> DynamicNearHairpinsDragGroup::detectFor(Dynamic* d, std::function<bool(const EngravingItem*)> isDragged)
     150              : {
     151            0 :     Hairpin* leftHairpin = nullptr;
     152            0 :     Hairpin* rightHairpin = nullptr;
     153              : 
     154            0 :     std::tie(leftHairpin, rightHairpin) = findAdjacentHairpins(d);
     155              : 
     156              :     // Drag hairpins according to this rule only if they are not being dragged themselves
     157            0 :     if (isDragged(leftHairpin)) {
     158            0 :         leftHairpin = nullptr;
     159              :     }
     160            0 :     if (isDragged(rightHairpin)) {
     161            0 :         rightHairpin = nullptr;
     162              :     }
     163              : 
     164            0 :     if (leftHairpin || rightHairpin) {
     165            0 :         return std::unique_ptr<ElementGroup>(new DynamicNearHairpinsDragGroup(leftHairpin, d, rightHairpin));
     166              :     }
     167            0 :     return nullptr;
     168              : }
     169              : 
     170            0 : void DynamicNearHairpinsDragGroup::startDrag(EditData& ed)
     171              : {
     172            0 :     m_dynamic->startDrag(ed);
     173            0 : }
     174              : 
     175            0 : RectF DynamicNearHairpinsDragGroup::drag(EditData& ed)
     176              : {
     177            0 :     RectF r(static_cast<EngravingItem*>(m_dynamic)->drag(ed));
     178              : 
     179            0 :     const Fraction tick = m_dynamic->segment()->tick();
     180              : 
     181            0 :     if (m_leftHairpin && m_leftHairpin->tick2() != tick && tick > m_leftHairpin->tick()) {
     182            0 :         m_leftHairpin->undoChangeProperty(Pid::SPANNER_TICKS, tick - m_leftHairpin->tick());
     183              :     }
     184              : 
     185            0 :     if (m_rightHairpin && m_rightHairpin->tick() != tick) {
     186            0 :         const Fraction tick2 = m_rightHairpin->tick2();
     187            0 :         if (tick < tick2) {
     188            0 :             m_rightHairpin->undoChangeProperty(Pid::SPANNER_TICK, tick);
     189            0 :             m_rightHairpin->undoChangeProperty(Pid::SPANNER_TICKS, tick2 - tick);
     190              :         }
     191              :     }
     192              : 
     193            0 :     if (m_leftHairpin || m_rightHairpin) {
     194            0 :         m_dynamic->triggerLayout();
     195              :     }
     196              : 
     197            0 :     return r;
     198              : }
     199              : 
     200            0 : void DynamicNearHairpinsDragGroup::endDrag(EditData& ed)
     201              : {
     202            0 :     m_dynamic->endDrag(ed);
     203            0 :     m_dynamic->triggerLayout();
     204            0 : }
     205              : 
     206              : //-------------------------------------------------------
     207              : // DynamicExpressionDragGroup
     208              : //-------------------------------------------------------
     209              : 
     210            0 : std::unique_ptr<ElementGroup> DynamicExpressionDragGroup::detectFor(Dynamic* d, std::function<bool(const EngravingItem*)> isDragged)
     211              : {
     212            0 :     Expression* snappedExpression = d->snappedExpression();
     213            0 :     if (snappedExpression && !isDragged(snappedExpression)) {
     214            0 :         return std::unique_ptr<DynamicExpressionDragGroup>(new DynamicExpressionDragGroup(d, snappedExpression));
     215              :     }
     216            0 :     return nullptr;
     217              : }
     218              : 
     219            0 : std::unique_ptr<ElementGroup> DynamicExpressionDragGroup::detectFor(Expression* e, std::function<bool(const EngravingItem*)> isDragged)
     220              : {
     221            0 :     Dynamic* snappedDynamic = e->snappedDynamic();
     222            0 :     if (snappedDynamic && !isDragged(snappedDynamic)) {
     223            0 :         return std::unique_ptr<DynamicExpressionDragGroup>(new DynamicExpressionDragGroup(snappedDynamic, e));
     224              :     }
     225            0 :     return nullptr;
     226              : }
     227              : 
     228            0 : void DynamicExpressionDragGroup::startDrag(EditData& ed)
     229              : {
     230            0 :     m_dynamic->startDrag(ed);
     231            0 :     m_expression->startDrag(ed);
     232            0 : }
     233              : 
     234            0 : RectF DynamicExpressionDragGroup::drag(EditData& ed)
     235              : {
     236            0 :     RectF r = m_dynamic->drag(ed);
     237            0 :     r.unite(m_expression->drag(ed));
     238              : 
     239            0 :     m_dynamic->triggerLayout();
     240            0 :     m_expression->triggerLayout();
     241              : 
     242            0 :     return r;
     243              : }
     244              : 
     245            0 : void DynamicExpressionDragGroup::endDrag(EditData& ed)
     246              : {
     247            0 :     m_dynamic->endDrag(ed);
     248            0 :     m_dynamic->triggerLayout();
     249            0 :     m_expression->endDrag(ed);
     250            0 :     m_expression->triggerLayout();
     251            0 : }
     252              : } // namespace mu::engraving
        

Generated by: LCOV version 2.0-1