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 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 : #include "mmrestlayout.h"
23 :
24 : #include "dom/barline.h"
25 : #include "dom/factory.h"
26 : #include "dom/layoutbreak.h"
27 : #include "dom/marker.h"
28 : #include "dom/measure.h"
29 : #include "dom/mmrest.h"
30 : #include "dom/mmrestrange.h"
31 : #include "dom/score.h"
32 : #include "dom/segment.h"
33 : #include "dom/staff.h"
34 :
35 : #include "editing/editmeasures.h"
36 :
37 : #include "measurelayout.h"
38 : #include "tlayout.h"
39 :
40 : using namespace mu::engraving;
41 : using namespace mu::engraving::rendering::score;
42 :
43 : static const std::unordered_set<ElementType> BREAK_TYPES {
44 : ElementType::TEMPO_TEXT,
45 : ElementType::REHEARSAL_MARK,
46 : ElementType::HARMONY,
47 : ElementType::STAFF_TEXT,
48 : ElementType::EXPRESSION,
49 : ElementType::DYNAMIC,
50 : ElementType::SYSTEM_TEXT,
51 : ElementType::TRIPLET_FEEL,
52 : ElementType::PLAYTECH_ANNOTATION,
53 : ElementType::CAPO,
54 : ElementType::INSTRUMENT_CHANGE,
55 : ElementType::STRING_TUNINGS,
56 : ElementType::SYMBOL,
57 : ElementType::FRET_DIAGRAM,
58 : ElementType::HARP_DIAGRAM,
59 : ElementType::PLAY_COUNT_TEXT,
60 : ElementType::FERMATA,
61 : };
62 :
63 : static const std::unordered_set<ElementType> ALWAYS_BREAK_TYPES {
64 : ElementType::TEMPO_TEXT,
65 : ElementType::REHEARSAL_MARK
66 : };
67 :
68 : static const std::unordered_set<ElementType> CONDITIONAL_BREAK_TYPES {
69 : ElementType::HARMONY,
70 : ElementType::STAFF_TEXT,
71 : ElementType::EXPRESSION,
72 : ElementType::DYNAMIC,
73 : ElementType::SYSTEM_TEXT,
74 : ElementType::TRIPLET_FEEL,
75 : ElementType::PLAYTECH_ANNOTATION,
76 : ElementType::CAPO,
77 : ElementType::INSTRUMENT_CHANGE,
78 : ElementType::STRING_TUNINGS,
79 : ElementType::SYMBOL,
80 : ElementType::FRET_DIAGRAM,
81 : ElementType::HARP_DIAGRAM,
82 : };
83 :
84 : /*
85 : MMRests are measures which overlay existing notation
86 : When they are created, any item which should be visible is moved from the underlying measure to the MMRest measure.
87 : Items which are invisible remain in the underlying measure.
88 : This means that when deciding where in the score to break MMRests, we must check both the underlying measures and any MMRests connected
89 : to them
90 : */
91 :
92 128 : void MMRestLayout::reuseExistingMMRest(LayoutContext& ctx, Measure* mmrMeasure, Measure* lastMeasure, Fraction len)
93 : {
94 128 : if (mmrMeasure->ticks() == len) {
95 118 : MeasureLayout::removeSystemTrailer(mmrMeasure, ctx);
96 118 : return;
97 : }
98 :
99 10 : Fraction remainingMMRDuration = std::min(mmrMeasure->ticks() - len, ctx.dom().lastMeasure()->endTick() - len);
100 :
101 10 : Segment* barLineSeg = mmrMeasure->findSegmentR(SegmentType::EndBarLine, mmrMeasure->ticks());
102 10 : Segment* clefSeg = mmrMeasure->findSegmentR(SegmentType::Clef, mmrMeasure->ticks());
103 10 : Segment* breathSeg = mmrMeasure->findSegmentR(SegmentType::Breath, mmrMeasure->ticks());
104 :
105 10 : if (!remainingMMRDuration.negative() && remainingMMRDuration.isNotZero()) {
106 : // Time remaining. Create another mmrest to fill the time
107 4 : Measure* nextFirstMeasure = ctx.mutDom().tick2measure(lastMeasure->endTick());
108 4 : if (!nextFirstMeasure->mmRest()) {
109 3 : Measure* nextLastMeasure = ctx.mutDom().tick2measure(lastMeasure->endTick() + remainingMMRDuration - Fraction::eps());
110 3 : nextLastMeasure = nextLastMeasure ? nextLastMeasure : ctx.mutDom().lastMeasure();
111 3 : const int numMeasuresInNewMMRest = nextLastMeasure->measureIndex() - nextFirstMeasure->measureIndex() + 1;
112 :
113 3 : Measure* nextMMRMeasure = Factory::createMeasure(ctx.mutDom().score());
114 3 : nextMMRMeasure->setTicks(remainingMMRDuration);
115 3 : nextMMRMeasure->setTick(nextFirstMeasure->tick());
116 3 : ctx.mutDom().undo(new ChangeMMRest(nextFirstMeasure, nextMMRMeasure));
117 :
118 3 : nextMMRMeasure->setTimesig(nextFirstMeasure->timesig());
119 3 : nextMMRMeasure->setRepeatCount(nextLastMeasure->repeatCount());
120 3 : nextMMRMeasure->setMMRestCount(numMeasuresInNewMMRest);
121 3 : nextMMRMeasure->setMeasureNumber(nextFirstMeasure->measureNumber());
122 :
123 3 : ctx.mutDom().updateLocksOnCreateMMRest(nextFirstMeasure, nextLastMeasure);
124 :
125 3 : nextMMRMeasure->setRepeatStart(nextFirstMeasure->repeatStart() || nextLastMeasure->repeatStart());
126 3 : nextMMRMeasure->setRepeatEnd(nextFirstMeasure->repeatEnd() || nextLastMeasure->repeatEnd());
127 :
128 3 : if (barLineSeg) {
129 3 : changeElementsParent(barLineSeg, nextMMRMeasure, remainingMMRDuration, ctx, false);
130 : }
131 3 : if (clefSeg) {
132 0 : changeElementsParent(clefSeg, nextMMRMeasure, remainingMMRDuration, ctx, false);
133 : }
134 3 : if (breathSeg) {
135 0 : changeElementsParent(breathSeg, nextMMRMeasure, remainingMMRDuration, ctx, false);
136 : }
137 : }
138 : }
139 :
140 : // adjust length
141 10 : mmrMeasure->setTicks(len);
142 : // move existing end barline, clef and breath
143 10 : if (barLineSeg) {
144 10 : barLineSeg->setRtick(len);
145 : }
146 10 : if (clefSeg) {
147 0 : clefSeg->setRtick(len);
148 : }
149 10 : if (breathSeg) {
150 0 : breathSeg->setRtick(len);
151 : }
152 10 : MeasureLayout::removeSystemTrailer(mmrMeasure, ctx);
153 : }
154 :
155 : //---------------------------------------------------------
156 : // createMMRest
157 : // create a multimeasure rest
158 : // from firstMeasure to lastMeasure (inclusive)
159 : //---------------------------------------------------------
160 :
161 163 : void MMRestLayout::createMMRest(LayoutContext& ctx, Measure* firstMeasure, Measure* lastMeasure, const Fraction& len)
162 : {
163 163 : int numMeasuresInMMRest = 1;
164 163 : if (firstMeasure != lastMeasure) {
165 453 : for (Measure* m = firstMeasure->nextMeasure(); m; m = m->nextMeasure()) {
166 453 : ++numMeasuresInMMRest;
167 453 : m->setMMRestCount(0);
168 453 : if (Measure* oldMMRest = m->mmRest()) {
169 2 : ctx.mutDom().undo(new ChangeMMRest(m, nullptr));
170 : // These MMRests are being removed. Move all elements back to underlying measures.
171 : // Any elements that need moving back to the MMRest (in lastUnderlyingMeasure) will be handled by changeMeasureElParents below
172 2 : Measure* lastUnderlyingMeasure = oldMMRest->mmRestLast();
173 2 : restoreMeasureElParents(m, lastUnderlyingMeasure, oldMMRest, ctx);
174 : }
175 453 : if (m == lastMeasure) {
176 132 : break;
177 : }
178 : }
179 : }
180 :
181 : // mmrMeasure coexists with n undisplayed measures of rests
182 163 : Measure* mmrMeasure = firstMeasure->mmRest();
183 163 : if (mmrMeasure) {
184 128 : reuseExistingMMRest(ctx, mmrMeasure, lastMeasure, len);
185 : } else {
186 35 : mmrMeasure = Factory::createMeasure(ctx.mutDom().score());
187 35 : mmrMeasure->setTicks(len);
188 35 : mmrMeasure->setTick(firstMeasure->tick());
189 35 : ctx.mutDom().undo(new ChangeMMRest(firstMeasure, mmrMeasure));
190 : }
191 163 : mmrMeasure->setTimesig(firstMeasure->timesig());
192 163 : mmrMeasure->setRepeatCount(lastMeasure->repeatCount());
193 163 : mmrMeasure->setMMRestCount(numMeasuresInMMRest);
194 163 : mmrMeasure->setMeasureNumber(firstMeasure->measureNumber());
195 :
196 163 : ctx.mutDom().updateLocksOnCreateMMRest(firstMeasure, lastMeasure);
197 :
198 163 : mmrMeasure->setRepeatStart(firstMeasure->repeatStart() || lastMeasure->repeatStart());
199 163 : mmrMeasure->setRepeatEnd(firstMeasure->repeatEnd() || lastMeasure->repeatEnd());
200 :
201 163 : Segment* chordRestSeg = mmrMeasure->undoGetSegmentR(SegmentType::ChordRest, Fraction(0, 1));
202 344 : for (size_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
203 181 : track_idx_t track = staffIdx * VOICES;
204 181 : EngravingItem* existing = chordRestSeg->element(track);
205 181 : if (!existing) {
206 45 : MMRest* mmr = Factory::createMMRest(chordRestSeg);
207 45 : mmr->setDurationType(DurationType::V_MEASURE);
208 45 : mmr->setTicks(mmrMeasure->ticks());
209 45 : mmr->setTrack(track);
210 45 : ctx.mutDom().doUndoAddElement(mmr);
211 136 : } else if (existing->isMMRest()) {
212 : // a reused mmrMeasure may have changed length, so keep its MM rests in sync
213 136 : toMMRest(existing)->setTicks(mmrMeasure->ticks());
214 : }
215 : }
216 :
217 163 : changeMeasureElParents(firstMeasure, lastMeasure, mmrMeasure, ctx);
218 :
219 163 : MeasureBase* nm = ctx.conf().isShowVBox() ? lastMeasure->next() : lastMeasure->nextMeasure();
220 163 : ctx.mutDom().undo(new ChangeMMRestNext(mmrMeasure, nm));
221 163 : ctx.mutDom().undo(new ChangeMMRestPrev(mmrMeasure, firstMeasure->prev()));
222 163 : }
223 :
224 163 : void MMRestLayout::changeMeasureElParents(Measure* firstMeasure, Measure* lastMeasure, Measure* mmrMeasure, LayoutContext& ctx)
225 : {
226 : // copy markers & jumps to mmrMeasure
227 : // jumps come from lastMeasure, markers come from firstMeasure
228 163 : ElementList newList = lastMeasure->el();
229 166 : for (EngravingItem* e : firstMeasure->el()) {
230 3 : if (e->isMarker() && firstMeasure != lastMeasure) {
231 0 : newList.push_back(e);
232 : }
233 : }
234 176 : for (EngravingItem* e : newList) {
235 13 : ctx.mutDom().undoChangeParent(e, mmrMeasure, e->staffIdx(), false);
236 : }
237 :
238 : // set mmrMeasure with same barline as last underlying measure
239 163 : Segment* lastMeasureEndBarlineSeg = lastMeasure->findSegmentR(SegmentType::EndBarLine, lastMeasure->ticks());
240 163 : changeElementsParent(lastMeasureEndBarlineSeg, mmrMeasure, mmrMeasure->ticks(), ctx, false);
241 :
242 : // if last underlying measure ends with clef change, show same at end of mmrest
243 163 : Segment* lastMeasureClefSeg = lastMeasure->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef,
244 163 : lastMeasure->ticks());
245 163 : changeElementsParent(lastMeasureClefSeg, mmrMeasure, mmrMeasure->ticks(), ctx, false);
246 :
247 : // further check for clefs
248 163 : Segment* underlyingClefSeg = lastMeasure->findSegmentR(SegmentType::Clef, lastMeasure->ticks());
249 163 : Segment* mmrClefSeg = changeElementsParent(underlyingClefSeg, mmrMeasure, mmrMeasure->ticks(), ctx, false);
250 :
251 163 : if (underlyingClefSeg && mmrClefSeg) {
252 1 : mmrClefSeg->setEnabled(underlyingClefSeg->enabled());
253 1 : mmrClefSeg->setTrailer(underlyingClefSeg->trailer());
254 : }
255 :
256 : // check for time signature
257 163 : Segment* underlyingTimeSigSeg = firstMeasure->findSegmentR(SegmentType::TimeSig, Fraction(0, 1));
258 163 : Segment* mmrTimeSigSeg = changeElementsParent(underlyingTimeSigSeg, mmrMeasure, Fraction(0, 1), ctx, false);
259 :
260 163 : if (underlyingTimeSigSeg && mmrTimeSigSeg) {
261 75 : mmrTimeSigSeg->setEnabled(underlyingTimeSigSeg->enabled());
262 75 : mmrTimeSigSeg->setHeader(underlyingTimeSigSeg->header());
263 : }
264 :
265 : // check for end of measure time signature
266 163 : Segment* underlyingEndTimeSigSeg = lastMeasure->findSegmentR(SegmentType::TimeSig, lastMeasure->ticks());
267 163 : Segment* mmrEndTimeSigSeg = changeElementsParent(underlyingEndTimeSigSeg, mmrMeasure, mmrMeasure->ticks(), ctx, false);
268 :
269 163 : if (underlyingEndTimeSigSeg && mmrEndTimeSigSeg) {
270 4 : mmrEndTimeSigSeg->setEnabled(underlyingEndTimeSigSeg->enabled());
271 4 : mmrEndTimeSigSeg->setHeader(underlyingEndTimeSigSeg->header());
272 4 : mmrEndTimeSigSeg->setEndOfMeasureChange(underlyingEndTimeSigSeg->endOfMeasureChange());
273 : }
274 :
275 : // check for end of measure breaths
276 163 : Segment* underlyingBreathSeg = lastMeasure->findSegmentR(SegmentType::Breath, lastMeasure->ticks());
277 163 : changeElementsParent(underlyingBreathSeg, mmrMeasure, mmrMeasure->ticks(), ctx, false);
278 :
279 : // check for ambitus
280 163 : Segment* underlyingAmbitusSeg = firstMeasure->findSegmentR(SegmentType::Ambitus, Fraction(0, 1));
281 163 : changeElementsParent(underlyingAmbitusSeg, mmrMeasure, Fraction(0, 1), ctx, false);
282 :
283 : // check for key signature
284 163 : Segment* underlyingKeySigSeg = firstMeasure->findSegmentR(SegmentType::KeySig, Fraction(0, 1));
285 163 : Segment* mmrKeySigSeg = changeElementsParent(underlyingKeySigSeg, mmrMeasure, Fraction(0, 1), ctx, false);
286 :
287 163 : if (underlyingKeySigSeg && mmrKeySigSeg) {
288 36 : mmrKeySigSeg->setEnabled(underlyingKeySigSeg->enabled());
289 36 : mmrKeySigSeg->setHeader(underlyingKeySigSeg->header());
290 : }
291 :
292 163 : mmrMeasure->checkHeader();
293 163 : mmrMeasure->checkTrailer();
294 :
295 : // check for rehearsal mark etc.
296 163 : Segment* mmrChordRestSeg = mmrMeasure->undoGetSegmentR(SegmentType::ChordRest, Fraction(0, 1));
297 163 : Segment* underlyingCRSeg = firstMeasure->findSegmentR(SegmentType::ChordRest, Fraction(0, 1));
298 163 : changeAnnotationsParent(underlyingCRSeg, mmrChordRestSeg, ctx, false);
299 163 : }
300 :
301 10 : void MMRestLayout::restoreMeasureElParents(Measure* firstMeasure, Measure* lastMeasure, Measure* mmrMeasure, LayoutContext& ctx)
302 : {
303 : // copy markers & jumps back to underlying measures
304 10 : ElementList mmrMeasureEls = mmrMeasure->el();
305 12 : for (EngravingItem* e : mmrMeasureEls) {
306 2 : Measure* newMeasure = e->isMarker() ? firstMeasure : lastMeasure;
307 2 : ctx.mutDom().undoChangeParent(e, newMeasure, e->staffIdx(), false);
308 : }
309 :
310 : // restore the barline from mmrMeasure to the last underlying measure
311 10 : Segment* mmrEndBarlineSeg = mmrMeasure->findSegmentR(SegmentType::EndBarLine, mmrMeasure->ticks());
312 10 : changeElementsParent(mmrEndBarlineSeg, lastMeasure, lastMeasure->ticks(), ctx, false);
313 :
314 : // restore clef segments from mmrMeasure to the last underlying measure
315 10 : Segment* mmrClefOrHeaderSeg = mmrMeasure->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, mmrMeasure->ticks());
316 10 : changeElementsParent(mmrClefOrHeaderSeg, lastMeasure, lastMeasure->ticks(), ctx, false);
317 :
318 10 : Segment* mmrClefSeg = mmrMeasure->findSegmentR(SegmentType::Clef, mmrMeasure->ticks());
319 10 : Segment* lastMeasureClefSeg = changeElementsParent(mmrClefSeg, lastMeasure, lastMeasure->ticks(), ctx, false);
320 :
321 10 : if (mmrClefSeg && lastMeasureClefSeg) {
322 0 : lastMeasureClefSeg->setEnabled(mmrClefSeg->enabled());
323 0 : lastMeasureClefSeg->setTrailer(mmrClefSeg->trailer());
324 : }
325 :
326 : // restore time signature segments from mmrMeasure to the first underlying measure
327 10 : Segment* mmrTimeSigSeg = mmrMeasure->findSegmentR(SegmentType::TimeSig, Fraction(0, 1));
328 10 : Segment* firstMeasureTimeSigSeg = changeElementsParent(mmrTimeSigSeg, firstMeasure, Fraction(0, 1), ctx, false);
329 :
330 10 : if (mmrTimeSigSeg && firstMeasureTimeSigSeg) {
331 3 : firstMeasureTimeSigSeg->setEnabled(mmrTimeSigSeg->enabled());
332 3 : firstMeasureTimeSigSeg->setHeader(mmrTimeSigSeg->header());
333 : }
334 :
335 : // restore end-of-measure time signature segment from mmrMeasure to the last underlying measure
336 10 : Segment* mmrEndTimeSigSeg = mmrMeasure->findSegmentR(SegmentType::TimeSig, mmrMeasure->ticks());
337 10 : Segment* lastMeasureEndTimeSigSeg = changeElementsParent(mmrEndTimeSigSeg, lastMeasure, lastMeasure->ticks(), ctx, false);
338 :
339 10 : if (mmrEndTimeSigSeg && lastMeasureEndTimeSigSeg) {
340 0 : lastMeasureEndTimeSigSeg->setEnabled(mmrEndTimeSigSeg->enabled());
341 0 : lastMeasureEndTimeSigSeg->setHeader(mmrEndTimeSigSeg->header());
342 0 : lastMeasureEndTimeSigSeg->setEndOfMeasureChange(mmrEndTimeSigSeg->endOfMeasureChange());
343 : }
344 :
345 : // restore breath segment from mmrMeasure to the last underlying measure
346 10 : Segment* mmrBreathSeg = mmrMeasure->findSegmentR(SegmentType::Breath, mmrMeasure->ticks());
347 10 : changeElementsParent(mmrBreathSeg, lastMeasure, lastMeasure->ticks(), ctx, false);
348 :
349 : // restore ambitus segment from mmrMeasure to the first underlying measure
350 10 : Segment* mmrAmbitusSeg = mmrMeasure->findSegmentR(SegmentType::Ambitus, Fraction(0, 1));
351 10 : changeElementsParent(mmrAmbitusSeg, firstMeasure, Fraction(0, 1), ctx, false);
352 :
353 : // restore key signature segment from mmrMeasure to the first underlying measure
354 10 : Segment* mmrKeySigSeg = mmrMeasure->findSegmentR(SegmentType::KeySig, Fraction(0, 1));
355 10 : Segment* firstMeasureKeySigSeg = changeElementsParent(mmrKeySigSeg, firstMeasure, Fraction(0, 1), ctx, false);
356 :
357 10 : if (mmrKeySigSeg && firstMeasureKeySigSeg) {
358 5 : firstMeasureKeySigSeg->setEnabled(mmrKeySigSeg->enabled());
359 5 : firstMeasureKeySigSeg->setHeader(mmrKeySigSeg->header());
360 : }
361 :
362 10 : firstMeasure->checkHeader();
363 10 : lastMeasure->checkTrailer();
364 :
365 : // restore annotations from the mmr chord/rest segment back to the first underlying measure
366 10 : Segment* mmrChordRestSeg = mmrMeasure->undoGetSegmentR(SegmentType::ChordRest, Fraction(0, 1));
367 10 : Segment* underlyingCRSeg = firstMeasure->findSegmentR(SegmentType::ChordRest, Fraction(0, 1));
368 10 : changeAnnotationsParent(mmrChordRestSeg, underlyingCRSeg, ctx, false);
369 10 : }
370 :
371 356 : void MMRestLayout::changeAnnotationsParent(Segment* oldParent, Segment* newParent, const LayoutContext& ctx, bool checkVisibility)
372 : {
373 356 : if (!oldParent || !newParent) {
374 0 : return;
375 : }
376 356 : std::vector<EngravingItem*> annotations = oldParent->annotations();
377 367 : for (EngravingItem* e : annotations) {
378 : // look at elements in underlying measure
379 11 : if (!muse::contains(BREAK_TYPES, e->type())) {
380 0 : continue;
381 : }
382 11 : if (checkVisibility && (!e->visible() || !ctx.dom().staff(e->staffIdx())->show())) {
383 0 : continue;
384 : }
385 :
386 11 : if (e->isInstrumentChange()) {
387 : /* InstrumentChange items register their Instrument in Part::instruments(), keyed by the tick of
388 : * the segment they belong to (see Segment::add/remove). Re-parenting one to a segment at a different
389 : * tick would re-key that entry, making the instrument change take effect at the wrong time: */
390 0 : DO_ASSERT_X(oldParent->tick() == newParent->tick(), "Changing InstrumentChange's parent to a different tick");
391 : }
392 :
393 11 : e->score()->undoChangeParent(e, newParent, e->staffIdx(), false);
394 : }
395 356 : }
396 :
397 1387 : Segment* MMRestLayout::changeElementsParent(Segment* oldSeg, Measure* newMeasure, const Fraction& newSegTick,
398 : LayoutContext& ctx, bool checkVisibility)
399 : {
400 : // Moves elements in oldSeg to newSeg at newSegTick in newMeasure. Creates a new segment if no new seg exists
401 1387 : if (!oldSeg) {
402 1204 : return nullptr;
403 : }
404 183 : Segment* newSeg = newMeasure->undoGetSegmentR(oldSeg->segmentType(), newSegTick);
405 390 : for (size_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
406 207 : const track_idx_t track = staff2track(staffIdx);
407 207 : EngravingItem* el = oldSeg->element(track);
408 207 : if (!el || !el->visible()) {
409 71 : continue;
410 : }
411 136 : if (checkVisibility && (!el->visible() || !ctx.dom().staff(staffIdx)->show())) {
412 0 : continue;
413 : }
414 136 : ctx.mutDom().undoChangeParent(el, newSeg, el->staffIdx(), false);
415 : }
416 :
417 183 : changeAnnotationsParent(oldSeg, newSeg, ctx, checkVisibility);
418 :
419 183 : return newSeg;
420 : }
421 :
422 : //---------------------------------------------------------
423 : // validMMRestMeasure
424 : // return true if this might be a measure in a
425 : // multi measure rest
426 : //---------------------------------------------------------
427 :
428 1123 : bool MMRestLayout::validMMRestMeasure(const LayoutContext& ctx, const Measure* m)
429 : {
430 1123 : if (m->excludeFromNumbering()) {
431 0 : return false;
432 : }
433 :
434 1123 : size_t nstaves = ctx.dom().nstaves();
435 2448 : for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
436 1329 : if (!ctx.dom().staff(staffIdx)->show()) {
437 66 : continue;
438 : }
439 :
440 1263 : if (m->isMeasureRepeatGroup(staffIdx)) {
441 4 : return false;
442 : }
443 : }
444 :
445 1119 : int n = 0;
446 2412 : for (const Segment* s = m->first(); s; s = s->next()) {
447 1780 : for (const EngravingItem* e : s->annotations()) {
448 59 : if (e->staffIdx() >= nstaves || !e->staff()->show() || !e->visible()) {
449 4 : continue;
450 : }
451 55 : if (muse::contains(BREAK_TYPES, e->type()) && !s->rtick().isZero()) {
452 : // play count text and fermatas are permitted at the end of a measure
453 0 : if (!e->isPlayCountText() && !e->isFermata()) {
454 0 : return false;
455 : }
456 : }
457 : }
458 1721 : size_t tracks = ctx.dom().ntracks();
459 1721 : if (!s->isChordRestType()) {
460 585 : continue;
461 : }
462 1136 : bool restFound = false;
463 4412 : for (track_idx_t track = 0; track < tracks; ++track) {
464 3700 : if ((track % VOICES) == 0 && !ctx.dom().staff(track / VOICES)->show()) {
465 60 : track += VOICES - 1;
466 60 : continue;
467 : }
468 3640 : if (!s->element(track)) {
469 2412 : continue;
470 : }
471 1228 : if (!s->element(track)->isRest()) {
472 424 : return false;
473 : } else {
474 804 : bool isNonEmptyIrregular = m->isIrregular() && !toRest(s->element(track))->isFullMeasureRest();
475 804 : if (isNonEmptyIrregular) {
476 0 : return false;
477 : }
478 : }
479 804 : restFound = true;
480 : }
481 722 : for (const EngravingItem* e : s->annotations()) {
482 10 : if (e->isFermata()) {
483 0 : return false;
484 : }
485 : }
486 712 : if (restFound) {
487 700 : ++n;
488 : }
489 : // measure is not empty if there is more than one rest
490 712 : if (n > 1) {
491 4 : return false;
492 : }
493 : }
494 691 : return true;
495 : }
496 :
497 513 : bool MMRestLayout::breakMMRForElement(Measure* measure, Measure* prevMeasure, const LayoutContext& ctx)
498 : {
499 10 : auto breakForAnnotation = [&](EngravingItem* e) {
500 10 : if (muse::contains(ALWAYS_BREAK_TYPES, e->type())) {
501 0 : return true;
502 : }
503 10 : bool breakForElement = e->systemFlag() || e->staff()->show();
504 10 : if (muse::contains(CONDITIONAL_BREAK_TYPES, e->type()) && breakForElement) {
505 10 : return true;
506 : }
507 0 : return false;
508 : };
509 :
510 : // break for marker in this measure
511 530 : for (EngravingItem* e : measure->el()) {
512 17 : if (e->isMarker()) {
513 0 : Marker* mark = toMarker(e);
514 0 : if (!(mark->align() == AlignH::RIGHT)) {
515 0 : return true;
516 : }
517 : }
518 : }
519 :
520 1215 : for (Segment* s = measure->first(); s; s = s->next()) {
521 731 : for (EngravingItem* e : s->annotations()) {
522 10 : if (!e->visible()) {
523 0 : continue;
524 : }
525 10 : if (breakForAnnotation(e)) {
526 10 : return true;
527 : }
528 : }
529 1602 : for (size_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
530 900 : if (!ctx.dom().staff(staffIdx)->show()) {
531 48 : continue;
532 : }
533 852 : EngravingItem* e = s->element(staffIdx * VOICES);
534 852 : if (!e || e->generated()) {
535 273 : continue;
536 : }
537 579 : if (s->isStartRepeatBarLineType()) {
538 0 : return true;
539 : }
540 579 : if (s->isType(SegmentType::KeySig | SegmentType::TimeSig) && measure->tick().isNotZero()) {
541 19 : return true;
542 : }
543 560 : if (s->isClefType()) {
544 0 : if (s->tick() != measure->endTick() && measure->tick().isNotZero()) {
545 0 : return true;
546 : }
547 : }
548 : }
549 : }
550 :
551 484 : if (!prevMeasure) {
552 0 : return false;
553 : }
554 :
555 : // break for marker & jump in previous measure
556 484 : for (EngravingItem* e : prevMeasure->el()) {
557 3 : if (e->isJump()) {
558 3 : return true;
559 0 : } else if (e->isMarker()) {
560 0 : Marker* mark = toMarker(e);
561 0 : if (mark->align() == AlignH::RIGHT) {
562 0 : return true;
563 : }
564 : }
565 : }
566 :
567 : // Break for breaths and annotations found mid-way into the previous measure
568 1258 : for (Segment* s = prevMeasure->first(); s; s = s->next()) {
569 1756 : for (size_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
570 979 : if (!ctx.dom().staff(staffIdx)->show()) {
571 54 : continue;
572 : }
573 925 : EngravingItem* e = s->element(staffIdx * VOICES);
574 925 : if (!e || e->generated()) {
575 318 : continue;
576 : }
577 607 : if (s->isBreathType()) {
578 2 : return true;
579 : }
580 : }
581 :
582 785 : for (EngravingItem* e : s->annotations()) {
583 8 : if (!e->visible()) {
584 0 : continue;
585 : }
586 8 : if (e->rtick() == Fraction(0, 1)) {
587 8 : continue;
588 : }
589 0 : if (breakForAnnotation(e) || e->isFermata()) {
590 0 : return true;
591 : }
592 : }
593 : }
594 :
595 : // Break for non-normal end barline in previous measure
596 479 : Segment* endBarSeg = prevMeasure->findSegmentR(SegmentType::EndBarLine, prevMeasure->ticks());
597 479 : if (endBarSeg) {
598 160 : for (size_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
599 123 : BarLine* bl = toBarLine(endBarSeg->element(staffIdx * VOICES));
600 123 : if (!bl) {
601 37 : continue;
602 : }
603 86 : BarLineType t = bl->barLineType();
604 86 : if (t != BarLineType::NORMAL && t != BarLineType::BROKEN && t != BarLineType::DOTTED && !bl->generated()) {
605 0 : return true;
606 : } else {
607 86 : break;
608 : }
609 : }
610 : }
611 :
612 : // Break for courtesy clefs/sigs at the end of the previous measure,
613 : // only if the element is on a visible staff
614 0 : auto hasVisibleElement = [&ctx](Segment* seg) -> bool {
615 0 : for (size_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
616 0 : if (!ctx.dom().staff(staffIdx)->show()) {
617 0 : continue;
618 : }
619 0 : EngravingItem* e = seg->element(staffIdx * VOICES);
620 0 : if (e && !e->generated()) {
621 0 : return true;
622 : }
623 : }
624 0 : return false;
625 479 : };
626 :
627 479 : if (Segment* clefSeg = prevMeasure->findSegment(SegmentType::Clef, measure->tick())) {
628 0 : if (hasVisibleElement(clefSeg)) {
629 0 : return true;
630 : }
631 : }
632 479 : if (Segment* tsSeg = prevMeasure->findSegment(SegmentType::TimeSigTypes, measure->tick())) {
633 0 : if (hasVisibleElement(tsSeg)) {
634 0 : return true;
635 : }
636 : }
637 479 : if (Segment* ksSeg = prevMeasure->findSegment(SegmentType::KeySigTypes, measure->tick())) {
638 0 : if (hasVisibleElement(ksSeg)) {
639 0 : return true;
640 : }
641 : }
642 :
643 479 : return false;
644 : }
645 :
646 : //---------------------------------------------------------
647 : // breakMultiMeasureRest
648 : // return true if this measure should start a new
649 : // multi measure rest
650 : //---------------------------------------------------------
651 :
652 512 : bool MMRestLayout::breakMultiMeasureRest(const LayoutContext& ctx, Measure* m)
653 : {
654 512 : if (m->breakMultiMeasureRest()) {
655 16 : return true;
656 : }
657 :
658 496 : if (m->repeatStart()
659 496 : || (m->prevMeasure() && m->prevMeasure()->repeatEnd())
660 494 : || (m->isIrregular())
661 494 : || (m->prevMeasure() && m->prevMeasure()->isIrregular())
662 992 : || (m->prevMeasure() && (m->prevMeasure()->sectionBreak()))) {
663 2 : return true;
664 : }
665 :
666 : static const std::set<ElementType> breakSpannerTypes {
667 : ElementType::VOLTA,
668 : ElementType::GRADUAL_TEMPO_CHANGE,
669 : ElementType::TEXTLINE,
670 500 : };
671 : // Break for spanners/textLines in this measure
672 494 : auto sl = ctx.dom().spannerMap().findOverlapping(m->tick().ticks(), m->endTick().ticks());
673 506 : for (auto i : sl) {
674 20 : Spanner* s = i.value;
675 20 : if (!s->visible()) {
676 0 : continue;
677 : }
678 20 : Fraction spannerStart = s->tick();
679 20 : Fraction spannerEnd = s->tick2();
680 20 : Fraction measureStart = m->tick();
681 20 : Fraction measureEnd = m->endTick();
682 20 : bool spannerStartsInside = spannerStart >= measureStart && spannerStart < measureEnd;
683 20 : bool spannerEndsInside = spannerEnd >= measureStart && spannerEnd < measureEnd;
684 20 : if (muse::contains(breakSpannerTypes, s->type()) && (spannerStartsInside || spannerEndsInside)) {
685 8 : return true;
686 : }
687 : }
688 : // Break for spanners/textLines starting or ending mid-way inside the *previous* measure
689 486 : Measure* prevMeas = m->prevMeasure();
690 486 : if (prevMeas) {
691 486 : auto prevMeasSpanners = ctx.dom().spannerMap().findOverlapping(prevMeas->tick().ticks(), prevMeas->endTick().ticks());
692 500 : for (auto i : prevMeasSpanners) {
693 14 : Spanner* s = i.value;
694 14 : if (!s->visible()) {
695 0 : continue;
696 : }
697 14 : Fraction spannerStart = s->tick();
698 14 : Fraction spannerEnd = s->tick2();
699 14 : Fraction measureStart = prevMeas->tick();
700 14 : Fraction measureEnd = prevMeas->endTick();
701 14 : bool spannerStartsInside = spannerStart > measureStart && spannerStart < measureEnd;
702 14 : bool spannerEndsInside = spannerEnd > measureStart && spannerEnd < measureEnd;
703 14 : if (muse::contains(breakSpannerTypes, s->type()) && (spannerStartsInside || spannerEndsInside)) {
704 0 : return true;
705 : }
706 : }
707 486 : }
708 :
709 486 : bool breakRest = breakMMRForElement(m, prevMeas, ctx);
710 :
711 486 : Measure* mmrest = m->mmRest();
712 486 : Measure* mmrestPrev = mmrest ? m->mmRest()->prevMeasureMM() : nullptr;
713 :
714 : // If we are creating MMRests from expanded notation, checking underlying measures is sufficient.
715 : // If we are updating MMRests which are already being shown (any layout update) we must also check that the elements dictating their boundaries are still present
716 : // This is because elements are moved between underlying and covering measures
717 486 : if (mmrest && (mmrest->mmRestFirst() == m || mmrest->mmRestLast() == m)) {
718 27 : breakRest |= breakMMRForElement(mmrest, mmrestPrev, ctx);
719 : }
720 :
721 486 : return breakRest;
722 494 : }
723 :
724 30511 : void MMRestLayout::createMultiMeasureRestsIfNeed(Measure* firstMeasure, LayoutContext& ctx)
725 : {
726 : LAYOUT_CALL() << LAYOUT_ITEM_INFO(firstMeasure);
727 :
728 30511 : if (ctx.dom().nstaves() == 0) {
729 96 : return;
730 : }
731 :
732 30415 : int mn = ctx.state().measureNumber();
733 :
734 30415 : if (ctx.conf().styleB(Sid::createMultiMeasureRests)) {
735 546 : Measure* measureToBeChecked = firstMeasure;
736 546 : Measure* lastMeasure = measureToBeChecked;
737 546 : int n = 0;
738 546 : Fraction len;
739 :
740 1123 : while (validMMRestMeasure(ctx, measureToBeChecked)) {
741 691 : if (n && breakMultiMeasureRest(ctx, measureToBeChecked)) {
742 59 : break;
743 : }
744 632 : if (measureToBeChecked != firstMeasure) {
745 453 : int measureNumber = MeasureLayout::adjustMeasureNumber(measureToBeChecked, ctx.state().measureNumber());
746 453 : ctx.mutState().setMeasureNumber(measureNumber);
747 : }
748 632 : ++n;
749 632 : len += measureToBeChecked->ticks();
750 632 : lastMeasure = measureToBeChecked;
751 632 : MeasureBase* nextMeasureBase = ctx.conf().isShowVBox() ? measureToBeChecked->next() : measureToBeChecked->nextMeasure();
752 632 : if (!(nextMeasureBase && nextMeasureBase->isMeasure())) {
753 55 : break;
754 : }
755 577 : measureToBeChecked = toMeasure(nextMeasureBase);
756 : }
757 :
758 546 : if (n >= ctx.conf().styleI(Sid::minEmptyMeasures)) {
759 163 : createMMRest(ctx, firstMeasure, lastMeasure, len);
760 163 : ctx.mutState().setCurMeasure(firstMeasure->mmRest());
761 163 : ctx.mutState().setNextMeasure(ctx.conf().isShowVBox() ? lastMeasure->next() : lastMeasure->nextMeasure());
762 : } else {
763 383 : if (firstMeasure->mmRest()) {
764 3 : removeMMRestElements(firstMeasure->mmRest(), ctx);
765 3 : ctx.mutDom().undo(new ChangeMMRest(firstMeasure, nullptr));
766 : }
767 383 : ctx.mutState().setMeasureNumber(mn);
768 : }
769 29869 : } else if (firstMeasure->mmRest()) {
770 5 : removeMMRestElements(firstMeasure->mmRest(), ctx);
771 :
772 5 : if (firstMeasure->mmRestCount() > 0) {
773 0 : LOGD("mmrest: measureNumber %d += %d", ctx.state().measureNumber(), firstMeasure->mmRestCount());
774 0 : int measureNumber = ctx.state().measureNumber() + firstMeasure->mmRestCount() - 1;
775 0 : ctx.mutState().setMeasureNumber(measureNumber);
776 : }
777 : }
778 : }
779 :
780 8 : void MMRestLayout::removeMMRestElements(Measure* mmrMeasure, LayoutContext& ctx)
781 : {
782 : // Move elements from MMRest measure back to underlying
783 8 : Measure* firstMeasure = mmrMeasure->mmRestFirst();
784 8 : Measure* lastMeasure = mmrMeasure->mmRestLast();
785 8 : IF_ASSERT_FAILED(firstMeasure && lastMeasure) {
786 0 : return;
787 : }
788 :
789 8 : restoreMeasureElParents(firstMeasure, lastMeasure, mmrMeasure, ctx);
790 : }
791 :
792 31790 : void MMRestLayout::layoutMMRestRange(Measure* m, LayoutContext& ctx)
793 : {
794 31790 : if (!m->isMMRest() || !ctx.conf().styleB(Sid::mmRestShowMeasureNumberRange)) {
795 : // Remove existing
796 78630 : for (unsigned staffIdx = 0; staffIdx < m->mstaves().size(); ++staffIdx) {
797 46840 : const MStaff* ms = m->mstaves().at(staffIdx);
798 46840 : MMRestRange* rr = ms->mmRangeText();
799 46840 : if (rr) {
800 0 : ctx.mutDom().doUndoRemoveElement(rr);
801 : }
802 : }
803 :
804 31790 : return;
805 : }
806 :
807 0 : String s;
808 0 : if (m->mmRestCount() > 1) {
809 : // middle char is an en dash (not em)
810 0 : s = String(u"%1–%2").arg(m->measureNumber() + 1).arg(m->measureNumber() + m->mmRestCount());
811 : } else {
812 : // If the minimum range to create a mmrest is set to 1,
813 : // then simply show the measure number as there is no range
814 0 : s = String::number(m->measureNumber() + 1);
815 : }
816 :
817 0 : for (unsigned staffIdx = 0; staffIdx < m->mstaves().size(); ++staffIdx) {
818 0 : const MStaff* ms = m->mstaves().at(staffIdx);
819 0 : MMRestRange* rr = ms->mmRangeText();
820 0 : if (!rr) {
821 0 : rr = new MMRestRange(m);
822 0 : rr->setTrack(staffIdx * VOICES);
823 0 : rr->setGenerated(true);
824 0 : m->add(rr);
825 : }
826 : // setXmlText is reimplemented to take care of brackets
827 0 : rr->setXmlText(s);
828 0 : TLayout::layoutMMRestRange(rr, rr->mutldata(), ctx);
829 : }
830 0 : }
|