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) 2025 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 "editkeysig.h"
24 :
25 : #include "dom/factory.h"
26 : #include "dom/instrument.h"
27 : #include "dom/keysig.h"
28 : #include "dom/measure.h"
29 : #include "dom/part.h"
30 : #include "dom/score.h"
31 : #include "dom/segment.h"
32 : #include "dom/staff.h"
33 :
34 : #include "addremoveelement.h"
35 : #include "transaction/transaction.h"
36 : #include "transpose.h"
37 :
38 : #include "log.h"
39 :
40 : using namespace mu::engraving;
41 :
42 : //---------------------------------------------------------
43 : // ChangeKeySig
44 : //---------------------------------------------------------
45 :
46 46 : ChangeKeySig::ChangeKeySig(KeySig* k, KeySigEvent newKeySig, bool sc, bool addEvtToStaff)
47 46 : : keysig(k), ks(newKeySig), showCourtesy(sc), evtInStaff(addEvtToStaff)
48 46 : {}
49 :
50 78 : void ChangeKeySig::flip()
51 : {
52 78 : Segment* segment = keysig->segment();
53 78 : Fraction tick = segment->tick();
54 78 : Staff* staff = keysig->staff();
55 :
56 78 : const bool curEvtInStaff = (staff->currentKeyTick(tick) == tick);
57 78 : KeySigEvent curKey = keysig->keySigEvent();
58 78 : const bool curShowCourtesy = keysig->showCourtesy();
59 :
60 78 : keysig->setKeySigEvent(ks);
61 78 : keysig->setShowCourtesy(showCourtesy);
62 :
63 : // Add/remove the corresponding key events, if appropriate.
64 78 : if (evtInStaff) {
65 78 : staff->setKey(tick, ks); // replace
66 0 : } else if (curEvtInStaff) {
67 0 : staff->removeKey(tick); // if nothing to add instead, just remove.
68 : }
69 : // If no keysig event corresponds to the key signature then this keysig
70 : // is probably generated. Otherwise it is probably added manually.
71 : // Set segment flags according to this, layout will change it if needed.
72 78 : segment->setEnabled(evtInStaff);
73 78 : segment->setHeader(!evtInStaff && segment->rtick() == Fraction(0, 1));
74 :
75 78 : showCourtesy = curShowCourtesy;
76 78 : ks = curKey;
77 78 : evtInStaff = curEvtInStaff;
78 78 : keysig->triggerLayout();
79 78 : keysig->score()->setLayout(keysig->staff()->nextKeyTick(tick), keysig->staffIdx());
80 78 : }
81 :
82 : //---------------------------------------------------------
83 : // EditKeySig
84 : //---------------------------------------------------------
85 :
86 29 : void EditKeySig::undoChangeKeySig(Transaction& tx, Score* score, Staff* ostaff, const Fraction& tick, KeySigEvent key)
87 : {
88 29 : KeySig* lks = 0;
89 29 : bool needsUpdate = false;
90 :
91 60 : for (Staff* staff : ostaff->staffList()) {
92 31 : if (staff->isDrumStaff(tick)) {
93 0 : continue;
94 : }
95 :
96 31 : Score* staffScore = staff->score();
97 31 : Measure* measure = staffScore->tick2measure(tick);
98 31 : if (!measure) {
99 0 : LOGW("measure for tick %d not found!", tick.ticks());
100 0 : continue;
101 : }
102 31 : Segment* s = measure->undoGetSegment(SegmentType::KeySig, tick);
103 :
104 31 : staff_idx_t staffIdx = staff->idx();
105 31 : track_idx_t track = staffIdx * VOICES;
106 31 : KeySig* ks = toKeySig(s->element(track));
107 :
108 31 : Interval interval = staff->part()->instrument(tick)->transpose();
109 31 : Interval oldStaffInterval = staff->transpose(tick);
110 31 : KeySigEvent nkey = key;
111 31 : bool concertPitch = staffScore->style().styleB(Sid::concertPitch);
112 :
113 31 : if (interval.chromatic && !concertPitch && !nkey.isAtonal()) {
114 4 : interval.flip();
115 4 : nkey.setKey(Transpose::transposeKey(key.concertKey(), interval, staff->part()->preferSharpFlat()));
116 4 : interval.flip();
117 : }
118 :
119 31 : staffScore->updateInstrumentChangeTranspositions(key, staff, tick);
120 31 : if (ks) {
121 16 : ks->undoChangeProperty(Pid::GENERATED, false);
122 16 : tx.push(new ChangeKeySig(ks, nkey, ks->showCourtesy()));
123 : } else {
124 15 : KeySig* nks = Factory::createKeySig(s);
125 15 : nks->setTrack(track);
126 15 : nks->setKeySigEvent(nkey);
127 15 : staffScore->doUndoAddElement(nks);
128 15 : if (lks) {
129 0 : tx.push(new Link(lks, nks));
130 : } else {
131 15 : lks = nks;
132 : }
133 : }
134 31 : if (interval != staff->transpose(tick) || interval != oldStaffInterval) {
135 1 : needsUpdate = true;
136 : }
137 60 : }
138 29 : if (needsUpdate) {
139 1 : Fraction tickEnd = Fraction::fromTicks(ostaff->keyList()->nextKeyTick(tick.ticks()));
140 1 : Transpose::transpositionChanged(tx, score, ostaff->part(), ostaff->transpose(tick), tick, tickEnd);
141 : }
142 29 : }
|