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