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 "mscore.h"
14 #include "staff.h"
15 #include "part.h"
16 #include "clef.h"
17 #include "xml.h"
18 #include "score.h"
19 #include "bracket.h"
20 #include "keysig.h"
21 #include "segment.h"
22 #include "style.h"
23 #include "measure.h"
24 #include "stringdata.h"
25 #include "stafftype.h"
26 #include "undo.h"
27 #include "cleflist.h"
28 #include "timesig.h"
29 #include "instrtemplate.h"
30 #include "barline.h"
31 #include "ottava.h"
32 #include "harmony.h"
33 #include "bracketItem.h"
34 #include "chord.h"
35 
36 // #define DEBUG_CLEFS
37 
38 #ifdef DEBUG_CLEFS
39 #define DUMP_CLEFS(s) dumpClefs(s)
40 #else
41 #define DUMP_CLEFS(s)
42 #endif
43 
44 namespace Ms {
45 
46 //---------------------------------------------------------
47 //   Staff
48 //---------------------------------------------------------
49 
Staff(Score * score)50 Staff::Staff(Score* score)
51    : ScoreElement(score)
52       {
53       initFromStaffType(0);
54       }
55 
56 //---------------------------------------------------------
57 //   idx
58 //---------------------------------------------------------
59 
idx() const60 int Staff::idx() const
61       {
62       return score()->staves().indexOf((Staff*)this, 0);
63       }
64 
65 //---------------------------------------------------------
66 //   triggerLayout
67 //---------------------------------------------------------
68 
triggerLayout()69 void Staff::triggerLayout()
70       {
71       score()->setLayoutAll(idx());
72       }
73 
triggerLayout(const Fraction & tick)74 void Staff::triggerLayout(const Fraction& tick)
75       {
76       score()->setLayout(tick, idx());
77       }
78 
79 //---------------------------------------------------------
80 //   fillBrackets
81 //    make sure index idx is valid
82 //---------------------------------------------------------
83 
fillBrackets(int idx)84 void Staff::fillBrackets(int idx)
85       {
86       for (int i = _brackets.size(); i <= idx; ++i) {
87             BracketItem* bi = new BracketItem(score());
88             bi->setStaff(this);
89             bi->setColumn(i);
90             _brackets.append(bi);
91             }
92       }
93 
94 //---------------------------------------------------------
95 //   cleanBrackets
96 //    remove NO_BRACKET entries from the end of list
97 //---------------------------------------------------------
98 
cleanBrackets()99 void Staff::cleanBrackets()
100       {
101       while (!_brackets.empty() && (_brackets.last()->bracketType() == BracketType::NO_BRACKET)) {
102             BracketItem* bi = _brackets.takeLast();
103             delete bi;
104             }
105       }
106 
107 //---------------------------------------------------------
108 //   bracket
109 //---------------------------------------------------------
110 
bracketType(int idx) const111 BracketType Staff::bracketType(int idx) const
112       {
113       if (idx < _brackets.size())
114             return _brackets[idx]->bracketType();
115       return BracketType::NO_BRACKET;
116       }
117 
118 //---------------------------------------------------------
119 //   bracketSpan
120 //---------------------------------------------------------
121 
bracketSpan(int idx) const122 int Staff::bracketSpan(int idx) const
123       {
124       if (idx < _brackets.size())
125             return _brackets[idx]->bracketSpan();
126       return 0;
127       }
128 
129 //---------------------------------------------------------
130 //   setBracket
131 //---------------------------------------------------------
132 
setBracketType(int idx,BracketType val)133 void Staff::setBracketType(int idx, BracketType val)
134       {
135       fillBrackets(idx);
136       _brackets[idx]->setBracketType(val);
137       cleanBrackets();
138       }
139 
140 //---------------------------------------------------------
141 //   swapBracket
142 //---------------------------------------------------------
143 
swapBracket(int oldIdx,int newIdx)144 void Staff::swapBracket(int oldIdx, int newIdx)
145       {
146       int idx = qMax(oldIdx, newIdx);
147       fillBrackets(idx);
148       _brackets[oldIdx]->setColumn(newIdx);
149       _brackets[newIdx]->setColumn(oldIdx);
150       _brackets.swap(oldIdx, newIdx);
151       cleanBrackets();
152       }
153 
154 //---------------------------------------------------------
155 //   changeBracketColumn
156 //---------------------------------------------------------
157 
changeBracketColumn(int oldColumn,int newColumn)158 void Staff::changeBracketColumn(int oldColumn, int newColumn)
159       {
160       int idx = qMax(oldColumn, newColumn);
161       fillBrackets(idx);
162       int step = newColumn > oldColumn ? 1 : -1;
163       for (int i = oldColumn; i != newColumn; i += step) {
164             int oldIdx = i;
165             int newIdx = i + step;
166             _brackets[oldIdx]->setColumn(newIdx);
167             _brackets[newIdx]->setColumn(oldIdx);
168             _brackets.swap(oldIdx, newIdx);
169             }
170       cleanBrackets();
171       }
172 
173 //---------------------------------------------------------
174 //   setBracketSpan
175 //---------------------------------------------------------
176 
setBracketSpan(int idx,int val)177 void Staff::setBracketSpan(int idx, int val)
178       {
179       Q_ASSERT(idx >= 0);
180       Q_ASSERT(val >= 0);
181       fillBrackets(idx);
182       _brackets[idx]->setBracketSpan(val);
183       }
184 
185 //---------------------------------------------------------
186 //   addBracket
187 //---------------------------------------------------------
188 
addBracket(BracketItem * b)189 void Staff::addBracket(BracketItem* b)
190       {
191       b->setStaff(this);
192       if (!_brackets.empty() && _brackets[0]->bracketType() == BracketType::NO_BRACKET)
193             _brackets[0] = b;
194       else {
195             //
196             // create new bracket level
197             //
198             for (Staff* s : score()->staves()) {
199                   if (s == this)
200                         s->_brackets.append(b);
201                   else {
202                         BracketItem* bi = new BracketItem(score());
203                         bi->setStaff(this);
204                         s->_brackets.append(bi);
205                         }
206                   }
207             }
208       }
209 
210 //---------------------------------------------------------
211 //   innerBracket
212 //    Return type inner bracket.
213 //    The bracket type determines the staff distance.
214 //---------------------------------------------------------
215 
innerBracket() const216 BracketType Staff::innerBracket() const
217       {
218       int staffIdx = idx();
219 
220       BracketType t = BracketType::NO_BRACKET;
221       int level = 1000;
222       for (int i = 0; i < score()->nstaves(); ++i) {
223             Staff* staff = score()->staff(i);
224             for (int k = 0; k < staff->brackets().size(); ++k) {
225                   const BracketItem* bi = staff->brackets().at(k);
226                   if (bi->bracketType() != BracketType::NO_BRACKET) {
227                         if (i < staffIdx && ((i + bi->bracketSpan()) > staffIdx) && k < level) {
228                               t = bi->bracketType();
229                               level = k;
230                               break;
231                               }
232                         }
233                   }
234             }
235       return t;
236       }
237 
238 //---------------------------------------------------------
239 //   cleanupBrackets
240 //---------------------------------------------------------
241 
cleanupBrackets()242 void Staff::cleanupBrackets()
243       {
244       int index = idx();
245       int n = score()->nstaves();
246       for (int i = 0; i < _brackets.size(); ++i) {
247             if (_brackets[i]->bracketType() == BracketType::NO_BRACKET)
248                   continue;
249             int span = _brackets[i]->bracketSpan();
250             if (span > (n - index)) {
251                   span = n - index;
252                   _brackets[i]->setBracketSpan(span);
253                   }
254             }
255       for (int i = 0; i < _brackets.size(); ++i) {
256             if (_brackets[i]->bracketType() == BracketType::NO_BRACKET)
257                   continue;
258             int span = _brackets[i]->bracketSpan();
259             if (span <= 1) {
260                   _brackets[i] = new BracketItem(score());
261                   _brackets[i]->setStaff(this);
262                   }
263             else {
264                   // delete all other brackets with same span
265                   for (int k = i + 1; k < _brackets.size(); ++k) {
266                         if (span == _brackets[k]->bracketSpan()) {
267                               _brackets[k] = new BracketItem(score());
268                               _brackets[k]->setStaff(this);
269                               }
270                         }
271                   }
272             }
273       }
274 
275 //---------------------------------------------------------
276 //   bracketLevels
277 //---------------------------------------------------------
278 
bracketLevels() const279 int Staff::bracketLevels() const
280       {
281       int columns = 0;
282       for (auto bi : _brackets)
283            columns = qMax(columns, bi->column());
284       return columns;
285       }
286 
287 //---------------------------------------------------------
288 //   partName
289 //---------------------------------------------------------
290 
partName() const291 QString Staff::partName() const
292       {
293       return _part->partName();
294       }
295 
296 //---------------------------------------------------------
297 //   Staff::clefType
298 //---------------------------------------------------------
299 
clefType(const Fraction & tick) const300 ClefTypeList Staff::clefType(const Fraction& tick) const
301       {
302       ClefTypeList ct = clefs.clef(tick.ticks());
303       if (ct._concertClef == ClefType::INVALID) {
304             // Clef compatibility based on instrument (override StaffGroup)
305             StaffGroup staffGroup = staffType(tick)->group();
306             if (staffGroup != StaffGroup::TAB)
307                   staffGroup = part()->instrument(tick)->useDrumset() ? StaffGroup::PERCUSSION : StaffGroup::STANDARD;
308 
309             switch (staffGroup) {
310                   case StaffGroup::TAB:
311                         {
312                         ClefType sct = ClefType(score()->styleI(Sid::tabClef));
313                         ct = staffType(tick)->lines() <= 4 ?  ClefTypeList(sct == ClefType::TAB ? ClefType::TAB4 : ClefType::TAB4_SERIF) : ClefTypeList(sct == ClefType::TAB ? ClefType::TAB : ClefType::TAB_SERIF);
314                         }
315                         break;
316                   case StaffGroup::STANDARD:
317                         ct = defaultClefType();
318                         break;
319                   case StaffGroup::PERCUSSION:
320                         ct = ClefTypeList(ClefType::PERC);
321                         break;
322                   }
323             }
324       return ct;
325       }
326 
327 //---------------------------------------------------------
328 //   Staff::clef
329 //---------------------------------------------------------
330 
clef(const Fraction & tick) const331 ClefType Staff::clef(const Fraction& tick) const
332       {
333       ClefTypeList c = clefType(tick);
334       return score()->styleB(Sid::concertPitch) ? c._concertClef : c._transposingClef;
335       }
336 
337 //---------------------------------------------------------
338 //   Staff::nextClefTick
339 //
340 //    return the tick of next clef after tick
341 //    return last tick of score if not found
342 //---------------------------------------------------------
343 
nextClefTick(const Fraction & tick) const344 Fraction Staff::nextClefTick(const Fraction& tick) const
345       {
346       Fraction t = Fraction::fromTicks(clefs.nextClefTick(tick.ticks()));
347       return t != Fraction(-1,1) ? t : score()->endTick();
348       }
349 
350 //---------------------------------------------------------
351 //   Staff::currentClefTick
352 //
353 //    return the tick position of the clef currently
354 //    in effect at tick
355 //    return 0, if no such clef
356 //---------------------------------------------------------
357 
currentClefTick(const Fraction & tick) const358 Fraction Staff::currentClefTick(const Fraction& tick) const
359       {
360       return Fraction::fromTicks(clefs.currentClefTick(tick.ticks()));
361       }
362 
363 
364 #ifndef NDEBUG
365 //---------------------------------------------------------
366 //   dumpClef
367 //---------------------------------------------------------
368 
dumpClefs(const char * title) const369 void Staff::dumpClefs(const char* title) const
370       {
371       qDebug("(%zd): %s", clefs.size(), title);
372       for (auto& i : clefs) {
373             qDebug("  %d: %d %d", i.first, int(i.second._concertClef), int(i.second._transposingClef));
374             }
375       }
376 
377 //---------------------------------------------------------
378 //   dumpKeys
379 //---------------------------------------------------------
380 
dumpKeys(const char * title) const381 void Staff::dumpKeys(const char* title) const
382       {
383       qDebug("(%zd): %s", _keys.size(), title);
384       for (auto& i : _keys) {
385             qDebug("  %d: %d", i.first, int(i.second.key()));
386             }
387       }
388 
389 //---------------------------------------------------------
390 //   dumpTimeSigs
391 //---------------------------------------------------------
392 
dumpTimeSigs(const char * title) const393 void Staff::dumpTimeSigs(const char* title) const
394       {
395       qDebug("size (%zd) staffIdx %d: %s", timesigs.size(), idx(), title);
396       for (auto& i : timesigs) {
397             qDebug("  %d: %d/%d", i.first, i.second->sig().numerator(), i.second->sig().denominator());
398             }
399       }
400 #endif
401 
402 //---------------------------------------------------------
403 //   setClef
404 //---------------------------------------------------------
405 
setClef(Clef * clef)406 void Staff::setClef(Clef* clef)
407       {
408       if (clef->generated())
409             return;
410       Fraction tick = clef->segment()->tick();
411       for (Segment* s = clef->segment()->next1(); s && s->tick() == tick; s = s->next1()) {
412             if ((s->segmentType() == SegmentType::Clef || s->segmentType() == SegmentType::HeaderClef)
413                 && s->element(clef->track())
414                 && !s->element(clef->track())->generated()) {
415                   // adding this clef has no effect on the clefs list
416                   return;
417                   }
418             }
419       clefs.setClef(clef->segment()->tick().ticks(), clef->clefTypeList());
420       DUMP_CLEFS("setClef");
421       }
422 
423 //---------------------------------------------------------
424 //   removeClef
425 //---------------------------------------------------------
426 
removeClef(const Clef * clef)427 void Staff::removeClef(const Clef* clef)
428       {
429       if (clef->generated())
430             return;
431       Fraction tick = clef->segment()->tick();
432       for (Segment* s = clef->segment()->next1(); s && s->tick() == tick; s = s->next1()) {
433             if ((s->segmentType() == SegmentType::Clef || s->segmentType() == SegmentType::HeaderClef)
434                 && s->element(clef->track())
435                 && !s->element(clef->track())->generated()) {
436                   // removal of this clef has no effect on the clefs list
437                   return;
438                   }
439             }
440       clefs.erase(clef->segment()->tick().ticks());
441       for (Segment* s = clef->segment()->prev1(); s && s->tick() == tick; s = s->prev1()) {
442             if ((s->segmentType() == SegmentType::Clef || s->segmentType() == SegmentType::HeaderClef)
443                && s->element(clef->track())
444                && !s->element(clef->track())->generated()) {
445                   // a previous clef at the same tick position gets valid
446                   clefs.setClef(tick.ticks(), toClef(s->element(clef->track()))->clefTypeList());
447                   break;
448                   }
449             }
450       DUMP_CLEFS("removeClef");
451       }
452 
453 //---------------------------------------------------------
454 //   timeStretch
455 //---------------------------------------------------------
456 
timeStretch(const Fraction & tick) const457 Fraction Staff::timeStretch(const Fraction& tick) const
458       {
459       TimeSig* timesig = timeSig(tick);
460       return timesig ? timesig->stretch() : Fraction(1,1);
461       }
462 
463 //---------------------------------------------------------
464 //   timeSig
465 //    lookup time signature before or at tick
466 //---------------------------------------------------------
467 
timeSig(const Fraction & tick) const468 TimeSig* Staff::timeSig(const Fraction& tick) const
469       {
470       auto i = timesigs.upper_bound(tick.ticks());
471       if (i != timesigs.begin())
472             --i;
473       if (i == timesigs.end())
474             return 0;
475       else if (tick < Fraction::fromTicks(i->first))
476             return 0;
477       return i->second;
478       }
479 
480 //---------------------------------------------------------
481 //   nextTimeSig
482 //    lookup time signature at tick or after
483 //---------------------------------------------------------
484 
nextTimeSig(const Fraction & tick) const485 TimeSig* Staff::nextTimeSig(const Fraction& tick) const
486       {
487       auto i = timesigs.lower_bound(tick.ticks());
488       return (i == timesigs.end()) ? 0 : i->second;
489       }
490 
491 
492 //---------------------------------------------------------
493 //   currentTimeSigTick
494 //
495 //    return the tick position of the time sig currently
496 //    in effect at tick
497 //---------------------------------------------------------
498 
currentTimeSigTick(const Fraction & tick) const499 Fraction Staff::currentTimeSigTick(const Fraction& tick) const
500       {
501       if (timesigs.empty())
502             return Fraction(0, 1);
503       auto i = timesigs.upper_bound(tick.ticks());
504       if (i == timesigs.begin())
505             return Fraction(0, 1);
506       --i;
507       return Fraction::fromTicks(i->first);
508       }
509 
510 //---------------------------------------------------------
511 //   group
512 //---------------------------------------------------------
513 
group(const Fraction & tick) const514 const Groups& Staff::group(const Fraction& tick) const
515       {
516       TimeSig* ts = timeSig(tick);
517       if (ts) {
518             if (!ts->groups().empty())
519                   return ts->groups();
520             return Groups::endings(ts->sig());
521             }
522       Measure* m = score()->tick2measure(tick);
523       return Groups::endings(m ? m->timesig() : Fraction(4,4));
524       }
525 
526 //---------------------------------------------------------
527 //   addTimeSig
528 //---------------------------------------------------------
529 
addTimeSig(TimeSig * timesig)530 void Staff::addTimeSig(TimeSig* timesig)
531       {
532       if (timesig->segment()->segmentType() == SegmentType::TimeSig)
533             timesigs[timesig->segment()->tick().ticks()] = timesig;
534 //      dumpTimeSigs("after addTimeSig");
535       }
536 
537 //---------------------------------------------------------
538 //   removeTimeSig
539 //---------------------------------------------------------
540 
removeTimeSig(TimeSig * timesig)541 void Staff::removeTimeSig(TimeSig* timesig)
542       {
543       if (timesig->segment()->segmentType() == SegmentType::TimeSig)
544             timesigs.erase(timesig->segment()->tick().ticks());
545 //      dumpTimeSigs("after removeTimeSig");
546       }
547 
548 //---------------------------------------------------------
549 //   clearTimeSig
550 //---------------------------------------------------------
551 
clearTimeSig()552 void Staff::clearTimeSig()
553       {
554       timesigs.clear();
555       }
556 
557 //---------------------------------------------------------
558 //   Staff::keySigEvent
559 //
560 //    locates the key sig currently in effect at tick
561 //---------------------------------------------------------
562 
keySigEvent(const Fraction & tick) const563 KeySigEvent Staff::keySigEvent(const Fraction& tick) const
564       {
565       return _keys.key(tick.ticks());
566       }
567 
568 //---------------------------------------------------------
569 //   setKey
570 //---------------------------------------------------------
571 
setKey(const Fraction & tick,KeySigEvent k)572 void Staff::setKey(const Fraction& tick, KeySigEvent k)
573       {
574       _keys.setKey(tick.ticks(), k);
575       }
576 
577 //---------------------------------------------------------
578 //   removeKey
579 //---------------------------------------------------------
580 
removeKey(const Fraction & tick)581 void Staff::removeKey(const Fraction& tick)
582       {
583       _keys.erase(tick.ticks());
584       }
585 
586 //---------------------------------------------------------
587 //   prevkey
588 //---------------------------------------------------------
589 
prevKey(const Fraction & tick) const590 KeySigEvent Staff::prevKey(const Fraction& tick) const
591       {
592       return _keys.prevKey(tick.ticks());
593       }
594 
595 //---------------------------------------------------------
596 //   Staff::nextKeyTick
597 //
598 //    return the tick at which the key sig after tick is located
599 //    return 0, if no such a key sig
600 //---------------------------------------------------------
601 
nextKeyTick(const Fraction & tick) const602 Fraction Staff::nextKeyTick(const Fraction& tick) const
603       {
604       Fraction t = Fraction::fromTicks(_keys.nextKeyTick(tick.ticks()));
605       return t != Fraction(-1,1) ? t : score()->endTick();
606       }
607 
608 //---------------------------------------------------------
609 //   Staff::currentKeyTick
610 //
611 //    return the tick position of the key currently
612 //    in effect at tick
613 //    return 0, if no such a key sig
614 //---------------------------------------------------------
615 
currentKeyTick(const Fraction & tick) const616 Fraction Staff::currentKeyTick(const Fraction& tick) const
617       {
618       return Fraction::fromTicks(_keys.currentKeyTick(tick.ticks()));
619       }
620 
621 //---------------------------------------------------------
622 //   write
623 //---------------------------------------------------------
624 
write(XmlWriter & xml) const625 void Staff::write(XmlWriter& xml) const
626       {
627       int idx = this->idx();
628       xml.stag(this, QString("id=\"%1\"").arg(idx + 1));
629       if (links()) {
630             Score* s = masterScore();
631             for (auto le : *links()) {
632                   Staff* staff = toStaff(le);
633                   if ((staff->score() == s) && (staff != this))
634                         xml.tag("linkedTo", staff->idx() + 1);
635                   }
636             }
637 
638       // for copy/paste we need to know the actual transposition
639       if (xml.clipboardmode()) {
640             Interval v = part()->instrument()->transpose(); // TODO: tick?
641             if (v.diatonic)
642                   xml.tag("transposeDiatonic", v.diatonic);
643             if (v.chromatic)
644                   xml.tag("transposeChromatic", v.chromatic);
645             }
646 
647       staffType(Fraction(0,1))->write(xml);
648       ClefTypeList ct = _defaultClefType;
649       if (ct._concertClef == ct._transposingClef) {
650             if (ct._concertClef != ClefType::G)
651                   xml.tag("defaultClef", ClefInfo::tag(ct._concertClef));
652             }
653       else {
654             xml.tag("defaultConcertClef", ClefInfo::tag(ct._concertClef));
655             xml.tag("defaultTransposingClef", ClefInfo::tag(ct._transposingClef));
656             }
657 
658       if (invisible(Fraction(0,1)))
659             xml.tag("invisible", invisible(Fraction(0,1)));
660       if (hideWhenEmpty() != HideMode::AUTO)
661             xml.tag("hideWhenEmpty", int(hideWhenEmpty()));
662       if (cutaway())
663             xml.tag("cutaway", cutaway());
664       if (showIfEmpty())
665             xml.tag("showIfSystemEmpty", showIfEmpty());
666       if (_hideSystemBarLine)
667             xml.tag("hideSystemBarLine", _hideSystemBarLine);
668       if (_mergeMatchingRests)
669             xml.tag("mergeMatchingRests", _mergeMatchingRests);
670 
671       for (const BracketItem* i : _brackets) {
672             BracketType a = i->bracketType();
673             int b = i->bracketSpan();
674             int c = i->column();
675             if (a != BracketType::NO_BRACKET || b > 0)
676                   xml.tagE(QString("bracket type=\"%1\" span=\"%2\" col=\"%3\"").arg(static_cast<int>(a)).arg(b).arg(c));
677             }
678 
679       writeProperty(xml, Pid::STAFF_BARLINE_SPAN);
680       writeProperty(xml, Pid::STAFF_BARLINE_SPAN_FROM);
681       writeProperty(xml, Pid::STAFF_BARLINE_SPAN_TO);
682       writeProperty(xml, Pid::STAFF_USERDIST);
683       writeProperty(xml, Pid::STAFF_COLOR);
684       writeProperty(xml, Pid::PLAYBACK_VOICE1);
685       writeProperty(xml, Pid::PLAYBACK_VOICE2);
686       writeProperty(xml, Pid::PLAYBACK_VOICE3);
687       writeProperty(xml, Pid::PLAYBACK_VOICE4);
688       xml.etag();
689       }
690 
691 //---------------------------------------------------------
692 //   read
693 //---------------------------------------------------------
694 
read(XmlReader & e)695 void Staff::read(XmlReader& e)
696       {
697       while (e.readNextStartElement()) {
698             if (!readProperties(e))
699                   e.unknown();
700             }
701       }
702 
703 //---------------------------------------------------------
704 //   readProperties
705 //---------------------------------------------------------
706 
readProperties(XmlReader & e)707 bool Staff::readProperties(XmlReader& e)
708       {
709       const QStringRef& tag(e.name());
710       if (tag == "StaffType") {
711             StaffType st;
712             st.read(e);
713             setStaffType(Fraction(0,1), st);
714             }
715       else if (tag == "defaultClef") {           // sets both default transposing and concert clef
716             QString val(e.readElementText());
717             ClefType ct = Clef::clefType(val);
718             setDefaultClefType(ClefTypeList(ct, ct));
719             }
720       else if (tag == "defaultConcertClef") {
721             QString val(e.readElementText());
722             setDefaultClefType(ClefTypeList(Clef::clefType(val), defaultClefType()._transposingClef));
723             }
724       else if (tag == "defaultTransposingClef") {
725             QString val(e.readElementText());
726             setDefaultClefType(ClefTypeList(defaultClefType()._concertClef, Clef::clefType(val)));
727             }
728       else if (tag == "small")                  // obsolete
729             staffType(Fraction(0,1))->setSmall(e.readInt());
730       else if (tag == "invisible")
731             staffType(Fraction(0,1))->setInvisible(e.readInt());          // same as: setInvisible(Fraction(0,1)), e.readInt())
732       else if (tag == "hideWhenEmpty")
733             setHideWhenEmpty(HideMode(e.readInt()));
734       else if (tag == "cutaway")
735             setCutaway(e.readInt());
736       else if (tag == "showIfSystemEmpty")
737             setShowIfEmpty(e.readInt());
738       else if (tag == "hideSystemBarLine")
739             _hideSystemBarLine = e.readInt();
740       else if (tag == "mergeMatchingRests")
741             _mergeMatchingRests = e.readInt();
742       else if (tag == "keylist")
743             _keys.read(e, score());
744       else if (tag == "bracket") {
745             int col = e.intAttribute("col", -1);
746             if (col == -1)
747                   col = _brackets.size();
748             setBracketType(col, BracketType(e.intAttribute("type", -1)));
749             setBracketSpan(col, e.intAttribute("span", 0));
750             e.readNext();
751             }
752       else if (tag == "barLineSpan")
753             _barLineSpan = e.readInt();
754       else if (tag == "barLineSpanFrom")
755             _barLineFrom = e.readInt();
756       else if (tag == "barLineSpanTo")
757             _barLineTo = e.readInt();
758       else if (tag == "distOffset")
759             _userDist = e.readDouble() * score()->spatium();
760       else if (tag == "mag")
761             /*_userMag =*/ e.readDouble(0.1, 10.0);
762       else if (tag == "linkedTo") {
763             int v = e.readInt() - 1;
764             Staff* st = masterScore()->staff(v);
765             if (_links) {
766                   qDebug("Staff::readProperties: multiple <linkedTo> tags");
767                   if (!st || isLinked(st)) // maybe we don't need actually to relink...
768                         return true;
769                   // not using unlink() here as it may delete _links
770                   // a pointer to which is stored also in XmlReader.
771                   _links->removeOne(this);
772                   _links = nullptr;
773                   }
774             if (st && st != this)
775                   linkTo(st);
776             else if (!score()->isMaster() && !st) {
777                   // if it is a master score it is OK not to find
778                   // a staff which is going after the current one.
779                   qDebug("staff %d not found in parent", v);
780                   }
781             }
782       else if (tag == "color")
783             staffType(Fraction(0,1))->setColor(e.readColor());
784       else if (tag == "transposeDiatonic")
785             e.setTransposeDiatonic(e.readInt());
786       else if (tag == "transposeChromatic")
787             e.setTransposeChromatic(e.readInt());
788       else if (tag == "playbackVoice1")
789             setPlaybackVoice(0, e.readInt());
790       else if (tag == "playbackVoice2")
791             setPlaybackVoice(1, e.readInt());
792       else if (tag == "playbackVoice3")
793             setPlaybackVoice(2, e.readInt());
794       else if (tag == "playbackVoice4")
795             setPlaybackVoice(3, e.readInt());
796       else
797             return false;
798       return true;
799       }
800 
801 //---------------------------------------------------------
802 //   height
803 //---------------------------------------------------------
804 
height() const805 qreal Staff::height() const
806       {
807       Fraction tick = Fraction(0,1);     // TODO
808 //      return (lines(tick) == 1 ? 2 : lines(tick)-1) * spatium(tick) * staffType(tick)->lineDistance().val();
809       return (lines(tick)-1) * spatium(tick) * staffType(tick)->lineDistance().val();
810       }
811 
812 //---------------------------------------------------------
813 //   spatium
814 //---------------------------------------------------------
815 
spatium(const Fraction & tick) const816 qreal Staff::spatium(const Fraction& tick) const
817       {
818       return score()->spatium() * mag(tick);
819       }
820 
spatium(const Element * e) const821 qreal Staff::spatium(const Element* e) const
822       {
823       return score()->spatium() * mag(e);
824       }
825 
826 //---------------------------------------------------------
827 //   mag
828 //---------------------------------------------------------
829 
mag(const StaffType * stt) const830 qreal Staff::mag(const StaffType* stt) const
831       {
832       return (stt->small() ? score()->styleD(Sid::smallStaffMag) : 1.0) * stt->userMag();
833       }
834 
mag(const Fraction & tick) const835 qreal Staff::mag(const Fraction& tick) const
836       {
837       return mag(staffType(tick));
838       }
839 
mag(const Element * e) const840 qreal Staff::mag(const Element* e) const
841       {
842       return mag(staffTypeForElement(e));
843       }
844 
845 //---------------------------------------------------------
846 //   swing
847 //---------------------------------------------------------
848 
swing(const Fraction & tick) const849 SwingParameters Staff::swing(const Fraction& tick) const
850       {
851       SwingParameters sp;
852       int swingUnit = 0;
853       QString unit = score()->styleSt(Sid::swingUnit);
854       int swingRatio = score()->styleI(Sid::swingRatio);
855       if (unit == TDuration(TDuration::DurationType::V_EIGHTH).name())
856             swingUnit = MScore::division / 2;
857       else if (unit == TDuration(TDuration::DurationType::V_16TH).name())
858             swingUnit = MScore::division / 4;
859       else if (unit == TDuration(TDuration::DurationType::V_ZERO).name())
860             swingUnit = 0;
861       sp.swingRatio = swingRatio;
862       sp.swingUnit = swingUnit;
863       if (_swingList.empty())
864             return sp;
865       QMap<int, SwingParameters>::const_iterator i = _swingList.upperBound(tick.ticks());
866       if (i == _swingList.begin())
867             return sp;
868       --i;
869       return i.value();
870       }
871 
872 //---------------------------------------------------------
873 //   capo
874 //---------------------------------------------------------
875 
capo(const Fraction & tick) const876 int Staff::capo(const Fraction& tick) const
877       {
878       if (_capoList.empty())
879             return 0;
880       QMap<int, int>::const_iterator i = _capoList.upperBound(tick.ticks());
881       if (i == _capoList.begin())
882             return 0;
883       --i;
884       return i.value();
885       }
886 
887 //---------------------------------------------------------
888 //   getNotes
889 //---------------------------------------------------------
890 
getNotes() const891 QList<Note*> Staff::getNotes() const
892       {
893       QList<Note*> list;
894 
895       int staffIdx = idx();
896 
897       SegmentType st = SegmentType::ChordRest;
898       for (Segment* s = score()->firstSegment(st); s; s = s->next1(st)) {
899             for (int voice = 0; voice < VOICES; ++voice) {
900                   int track = voice + staffIdx * VOICES;
901                   Element* e = s->element(track);
902                   if (e && e->isChord())
903                         addChord(list, toChord(e), voice);
904                   }
905             }
906 
907       return list;
908       }
909 
910 //---------------------------------------------------------
911 //   addChord
912 //---------------------------------------------------------
913 
addChord(QList<Note * > & list,Chord * chord,int voice) const914 void Staff::addChord(QList<Note*>& list, Chord* chord, int voice) const
915       {
916       for (Chord* c : chord->graceNotes())
917             addChord(list, c, voice);
918       for (Note* note : chord->notes()) {
919             if (note->tieBack())
920                   continue;
921             list.append(note);
922             }
923       }
924 
925 //---------------------------------------------------------
926 //   channel
927 //---------------------------------------------------------
928 
channel(const Fraction & tick,int voice) const929 int Staff::channel(const Fraction& tick,  int voice) const
930       {
931       if (_channelList[voice].empty())
932             return 0;
933       QMap<int, int>::const_iterator i = _channelList[voice].upperBound(tick.ticks());
934       if (i == _channelList[voice].begin())
935             return 0;
936       --i;
937       return i.value();
938       }
939 
940 //---------------------------------------------------------
941 //   middleLine
942 //    returns logical line number of middle staff line
943 //---------------------------------------------------------
944 
middleLine(const Fraction & tick) const945 int Staff::middleLine(const Fraction& tick) const
946       {
947       return lines(tick) - 1 - staffType(tick)->stepOffset();
948       }
949 
950 //---------------------------------------------------------
951 //   bottomLine
952 //    returns logical line number of bottom staff line
953 //---------------------------------------------------------
954 
bottomLine(const Fraction & tick) const955 int Staff::bottomLine(const Fraction& tick) const
956       {
957       return (lines(tick) - 1) * 2;
958       }
959 
960 //---------------------------------------------------------
961 //   stemless
962 //---------------------------------------------------------
963 
stemless(const Fraction & tick) const964 bool Staff::stemless(const Fraction& tick) const
965       {
966       return staffType(tick)->stemless();
967       }
968 
969 //---------------------------------------------------------
970 //   setSlashStyle
971 //---------------------------------------------------------
972 
setSlashStyle(const Fraction & tick,bool val)973 void Staff::setSlashStyle(const Fraction& tick, bool val)
974       {
975       staffType(tick)->setStemless(val);
976       }
977 
978 //---------------------------------------------------------
979 //   primaryStaff
980 ///   if there are linked staves, the primary staff is
981 ///   the one who is played back and it's not a tab staff
982 ///   because we don't have enough information  to play
983 ///   e.g ornaments. NOTE: it's not necessarily the top staff!
984 //---------------------------------------------------------
985 
primaryStaff() const986 bool Staff::primaryStaff() const
987       {
988       if (!_links)
989             return true;
990       QList<Staff*> s;
991       QList<Staff*> ss;
992       for (auto e : *_links) {
993             Staff* staff = toStaff(e);
994             if (staff->score() == score()) {
995                   s.append(staff);
996                   if (!staff->isTabStaff(Fraction(0,1)))
997                         ss.append(staff);
998                   }
999             }
1000       if (s.size() == 1) // the linked staves are in different scores
1001       	return s.front() == this;
1002       else // return a non tab linked staff in this score
1003       	return ss.front() == this;
1004       }
1005 
1006 //---------------------------------------------------------
1007 //   staffType
1008 //---------------------------------------------------------
1009 
staffType(const Fraction & tick) const1010 const StaffType* Staff::staffType(const Fraction& tick) const
1011       {
1012       return &_staffTypeList.staffType(tick);
1013       }
1014 
constStaffType(const Fraction & tick) const1015 const StaffType* Staff::constStaffType(const Fraction& tick) const
1016       {
1017       return &_staffTypeList.staffType(tick);
1018       }
1019 
staffType(const Fraction & tick)1020 StaffType* Staff::staffType(const Fraction& tick)
1021       {
1022       return &_staffTypeList.staffType(tick);
1023       }
1024 
staffTypeForElement(const Element * e) const1025 const StaffType* Staff::staffTypeForElement(const Element* e) const
1026       {
1027       if (_staffTypeList.uniqueStaffType()) // optimize if one staff type spans for the entire staff
1028             return &_staffTypeList.staffType({0, 1});
1029       return &_staffTypeList.staffType(e->tick());
1030       }
1031 
1032 //---------------------------------------------------------
1033 //   staffTypeListChanged
1034 //    Signal that the staffTypeList has changed at
1035 //    position tick. Update layout range.
1036 //---------------------------------------------------------
1037 
staffTypeListChanged(const Fraction & tick)1038 void Staff::staffTypeListChanged(const Fraction& tick)
1039       {
1040       std::pair<int, int> range = _staffTypeList.staffTypeRange(tick);
1041 
1042       if (range.first < 0)
1043             triggerLayout(Fraction(0,1));
1044       else
1045             triggerLayout(Fraction::fromTicks(range.first));
1046 
1047       if (range.second < 0) {
1048             // When reading a score and there is a Staff Change on the first
1049             // measure, there are no measures yet and nothing to layout.
1050             if (score()->lastMeasure())
1051                   triggerLayout(score()->lastMeasure()->endTick());
1052             }
1053       else {
1054             triggerLayout(Fraction::fromTicks(range.second));
1055             }
1056       }
1057 
1058 //---------------------------------------------------------
1059 //   setStaffType
1060 //---------------------------------------------------------
1061 
setStaffType(const Fraction & tick,const StaffType & nst)1062 StaffType* Staff::setStaffType(const Fraction& tick, const StaffType& nst)
1063       {
1064       return _staffTypeList.setStaffType(tick, nst);
1065       }
1066 
1067 //---------------------------------------------------------
1068 //   setStaffType
1069 //---------------------------------------------------------
1070 
removeStaffType(const Fraction & tick)1071 void Staff::removeStaffType(const Fraction& tick)
1072       {
1073       qreal old = spatium(tick);
1074       const bool removed = _staffTypeList.removeStaffType(tick);
1075       if (!removed)
1076             return;
1077       localSpatiumChanged(old, spatium(tick), tick);
1078       staffTypeListChanged(tick);
1079       }
1080 
1081 //---------------------------------------------------------
1082 //   init
1083 //---------------------------------------------------------
1084 
init(const InstrumentTemplate * t,const StaffType * staffType,int cidx)1085 void Staff::init(const InstrumentTemplate* t, const StaffType* staffType, int cidx)
1086       {
1087       // set staff-type-independent parameters
1088       const StaffType* pst = staffType ? staffType : t->staffTypePreset;
1089       if (!pst)
1090             pst = StaffType::getDefaultPreset(t->staffGroup);
1091 
1092       StaffType* stt = setStaffType(Fraction(0,1), *pst);
1093       if (cidx >= MAX_STAVES) {
1094             stt->setSmall(false);
1095             }
1096       else {
1097             stt->setSmall(t->smallStaff[cidx]);
1098             setBracketType(0, t->bracket[cidx]);
1099             setBracketSpan(0, t->bracketSpan[cidx]);
1100             setBarLineSpan(t->barlineSpan[cidx]);
1101             }
1102       setDefaultClefType(t->clefType(cidx));
1103       }
1104 
1105 //---------------------------------------------------------
1106 //   init
1107 //---------------------------------------------------------
1108 
init(const Staff * s)1109 void Staff::init(const Staff* s)
1110       {
1111       _staffTypeList     = s->_staffTypeList;
1112       setDefaultClefType(s->defaultClefType());
1113       for (BracketItem* i : s->_brackets){
1114             BracketItem* ni = new BracketItem(*i);
1115             ni->setScore(score());
1116             ni->setStaff(this);
1117             _brackets.push_back(ni);
1118             }
1119       _barLineSpan       = s->_barLineSpan;
1120       _barLineFrom       = s->_barLineFrom;
1121       _barLineTo         = s->_barLineTo;
1122       _invisible         = s->_invisible;
1123       _hideWhenEmpty     = s->_hideWhenEmpty;
1124       _cutaway           = s->_cutaway;
1125       _showIfEmpty       = s->_showIfEmpty;
1126       _hideSystemBarLine = s->_hideSystemBarLine;
1127       _mergeMatchingRests = s->_mergeMatchingRests;
1128       _color             = s->_color;
1129       _userDist          = s->_userDist;
1130       }
1131 
1132 //---------------------------------------------------------
1133 //   initFromStaffType
1134 //---------------------------------------------------------
1135 
initFromStaffType(const StaffType * staffType)1136 void Staff::initFromStaffType(const StaffType* staffType)
1137       {
1138       // get staff type if given (if none, get default preset for default staff group)
1139       if (!staffType)
1140             staffType = StaffType::getDefaultPreset(StaffGroup::STANDARD);
1141 
1142       // use selected staff type
1143       setStaffType(Fraction(0,1), *staffType);
1144       }
1145 
1146 //---------------------------------------------------------
1147 //   spatiumChanged
1148 //---------------------------------------------------------
1149 
spatiumChanged(qreal oldValue,qreal newValue)1150 void Staff::spatiumChanged(qreal oldValue, qreal newValue)
1151       {
1152       _userDist = (_userDist / oldValue) * newValue;
1153       }
1154 
1155 //---------------------------------------------------------
1156 //   show
1157 //---------------------------------------------------------
1158 
show() const1159 bool Staff::show() const
1160       {
1161       return _part->show();
1162       }
1163 
1164 //---------------------------------------------------------
1165 //   genKeySig
1166 //---------------------------------------------------------
1167 
genKeySig()1168 bool Staff::genKeySig()
1169       {
1170       if (constStaffType(Fraction(0,1))->group() == StaffGroup::TAB)
1171             return false;
1172       else
1173             return constStaffType(Fraction(0,1))->genKeysig();
1174       }
1175 
1176 //---------------------------------------------------------
1177 //   showLedgerLines
1178 //---------------------------------------------------------
1179 
showLedgerLines(const Fraction & tick) const1180 bool Staff::showLedgerLines(const Fraction& tick) const
1181       {
1182       return staffType(tick)->showLedgerLines();
1183       }
1184 
1185 //---------------------------------------------------------
1186 //   color
1187 //---------------------------------------------------------
1188 
color(const Fraction & tick) const1189 QColor Staff::color(const Fraction& tick) const
1190       {
1191       return staffType(tick)->color();
1192       }
1193 
1194 //---------------------------------------------------------
1195 //   setColor
1196 //---------------------------------------------------------
1197 
setColor(const Fraction & tick,const QColor & val)1198 void Staff::setColor(const Fraction& tick, const QColor& val)
1199       {
1200       staffType(tick)->setColor(val);
1201       }
1202 
1203 //---------------------------------------------------------
1204 //   updateOttava
1205 //---------------------------------------------------------
1206 
updateOttava()1207 void Staff::updateOttava()
1208       {
1209       int staffIdx = idx();
1210       _pitchOffsets.clear();
1211       for (auto i : score()->spanner()) {
1212             const Spanner* s = i.second;
1213             if (s->type() == ElementType::OTTAVA && s->staffIdx() == staffIdx) {
1214                   const Ottava* o = static_cast<const Ottava*>(s);
1215                   _pitchOffsets.setPitchOffset(o->tick().ticks(), o->pitchShift());
1216                   _pitchOffsets.setPitchOffset(o->tick2().ticks(), 0);
1217                   }
1218             }
1219       }
1220 
1221 //---------------------------------------------------------
1222 //   undoSetColor
1223 //---------------------------------------------------------
1224 
undoSetColor(const QColor &)1225 void Staff::undoSetColor(const QColor& /*val*/)
1226       {
1227 //      undoChangeProperty(Pid::COLOR, val);
1228       }
1229 
1230 //---------------------------------------------------------
1231 //   insertTime
1232 //---------------------------------------------------------
1233 
insertTime(const Fraction & tick,const Fraction & len)1234 void Staff::insertTime(const Fraction& tick, const Fraction& len)
1235       {
1236       if (len.isZero())
1237             return;
1238 
1239       // move all keys and clefs >= tick
1240 
1241       if (len < Fraction(0,1)) {
1242             // remove entries between tickpos >= tick and tickpos < (tick+len)
1243             _keys.erase(_keys.lower_bound(tick.ticks()), _keys.lower_bound((tick - len).ticks()));
1244             clefs.erase(clefs.lower_bound(tick.ticks()), clefs.lower_bound((tick - len).ticks()));
1245             }
1246 
1247       KeyList kl2;
1248       for (auto i = _keys.lower_bound(tick.ticks()); i != _keys.end();) {
1249             KeySigEvent kse = i->second;
1250             Fraction t = Fraction::fromTicks(i->first);
1251             _keys.erase(i++);
1252             kl2[(t + len).ticks()] = kse;
1253             }
1254       _keys.insert(kl2.begin(), kl2.end());
1255 
1256       // check if there is a clef at the end of measure
1257       // before tick
1258       Clef* clef = 0;
1259       Measure* m = score()->tick2measure(tick);
1260       if (m && (m->tick() == tick) && (m->prevMeasure())) {
1261             m = m->prevMeasure();
1262             Segment* s = m->findSegment(SegmentType::Clef, tick);
1263             if (s) {
1264                   int track = idx() * VOICES;
1265                   clef = toClef(s->element(track));
1266                   }
1267             }
1268 
1269       ClefList cl2;
1270       for (auto i = clefs.lower_bound(tick.ticks()); i != clefs.end();) {
1271             ClefTypeList ctl = i->second;
1272             Fraction t = Fraction::fromTicks(i->first);
1273             if (clef && tick == t) {
1274                   ++i;
1275                   continue;
1276                   }
1277             clefs.erase(i++);
1278             cl2.setClef((t + len).ticks(), ctl);
1279             }
1280       clefs.insert(cl2.begin(), cl2.end());
1281 
1282       // check if there is a clef at the end of measure
1283       // before tick: do not remove from clefs list
1284 
1285       if (clef)
1286             setClef(clef);
1287 
1288       updateOttava();
1289       DUMP_CLEFS("  insertTime");
1290       }
1291 
1292 //---------------------------------------------------------
1293 //   staffList
1294 //    return list of linked staves
1295 //---------------------------------------------------------
1296 
staffList() const1297 QList<Staff*> Staff::staffList() const
1298       {
1299       QList<Staff*> staffList;
1300       if (_links) {
1301             for (ScoreElement* e : *_links)
1302                   staffList.append(toStaff(e));
1303 //            staffList = _linkedStaves->staves();
1304             }
1305       else
1306             staffList.append(const_cast<Staff*>(this));
1307       return staffList;
1308       }
1309 
1310 //---------------------------------------------------------
1311 //   rstaff
1312 //---------------------------------------------------------
1313 
rstaff() const1314 int Staff::rstaff() const
1315       {
1316       return _part->staves()->indexOf((Staff*)this, 0);
1317       }
1318 
1319 //---------------------------------------------------------
1320 //   isTop
1321 //---------------------------------------------------------
1322 
isTop() const1323 bool Staff::isTop() const
1324       {
1325       return _part->staves()->front() == this;
1326       }
1327 
1328 //---------------------------------------------------------
1329 //   getProperty
1330 //---------------------------------------------------------
1331 
getProperty(Pid id) const1332 QVariant Staff::getProperty(Pid id) const
1333       {
1334       switch (id) {
1335             case Pid::SMALL:
1336                   return staffType(Fraction(0,1))->small();
1337             case Pid::MAG:
1338                   return staffType(Fraction(0,1))->userMag();
1339             case Pid::STAFF_INVISIBLE:
1340                   return staffType(Fraction(0,1))->invisible();
1341             case Pid::STAFF_COLOR:
1342                   return staffType(Fraction(0,1))->color();
1343             case Pid::PLAYBACK_VOICE1:
1344                   return playbackVoice(0);
1345             case Pid::PLAYBACK_VOICE2:
1346                   return playbackVoice(1);
1347             case Pid::PLAYBACK_VOICE3:
1348                   return playbackVoice(2);
1349             case Pid::PLAYBACK_VOICE4:
1350                   return playbackVoice(3);
1351             case Pid::STAFF_BARLINE_SPAN:
1352                   return barLineSpan();
1353             case Pid::STAFF_BARLINE_SPAN_FROM:
1354                   return barLineFrom();
1355             case Pid::STAFF_BARLINE_SPAN_TO:
1356                   return barLineTo();
1357             case Pid::STAFF_USERDIST:
1358                   return userDist();
1359             case Pid::GENERATED:
1360                   return false;
1361             default:
1362                   qDebug("unhandled id <%s>", propertyName(id));
1363                   return QVariant();
1364             }
1365       }
1366 
1367 //---------------------------------------------------------
1368 //   setProperty
1369 //---------------------------------------------------------
1370 
setProperty(Pid id,const QVariant & v)1371 bool Staff::setProperty(Pid id, const QVariant& v)
1372       {
1373       switch (id) {
1374             case Pid::SMALL: {
1375                   qreal _spatium = spatium(Fraction(0,1));
1376                   staffType(Fraction(0,1))->setSmall(v.toBool());
1377                   localSpatiumChanged(_spatium, spatium(Fraction(0,1)), Fraction(0, 1));
1378                   break;
1379                   }
1380             case Pid::MAG: {
1381                   qreal _spatium = spatium(Fraction(0,1));
1382                   staffType(Fraction(0,1))->setUserMag(v.toReal());
1383                   localSpatiumChanged(_spatium, spatium(Fraction(0,1)), Fraction(0, 1));
1384                   }
1385                   break;
1386             case Pid::STAFF_COLOR:
1387                   setColor(Fraction(0,1),v.value<QColor>());
1388                   break;
1389             case Pid::PLAYBACK_VOICE1:
1390                   setPlaybackVoice(0, v.toBool());
1391                   break;
1392             case Pid::PLAYBACK_VOICE2:
1393                   setPlaybackVoice(1, v.toBool());
1394                   break;
1395             case Pid::PLAYBACK_VOICE3:
1396                   setPlaybackVoice(2, v.toBool());
1397                   break;
1398             case Pid::PLAYBACK_VOICE4:
1399                   setPlaybackVoice(3, v.toBool());
1400                   break;
1401             case Pid::STAFF_BARLINE_SPAN: {
1402                   setBarLineSpan(v.toInt());
1403                   // update non-generated barlines
1404                   int track = idx() * VOICES;
1405                   std::vector<Element*> blList;
1406                   for (Measure* m = score()->firstMeasure(); m; m = m->nextMeasure()) {
1407                         Segment* s = m->getSegmentR(SegmentType::EndBarLine, m->ticks());
1408                         if (s && s->element(track))
1409                               blList.push_back(s->element(track));
1410                         if (Measure* mm = m->mmRest()) {
1411                               Segment* ss = mm->getSegmentR(SegmentType::EndBarLine, mm->ticks());
1412                               if (ss && ss->element(track))
1413                                     blList.push_back(ss->element(track));
1414                               }
1415                         }
1416                   for (Element* e : blList) {
1417                         if (e && e->isBarLine() && !e->generated())
1418                               toBarLine(e)->setSpanStaff(v.toInt());
1419                         }
1420                   }
1421                   break;
1422             case Pid::STAFF_BARLINE_SPAN_FROM:
1423                   setBarLineFrom(v.toInt());
1424                   break;
1425             case Pid::STAFF_BARLINE_SPAN_TO:
1426                   setBarLineTo(v.toInt());
1427                   break;
1428             case Pid::STAFF_USERDIST:
1429                   setUserDist(v.toReal());
1430                   break;
1431             default:
1432                   qDebug("unhandled id <%s>", propertyName(id));
1433                   break;
1434             }
1435       triggerLayout();
1436       return true;
1437       }
1438 
1439 //---------------------------------------------------------
1440 //   propertyDefault
1441 //---------------------------------------------------------
1442 
propertyDefault(Pid id) const1443 QVariant Staff::propertyDefault(Pid id) const
1444       {
1445       switch (id) {
1446             case Pid::SMALL:
1447                   return false;
1448             case Pid::MAG:
1449                   return 1.0;
1450             case Pid::STAFF_COLOR:
1451                   return QColor(Qt::black);
1452             case Pid::PLAYBACK_VOICE1:
1453             case Pid::PLAYBACK_VOICE2:
1454             case Pid::PLAYBACK_VOICE3:
1455             case Pid::PLAYBACK_VOICE4:
1456                   return true;
1457             case Pid::STAFF_BARLINE_SPAN:
1458                   return false;
1459             case Pid::STAFF_BARLINE_SPAN_FROM:
1460             case Pid::STAFF_BARLINE_SPAN_TO:
1461                   return 0;
1462             case Pid::STAFF_USERDIST:
1463                   return qreal(0.0);
1464             default:
1465                   qDebug("unhandled id <%s>", propertyName(id));
1466                   return QVariant();
1467             }
1468       }
1469 
1470 //---------------------------------------------------------
1471 //   localSpatiumChanged
1472 //---------------------------------------------------------
1473 
localSpatiumChanged(double oldVal,double newVal,Fraction tick)1474 void Staff::localSpatiumChanged(double oldVal, double newVal, Fraction tick)
1475       {
1476       const int intEndTick = _staffTypeList.staffTypeRange(tick).second;
1477       const Fraction etick = (intEndTick == -1) ? score()->lastMeasure()->endTick() : Fraction::fromTicks(intEndTick);
1478 
1479       int staffIdx = idx();
1480       int startTrack = staffIdx * VOICES;
1481       int endTrack = startTrack + VOICES;
1482       for (Segment* s = score()->tick2rightSegment(tick); s && s->tick() < etick; s = s->next1()) {
1483             for (Element* e : s->annotations()) {
1484                   if (e->track() >= startTrack && e->track() < endTrack)
1485                         e->localSpatiumChanged(oldVal, newVal);
1486                   }
1487             for (int track = startTrack; track < endTrack; ++track) {
1488                   if (s->element(track))
1489                         s->element(track)->localSpatiumChanged(oldVal, newVal);
1490                   }
1491             }
1492       auto spanners = score()->spannerMap().findContained(tick.ticks(), etick.ticks());
1493       for (auto interval : spanners) {
1494             Spanner* spanner = interval.value;
1495             if (spanner->staffIdx() == staffIdx) {
1496                   for (auto k : spanner->spannerSegments())
1497                         k->localSpatiumChanged(oldVal, newVal);
1498                   }
1499             }
1500       }
1501 
1502 //---------------------------------------------------------
1503 //   isPitchedStaff
1504 //---------------------------------------------------------
1505 
isPitchedStaff(const Fraction & tick) const1506 bool Staff::isPitchedStaff(const Fraction& tick) const
1507       {
1508       //return staffType(tick)->group() == StaffGroup::STANDARD;
1509       return (staffType(tick)->group() != StaffGroup::TAB && !part()->instrument(tick)->useDrumset());
1510       }
1511 
1512 //---------------------------------------------------------
1513 //   isTabStaff
1514 //---------------------------------------------------------
1515 
isTabStaff(const Fraction & tick) const1516 bool Staff::isTabStaff(const Fraction& tick) const
1517       {
1518       return staffType(tick)->group() == StaffGroup::TAB;
1519       }
1520 
1521 //---------------------------------------------------------
1522 //   isDrumStaff
1523 //---------------------------------------------------------
1524 
isDrumStaff(const Fraction & tick) const1525 bool Staff::isDrumStaff(const Fraction& tick) const
1526       {
1527       //check for instrument instead of staffType (for pitched to unpitched instr. changes)
1528       return part()->instrument(tick)->useDrumset();
1529       }
1530 
1531 //---------------------------------------------------------
1532 //   lines
1533 //---------------------------------------------------------
1534 
lines(const Fraction & tick) const1535 int Staff::lines(const Fraction& tick) const
1536       {
1537       return staffType(tick)->lines();
1538       }
1539 
1540 //---------------------------------------------------------
1541 //   setLines
1542 //---------------------------------------------------------
1543 
setLines(const Fraction & tick,int val)1544 void Staff::setLines(const Fraction& tick, int val)
1545       {
1546       staffType(tick)->setLines(val);
1547       }
1548 
1549 //---------------------------------------------------------
1550 //   lineDistance
1551 //    distance between staff lines
1552 //---------------------------------------------------------
1553 
lineDistance(const Fraction & tick) const1554 qreal Staff::lineDistance(const Fraction& tick) const
1555       {
1556       return staffType(tick)->lineDistance().val();
1557       }
1558 
1559 //---------------------------------------------------------
1560 //   invisible
1561 //---------------------------------------------------------
1562 
invisible(const Fraction & tick) const1563 bool Staff::invisible(const Fraction& tick) const
1564       {
1565       return staffType(tick)->invisible();
1566       }
1567 
1568 //---------------------------------------------------------
1569 //   setInvisible
1570 //---------------------------------------------------------
1571 
setInvisible(const Fraction & tick,bool val)1572 void Staff::setInvisible(const Fraction& tick, bool val)
1573       {
1574       staffType(tick)->setInvisible(val);
1575       }
1576 
1577 }
1578 
1579