LCOV - code coverage report
Current view: top level - src/engraving/editing - editvisibility.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 85.6 % 97 83
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) 2026 MuseScore Limited
       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 "editvisibility.h"
      24              : 
      25              : #include "global/containers.h"
      26              : 
      27              : #include "../dom/accidental.h"
      28              : #include "../dom/beam.h"
      29              : #include "../dom/chord.h"
      30              : #include "../dom/engravingitem.h"
      31              : #include "../dom/note.h"
      32              : #include "../dom/notedot.h"
      33              : #include "../dom/ornament.h"
      34              : #include "../dom/rest.h"
      35              : #include "../dom/score.h"
      36              : #include "../dom/select.h"
      37              : #include "../dom/trill.h"
      38              : 
      39              : #include "editproperty.h"
      40              : #include "transaction/transaction.h"
      41              : 
      42              : using namespace mu::engraving;
      43              : 
      44            0 : void EditVisibility::setSelectedElementsVisible(Transaction& tx, Score* score)
      45              : {
      46            0 :     for (EngravingItem* e : score->selection().elements()) {
      47            0 :         tx.push(new ChangeProperty(e, Pid::VISIBLE, true));
      48              :     }
      49            0 : }
      50              : 
      51            0 : void EditVisibility::setSelectedElementsInvisible(Transaction& tx, Score* score)
      52              : {
      53            0 :     for (EngravingItem* e : score->selection().elements()) {
      54            0 :         tx.push(new ChangeProperty(e, Pid::VISIBLE, false));
      55              :     }
      56            0 : }
      57              : 
      58            4 : void EditVisibility::toggleVisible(Transaction& tx, Score* score)
      59              : {
      60            4 :     bool allVisible = true;
      61              : 
      62           34 :     for (EngravingItem* item : score->selection().elements()) {
      63           32 :         if (!item->getProperty(Pid::VISIBLE).toBool()) {
      64            2 :             allVisible = false;
      65            2 :             break;
      66              :         }
      67              :     }
      68              : 
      69            4 :     bool newVisible = !allVisible;
      70              : 
      71           80 :     for (EngravingItem* item : score->selection().elements()) {
      72           76 :         undoChangeVisible(tx, item, newVisible);
      73              :     }
      74            4 : }
      75              : 
      76         1352 : static bool chordHasVisibleNote(const Chord* chord)
      77              : {
      78         2441 :     for (const Note* note : chord->notes()) {
      79         1378 :         if (note->visible()) {
      80          289 :             return true;
      81              :         }
      82              :     }
      83              : 
      84         1063 :     return false;
      85              : }
      86              : 
      87          256 : static bool beamHasVisibleNote(const Beam* beam)
      88              : {
      89         1054 :     for (const EngravingItem* item : beam->elements()) {
      90          887 :         if (item->isChord() && chordHasVisibleNote(toChord(item))) {
      91           89 :             return true;
      92              :         }
      93              :     }
      94              : 
      95          167 :     return false;
      96              : }
      97              : 
      98              : static void undoChangeOrnamentVisibility(Ornament* ornament, bool visible);
      99              : 
     100           79 : static void undoChangeNoteVisibility(Note* note, bool visible)
     101              : {
     102           79 :     note->undoChangeProperty(Pid::VISIBLE, visible);
     103              : 
     104           79 :     if (note->bendBack() || note->bendFor()) {
     105            0 :         note->setOverrideBendVisibilityRules(true);
     106              :     } else {
     107           79 :         note->setOverrideBendVisibilityRules(false);
     108              :     }
     109              : 
     110           90 :     for (NoteDot* dot : note->dots()) {
     111           11 :         dot->undoChangeProperty(Pid::VISIBLE, visible);
     112              :     }
     113              : 
     114           79 :     for (EngravingItem* e : note->el()) {
     115            0 :         e->undoChangeProperty(Pid::VISIBLE, visible);
     116              :     }
     117              : 
     118           79 :     if (note->accidental()) {
     119           13 :         note->accidental()->undoChangeProperty(Pid::VISIBLE, visible);
     120              :     }
     121              : 
     122           79 :     Chord* noteChord = note->chord();
     123           79 :     Beam* beam = noteChord->beam();
     124           79 :     std::vector<Chord*> chords;
     125              : 
     126           79 :     if (beam) {
     127          276 :         for (EngravingItem* item : beam->elements()) {
     128          219 :             if (item->isChord()) {
     129          219 :                 chords.push_back(toChord(item));
     130              :             }
     131              :         }
     132              :     } else {
     133           22 :         chords.push_back(noteChord);
     134              :     }
     135              : 
     136              :     static const std::unordered_set<ElementType> IGNORED_TYPES {
     137              :         ElementType::NOTE,
     138              :         ElementType::LYRICS,
     139              :         ElementType::SLUR,
     140              :         ElementType::HAMMER_ON_PULL_OFF,
     141              :         ElementType::CHORD, // grace notes
     142              :         ElementType::LEDGER_LINE, // temporary objects, impossible to change visibility
     143           81 :     };
     144              : 
     145          320 :     for (const Chord* chord : chords) {
     146          706 :         for (const EngravingObject* obj : chord->linkList()) {
     147          465 :             const Chord* linkedChord = toChord(obj);
     148          465 :             const bool chordHasVisibleNote_ = chordHasVisibleNote(linkedChord);
     149              :             // note visibility can differ between scores, so check this score's own beam
     150          465 :             const Beam* linkedBeam = linkedChord->beam();
     151          465 :             const bool beamHasVisibleNote_ = chordHasVisibleNote_ || (linkedBeam && beamHasVisibleNote(linkedBeam));
     152         1651 :             for (EngravingObject* child : linkedChord->getChildren()) {
     153         1186 :                 const ElementType type = child->type();
     154              : 
     155         1186 :                 if (muse::contains(IGNORED_TYPES, type)) {
     156         1059 :                     continue;
     157              :                 }
     158              : 
     159          683 :                 if (beam) {
     160          572 :                     if (type == ElementType::STEM || type == ElementType::BEAM) {
     161          556 :                         child->undoChangeProperty(Pid::VISIBLE, beamHasVisibleNote_);
     162          556 :                         continue;
     163              :                     }
     164              :                 }
     165          127 :                 if (child->isOrnament()) {
     166            1 :                     undoChangeOrnamentVisibility(toOrnament(child), visible);
     167              :                 } else {
     168          126 :                     child->undoChangeProperty(Pid::VISIBLE, chordHasVisibleNote_);
     169              :                 }
     170          465 :             }
     171          241 :         }
     172              :     }
     173           79 : }
     174              : 
     175           11 : static void undoChangeRestVisibility(Rest* rest, bool visible)
     176              : {
     177           11 :     rest->undoChangeProperty(Pid::VISIBLE, visible);
     178              : 
     179           16 :     for (NoteDot* dot : rest->dotList()) {
     180            5 :         dot->undoChangeProperty(Pid::VISIBLE, visible);
     181              :     }
     182           11 : }
     183              : 
     184            3 : static void undoChangeOrnamentVisibility(Ornament* ornament, bool visible)
     185              : {
     186            3 :     ornament->undoChangeProperty(Pid::VISIBLE, visible);
     187            3 :     Chord* cueNoteChord = ornament->cueNoteChord();
     188            3 :     if (cueNoteChord) {
     189            1 :         undoChangeNoteVisibility(cueNoteChord->upNote(), visible);
     190              :     }
     191            3 :     if (ornament->accidentalAbove()) {
     192            2 :         ornament->accidentalAbove()->undoChangeProperty(Pid::VISIBLE, visible);
     193              :     }
     194            3 :     if (ornament->accidentalBelow()) {
     195            2 :         ornament->accidentalBelow()->undoChangeProperty(Pid::VISIBLE, visible);
     196              :     }
     197            3 : }
     198              : 
     199          144 : void EditVisibility::undoChangeVisible(Transaction&, EngravingItem* item, bool visible)
     200              : {
     201          144 :     if (item->isNote()) {
     202           78 :         undoChangeNoteVisibility(toNote(item), visible);
     203           66 :     } else if (item->isRest()) {
     204           11 :         undoChangeRestVisibility(toRest(item), visible);
     205           55 :     } else if (item->isOrnament()) {
     206            2 :         undoChangeOrnamentVisibility(toOrnament(item), visible);
     207           53 :     } else if (item->isTrillSegment()) {
     208            0 :         item->undoChangeProperty(Pid::VISIBLE, visible);
     209            0 :         Ornament* orn = toTrillSegment(item)->trill()->ornament();
     210            0 :         if (orn) {
     211            0 :             undoChangeOrnamentVisibility(orn, visible);
     212              :         }
     213              :     } else {
     214           53 :         item->undoChangeProperty(Pid::VISIBLE, visible);
     215              :     }
     216          144 : }
        

Generated by: LCOV version 2.0-1