LCOV - code coverage report
Current view: top level - src/engraving/dom - keysig.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 56.2 % 162 91
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 "keysig.h"
      24              : 
      25              : #include "types/typesconv.h"
      26              : 
      27              : #include "masterscore.h"
      28              : #include "measure.h"
      29              : #include "score.h"
      30              : #include "segment.h"
      31              : #include "staff.h"
      32              : #include "part.h"
      33              : 
      34              : #include "editing/editkeysig.h"
      35              : #include "editing/transaction/transaction.h"
      36              : #include "editing/transpose.h"
      37              : 
      38              : #include "log.h"
      39              : 
      40              : using namespace mu;
      41              : using namespace mu::engraving;
      42              : 
      43              : namespace mu::engraving {
      44              : //---------------------------------------------------------
      45              : //   KeySig
      46              : //---------------------------------------------------------
      47              : 
      48         6946 : KeySig::KeySig(DummyParentOr<Segment> s)
      49         6946 :     : EngravingItem(ElementType::KEYSIG, s, ElementFlag::ON_STAFF)
      50              : {
      51         6946 :     m_showCourtesy = true;
      52         6946 :     m_hideNaturals = false;
      53         6946 : }
      54              : 
      55          183 : KeySig::KeySig(const KeySig& k)
      56          183 :     : EngravingItem(k)
      57              : {
      58          183 :     m_showCourtesy = k.m_showCourtesy;
      59          183 :     m_sig          = k.m_sig;
      60          183 :     m_hideNaturals = false;
      61          183 : }
      62              : 
      63              : //---------------------------------------------------------
      64              : //   mag
      65              : //---------------------------------------------------------
      66              : 
      67       553346 : double KeySig::mag() const
      68              : {
      69       553346 :     return staff() ? staff()->staffMag(this) : 1.0;
      70              : }
      71              : 
      72              : //---------------------------------------------------------
      73              : //   acceptDrop
      74              : //---------------------------------------------------------
      75              : 
      76            0 : bool KeySig::acceptDrop(EditData& data) const
      77              : {
      78            0 :     return data.dropElement->isKeySig();
      79              : }
      80              : 
      81              : //---------------------------------------------------------
      82              : //   drop
      83              : //---------------------------------------------------------
      84              : 
      85            0 : EngravingItem* KeySig::drop(Transaction& tx, EditData& data)
      86              : {
      87            0 :     KeySig* ks = toKeySig(data.dropElement);
      88            0 :     if (!ks->isKeySig()) {
      89            0 :         delete ks;
      90            0 :         return 0;
      91              :     }
      92            0 :     KeySigEvent k = ks->keySigEvent();
      93            0 :     delete ks;
      94            0 :     if (data.modifiers & ControlModifier) {
      95              :         // apply only to this stave
      96            0 :         if (!(k == keySigEvent())) {
      97            0 :             EditKeySig::undoChangeKeySig(tx, score(), staff(), tick(), k);
      98              :         }
      99              :     } else {
     100              :         // apply to all staves:
     101            0 :         for (Staff* s : score()->masterScore()->staves()) {
     102            0 :             EditKeySig::undoChangeKeySig(tx, score(), s, tick(), k);
     103              :         }
     104              :     }
     105            0 :     return this;
     106            0 : }
     107              : 
     108              : //---------------------------------------------------------
     109              : //   setKey
     110              : //---------------------------------------------------------
     111              : 
     112          910 : void KeySig::setKey(Key concertKey)
     113              : {
     114          910 :     KeySigEvent e;
     115          910 :     e.setConcertKey(concertKey);
     116          910 :     if (staff() && !style().styleB(Sid::concertPitch)) {
     117          342 :         const Part* part = staff()->originPart(tick());
     118          342 :         Interval v = part->instrument(tick())->transpose();
     119          342 :         if (!v.isZero()) {
     120          292 :             v.flip();
     121          292 :             Key transposedKey = Transpose::transposeKey(concertKey, v, part->preferSharpFlat());
     122          292 :             e.setKey(transposedKey);
     123              :         }
     124              :     }
     125          910 :     setKeySigEvent(e);
     126          910 : }
     127              : 
     128              : //---------------------------------------------------------
     129              : //   setKey
     130              : //---------------------------------------------------------
     131              : 
     132            4 : void KeySig::setKey(Key concertKey, Key transposedKey)
     133              : {
     134            4 :     KeySigEvent e;
     135            4 :     e.setConcertKey(concertKey);
     136            4 :     e.setKey(transposedKey);
     137            4 :     setKeySigEvent(e);
     138            4 : }
     139              : 
     140              : //---------------------------------------------------------
     141              : //   operator==
     142              : //---------------------------------------------------------
     143              : 
     144            4 : bool KeySig::operator==(const KeySig& k) const
     145              : {
     146            4 :     return m_sig == k.m_sig;
     147              : }
     148              : 
     149              : //---------------------------------------------------------
     150              : //   isChange
     151              : //---------------------------------------------------------
     152              : 
     153           11 : bool KeySig::isChange() const
     154              : {
     155           11 :     if (!staff()) {
     156            0 :         return false;
     157              :     }
     158           11 :     if (!segment() || segment()->segmentType() != SegmentType::KeySig) {
     159            0 :         return false;
     160              :     }
     161           11 :     const Fraction keyTick = tick();
     162           11 :     return staff()->currentKeyTick(keyTick) == keyTick;
     163              : }
     164              : 
     165              : //---------------------------------------------------------
     166              : //   changeKeySigEvent
     167              : //---------------------------------------------------------
     168              : 
     169            0 : void KeySig::changeKeySigEvent(const KeySigEvent& t)
     170              : {
     171            0 :     if (m_sig == t) {
     172            0 :         return;
     173              :     }
     174            0 :     setKeySigEvent(t);
     175              : }
     176              : 
     177        68968 : PointF KeySig::staffOffset() const
     178              : {
     179        68968 :     const Segment* seg = segment();
     180        68968 :     const Measure* meas = seg ? seg->measure() : nullptr;
     181        68968 :     if (meas && meas->endTick() == tick()) {
     182              :         // Courtesy key sig should be adjusted by the following staffType's offset
     183         1933 :         return EngravingItem::staffOffset();
     184              :     }
     185        67035 :     return PointF(0.0, 0.0);
     186              : }
     187              : 
     188        31968 : EngravingObject* KeySig::propertyDelegate(Pid propertyId) const
     189              : {
     190        31968 :     if (!_isCourtesy) {
     191        31968 :         return nullptr;
     192              :     }
     193            0 :     switch (propertyId) {
     194            0 :     case Pid::KEY:
     195              :     case Pid::KEY_CONCERT:
     196              :     case Pid::SHOW_COURTESY:
     197              :     case Pid::KEYSIG_MODE:
     198              :     {
     199            0 :         Segment* thisSeg = segment();
     200            0 :         Segment* nextKSSeg = thisSeg ? thisSeg->next1(SegmentType::KeySig) : nullptr;
     201            0 :         if (nextKSSeg && nextKSSeg->tick() == thisSeg->tick()) {
     202            0 :             return nextKSSeg->element(track());
     203              :         }
     204            0 :         break;
     205              :     }
     206            0 :     default:
     207            0 :         break;
     208              :     }
     209              : 
     210            0 :     return nullptr;
     211              : }
     212              : 
     213              : //---------------------------------------------------------
     214              : //   getProperty
     215              : //---------------------------------------------------------
     216              : 
     217        13509 : PropertyValue KeySig::getProperty(Pid propertyId) const
     218              : {
     219        13509 :     if (EngravingObject* e = propertyDelegate(propertyId)) {
     220            0 :         return e->getProperty(propertyId);
     221              :     }
     222        13509 :     switch (propertyId) {
     223            0 :     case Pid::KEY:
     224            0 :         return int(key());
     225            0 :     case Pid::KEY_CONCERT:
     226            0 :         return int(concertKey());
     227         1226 :     case Pid::SHOW_COURTESY:
     228         1226 :         return showCourtesy();
     229            0 :     case Pid::KEYSIG_MODE:
     230            0 :         return mode();
     231         1226 :     case Pid::IS_COURTESY:
     232         1226 :         return _isCourtesy;
     233        11057 :     default:
     234        11057 :         return EngravingItem::getProperty(propertyId);
     235              :     }
     236              : }
     237              : 
     238              : //---------------------------------------------------------
     239              : //   setProperty
     240              : //---------------------------------------------------------
     241              : 
     242           10 : bool KeySig::setProperty(Pid propertyId, const PropertyValue& v)
     243              : {
     244           10 :     if (EngravingObject* e = propertyDelegate(propertyId)) {
     245            0 :         return e->setProperty(propertyId, v);
     246              :     }
     247           10 :     switch (propertyId) {
     248            0 :     case Pid::KEY:
     249            0 :         if (generated()) {
     250            0 :             return false;
     251              :         }
     252            0 :         setKey(m_sig.concertKey(), Key(v.toInt()));
     253            0 :         break;
     254            0 :     case Pid::KEY_CONCERT:
     255            0 :         if (generated()) {
     256            0 :             return false;
     257              :         }
     258            0 :         setKey(Key(v.toInt()));
     259            0 :         break;
     260            4 :     case Pid::SHOW_COURTESY:
     261            4 :         if (generated()) {
     262            0 :             return false;
     263              :         }
     264            4 :         setShowCourtesy(v.toBool());
     265            4 :         break;
     266            1 :     case Pid::KEYSIG_MODE:
     267            1 :         if (generated()) {
     268            0 :             return false;
     269              :         }
     270            1 :         setMode(v.value<KeyMode>());
     271            1 :         staff()->setKey(tick(), keySigEvent());
     272            1 :         break;
     273            0 :     case Pid::IS_COURTESY:
     274            0 :         _isCourtesy = v.toBool();
     275            0 :         break;
     276            5 :     default:
     277            5 :         if (!EngravingItem::setProperty(propertyId, v)) {
     278            0 :             return false;
     279              :         }
     280            5 :         break;
     281              :     }
     282           10 :     triggerLayoutAll();
     283           10 :     setGenerated(false);
     284           10 :     return true;
     285              : }
     286              : 
     287              : //---------------------------------------------------------
     288              : //   undoChangeProperty
     289              : //---------------------------------------------------------
     290              : 
     291           16 : void KeySig::undoChangeProperty(Pid id, const PropertyValue& v, PropertyFlags ps)
     292              : {
     293           16 :     if (EngravingObject* e = propertyDelegate(id)) {
     294              :         /* If this is a courtesy, we must change the property of the _real_ key signature,
     295              :          * and we want to avoid EngravingObject::undoChangeProperty unsetting GENERATED
     296              :          * unless something really has changed about the courtesy itself: */
     297            0 :         e->undoChangeProperty(id, v, ps);
     298              :         // If removing the courtesy, deselect it first:
     299            0 :         if (id == Pid::SHOW_COURTESY && _isCourtesy && !v.toBool() && selected() && e->isKeySig()) {
     300            0 :             score()->deselect(this);
     301            0 :             score()->select(toEngravingItem(e), SelectType::ADD, staffIdx());
     302              :         }
     303            0 :         return;
     304              :     }
     305           16 :     EngravingItem::undoChangeProperty(id, v, ps);
     306              : }
     307              : 
     308              : //---------------------------------------------------------
     309              : //   propertyDefault
     310              : //---------------------------------------------------------
     311              : 
     312        13486 : PropertyValue KeySig::propertyDefault(Pid id) const
     313              : {
     314        13486 :     switch (id) {
     315            0 :     case Pid::KEY:
     316            0 :         return int(Key::INVALID);
     317            0 :     case Pid::KEY_CONCERT:
     318            0 :         return int(Key::INVALID);
     319         1226 :     case Pid::SHOW_COURTESY:
     320         1226 :         return true;
     321            0 :     case Pid::KEYSIG_MODE:
     322            0 :         return KeyMode::UNKNOWN;
     323         1226 :     case Pid::IS_COURTESY:
     324         1226 :         return false;
     325        11034 :     default:
     326        11034 :         return EngravingItem::propertyDefault(id);
     327              :     }
     328              : }
     329              : 
     330              : //---------------------------------------------------------
     331              : //   nextSegmentElement
     332              : //---------------------------------------------------------
     333              : 
     334           31 : EngravingItem* KeySig::nextSegmentElement()
     335              : {
     336           31 :     return segment()->firstInNextSegments(staffIdx());
     337              : }
     338              : 
     339              : //---------------------------------------------------------
     340              : //   prevSegmentElement
     341              : //---------------------------------------------------------
     342              : 
     343           29 : EngravingItem* KeySig::prevSegmentElement()
     344              : {
     345           29 :     return segment()->lastInPrevSegments(staffIdx());
     346              : }
     347              : 
     348              : //---------------------------------------------------------
     349              : //   accessibleInfo
     350              : //---------------------------------------------------------
     351              : 
     352            0 : String KeySig::accessibleInfo() const
     353              : {
     354            0 :     String keySigType = TConv::translatedUserName(key(), isAtonal(), isCustom());
     355            0 :     return String(u"%1: %2").arg(EngravingItem::accessibleInfo(), keySigType);
     356            0 : }
     357              : 
     358              : //---------------------------------------------------------
     359              : //   translatedSubtypeUserName
     360              : //---------------------------------------------------------
     361              : 
     362            1 : muse::TranslatableString KeySig::subtypeUserName() const
     363              : {
     364            1 :     return TConv::userName(key(), isAtonal(), isCustom());
     365              : }
     366              : }
        

Generated by: LCOV version 2.0-1