LCOV - code coverage report
Current view: top level - src/engraving/dom - timesig.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 63.9 % 233 149
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 "timesig.h"
      24              : 
      25              : #include <functional>
      26              : 
      27              : #include "style/style.h"
      28              : 
      29              : #include "../editing/edittimesig.h"
      30              : #include "../editing/transaction/transaction.h"
      31              : 
      32              : #include "measure.h"
      33              : #include "score.h"
      34              : #include "segment.h"
      35              : #include "staff.h"
      36              : 
      37              : #include "log.h"
      38              : 
      39              : using namespace mu;
      40              : using namespace mu::engraving;
      41              : 
      42              : namespace mu::engraving {
      43              : static const ElementStyle tsStyle {
      44              :     { Sid::timeSigNormalScale, Pid::SCALE },
      45              : };
      46              : 
      47              : //---------------------------------------------------------
      48              : //   TimeSig
      49              : //    Constructs an invalid time signature element.
      50              : //    After construction first call setTrack() then
      51              : //    call setSig().
      52              : //    Layout() is static and called in setSig().
      53              : //---------------------------------------------------------
      54              : 
      55         3599 : TimeSig::TimeSig(DummyParentOr<Segment> parent)
      56         3599 :     : EngravingItem(ElementType::TIMESIG, parent, ElementFlag::ON_STAFF | ElementFlag::MOVABLE | ElementFlag::PLACE_ABOVE)
      57              : {
      58         3599 :     initElementStyle(&tsStyle);
      59              : 
      60         3599 :     m_showCourtesySig = true;
      61         3599 :     m_stretch.set(1, 1);
      62         3599 :     m_sig.set(0, 1);                 // initialize to invalid
      63         3599 :     m_timeSigType      = TimeSigType::NORMAL;
      64         3599 :     m_largeParentheses = false;
      65         3599 :     setMinDistance(0.5_sp); // TODO: style
      66         3599 : }
      67              : 
      68           90 : void TimeSig::setOwnershipParent(DummyParentOr<Segment> parent)
      69              : {
      70           90 :     EngravingItem::setOwnershipParent(parent);
      71           90 : }
      72              : 
      73              : //---------------------------------------------------------
      74              : //   mag
      75              : //---------------------------------------------------------
      76              : 
      77       207723 : double TimeSig::mag() const
      78              : {
      79       207723 :     return timeSigPlacement() == TimeSigPlacement::NORMAL && staff() ? staff()->staffMag(this) : 1.0;
      80              : }
      81              : 
      82              : //---------------------------------------------------------
      83              : //   setSig
      84              : //    custom text has to be set after setSig()
      85              : //---------------------------------------------------------
      86              : 
      87         3429 : void TimeSig::setSig(const Fraction& f, TimeSigType st)
      88              : {
      89         3429 :     m_sig              = f;
      90         3429 :     m_timeSigType      = st;
      91         3429 :     m_largeParentheses = false;
      92         3429 :     m_numeratorString.clear();
      93         3429 :     m_denominatorString.clear();
      94         3429 : }
      95              : 
      96              : //---------------------------------------------------------
      97              : //   acceptDrop
      98              : //---------------------------------------------------------
      99              : 
     100            0 : bool TimeSig::acceptDrop(EditData& data) const
     101              : {
     102            0 :     return data.dropElement->isTimeSig();
     103              : }
     104              : 
     105              : //---------------------------------------------------------
     106              : //   drop
     107              : //---------------------------------------------------------
     108              : 
     109            0 : EngravingItem* TimeSig::drop(Transaction& tx, EditData& data)
     110              : {
     111            0 :     EngravingItem* e = data.dropElement;
     112            0 :     if (e->isTimeSig()) {
     113              :         // change timesig applies to all staves, can't simply set subtype
     114              :         // for this one only
     115              :         // ownership of e is transferred to EditTimeSig::addTimeSig
     116              : 
     117            0 :         if (tick() != measure()->endTick()) {
     118            0 :             EditTimeSig::addTimeSig(tx, score(), measure(), staffIdx(), toTimeSig(e), false);
     119            0 :             return nullptr;
     120              :         }
     121              : 
     122              :         // This is a timesig at the end of a measure.
     123            0 :         if (*toTimeSig(e) == *this) {
     124            0 :             delete e;
     125            0 :             return nullptr;
     126              :         }
     127              : 
     128            0 :         if (!measure()->nextMeasure()) {
     129            0 :             return nullptr;
     130              :         }
     131              : 
     132              :         // Apply change to next measure
     133            0 :         EditTimeSig::addTimeSig(tx, score(), measure()->nextMeasure(), staffIdx(), toTimeSig(e), false);
     134            0 :         return nullptr;
     135              :     }
     136            0 :     delete e;
     137            0 :     return nullptr;
     138              : }
     139              : 
     140              : //---------------------------------------------------------
     141              : //   setNumeratorString
     142              : //    setSig() has to be called first
     143              : //---------------------------------------------------------
     144              : 
     145         1771 : void TimeSig::setNumeratorString(const String& a)
     146              : {
     147         1771 :     if (m_timeSigType == TimeSigType::NORMAL) {
     148         1718 :         m_numeratorString = a;
     149              :     }
     150         1771 : }
     151              : 
     152              : //---------------------------------------------------------
     153              : //   setDenominatorString
     154              : //    setSig() has to be called first
     155              : //---------------------------------------------------------
     156              : 
     157         1768 : void TimeSig::setDenominatorString(const String& a)
     158              : {
     159         1768 :     if (m_timeSigType == TimeSigType::NORMAL) {
     160         1715 :         m_denominatorString = a;
     161              :     }
     162         1768 : }
     163              : 
     164              : //---------------------------------------------------------
     165              : //   setFrom
     166              : //---------------------------------------------------------
     167              : 
     168          492 : void TimeSig::setFrom(const TimeSig* ts)
     169              : {
     170          492 :     m_timeSigType       = ts->timeSigType();
     171          492 :     m_numeratorString   = ts->m_numeratorString;
     172          492 :     m_denominatorString = ts->m_denominatorString;
     173          492 :     m_sig               = ts->m_sig;
     174          492 :     m_stretch           = ts->m_stretch;
     175          492 : }
     176              : 
     177              : //---------------------------------------------------------
     178              : //   ssig
     179              : //---------------------------------------------------------
     180              : 
     181            0 : String TimeSig::ssig() const
     182              : {
     183            0 :     return String(u"%1/%2").arg(m_sig.numerator()).arg(m_sig.denominator());
     184              : }
     185              : 
     186              : //---------------------------------------------------------
     187              : //   setSSig
     188              : //---------------------------------------------------------
     189              : 
     190            0 : void TimeSig::setSSig(const String& s)
     191              : {
     192            0 :     StringList sl = s.split(u'/');
     193            0 :     if (sl.size() == 2) {
     194            0 :         m_sig.setNumerator(sl[0].toInt());
     195            0 :         m_sig.setDenominator(sl[1].toInt());
     196              :     }
     197            0 : }
     198              : 
     199              : //---------------------------------------------------------
     200              : //   getProperty
     201              : //---------------------------------------------------------
     202              : 
     203        27903 : PropertyValue TimeSig::getProperty(Pid propertyId) const
     204              : {
     205        27903 :     switch (propertyId) {
     206         1993 :     case Pid::SHOW_COURTESY:
     207         1993 :         return showCourtesySig();
     208         1993 :     case Pid::NUMERATOR_STRING:
     209         1993 :         return numeratorString();
     210         1993 :     case Pid::DENOMINATOR_STRING:
     211         1993 :         return denominatorString();
     212           14 :     case Pid::GROUP_NODES:
     213           14 :         return groups().nodes();
     214           45 :     case Pid::TIMESIG:
     215           45 :         return PropertyValue::fromValue(m_sig);
     216           14 :     case Pid::TIMESIG_STRETCH:
     217           14 :         return PropertyValue::fromValue(stretch());
     218         2009 :     case Pid::TIMESIG_TYPE:
     219         2009 :         return int(m_timeSigType);
     220            0 :     case Pid::SCALE:
     221            0 :         return m_scale;
     222         1979 :     case Pid::IS_COURTESY:
     223         1979 :         return _isCourtesy;
     224              : 
     225        17863 :     default:
     226        17863 :         return EngravingItem::getProperty(propertyId);
     227              :     }
     228              : }
     229              : 
     230              : //---------------------------------------------------------
     231              : //   setProperty
     232              : //---------------------------------------------------------
     233              : 
     234         3817 : bool TimeSig::setProperty(Pid propertyId, const PropertyValue& v)
     235              : {
     236         3817 :     switch (propertyId) {
     237            0 :     case Pid::SHOW_COURTESY:
     238            0 :         if (generated()) {
     239            0 :             return false;
     240              :         }
     241            0 :         setShowCourtesySig(v.toBool());
     242            0 :         break;
     243            0 :     case Pid::NUMERATOR_STRING:
     244            0 :         setNumeratorString(v.value<String>());
     245            0 :         break;
     246            0 :     case Pid::DENOMINATOR_STRING:
     247            0 :         setDenominatorString(v.value<String>());
     248            0 :         break;
     249            0 :     case Pid::GROUP_NODES:
     250            0 :         setGroups(v.value<GroupNodes>());
     251            0 :         break;
     252           17 :     case Pid::TIMESIG:
     253           17 :         setSig(v.value<Fraction>());
     254           17 :         break;
     255            0 :     case Pid::TIMESIG_STRETCH:
     256            0 :         setStretch(v.value<Fraction>());
     257            0 :         break;
     258            2 :     case Pid::TIMESIG_TYPE:
     259            2 :         m_timeSigType = (TimeSigType)(v.toInt());
     260            2 :         break;
     261         3795 :     case Pid::SCALE:
     262         3795 :         m_scale = v.value<ScaleF>();
     263         3795 :         break;
     264            0 :     case Pid::IS_COURTESY:
     265            0 :         _isCourtesy = v.toBool();
     266            0 :         break;
     267            3 :     default:
     268            3 :         if (!EngravingItem::setProperty(propertyId, v)) {
     269            0 :             return false;
     270              :         }
     271            3 :         break;
     272              :     }
     273         3817 :     triggerLayoutAll();        // TODO
     274         3817 :     setGenerated(false);
     275         3817 :     return true;
     276              : }
     277              : 
     278              : //---------------------------------------------------------
     279              : //   propertyDefault
     280              : //---------------------------------------------------------
     281              : 
     282        32003 : PropertyValue TimeSig::propertyDefault(Pid id) const
     283              : {
     284        32003 :     switch (id) {
     285         1979 :     case Pid::SHOW_COURTESY:
     286         1979 :         return true;
     287         1979 :     case Pid::NUMERATOR_STRING:
     288         3958 :         return String();
     289         1979 :     case Pid::DENOMINATOR_STRING:
     290         3958 :         return String();
     291            0 :     case Pid::TIMESIG:
     292            0 :         return PropertyValue::fromValue(Fraction(4, 4));
     293         1979 :     case Pid::TIMESIG_TYPE:
     294         1979 :         return int(TimeSigType::NORMAL);
     295         1979 :     case Pid::PLACEMENT:
     296         1979 :         return PlacementV::ABOVE;
     297         1979 :     case Pid::IS_COURTESY:
     298         1979 :         return false;
     299        20129 :     default:
     300        20129 :         return EngravingItem::propertyDefault(id);
     301              :     }
     302              : }
     303              : 
     304        18919 : PointF TimeSig::staffOffset() const
     305              : {
     306        18919 :     const Segment* seg = segment();
     307        18919 :     const Measure* meas = seg ? seg->measure() : nullptr;
     308        18919 :     const Fraction tsTick = meas ? meas->tick() : tick();
     309        18919 :     const StaffType* st = staff()->constStaffType(tsTick);
     310        18919 :     const double yOffset = st ? st->yoffset().val() * spatium() : 0.0;
     311        18919 :     return PointF(0.0, yOffset);
     312              : }
     313              : 
     314              : //---------------------------------------------------------
     315              : //   nextSegmentElement
     316              : //---------------------------------------------------------
     317              : 
     318            0 : EngravingItem* TimeSig::nextSegmentElement()
     319              : {
     320            0 :     return segment()->firstInNextSegments(staffIdx());
     321              : }
     322              : 
     323              : //---------------------------------------------------------
     324              : //   prevSegmentElement
     325              : //---------------------------------------------------------
     326              : 
     327            0 : EngravingItem* TimeSig::prevSegmentElement()
     328              : {
     329            0 :     return segment()->lastInPrevSegments(staffIdx());
     330              : }
     331              : 
     332              : //---------------------------------------------------------
     333              : //   subtype
     334              : //---------------------------------------------------------
     335              : 
     336            0 : int TimeSig::subtype() const
     337              : {
     338            0 :     size_t h1 = std::hash<int> {}(numerator());
     339            0 :     size_t h2 = std::hash<int> {}(denominator());
     340            0 :     size_t h3 = std::hash<TimeSigType> {}(timeSigType());
     341              : 
     342            0 :     return static_cast<int>(h1 ^ (h2 << 1) ^ (h3 << 2));
     343              : }
     344              : 
     345              : //---------------------------------------------------------
     346              : //   subtypeUserName
     347              : //---------------------------------------------------------
     348              : 
     349            1 : muse::TranslatableString TimeSig::subtypeUserName() const
     350              : {
     351            1 :     switch (timeSigType()) {
     352            0 :     case TimeSigType::FOUR_FOUR:
     353            0 :         return TranslatableString("engraving/timesig", "Common time");
     354            0 :     case TimeSigType::ALLA_BREVE:
     355            0 :         return TranslatableString("engraving/timesig", "Cut time");
     356            0 :     case TimeSigType::CUT_BACH:
     357            0 :         return TranslatableString("engraving/timesig", "Cut time (Bach)");
     358            0 :     case TimeSigType::CUT_TRIPLE:
     359            0 :         return TranslatableString("engraving/timesig", "Cut triple time (9/8)");
     360            1 :     default:
     361            1 :         return TranslatableString("engraving/timesig", "%1/%2 time").arg(numerator(), denominator());
     362              :     }
     363              : }
     364              : 
     365              : //---------------------------------------------------------
     366              : //   accessibleInfo
     367              : //---------------------------------------------------------
     368              : 
     369            0 : String TimeSig::accessibleInfo() const
     370              : {
     371            0 :     return String(u"%1: %2").arg(EngravingItem::accessibleInfo(), translatedSubtypeUserName());
     372              : }
     373              : 
     374         3599 : void TimeSig::initElementStyle(const ElementStyle* elementStype)
     375              : {
     376         3599 :     EngravingItem::initElementStyle(elementStype);
     377              : 
     378         3599 :     m_scale = propertyDefault(Pid::SCALE).value<ScaleF>();
     379         3599 : }
     380              : 
     381          196 : void TimeSig::styleChanged()
     382              : {
     383          196 :     if (isStyled(Pid::SCALE)) {
     384          196 :         m_scale = propertyDefault(Pid::SCALE).value<ScaleF>();
     385              :     }
     386          196 :     EngravingItem::styleChanged();
     387          196 : }
     388              : 
     389         8082 : Sid TimeSig::getPropertyStyle(Pid id) const
     390              : {
     391         8082 :     if (id == Pid::SCALE) {
     392         8077 :         switch (timeSigPlacement()) {
     393         8043 :         case TimeSigPlacement::NORMAL: return Sid::timeSigNormalScale;
     394            0 :         case TimeSigPlacement::ABOVE_STAVES: return Sid::timeSigAboveScale;
     395           34 :         case TimeSigPlacement::ACROSS_STAVES: return Sid::timeSigAcrossScale;
     396            0 :         default:
     397            0 :             return Sid::NOSTYLE;
     398              :         }
     399              :     }
     400              : 
     401            5 :     return EngravingItem::getPropertyStyle(id);
     402              : }
     403              : 
     404       391315 : TimeSigPlacement TimeSig::timeSigPlacement() const
     405              : {
     406       391315 :     return style().styleV(Sid::timeSigPlacement).value<TimeSigPlacement>();
     407              : }
     408              : 
     409         6419 : TimeSigStyle TimeSig::timeSigStyle() const
     410              : {
     411         6419 :     switch (timeSigPlacement()) {
     412         6385 :     case TimeSigPlacement::NORMAL: return style().styleV(Sid::timeSigNormalStyle).value<TimeSigStyle>();
     413            0 :     case TimeSigPlacement::ABOVE_STAVES: return style().styleV(Sid::timeSigAboveStyle).value<TimeSigStyle>();
     414           34 :     case TimeSigPlacement::ACROSS_STAVES: return style().styleV(Sid::timeSigAcrossStyle).value<TimeSigStyle>();
     415            0 :     default:
     416            0 :         return TimeSigStyle::NORMAL;
     417              :     }
     418              : }
     419              : 
     420         6419 : double TimeSig::numDist() const
     421              : {
     422         6419 :     switch (timeSigPlacement()) {
     423         6385 :     case TimeSigPlacement::NORMAL: return style().styleAbsolute(Sid::timeSigNormalNumDist);
     424            0 :     case TimeSigPlacement::ABOVE_STAVES: return style().styleAbsolute(Sid::timeSigAboveNumDist);
     425           34 :     case TimeSigPlacement::ACROSS_STAVES: return style().styleAbsolute(Sid::timeSigAcrossNumDist);
     426            0 :     default:
     427            0 :         return 0.0;
     428              :     }
     429              : }
     430              : 
     431         6419 : double TimeSig::yPos() const
     432              : {
     433         6419 :     switch (timeSigPlacement()) {
     434         6385 :     case TimeSigPlacement::NORMAL: return style().styleAbsolute(Sid::timeSigNormalY);
     435            0 :     case TimeSigPlacement::ABOVE_STAVES: return (staff()->hasSystemObjectsBelowBottomStaff() ? -1.0 : 1.0)
     436            0 :                * style().styleAbsolute(Sid::timeSigAboveY);
     437           34 :     case TimeSigPlacement::ACROSS_STAVES: return style().styleAbsolute(Sid::timeSigAcrossY);
     438            0 :     default:
     439            0 :         return 0.0;
     440              :     }
     441              : }
     442              : 
     443         6762 : bool TimeSig::showOnThisStaff() const
     444              : {
     445         6762 :     return timeSigPlacement() == TimeSigPlacement::NORMAL || staffIdx() == 0 || staff()->isSystemObjectStaff();
     446              : }
     447              : 
     448       143059 : bool TimeSig::isAboveStaves() const
     449              : {
     450       143059 :     return timeSigPlacement() == TimeSigPlacement::ABOVE_STAVES;
     451              : }
     452              : 
     453         6419 : bool TimeSig::isAcrossStaves() const
     454              : {
     455         6419 :     return timeSigPlacement() == TimeSigPlacement::ACROSS_STAVES;
     456              : }
     457              : 
     458              : //---------------------------------------------------------
     459              : //   operator==
     460              : //---------------------------------------------------------
     461              : 
     462          137 : bool TimeSig::operator==(const TimeSig& ts) const
     463              : {
     464          137 :     return (timeSigType() == ts.timeSigType())
     465          135 :            && (sig().identical(ts.sig()))
     466          262 :            && (stretch() == ts.stretch())
     467          125 :            && (groups() == ts.groups())
     468          125 :            && (m_numeratorString == ts.m_numeratorString)
     469          409 :            && (m_denominatorString == ts.m_denominatorString)
     470              :     ;
     471              : }
     472              : 
     473         3906 : void TimeSig::added()
     474              : {
     475         3906 :     IF_ASSERT_FAILED(score()) {
     476            0 :         return;
     477              :     }
     478              : 
     479         3906 :     score()->updateTicksAndTimeSigMapLater();
     480              : }
     481              : 
     482          153 : void TimeSig::removed()
     483              : {
     484          153 :     IF_ASSERT_FAILED(score()) {
     485            0 :         return;
     486              :     }
     487              : 
     488          153 :     score()->updateTicksAndTimeSigMapLater();
     489              : }
     490              : }
        

Generated by: LCOV version 2.0-1