MuseScore/libmscore/staff.cpp

1300 lines
42 KiB
C++
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2002-2011 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#include "mscore.h"
#include "staff.h"
#include "part.h"
#include "clef.h"
#include "xml.h"
#include "score.h"
#include "bracket.h"
#include "keysig.h"
#include "segment.h"
#include "style.h"
#include "measure.h"
#include "stringdata.h"
2012-05-26 14:26:10 +02:00
#include "stafftype.h"
#include "undo.h"
#include "cleflist.h"
#include "timesig.h"
#include "instrtemplate.h"
#include "barline.h"
2013-07-16 09:03:47 +02:00
#include "ottava.h"
#include "harmony.h"
2012-05-26 14:26:10 +02:00
// #define DEBUG_CLEFS
#ifdef DEBUG_CLEFS
#define DUMP_CLEFS(s) dumpClefs(s)
#else
#define DUMP_CLEFS(s)
#endif
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// idx
//---------------------------------------------------------
int Staff::idx() const
{
return _score->staffIdx(this);
}
//---------------------------------------------------------
// bracket
//---------------------------------------------------------
BracketType Staff::bracket(int idx) const
{
if (idx < _brackets.size())
return _brackets[idx]._bracket;
return BracketType::NO_BRACKET;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// bracketSpan
//---------------------------------------------------------
int Staff::bracketSpan(int idx) const
{
if (idx < _brackets.size())
return _brackets[idx]._bracketSpan;
return 0;
}
//---------------------------------------------------------
// setBracket
//---------------------------------------------------------
void Staff::setBracket(int idx, BracketType val)
{
2012-10-12 15:36:57 +02:00
for (int i = _brackets.size(); i <= idx; ++i)
_brackets.append(BracketItem());
2012-05-26 14:26:10 +02:00
_brackets[idx]._bracket = val;
2016-02-06 22:03:43 +01:00
while (!_brackets.empty() && (_brackets.last()._bracket == BracketType::NO_BRACKET))
2012-05-26 14:26:10 +02:00
_brackets.removeLast();
}
//---------------------------------------------------------
// setBracketSpan
//---------------------------------------------------------
void Staff::setBracketSpan(int idx, int val)
{
2012-10-12 15:36:57 +02:00
Q_ASSERT(idx >= 0);
Q_ASSERT(val >= 0);
for (int i = _brackets.size(); i <= idx; ++i)
_brackets.append(BracketItem());
2012-05-26 14:26:10 +02:00
_brackets[idx]._bracketSpan = val;
}
//---------------------------------------------------------
// addBracket
//---------------------------------------------------------
void Staff::addBracket(BracketItem b)
{
2016-02-06 22:03:43 +01:00
if (!_brackets.empty() && _brackets[0]._bracket == BracketType::NO_BRACKET) {
2012-05-26 14:26:10 +02:00
_brackets[0] = b;
}
else {
//
// create new bracket level
//
foreach(Staff* s, _score->staves()) {
if (s == this)
s->_brackets.append(b);
else
s->_brackets.append(BracketItem());
}
}
}
2016-03-02 13:20:19 +01:00
//---------------------------------------------------------
// innerBracket
// Return type inner bracket.
// The bracket type determines the staff distance.
//---------------------------------------------------------
BracketType Staff::innerBracket() const
{
int staffIdx = idx();
BracketType t = BracketType::NO_BRACKET;
int level = 1000;
for (int i = 0; i < score()->nstaves(); ++i) {
Staff* staff = score()->staff(i);
for (int k = 0; k < staff->brackets().size(); ++k) {
const BracketItem& bi = staff->brackets().at(k);
2016-03-02 13:20:19 +01:00
if (bi._bracket != BracketType::NO_BRACKET) {
if (i < staffIdx && ((i + bi._bracketSpan) > staffIdx) && k < level) {
t = bi._bracket;
level = k;
break;
}
}
}
}
return t;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// cleanupBrackets
//---------------------------------------------------------
void Staff::cleanupBrackets()
{
int index = idx();
int n = _score->nstaves();
for (int i = 0; i < _brackets.size(); ++i) {
if (_brackets[i]._bracket == BracketType::NO_BRACKET)
2013-06-05 15:47:34 +02:00
continue;
int span = _brackets[i]._bracketSpan;
if (span > (n - index)) {
span = n - index;
_brackets[i]._bracketSpan = span;
2012-05-26 14:26:10 +02:00
}
}
for (int i = 0; i < _brackets.size(); ++i) {
if (_brackets[i]._bracket == BracketType::NO_BRACKET)
2013-06-05 15:47:34 +02:00
continue;
int span = _brackets[i]._bracketSpan;
if (span <= 1)
_brackets[i] = BracketItem();
else {
// delete all other brackets with same span
for (int k = i + 1; k < _brackets.size(); ++k) {
if (span == _brackets[k]._bracketSpan)
_brackets[k] = BracketItem();
2012-05-26 14:26:10 +02:00
}
}
}
}
//---------------------------------------------------------
// partName
//---------------------------------------------------------
QString Staff::partName() const
{
return _part->partName();
}
//---------------------------------------------------------
// Staff
//---------------------------------------------------------
2012-07-06 14:21:05 +02:00
Staff::Staff(Score* s)
: ScoreElement(s)
2012-07-06 14:21:05 +02:00
{
_barLineTo = (lines() - 1) * 2;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// ~Staff
//---------------------------------------------------------
Staff::~Staff()
{
if (_linkedStaves) {
_linkedStaves->remove(this);
2016-02-06 22:03:43 +01:00
if (_linkedStaves->empty())
2012-05-26 14:26:10 +02:00
delete _linkedStaves;
}
}
//---------------------------------------------------------
2014-08-16 11:21:56 +02:00
// Staff::clefType
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2014-08-16 11:21:56 +02:00
ClefTypeList Staff::clefType(int tick) const
2012-05-26 14:26:10 +02:00
{
ClefTypeList ct = clefs.clef(tick);
if (ct._concertClef == ClefType::INVALID) {
switch(_staffType.group()) {
2014-08-16 11:21:56 +02:00
case StaffGroup::TAB:
ct = ClefTypeList(ClefType(score()->styleI(StyleIdx::tabClef)));
break;
case StaffGroup::STANDARD:
2014-08-16 11:21:56 +02:00
ct = defaultClefType();
break;
case StaffGroup::PERCUSSION:
2014-08-16 11:21:56 +02:00
ct = ClefTypeList(ClefType::PERC);
break;
}
}
return ct;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// Staff::clef
//---------------------------------------------------------
ClefType Staff::clef(int tick) const
{
2014-08-16 11:21:56 +02:00
ClefTypeList c = clefType(tick);
2014-05-26 15:31:36 +02:00
return score()->styleB(StyleIdx::concertPitch) ? c._concertClef : c._transposingClef;
2012-05-26 14:26:10 +02:00
}
#ifndef NDEBUG
//---------------------------------------------------------
// dumpClef
//---------------------------------------------------------
void Staff::dumpClefs(const char* title) const
{
2015-02-14 17:17:07 +01:00
qDebug("dump clefs (%zd): %s", clefs.size(), title);
for (auto& i : clefs) {
qDebug(" %d: %d %d", i.first, int(i.second._concertClef), int(i.second._transposingClef));
}
}
//---------------------------------------------------------
// dumpKeys
//---------------------------------------------------------
void Staff::dumpKeys(const char* title) const
{
2015-02-14 17:17:07 +01:00
qDebug("dump keys (%zd): %s", _keys.size(), title);
for (auto& i : _keys) {
qDebug(" %d: %d", i.first, int(i.second.key()));
}
}
2015-02-16 12:12:23 +01:00
//---------------------------------------------------------
// dumpTimeSigs
//---------------------------------------------------------
void Staff::dumpTimeSigs(const char* title) const
{
qDebug("dump timesig size (%zd) staffIdx %d: %s", timesigs.size(), idx(), title);
for (auto& i : timesigs) {
qDebug(" %d: %d/%d", i.first, i.second->sig().numerator(), i.second->sig().denominator());
}
}
#endif
2013-09-05 16:37:49 +02:00
//---------------------------------------------------------
// setClef
//---------------------------------------------------------
2014-07-25 17:13:27 +02:00
void Staff::setClef(Clef* clef)
2013-09-05 16:37:49 +02:00
{
2014-08-05 14:10:22 +02:00
if (clef->generated())
return;
2014-07-25 17:13:27 +02:00
int tick = clef->segment()->tick();
for (Segment* s = clef->segment()->next(); s && s->tick() == tick; s = s->next()) {
if (s->segmentType() == Segment::Type::Clef && s->element(clef->track())) {
// adding this clef has no effect on the clefs list
return;
}
}
clefs.setClef(clef->segment()->tick(), clef->clefTypeList());
DUMP_CLEFS("setClef");
2013-09-05 16:37:49 +02:00
}
2014-05-08 17:59:24 +02:00
//---------------------------------------------------------
2014-07-25 17:13:27 +02:00
// removeClef
2014-05-08 17:59:24 +02:00
//---------------------------------------------------------
2014-07-25 17:13:27 +02:00
void Staff::removeClef(Clef* clef)
2013-09-05 16:37:49 +02:00
{
2014-08-05 14:10:22 +02:00
if (clef->generated())
return;
2014-07-25 17:13:27 +02:00
int tick = clef->segment()->tick();
for (Segment* s = clef->segment()->next(); s && s->tick() == tick; s = s->next()) {
if (s->segmentType() == Segment::Type::Clef && s->element(clef->track())) {
// removal of this clef has no effect on the clefs list
return;
}
}
clefs.erase(clef->segment()->tick());
for (Segment* s = clef->segment()->prev(); s && s->tick() == tick; s = s->prev()) {
if (s->segmentType() == Segment::Type::Clef
&& s->element(clef->track())
&& !s->element(clef->track())->generated()) {
2014-07-25 17:13:27 +02:00
// a previous clef at the same tick position gets valid
clefs.setClef(tick, static_cast<Clef*>(s->element(clef->track()))->clefTypeList());
break;
}
}
DUMP_CLEFS("removeClef");
2013-09-05 16:37:49 +02:00
}
//---------------------------------------------------------
2014-05-08 17:59:24 +02:00
// timeStretch
2013-09-05 16:37:49 +02:00
//---------------------------------------------------------
2014-05-08 17:59:24 +02:00
Fraction Staff::timeStretch(int tick) const
2013-09-05 16:37:49 +02:00
{
2014-05-08 17:59:24 +02:00
TimeSig* timesig = timeSig(tick);
return timesig == 0 ? Fraction(1,1) : timesig->stretch();
2013-09-05 16:37:49 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// timeSig
// lookup time signature before or at tick
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
TimeSig* Staff::timeSig(int tick) const
{
2013-05-06 14:20:31 +02:00
auto i = timesigs.upper_bound(tick);
if (i != timesigs.begin())
--i;
2014-11-27 13:04:03 +01:00
else if (tick < i->first)
return 0;
2013-05-06 14:20:31 +02:00
return (i == timesigs.end()) ? 0 : i->second;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// group
//---------------------------------------------------------
const Groups& Staff::group(int tick) const
{
TimeSig* ts = timeSig(tick);
if (ts) {
if (!ts->groups().empty())
return ts->groups();
2013-05-06 14:20:31 +02:00
return Groups::endings(ts->sig());
}
Measure* m = score()->tick2measure(tick);
2014-05-03 10:10:46 +02:00
return Groups::endings(m ? m->timesig() : Fraction(4,4));
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// addTimeSig
//---------------------------------------------------------
void Staff::addTimeSig(TimeSig* timesig)
{
if (timesig->segment()->segmentType() == Segment::Type::TimeSig)
timesigs[timesig->segment()->tick()] = timesig;
2015-02-16 12:12:23 +01:00
// dumpTimeSigs("after addTimeSig");
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// removeTimeSig
//---------------------------------------------------------
void Staff::removeTimeSig(TimeSig* timesig)
{
if (timesig->segment()->segmentType() == Segment::Type::TimeSig)
timesigs.erase(timesig->segment()->tick());
2015-02-16 12:12:23 +01:00
// dumpTimeSigs("after removeTimeSig");
2012-05-26 14:26:10 +02:00
}
2014-11-27 13:04:03 +01:00
//---------------------------------------------------------
// clearTimeSig
//---------------------------------------------------------
void Staff::clearTimeSig()
{
timesigs.clear();
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2015-06-13 17:57:57 +02:00
// Staff::keySigEvent
//
// locates the key sig currently in effect at tick
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
KeySigEvent Staff::keySigEvent(int tick) const
2012-05-26 14:26:10 +02:00
{
2014-06-03 15:28:10 +02:00
return _keys.key(tick);
}
2014-06-04 10:20:14 +02:00
//---------------------------------------------------------
// setKey
//---------------------------------------------------------
void Staff::setKey(int tick, KeySigEvent k)
2014-06-04 10:20:14 +02:00
{
_keys.setKey(tick, k);
// dumpKeys("setKey");
2014-06-04 10:20:14 +02:00
}
//---------------------------------------------------------
// removeKey
//---------------------------------------------------------
void Staff::removeKey(int tick)
{
2014-07-17 09:32:30 +02:00
_keys.erase(tick);
// dumpKeys("removeKey");
2014-06-04 10:20:14 +02:00
}
2014-06-03 15:28:10 +02:00
//---------------------------------------------------------
// prevkey
//---------------------------------------------------------
KeySigEvent Staff::prevKey(int tick) const
2014-06-03 15:28:10 +02:00
{
return _keys.prevKey(tick);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// Staff::nextKeyTick
//
// return the tick at which the key sig after tick is located
// return 0, if no such a key sig
//---------------------------------------------------------
int Staff::nextKeyTick(int tick) const
{
2014-06-03 15:28:10 +02:00
return _keys.nextKeyTick(tick);
}
//---------------------------------------------------------
// Staff::currentKeyTick
//
// return the tick position of the key currently
// in effect at tick
// return 0, if no such a key sig
//---------------------------------------------------------
int Staff::currentKeyTick(int tick) const
{
return _keys.currentKeyTick(tick);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// write
//---------------------------------------------------------
void Staff::write(Xml& xml) const
{
int idx = score()->staffIdx(this);
xml.stag(QString("Staff id=\"%1\"").arg(idx + 1));
2012-05-26 14:26:10 +02:00
if (linkedStaves()) {
Score* s = score();
if (s->parentScore())
s = s->parentScore();
foreach(Staff* staff, linkedStaves()->staves()) {
if ((staff->score() == s) && (staff != this))
xml.tag("linkedTo", s->staffIdx(staff) + 1);
}
}
2014-04-30 10:08:38 +02:00
2014-05-05 15:38:40 +02:00
// for copy/paste we need to know the actual transposition
if (xml.clipboardmode) {
Interval v = part()->instrument()->transpose(); // TODO: tick?
2014-05-05 15:38:40 +02:00
if (v.diatonic)
xml.tag("transposeDiatonic", v.diatonic);
if (v.chromatic)
xml.tag("transposeChromatic", v.chromatic);
}
2014-04-28 18:38:50 +02:00
_staffType.write(xml);
2014-08-16 11:21:56 +02:00
ClefTypeList ct = _defaultClefType;
if (ct._concertClef == ct._transposingClef) {
if (ct._concertClef != ClefType::G)
xml.tag("defaultClef", ClefInfo::tag(ct._concertClef));
}
else {
xml.tag("defaultConcertClef", ClefInfo::tag(ct._concertClef));
xml.tag("defaultTransposingClef", ClefInfo::tag(ct._transposingClef));
}
2014-04-30 10:08:38 +02:00
2012-05-26 14:26:10 +02:00
if (small() && !xml.excerptmode) // switch small staves to normal ones when extracting part
xml.tag("small", small());
if (invisible())
xml.tag("invisible", invisible());
2015-08-04 19:53:54 +02:00
if (hideWhenEmpty() != HideMode::AUTO)
xml.tag("hideWhenEmpty", int(hideWhenEmpty()));
if (cutaway())
xml.tag("cutaway", cutaway());
if (showIfEmpty())
xml.tag("showIfSystemEmpty", showIfEmpty());
2015-01-05 17:55:06 +01:00
if (_hideSystemBarLine)
xml.tag("hideSystemBarLine", _hideSystemBarLine);
2014-07-31 18:46:41 +02:00
for (const BracketItem& i : _brackets)
xml.tagE(QString("bracket type=\"%1\" span=\"%2\"").arg((signed char)(i._bracket)).arg(i._bracketSpan));
// for economy and consistency, only output "from" and "to" attributes if different from default
int defaultLineFrom = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0);
int defaultLineTo;
if (_barLineSpan == 0) // if no bar line at all
defaultLineTo = _barLineTo; // whatever the current spanTo is, use as default
else { // if some bar line, default is the default for span target staff
int targetStaffIdx = idx + _barLineSpan - 1;
if (targetStaffIdx >= score()->nstaves()) {
qFatal("bad _barLineSpan %d for staff %d (nstaves %d)",
_barLineSpan, idx, score()->nstaves());
}
int targetStaffLines = score()->staff(targetStaffIdx)->lines();
defaultLineTo = (targetStaffLines == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (targetStaffLines-1) * 2);
}
if (_barLineSpan != 1 || _barLineFrom != defaultLineFrom || _barLineTo != defaultLineTo) {
if(_barLineFrom != defaultLineFrom || _barLineTo != defaultLineTo)
xml.tag(QString("barLineSpan from=\"%1\" to=\"%2\"").arg(_barLineFrom).arg(_barLineTo), _barLineSpan);
else
xml.tag("barLineSpan", _barLineSpan);
}
2012-05-26 14:26:10 +02:00
if (_userDist != 0.0)
xml.tag("distOffset", _userDist / score()->spatium());
writeProperty(xml, P_ID::MAG);
writeProperty(xml, P_ID::COLOR);
2012-05-26 14:26:10 +02:00
xml.etag();
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
void Staff::read(XmlReader& e)
2012-05-26 14:26:10 +02:00
{
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
2014-04-30 10:08:38 +02:00
if (tag == "type") { // obsolete
int staffTypeIdx = e.readInt();
2014-08-13 15:42:40 +02:00
qDebug("obsolete: Staff::read staffTypeIdx %d", staffTypeIdx);
_staffType = *StaffType::preset(StaffTypes(staffTypeIdx));
// set default barLineFrom and barLineTo according to staff type num. of lines
// (1-line staff bar lines are special)
_barLineFrom = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0);
_barLineTo = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (lines() - 1) * 2);
2014-04-30 10:08:38 +02:00
}
2014-05-08 17:59:24 +02:00
else if (tag == "StaffType") {
2014-04-28 18:38:50 +02:00
_staffType.read(e);
// set default barLineFrom and barLineTo according to staff type num. of lines
// (1-line staff bar lines are special)
_barLineFrom = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0);
_barLineTo = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (lines() - 1) * 2);
2014-05-08 17:59:24 +02:00
}
2014-08-16 11:21:56 +02:00
else if (tag == "defaultClef") { // sets both default transposing and concert clef
QString val(e.readElementText());
ClefType ct = Clef::clefType(val);
setDefaultClefType(ClefTypeList(ct, ct));
}
else if (tag == "defaultConcertClef") {
QString val(e.readElementText());
setDefaultClefType(ClefTypeList(Clef::clefType(val), defaultClefType()._transposingClef));
}
else if (tag == "defaultTransposingClef") {
QString val(e.readElementText());
setDefaultClefType(ClefTypeList(defaultClefType()._concertClef, Clef::clefType(val)));
}
2012-05-26 14:26:10 +02:00
else if (tag == "small")
2013-01-11 18:10:18 +01:00
setSmall(e.readInt());
2012-05-26 14:26:10 +02:00
else if (tag == "invisible")
2013-01-11 18:10:18 +01:00
setInvisible(e.readInt());
2015-08-04 19:53:54 +02:00
else if (tag == "hideWhenEmpty")
setHideWhenEmpty(HideMode(e.readInt()));
else if (tag == "neverHide") { // 2.0 compatibility
bool v = e.readInt();
if (v)
setHideWhenEmpty(HideMode::NEVER);
}
else if (tag == "cutaway")
setCutaway(e.readInt());
else if (tag == "showIfSystemEmpty")
setShowIfEmpty(e.readInt());
2015-01-05 17:55:06 +01:00
else if (tag == "hideSystemBarLine")
_hideSystemBarLine = e.readInt();
2012-05-26 14:26:10 +02:00
else if (tag == "keylist")
2014-06-03 15:28:10 +02:00
_keys.read(e, _score);
2012-05-26 14:26:10 +02:00
else if (tag == "bracket") {
BracketItem b;
2013-01-17 12:56:14 +01:00
b._bracket = BracketType(e.intAttribute("type", -1));
2013-01-11 18:10:18 +01:00
b._bracketSpan = e.intAttribute("span", 0);
2012-05-26 14:26:10 +02:00
_brackets.append(b);
2013-01-17 12:56:14 +01:00
e.readNext();
2012-05-26 14:26:10 +02:00
}
2012-10-14 00:35:11 +02:00
else if (tag == "barLineSpan") {
// WARNING: following statement assumes number of staff lines to be correctly set
// must read <StaffType> before reading the <barLineSpan>
int defaultSpan = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0);
_barLineFrom = e.intAttribute("from", defaultSpan);
// the proper default SpanTo depends upon the barLineSpan
// as we do not know it yet, set a generic (UNKNOWN) default
defaultSpan = UNKNOWN_BARLINE_TO;
_barLineTo = e.intAttribute("to", defaultSpan);
// ready to read the main value...
_barLineSpan = e.readInt();
//...and to adjust the SpanTo value if the source did not provide an explicit value
// if no bar line or single staff span, set _barLineTo to this staff height
// if span to another staff (yet to be read), leave as unknown
// (Score::read() will retrieve the correct height of the target staff)
if (_barLineTo == UNKNOWN_BARLINE_TO && _barLineSpan <= 1)
_barLineTo = lines() == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (lines() - 1) * 2;
2012-10-14 00:35:11 +02:00
}
2012-05-26 14:26:10 +02:00
else if (tag == "distOffset")
_userDist = e.readDouble() * score()->spatium();
2015-01-15 14:50:50 +01:00
else if (tag == "mag")
_userMag = e.readDouble(0.1, 10.0);
2012-05-26 14:26:10 +02:00
else if (tag == "linkedTo") {
2013-01-11 18:10:18 +01:00
int v = e.readInt() - 1;
2012-05-26 14:26:10 +02:00
//
// if this is an excerpt, link staff to parentScore()
//
if (score()->parentScore()) {
2012-09-03 21:15:38 +02:00
Staff* st = score()->parentScore()->staff(v);
if (st)
linkTo(st);
else {
2012-09-20 11:35:34 +02:00
qDebug("staff %d not found in parent", v);
2012-09-03 21:15:38 +02:00
}
2012-05-26 14:26:10 +02:00
}
else {
int idx = score()->staffIdx(this);
if (v >= 0 && v < idx)
2012-05-26 14:26:10 +02:00
linkTo(score()->staff(v));
}
}
else if (tag == "color")
_color = e.readColor();
2014-05-05 15:38:40 +02:00
else if (tag == "transposeDiatonic")
e.setTransposeDiatonic(e.readInt());
else if (tag == "transposeChromatic")
e.setTransposeChromatic(e.readInt());
2012-05-26 14:26:10 +02:00
else
2013-01-11 18:10:18 +01:00
e.unknown();
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// height
//---------------------------------------------------------
qreal Staff::height() const
{
2014-06-19 15:27:44 +02:00
return (lines() == 1 ? 2 : lines()-1) * spatium() * _staffType.lineDistance().val();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// spatium
//---------------------------------------------------------
qreal Staff::spatium() const
{
return _score->spatium() * mag();
}
//---------------------------------------------------------
// mag
//---------------------------------------------------------
qreal Staff::mag() const
{
return (_small ? score()->styleD(StyleIdx::smallStaffMag) : 1.0) * userMag();
2012-05-26 14:26:10 +02:00
}
Implementation of text swing (step1) added swing tab swing settings tab in staff text properties Implemented step 2 of swing implementation using staff texts Added call for updateSwing in stafftextproperties Initial page for dialog changed System flag enabled for swing parameters saving and loading with text specified swing implemented removed extra print statement fixed formatting Added groupbox to make the default behavior to no change in swing fixed indentation in stafftextproperties fixing conflicts in staff.h Removed writing of setSwing to file Removed SwingParameter member from staff and fixed layout of swing tab in dialog fixed the issue with disabled controls Added tests for staff text implementation of swing playback cleaned up the code Swing playback using staff texts implemented, facilitating local control over swing parameters and tests for the same added Cleaned up code Cleaned up code further Swing Playback using staff texts implemented Cleaned up code further Cleaning up code further Using MScore::division in place of 480 as ticks Modified test files according to new usage of MScore::division Removed unwanted printf statements Using strings to write to xml rather than doubles for swingUnit Replaced 240 and 120 in terms of MScore::division in stafftext:write Using TDuration to write to xml Replaced string literals by TDuration for style parameters Replaced "off" with "" in style.cpp Set defaults for unit and ratio in constructors Removed usage of two structs for SwingParameters Changed order of assignments in setSwingParameters Swing playback using staff-texts implemented and tests added
2014-07-24 20:09:49 +02:00
//---------------------------------------------------------
// swing
//---------------------------------------------------------
SwingParameters Staff::swing(int tick) const
{
SwingParameters sp;
int swingUnit = 0;
Implementation of text swing (step1) added swing tab swing settings tab in staff text properties Implemented step 2 of swing implementation using staff texts Added call for updateSwing in stafftextproperties Initial page for dialog changed System flag enabled for swing parameters saving and loading with text specified swing implemented removed extra print statement fixed formatting Added groupbox to make the default behavior to no change in swing fixed indentation in stafftextproperties fixing conflicts in staff.h Removed writing of setSwing to file Removed SwingParameter member from staff and fixed layout of swing tab in dialog fixed the issue with disabled controls Added tests for staff text implementation of swing playback cleaned up the code Swing playback using staff texts implemented, facilitating local control over swing parameters and tests for the same added Cleaned up code Cleaned up code further Swing Playback using staff texts implemented Cleaned up code further Cleaning up code further Using MScore::division in place of 480 as ticks Modified test files according to new usage of MScore::division Removed unwanted printf statements Using strings to write to xml rather than doubles for swingUnit Replaced 240 and 120 in terms of MScore::division in stafftext:write Using TDuration to write to xml Replaced string literals by TDuration for style parameters Replaced "off" with "" in style.cpp Set defaults for unit and ratio in constructors Removed usage of two structs for SwingParameters Changed order of assignments in setSwingParameters Swing playback using staff-texts implemented and tests added
2014-07-24 20:09:49 +02:00
QString unit = score()->styleSt(StyleIdx::swingUnit);
int swingRatio = score()->styleI(StyleIdx::swingRatio);
if (unit == TDuration(TDuration::DurationType::V_EIGHTH).name()) {
Implementation of text swing (step1) added swing tab swing settings tab in staff text properties Implemented step 2 of swing implementation using staff texts Added call for updateSwing in stafftextproperties Initial page for dialog changed System flag enabled for swing parameters saving and loading with text specified swing implemented removed extra print statement fixed formatting Added groupbox to make the default behavior to no change in swing fixed indentation in stafftextproperties fixing conflicts in staff.h Removed writing of setSwing to file Removed SwingParameter member from staff and fixed layout of swing tab in dialog fixed the issue with disabled controls Added tests for staff text implementation of swing playback cleaned up the code Swing playback using staff texts implemented, facilitating local control over swing parameters and tests for the same added Cleaned up code Cleaned up code further Swing Playback using staff texts implemented Cleaned up code further Cleaning up code further Using MScore::division in place of 480 as ticks Modified test files according to new usage of MScore::division Removed unwanted printf statements Using strings to write to xml rather than doubles for swingUnit Replaced 240 and 120 in terms of MScore::division in stafftext:write Using TDuration to write to xml Replaced string literals by TDuration for style parameters Replaced "off" with "" in style.cpp Set defaults for unit and ratio in constructors Removed usage of two structs for SwingParameters Changed order of assignments in setSwingParameters Swing playback using staff-texts implemented and tests added
2014-07-24 20:09:49 +02:00
swingUnit = MScore::division / 2;
}
else if (unit == TDuration(TDuration::DurationType::V_16TH).name())
swingUnit = MScore::division / 4;
else if (unit == TDuration(TDuration::DurationType::V_ZERO).name())
swingUnit = 0;
sp.swingRatio = swingRatio;
sp.swingUnit = swingUnit;
2016-02-06 22:03:43 +01:00
if (_swingList.empty())
Implementation of text swing (step1) added swing tab swing settings tab in staff text properties Implemented step 2 of swing implementation using staff texts Added call for updateSwing in stafftextproperties Initial page for dialog changed System flag enabled for swing parameters saving and loading with text specified swing implemented removed extra print statement fixed formatting Added groupbox to make the default behavior to no change in swing fixed indentation in stafftextproperties fixing conflicts in staff.h Removed writing of setSwing to file Removed SwingParameter member from staff and fixed layout of swing tab in dialog fixed the issue with disabled controls Added tests for staff text implementation of swing playback cleaned up the code Swing playback using staff texts implemented, facilitating local control over swing parameters and tests for the same added Cleaned up code Cleaned up code further Swing Playback using staff texts implemented Cleaned up code further Cleaning up code further Using MScore::division in place of 480 as ticks Modified test files according to new usage of MScore::division Removed unwanted printf statements Using strings to write to xml rather than doubles for swingUnit Replaced 240 and 120 in terms of MScore::division in stafftext:write Using TDuration to write to xml Replaced string literals by TDuration for style parameters Replaced "off" with "" in style.cpp Set defaults for unit and ratio in constructors Removed usage of two structs for SwingParameters Changed order of assignments in setSwingParameters Swing playback using staff-texts implemented and tests added
2014-07-24 20:09:49 +02:00
return sp;
QMap<int, SwingParameters>::const_iterator i = _swingList.upperBound(tick);
if (i == _swingList.begin())
return sp;
--i;
return i.value();
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// channel
//---------------------------------------------------------
int Staff::channel(int tick, int voice) const
{
2016-02-06 22:03:43 +01:00
if (_channelList[voice].empty())
2012-05-26 14:26:10 +02:00
return 0;
QMap<int, int>::const_iterator i = _channelList[voice].upperBound(tick);
2012-05-26 14:26:10 +02:00
if (i == _channelList[voice].begin())
return 0;
2012-05-26 14:26:10 +02:00
--i;
return i.value();
}
//---------------------------------------------------------
// lines
//---------------------------------------------------------
int Staff::lines() const
{
2014-04-28 18:38:50 +02:00
return _staffType.lines();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// setLines
//---------------------------------------------------------
void Staff::setLines(int val)
{
if (val == lines())
return;
2014-04-28 18:38:50 +02:00
_staffType.setLines(val); // TODO: make undoable
2012-05-26 14:26:10 +02:00
}
2012-10-14 00:35:11 +02:00
//---------------------------------------------------------
2015-06-13 17:57:57 +02:00
// lineDistance
// distance between staff lines
2012-10-14 00:35:11 +02:00
//---------------------------------------------------------
qreal Staff::lineDistance() const
{
2014-04-28 18:38:50 +02:00
return _staffType.lineDistance().val();
2012-10-14 00:35:11 +02:00
}
//---------------------------------------------------------
// logicalLineDistance
// distance between logical (note) lines
//---------------------------------------------------------
qreal Staff::logicalLineDistance() const
{
return scaleNotesToLines() ? _staffType.lineDistance().val() : 1.0;
}
//---------------------------------------------------------
// scaleNotesToLines
// returns true if logical line = physical line
//---------------------------------------------------------
bool Staff::scaleNotesToLines() const
{
// TODO: make style option
2015-09-01 20:18:28 +02:00
return !isDrumStaff();
}
//---------------------------------------------------------
// middleLine
// returns logical line number of middle staff line
//---------------------------------------------------------
int Staff::middleLine() const
{
int line = lines() - 1;
2015-09-01 20:18:28 +02:00
if (scaleNotesToLines())
return line;
else
return line * lineDistance() / logicalLineDistance();
//return isTabStaff() ? line : line * lineDistance() / logicalLineDistance();
}
//---------------------------------------------------------
// bottomLine
// returns logical line number of bottom staff line
//---------------------------------------------------------
int Staff::bottomLine() const
{
int line = (lines() - 1) * 2;
2015-09-01 20:18:28 +02:00
if (scaleNotesToLines())
return line;
else
return line * lineDistance() / logicalLineDistance();
//return isTabStaff() ? line : line * lineDistance() / logicalLineDistance();
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// slashStyle
//---------------------------------------------------------
bool Staff::slashStyle() const
{
2014-04-28 18:38:50 +02:00
return _staffType.slashStyle();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// setSlashStyle
//---------------------------------------------------------
void Staff::setSlashStyle(bool val)
{
2014-04-28 18:38:50 +02:00
_staffType.setSlashStyle(val);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// linkTo
//---------------------------------------------------------
void Staff::linkTo(Staff* staff)
{
if (!_linkedStaves) {
if (staff->linkedStaves()) {
_linkedStaves = staff->linkedStaves();
}
else {
_linkedStaves = new LinkedStaves;
_linkedStaves->add(staff);
staff->setLinkedStaves(_linkedStaves);
}
_linkedStaves->add(this);
}
else {
2013-07-16 18:16:16 +02:00
_linkedStaves->add(staff);
2014-05-22 16:18:35 +02:00
if (!staff->linkedStaves())
staff->_linkedStaves = _linkedStaves;
2012-05-26 14:26:10 +02:00
}
}
2014-08-01 16:21:39 +02:00
//---------------------------------------------------------
// unlink
//---------------------------------------------------------
void Staff::unlink(Staff* staff)
{
2014-08-11 15:25:55 +02:00
if (!_linkedStaves)
return;
if (!_linkedStaves->staves().contains(staff))
return;
2014-08-01 16:21:39 +02:00
_linkedStaves->remove(staff);
2014-08-07 19:39:18 +02:00
if (_linkedStaves->staves().size() <= 1) {
delete _linkedStaves;
_linkedStaves = 0;
}
staff->_linkedStaves = 0;
2014-08-01 16:21:39 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// add
//---------------------------------------------------------
void LinkedStaves::add(Staff* staff)
{
if (!_staves.contains(staff))
_staves.append(staff);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void LinkedStaves::remove(Staff* staff)
{
_staves.removeOne(staff);
}
//---------------------------------------------------------
// isLinked
/// return true if staff is different and
/// linked to this staff
//---------------------------------------------------------
2014-04-24 15:03:03 +02:00
bool Staff::isLinked(Staff* staff)
{
if (staff == this || !_linkedStaves)
return false;
for(Staff* s : _linkedStaves->staves()) {
if(s == staff)
return true;
}
return false;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// primaryStaff
/// if there are linked staves, the primary staff is
2015-06-22 17:59:08 +02:00
/// the one who is played back and it's not a tab staff
/// because we don't have enough information to play
/// e.g ornaments. NOTE: it's not necessarily the top staff!
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
bool Staff::primaryStaff() const
{
if (!_linkedStaves)
return true;
2015-06-22 18:19:05 +02:00
QList<Staff*> s;
QList<Staff*> ss;
2012-05-26 14:26:10 +02:00
foreach(Staff* staff, _linkedStaves->staves()) {
2015-06-22 18:19:05 +02:00
if (staff->score() == score()) {
2012-05-26 14:26:10 +02:00
s.append(staff);
2015-06-22 18:19:05 +02:00
if (!staff->isTabStaff())
ss.append(staff);
}
2012-05-26 14:26:10 +02:00
}
2015-06-22 18:19:05 +02:00
if (s.size() == 1) // the linked staves are in different scores
return s.front() == this;
else // return a non tab linked staff in this score
return ss.front() == this;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// setStaffType
//---------------------------------------------------------
2014-04-28 18:38:50 +02:00
void Staff::setStaffType(const StaffType* st)
2012-05-26 14:26:10 +02:00
{
2014-05-03 11:33:47 +02:00
if (_staffType == *st)
return;
int linesOld = lines();
int linesNew = st->lines();
2014-04-28 18:38:50 +02:00
_staffType = *st;
if (linesNew != linesOld) {
int sIdx = score()->staffIdx(this);
if (sIdx < 0) { // staff does not belong to score (yet?)
if (linesNew == 1) { // 1-line staves have special bar lines
_barLineFrom = BARLINE_SPAN_1LINESTAFF_FROM;
_barLineTo = BARLINE_SPAN_1LINESTAFF_TO;
}
else { // set default barLineFrom/to (from first to last staff line)
_barLineFrom = 0;
_barLineTo = (linesNew-1)*2;
}
}
else // update barLineFrom/To in whole score context
score()->updateBarLineSpans(sIdx, linesOld, linesNew /*, true*/);
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// init
//---------------------------------------------------------
void Staff::init(const InstrumentTemplate* t, const StaffType* staffType, int cidx)
2012-05-26 14:26:10 +02:00
{
// set staff-type-independent parameters
if (cidx > MAX_STAVES) {
setSmall(false);
}
else {
setSmall(t->smallStaff[cidx]);
setBracket(0, t->bracket[cidx]);
setBracketSpan(0, t->bracketSpan[cidx]);
setBarLineSpan(t->barlineSpan[cidx]);
}
2014-04-30 10:08:38 +02:00
const StaffType* pst = staffType ? staffType : t->staffTypePreset;
if (!pst)
pst = StaffType::getDefaultPreset(t->staffGroup);
2012-05-26 14:26:10 +02:00
2014-04-30 10:08:38 +02:00
setStaffType(pst);
2014-08-16 11:21:56 +02:00
setDefaultClefType(t->clefType(cidx));
}
//---------------------------------------------------------
// init
//---------------------------------------------------------
void Staff::init(const Staff* s)
{
setStaffType(s->staffType());
setDefaultClefType(s->defaultClefType());
setSmall(s->small());
_brackets = s->_brackets;
_barLineSpan = s->_barLineSpan;
_barLineFrom = s->_barLineFrom;
_barLineTo = s->_barLineTo;
_invisible = s->_invisible;
2015-08-04 19:53:54 +02:00
_hideWhenEmpty = s->_hideWhenEmpty;
_cutaway = s->_cutaway;
_showIfEmpty = s->_showIfEmpty;
_hideSystemBarLine = s->_hideSystemBarLine;
_color = s->_color;
_userDist = s->_userDist;
_userMag = s->_userMag;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// initFromStaffType
//---------------------------------------------------------
void Staff::initFromStaffType(const StaffType* staffType)
{
// get staff type if given (if none, get default preset for default staff group)
2014-04-30 10:08:38 +02:00
if (!staffType)
staffType = StaffType::getDefaultPreset(StaffGroup::STANDARD);
// use selected staff type
2014-04-28 18:38:50 +02:00
setStaffType(staffType);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// spatiumChanged
//---------------------------------------------------------
void Staff::spatiumChanged(qreal oldValue, qreal newValue)
{
_userDist = (_userDist / oldValue) * newValue;
}
//---------------------------------------------------------
// show
//---------------------------------------------------------
bool Staff::show() const
{
return _part->show();
}
2013-07-16 09:03:47 +02:00
//---------------------------------------------------------
// genKeySig
//---------------------------------------------------------
bool Staff::genKeySig()
{
if (_staffType.group() == StaffGroup::TAB)
2014-04-28 18:38:50 +02:00
return false;
else
return _staffType.genKeysig();
}
2013-07-16 09:03:47 +02:00
//---------------------------------------------------------
// showLedgerLines
//---------------------------------------------------------
bool Staff::showLedgerLines()
{
TAB: Support for input and display of bass string notations Supports 'standard' configuration for bass string notations in historic tablatures (lutes and other plucked instruments, as well as viols), both of the French and of the Italian style. This should fill the last 'big hole' in historic TAB support. Bass strings (or bourdons) are extra strings in addition to the 6 'standard' strings, which are not represented by tab lines and were indicated by other typograhic devices in historic sources. Among the innumerable variations shown in sources, this implementation supports the following styles, chosen to be general enough to suit the majority of cases, without requiring new parameters in the TAB style dialogue box: - French: the first 4 bass courses are indicated by a fret mark in the 'seventh' TAB position (below bottom string) with 0, 1, 2 or 3 slashes prefixed; other bass courses are indicated, also in the 'seventh' TAB position, by the string number (from 4 on) and cannot contain a fret mark (as they didn't in historic sources). - Italian: the first 2 bass courses are indicated by a fret mark in the 'seventh' TAB position (abover top string) with 1 or 2 'ledger lines' underneath; other bass courses are indicated, also in the 'seventh' TAB position, by the string number (from 9 on) and cannot contain a fret mark (as they didn't in historic sources). Rhythm marks above these indication are raised to leave room for them. Both styles do not blindly assume that French style is top-to-bottom and Italian is 'upside-down' -- as historic sources are -- but adapt to the actual string order of the TAB. The choice between the two styles depends on the TAB using numbers or letters for the fret marks. The implementation does not try to detect if the TAB is really of a historic style and applies either bass string notation whenever more strings are used than there are TAB lines. If this proves unsuitable to modern usage, some better heuristics can probably be found. For a discussion and some screen shots, see: https://musescore.org/en/node/67261 **Note entry** During TAB note entry, if the instruments has more strings than the TAB has lines, the string cursor can be moved outside of the TAB body, one position below for 'top-to-bottom' TAB's and one position above for 'upside-down' TAB's. Further up or down movements add, to the 'blue cursor rectangle', markers indicating which is the actual target string (the cursor does not actually move), equal to the marks a note in that string will receive (slashes, ledger lines or string ordinal, according to the style and the string); during input the user will then receive the same info as when reading entered notes. Other Notes: - the `InputStatus::_string` variable, holding the current target TAB string in TAB note entry, changed meaning from the __visual__ string index to the __physical__ string index: this allows a better containment of the peculiarities of the individual TAB styles within the `StaffStyle` class, leaving other classes somehow freer of concern about TAB visual order and other peculiarities. As this variable is only used with TAB's, this change should not affect other functions. - Some calculation for rhythm symbols have been moved from `TabDurationSymbol::draw()` to `TabDurationSymbol::layout()`, hopefully speeding up the drawing process. - In fonts for historic styles, '10' has been replaced by 'X' both in fret numbers and in string ordinals, as this is more common in historic sources. Currently, this is not configurable; an additional style parameter could be added in future, if there will be enough request for it.
2015-07-06 17:40:02 +02:00
return _staffType.showLedgerLines();
}
2013-07-16 09:03:47 +02:00
//---------------------------------------------------------
// updateOttava
//---------------------------------------------------------
2014-07-15 12:49:51 +02:00
void Staff::updateOttava()
{
int staffIdx = idx();
_pitchOffsets.clear();
for (auto i : score()->spanner()) {
const Spanner* s = i.second;
if (s->type() == Element::Type::OTTAVA && s->staffIdx() == staffIdx) {
const Ottava* o = static_cast<const Ottava*>(s);
_pitchOffsets.setPitchOffset(o->tick(), o->pitchShift());
_pitchOffsets.setPitchOffset(o->tick2(), 0);
}
}
2013-07-16 09:03:47 +02:00
}
//---------------------------------------------------------
// undoSetColor
//---------------------------------------------------------
2014-01-15 22:05:05 +01:00
void Staff::undoSetColor(const QColor& /*val*/)
{
2014-05-26 18:18:01 +02:00
// score()->undoChangeProperty(this, P_ID::COLOR, val);
}
2014-05-08 17:59:24 +02:00
//---------------------------------------------------------
// insertTime
//---------------------------------------------------------
void Staff::insertTime(int tick, int len)
{
if (len == 0)
return;
// move all keys and clefs >= tick
if (len < 0) {
// remove entries between tickpos >= tick and tickpos < (tick+len)
_keys.erase(_keys.lower_bound(tick), _keys.lower_bound(tick-len));
clefs.erase(clefs.lower_bound(tick), clefs.lower_bound(tick-len));
}
2014-05-08 17:59:24 +02:00
KeyList kl2;
for (auto i = _keys.lower_bound(tick); i != _keys.end();) {
KeySigEvent kse = i->second;
int tick = i->first;
2014-06-03 15:28:10 +02:00
_keys.erase(i++);
kl2[tick + len] = kse;
2014-05-08 17:59:24 +02:00
}
2014-06-03 15:28:10 +02:00
_keys.insert(kl2.begin(), kl2.end());
2014-05-08 17:59:24 +02:00
// check if there is a clef at the end of measure
// before tick
Clef* clef = 0;
Measure* m = _score->tick2measure(tick);
if (m && (m->tick() == tick) && (m->prevMeasure())) {
m = m->prevMeasure();
Segment* s = m->findSegment(Segment::Type::Clef, tick);
if (s) {
int track = idx() * VOICES;
clef = static_cast<Clef*>(s->element(track));
}
}
2014-05-08 17:59:24 +02:00
ClefList cl2;
for (auto i = clefs.lower_bound(tick); i != clefs.end();) {
2014-05-08 17:59:24 +02:00
ClefTypeList ctl = i->second;
int t = i->first;
if (clef && tick == t) {
++i;
continue;
}
2014-05-08 17:59:24 +02:00
clefs.erase(i++);
cl2.setClef(t + len, ctl);
2014-05-08 17:59:24 +02:00
}
clefs.insert(cl2.begin(), cl2.end());
// check if there is a clef at the end of measure
// before tick: do not remove from clefs list
if (clef)
setClef(clef);
updateOttava();
DUMP_CLEFS(" insertTime");
2014-05-08 17:59:24 +02:00
}
2014-05-21 20:08:37 +02:00
//---------------------------------------------------------
// staffList
// return list of linked staves
//---------------------------------------------------------
QList<Staff*> Staff::staffList() const
{
QList<Staff*> staffList;
if (_linkedStaves)
staffList = _linkedStaves->staves();
else
staffList.append(const_cast<Staff*>(this));
return staffList;
}
2014-08-05 16:09:14 +02:00
//---------------------------------------------------------
// setBarLineTo
//---------------------------------------------------------
void Staff::setBarLineTo(int val)
{
_barLineTo = val;
}
2014-08-11 15:25:55 +02:00
//---------------------------------------------------------
// rstaff
//---------------------------------------------------------
int Staff::rstaff() const
{
return _part->staves()->indexOf((Staff*)this, 0);
}
//---------------------------------------------------------
// isTop
//---------------------------------------------------------
bool Staff::isTop() const
{
return _part->staves()->front() == this;
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
QVariant Staff::getProperty(P_ID id) const
{
switch (id) {
case P_ID::MAG:
return userMag();
case P_ID::COLOR:
return color();
case P_ID::SMALL:
return small();
default:
qDebug("Staff::getProperty: unhandled id");
return QVariant();
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool Staff::setProperty(P_ID id, const QVariant& v)
{
switch (id) {
case P_ID::MAG: {
double oldVal = mag();
setUserMag(v.toDouble());
scaleChanged(oldVal, mag());
}
break;
case P_ID::COLOR:
setColor(v.value<QColor>());
break;
case P_ID::SMALL: {
double oldVal = mag();
setSmall(v.toBool());
scaleChanged(oldVal, mag());
}
break;
default:
qDebug("Staff::setProperty: unhandled id");
break;
}
2016-03-02 13:20:19 +01:00
score()->setLayoutAll();
return true;
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
QVariant Staff::propertyDefault(P_ID id) const
{
switch (id) {
case P_ID::MAG:
return 1.0;
case P_ID::COLOR:
return QColor(Qt::black);
case P_ID::SMALL:
return false;
default:
return QVariant();
}
}
//---------------------------------------------------------
// scaleChanged
//---------------------------------------------------------
void Staff::scaleChanged(double oldVal, double newVal)
{
int staffIdx = idx();
int startTrack = staffIdx * VOICES;
int endTrack = startTrack + VOICES;
for (Segment* s = score()->firstSegment(); s; s = s->next1()) {
for (Element* e : s->annotations())
e->localSpatiumChanged(oldVal, newVal);
for (int track = startTrack; track < endTrack; ++track) {
if (s->element(track))
s->element(track)->localSpatiumChanged(oldVal, newVal);
}
}
for (auto i : score()->spanner()) {
Spanner* spanner = i.second;
if (spanner->staffIdx() == staffIdx) {
for (auto k : spanner->spannerSegments())
k->localSpatiumChanged(oldVal, newVal);
}
}
}
2013-05-13 18:49:17 +02:00
}