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