Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "measurebase.h"
24 :
25 : #include "../editing/editpagelocks.h"
26 : #include "../editing/editsystemlocks.h"
27 :
28 : #include "actionicon.h"
29 : #include "box.h"
30 : #include "factory.h"
31 : #include "layoutbreak.h"
32 : #include "measure.h"
33 : #include "page.h"
34 : #include "score.h"
35 : #include "staff.h"
36 : #include "stafftypechange.h"
37 : #include "system.h"
38 :
39 : #include "log.h"
40 :
41 : using namespace mu;
42 : using namespace mu::engraving;
43 :
44 : //---------------------------------------------------------
45 : // MeasureBase
46 : //---------------------------------------------------------
47 :
48 18589 : MeasureBase::MeasureBase(const ElementType& type, Score* parent)
49 18589 : : EngravingItem(type, parent)
50 : {
51 18589 : }
52 :
53 0 : void MeasureBase::setOwnershipParent(Score* score)
54 : {
55 0 : EngravingItem::setOwnershipParent(score);
56 0 : }
57 :
58 1 : void MeasureBase::setOwnershipParent(Box* box)
59 : {
60 1 : EngravingItem::setOwnershipParent(box);
61 1 : }
62 :
63 917118 : EngravingItem* MeasureBase::layoutParent() const
64 : {
65 917118 : if (m_system) {
66 915565 : return m_system;
67 : }
68 : // e.g. a horizontal frame nested inside a vertical frame is placed within its parent frame
69 1553 : return EngravingItem::layoutParent();
70 : }
71 :
72 0 : MeasureBase::MeasureBase(const MeasureBase& m)
73 0 : : EngravingItem(m)
74 : {
75 0 : m_next = m.m_next;
76 0 : m_prev = m.m_prev;
77 0 : m_tick = m.m_tick;
78 :
79 0 : for (EngravingItem* e : m.m_el) {
80 0 : add(e->clone());
81 : }
82 0 : }
83 :
84 : //---------------------------------------------------------
85 : // clearElements
86 : //---------------------------------------------------------
87 :
88 0 : void MeasureBase::clearElements()
89 : {
90 0 : muse::DeleteAll(m_el);
91 0 : m_el.clear();
92 0 : }
93 :
94 : //---------------------------------------------------------
95 : // takeElements
96 : //---------------------------------------------------------
97 :
98 0 : ElementList MeasureBase::takeElements()
99 : {
100 0 : ElementList l;
101 0 : l.swap(m_el);
102 0 : return l;
103 : }
104 :
105 : //---------------------------------------------------------
106 : // setScore
107 : //---------------------------------------------------------
108 :
109 0 : void MeasureBase::setScore(Score* score)
110 : {
111 0 : EngravingItem::setScore(score);
112 0 : for (EngravingItem* e : m_el) {
113 0 : e->setScore(score);
114 : }
115 0 : }
116 :
117 : //---------------------------------------------------------
118 : // MeasureBase
119 : //---------------------------------------------------------
120 :
121 17307 : MeasureBase::~MeasureBase()
122 : {
123 17307 : muse::DeleteAll(m_el);
124 17307 : }
125 :
126 1 : System* MeasureBase::prevNonVBoxSystem() const
127 : {
128 1 : const System* currSystem = system();
129 1 : const MeasureBase* firstInCurrSystem = currSystem ? currSystem->first() : nullptr;
130 1 : IF_ASSERT_FAILED(firstInCurrSystem) {
131 0 : return nullptr;
132 : }
133 :
134 : // TODO: This logic is coupled to moveMeasureToPrevSystem - it should be possible to
135 : // move a MeasureBase from below a VBox (or n VBoxes) to above. Once that's achieved,
136 : // we can remove lastIsValid and simply iterate until we find a "non VBox system"...
137 1 : const MeasureBase* lastInPrevSystem = firstInCurrSystem->prevMM();
138 1 : const bool lastIsValid = lastInPrevSystem && !lastInPrevSystem->isVBoxBase();
139 :
140 1 : return lastIsValid ? lastInPrevSystem->system() : nullptr;
141 : }
142 :
143 1 : System* MeasureBase::nextNonVBoxSystem() const
144 : {
145 1 : const System* currSystem = system();
146 1 : const MeasureBase* lastInCurrSystem = currSystem ? currSystem->last() : nullptr;
147 1 : IF_ASSERT_FAILED(lastInCurrSystem) {
148 0 : return nullptr;
149 : }
150 :
151 : // TODO: This logic is coupled to moveMeasureToNextSystem - it should be possible to
152 : // move a MeasureBase from above a VBox (or n VBoxes) to below. Once that's achieved,
153 : // we can remove firstIsValid and simply iterate until we find a "non VBox system"...
154 1 : const MeasureBase* firstInNextSystem = lastInCurrSystem->nextMM();
155 1 : const bool firstIsValid = firstInNextSystem && !firstInNextSystem->isVBoxBase();
156 :
157 1 : return firstIsValid ? firstInNextSystem->system() : nullptr;
158 : }
159 :
160 8 : Page* MeasureBase::page() const
161 : {
162 8 : return system() ? system()->page() : nullptr;
163 : }
164 :
165 1 : Page* MeasureBase::prevPage() const
166 : {
167 1 : Page* curPage = page();
168 1 : IF_ASSERT_FAILED(curPage) {
169 0 : return nullptr;
170 : }
171 :
172 1 : Page* prevPage = curPage;
173 4 : for (const MeasureBase* mb = this; mb && prevPage == curPage; mb = mb->prevMM()) {
174 3 : prevPage = mb->system()->page();
175 : }
176 :
177 1 : return prevPage != curPage ? prevPage : nullptr;
178 : }
179 :
180 1 : Page* MeasureBase::nextPage() const
181 : {
182 1 : Page* curPage = page();
183 1 : IF_ASSERT_FAILED(curPage) {
184 0 : return nullptr;
185 : }
186 :
187 1 : Page* nextPage = curPage;
188 6 : for (const MeasureBase* mb = this; mb && nextPage == curPage; mb = mb->nextMM()) {
189 5 : nextPage = mb->system()->page();
190 : }
191 :
192 1 : return nextPage != curPage ? nextPage : nullptr;
193 : }
194 :
195 0 : bool MeasureBase::acceptDrop(EditData& data) const
196 : {
197 0 : const EngravingItem* e = data.dropElement;
198 0 : if (!e || !system() || !page()) {
199 0 : return false;
200 : }
201 :
202 0 : if (e->isLayoutBreak()) {
203 0 : return true;
204 : }
205 :
206 0 : if (e->isActionIcon()) {
207 0 : switch (toActionIcon(e)->actionType()) {
208 0 : case ActionIconType::PAGE_LOCK:
209 : {
210 0 : LayoutMode layoutMode = score()->layoutMode();
211 0 : return layoutMode == LayoutMode::PAGE;
212 : }
213 0 : case ActionIconType::SYSTEM_LOCK:
214 : {
215 0 : LayoutMode layoutMode = score()->layoutMode();
216 0 : return layoutMode == LayoutMode::PAGE || layoutMode == LayoutMode::SYSTEM;
217 : }
218 0 : default: break;
219 : }
220 : }
221 0 : return false;
222 : }
223 :
224 0 : EngravingItem* MeasureBase::drop(Transaction& tx, EditData& data)
225 : {
226 0 : EngravingItem* e = data.dropElement;
227 0 : if (!e || !system() || !page()) {
228 0 : delete e;
229 0 : return nullptr;
230 : }
231 0 : if (e->isLayoutBreak()) {
232 0 : LayoutBreak* b = toLayoutBreak(e);
233 0 : MeasureBase* mb = this;
234 0 : if (isMeasure()) {
235 0 : Measure* m = toMeasure(this);
236 0 : if (m->isMMRest()) {
237 0 : mb = m->mmRestLast();
238 : }
239 : }
240 0 : switch (b->layoutBreakType()) {
241 0 : case LayoutBreakType::PAGE:
242 0 : if (mb->pageBreak()) {
243 0 : delete b;
244 0 : b = nullptr;
245 : } else {
246 0 : mb->setLineBreak(false);
247 : }
248 0 : break;
249 0 : case LayoutBreakType::LINE:
250 0 : if (mb->lineBreak()) {
251 0 : delete b;
252 0 : b = nullptr;
253 : } else {
254 0 : mb->setPageBreak(false);
255 : }
256 0 : break;
257 0 : case LayoutBreakType::SECTION:
258 0 : if (mb->sectionBreak()) {
259 0 : delete b;
260 0 : b = nullptr;
261 : } else {
262 0 : mb->setLineBreak(false);
263 : }
264 0 : break;
265 0 : case LayoutBreakType::NOBREAK:
266 0 : if (mb->noBreak() || mb->isEndOfSystemLock() || mb->isEndOfPageLock()) {
267 0 : delete b;
268 0 : b = nullptr;
269 : } else {
270 0 : mb->setLineBreak(false);
271 0 : mb->setPageBreak(false);
272 : }
273 0 : break;
274 : }
275 0 : if (b) {
276 0 : if (b->layoutBreakType() != LayoutBreakType::NOBREAK) {
277 0 : EditSystemLocks::removeSystemLocksOnAddLayoutBreak(tx, score(), b->layoutBreakType(), this);
278 : }
279 0 : b->setTrack(0);
280 0 : b->setOwnershipParent(mb);
281 0 : score()->undoAddElement(b);
282 : }
283 0 : mb->cleanupLayoutBreaks(true);
284 0 : return b;
285 : }
286 0 : if (e->isActionIcon()) {
287 0 : switch (toActionIcon(e)->actionType()) {
288 0 : case ActionIconType::SYSTEM_LOCK:
289 0 : EditSystemLocks::makeIntoSystem(tx, score(), system()->first(), this);
290 0 : break;
291 0 : case ActionIconType::PAGE_LOCK:
292 0 : EditPageLocks::makeIntoPage(tx, score(), page()->firstMeasureBase(), this);
293 0 : break;
294 0 : default:
295 0 : LOGD("MeasureBase: cannot drop %s here", e->typeName());
296 0 : break;
297 : }
298 : }
299 0 : delete e;
300 0 : return nullptr;
301 : }
302 :
303 : //---------------------------------------------------------
304 : // add
305 : /// Add new EngravingItem \a el to MeasureBase
306 : //---------------------------------------------------------
307 :
308 3316 : void MeasureBase::add(EngravingItem* e)
309 : {
310 3316 : if (e->ownershipParent() != this) {
311 53 : e->setOwnershipParent(this);
312 : }
313 :
314 3316 : if (e->isLayoutBreak()) {
315 959 : LayoutBreak* b = toLayoutBreak(e);
316 959 : switch (b->layoutBreakType()) {
317 20 : case LayoutBreakType::PAGE:
318 20 : setPageBreak(true);
319 20 : setLineBreak(false);
320 20 : setNoBreak(false);
321 20 : break;
322 857 : case LayoutBreakType::LINE:
323 857 : setPageBreak(false);
324 857 : setLineBreak(true);
325 857 : setSectionBreak(false);
326 857 : setNoBreak(false);
327 857 : break;
328 33 : case LayoutBreakType::SECTION:
329 33 : setLineBreak(false);
330 33 : setSectionBreak(true);
331 33 : setNoBreak(false);
332 33 : if (b->startWithMeasureOne()) {
333 33 : triggerLayoutToEnd();
334 : }
335 33 : break;
336 49 : case LayoutBreakType:: NOBREAK:
337 49 : setPageBreak(false);
338 49 : setLineBreak(false);
339 49 : setSectionBreak(false);
340 49 : setNoBreak(true);
341 49 : break;
342 : }
343 959 : if (next()) {
344 158 : next()->triggerLayout();
345 : }
346 : }
347 3316 : triggerLayout();
348 3316 : m_el.push_back(e);
349 3316 : e->added();
350 3316 : }
351 :
352 : //---------------------------------------------------------
353 : // remove
354 : /// Remove EngravingItem \a el from MeasureBase.
355 : //---------------------------------------------------------
356 :
357 29 : void MeasureBase::remove(EngravingItem* el)
358 : {
359 29 : if (el->isLayoutBreak()) {
360 29 : LayoutBreak* lb = toLayoutBreak(el);
361 29 : switch (lb->layoutBreakType()) {
362 2 : case LayoutBreakType::PAGE:
363 2 : setPageBreak(false);
364 2 : break;
365 17 : case LayoutBreakType::LINE:
366 17 : setLineBreak(false);
367 17 : break;
368 0 : case LayoutBreakType::SECTION:
369 0 : setSectionBreak(false);
370 0 : if (lb->startWithMeasureOne()) {
371 0 : triggerLayoutToEnd();
372 : }
373 0 : break;
374 10 : case LayoutBreakType::NOBREAK:
375 10 : setNoBreak(false);
376 10 : break;
377 : }
378 : }
379 :
380 29 : if (!m_el.remove(el)) {
381 0 : LOGD("MeasureBase(%p)::remove(%s,%p) not found", this, el->typeName(), el);
382 : } else {
383 29 : el->removed();
384 : }
385 :
386 29 : triggerLayout();
387 29 : if (next()) {
388 28 : next()->triggerLayout();
389 : }
390 29 : }
391 :
392 : //---------------------------------------------------------
393 : // nextMeasure
394 : //---------------------------------------------------------
395 :
396 557797 : Measure* MeasureBase::nextMeasure() const
397 : {
398 557797 : MeasureBase* m = m_next;
399 : for (;;) {
400 560714 : if (m == 0 || m->isMeasure()) {
401 557797 : break;
402 : }
403 2917 : m = m->m_next;
404 : }
405 557797 : return toMeasure(m);
406 : }
407 :
408 : //---------------------------------------------------------
409 : // nextMeasureMM
410 : //---------------------------------------------------------
411 :
412 146742 : Measure* MeasureBase::nextMeasureMM() const
413 : {
414 146742 : Measure* mm = nextMeasure();
415 146742 : if (mm && style().styleB(Sid::createMultiMeasureRests) && mm->hasMMRest()) {
416 392 : return mm->mmRest();
417 : }
418 146350 : return mm;
419 : }
420 :
421 : //---------------------------------------------------------
422 : // prevMeasure
423 : //---------------------------------------------------------
424 :
425 695831 : Measure* MeasureBase::prevMeasure() const
426 : {
427 695831 : MeasureBase* m = prev();
428 778678 : while (m) {
429 645995 : if (m->isMeasure()) {
430 563148 : return toMeasure(m);
431 : }
432 82847 : m = m->prev();
433 : }
434 132683 : return nullptr;
435 : }
436 :
437 : //---------------------------------------------------------
438 : // prevMeasureMM
439 : //---------------------------------------------------------
440 :
441 320972 : Measure* MeasureBase::prevMeasureMM() const
442 : {
443 320972 : Measure* m = prevMeasure();
444 320972 : if (m) {
445 273277 : return m->coveringMMRestOrThis();
446 : }
447 :
448 47695 : return nullptr;
449 : }
450 :
451 8858 : const MeasureBase* MeasureBase::mbWithPrecedingSectionBreak() const
452 : {
453 : // we're trying to find the MeasureBase that determines
454 : // if the next one after this starts a new section
455 : // if this is a measure, it's the one that determines this
456 : // but if it is a frame, we may need to look backwards
457 8858 : const MeasureBase* mb = this;
458 11701 : while (mb && !mb->isMeasure() && !mb->sectionBreak()) {
459 2843 : mb = mb->prev();
460 : }
461 8858 : return mb;
462 : }
463 :
464 : //---------------------------------------------------------
465 : // pause
466 : //---------------------------------------------------------
467 :
468 813 : double MeasureBase::pause() const
469 : {
470 813 : const LayoutBreak* layoutBreak = sectionBreakElement();
471 813 : return layoutBreak ? layoutBreak->pause() : 0.0;
472 : }
473 :
474 : //---------------------------------------------------------
475 : // top
476 : //---------------------------------------------------------
477 :
478 17106640 : MeasureBase* MeasureBase::top() const
479 : {
480 17106640 : const MeasureBase* mb = this;
481 17106640 : while (mb->ownershipParent()) {
482 17106640 : if (mb->ownershipParent()->isMeasureBase()) {
483 0 : mb = toMeasureBase(mb->ownershipParent());
484 : } else {
485 17106640 : break;
486 : }
487 : }
488 17106640 : return const_cast<MeasureBase*>(mb);
489 : }
490 :
491 : //---------------------------------------------------------
492 : // getInScore
493 : //---------------------------------------------------------
494 :
495 19 : MeasureBase* MeasureBase::getInScore(Score* score, bool useNextMeasureFallback) const
496 : {
497 19 : MeasureBase* newMB = nullptr;
498 19 : if (!isMeasure() && !excludeFromOtherParts()) {
499 0 : for (auto e : linkList()) {
500 0 : if (e->score() == score) {
501 0 : newMB = toMeasureBase(e);
502 0 : break;
503 : }
504 0 : }
505 : }
506 19 : if (isMeasure() || (!newMB && useNextMeasureFallback)) {
507 19 : newMB = score->tick2measure(tick());
508 : }
509 19 : if (!newMB) {
510 0 : LOGD("measure base not found in score");
511 : }
512 19 : return newMB;
513 : }
514 :
515 : //---------------------------------------------------------
516 : // tick
517 : //---------------------------------------------------------
518 :
519 17096791 : Fraction MeasureBase::tick() const
520 : {
521 17096791 : const MeasureBase* mb = top();
522 17096791 : return mb ? mb->m_tick : Fraction(-1, 1);
523 : }
524 :
525 22192 : void MeasureBase::setTick(const Fraction& f)
526 : {
527 22192 : m_tick = f;
528 22192 : }
529 :
530 : //---------------------------------------------------------
531 : // triggerLayout
532 : //---------------------------------------------------------
533 :
534 9788 : void MeasureBase::triggerLayout() const
535 : {
536 : // for measurebases within other measurebases (e.g., hbox within vbox), use top level
537 9788 : const MeasureBase* mb = top();
538 : // avoid triggering layout before getting added to a score
539 9788 : if (mb->prev() || mb->next()) {
540 444 : score()->setLayout(mb->tick(), muse::nidx, mb);
541 : }
542 9788 : }
543 :
544 : //---------------------------------------------------------
545 : // scanElements
546 : //---------------------------------------------------------
547 :
548 3382 : void MeasureBase::scanElements(std::function<void(EngravingItem*)> func)
549 : {
550 3382 : if (isMeasure()) {
551 3391 : for (EngravingItem* e : m_el) {
552 142 : staff_idx_t staffIdx = e->staffIdx();
553 142 : if (staffIdx != muse::nidx && staffIdx >= score()->staves().size()) {
554 0 : LOGD("MeasureBase::scanElements: bad staffIdx %zu in element %s", staffIdx, e->typeName());
555 : }
556 142 : if ((e->track() == muse::nidx) || e->systemFlag() || toMeasure(this)->visible(staffIdx)) {
557 142 : e->scanElements(func);
558 : }
559 : }
560 : } else {
561 377 : for (EngravingItem* e : m_el) {
562 244 : e->scanElements(func);
563 : }
564 : }
565 3382 : if (isBox()) {
566 133 : func(this);
567 : }
568 3382 : }
569 :
570 : //---------------------------------------------------------
571 : // first
572 : //---------------------------------------------------------
573 :
574 28510 : MeasureBase* Score::first() const
575 : {
576 28510 : return m_measures.first();
577 : }
578 :
579 : //---------------------------------------------------------
580 : // last
581 : //---------------------------------------------------------
582 :
583 9421 : MeasureBase* Score::last() const
584 : {
585 9421 : return m_measures.last();
586 : }
587 :
588 : //---------------------------------------------------------
589 : // undoSetBreak
590 : //---------------------------------------------------------
591 :
592 504 : void MeasureBase::undoSetBreak(bool v, LayoutBreakType type)
593 : {
594 504 : switch (type) {
595 142 : case LayoutBreakType::LINE:
596 142 : if (lineBreak() == v) {
597 142 : return;
598 : }
599 0 : setLineBreak(v);
600 0 : break;
601 208 : case LayoutBreakType::PAGE:
602 208 : if (pageBreak() == v) {
603 208 : return;
604 : }
605 0 : if (v && lineBreak()) {
606 0 : setLineBreak(false);
607 : }
608 0 : setPageBreak(v);
609 0 : break;
610 114 : case LayoutBreakType::SECTION:
611 114 : if (sectionBreak() == v) {
612 114 : return;
613 : }
614 0 : if (v && lineBreak()) {
615 0 : setLineBreak(false);
616 : }
617 0 : setSectionBreak(v);
618 0 : break;
619 40 : case LayoutBreakType::NOBREAK:
620 40 : if (noBreak() == v) {
621 28 : return;
622 : }
623 12 : if (v) {
624 9 : setLineBreak(false);
625 9 : setPageBreak(false);
626 9 : setSectionBreak(false);
627 : }
628 12 : setNoBreak(v);
629 12 : break;
630 : }
631 :
632 12 : if (v) {
633 9 : MeasureBase* mb = (isMeasure() && toMeasure(this)->isMMRest()) ? toMeasure(this)->mmRestLast() : this;
634 9 : LayoutBreak* lb = Factory::createLayoutBreak(mb);
635 9 : lb->setLayoutBreakType(type);
636 9 : lb->setTrack(0);
637 9 : score()->undoAddElement(lb);
638 : }
639 12 : cleanupLayoutBreaks(true);
640 : }
641 :
642 : //---------------------------------------------------------
643 : // cleanupLayoutBreaks
644 : //---------------------------------------------------------
645 :
646 726 : void MeasureBase::cleanupLayoutBreaks(bool undo)
647 : {
648 : // remove unneeded layout breaks
649 726 : std::vector<EngravingItem*> toDelete;
650 1474 : for (EngravingItem* e : el()) {
651 748 : if (e->isLayoutBreak()) {
652 726 : switch (toLayoutBreak(e)->layoutBreakType()) {
653 631 : case LayoutBreakType::LINE:
654 631 : if (!lineBreak()) {
655 0 : toDelete.push_back(e);
656 : }
657 631 : break;
658 15 : case LayoutBreakType::PAGE:
659 15 : if (!pageBreak()) {
660 0 : toDelete.push_back(e);
661 : }
662 15 : break;
663 33 : case LayoutBreakType::SECTION:
664 33 : if (!sectionBreak()) {
665 0 : toDelete.push_back(e);
666 : }
667 33 : break;
668 47 : case LayoutBreakType::NOBREAK:
669 47 : if (!noBreak()) {
670 3 : toDelete.push_back(e);
671 : }
672 47 : break;
673 : }
674 : }
675 : }
676 729 : for (EngravingItem* e : toDelete) {
677 3 : if (undo) {
678 3 : score()->undoRemoveElement(e);
679 : } else {
680 0 : m_el.remove(e);
681 : }
682 : }
683 726 : }
684 :
685 : //---------------------------------------------------------
686 : // nextMM
687 : //---------------------------------------------------------
688 :
689 83974 : MeasureBase* MeasureBase::nextMM() const
690 : {
691 167948 : if (m_next
692 72405 : && m_next->isMeasure()
693 71829 : && style().styleB(Sid::createMultiMeasureRests)
694 156379 : && toMeasure(m_next)->hasMMRest()) {
695 306 : return toMeasure(m_next)->mmRest();
696 : }
697 83668 : return m_next;
698 : }
699 :
700 : //---------------------------------------------------------
701 : // prevMM
702 : //---------------------------------------------------------
703 :
704 6692 : MeasureBase* MeasureBase::prevMM() const
705 : {
706 13384 : if (m_prev
707 6692 : && m_prev->isMeasure()
708 13384 : && style().styleB(Sid::createMultiMeasureRests)) {
709 114 : return const_cast<Measure*>(toMeasure(m_prev)->coveringMMRestOrThis());
710 : }
711 6578 : return m_prev;
712 : }
713 :
714 : //---------------------------------------------------------
715 : // index
716 : //---------------------------------------------------------
717 :
718 10051 : int MeasureBase::index() const
719 : {
720 10051 : int idx = 0;
721 10051 : MeasureBase* m = score()->first();
722 10051 : Measure* mmRestFirst = nullptr;
723 10051 : if (isMeasure() && toMeasure(this)->isMMRest()) {
724 0 : mmRestFirst = toMeasure(this)->mmRestFirst();
725 : }
726 186907 : while (m) {
727 186907 : if (m == this || m == mmRestFirst) {
728 10051 : return idx;
729 : }
730 176856 : m = m->next();
731 176856 : ++idx;
732 : }
733 0 : return -1;
734 : }
735 :
736 : //---------------------------------------------------------
737 : // measureIndex
738 : // returns index of measure counting only Measures but
739 : // skipping other MeasureBase descendants
740 : //---------------------------------------------------------
741 :
742 28 : int MeasureBase::measureIndex() const
743 : {
744 28 : int idx = 0;
745 28 : MeasureBase* m = score()->firstMeasure();
746 28 : Measure* mmRestFirst = nullptr;
747 28 : if (isMeasure() && toMeasure(this)->isMMRest()) {
748 0 : mmRestFirst = toMeasure(this)->mmRestFirst();
749 : }
750 109 : while (m) {
751 109 : if (m == this || m == mmRestFirst) {
752 28 : return idx;
753 : }
754 81 : m = m->next();
755 81 : if (m && m->isMeasure()) {
756 81 : ++idx;
757 : }
758 : }
759 0 : return -1;
760 : }
761 :
762 0 : bool MeasureBase::isBefore(const EngravingItem* other) const
763 : {
764 0 : if (other->isMeasureBase()) {
765 0 : const MeasureBase* otherMb = toMeasureBase(other);
766 0 : return isBefore(otherMb);
767 : }
768 :
769 0 : return EngravingItem::isBefore(other);
770 : }
771 :
772 13704 : bool MeasureBase::isBefore(const MeasureBase* other) const
773 : {
774 13704 : if (this == other) {
775 2313 : return false;
776 : }
777 :
778 11391 : Fraction otherTick = other->tick();
779 11391 : if (otherTick != m_tick) {
780 11258 : return m_tick < otherTick;
781 : }
782 :
783 133 : if (this->isMeasure() && other->isMeasure()) {
784 : // (this == other) has already been excluded, so this is only
785 : // possible if one is the overlying mmRest starting on the other.
786 : // Let's set by convention that the mmRest isBefore the underlying measure.
787 1 : return toMeasure(this)->isMMRest();
788 : }
789 :
790 132 : bool otherIsMMRest = other->isMeasure() && toMeasure(other)->isMMRest();
791 182 : for (const MeasureBase* mb = otherIsMMRest ? nextMM() : next(); mb && mb->tick() == m_tick;
792 25 : mb = otherIsMMRest ? mb->nextMM() : mb->next()) {
793 141 : if (mb == other) {
794 116 : return true;
795 : }
796 : }
797 :
798 16 : return false;
799 : }
800 :
801 39099 : const RangeLock* MeasureBase::systemLock() const
802 : {
803 39099 : return score()->systemLocks()->lockContaining(this);
804 : }
805 :
806 25073 : bool MeasureBase::isStartOfSystemLock() const
807 : {
808 25073 : const RangeLock* lock = score()->systemLocks()->lockStartingAt(this);
809 25073 : return lock != nullptr;
810 : }
811 :
812 28872 : bool MeasureBase::isEndOfSystemLock() const
813 : {
814 28872 : const RangeLock* lock = systemLock();
815 28872 : return lock && lock->endMB() == this;
816 : }
817 :
818 49197 : const RangeLock* MeasureBase::pageLock() const
819 : {
820 49197 : return score()->pageLocks()->lockContaining(this);
821 : }
822 :
823 31260 : bool MeasureBase::isStartOfPageLock() const
824 : {
825 31260 : const RangeLock* lock = score()->pageLocks()->lockStartingAt(this);
826 31260 : return lock != nullptr;
827 : }
828 :
829 38985 : bool MeasureBase::isEndOfPageLock() const
830 : {
831 38985 : const RangeLock* lock = pageLock();
832 38985 : return lock && lock->endMB() == this;
833 : }
834 :
835 : //---------------------------------------------------------
836 : // sectionBreakElement
837 : //---------------------------------------------------------
838 :
839 203447 : LayoutBreak* MeasureBase::sectionBreakElement() const
840 : {
841 203447 : if (sectionBreak()) {
842 519 : for (EngravingItem* e : el()) {
843 519 : if (e->isLayoutBreak() && toLayoutBreak(e)->isSectionBreak()) {
844 497 : return toLayoutBreak(e);
845 : }
846 : }
847 : }
848 :
849 202950 : return nullptr;
850 : }
851 :
852 : //---------------------------------------------------------
853 : // MeasureBaseList
854 : //---------------------------------------------------------
855 :
856 2334 : MeasureBaseList::MeasureBaseList()
857 : {
858 2334 : m_first = nullptr;
859 2334 : m_last = nullptr;
860 2334 : m_size = 0;
861 2334 : }
862 :
863 0 : void MeasureBaseList::clear()
864 : {
865 0 : m_first = nullptr;
866 0 : m_last = nullptr;
867 0 : m_size = 0;
868 0 : m_tickIndex.clear();
869 0 : }
870 :
871 : //---------------------------------------------------------
872 : // push_back
873 : //---------------------------------------------------------
874 :
875 18047 : void MeasureBaseList::push_back(MeasureBase* m)
876 : {
877 18047 : ++m_size;
878 18047 : if (m_last) {
879 15838 : m_last->setNext(m);
880 15838 : m->setPrev(m_last);
881 15838 : m->setNext(0);
882 : } else {
883 2209 : m_first = m;
884 2209 : m->setPrev(0);
885 2209 : m->setNext(0);
886 : }
887 18047 : m_last = m;
888 18047 : }
889 :
890 : //---------------------------------------------------------
891 : // push_front
892 : //---------------------------------------------------------
893 :
894 18 : void MeasureBaseList::push_front(MeasureBase* m)
895 : {
896 18 : ++m_size;
897 18 : if (m_first) {
898 18 : m_first->setPrev(m);
899 18 : m->setNext(m_first);
900 18 : m->setPrev(0);
901 : } else {
902 0 : m_last = m;
903 0 : m->setPrev(0);
904 0 : m->setNext(0);
905 : }
906 18 : m_first = m;
907 18 : }
908 :
909 : //---------------------------------------------------------
910 : // add
911 : // insert m before m->next()
912 : //---------------------------------------------------------
913 :
914 249 : void MeasureBaseList::add(MeasureBase* m)
915 : {
916 249 : MeasureBase* el = m->next();
917 249 : if (el == 0) {
918 231 : append(m);
919 231 : return;
920 : }
921 18 : if (el == m_first) {
922 18 : push_front(m);
923 18 : return;
924 : }
925 0 : ++m_size;
926 0 : m->setPrev(el->prev());
927 0 : el->prev()->setNext(m);
928 0 : el->setPrev(m);
929 : }
930 :
931 : //---------------------------------------------------------
932 : // remove
933 : //---------------------------------------------------------
934 :
935 4 : void MeasureBaseList::remove(MeasureBase* m)
936 : {
937 4 : --m_size;
938 4 : if (m->prev()) {
939 1 : m->prev()->setNext(m->next());
940 : } else {
941 3 : m_first = m->next();
942 : }
943 4 : if (m->next()) {
944 4 : m->next()->setPrev(m->prev());
945 : } else {
946 0 : m_last = m->prev();
947 : }
948 4 : }
949 :
950 : //---------------------------------------------------------
951 : // insert
952 : //---------------------------------------------------------
953 :
954 382 : void MeasureBaseList::insert(MeasureBase* fm, MeasureBase* lm)
955 : {
956 447 : for (MeasureBase* m = fm; m != lm; m = m->next()) {
957 65 : ++m_size;
958 : }
959 382 : ++m_size;
960 382 : MeasureBase* pm = fm->prev();
961 382 : if (pm) {
962 325 : pm->setNext(fm);
963 : } else {
964 57 : m_first = fm;
965 : }
966 382 : MeasureBase* nm = lm->next();
967 382 : if (nm) {
968 136 : nm->setPrev(lm);
969 : } else {
970 246 : m_last = lm;
971 : }
972 382 : }
973 :
974 : //---------------------------------------------------------
975 : // remove
976 : //---------------------------------------------------------
977 :
978 80 : void MeasureBaseList::remove(MeasureBase* fm, MeasureBase* lm)
979 : {
980 139 : for (MeasureBase* m = fm; m != lm; m = m->next()) {
981 59 : --m_size;
982 : }
983 80 : --m_size;
984 80 : MeasureBase* pm = fm->prev();
985 80 : MeasureBase* nm = lm->next();
986 80 : if (pm) {
987 61 : pm->setNext(nm);
988 : } else {
989 19 : m_first = nm;
990 : }
991 80 : if (nm) {
992 52 : nm->setPrev(pm);
993 : } else {
994 28 : m_last = pm;
995 : }
996 80 : }
997 :
998 : //---------------------------------------------------------
999 : // change
1000 : //---------------------------------------------------------
1001 :
1002 0 : void MeasureBaseList::change(MeasureBase* ob, MeasureBase* nb)
1003 : {
1004 0 : nb->setPrev(ob->prev());
1005 0 : nb->setNext(ob->next());
1006 0 : if (ob->prev()) {
1007 0 : ob->prev()->setNext(nb);
1008 : }
1009 0 : if (ob->next()) {
1010 0 : ob->next()->setPrev(nb);
1011 : }
1012 0 : if (ob == m_last) {
1013 0 : m_last = nb;
1014 : }
1015 0 : if (ob == m_first) {
1016 0 : m_first = nb;
1017 : }
1018 0 : if (nb->isBox()) {
1019 0 : nb->setSystem(ob->system());
1020 : }
1021 0 : for (EngravingItem* e : nb->el()) {
1022 0 : e->setOwnershipParent(nb);
1023 : }
1024 0 : }
1025 :
1026 : //---------------------------------------------------------
1027 : // append
1028 : // append measure to the end of the list and update
1029 : // tick index
1030 : //---------------------------------------------------------
1031 :
1032 18047 : void MeasureBaseList::append(MeasureBase* m)
1033 : {
1034 18047 : assert(!m->next());
1035 18047 : assert(!m->prev() || m->prev() == m_last);
1036 :
1037 18047 : push_back(m);
1038 18047 : m_tickIndex.emplace(std::make_pair(m->tick().ticks(), m));
1039 18047 : }
1040 :
1041 129979 : Measure* MeasureBaseList::measureByTick(int tick) const
1042 : {
1043 129979 : if (empty() || tick > m_last->endTick().ticks()) {
1044 888 : return nullptr;
1045 : }
1046 :
1047 129091 : auto it = m_tickIndex.upper_bound(tick);
1048 :
1049 129091 : if (it == m_tickIndex.begin()) {
1050 1 : MeasureBase* mb = it->second;
1051 :
1052 1 : if (mb->isMeasure()) {
1053 0 : return toMeasure(mb);
1054 : }
1055 1 : return nullptr;
1056 : }
1057 :
1058 129090 : --it;
1059 0 : for (;; --it) {
1060 129090 : if (it == m_tickIndex.begin()) {
1061 18677 : MeasureBase* mb = it->second;
1062 :
1063 18677 : if (mb->isMeasure()) {
1064 18649 : return toMeasure(mb);
1065 : }
1066 28 : return nullptr;
1067 : }
1068 :
1069 110413 : MeasureBase* mb = it->second;
1070 110413 : if (!mb) {
1071 0 : break;
1072 : }
1073 :
1074 110413 : if (mb->isMeasure()) {
1075 110413 : return toMeasure(mb);
1076 : }
1077 0 : }
1078 :
1079 0 : return nullptr;
1080 : }
1081 :
1082 10 : MeasureBase* MeasureBaseList::firstMeasureBaseAtTick(int tick) const
1083 : {
1084 10 : if (empty() || tick > m_last->endTick().ticks()) {
1085 0 : return nullptr;
1086 : }
1087 :
1088 10 : auto it = m_tickIndex.upper_bound(tick);
1089 :
1090 10 : if (it != m_tickIndex.begin()) {
1091 10 : --it;
1092 : }
1093 10 : return it->second;
1094 : }
1095 :
1096 0 : std::vector<MeasureBase*> MeasureBaseList::measureBasesAtTick(int tick) const
1097 : {
1098 0 : std::vector<MeasureBase*> result;
1099 0 : if (empty() || tick > m_last->endTick().ticks()) {
1100 0 : return result;
1101 : }
1102 :
1103 0 : result = muse::values(m_tickIndex, tick);
1104 :
1105 0 : return result;
1106 0 : }
1107 :
1108 2340 : void MeasureBaseList::updateTickIndex()
1109 : {
1110 2340 : m_tickIndex.clear();
1111 :
1112 21426 : for (MeasureBase* mb = m_first; mb; mb = mb->next()) {
1113 19086 : m_tickIndex.emplace(std::make_pair(mb->tick().ticks(), mb));
1114 : }
1115 2340 : }
|