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) 2023 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 <cfloat>
23 :
24 : #include "measurelayout.h"
25 :
26 : #include "iengravingconfiguration.h" // IWYU pragma: keep
27 :
28 : #include "dom/ambitus.h"
29 : #include "dom/barline.h"
30 : #include "dom/beam.h"
31 : #include "dom/factory.h"
32 : #include "dom/keysig.h"
33 : #include "dom/layoutbreak.h"
34 : #include "dom/lyrics.h"
35 : #include "dom/marker.h"
36 : #include "dom/measure.h"
37 : #include "dom/measurenumber.h"
38 : #include "dom/measurerepeat.h"
39 : #include "dom/mmrest.h"
40 : #include "dom/mmrestrange.h"
41 : #include "dom/part.h"
42 : #include "dom/parenthesis.h"
43 : #include "dom/spacer.h"
44 : #include "dom/score.h"
45 : #include "dom/staff.h"
46 : #include "dom/stafflines.h"
47 : #include "dom/system.h"
48 : #include "dom/tie.h"
49 : #include "dom/timesig.h"
50 : #include "dom/tremolosinglechord.h"
51 : #include "dom/tremolotwochord.h"
52 : #include "dom/utils.h"
53 :
54 : #include "editing/editkeysig.h"
55 : #include "types/typesconv.h"
56 :
57 : #include "arpeggiolayout.h"
58 : #include "beamlayout.h"
59 : #include "chordbracketlayout.h"
60 : #include "chordlayout.h"
61 : #include "horizontalspacing.h"
62 : #include "layoutcontext.h"
63 : #include "mmrestlayout.h"
64 : #include "modifydom.h"
65 : #include "parenthesislayout.h"
66 : #include "restlayout.h"
67 : #include "segmentlayout.h"
68 : #include "slurtielayout.h"
69 : #include "tlayout.h"
70 : #include "tremololayout.h"
71 :
72 : #include "log.h"
73 :
74 : using namespace mu::engraving;
75 : using namespace mu::engraving::rtti;
76 : using namespace mu::engraving::rendering::score;
77 :
78 : //---------------------------------------------------------
79 : // layout2
80 : // called after layout of page
81 : //---------------------------------------------------------
82 :
83 33503 : void MeasureLayout::layout2(Measure* item, LayoutContext& ctx)
84 : {
85 33503 : assert(item->system());
86 33503 : assert(ctx.dom().nstaves() == item->mstaves().size());
87 :
88 82235 : for (size_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
89 48732 : if (Spacer* sp = item->vspacerDown(staffIdx)) {
90 2 : TLayout::layoutSpacer(sp, ctx);
91 2 : double y = item->system()->staff(staffIdx)->y() + sp->staffOffsetY();
92 2 : sp->setPos(item->spatium() * .5, y + sp->staff()->staffHeight(item->tick()));
93 : }
94 48732 : if (Spacer* sp = item->vspacerUp(staffIdx)) {
95 0 : TLayout::layoutSpacer(sp, ctx);
96 0 : double y = item->system()->staff(staffIdx)->y() + sp->staffOffsetY();
97 0 : sp->setPos(item->spatium() * .5, y - sp->absoluteGap());
98 : }
99 : }
100 :
101 : // layout LAYOUT_BREAK elements
102 33503 : TLayout::layoutBaseMeasureBase(item, item->mutldata(), ctx);
103 :
104 : //---------------------------------------------------
105 : // layout cross-staff ties
106 : //---------------------------------------------------
107 :
108 49421 : auto layoutCrossStaffTies = [](Chord* chord, Measure* item, const Fraction& stick, LayoutContext& ctx) ->void {
109 108058 : for (Note* note : chord->notes()) {
110 58637 : Tie* tieFor = note->tieFor();
111 58637 : Tie* tieBack = note->tieBack();
112 58637 : LaissezVib* lv = note->laissezVib();
113 58637 : if (lv && lv->isCrossStaff()) {
114 0 : SlurTieLayout::layoutLaissezVibChord(chord, ctx);
115 : }
116 58637 : if (tieFor && !lv && tieFor->isCrossStaff()) {
117 4 : SlurTieLayout::layoutTieFor(tieFor, item->system());
118 : }
119 58637 : if (tieBack && tieBack->tick() < stick && tieBack->isCrossStaff()) {
120 0 : SlurTieLayout::layoutTieBack(tieBack, item->system(), ctx);
121 : }
122 : }
123 49421 : };
124 :
125 33503 : const Fraction stick = item->system()->measures().front()->tick();
126 33503 : const size_t tracks = ctx.dom().ntracks();
127 : static const SegmentType st { SegmentType::ChordRest };
128 226442 : for (track_idx_t track = 0; track < tracks; ++track) {
129 192939 : if (!ctx.dom().staff(track2staff(track))->show()) {
130 663 : track += VOICES - 1;
131 663 : continue;
132 : }
133 563008 : for (Segment* seg = item->first(st); seg; seg = seg->next(st)) {
134 370732 : EngravingItem* element = seg->element(track);
135 370732 : if (!element || !element->isChord()) {
136 322220 : continue;
137 : }
138 48512 : Chord* chord = toChord(element);
139 48512 : layoutCrossStaffTies(chord, item, stick, ctx);
140 :
141 49421 : for (Chord* graceChord : chord->graceNotes()) {
142 909 : layoutCrossStaffTies(graceChord, item, stick, ctx);
143 : }
144 : }
145 : }
146 33503 : }
147 :
148 36768 : void MeasureLayout::moveToNextMeasure(LayoutContext& ctx)
149 : {
150 : LAYOUT_CALL();
151 36768 : LayoutState& state = ctx.mutState();
152 :
153 36768 : state.setPrevMeasure(state.curMeasure());
154 36768 : state.setCurMeasure(state.nextMeasure());
155 36768 : if (!state.curMeasure()) {
156 3822 : state.setNextMeasure(ctx.conf().isShowVBox() ? ctx.mutDom().first() : ctx.mutDom().firstMeasure());
157 : } else {
158 32946 : MeasureBase* m = ctx.conf().isShowVBox() ? state.curMeasure()->next() : state.curMeasure()->nextMeasure();
159 32946 : state.setNextMeasure(m);
160 : }
161 36768 : }
162 :
163 30347 : void MeasureLayout::checkStaffMoveValidity(Measure* measure, const LayoutContext& ctx)
164 : {
165 124438 : for (const Segment& segment : measure->segments()) {
166 94091 : if (!segment.isJustType(SegmentType::ChordRest)) {
167 30787 : continue;
168 : }
169 :
170 418080 : for (track_idx_t t = 0; t < ctx.dom().nstaves() * VOICES; ++t) {
171 354776 : ChordRest* cr = toChordRest(segment.element(t));
172 354776 : if (cr) {
173 : // Check if requested cross-staff is possible
174 87905 : if (cr->staffMove() || cr->storedStaffMove()) {
175 215 : cr->checkStaffMoveValidity();
176 : }
177 : }
178 : }
179 : }
180 30347 : }
181 :
182 34473 : void MeasureLayout::layoutMeasure(MeasureBase* currentMB, LayoutContext& ctx)
183 : {
184 34473 : if (!currentMB || !currentMB->isMeasure()) {
185 2437 : return;
186 : }
187 :
188 32036 : Measure* measure = toMeasure(currentMB);
189 :
190 32036 : if (!measure->ldata()->needLayout()) {
191 1593 : return;
192 : }
193 :
194 30443 : if (ctx.conf().isLinearMode() && (measure->tick() < ctx.state().startTick() || measure->tick() > ctx.state().endTick())) {
195 0 : return;
196 : }
197 :
198 30443 : if (ctx.dom().allStavesInvisible()) {
199 96 : return;
200 : }
201 :
202 30347 : measure->mutldata()->setNeedLayout(false);
203 :
204 : // Check if requested cross-staff is possible
205 : // This must happen before cmdUpdateNotes
206 30347 : checkStaffMoveValidity(measure, ctx);
207 :
208 : // ---- Modify DOM ----
209 30347 : ModifyDom::setCrossMeasure(measure, ctx);
210 30347 : ModifyDom::connectTremolo(measure);
211 30347 : ModifyDom::cmdUpdateNotes(measure, ctx.dom());
212 30347 : ModifyDom::createStems(measure, ctx);
213 30347 : ModifyDom::setTrackForChordGraceNotes(measure, ctx.dom());
214 30347 : ModifyDom::sortMeasureSegments(measure, ctx);
215 : // --------------------
216 : //
217 : // calculate accidentals and note lines,
218 : // create stem and set stem direction
219 : //
220 :
221 30347 : const DomAccessor& dom = ctx.dom();
222 30347 : const LayoutConfiguration& conf = ctx.conf();
223 :
224 74673 : for (size_t staffIdx = 0; staffIdx < dom.nstaves(); ++staffIdx) {
225 44326 : const Staff* staff = dom.staff(staffIdx);
226 :
227 44326 : track_idx_t startTrack = staffIdx * VOICES;
228 44326 : track_idx_t endTrack = startTrack + VOICES;
229 :
230 180666 : for (const Segment& segment : measure->segments()) {
231 136340 : if (!staff->show() && !segment.isType(SegmentType::TimeSigTypes)) {
232 1827 : continue;
233 : }
234 :
235 134513 : SegmentLayout::layoutMeasureIndependentElements(segment, startTrack, ctx);
236 :
237 134513 : if (!segment.isJustType(SegmentType::ChordRest)) {
238 46667 : continue;
239 : }
240 :
241 : //! NOTE Maybe it makes sense to group these methods by chord
242 :
243 87846 : SegmentLayout::setChordMag(staff, segment, startTrack, endTrack, conf);
244 :
245 87846 : SegmentLayout::layoutChordDrumset(staff, segment, startTrack, endTrack, conf);
246 :
247 87846 : SegmentLayout::computeChordsUp(segment, startTrack, endTrack, ctx);
248 :
249 87846 : SegmentLayout::layoutChordsStem(segment, startTrack, endTrack, ctx);
250 : }
251 : }
252 :
253 30347 : BeamLayout::createBeams(ctx, measure);
254 :
255 : /* HACK: The real beam layout is computed at much later stage (you can't do the beams until you know
256 : * horizontal spacing). However, horizontal spacing needs to know stems extensions to avoid collision
257 : * with stems, and stems extensions depend on beams. Solution: we compute dummy beams here, *before*
258 : * horizontal spacing. It is pointless for the beams themselves, but it *does* correctly extend the
259 : * stems, thus allowing to compute horizontal spacing correctly. (M.S.) */
260 124445 : for (Segment& s : measure->segments()) {
261 94098 : if (!s.isChordRestType()) {
262 30794 : continue;
263 : }
264 418080 : for (EngravingItem* item : s.elist()) {
265 354776 : if (!item || !item->isChordRest()) {
266 266871 : continue;
267 : }
268 87905 : if (const Staff* staff = ctx.dom().staff(item->vStaffIdx()); staff && staff->show()) {
269 87101 : BeamLayout::layoutNonCrossBeams(toChordRest(item), ctx);
270 : }
271 : }
272 : }
273 :
274 74673 : for (staff_idx_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
275 44326 : const Staff* staff = ctx.dom().staff(staffIdx);
276 44326 : if (!staff->show()) {
277 667 : continue;
278 : }
279 :
280 178082 : for (Segment& segment : measure->segments()) {
281 134423 : if (segment.isChordRestType()) {
282 87846 : ChordLayout::layoutChords1(ctx, &segment, staffIdx);
283 87846 : RestLayout::resolveVerticalRestConflicts(ctx, &segment, staffIdx);
284 439230 : for (voice_idx_t voice = 0; voice < VOICES; ++voice) {
285 351384 : ChordRest* cr = segment.cr(staffIdx * VOICES + voice);
286 351384 : if (cr) {
287 89281 : for (Lyrics* l : cr->lyrics()) {
288 2180 : if (l) {
289 2180 : TLayout::layoutLyrics(l, ctx);
290 : }
291 : }
292 : }
293 : }
294 : }
295 : }
296 : }
297 :
298 124445 : for (Segment& segment : measure->segments()) {
299 94098 : if (segment.isBreathType()) {
300 965 : for (EngravingItem* e : segment.elist()) {
301 824 : if (e && e->isBreath()) {
302 168 : TLayout::layoutItem(e, ctx);
303 : }
304 : }
305 93957 : } else if (segment.isChordRestType()) {
306 63304 : ChordBracketLayout::layoutSegment(&segment, ctx);
307 70501 : for (EngravingItem* e : segment.annotations()) {
308 7197 : if (e->isSymbol() || e->isHarmony() || e->isFretDiagram()) {
309 2641 : TLayout::layoutItem(e, ctx);
310 : }
311 : }
312 : }
313 : }
314 :
315 30347 : Segment* seg = measure->findSegmentR(SegmentType::StartRepeatBarLine, Fraction(0, 1));
316 30347 : if (measure->repeatStart()) {
317 225 : if (!seg) {
318 133 : seg = measure->getSegmentR(SegmentType::StartRepeatBarLine, Fraction(0, 1));
319 : }
320 225 : barLinesSetSpan(seg, ctx); // this also creates necessary barlines
321 567 : for (size_t staffIdx = 0; staffIdx < ctx.dom().nstaves(); ++staffIdx) {
322 342 : BarLine* b = toBarLine(seg->element(staffIdx * VOICES));
323 342 : if (b) {
324 342 : b->setBarLineType(BarLineType::START_REPEAT);
325 342 : TLayout::layoutBarLine(b, b->mutldata(), ctx);
326 : }
327 : }
328 30122 : } else if (seg) {
329 4 : ctx.mutDom().undoRemoveElement(seg);
330 : }
331 :
332 124574 : for (Segment& s : measure->segments()) {
333 94227 : if (s.isEndBarLineType()) {
334 15814 : continue;
335 : }
336 78413 : s.createShapes();
337 : }
338 :
339 30347 : measure->computeTicks(); // Must be called *after* Segment::createShapes() because it relies on the
340 : // Segment::visible() property, which is determined by Segment::createShapes().
341 : }
342 :
343 55377 : void MeasureLayout::updateGraceNotes(Measure* measure, LayoutContext& ctx)
344 : {
345 : // Clean everything
346 265405 : for (Segment& s : measure->segments()) {
347 1432488 : for (track_idx_t track = 0; track < ctx.dom().ntracks(); ++track) {
348 1222460 : EngravingItem* e = s.preAppendedItem(track);
349 1222460 : if (e && e->isGraceNotesGroup()) {
350 531 : s.clearPreAppended(track);
351 531 : std::set<staff_idx_t> stavesToReShape;
352 1227 : for (Chord* grace : *toGraceNotesGroup(e)) {
353 696 : stavesToReShape.insert(grace->staffIdx());
354 696 : stavesToReShape.insert(grace->vStaffIdx());
355 : }
356 1054 : for (staff_idx_t staffToReshape : stavesToReShape) {
357 523 : s.createShape(staffToReshape);
358 : }
359 531 : }
360 : }
361 : }
362 :
363 : // Append grace notes to appropriate segment
364 265405 : for (Segment& s : measure->segments()) {
365 210028 : if (!s.isChordRestType()) {
366 98188 : continue;
367 : }
368 740808 : for (auto el : s.elist()) {
369 628968 : if (el && el->isChord() && !toChord(el)->graceNotes().empty()) {
370 994 : ChordLayout::appendGraceNotes(toChord(el));
371 : }
372 : }
373 : }
374 :
375 : // Layout grace note groups
376 265405 : for (Segment& s : measure->segments()) {
377 1432488 : for (track_idx_t track = 0; track < ctx.dom().ntracks(); ++track) {
378 1222460 : EngravingItem* e = s.preAppendedItem(track);
379 1222460 : if (e && e->isGraceNotesGroup()) {
380 1028 : GraceNotesGroup* gng = toGraceNotesGroup(e);
381 1028 : TLayout::layoutGraceNotesGroup(gng, ctx);
382 1028 : gng->addToShape();
383 : }
384 : }
385 : }
386 55377 : }
387 :
388 36768 : void MeasureLayout::getNextMeasure(LayoutContext& ctx)
389 : {
390 36783 : TRACEFUNC;
391 : LAYOUT_CALL();
392 :
393 36768 : moveToNextMeasure(ctx);
394 :
395 36768 : updateTicksMeasNumbersAndMMRests(ctx.mutState().curMeasure(), ctx);
396 :
397 36768 : MeasureBase* mb = ctx.mutState().curMeasure();
398 36768 : if (mb && mb->isMeasure()) {
399 30511 : toMeasure(mb)->mutldata()->setNeedLayout(true);
400 : }
401 36768 : }
402 :
403 36768 : void MeasureLayout::updateTicksMeasNumbersAndMMRests(MeasureBase* currentMB, LayoutContext& ctx)
404 : {
405 36768 : IF_ASSERT_FAILED(currentMB == ctx.state().curMeasure()) {
406 0 : return;
407 : }
408 :
409 36768 : if (!currentMB) {
410 3822 : return;
411 : }
412 :
413 32946 : if (!currentMB->isMeasure()) {
414 2435 : assert(currentMB->tick() == ctx.state().tick());
415 :
416 2435 : const LayoutBreak* layoutBreak = currentMB->sectionBreakElement();
417 2435 : if (layoutBreak && layoutBreak->startWithMeasureOne()) {
418 18 : ctx.mutState().setMeasureNumber(0);
419 : }
420 :
421 2435 : return;
422 : }
423 :
424 30511 : Measure* measure = toMeasure(currentMB);
425 :
426 30511 : int measureNumber = adjustMeasureNumber(measure, ctx.state().measureNumber());
427 :
428 30511 : ctx.mutState().setMeasureNumber(measureNumber);
429 :
430 30511 : MMRestLayout::createMultiMeasureRestsIfNeed(measure, ctx);
431 :
432 30511 : currentMB = ctx.mutState().curMeasure();
433 30511 : measure = toMeasure(currentMB);
434 :
435 30511 : measure->moveTicks(ctx.state().tick() - measure->tick());
436 :
437 30511 : ctx.mutState().setTick(ctx.state().tick() + measure->ticks());
438 : }
439 :
440 : //---------------------------------------------------------
441 : // adjustMeasureNumber
442 : //---------------------------------------------------------
443 :
444 30964 : int MeasureLayout::adjustMeasureNumber(Measure* m, int measureNumber)
445 : {
446 30964 : measureNumber += m->measureNumberOffset();
447 30964 : m->setMeasureNumber(measureNumber);
448 30964 : if (!m->excludeFromNumbering()) {
449 30930 : ++measureNumber;
450 : }
451 :
452 30964 : const LayoutBreak* layoutBreak = m->sectionBreakElement();
453 30964 : if (layoutBreak && layoutBreak->startWithMeasureOne()) {
454 51 : measureNumber = 0;
455 : }
456 :
457 30964 : return measureNumber;
458 : }
459 :
460 : /****************************************************************
461 : * computePreSpacingItems
462 : * Computes information that is needed before horizontal spacing.
463 : * Caution: assumes that the system is known! (which is why we
464 : * cannot compute this stuff in LayoutMeasure::getNextMeasure().)
465 : * **************************************************************/
466 32006 : void MeasureLayout::computePreSpacingItems(Measure* m, LayoutContext& ctx)
467 : {
468 : // Compute chord properties
469 32006 : bool isFirstChordInMeasure = true;
470 32006 : ChordLayout::clearLineAttachPoints(m);
471 132873 : for (Segment& seg : m->segments()) {
472 100867 : if (!seg.isChordRestType()) {
473 33973 : continue;
474 : }
475 445370 : for (EngravingItem* e : seg.elist()) {
476 378476 : if (!e || !e->isChord()) {
477 326659 : continue;
478 : }
479 51817 : Chord* chord = toChord(e);
480 51817 : Staff* staff = chord->staff();
481 51817 : if (staff && !staff->show()) {
482 136 : continue;
483 : }
484 :
485 51681 : ChordLayout::updateLineAttachPoints(chord, isFirstChordInMeasure, ctx);
486 52590 : for (Chord* gn : chord->graceNotes()) {
487 909 : ChordLayout::updateLineAttachPoints(gn, false, ctx);
488 : }
489 51681 : if (chord->arpeggio()) {
490 252 : ArpeggioLayout::clearAccidentals(chord->arpeggio(), ctx);
491 : }
492 :
493 51681 : ChordLayout::layoutArticulations(chord, ctx);
494 51681 : ChordLayout::checkStartEndSlurs(chord, ctx);
495 51681 : ChordLayout::layoutArticulations2(chord, ctx);
496 51681 : chord->computeKerningExceptions();
497 : }
498 :
499 74197 : for (EngravingItem* annotation : seg.annotations()) {
500 7303 : if (annotation->isFermata()) {
501 275 : TLayout::layoutItem(annotation, ctx);
502 : }
503 : }
504 :
505 66894 : ChordBracketLayout::layoutSegment(&seg, ctx);
506 66894 : seg.createShapes();
507 66894 : isFirstChordInMeasure = false;
508 : }
509 32006 : }
510 :
511 30273 : void MeasureLayout::layoutStaffLines(Measure* m, LayoutContext& ctx)
512 : {
513 30273 : int staffIdx = 0;
514 74463 : for (const MStaff* ms : m->mstaves()) {
515 44190 : if (m->isCutawayClef(staffIdx) && (ctx.dom().staff(staffIdx)->cutaway() || !m->visible(staffIdx))) {
516 : // draw short staff lines for a courtesy clef on a hidden measure
517 0 : Segment* clefSeg = m->findSegmentR(SegmentType::Clef, m->ticks());
518 0 : double staffMag = ctx.dom().staff(staffIdx)->staffMag(m->tick());
519 : double partialWidth = clefSeg
520 0 : ? m->width() - clefSeg->x() + clefSeg->minLeft() + ctx.conf().styleAbsolute(Sid::clefLeftMargin)
521 0 : * staffMag
522 0 : : 0.0;
523 0 : layoutPartialWidth(ms->lines(), ctx, m->width(), partialWidth / (m->spatium() * staffMag), true);
524 : } else {
525 : // normal staff lines
526 44190 : TLayout::layoutStaffLines(ms->lines(), ctx);
527 : }
528 44190 : staffIdx += 1;
529 : }
530 30273 : }
531 :
532 31790 : void MeasureLayout::layoutPlayCountText(Measure* m, LayoutContext& ctx)
533 : {
534 31790 : if (!m->repeatEnd()) {
535 31399 : return;
536 : }
537 :
538 391 : Score* score = m->score();
539 391 : const std::vector<MStaff*>& measureStaves = m->mstaves();
540 :
541 903 : for (staff_idx_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
542 512 : if (staffIdx >= measureStaves.size()) {
543 0 : break;
544 : }
545 512 : track_idx_t track = staff2track(staffIdx);
546 :
547 512 : Segment* endBarSeg = m->last(SegmentType::BarLineTypes);
548 : PlayCountText* playCount
549 512 : = endBarSeg ? toPlayCountText(endBarSeg->findAnnotation(ElementType::PLAY_COUNT_TEXT, track, track)) : nullptr;
550 512 : if (!playCount) {
551 506 : continue;
552 : }
553 :
554 6 : String text;
555 6 : const int repeatCount = m->repeatCount();
556 12 : String defaultText = TConv::translatedUserName(ctx.conf().styleV(Sid::repeatPlayCountPreset).value<RepeatPlayCountPreset>()).arg(
557 6 : repeatCount);
558 :
559 6 : switch (playCount->playCountTextSetting()) {
560 6 : case AutoCustomHide::AUTO:
561 6 : text = defaultText;
562 6 : break;
563 0 : case AutoCustomHide::CUSTOM:
564 0 : text = playCount->playCountCustomText();
565 0 : if (text.empty()) {
566 0 : text = defaultText;
567 : }
568 0 : break;
569 0 : case AutoCustomHide::HIDE:
570 0 : playCount->mutldata()->setIsSkipDraw(true);
571 0 : break;
572 : }
573 :
574 6 : if (!playCount->cursor()->editing()) {
575 6 : playCount->setXmlText(text);
576 : }
577 6 : }
578 : }
579 :
580 31790 : void MeasureLayout::layoutMeasureNumber(Measure* m, LayoutContext& ctx)
581 : {
582 31790 : MeasureNumberPlacement placementMode = ctx.conf().styleV(Sid::measureNumberPlacementMode).value<MeasureNumberPlacement>();
583 :
584 31790 : String stringNum = String::number(m->measureNumber() + 1);
585 :
586 31790 : Score* score = m->score();
587 :
588 31790 : const std::vector<MStaff*>& measureStaves = m->mstaves();
589 :
590 78630 : for (staff_idx_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
591 46840 : if (staffIdx >= measureStaves.size()) {
592 0 : break;
593 : }
594 :
595 46840 : if (m->showMeasureNumberOnStaff(staffIdx)) {
596 3851 : MeasureNumber* measureNumber = measureStaves[staffIdx]->measureNumber();
597 3851 : if (!measureNumber) {
598 2335 : measureNumber = new MeasureNumber(m);
599 2335 : measureNumber->setTrack(staff2track(staffIdx));
600 2335 : measureNumber->setGenerated(true);
601 2335 : m->add(measureNumber);
602 : }
603 :
604 3851 : measureNumber->setXmlText(stringNum);
605 3851 : measureNumber->setSystemFlag(placementMode != MeasureNumberPlacement::ON_ALL_STAVES);
606 3851 : TLayout::layoutMeasureNumber(measureNumber, measureNumber->mutldata(), ctx);
607 : }
608 : }
609 31790 : }
610 :
611 28569 : MeasureLayout::MeasureStartEndPos MeasureLayout::getMeasureStartEndPos(const Measure* measure, const Segment* firstCrSeg,
612 : const staff_idx_t staffIdx, const bool needsHeaderException,
613 : const bool modernMMRest,
614 : const LayoutContext& ctx)
615 : {
616 28569 : if (!measure || !firstCrSeg) {
617 0 : return MeasureStartEndPos(0.0, 0.0);
618 : }
619 :
620 : Segment* s1;
621 31447 : for (s1 = firstCrSeg->prevActive(); s1 && s1->allElementsInvisible(); s1 = s1->prevActive()) {
622 : }
623 : Segment* s2;
624 :
625 31890 : for (s2 = firstCrSeg->nextActive(); s2; s2 = s2->nextActive()) {
626 31857 : if (modernMMRest && !s2->isChordRestType() && !s2->isBreathType() && s2->element(staffIdx * VOICES)) {
627 148 : break;
628 : }
629 :
630 63418 : if (!modernMMRest
631 31704 : && (s2->isClefRepeatAnnounceType() || (s2->isTimeSigRepeatAnnounceType() && !s2->hasTimeSigAboveStaves())
632 63413 : || s2->isKeySigRepeatAnnounceType() || s2->isEndBarLineType()) && s2->element(staffIdx * VOICES)) {
633 28388 : break;
634 : }
635 : }
636 :
637 28569 : double x1 = 0.0;
638 40436 : while (s1) {
639 11879 : if (!s1->hasTimeSigAboveStaves() && !s1->allElementsInvisible()) {
640 10509 : x1 = std::max(x1, s1->x() + s1->minRight());
641 10509 : if (s1->isCourtesySegment()) {
642 12 : break;
643 : }
644 : }
645 11867 : s1 = s1->prevActive();
646 : }
647 :
648 28569 : double x2 = s2 ? s2->x() - s2->minLeft() : measure->width();
649 :
650 33650 : bool headerException = measure->header() && firstCrSeg->prev() && !firstCrSeg->prev()->isStartRepeatBarLineType()
651 33650 : && needsHeaderException;
652 28569 : if (headerException) { //needs this exception on header bar
653 : // Set x1 to the imaginary barline located the minimum barline->note distance to the left of the rest's segment
654 86 : x1 = firstCrSeg->x() - ctx.conf().styleAbsolute(Sid::barNoteDistance);
655 : }
656 :
657 28569 : return MeasureStartEndPos(x1, x2);
658 : }
659 :
660 : //-----------------------------------------------------------------------------
661 : // layoutMeasureElements()
662 : // lays out all the element of a measure
663 : // LEGACY: this method used to be called stretchMeasure() and was used to
664 : // distribute the remaining space at the end of a system. That task is now
665 : // performed elsewhere and only the layout tasks are kept.
666 : //-----------------------------------------------------------------------------
667 :
668 30415 : void MeasureLayout::layoutMeasureElements(Measure* m, LayoutContext& ctx)
669 : {
670 : //---------------------------------------------------
671 : // layout individual elements
672 : //---------------------------------------------------
673 :
674 147477 : for (Segment& s : m->segments()) {
675 117062 : if (!s.enabled()) {
676 980 : continue;
677 : }
678 :
679 : // After the rest of the spacing is calculated we position grace-notes-after.
680 116082 : ChordLayout::repositionGraceNotesAfter(&s, ctx.dom().ntracks());
681 :
682 791750 : for (EngravingItem* e : s.elist()) {
683 675668 : if (!e) {
684 508136 : continue;
685 : }
686 167532 : staff_idx_t staffIdx = e->staffIdx();
687 167532 : bool modernMMRest = e->isMMRest() && !toMMRest(e)->isOldStyle();
688 167532 : if ((e->isRest() && toRest(e)->isFullMeasureRest()) || e->isMMRest() || e->isMeasureRepeat()) {
689 : //
690 : // element has to be centered in free space
691 : // x1 - left measure position of free space
692 : // x2 - right measure position of free space
693 :
694 28569 : const MeasureStartEndPos measureStartEnd = getMeasureStartEndPos(m, &s, staffIdx, e->isMMRest(), modernMMRest, ctx);
695 :
696 28569 : const double x1 = measureStartEnd.x1;
697 28569 : const double x2 = measureStartEnd.x2;
698 :
699 28569 : if (e->isMMRest()) {
700 181 : MMRest* mmrest = toMMRest(e);
701 : // center multimeasure rest
702 181 : double d = ctx.conf().styleAbsolute(Sid::multiMeasureRestMargin);
703 181 : double w = x2 - x1 - 2 * d;
704 181 : MMRest::LayoutData* mmrestLD = mmrest->mutldata();
705 181 : mmrestLD->restWidth = w;
706 181 : TLayout::layoutMMRest(mmrest, mmrest->mutldata(), ctx);
707 181 : mmrestLD->setPosX(x1 - s.x() + d);
708 28388 : } else if (e->isMeasureRepeat() && !(toMeasureRepeat(e)->numMeasures() % 2)) {
709 : // two- or four-measure repeat, center on following barline
710 89 : double measureWidth = x2 - s.x() + .5 * (m->styleP(Sid::barWidth));
711 89 : e->mutldata()->setPosX(measureWidth - .5 * e->width());
712 89 : if (toMeasureRepeat(e)->numMeasures() == 4 && ctx.conf().styleB(Sid::fourMeasureRepeatShowExtenders)) {
713 0 : TLayout::layoutMeasureRepeatExtender(toMeasureRepeat(e), toMeasureRepeat(e)->mutldata(), ctx);
714 : }
715 : } else {
716 : // full measure rest or one-measure repeat, center within this measure
717 28299 : TLayout::layoutItem(e, ctx);
718 28299 : Shape sh = e->ldata()->shape();
719 28299 : auto shEL = sh.find_first(ElementType::REST);
720 : //! HACK Previously, bbox of rest was used here
721 : //! Now we are using a shape, and in the shape we need to find the part related to rest
722 : //! But in some cases, the information about what the ShapeElement belongs to will disappear at the moment (item is null),
723 : //! in this case, let's just take the first element, it currently corresponds to the rest
724 28299 : if (!shEL) {
725 857 : shEL = sh.get_first();
726 : }
727 28299 : if (shEL) {
728 27580 : e->mutldata()->setPosX((x2 - x1 - shEL->width()) * .5 + x1 - s.x() - shEL->x());
729 : }
730 28299 : }
731 28569 : s.createShape(staffIdx); // DEBUG
732 138963 : } else if (e->isRest()) {
733 11159 : e->mutldata()->setPosX(0);
734 127804 : } else if (e->isChord()) {
735 48273 : Chord* c = toChord(e);
736 48273 : if (c->tremoloSingleChord()) {
737 268 : TremoloLayout::layout(c->tremoloSingleChord(), ctx);
738 : }
739 :
740 48273 : if (c->tremoloTwoChord()) {
741 220 : TremoloTwoChord* tr = c->tremoloTwoChord();
742 220 : Chord* c1 = tr->chord1();
743 220 : Chord* c2 = tr->chord2();
744 220 : if (c1 && !c1->staffMove() && c2 && !c2->staffMove()) {
745 220 : TremoloLayout::layout(tr, ctx);
746 : }
747 : }
748 :
749 49179 : for (Chord* g : c->graceNotes()) {
750 906 : if (g->tremoloSingleChord()) {
751 2 : TremoloLayout::layout(g->tremoloSingleChord(), ctx);
752 : }
753 :
754 906 : if (g->tremoloTwoChord()) {
755 0 : TremoloTwoChord* tr = g->tremoloTwoChord();
756 0 : Chord* gc1 = tr->chord1();
757 0 : Chord* gc2 = tr->chord2();
758 0 : if (gc1 && !gc1->staffMove() && gc2 && !gc2->staffMove()) {
759 0 : TremoloLayout::layout(tr, ctx);
760 : }
761 : }
762 : }
763 79531 : } else if (e->isBarLine()) {
764 50442 : e->mutldata()->setPosY(0.0);
765 : // for end barlines, x position was set in createEndBarLines
766 50442 : if (s.segmentType() != SegmentType::EndBarLine) {
767 6174 : e->mutldata()->setPosX(0.0);
768 : }
769 : }
770 : }
771 : }
772 30415 : }
773 :
774 225 : void MeasureLayout::barLinesSetSpan(Segment* seg, LayoutContext& ctx)
775 : {
776 225 : int track = 0;
777 567 : for (Staff* staff : ctx.dom().staves()) {
778 342 : BarLine* bl = toBarLine(seg->element(track)); // get existing bar line for this staff, if any
779 342 : if (bl) {
780 133 : if (bl->generated()) {
781 122 : bl->setSpanStaff(staff->barLineSpan());
782 122 : bl->setSpanFrom(staff->barLineFrom());
783 122 : bl->setSpanTo(staff->barLineTo());
784 : }
785 : } else {
786 209 : bl = Factory::createBarLine(seg);
787 209 : bl->setTrack(track);
788 209 : bl->setGenerated(true);
789 209 : bl->setSpanStaff(staff->barLineSpan());
790 209 : bl->setSpanFrom(staff->barLineFrom());
791 209 : bl->setSpanTo(staff->barLineTo());
792 209 : TLayout::layoutBarLine(bl, bl->mutldata(), ctx);
793 209 : ctx.mutDom().addElement(bl);
794 : }
795 342 : track += VOICES;
796 : }
797 225 : }
798 :
799 : //---------------------------------------------------------
800 : // createEndBarLines
801 : // actually creates or modifies barlines
802 : // return the width change for measure
803 : //---------------------------------------------------------
804 :
805 62409 : void MeasureLayout::createEndBarLines(Measure* m, bool isLastMeasureInSystem, LayoutContext& ctx)
806 : {
807 62409 : const size_t nstaves = ctx.dom().nstaves();
808 62409 : Segment* barlineSeg = m->findSegmentR(SegmentType::EndBarLine, m->ticks());
809 62409 : const Measure* nextMeasure = m->nextMeasure();
810 62409 : double barlineWidth = 0.0;
811 62409 : bool sectionBreakHideCourtesy = false;
812 62409 : if (LayoutBreak* sectionBreakElement = m->sectionBreakElement()) {
813 110 : sectionBreakHideCourtesy = !sectionBreakElement->showCourtesy();
814 : }
815 :
816 62409 : m->setHasCourtesyKeySig(false);
817 : // Set flag "hasCourtesyKeySig" if this measure needs a courtesy key sig.
818 : // This flag is later used to set a double end bar line and to actually
819 : // create the courtesy key sig.
820 :
821 62409 : bool hasKeySig = false;
822 62409 : bool hasTimeSig = false;
823 62409 : bool hasCourtesyTimeSig = false;
824 62409 : if (nextMeasure && !sectionBreakHideCourtesy) {
825 : // Don't change barlines at the end of a section break,
826 : // and don't create courtesy key/time signatures.
827 31327 : const bool showCourtesyKeySig = (isLastMeasureInSystem && ctx.conf().styleB(Sid::genCourtesyKeysig))
828 85858 : || (m->repeatJump() && ctx.conf().styleB(Sid::showCourtesiesOtherJumps));
829 :
830 54531 : Fraction tick = m->endTick();
831 132190 : for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
832 78376 : const Staff* staff = ctx.dom().staff(staffIdx);
833 78376 : const KeySigEvent key1 = staff->keySigEvent(tick - Fraction::eps());
834 78376 : const KeySigEvent key2 = staff->keySigEvent(tick);
835 78376 : if (key1 == key2) {
836 77659 : continue;
837 : }
838 : // locate a key sig. in next measure and, if found,
839 : // check if it has court. sig turned off
840 717 : Segment* keySigSeg = nextMeasure->findSegment(SegmentType::KeySig, tick);
841 717 : if (keySigSeg) {
842 717 : hasKeySig = true;
843 717 : KeySig* keySig = toKeySig(keySigSeg->element(staffIdx * VOICES));
844 717 : if (keySig && !keySig->showCourtesy()) {
845 0 : continue;
846 : }
847 : }
848 717 : if (showCourtesyKeySig) {
849 456 : m->setHasCourtesyKeySig(true);
850 : }
851 717 : break;
852 156752 : }
853 :
854 31327 : bool showCourtesyTimeSig = (isLastMeasureInSystem && ctx.conf().styleB(Sid::genCourtesyTimesig))
855 85858 : || (m->repeatJump() && ctx.conf().styleB(Sid::showCourtesiesOtherJumps));
856 :
857 54531 : Segment* timeSigSeg = nextMeasure->findSegmentR(SegmentType::TimeSig, Fraction(0, 1));
858 54531 : if (timeSigSeg) {
859 657 : for (track_idx_t track = 0; track < nstaves * VOICES; track += VOICES) {
860 602 : TimeSig* timeSig = toTimeSig(timeSigSeg->element(track));
861 602 : if (!timeSig) {
862 83 : continue;
863 : }
864 519 : hasTimeSig = true;
865 519 : if (timeSig->showCourtesySig() && showCourtesyTimeSig) {
866 339 : hasCourtesyTimeSig = true;
867 : }
868 519 : break;
869 : }
870 : }
871 : }
872 :
873 54639 : bool nextMeasRepeat = nextMeasure && nextMeasure->repeatStart() && !m->repeatEnd() && !isLastMeasureInSystem
874 117048 : && m->next() == nextMeasure;
875 :
876 62409 : bool barlineBeforeRepeatSigs = ctx.conf().styleB(Sid::barlineBeforeSigChange) && (hasTimeSig || hasKeySig);
877 :
878 62409 : if (nextMeasRepeat && !barlineBeforeRepeatSigs) {
879 : // we may skip barline at end of a measure immediately before a start repeat:
880 : // next measure is repeat start, this measure is not a repeat end,
881 : // this is not last measure of system, no intervening frame
882 97 : if (!barlineSeg) {
883 0 : return;
884 : }
885 97 : barlineSeg->setEnabled(false);
886 : } else {
887 62312 : BarLineType blType = nextMeasure ? BarLineType::NORMAL : BarLineType::END;
888 62312 : if (!barlineSeg) {
889 14565 : barlineSeg = m->getSegmentR(SegmentType::EndBarLine, m->ticks());
890 : }
891 62312 : barlineSeg->setEnabled(true);
892 :
893 62312 : const bool isRepeatSigBarline = ctx.conf().styleB(Sid::barlineBeforeSigChange) && nextMeasRepeat;
894 :
895 62312 : const int keySigBarlineMode = ctx.conf().styleI(Sid::keySigCourtesyBarlineMode);
896 62312 : const bool beforeKSCourtesy = keySigBarlineMode == int(CourtesyBarlineMode::DOUBLE_BEFORE_COURTESY) && m->hasCourtesyKeySig();
897 62312 : const bool alwaysDoubleKS = keySigBarlineMode == int(CourtesyBarlineMode::ALWAYS_DOUBLE) && hasKeySig;
898 62312 : const bool beforeRepeatKS = isRepeatSigBarline && hasKeySig && ctx.conf().styleB(Sid::doubleBarlineBeforeKeySig);
899 62312 : if (beforeKSCourtesy || alwaysDoubleKS || beforeRepeatKS) {
900 456 : blType = BarLineType::DOUBLE;
901 : }
902 :
903 62312 : const int timeSigBarlineMode = ctx.conf().styleI(Sid::timeSigCourtesyBarlineMode);
904 62312 : const bool beforeTSCourtesy = timeSigBarlineMode == int(CourtesyBarlineMode::DOUBLE_BEFORE_COURTESY) && hasCourtesyTimeSig;
905 62312 : const bool alwaysDoubleTS = timeSigBarlineMode == int(CourtesyBarlineMode::ALWAYS_DOUBLE) && hasTimeSig;
906 62312 : const bool beforeRepeatTS = isRepeatSigBarline && hasTimeSig && ctx.conf().styleB(Sid::doubleBarlineBeforeTimeSig);
907 :
908 62312 : if (beforeTSCourtesy || alwaysDoubleTS || beforeRepeatTS) {
909 0 : blType = BarLineType::DOUBLE;
910 : }
911 :
912 62312 : bool force = false;
913 62312 : if (m->repeatEnd()) {
914 781 : blType = BarLineType::END_REPEAT;
915 781 : force = true;
916 : }
917 :
918 153317 : for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
919 91005 : track_idx_t track = staffIdx * VOICES;
920 91005 : BarLine* barLine = toBarLine(barlineSeg->element(track));
921 91005 : const Staff* staff = ctx.dom().staff(staffIdx);
922 91005 : if (!barLine) {
923 21673 : barLine = Factory::createBarLine(barlineSeg);
924 21673 : barLine->setTrack(track);
925 21673 : barLine->setGenerated(true);
926 21673 : barLine->setSpanStaff(staff->barLineSpan());
927 21673 : barLine->setSpanFrom(staff->barLineFrom());
928 21673 : barLine->setSpanTo(staff->barLineTo());
929 21673 : barLine->setBarLineType(blType);
930 21673 : ctx.mutDom().addElement(barLine);
931 : } else {
932 : // do not change bar line type if bar line is user modified
933 : // and its not a repeat start/end barline (forced)
934 :
935 69332 : if (barLine->generated()) {
936 61276 : barLine->setSpanStaff(staff->barLineSpan());
937 61276 : barLine->setSpanFrom(staff->barLineFrom());
938 61276 : barLine->setSpanTo(staff->barLineTo());
939 61276 : barLine->setBarLineType(blType);
940 8056 : } else if (barLine->barLineType() != blType && force) {
941 43 : barLine->setBarLineType(blType);
942 43 : barLine->setGenerated(true);
943 : }
944 : }
945 :
946 91005 : TLayout::layoutBarLine(barLine, barLine->mutldata(), ctx);
947 91005 : barlineWidth = std::max(barlineWidth, barLine->width());
948 : }
949 : // right align within segment
950 153317 : for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
951 91005 : track_idx_t track = staffIdx * VOICES;
952 91005 : BarLine* barLine = toBarLine(barlineSeg->element(track));
953 91005 : if (!barLine) {
954 0 : continue;
955 : }
956 91005 : barLine->mutldata()->moveX(barlineWidth - barLine->width());
957 : }
958 62312 : barlineSeg->createShapes();
959 : }
960 :
961 62409 : setClefSegVisibility(m, isLastMeasureInSystem, ctx);
962 : }
963 :
964 62409 : void MeasureLayout::setClefSegVisibility(Measure* m, bool isLastMeasureInSystem, LayoutContext& ctx)
965 : {
966 62409 : const size_t nstaves = ctx.dom().nstaves();
967 62409 : bool sectionBreakHideCourtesy = false;
968 62409 : if (LayoutBreak* sectionBreakElement = m->sectionBreakElement()) {
969 110 : sectionBreakHideCourtesy = !sectionBreakElement->showCourtesy();
970 : }
971 62409 : const Measure* nextMeasure = m->nextMeasure();
972 :
973 62409 : Segment* clefSeg = m->findSegmentR(SegmentType::Clef, m->ticks());
974 62409 : if (!clefSeg && nextMeasure) {
975 54168 : clefSeg = nextMeasure->findSegmentR(SegmentType::Clef, Fraction(0, 1));
976 : }
977 :
978 62409 : if (!clefSeg) {
979 61928 : return;
980 : }
981 :
982 481 : bool visibleClef = false;
983 481 : bool clefFound = false;
984 1156 : for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
985 675 : if (!ctx.dom().staff(staffIdx)->show()) {
986 8 : continue;
987 : }
988 :
989 667 : const track_idx_t track = staffIdx * VOICES;
990 667 : Clef* clef = toClef(clefSeg->element(track));
991 667 : if (!clef) {
992 162 : continue;
993 : }
994 :
995 505 : clefFound = true;
996 :
997 505 : const bool showCourtesy = ctx.conf().styleB(Sid::genCourtesyClef) && clef->showCourtesy(); // normally show a courtesy clef
998 : // check if the measure is the last measure of the system or the last measure before a frame
999 505 : const bool lastMeasure = isLastMeasureInSystem || (nextMeasure ? !(m->next() == nextMeasure) : true);
1000 505 : if (!nextMeasure || sectionBreakHideCourtesy || (lastMeasure && !showCourtesy)) {
1001 : // hide the courtesy clef in the final measure of a section, or if the measure is the final measure of a system
1002 : // and the score style or the clef style is set to "not show courtesy clef",
1003 : // or if the clef is at the end of the very last measure of the score
1004 57 : clef->clear();
1005 57 : clefSeg->createShape(staffIdx);
1006 : } else {
1007 448 : TLayout::layoutClef(clef, clef->mutldata(), ctx.conf());
1008 448 : clefSeg->createShape(staffIdx);
1009 448 : visibleClef = true;
1010 : }
1011 : }
1012 :
1013 481 : if (visibleClef) { // there is at least one visible clef in the clef segment
1014 442 : clefSeg->setVisible(true);
1015 39 : } else if (!visibleClef && clefFound) { // all (courtesy) clefs in the clef segment are not visible
1016 39 : clefSeg->setVisible(false);
1017 : } else { // should never happen
1018 0 : LOGD("Clef Segment without Clef elements at tick %d/%d", clefSeg->tick().numerator(), clefSeg->tick().denominator());
1019 0 : clefSeg->setVisible(false);
1020 0 : return;
1021 : }
1022 : }
1023 :
1024 32077 : void MeasureLayout::setCourtesyTimeSig(Measure* m, const Fraction& refSigTick, const Fraction& courtesySigTick,
1025 : const SegmentType courtesySegType, LayoutContext& ctx)
1026 : {
1027 : // Find original element
1028 32077 : const size_t nstaves = ctx.dom().nstaves();
1029 32077 : const Fraction courtesySigRTick = courtesySigTick - m->tick();
1030 32077 : const Measure* prevMeasure = m->prevMeasureMM();
1031 :
1032 32077 : const bool isTrailer = courtesySegType == SegmentType::TimeSigAnnounce;
1033 32077 : const bool isContinuationCourtesy = courtesySegType == SegmentType::TimeSigStartRepeatAnnounce;
1034 :
1035 : const Segment* prevCourtesySegment
1036 32077 : = prevMeasure ? prevMeasure->findSegmentR(SegmentType::TimeSigRepeatAnnounce, prevMeasure->ticks()) : nullptr;
1037 :
1038 : // Cont. courtesies - check for sig at the start of the measure OR end of previous measure if changesBeforeBarline... is on
1039 585 : const bool checkPrevMeasure = isContinuationCourtesy && prevMeasure
1040 32940 : && ((prevMeasure->repeatEnd() && ctx.conf().styleB(Sid::changesBeforeBarlineRepeats))
1041 278 : || (prevMeasure->repeatJump()
1042 278 : && ctx.conf().styleB(Sid::changesBeforeBarlineOtherJumps)));
1043 32077 : const Segment* tsSegAtCourtesyTick = m->findSegmentR(SegmentType::TimeSig, courtesySigRTick);
1044 32659 : tsSegAtCourtesyTick = !tsSegAtCourtesyTick && checkPrevMeasure ? prevMeasure->findSegmentR(SegmentType::TimeSig,
1045 : courtesySigTick
1046 582 : - prevMeasure->tick()) : tsSegAtCourtesyTick;
1047 32077 : const bool shouldShowContCourtesy = prevMeasure && prevMeasure->hasCourtesyTimeSig();
1048 :
1049 32077 : Segment* courtesySigSeg = m->findSegmentR(courtesySegType, courtesySigRTick);
1050 78348 : for (track_idx_t track = 0; track < nstaves * VOICES; track += VOICES) {
1051 46271 : const Staff* staff = ctx.dom().staff(track2staff(track));
1052 46271 : const TimeSig* actualTimeSig = staff->timeSig(refSigTick);
1053 46271 : const TimeSig* curTimeSig = staff->timeSig(courtesySigTick - Fraction::eps());
1054 46271 : if (!actualTimeSig || !curTimeSig) {
1055 771 : continue;
1056 : }
1057 :
1058 : // Show repeat courtesy if the sigs are different
1059 : // Show continuation courtesy if there's a repeat courtesy before it
1060 : // Show trailer courtesy only when there's a time sig element in the next bar
1061 45500 : const bool sigsDifferent = actualTimeSig->sig() != curTimeSig->sig();
1062 90166 : const bool needsCourtesy = isContinuationCourtesy ? shouldShowContCourtesy && prevCourtesySegment && prevCourtesySegment->element(
1063 44666 : track) : isTrailer ? actualTimeSig->tick() == m->endTick() : sigsDifferent;
1064 : // If there is a real key sig at this tick (in this bar or the previous), don't create a courtesy
1065 45500 : const bool hasSigAtTick = tsSegAtCourtesyTick && tsSegAtCourtesyTick->enabled() && tsSegAtCourtesyTick->element(track);
1066 : // Only show courtesy if its real signature has courtesies enabled
1067 45500 : const bool actualShowCourtesy = actualTimeSig && actualTimeSig->showCourtesySig();
1068 45500 : const bool show = actualShowCourtesy && needsCourtesy && !hasSigAtTick && ctx.conf().styleB(Sid::genCourtesyTimesig);
1069 :
1070 45500 : if (!courtesySigSeg) {
1071 45159 : if (!show) {
1072 44985 : continue;
1073 : }
1074 :
1075 : // Create a segment if one doesn't already exist
1076 174 : courtesySigSeg = Factory::createSegment(m, courtesySegType, courtesySigRTick);
1077 174 : m->add(courtesySigSeg);
1078 174 : m->setTrailer(m->trailer() || isTrailer);
1079 : }
1080 515 : if (!isContinuationCourtesy) {
1081 500 : m->setHasCourtesyTimeSig(true);
1082 : }
1083 515 : courtesySigSeg->setTrailer(isTrailer);
1084 515 : courtesySigSeg->setEnabled(true);
1085 :
1086 : // Find courtesy element or create if it doesn't exist
1087 515 : TimeSig* courtesyTimeSig = nullptr;
1088 515 : EngravingItem* timeSigElem = courtesySigSeg->element(track);
1089 515 : if (timeSigElem && timeSigElem->isTimeSig()) {
1090 250 : courtesyTimeSig = toTimeSig(timeSigElem);
1091 : }
1092 :
1093 : // this time sig shouldn't be shown, remove from segment
1094 515 : if (!show) {
1095 28 : if (courtesyTimeSig) {
1096 4 : courtesySigSeg->remove(courtesyTimeSig);
1097 : }
1098 28 : continue;
1099 : }
1100 :
1101 487 : if (!courtesyTimeSig) {
1102 241 : courtesyTimeSig = Factory::createTimeSig(courtesySigSeg);
1103 241 : courtesyTimeSig->setTrack(track);
1104 241 : courtesyTimeSig->setGenerated(true);
1105 241 : courtesyTimeSig->setIsCourtesy(true);
1106 241 : courtesySigSeg->add(courtesyTimeSig);
1107 : }
1108 :
1109 : // Layout & create shapes
1110 487 : courtesyTimeSig->setFrom(actualTimeSig);
1111 487 : if (courtesyTimeSig->isStyled(Pid::SCALE)) {
1112 : // If this courtesyTimeSig was previously disabled its scale style may have not been updated
1113 487 : courtesyTimeSig->setScale(courtesyTimeSig->propertyDefault(Pid::SCALE).value<ScaleF>());
1114 : }
1115 :
1116 487 : TLayout::layoutTimeSig(courtesyTimeSig, courtesyTimeSig->mutldata(), ctx);
1117 : }
1118 :
1119 32077 : if (courtesySigSeg && ((!isContinuationCourtesy && !m->hasCourtesyTimeSig()) || !ctx.conf().styleB(Sid::genCourtesyTimesig))) {
1120 : // Whole segment shouldn't be shown, remove any existing courtesy signatures
1121 3 : if (!isContinuationCourtesy) {
1122 3 : m->setHasCourtesyTimeSig(false);
1123 : }
1124 3 : if (courtesySigSeg) {
1125 3 : courtesySigSeg->setEnabled(false);
1126 : }
1127 : }
1128 :
1129 32077 : if (courtesySigSeg && courtesySigSeg->enabled()) {
1130 359 : if (courtesySigSeg->hasElements()) {
1131 353 : courtesySigSeg->createShapes();
1132 : } else {
1133 6 : courtesySigSeg->setEnabled(false);
1134 6 : if (!isContinuationCourtesy) {
1135 6 : m->setHasCourtesyTimeSig(false);
1136 : }
1137 : }
1138 : }
1139 32077 : }
1140 :
1141 32203 : void MeasureLayout::setCourtesyKeySig(Measure* m, const Fraction& refSigTick, const Fraction& courtesySigTick,
1142 : const SegmentType courtesySegType, LayoutContext& ctx)
1143 : {
1144 : // Find original element
1145 32203 : const size_t nstaves = ctx.dom().nstaves();
1146 32203 : const Fraction courtesySigRTick = courtesySigTick - m->tick();
1147 32203 : const Measure* prevMeasure = m->prevMeasureMM();
1148 :
1149 32203 : const bool isTrailer = courtesySegType == SegmentType::KeySigAnnounce;
1150 32203 : const bool isContinuationCourtesy = courtesySegType == SegmentType::KeySigStartRepeatAnnounce;
1151 :
1152 : const Segment* prevCourtesySegment
1153 32203 : = prevMeasure ? prevMeasure->findSegmentR(SegmentType::KeySigRepeatAnnounce, prevMeasure->ticks()) : nullptr;
1154 :
1155 : // Cont. courtesies - check for sig at the start of the measure OR end of previous measure if changesBeforeBarline... is on
1156 585 : const bool checkPrevMeasure = isContinuationCourtesy && prevMeasure
1157 33066 : && ((prevMeasure->repeatEnd() && ctx.conf().styleB(Sid::changesBeforeBarlineRepeats))
1158 278 : || (prevMeasure->repeatJump()
1159 278 : && ctx.conf().styleB(Sid::changesBeforeBarlineOtherJumps)));
1160 32203 : const Segment* ksSegAtCourtesyTick = m->findSegmentR(SegmentType::KeySig, courtesySigRTick);
1161 32647 : ksSegAtCourtesyTick = !ksSegAtCourtesyTick && checkPrevMeasure ? prevMeasure->findSegmentR(SegmentType::KeySig,
1162 : courtesySigTick
1163 444 : - prevMeasure->tick()) : ksSegAtCourtesyTick;
1164 :
1165 32203 : const bool shouldShowContCourtesy = prevMeasure && prevMeasure->hasCourtesyKeySig();
1166 :
1167 32203 : Segment* courtesySigSeg = m->findSegmentR(courtesySegType, courtesySigRTick);
1168 78668 : for (track_idx_t track = 0; track < nstaves * VOICES; track += VOICES) {
1169 : // Find reference signature
1170 46465 : const Staff* staff = ctx.dom().staff(track2staff(track));
1171 46465 : const Fraction refSigElementTick = staff->currentKeyTick(refSigTick);
1172 46465 : const Measure* refMeasure = ctx.dom().tick2measureMM(refSigElementTick);
1173 : const Segment* actualKeySigSeg
1174 46465 : = refMeasure ? refMeasure->findSegmentR(SegmentType::KeySig, refSigElementTick - refMeasure->tick()) : nullptr;
1175 46465 : const EngravingItem* el = actualKeySigSeg ? actualKeySigSeg->element(track) : nullptr;
1176 46465 : const KeySig* actualKeySig = el ? toKeySig(el) : nullptr;
1177 :
1178 46465 : const KeySigEvent refKey = staff->keySigEvent(refSigTick);
1179 : // Get info from correct tick for repeats
1180 : // For trailers and pre-repeat courtesies, signatures should be different
1181 46465 : const bool sigsDifferent = staff->key(m->endTick() - Fraction::eps()) != refKey.key();
1182 46465 : const bool needsCourtesy = isContinuationCourtesy ? shouldShowContCourtesy && prevCourtesySegment && prevCourtesySegment->element(
1183 45612 : track) : sigsDifferent;
1184 : // Only show key sig changes on pitched staves
1185 46465 : const bool staffIsPitchedAtNextMeas = ctx.dom().lastMeasureMM() == m
1186 46465 : || (m->nextMeasureMM() && staff->isPitchedStaff(m->nextMeasureMM()->tick()));
1187 : // If there is a real key sig at this tick (in this bar or the previous), don't create a courtesy
1188 46465 : const bool hasSigAtTick = ksSegAtCourtesyTick && ksSegAtCourtesyTick->enabled() && ksSegAtCourtesyTick->element(track);
1189 : // Only show courtesy if its real signature has courtesies enabled
1190 46465 : const bool actualShowCourtesy = actualKeySig ? actualKeySig->showCourtesy() : true;
1191 46465 : const bool show = actualShowCourtesy && staffIsPitchedAtNextMeas && needsCourtesy && !hasSigAtTick && ctx.conf().styleB(
1192 46465 : Sid::genCourtesyKeysig);
1193 :
1194 46465 : if (!courtesySigSeg) {
1195 46049 : if (!show) {
1196 45806 : continue;
1197 : }
1198 :
1199 : // Create a segment if one doesn't already exist
1200 243 : courtesySigSeg = Factory::createSegment(m, courtesySegType, courtesySigRTick);
1201 243 : m->add(courtesySigSeg);
1202 243 : m->setTrailer(m->trailer() || isTrailer);
1203 : }
1204 659 : if (!isContinuationCourtesy) {
1205 648 : m->setHasCourtesyKeySig(true);
1206 : }
1207 659 : courtesySigSeg->setTrailer(isTrailer);
1208 659 : courtesySigSeg->setEnabled(true);
1209 :
1210 : // Find courtesy element or create if it doesn't exist
1211 659 : KeySig* courtesyKeySig = nullptr;
1212 659 : EngravingItem* keySigElem = courtesySigSeg->element(track);
1213 659 : if (keySigElem && keySigElem->isKeySig()) {
1214 307 : courtesyKeySig = toKeySig(keySigElem);
1215 : }
1216 :
1217 : // this key sig shouldn't be shown, remove from segment
1218 659 : if (!show) {
1219 24 : if (courtesyKeySig) {
1220 2 : courtesySigSeg->remove(courtesyKeySig);
1221 : }
1222 24 : continue;
1223 : }
1224 :
1225 635 : if (!courtesyKeySig) {
1226 330 : courtesyKeySig = Factory::createKeySig(courtesySigSeg);
1227 330 : courtesyKeySig->setTrack(track);
1228 330 : courtesyKeySig->setGenerated(true);
1229 330 : courtesyKeySig->setIsCourtesy(true);
1230 330 : courtesySigSeg->add(courtesyKeySig);
1231 : }
1232 635 : courtesyKeySig->setKeySigEvent(refKey);
1233 :
1234 : // Layout & create shapes
1235 635 : TLayout::layoutKeySig(courtesyKeySig, courtesyKeySig->mutldata(), ctx.conf());
1236 46465 : }
1237 :
1238 32203 : if (courtesySigSeg && ((!isContinuationCourtesy && !m->hasCourtesyKeySig()) || !ctx.conf().styleB(Sid::genCourtesyKeysig))) {
1239 : // Whole segment shouldn't be shown, remove any existing courtesy signatures
1240 0 : if (!isContinuationCourtesy) {
1241 0 : m->setHasCourtesyKeySig(false);
1242 : }
1243 0 : if (courtesySigSeg) {
1244 0 : courtesySigSeg->setEnabled(false);
1245 : }
1246 : }
1247 :
1248 32203 : if (courtesySigSeg && courtesySigSeg->enabled()) {
1249 440 : if (courtesySigSeg->hasElements()) {
1250 438 : courtesySigSeg->createShapes();
1251 : } else {
1252 2 : courtesySigSeg->setEnabled(false);
1253 2 : if (!isContinuationCourtesy) {
1254 2 : m->setHasCourtesyKeySig(false);
1255 : }
1256 : }
1257 : }
1258 32203 : }
1259 :
1260 1286 : void MeasureLayout::setCourtesyClef(Measure* m, const Fraction& refClefTick, const Fraction& courtesyClefTick,
1261 : const SegmentType courtesySegType, LayoutContext& ctx)
1262 : {
1263 : // Find original element
1264 1286 : const size_t nstaves = ctx.dom().nstaves();
1265 1286 : const Fraction courtesyClefRTick = courtesyClefTick - m->tick();
1266 1286 : const Measure* prevMeasure = m->prevMeasureMM();
1267 :
1268 1286 : const bool isContinuationCourtesy = courtesySegType == SegmentType::ClefStartRepeatAnnounce;
1269 :
1270 : const Segment* prevCourtesySegment
1271 1286 : = prevMeasure ? prevMeasure->findSegmentR(SegmentType::ClefRepeatAnnounce, prevMeasure->ticks()) : nullptr;
1272 1286 : const Segment* clefSegAtCourtesyTick = m->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, courtesyClefRTick);
1273 : clefSegAtCourtesyTick
1274 1286 : = !clefSegAtCourtesyTick
1275 1286 : && prevMeasure ? prevMeasure->findSegmentR(SegmentType::KeySig, courtesyClefTick - prevMeasure->tick()) : clefSegAtCourtesyTick;
1276 :
1277 1286 : bool shouldShowContCourtesy = prevMeasure && prevMeasure->hasCourtesyClef();
1278 :
1279 1286 : Segment* courtesyClefSeg = m->findSegmentR(courtesySegType, courtesyClefRTick);
1280 3217 : for (track_idx_t track = 0; track < nstaves * VOICES; track += VOICES) {
1281 1931 : const Staff* staff = ctx.dom().staff(track2staff(track));
1282 1931 : const Fraction refClefElementTick = staff->currentClefTick(refClefTick);
1283 1931 : const Measure* refMeasure = ctx.dom().tick2measureMM(refClefElementTick);
1284 : const Segment* actualClefSeg
1285 3862 : = refMeasure ? refMeasure->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef,
1286 1931 : refClefElementTick - refMeasure->tick()) : nullptr;
1287 1931 : if (!actualClefSeg && refMeasure && refMeasure->prevMeasureMM()) {
1288 : // Check previous measure
1289 17 : Measure* refPrevMeasure = refMeasure->prevMeasureMM();
1290 : actualClefSeg
1291 17 : = refPrevMeasure->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, refClefElementTick - refPrevMeasure->tick());
1292 : }
1293 1931 : const EngravingItem* el = actualClefSeg ? actualClefSeg->element(track) : nullptr;
1294 1931 : const Clef* actualClef = el ? toClef(el) : nullptr;
1295 :
1296 1931 : const ClefType refClef = staff->clef(refClefTick);
1297 : // For trailers and pre-repeat courtesies, clefs should be different
1298 1931 : const bool clefsDifferent = staff->clef(m->endTick() - Fraction::eps()) != refClef;
1299 1931 : const bool needsCourtesy = isContinuationCourtesy ? shouldShowContCourtesy && prevCourtesySegment && prevCourtesySegment->element(
1300 1078 : track) : clefsDifferent;
1301 : // If there is a real clef at this tick (in this bar or the previous), don't create a courtesy
1302 1931 : const bool hasClefAtTick = clefSegAtCourtesyTick && clefSegAtCourtesyTick->enabled() && clefSegAtCourtesyTick->element(track);
1303 : // Only show courtesy if its real clef has courtesies enabled
1304 1931 : const bool actualShowCourtesy = actualClef && actualClef->showCourtesy();
1305 1931 : const bool show = actualShowCourtesy && needsCourtesy && !hasClefAtTick && ctx.conf().styleB(Sid::genCourtesyClef);
1306 :
1307 1931 : if (!courtesyClefSeg) {
1308 1904 : if (!show) {
1309 1904 : continue;
1310 : }
1311 :
1312 : // Create a segment if one doesn't already exist
1313 10 : courtesyClefSeg = Factory::createSegment(m, courtesySegType, courtesyClefRTick);
1314 10 : m->add(courtesyClefSeg);
1315 10 : courtesyClefSeg->setTrailer(false);
1316 : }
1317 37 : if (!isContinuationCourtesy) {
1318 19 : m->setHasCourtesyClef(true);
1319 : }
1320 37 : courtesyClefSeg->setEnabled(true);
1321 :
1322 : // Find courtesy element or create if it doesn't exist
1323 37 : Clef* courtesyClef = nullptr;
1324 37 : EngravingItem* clefElem = courtesyClefSeg->element(track);
1325 37 : if (clefElem && clefElem->isClef()) {
1326 17 : courtesyClef = toClef(clefElem);
1327 : }
1328 :
1329 : // this clef shouldn't be shown, remove from segment
1330 37 : if (!show) {
1331 10 : if (courtesyClef) {
1332 0 : courtesyClefSeg->remove(courtesyClef);
1333 : }
1334 10 : continue;
1335 : }
1336 :
1337 27 : if (!courtesyClef) {
1338 10 : courtesyClef = Factory::createClef(courtesyClefSeg);
1339 10 : courtesyClef->setTrack(track);
1340 10 : courtesyClef->setGenerated(true);
1341 10 : courtesyClef->setSmall(true);
1342 10 : courtesyClef->setClefType(actualClef->clefType());
1343 10 : courtesyClef->setIsCourtesy(true);
1344 10 : courtesyClefSeg->add(courtesyClef);
1345 : }
1346 :
1347 : // Layout & create shapes
1348 27 : TLayout::layoutClef(courtesyClef, courtesyClef->mutldata(), ctx.conf());
1349 : }
1350 :
1351 1286 : if (courtesyClefSeg && (!ctx.conf().styleB(Sid::genCourtesyClef) || (!isContinuationCourtesy && !m->hasCourtesyClef()))) {
1352 : // Whole segment shouldn't be shown, remove any existing courtesy signatures
1353 0 : if (!isContinuationCourtesy) {
1354 0 : m->setHasCourtesyClef(false);
1355 : }
1356 0 : if (courtesyClefSeg) {
1357 0 : courtesyClefSeg->setEnabled(false);
1358 : }
1359 : }
1360 :
1361 1286 : if (courtesyClefSeg && courtesyClefSeg->enabled()) {
1362 27 : if (courtesyClefSeg->hasElements()) {
1363 27 : courtesyClefSeg->createShapes();
1364 : } else {
1365 0 : courtesyClefSeg->setEnabled(false);
1366 0 : if (isContinuationCourtesy) {
1367 0 : m->setHasCourtesyClef(false);
1368 : }
1369 : }
1370 : }
1371 1286 : }
1372 :
1373 82 : static void calcParenTopBottom(Parenthesis* item, double& top, double& bottom, LayoutContext& ctx)
1374 : {
1375 82 : EngravingItem* parent = item->layoutParent();
1376 82 : const double spatium = item->spatium();
1377 82 : if (!parent) {
1378 0 : return;
1379 : }
1380 :
1381 82 : if (!parent->ldata()->isValid()) {
1382 0 : TLayout::layoutItem(parent, ctx);
1383 : }
1384 :
1385 82 : RectF bbox = parent->ldata()->bbox();
1386 :
1387 82 : top = std::min(top, bbox.top() + parent->pos().y() + spatium / 4);
1388 82 : bottom = std::max(bottom, bbox.bottom() + parent->pos().y() - spatium / 4);
1389 : }
1390 :
1391 1309 : void MeasureLayout::addRepeatCourtesyParentheses(Measure* m, const bool continuation, LayoutContext& ctx)
1392 : {
1393 1309 : const SegmentType tsSegType = continuation ? SegmentType::TimeSigStartRepeatAnnounce : SegmentType::TimeSigRepeatAnnounce;
1394 1309 : const SegmentType ksSegType = continuation ? SegmentType::KeySigStartRepeatAnnounce : SegmentType::KeySigRepeatAnnounce;
1395 1309 : const SegmentType clefSegType = continuation ? SegmentType::ClefStartRepeatAnnounce : SegmentType::ClefRepeatAnnounce;
1396 :
1397 1309 : const Fraction sigTick = continuation ? Fraction(0, 1) : m->ticks();
1398 :
1399 22295 : auto elShouldHaveParenthesis = [&](const Segment* seg, const track_idx_t track) -> bool {
1400 22295 : if (!seg || !seg->enabled() || track > ctx.dom().ntracks()) {
1401 21906 : return false;
1402 : }
1403 :
1404 389 : const Staff* staff = ctx.dom().staff(track2staff(track));
1405 389 : if (!staff) {
1406 140 : return false;
1407 : }
1408 249 : const StaffType* st = staff->staffType(seg->tick());
1409 249 : const bool noTimesig = st && seg->isType(SegmentType::TimeSigTypes) && !st->genTimesig();
1410 249 : const bool noKeysig = st && seg->isType(SegmentType::KeySigTypes) && !st->genKeysig();
1411 249 : const bool noClef = st && seg->isType(SegmentType::ClefTypes) && !st->genClef();
1412 249 : if (noTimesig || noKeysig || noClef) {
1413 0 : return false;
1414 : }
1415 :
1416 249 : const EngravingItem* el = seg->element(track);
1417 249 : return el && el->visible();
1418 1309 : };
1419 :
1420 3185 : auto timeSigShouldHaveOwnParentheses = [&](const Segment* seg, const track_idx_t track) -> bool {
1421 3185 : if (!elShouldHaveParenthesis(seg, track)) {
1422 3156 : return false;
1423 : }
1424 :
1425 29 : const EngravingItem* el = seg ? seg->element(track) : nullptr;
1426 29 : if (!el || !el->isTimeSig()) {
1427 0 : return false;
1428 : }
1429 :
1430 29 : return ctx.conf().styleV(Sid::timeSigPlacement).value<TimeSigPlacement>() != TimeSigPlacement::NORMAL;
1431 1309 : };
1432 :
1433 3185 : auto createParenthesesForSegments = [&](Segment* leftSeg, Segment* rightSeg, track_idx_t track) -> void {
1434 3185 : double top = DBL_MAX;
1435 3185 : double bottom = -DBL_MAX;
1436 3185 : EngravingItem* leftItem = leftSeg ? leftSeg->element(track) : nullptr;
1437 3185 : EngravingItem* rightItem = rightSeg ? rightSeg->element(track) : nullptr;
1438 3185 : Parenthesis* leftParen = nullptr;
1439 3185 : if (leftItem) {
1440 41 : leftItem->setParenthesesMode(leftItem->rightParen() ? ParenthesesMode::BOTH : ParenthesesMode::LEFT, true, true);
1441 41 : leftParen = leftItem->leftParen();
1442 : }
1443 3185 : Parenthesis* rightParen = nullptr;
1444 3185 : if (rightItem) {
1445 41 : rightItem->setParenthesesMode(rightItem->leftParen() ? ParenthesesMode::BOTH : ParenthesesMode::RIGHT, true, true);
1446 41 : rightParen = rightItem->rightParen();
1447 : }
1448 41 : bool needsBigTimeSigAdjust = leftSeg && rightSeg && leftSeg == rightSeg && leftSeg->isType(SegmentType::TimeSigTypes)
1449 3226 : && ctx.conf().styleV(Sid::timeSigPlacement).value<TimeSigPlacement>()
1450 3185 : != TimeSigPlacement::NORMAL;
1451 3185 : if ((ctx.conf().styleB(Sid::smallParens) || needsBigTimeSigAdjust) && leftParen && rightParen) {
1452 41 : const double spatium = leftParen->spatium();
1453 41 : calcParenTopBottom(leftParen, top, bottom, ctx);
1454 41 : calcParenTopBottom(rightParen, top, bottom, ctx);
1455 :
1456 41 : double height = bottom - top;
1457 :
1458 41 : if (!ctx.conf().styleB(Sid::smallParens)) {
1459 0 : top -= 1.25 * spatium;
1460 0 : height += 2.5 * spatium;
1461 : }
1462 :
1463 41 : rightParen->mutldata()->startY.set_value(top);
1464 41 : rightParen->mutldata()->height.set_value(height);
1465 41 : rightParen->mutldata()->midPointThickness.set_value(height / 60 * rightParen->ldata()->mag()); // 0.1sp for a height of 6sp
1466 41 : leftParen->mutldata()->startY.set_value(top);
1467 41 : leftParen->mutldata()->height.set_value(height);
1468 41 : leftParen->mutldata()->midPointThickness.set_value(height / 60 * leftParen->ldata()->mag()); // 0.1sp for a height of 6sp
1469 :
1470 41 : double mag = std::max(leftParen->ldata()->mag(), rightParen->ldata()->mag());
1471 41 : leftParen->mutldata()->setMag(mag);
1472 41 : rightParen->mutldata()->setMag(mag);
1473 3144 : } else if (leftParen || rightParen) {
1474 0 : const Staff* staff = leftParen ? leftParen->staff() : rightParen->staff();
1475 0 : const double spatium = leftParen ? leftParen->spatium() : rightParen->spatium();
1476 0 : const Fraction tick = leftParen ? leftParen->tick() : rightParen->tick();
1477 0 : if (leftParen) {
1478 0 : leftParen->mutldata()->startY.set_value(-spatium);
1479 0 : leftParen->mutldata()->height.set_value(staff->staffHeight(tick) + 2 * spatium * leftParen->mag());
1480 0 : leftParen->mutldata()->midPointThickness.set_value(leftParen->ldata()->height / 60 * leftParen->ldata()->mag()); // 0.1sp for a height of 6sp
1481 : }
1482 0 : if (rightParen) {
1483 0 : rightParen->mutldata()->startY.set_value(-spatium);
1484 0 : rightParen->mutldata()->height.set_value(staff->staffHeight(tick) + 2 * spatium * rightParen->mag());
1485 0 : rightParen->mutldata()->midPointThickness.set_value(rightParen->ldata()->height / 60 * rightParen->ldata()->mag()); // 0.1sp for a height of 6sp
1486 : }
1487 : }
1488 :
1489 3185 : if (leftParen) {
1490 41 : ParenthesisLayout::layoutParentheses(leftItem, ctx);
1491 : }
1492 :
1493 3185 : if (rightParen && rightItem != leftItem) {
1494 25 : ParenthesisLayout::layoutParentheses(rightItem, ctx);
1495 : }
1496 3185 : };
1497 :
1498 4494 : for (track_idx_t track = 0; track <= ctx.dom().nstaves() * VOICES; track += VOICES) {
1499 3185 : Segment* clefSeg = m->findSegmentR(clefSegType, sigTick);
1500 3185 : Segment* ksSeg = m->findSegmentR(ksSegType, sigTick);
1501 3185 : Segment* tsSeg = m->findSegmentR(tsSegType, sigTick);
1502 3185 : bool separateTsParens = timeSigShouldHaveOwnParentheses(tsSeg, track);
1503 :
1504 3185 : Segment* leftMostSeg = clefSeg;
1505 :
1506 3185 : if (!elShouldHaveParenthesis(leftMostSeg, track)) {
1507 3158 : leftMostSeg = ksSeg;
1508 : }
1509 :
1510 3185 : if (!separateTsParens && !elShouldHaveParenthesis(leftMostSeg, track)) {
1511 3148 : leftMostSeg = tsSeg;
1512 : }
1513 :
1514 3185 : if (!elShouldHaveParenthesis(leftMostSeg, track)) {
1515 3144 : leftMostSeg = nullptr;
1516 : }
1517 :
1518 : // Remove stale parentheses
1519 12740 : for (Segment* seg : { clefSeg, ksSeg, tsSeg }) {
1520 9555 : if (seg == leftMostSeg || !seg || (seg == tsSeg && separateTsParens) || !seg->element(track)) {
1521 9515 : continue;
1522 : }
1523 40 : EngravingItem* item = seg->element(track);
1524 40 : removeRepeatCourtesyParenthesis(item, DirectionH::LEFT);
1525 : }
1526 :
1527 3185 : Segment* rightMostSeg = separateTsParens ? nullptr : tsSeg;
1528 :
1529 3185 : if (!elShouldHaveParenthesis(rightMostSeg, track)) {
1530 3156 : rightMostSeg = ksSeg;
1531 : }
1532 :
1533 3185 : if (!elShouldHaveParenthesis(rightMostSeg, track)) {
1534 3156 : rightMostSeg = clefSeg;
1535 : }
1536 :
1537 3185 : if (!elShouldHaveParenthesis(rightMostSeg, track)) {
1538 3144 : rightMostSeg = nullptr;
1539 : }
1540 :
1541 : // Remove stale parentheses
1542 12740 : for (Segment* seg : { clefSeg, ksSeg, tsSeg }) {
1543 9555 : if (seg == rightMostSeg || !seg || (seg == tsSeg && separateTsParens) || !seg->element(track)) {
1544 9515 : continue;
1545 : }
1546 40 : EngravingItem* item = seg->element(track);
1547 40 : removeRepeatCourtesyParenthesis(item, DirectionH::RIGHT);
1548 : }
1549 :
1550 3185 : createParenthesesForSegments(leftMostSeg, rightMostSeg, track);
1551 :
1552 3185 : if (separateTsParens) {
1553 0 : createParenthesesForSegments(tsSeg, tsSeg, track);
1554 : }
1555 : }
1556 1309 : }
1557 :
1558 109445 : void MeasureLayout::removeRepeatCourtesyParenthesesMeasure(Measure* m, const bool continuation, LayoutContext& ctx)
1559 : {
1560 109445 : const SegmentType tsSegType = continuation ? SegmentType::TimeSigStartRepeatAnnounce : SegmentType::TimeSigRepeatAnnounce;
1561 109445 : const SegmentType ksSegType = continuation ? SegmentType::KeySigStartRepeatAnnounce : SegmentType::KeySigRepeatAnnounce;
1562 109445 : const SegmentType clefSegType = continuation ? SegmentType::ClefStartRepeatAnnounce : SegmentType::ClefRepeatAnnounce;
1563 :
1564 109445 : const Fraction sigTick = continuation ? Fraction(0, 1) : m->ticks();
1565 :
1566 109445 : Segment* clefSeg = m->findSegmentR(clefSegType, sigTick);
1567 109445 : Segment* ksSeg = m->findSegmentR(ksSegType, sigTick);
1568 109445 : Segment* tsSeg = m->findSegmentR(tsSegType, sigTick);
1569 :
1570 437780 : for (Segment* seg : { clefSeg, ksSeg, tsSeg }) {
1571 328335 : if (!seg) {
1572 328335 : continue;
1573 : }
1574 0 : for (track_idx_t track = 0; track <= ctx.dom().nstaves() * VOICES; track += VOICES) {
1575 0 : EngravingItem* item = seg->element(track);
1576 0 : if (!item) {
1577 0 : continue;
1578 : }
1579 0 : removeRepeatCourtesyParenthesis(item);
1580 : }
1581 : }
1582 109445 : }
1583 :
1584 80 : void MeasureLayout::removeRepeatCourtesyParenthesis(EngravingItem* item, const DirectionH direction)
1585 : {
1586 80 : if (!item) {
1587 0 : return;
1588 : }
1589 80 : if (direction == DirectionH::AUTO) {
1590 0 : if (Parenthesis* leftParen = item->leftParen()) {
1591 0 : item->remove(leftParen);
1592 : }
1593 0 : if (Parenthesis* rightParen = item->rightParen()) {
1594 0 : item->remove(rightParen);
1595 : }
1596 0 : return;
1597 : }
1598 :
1599 80 : Parenthesis* paren = item->paren(direction);
1600 80 : if (!paren) {
1601 80 : return;
1602 : }
1603 :
1604 0 : item->remove(paren);
1605 : }
1606 :
1607 55377 : void MeasureLayout::setRepeatCourtesiesAndParens(Measure* m, LayoutContext& ctx)
1608 : {
1609 55377 : const bool showCourtesyRepeats = m->repeatEnd() && ctx.conf().styleB(Sid::showCourtesiesRepeats);
1610 55377 : const bool showCourtesyOtherJumps = m->repeatJump() && ctx.conf().styleB(Sid::showCourtesiesOtherJumps);
1611 :
1612 55377 : if (showCourtesyRepeats) {
1613 416 : MeasureLayout::addRepeatCourtesies(m, ctx);
1614 416 : if (ctx.conf().styleB(Sid::useParensRepeatCourtesies)) {
1615 416 : MeasureLayout::addRepeatCourtesyParentheses(m, false, ctx);
1616 : } else {
1617 0 : MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, false, ctx);
1618 : }
1619 : }
1620 :
1621 55377 : if (showCourtesyOtherJumps) {
1622 308 : MeasureLayout::addRepeatCourtesies(m, ctx);
1623 308 : if (ctx.conf().styleB(Sid::useParensOtherJumpCourtesies)) {
1624 308 : MeasureLayout::addRepeatCourtesyParentheses(m, false, ctx);
1625 : } else {
1626 0 : MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, false, ctx);
1627 : }
1628 : }
1629 :
1630 55377 : if (!showCourtesyRepeats && !showCourtesyOtherJumps) {
1631 54653 : MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, false, ctx);
1632 54653 : removeRepeatCourtesies(m);
1633 : }
1634 :
1635 103896 : const bool courtesiesAfterCancellingRepeats = m->prevMeasureMM() && m->prevMeasureMM()->repeatEnd()
1636 521 : && ctx.conf().styleB(Sid::showCourtesiesAfterCancellingRepeats)
1637 103896 : && ctx.conf().styleB(Sid::showCourtesiesRepeats);
1638 103896 : const bool courtesiesAfterCancellingOtherJumps = m->prevMeasureMM() && m->prevMeasureMM()->repeatJump()
1639 436 : && ctx.conf().styleB(Sid::showCourtesiesAfterCancellingOtherJumps)
1640 103896 : && ctx.conf().styleB(Sid::showCourtesiesOtherJumps);
1641 55377 : if (courtesiesAfterCancellingRepeats) {
1642 307 : MeasureLayout::addRepeatContinuationCourtesies(m, ctx);
1643 307 : if (ctx.conf().styleB(Sid::useParensRepeatCourtesiesAfterCancelling)) {
1644 307 : MeasureLayout::addRepeatCourtesyParentheses(m, true, ctx);
1645 : } else {
1646 0 : MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, true, ctx);
1647 : }
1648 : }
1649 :
1650 55377 : if (courtesiesAfterCancellingOtherJumps) {
1651 278 : MeasureLayout::addRepeatContinuationCourtesies(m, ctx);
1652 278 : if (ctx.conf().styleB(Sid::useParensOtherJumpCourtesiesAfterCancelling)) {
1653 278 : MeasureLayout::addRepeatCourtesyParentheses(m, true, ctx);
1654 : } else {
1655 0 : MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, true, ctx);
1656 : }
1657 : }
1658 :
1659 55377 : if (!courtesiesAfterCancellingRepeats && !courtesiesAfterCancellingOtherJumps) {
1660 54792 : MeasureLayout::removeRepeatCourtesyParenthesesMeasure(m, true, ctx);
1661 54792 : removeRepeatContinuationCourtesies(m);
1662 : }
1663 55377 : }
1664 :
1665 724 : void MeasureLayout::addRepeatCourtesies(Measure* m, LayoutContext& ctx)
1666 : {
1667 724 : const std::vector<Measure*> measures = findFollowingRepeatMeasures(m);
1668 724 : if (measures.empty()) {
1669 91 : removeRepeatCourtesies(m);
1670 91 : return;
1671 : }
1672 :
1673 633 : bool hasCourtesies = false;
1674 1385 : for (Measure* repeatStartMeasure : measures) {
1675 : // Follow section break courtesy property
1676 752 : const Measure* prevMeasure = repeatStartMeasure->prevMeasureMM();
1677 752 : const LayoutBreak* sectionBreak = prevMeasure ? prevMeasure->sectionBreakElement() : nullptr;
1678 752 : const bool sectionBreakHideCourtesies = sectionBreak && !sectionBreak->showCourtesy();
1679 :
1680 752 : if (repeatStartMeasure == m->nextMeasureMM() || sectionBreakHideCourtesies) {
1681 51 : continue;
1682 : }
1683 701 : setCourtesyClef(m, repeatStartMeasure->tick(), m->endTick(), SegmentType::ClefRepeatAnnounce, ctx);
1684 701 : setCourtesyKeySig(m, repeatStartMeasure->tick(), m->endTick(), SegmentType::KeySigRepeatAnnounce, ctx);
1685 701 : setCourtesyTimeSig(m, repeatStartMeasure->tick(), m->endTick(), SegmentType::TimeSigRepeatAnnounce, ctx);
1686 :
1687 701 : hasCourtesies = true;
1688 : }
1689 :
1690 633 : if (!hasCourtesies) {
1691 10 : removeRepeatCourtesies(m);
1692 : }
1693 724 : }
1694 :
1695 54754 : void MeasureLayout::removeRepeatCourtesies(Measure* m)
1696 : {
1697 111320 : for (Segment* seg = m->last(); seg != m->first(); seg = seg->prev()) {
1698 80091 : if (seg->isChordRestType()) {
1699 23525 : break;
1700 : }
1701 56566 : if (!seg->isType(SegmentType::ClefRepeatAnnounce | SegmentType::TimeSigRepeatAnnounce | SegmentType::KeySigRepeatAnnounce)) {
1702 56566 : continue;
1703 : }
1704 0 : seg->mutldata()->reset();
1705 :
1706 0 : if (seg->enabled()) {
1707 0 : seg->setEnabled(false);
1708 : }
1709 : }
1710 54754 : m->setHasCourtesyClef(false);
1711 54754 : m->setHasCourtesyKeySig(false);
1712 54754 : m->setHasCourtesyTimeSig(false);
1713 54754 : }
1714 :
1715 585 : void MeasureLayout::addRepeatContinuationCourtesies(Measure* m, LayoutContext& ctx)
1716 : {
1717 585 : setCourtesyTimeSig(m, m->tick(), m->tick(), SegmentType::TimeSigStartRepeatAnnounce, ctx);
1718 585 : setCourtesyKeySig(m, m->tick(), m->tick(), SegmentType::KeySigStartRepeatAnnounce, ctx);
1719 585 : setCourtesyClef(m, m->tick(), m->tick(), SegmentType::ClefStartRepeatAnnounce, ctx);
1720 585 : }
1721 :
1722 54792 : void MeasureLayout::removeRepeatContinuationCourtesies(Measure* m)
1723 : {
1724 94742 : for (Segment* seg = m->first(); seg != m->last(); seg = seg->next()) {
1725 94616 : if (seg->isChordRestType()) {
1726 54666 : break;
1727 : }
1728 39950 : if (!seg->isType(SegmentType::ClefStartRepeatAnnounce | SegmentType::TimeSigStartRepeatAnnounce
1729 : | SegmentType::KeySigStartRepeatAnnounce)) {
1730 39950 : continue;
1731 : }
1732 :
1733 0 : seg->mutldata()->reset();
1734 :
1735 0 : if (seg->enabled()) {
1736 0 : seg->setEnabled(false);
1737 : }
1738 : }
1739 54792 : }
1740 :
1741 17654 : Segment* MeasureLayout::addHeaderClef(Measure* m, bool isFirstClef, const Staff* staff, LayoutContext& ctx)
1742 : {
1743 17654 : const staff_idx_t staffIdx = staff->idx();
1744 17654 : const track_idx_t track = staffIdx * VOICES;
1745 17654 : Segment* cSegment = m->findFirstR(SegmentType::HeaderClef, Fraction(0, 1));
1746 17654 : const StaffType* staffType = staff->staffType(m->tick());
1747 :
1748 17654 : const bool hideClef = staffType->isTabStaff() ? ctx.conf().styleB(Sid::hideTabClefAfterFirst) : !ctx.conf().styleB(Sid::genClef);
1749 :
1750 : // find the clef type at the previous tick
1751 17654 : ClefTypeList cl = staff->clefType(m->tick() - Fraction::eps());
1752 17654 : bool showCourtesy = true;
1753 17654 : Segment* s = nullptr;
1754 17654 : if (m->prevMeasure()) {
1755 : // look for a clef change at the end of the previous measure
1756 6911 : s = m->prevMeasure()->findSegment(SegmentType::Clef, m->tick());
1757 10743 : } else if (m->isMMRest()) {
1758 : // look for a header clef at the beginning of the first underlying measure
1759 111 : s = m->mmRestFirst()->findFirstR(SegmentType::HeaderClef, Fraction(0, 1));
1760 : }
1761 17654 : if (s) {
1762 257 : Clef* c = toClef(s->element(track));
1763 257 : if (c) {
1764 195 : cl = c->clefTypeList();
1765 195 : showCourtesy = c->showCourtesy();
1766 : }
1767 : }
1768 17654 : Clef* clef = nullptr;
1769 17654 : if (cSegment) {
1770 14366 : clef = toClef(cSegment->element(track));
1771 : }
1772 17654 : if (staff->staffTypeForElement(m)->genClef() && (isFirstClef || !hideClef)) {
1773 17570 : if (!cSegment) {
1774 3280 : cSegment = Factory::createSegment(m, SegmentType::HeaderClef, Fraction(0, 1));
1775 3280 : m->add(cSegment);
1776 : }
1777 17570 : cSegment->setHeader(true);
1778 17570 : if (!clef) {
1779 : //
1780 : // create missing clef
1781 : //
1782 5021 : clef = Factory::createClef(cSegment);
1783 5021 : clef->setTrack(track);
1784 5021 : clef->setGenerated(true);
1785 5021 : clef->setShowCourtesy(showCourtesy);
1786 5021 : cSegment->add(clef);
1787 : }
1788 17570 : if (clef->generated()) {
1789 13233 : clef->setClefType(cl);
1790 : }
1791 17570 : clef->setSmall(false);
1792 17570 : clef->mutldata()->reset();
1793 17570 : TLayout::layoutClef(clef, clef->mutldata(), ctx.conf());
1794 17570 : cSegment->setEnabled(true);
1795 84 : } else if (clef) {
1796 0 : clef->ownershipParentItem()->remove(clef);
1797 0 : if (clef->generated()) {
1798 0 : delete clef;
1799 : }
1800 : }
1801 :
1802 17654 : return cSegment;
1803 : }
1804 :
1805 17654 : Segment* MeasureLayout::addHeaderKeySig(Measure* m, bool isFirstKeysig, const Staff* staff, LayoutContext& ctx)
1806 : {
1807 17654 : const staff_idx_t staffIdx = staff->idx();
1808 17654 : const track_idx_t track = staffIdx * VOICES;
1809 17654 : Segment* kSegment = m->findFirstR(SegmentType::KeySig, Fraction(0, 1));
1810 : // If we need a Key::C KeySig (which would be invisible) and there is
1811 : // a courtesy key sig, don’t create it and switch generated flags.
1812 : // This avoids creating an invisible KeySig which can distort layout.
1813 :
1814 17654 : KeySigEvent keyIdx = staff->keySigEvent(m->tick());
1815 17654 : KeySig* ksAnnounce = 0;
1816 17654 : if ((isFirstKeysig || ctx.conf().styleB(Sid::genKeysig)) && (keyIdx.key() == Key::C)) {
1817 16105 : Measure* pm = m->prevMeasureMM();
1818 16105 : if (pm && pm->hasCourtesyKeySig()) {
1819 8 : Segment* ks = pm->first(SegmentType::KeySigAnnounce);
1820 8 : if (ks) {
1821 0 : ksAnnounce = toKeySig(ks->element(track));
1822 0 : if (ksAnnounce) {
1823 0 : isFirstKeysig = false;
1824 : // if (keysig) {
1825 : // ksAnnounce->setGenerated(false);
1826 : //TODO keysig->setGenerated(true);
1827 : // }
1828 : }
1829 : }
1830 : }
1831 : }
1832 :
1833 17654 : bool isPitchedStaff = staff->isPitchedStaff(m->tick());
1834 :
1835 17654 : KeySig* keysig = nullptr;
1836 17654 : if (kSegment) {
1837 13725 : keysig = toKeySig(kSegment->element(track));
1838 : }
1839 : // keep key sigs in TABs: TABs themselves should hide them
1840 17654 : if ((isFirstKeysig || ctx.conf().styleB(Sid::genKeysig)) && isPitchedStaff) {
1841 16202 : if (!kSegment) {
1842 3025 : kSegment = Factory::createSegment(m, SegmentType::KeySig, Fraction(0, 1));
1843 3025 : m->add(kSegment);
1844 : }
1845 16202 : kSegment->setHeader(true);
1846 16202 : if (!keysig) {
1847 : //
1848 : // create missing key signature
1849 : //
1850 4524 : keysig = Factory::createKeySig(kSegment);
1851 4524 : keysig->setTrack(track);
1852 4524 : keysig->setGenerated(true);
1853 4524 : kSegment->add(keysig);
1854 : }
1855 16202 : keysig->setKeySigEvent(keyIdx);
1856 16202 : keysig->mutldata()->reset();
1857 16202 : TLayout::layoutKeySig(keysig, keysig->mutldata(), ctx.conf());
1858 16202 : kSegment->setEnabled(true);
1859 1452 : } else if (keysig && isPitchedStaff) {
1860 : // do not remove user modified keysigs
1861 0 : bool remove = true;
1862 0 : EngravingItem* e = kSegment->element(staffIdx * VOICES);
1863 0 : Key key = staff->key(m->tick());
1864 0 : if ((e && !e->generated()) || (key != keyIdx.key())) {
1865 0 : remove = false;
1866 : }
1867 :
1868 0 : if (remove) {
1869 0 : keysig->ownershipParentItem()->remove(keysig);
1870 0 : if (keysig->generated()) {
1871 0 : delete keysig;
1872 : }
1873 : }
1874 : }
1875 :
1876 17654 : return kSegment;
1877 17654 : }
1878 :
1879 : //-------------------------------------------------------------------
1880 : // addSystemHeader
1881 : /// Add elements to make this measure suitable as the first measure
1882 : /// of a system.
1883 : // The system header can contain a starting BarLine, a Clef,
1884 : // and a KeySig
1885 : //-------------------------------------------------------------------
1886 :
1887 11459 : void MeasureLayout::addSystemHeader(Measure* m, bool isFirstSystem, LayoutContext& ctx)
1888 : {
1889 11459 : int staffIdx = 0;
1890 11459 : Segment* kSegment = nullptr;
1891 11459 : Segment* cSegment = nullptr;
1892 :
1893 29113 : for (const Staff* staff : ctx.dom().staves()) {
1894 17654 : const int track = staffIdx * VOICES;
1895 :
1896 : // Check if this is the first VISIBLE appearance
1897 17654 : bool isFirstClef = true;
1898 17654 : bool isFirstKeySig = true;
1899 17654 : if (!isFirstSystem) {
1900 11369 : const Fraction clefTick = staff->currentClefTick(m->tick());
1901 11369 : const Fraction keySigTick = staff->currentKeyTick(m->tick());
1902 : // Get first measure whether MMR or not
1903 11369 : Measure* searchMeasure = ctx.mutDom().tick2measure(std::min(clefTick, keySigTick));
1904 11369 : searchMeasure = searchMeasure->hasMMRest()
1905 11369 : && ctx.conf().styleB(Sid::createMultiMeasureRests) ? searchMeasure->mmRest() : searchMeasure;
1906 24674 : while (searchMeasure->tick() < m->tick() && (isFirstClef || isFirstKeySig)) {
1907 13305 : const System* sys = searchMeasure->system();
1908 13305 : if (isFirstClef && searchMeasure->tick() >= clefTick) {
1909 : // Need to check previous measure for clef change if one not found in this measure
1910 8784 : Segment* clefSeg = searchMeasure->findFirstR(SegmentType::Clef | SegmentType::HeaderClef, Fraction(0, 1));
1911 8784 : Measure* prevMeas = searchMeasure->prevMeasure();
1912 8784 : if (prevMeas && !clefSeg) {
1913 1928 : clefSeg = prevMeas->findSegment(SegmentType::Clef, m->tick());
1914 : }
1915 8784 : if (clefSeg && clefSeg->enabled()) {
1916 6815 : const Clef* c = toClef(clefSeg->element(track));
1917 6815 : if (c && sys && sys->staff(staffIdx)->show()) {
1918 6578 : isFirstClef = false;
1919 : }
1920 : }
1921 : }
1922 13305 : if (isFirstKeySig && searchMeasure->tick() >= keySigTick) {
1923 10098 : const Segment* ksSeg = searchMeasure->findSegment(SegmentType::KeySig, searchMeasure->tick());
1924 10098 : if (ksSeg && ksSeg->enabled()) {
1925 6689 : const KeySig* ks = toKeySig(ksSeg->element(track));
1926 6689 : if (ks && sys && sys->staff(staffIdx)->show()) {
1927 6452 : isFirstKeySig = false;
1928 : }
1929 : }
1930 : }
1931 13305 : searchMeasure = searchMeasure->nextMeasureMM();
1932 : }
1933 : }
1934 :
1935 17654 : cSegment = addHeaderClef(m, isFirstSystem || isFirstClef, staff, ctx);
1936 :
1937 17654 : kSegment = addHeaderKeySig(m, isFirstSystem || isFirstKeySig, staff, ctx);
1938 :
1939 17654 : ++staffIdx;
1940 : }
1941 11459 : if (cSegment) {
1942 11447 : cSegment->createShapes();
1943 : }
1944 11459 : if (kSegment) {
1945 11257 : kSegment->createShapes();
1946 : }
1947 :
1948 11459 : MeasureLayout::createSystemBeginBarLine(m, ctx);
1949 :
1950 11459 : m->checkHeader();
1951 11459 : }
1952 :
1953 752 : void MeasureLayout::removeSystemHeader(Measure* m)
1954 : {
1955 752 : if (!m->header()) {
1956 0 : return;
1957 : }
1958 2659 : for (Segment* seg = m->first(); seg; seg = seg->next()) {
1959 2659 : if (seg->isKeySigType()) {
1960 749 : bool keySigChangeHappensHere = false;
1961 2013 : for (Staff* staff : m->score()->staves()) {
1962 1269 : if (staff->keyList()->count(m->tick().ticks()) > 0) {
1963 5 : keySigChangeHappensHere = true;
1964 5 : break;
1965 : }
1966 : }
1967 749 : if (seg->header() && !keySigChangeHappensHere) {
1968 744 : seg->setEnabled(false);
1969 : }
1970 : }
1971 2659 : if (!seg->header()) {
1972 752 : break;
1973 : }
1974 1907 : if (!seg->isKeySigType()) {
1975 1158 : seg->setEnabled(false);
1976 : }
1977 : }
1978 752 : m->setHeader(false);
1979 : }
1980 :
1981 34955 : void MeasureLayout::addSystemTrailer(Measure* m, Measure* nm, LayoutContext& ctx)
1982 : {
1983 34955 : const size_t nstaves = ctx.dom().nstaves();
1984 34955 : bool systemBreakHideCourtesy = false;
1985 34955 : if (LayoutBreak* sectionBreakElement = m->sectionBreakElement()) {
1986 101 : systemBreakHideCourtesy = !sectionBreakElement->showCourtesy();
1987 : }
1988 :
1989 : // locate a time sig. in the next measure and, if found,
1990 : // check if it has court. sig. turned off
1991 34955 : if (nm && ctx.conf().styleB(Sid::genCourtesyTimesig) && !systemBreakHideCourtesy && !ctx.conf().isFloatMode()) {
1992 30791 : setCourtesyTimeSig(m, nm->tick(), m->endTick(), SegmentType::TimeSigAnnounce, ctx);
1993 : }
1994 :
1995 : // courtesy key signatures, clefs
1996 34955 : if (nm && ctx.conf().styleB(Sid::genCourtesyKeysig) && !systemBreakHideCourtesy) {
1997 30917 : setCourtesyKeySig(m, nm->tick(), m->endTick(), SegmentType::KeySigAnnounce, ctx);
1998 : }
1999 :
2000 34955 : Segment* courtesyClefSeg = m->findSegmentR(SegmentType::Clef, m->ticks());
2001 34955 : if (courtesyClefSeg) {
2002 723 : for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
2003 423 : const track_idx_t track = staffIdx * VOICES;
2004 :
2005 423 : Clef* courtesyClef = toClef(courtesyClefSeg->element(track));
2006 423 : if (courtesyClef) {
2007 319 : courtesyClef->setSmall(true);
2008 319 : courtesyClef->setIsTrailer(true);
2009 : }
2010 : }
2011 : }
2012 34955 : if (courtesyClefSeg) {
2013 300 : courtesyClefSeg->createShapes();
2014 : }
2015 :
2016 34955 : m->checkTrailer();
2017 34955 : }
2018 :
2019 1090 : void MeasureLayout::removeSystemTrailer(Measure* m, LayoutContext& ctx)
2020 : {
2021 2606 : for (Segment* seg = m->last(); seg != m->first(); seg = seg->prev()) {
2022 2208 : if (seg->isChordRestType()) {
2023 692 : break;
2024 : }
2025 :
2026 1516 : if (seg->isClefType()) {
2027 110 : for (EngravingItem* el : seg->elist()) {
2028 96 : if (!el) {
2029 80 : continue;
2030 : }
2031 16 : Clef* clef = toClef(el);
2032 16 : clef->setIsTrailer(false);
2033 16 : TLayout::layoutClef(clef, clef->mutldata(), ctx.conf());
2034 : }
2035 14 : seg->createShapes();
2036 : }
2037 :
2038 1516 : if (seg->isTimeTickType() || !seg->trailer()) {
2039 1084 : continue;
2040 : }
2041 :
2042 432 : if (seg->enabled()) {
2043 430 : seg->setEnabled(false);
2044 430 : seg->setTrailer(false);
2045 : }
2046 : }
2047 1090 : m->setTrailer(false);
2048 1090 : }
2049 :
2050 25855 : void MeasureLayout::createSystemBeginBarLine(Measure* m, LayoutContext& ctx)
2051 : {
2052 25855 : if (!m->system()) {
2053 0 : return;
2054 : }
2055 25855 : Segment* s = m->findSegment(SegmentType::BeginBarLine, m->tick());
2056 25855 : size_t n = 0;
2057 25855 : if (m->system()) {
2058 65291 : for (SysStaff* sysStaff : m->system()->staves()) {
2059 39436 : if (sysStaff->show()) {
2060 38855 : ++n;
2061 : }
2062 : }
2063 : }
2064 7673 : if ((n > 1 && ctx.conf().styleB(Sid::startBarlineMultiple))
2065 33528 : || (n == 1 && (ctx.conf().styleB(Sid::startBarlineSingle) || m->system()->brackets().size()))) {
2066 7706 : if (!s) {
2067 1277 : s = Factory::createSegment(m, SegmentType::BeginBarLine, Fraction(0, 1));
2068 1277 : m->add(s);
2069 : }
2070 28764 : for (track_idx_t track = 0; track < ctx.dom().ntracks(); track += VOICES) {
2071 21058 : BarLine* bl = toBarLine(s->element(track));
2072 21058 : if (!bl) {
2073 3484 : bl = Factory::createBarLine(s);
2074 3484 : bl->setTrack(track);
2075 3484 : bl->setGenerated(true);
2076 3484 : bl->setBarLineType(BarLineType::NORMAL);
2077 3484 : bl->setSpanStaff(true);
2078 3484 : s->add(bl);
2079 : }
2080 :
2081 21058 : TLayout::layoutBarLine(bl, bl->mutldata(), ctx);
2082 : }
2083 7706 : s->createShapes();
2084 7706 : s->setEnabled(true);
2085 7706 : s->setHeader(true);
2086 7706 : m->setHeader(true);
2087 18149 : } else if (s) {
2088 73 : s->setEnabled(false);
2089 : }
2090 : }
2091 :
2092 0 : void MeasureLayout::stretchMeasureInPracticeMode(Measure* m, double targetWidth, LayoutContext& ctx)
2093 : {
2094 0 : Measure::LayoutData* ldata = m->mutldata();
2095 0 : ldata->setWidth(targetWidth);
2096 :
2097 : //---------------------------------------------------
2098 : // compute stretch
2099 : //---------------------------------------------------
2100 :
2101 0 : std::multimap<double, Segment*> springs;
2102 :
2103 0 : Segment* seg = m->first();
2104 0 : while (seg && !seg->enabled()) {
2105 0 : seg = seg->next();
2106 : }
2107 0 : double minimumWidth = seg ? seg->x() : 0.0;
2108 0 : for (Segment& s : m->segments()) {
2109 0 : s.setStretch(1);
2110 :
2111 : // if (!s.enabled() || !s.visible())
2112 : // ;continue;
2113 0 : Fraction t = s.ticks();
2114 0 : if (t.isNotZero()) {
2115 0 : springs.insert(std::pair<double, Segment*>(0, &s));
2116 : }
2117 0 : minimumWidth += s.width() + s.spacing();
2118 : }
2119 :
2120 : //---------------------------------------------------
2121 : // compute 1/Force for a given Extend
2122 : //---------------------------------------------------
2123 :
2124 0 : if (targetWidth > minimumWidth) {
2125 0 : double chordRestSegmentsWidth{ 0 };
2126 0 : for (auto i = springs.begin(); i != springs.end(); i++) {
2127 0 : chordRestSegmentsWidth += i->second->width() + i->second->spacing();
2128 : }
2129 :
2130 0 : double stretch = 1 + (targetWidth - minimumWidth) / chordRestSegmentsWidth;
2131 :
2132 : //---------------------------------------------------
2133 : // distribute stretch to segments
2134 : //---------------------------------------------------
2135 :
2136 0 : for (auto& i : springs) {
2137 0 : i.second->setStretch(stretch);
2138 : }
2139 :
2140 : //---------------------------------------------------
2141 : // move segments to final position
2142 : //---------------------------------------------------
2143 :
2144 0 : Segment* s = m->first();
2145 0 : while (s && !s->enabled()) {
2146 0 : s = s->next();
2147 : }
2148 :
2149 0 : double x = s ? s->pos().x() : 0.0;
2150 0 : while (s) {
2151 : // if (!s->enabled() || !s->visible()) {
2152 : // s = s->nextEnabled();
2153 : // continue;
2154 : // }
2155 :
2156 0 : double spacing = s->spacing();
2157 0 : double widthWithoutSpacing = s->width() - spacing;
2158 0 : double segmentStretch = s->stretch();
2159 0 : x += spacing * (muse::RealIsNull(segmentStretch) ? 1 : segmentStretch);
2160 0 : s->mutldata()->setPosX(x);
2161 0 : x += widthWithoutSpacing * (muse::RealIsNull(segmentStretch) ? 1 : segmentStretch);
2162 0 : s = s->nextEnabled();
2163 : }
2164 : }
2165 :
2166 : //---------------------------------------------------
2167 : // layout individual elements
2168 : //---------------------------------------------------
2169 :
2170 0 : for (Segment& s : m->segments()) {
2171 0 : if (!s.enabled()) {
2172 0 : continue;
2173 : }
2174 : // After the rest of the spacing is calculated we position grace-notes-after.
2175 0 : ChordLayout::repositionGraceNotesAfter(&s, ctx.dom().ntracks());
2176 0 : for (EngravingItem* e : s.elist()) {
2177 0 : if (!e) {
2178 0 : continue;
2179 : }
2180 0 : ElementType t = e->type();
2181 0 : staff_idx_t staffIdx = e->staffIdx();
2182 0 : if (t == ElementType::MEASURE_REPEAT || (t == ElementType::REST && (m->isMMRest() || toRest(e)->isFullMeasureRest()))) {
2183 : //
2184 : // element has to be centered in free space
2185 : // x1 - left measure position of free space
2186 : // x2 - right measure position of free space
2187 :
2188 : Segment* s1;
2189 0 : for (s1 = s.prev(); s1 && !s1->enabled(); s1 = s1->prev()) {
2190 : }
2191 : Segment* s2;
2192 0 : for (s2 = s.next(); s2; s2 = s2->next()) {
2193 0 : if (s2->enabled() && !s2->isChordRestType() && s2->element(staffIdx * VOICES)) {
2194 0 : break;
2195 : }
2196 : }
2197 0 : double x1 = s1 ? s1->x() + s1->minRight() : 0;
2198 0 : double x2 = s2 ? s2->x() - s2->minLeft() : targetWidth;
2199 :
2200 0 : if (m->isMMRest()) {
2201 0 : MMRest* mmrest = toMMRest(e);
2202 : //
2203 : // center multi measure rest
2204 : //
2205 0 : double d = ctx.conf().styleAbsolute(Sid::multiMeasureRestMargin);
2206 0 : double w = x2 - x1 - 2 * d;
2207 :
2208 0 : mmrest->mutldata()->restWidth = w;
2209 0 : TLayout::layoutMMRest(mmrest, mmrest->mutldata(), ctx);
2210 0 : e->setPos(x1 - s.x() + d, e->staff()->staffHeight() * .5); // center vertically in measure
2211 0 : s.createShape(staffIdx);
2212 : } else { // if (rest->isFullMeasureRest()) {
2213 : //
2214 : // center full measure rest
2215 : //
2216 0 : e->mutldata()->setPosX((x2 - x1 - e->width()) * .5 + x1 - s.x() - e->ldata()->bbox().x());
2217 0 : s.createShape(staffIdx); // DEBUG
2218 : }
2219 0 : } else if (t == ElementType::REST) {
2220 0 : e->mutldata()->setPosX(0);
2221 0 : } else if (t == ElementType::CHORD) {
2222 0 : Chord* c = toChord(e);
2223 0 : if (c->tremoloSingleChord()) {
2224 0 : TremoloLayout::layout(c->tremoloSingleChord(), ctx);
2225 0 : } else if (c->tremoloTwoChord()) {
2226 0 : TremoloTwoChord* tr = c->tremoloTwoChord();
2227 0 : Chord* c1 = tr->chord1();
2228 0 : Chord* c2 = tr->chord2();
2229 0 : if (c1 && !c1->staffMove() && c2 && !c2->staffMove()) {
2230 0 : TremoloLayout::layout(tr, ctx);
2231 : }
2232 : }
2233 0 : } else if (t == ElementType::BAR_LINE) {
2234 0 : e->mutldata()->setPosY(0.0);
2235 : // for end barlines, x position was set in createEndBarLines
2236 0 : if (s.segmentType() != SegmentType::EndBarLine) {
2237 0 : e->mutldata()->setPosX(0.0);
2238 : }
2239 : }
2240 : }
2241 : }
2242 0 : }
2243 :
2244 31954 : void MeasureLayout::layoutTimeTickAnchors(Measure* m, LayoutContext& ctx)
2245 : {
2246 31954 : bool darker = true;
2247 153228 : for (Segment& segment : m->segments()) {
2248 121274 : if (!segment.isTimeTickType()) {
2249 120781 : continue;
2250 : }
2251 :
2252 501 : Segment* refCRSeg = m->findSegmentR(SegmentType::ChordRest, segment.rtick());
2253 501 : if (!(refCRSeg && refCRSeg->isActive())) {
2254 405 : refCRSeg = segment.prevActive();
2255 408 : while (refCRSeg && !refCRSeg->isChordRestType()) {
2256 3 : refCRSeg = refCRSeg->prevActive();
2257 : }
2258 : }
2259 :
2260 501 : if (!refCRSeg || refCRSeg->ticks().isZero()) {
2261 8 : continue;
2262 : }
2263 :
2264 493 : Fraction refSegDuration = refCRSeg->ticks();
2265 493 : Fraction thisDuration = segment.ticks();
2266 493 : Fraction relativeTick = segment.rtick() - refCRSeg->rtick();
2267 :
2268 493 : Segment* nextSeg = m->findSegmentR(SegmentType::ChordRest, refCRSeg->rtick() + refCRSeg->ticks());
2269 493 : if (!(nextSeg && nextSeg->isActive())) {
2270 425 : nextSeg = m->findSegmentR(SegmentType::BarLineTypes, refCRSeg->rtick() + refCRSeg->ticks());
2271 : }
2272 493 : double width = nextSeg ? nextSeg->x() - refCRSeg->x() : refCRSeg->width();
2273 :
2274 493 : double relativeX = width * (relativeTick.toDouble() / refCRSeg->ticks().toDouble());
2275 493 : double relativeWidth = width * (thisDuration.toDouble() / refSegDuration.toDouble());
2276 :
2277 493 : segment.mutldata()->setPosX(refCRSeg->x() + relativeX);
2278 493 : segment.setWidth(relativeWidth);
2279 :
2280 3449 : for (EngravingItem* item : segment.elist()) {
2281 2956 : if (item) {
2282 498 : TLayout::layoutItem(item, ctx);
2283 498 : toTimeTickAnchor(item)->mutldata()->setDarker(darker);
2284 : }
2285 : }
2286 493 : darker = !darker;
2287 : }
2288 31954 : }
2289 :
2290 : //---------------------------------------------------------
2291 : // layoutPartialWidth
2292 : /// Layout staff lines for the specified width only, aligned
2293 : /// to the left or right of the measure
2294 : //---------------------------------------------------------
2295 :
2296 0 : void MeasureLayout::layoutPartialWidth(StaffLines* lines, LayoutContext& ctx, double w, double wPartial, bool alignRight)
2297 : {
2298 0 : StaffLines::LayoutData* ldata = lines->mutldata();
2299 0 : const Staff* s = lines->staff();
2300 0 : double _spatium = lines->spatium();
2301 0 : wPartial *= _spatium;
2302 0 : double dist = _spatium;
2303 0 : lines->setPos(PointF(0.0, 0.0));
2304 : int _lines;
2305 0 : if (s) {
2306 0 : lines->mutldata()->setMag(s->staffMag(lines->measure()->tick()));
2307 0 : lines->setColor(s->color(lines->measure()->tick()));
2308 0 : const StaffType* st = s->staffType(lines->measure()->tick());
2309 0 : dist *= st->lineDistance().val();
2310 0 : _lines = st->lines();
2311 0 : lines->mutldata()->setPosY(lines->staffOffsetY());
2312 : } else {
2313 0 : _lines = 5;
2314 0 : lines->setColor(lines->configuration()->defaultColor());
2315 : }
2316 0 : lines->setLw(ctx.conf().styleS(Sid::staffLineWidth).val() * _spatium);
2317 0 : double x1 = lines->pos().x();
2318 0 : double x2 = x1 + w;
2319 0 : double y = lines->pos().y();
2320 0 : ldata->setBbox(x1, -lines->lw() * .5 + y, w, (_lines - 1) * dist + lines->lw());
2321 :
2322 0 : if (_lines == 1) {
2323 0 : double extraSize = _spatium;
2324 0 : ldata->setBbox(ldata->bbox().adjusted(0, -extraSize, 0, extraSize));
2325 : }
2326 :
2327 0 : std::vector<LineF> ll;
2328 0 : for (int i = 0; i < _lines; ++i) {
2329 0 : if (alignRight) {
2330 0 : ll.push_back(LineF(x2 - wPartial, y, x2, y));
2331 : } else {
2332 0 : ll.push_back(LineF(x1, y, x1 + wPartial, y));
2333 : }
2334 0 : y += dist;
2335 : }
2336 0 : lines->setLines(ll);
2337 0 : }
2338 :
2339 23147 : void MeasureLayout::updateKeySignatures(const Measure* measure, LayoutContext& ctx)
2340 : {
2341 23147 : Measure* prevMeasure = measure->prevMeasure();
2342 23147 : if (!prevMeasure || !prevMeasure->repeatEnd()) {
2343 22862 : return;
2344 : }
2345 1156 : for (const Segment& seg : measure->segments()) {
2346 871 : if (!seg.isType(SegmentType::KeySigTypes)) {
2347 863 : continue;
2348 : }
2349 :
2350 68 : for (EngravingItem* el : seg.elist()) {
2351 60 : if (!el) {
2352 45 : continue;
2353 : }
2354 :
2355 15 : KeySig* ks = toKeySig(el);
2356 :
2357 15 : TLayout::layoutKeySig(ks, ks->mutldata(), ctx.conf());
2358 : }
2359 : }
2360 : }
|