1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2002-2011 Werner Schweer
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENCE.GPL
11 //=============================================================================
12
13 #include "measurebase.h"
14 #include "measure.h"
15 #include "staff.h"
16 #include "score.h"
17 #include "chord.h"
18 #include "note.h"
19 #include "layoutbreak.h"
20 #include "image.h"
21 #include "segment.h"
22 #include "tempo.h"
23 #include "xml.h"
24 #include "system.h"
25 #include "stafftypechange.h"
26
27 namespace Ms {
28
29 //---------------------------------------------------------
30 // MeasureBase
31 //---------------------------------------------------------
32
MeasureBase(Score * score)33 MeasureBase::MeasureBase(Score* score)
34 : Element(score)
35 {
36 setIrregular(true);
37 }
38
MeasureBase(const MeasureBase & m)39 MeasureBase::MeasureBase(const MeasureBase& m)
40 : Element(m)
41 {
42 _next = m._next;
43 _prev = m._prev;
44 _tick = m._tick;
45 _no = m._no;
46 _noOffset = m._noOffset;
47
48 for (Element* e : m._el)
49 add(e->clone());
50 }
51
52 //---------------------------------------------------------
53 // clearElements
54 //---------------------------------------------------------
55
clearElements()56 void MeasureBase::clearElements()
57 {
58 qDeleteAll(_el);
59 _el.clear();
60 }
61
62 //---------------------------------------------------------
63 // takeElements
64 //---------------------------------------------------------
65
takeElements()66 ElementList MeasureBase::takeElements()
67 {
68 ElementList l = _el;
69 _el.clear();
70 return l;
71 }
72
73 //---------------------------------------------------------
74 // setScore
75 //---------------------------------------------------------
76
setScore(Score * score)77 void MeasureBase::setScore(Score* score)
78 {
79 Element::setScore(score);
80 for (Element* e : _el)
81 e->setScore(score);
82 }
83
84 //---------------------------------------------------------
85 // MeasureBase
86 //---------------------------------------------------------
87
~MeasureBase()88 MeasureBase::~MeasureBase()
89 {
90 qDeleteAll(_el);
91 }
92
93 //---------------------------------------------------------
94 // scanElements
95 //---------------------------------------------------------
96
scanElements(void * data,void (* func)(void *,Element *),bool all)97 void MeasureBase::scanElements(void* data, void (*func)(void*, Element*), bool all)
98 {
99 if (isMeasure()) {
100 for (Element* e : _el) {
101 if (score()->tagIsValid(e->tag())) {
102 if (e->staffIdx() >= score()->staves().size())
103 qDebug("MeasureBase::scanElements: bad staffIdx %d in element %s", e->staffIdx(), e->name());
104 if ((e->track() == -1) || e->systemFlag() || ((Measure*)this)->visible(e->staffIdx()))
105 e->scanElements(data, func, all);
106 }
107 }
108 }
109 else {
110 for (Element* e : _el) {
111 if (score()->tagIsValid(e->tag()))
112 e->scanElements(data, func, all);
113 }
114 }
115 if (isBox())
116 func(data, this);
117 }
118
119 //---------------------------------------------------------
120 // add
121 /// Add new Element \a el to MeasureBase
122 //---------------------------------------------------------
123
add(Element * e)124 void MeasureBase::add(Element* e)
125 {
126 e->setParent(this);
127 if (e->isLayoutBreak()) {
128 LayoutBreak* b = toLayoutBreak(e);
129 switch (b->layoutBreakType()) {
130 case LayoutBreak::PAGE:
131 setPageBreak(true);
132 setLineBreak(false);
133 setNoBreak(false);
134 break;
135 case LayoutBreak::LINE:
136 setPageBreak(false);
137 setLineBreak(true);
138 setSectionBreak(false);
139 setNoBreak(false);
140 break;
141 case LayoutBreak::SECTION:
142 setLineBreak(false);
143 setSectionBreak(true);
144 setNoBreak(false);
145 //does not work with repeats: score()->tempomap()->setPause(endTick(), b->pause());
146 triggerLayoutAll();
147 break;
148 case LayoutBreak::NOBREAK:
149 setPageBreak(false);
150 setLineBreak(false);
151 setSectionBreak(false);
152 setNoBreak(true);
153 break;
154 }
155 if (next())
156 next()->triggerLayout();
157 // triggerLayoutAll(); // TODO
158 }
159 triggerLayout();
160 _el.push_back(e);
161 }
162
163 //---------------------------------------------------------
164 // remove
165 /// Remove Element \a el from MeasureBase.
166 //---------------------------------------------------------
167
remove(Element * el)168 void MeasureBase::remove(Element* el)
169 {
170 if (el->isLayoutBreak()) {
171 LayoutBreak* lb = toLayoutBreak(el);
172 switch (lb->layoutBreakType()) {
173 case LayoutBreak::PAGE:
174 setPageBreak(false);
175 break;
176 case LayoutBreak::LINE:
177 setLineBreak(false);
178 break;
179 case LayoutBreak::SECTION:
180 setSectionBreak(false);
181 score()->setPause(endTick(), 0);
182 triggerLayoutAll();
183 break;
184 case LayoutBreak::NOBREAK:
185 setNoBreak(false);
186 break;
187 }
188 }
189 if (!_el.remove(el)) {
190 qDebug("MeasureBase(%p)::remove(%s,%p) not found", this, el->name(), el);
191 }
192 }
193
194 //---------------------------------------------------------
195 // nextMeasure
196 //---------------------------------------------------------
197
nextMeasure() const198 Measure* MeasureBase::nextMeasure() const
199 {
200 MeasureBase* m = _next;
201 for (;;) {
202 if (m == 0 || m->isMeasure())
203 break;
204 m = m->_next;
205 }
206 return toMeasure(m);
207 }
208
209 //---------------------------------------------------------
210 // nextMeasureMM
211 //---------------------------------------------------------
212
nextMeasureMM() const213 Measure* MeasureBase::nextMeasureMM() const
214 {
215 Measure* mm = nextMeasure();
216 if (mm && score()->styleB(Sid::createMultiMeasureRests) && mm->hasMMRest())
217 return mm->mmRest();
218 return mm;
219 }
220
221 //---------------------------------------------------------
222 // prevMeasure
223 //---------------------------------------------------------
224
prevMeasure() const225 Measure* MeasureBase::prevMeasure() const
226 {
227 MeasureBase* m = prev();
228 while (m) {
229 if (m->isMeasure())
230 return toMeasure(m);
231 m = m->prev();
232 }
233 return 0;
234 }
235
236 //---------------------------------------------------------
237 // prevMeasure
238 //---------------------------------------------------------
239
prevMeasureMM() const240 Measure* MeasureBase::prevMeasureMM() const
241 {
242 MeasureBase* m = prev();
243 while (m) {
244 if (m->isMeasure()) {
245 Measure* mm = toMeasure(m);
246 if (score()->styleB(Sid::createMultiMeasureRests)) {
247 if (mm->mmRestCount() >= 0) {
248 if (mm->hasMMRest())
249 return mm->mmRest();
250 return mm;
251 }
252 }
253 else
254 return mm;
255 }
256 m = m->prev();
257 }
258 return 0;
259 }
260
261 //---------------------------------------------------------
262 // findPotentialSectionBreak
263 //---------------------------------------------------------
264
findPotentialSectionBreak() const265 const MeasureBase *MeasureBase::findPotentialSectionBreak() const
266 {
267 // we're trying to find the MeasureBase that determines
268 // if the next one after this starts a new section
269 // if this is a measure, it's the one that determines this
270 // but if it is a frame, we may need to look backwards
271 const MeasureBase* mb = this;
272 while (mb && !mb->isMeasure() && !mb->sectionBreak())
273 mb = mb->prev();
274 return mb;
275 }
276
277 //---------------------------------------------------------
278 // pause
279 //---------------------------------------------------------
280
pause() const281 qreal MeasureBase::pause() const
282 {
283 return sectionBreak() ? sectionBreakElement()->pause() : 0.0;
284 }
285
286 //---------------------------------------------------------
287 // layout
288 //---------------------------------------------------------
289
layout()290 void MeasureBase::layout()
291 {
292 int breakCount = 0;
293
294 for (Element* element : _el) {
295 if (!score()->tagIsValid(element->tag()))
296 continue;
297 if (element->isLayoutBreak()) {
298 qreal _spatium = spatium();
299 qreal x;
300 qreal y;
301 if (toLayoutBreak(element)->isNoBreak()) {
302 x = width() - element->width() * .5;
303 y = -(_spatium + element->height());
304 }
305 else {
306 x = -_spatium - element->width() + width()
307 - breakCount * (element->width() + _spatium * .8);
308 y = -2 * _spatium - element->height();
309 breakCount++;
310 }
311 element->setPos(x, y);
312 }
313 else if (element->isMarker() || element->isJump())
314 ;
315 else
316 element->layout();
317 }
318 }
319
320 //---------------------------------------------------------
321 // top
322 //---------------------------------------------------------
323
top() const324 MeasureBase* MeasureBase::top() const
325 {
326 const MeasureBase* mb = this;
327 while (mb->parent()) {
328 if (mb->parent()->isMeasureBase())
329 mb = toMeasureBase(mb->parent());
330 else
331 break;
332 }
333 return const_cast<MeasureBase*>(mb);
334 }
335
336 //---------------------------------------------------------
337 // tick
338 //---------------------------------------------------------
339
tick() const340 Fraction MeasureBase::tick() const
341 {
342 const MeasureBase* mb = top();
343 return mb ? mb->_tick : Fraction(-1, 1);
344 }
345
346 //---------------------------------------------------------
347 // triggerLayout
348 //---------------------------------------------------------
349
triggerLayout() const350 void MeasureBase::triggerLayout() const
351 {
352 // for measurebases within other measurebases (e.g., hbox within vbox), use top level
353 const MeasureBase* mb = top();
354 // avoid triggering layout before getting added to a score
355 if (mb->prev() || mb->next())
356 score()->setLayout(mb->tick(), -1, mb);
357 }
358
359 //---------------------------------------------------------
360 // first
361 //---------------------------------------------------------
362
first() const363 MeasureBase* Score::first() const
364 {
365 return _measures.first();
366 }
367
368 //---------------------------------------------------------
369 // last
370 //---------------------------------------------------------
371
last() const372 MeasureBase* Score::last() const
373 {
374 return _measures.last();
375 }
376
377 //---------------------------------------------------------
378 // getProperty
379 //---------------------------------------------------------
380
getProperty(Pid id) const381 QVariant MeasureBase::getProperty(Pid id) const
382 {
383 switch (id) {
384 case Pid::REPEAT_END:
385 return repeatEnd();
386 case Pid::REPEAT_START:
387 return repeatStart();
388 case Pid::REPEAT_JUMP:
389 return repeatJump();
390 case Pid::NO_OFFSET:
391 return noOffset();
392 case Pid::IRREGULAR:
393 return irregular();
394 default:
395 return Element::getProperty(id);
396 }
397 }
398
399 //---------------------------------------------------------
400 // setProperty
401 //---------------------------------------------------------
402
setProperty(Pid id,const QVariant & value)403 bool MeasureBase::setProperty(Pid id, const QVariant& value)
404 {
405 switch (id) {
406 case Pid::REPEAT_END:
407 setRepeatEnd(value.toBool());
408 break;
409 case Pid::REPEAT_START:
410 setRepeatStart(value.toBool());
411 break;
412 case Pid::REPEAT_JUMP:
413 setRepeatJump(value.toBool());
414 break;
415 case Pid::NO_OFFSET:
416 setNoOffset(value.toInt());
417 break;
418 case Pid::IRREGULAR:
419 setIrregular(value.toBool());
420 break;
421 default:
422 if (!Element::setProperty(id, value))
423 return false;
424 break;
425 }
426 triggerLayoutAll();
427 score()->setPlaylistDirty();
428 return true;
429 }
430
431 //---------------------------------------------------------
432 // propertyDefault
433 //---------------------------------------------------------
434
propertyDefault(Pid propertyId) const435 QVariant MeasureBase::propertyDefault(Pid propertyId) const
436 {
437 switch (propertyId) {
438 case Pid::REPEAT_END:
439 case Pid::REPEAT_START:
440 case Pid::REPEAT_JUMP:
441 return false;
442 default:
443 break;
444 }
445 return Element::propertyDefault(propertyId);
446 }
447
448 //---------------------------------------------------------
449 // undoSetBreak
450 //---------------------------------------------------------
451
undoSetBreak(bool v,LayoutBreak::Type type)452 void MeasureBase::undoSetBreak(bool v, LayoutBreak::Type type)
453 {
454 switch (type) {
455 case LayoutBreak::LINE:
456 if (lineBreak() == v)
457 return;
458 setLineBreak(v);
459 break;
460 case LayoutBreak::PAGE:
461 if (pageBreak() == v)
462 return;
463 if (v && lineBreak())
464 setLineBreak(false);
465 setPageBreak(v);
466 break;
467 case LayoutBreak::SECTION:
468 if (sectionBreak() == v)
469 return;
470 if (v && lineBreak())
471 setLineBreak(false);
472 setSectionBreak(v);
473 break;
474 case LayoutBreak::NOBREAK:
475 if (noBreak() == v)
476 return;
477 if (v) {
478 setLineBreak(false);
479 setPageBreak(false);
480 setSectionBreak(false);
481 }
482 setNoBreak(v);
483 break;
484 }
485
486 if (v) {
487 LayoutBreak* lb = new LayoutBreak(score());
488 lb->setLayoutBreakType(type);
489 lb->setTrack(-1); // this are system elements
490 MeasureBase* mb = (isMeasure() && toMeasure(this)->isMMRest()) ? toMeasure(this)->mmRestLast() : this;
491 lb->setParent(mb);
492 score()->undoAddElement(lb);
493 }
494 cleanupLayoutBreaks(true);
495 }
496
497 //---------------------------------------------------------
498 // cleanupLayoutBreaks
499 //---------------------------------------------------------
500
cleanupLayoutBreaks(bool undo)501 void MeasureBase::cleanupLayoutBreaks(bool undo)
502 {
503 // remove unneeded layout breaks
504 std::vector<Element*> toDelete;
505 for (Element* e : el()) {
506 if (e->isLayoutBreak()) {
507 switch (toLayoutBreak(e)->layoutBreakType()) {
508 case LayoutBreak::LINE:
509 if (!lineBreak())
510 toDelete.push_back(e);
511 break;
512 case LayoutBreak::PAGE:
513 if (!pageBreak())
514 toDelete.push_back(e);
515 break;
516 case LayoutBreak::SECTION:
517 if (!sectionBreak())
518 toDelete.push_back(e);
519 break;
520 case LayoutBreak::NOBREAK:
521 if (!noBreak())
522 toDelete.push_back(e);
523 break;
524 }
525 }
526 }
527 for (Element* e : toDelete) {
528 if (undo)
529 score()->undoRemoveElement(e);
530 else
531 _el.remove(e);
532 }
533 }
534
535 //---------------------------------------------------------
536 // nextMM
537 //---------------------------------------------------------
538
nextMM() const539 MeasureBase* MeasureBase::nextMM() const
540 {
541 if (_next
542 && _next->isMeasure()
543 && score()->styleB(Sid::createMultiMeasureRests)
544 && toMeasure(_next)->hasMMRest()) {
545 return toMeasure(_next)->mmRest();
546 }
547 return _next;
548 }
549
550 //---------------------------------------------------------
551 // prevMM
552 //---------------------------------------------------------
553
prevMM() const554 MeasureBase* MeasureBase::prevMM() const
555 {
556 if (_prev
557 && _prev->isMeasure()
558 && score()->styleB(Sid::createMultiMeasureRests)) {
559 return const_cast<Measure*>(toMeasure(_prev)->mmRest1());
560 }
561 return _prev;
562 }
563
564 //---------------------------------------------------------
565 // writeProperties
566 //---------------------------------------------------------
567
writeProperties(XmlWriter & xml) const568 void MeasureBase::writeProperties(XmlWriter& xml) const
569 {
570 Element::writeProperties(xml);
571 for (const Element* e : el())
572 e->write(xml);
573 }
574
575 //---------------------------------------------------------
576 // readProperties
577 //---------------------------------------------------------
578
readProperties(XmlReader & e)579 bool MeasureBase::readProperties(XmlReader& e)
580 {
581 const QStringRef& tag(e.name());
582 if (tag == "LayoutBreak") {
583 LayoutBreak* lb = new LayoutBreak(score());
584 lb->read(e);
585 bool doAdd = true;
586 switch (lb->layoutBreakType()) {
587 case LayoutBreak::LINE:
588 if (lineBreak())
589 doAdd = false;
590 break;
591 case LayoutBreak::PAGE:
592 if (pageBreak())
593 doAdd = false;
594 break;
595 case LayoutBreak::SECTION:
596 if (sectionBreak())
597 doAdd = false;
598 break;
599 case LayoutBreak::NOBREAK:
600 if (noBreak())
601 doAdd = false;
602 break;
603 }
604 if (doAdd) {
605 add(lb);
606 cleanupLayoutBreaks(false);
607 }
608 else
609 delete lb;
610 }
611 else if (tag == "StaffTypeChange") {
612 StaffTypeChange* stc = new StaffTypeChange(score());
613 stc->setTrack(e.track());
614 stc->setParent(this);
615 stc->read(e);
616 add(stc);
617 }
618 else if (Element::readProperties(e))
619 ;
620 else
621 return false;
622 return true;
623 }
624
625 //---------------------------------------------------------
626 // index
627 //---------------------------------------------------------
628
index() const629 int MeasureBase::index() const
630 {
631 int idx = 0;
632 MeasureBase* m = score()->first();
633 while (m) {
634 if (m == this)
635 return idx;
636 m = m->next();
637 ++idx;
638 }
639 return -1;
640 }
641
642 //---------------------------------------------------------
643 // measureIndex
644 // returns index of measure counting only Measures but
645 // skipping other MeasureBase descendants
646 //---------------------------------------------------------
647
measureIndex() const648 int MeasureBase::measureIndex() const
649 {
650 int idx = 0;
651 MeasureBase* m = score()->firstMeasure();
652 while (m) {
653 if (m == this)
654 return idx;
655 m = m->next();
656 if (m && m->isMeasure())
657 ++idx;
658 }
659 return -1;
660 }
661
662 //---------------------------------------------------------
663 // sectionBreakElement
664 //---------------------------------------------------------
665
sectionBreakElement() const666 LayoutBreak* MeasureBase::sectionBreakElement() const
667 {
668 if (sectionBreak()) {
669 for (Element* e : el()) {
670 if (e->isLayoutBreak() && toLayoutBreak(e)->isSectionBreak())
671 return toLayoutBreak(e);
672 }
673 }
674 return 0;
675 }
676 }
677
678