MuseScore/libmscore/measure.cpp

4339 lines
163 KiB
C++
Raw Normal View History

//=============================================================================
2012-05-26 14:26:10 +02:00
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2002-2016 Werner Schweer
2012-05-26 14:26:10 +02:00
//
// 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
//=============================================================================
/**
\file
Implementation of most part of class Measure.
*/
#include "measure.h"
#include "accidental.h"
#include "ambitus.h"
#include "articulation.h"
#include "barline.h"
#include "beam.h"
#include "box.h"
#include "bracket.h"
#include "breath.h"
2012-05-26 14:26:10 +02:00
#include "chord.h"
#include "clef.h"
#include "drumset.h"
#include "duration.h"
2012-05-26 14:26:10 +02:00
#include "dynamic.h"
#include "fermata.h"
#include "fret.h"
#include "glissando.h"
2012-05-26 14:26:10 +02:00
#include "hairpin.h"
#include "harmony.h"
#include "hook.h"
#include "icon.h"
#include "image.h"
#include "key.h"
#include "keysig.h"
2012-05-26 14:26:10 +02:00
#include "layoutbreak.h"
#include "layout.h"
#include "note.h"
#include "ottava.h"
#include "page.h"
#include "part.h"
#include "pedal.h"
2012-05-26 14:26:10 +02:00
#include "pitchspelling.h"
#include "repeat.h"
#include "rest.h"
#include "score.h"
#include "segment.h"
#include "select.h"
#include "sig.h"
#include "slur.h"
2012-05-26 14:26:10 +02:00
#include "spacer.h"
#include "staff.h"
#include "stafftext.h"
2012-05-26 14:26:10 +02:00
#include "stafftype.h"
#include "stringdata.h"
#include "style.h"
#include "sym.h"
#include "system.h"
#include "tempotext.h"
2018-10-24 10:40:03 +02:00
#include "measurenumber.h"
#include "tie.h"
2012-05-26 14:26:10 +02:00
#include "tiemap.h"
#include "timesig.h"
#include "tremolo.h"
#include "trill.h"
#include "tuplet.h"
2012-05-26 14:26:10 +02:00
#include "tupletmap.h"
#include "undo.h"
#include "utils.h"
#include "volta.h"
#include "xml.h"
2016-02-10 13:40:34 +01:00
#include "systemdivider.h"
2016-12-18 14:31:13 +01:00
#include "stafftypechange.h"
2016-12-23 12:05:18 +01:00
#include "stafflines.h"
2017-03-31 13:03:15 +02:00
#include "bracketItem.h"
2012-05-26 14:26:10 +02:00
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// MStaff
2016-12-12 14:55:35 +01:00
/// Per staff values of measure.
//---------------------------------------------------------
class MStaff {
2018-10-24 10:40:03 +02:00
MeasureNumber* _noText { 0 }; ///< Measure number text object
StaffLines* _lines { 0 };
Spacer* _vspacerUp { 0 };
Spacer* _vspacerDown { 0 };
bool _hasVoices { false }; ///< indicates that MStaff contains more than one voice,
2016-12-12 14:55:35 +01:00
///< this changes some layout rules
2018-10-24 10:40:03 +02:00
bool _visible { true };
bool _stemless { false };
2016-12-12 14:55:35 +01:00
#ifndef NDEBUG
2018-10-24 10:40:03 +02:00
bool _corrupted { false };
2016-12-12 14:55:35 +01:00
#endif
public:
MStaff() {}
~MStaff();
MStaff(const MStaff&);
void setScore(Score*);
void setTrack(int);
2018-10-24 10:40:03 +02:00
MeasureNumber* noText() const { return _noText; }
void setNoText(MeasureNumber* t) { _noText = t; }
2016-12-12 14:55:35 +01:00
StaffLines* lines() const { return _lines; }
void setLines(StaffLines* l) { _lines = l; }
Spacer* vspacerUp() const { return _vspacerUp; }
void setVspacerUp(Spacer* s) { _vspacerUp = s; }
Spacer* vspacerDown() const { return _vspacerDown; }
void setVspacerDown(Spacer* s) { _vspacerDown = s; }
bool hasVoices() const { return _hasVoices; }
void setHasVoices(bool val) { _hasVoices = val; }
bool visible() const { return _visible; }
void setVisible(bool val) { _visible = val; }
bool stemless() const { return _stemless; }
void setStemless(bool val) { _stemless = val; }
2016-12-12 14:55:35 +01:00
#ifndef NDEBUG
bool corrupted() const { return _corrupted; }
void setCorrupted(bool val) { _corrupted = val; }
2016-12-12 14:55:35 +01:00
#endif
};
2012-05-26 14:26:10 +02:00
MStaff::~MStaff()
{
delete _noText;
2016-12-12 12:02:18 +01:00
delete _lines;
2012-05-26 14:26:10 +02:00
delete _vspacerUp;
delete _vspacerDown;
}
MStaff::MStaff(const MStaff& m)
{
_noText = 0;
2016-12-12 12:02:18 +01:00
_lines = new StaffLines(*m._lines);
_hasVoices = m._hasVoices;
_vspacerUp = 0;
_vspacerDown = 0;
_visible = m._visible;
_stemless = m._stemless;
#ifndef NDEBUG
_corrupted = m._corrupted;
#endif
}
2016-12-12 12:02:18 +01:00
//---------------------------------------------------------
// MStaff::setScore
//---------------------------------------------------------
void MStaff::setScore(Score* score)
{
if (_lines)
_lines->setScore(score);
if (_vspacerUp)
_vspacerUp->setScore(score);
if (_vspacerDown)
_vspacerDown->setScore(score);
if (_noText)
_noText->setScore(score);
}
//---------------------------------------------------------
// setTrack
//---------------------------------------------------------
void MStaff::setTrack(int track)
{
if (_lines)
_lines->setTrack(track);
if (_vspacerUp)
_vspacerUp->setTrack(track);
if (_vspacerDown)
_vspacerDown->setTrack(track);
if (_noText)
_noText->setTrack(track);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// Measure
//---------------------------------------------------------
Measure::Measure(Score* s)
: MeasureBase(s), _timesig(4,4)
2012-05-26 14:26:10 +02:00
{
setTicks(Fraction(4,4));
2012-05-26 14:26:10 +02:00
_repeatCount = 2;
2016-03-10 10:41:31 +01:00
int n = score()->nstaves();
2016-01-04 14:48:58 +01:00
_mstaves.reserve(n);
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < n; ++staffIdx) {
MStaff* ms = new MStaff;
2012-05-26 14:26:10 +02:00
Staff* staff = score()->staff(staffIdx);
ms->setLines(new StaffLines(score()));
ms->lines()->setTrack(staffIdx * VOICES);
ms->lines()->setParent(this);
ms->lines()->setVisible(!staff->invisible());
_mstaves.push_back(ms);
2012-05-26 14:26:10 +02:00
}
2016-01-04 14:48:58 +01:00
setIrregular(false);
2016-02-04 11:27:47 +01:00
_noMode = MeasureNumberMode::AUTO;
2016-02-09 09:20:54 +01:00
_userStretch = 1.0;
2016-02-04 11:27:47 +01:00
_breakMultiMeasureRest = false;
_mmRest = 0;
_mmRestCount = 0;
setFlag(ElementFlag::MOVABLE, true);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// measure
//---------------------------------------------------------
Measure::Measure(const Measure& m)
: MeasureBase(m)
{
2016-02-04 11:27:47 +01:00
_segments = m._segments.clone();
_timesig = m._timesig;
_len = m._len;
_repeatCount = m._repeatCount;
_userStretch = m._userStretch;
2012-05-26 14:26:10 +02:00
2016-01-04 14:48:58 +01:00
_mstaves.reserve(m._mstaves.size());
for (MStaff* ms : m._mstaves)
2016-02-06 22:03:43 +01:00
_mstaves.push_back(new MStaff(*ms));
2012-05-26 14:26:10 +02:00
_breakMultiMeasureRest = m._breakMultiMeasureRest;
_mmRest = m._mmRest;
_mmRestCount = m._mmRestCount;
2012-05-26 14:26:10 +02:00
_playbackCount = m._playbackCount;
}
2016-12-12 14:55:35 +01:00
//---------------------------------------------------------
// layoutStaffLines
//---------------------------------------------------------
void Measure::layoutStaffLines()
{
for (MStaff* ms : _mstaves)
ms->lines()->layout();
}
//---------------------------------------------------------
// createStaves
//---------------------------------------------------------
void Measure::createStaves(int staffIdx)
{
for (int n = int(_mstaves.size()); n <= staffIdx; ++n) {
2016-12-12 14:55:35 +01:00
Staff* staff = score()->staff(n);
MStaff* s = new MStaff;
s->setLines(new StaffLines(score()));
s->lines()->setParent(this);
s->lines()->setTrack(n * VOICES);
s->lines()->setVisible(!staff->invisible());
_mstaves.push_back(s);
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// setScore
//---------------------------------------------------------
void Measure::setScore(Score* score)
{
MeasureBase::setScore(score);
for (Segment* s = first(); s; s = s->next())
s->setScore(score);
}
2016-12-12 14:55:35 +01:00
bool Measure::hasVoices(int staffIdx) const { return _mstaves[staffIdx]->hasVoices(); }
void Measure::setHasVoices(int staffIdx, bool v) { return _mstaves[staffIdx]->setHasVoices(v); }
StaffLines* Measure::staffLines(int staffIdx) { return _mstaves[staffIdx]->lines(); }
Spacer* Measure::vspacerDown(int staffIdx) const { return _mstaves[staffIdx]->vspacerDown(); }
Spacer* Measure::vspacerUp(int staffIdx) const { return _mstaves[staffIdx]->vspacerUp(); }
void Measure::setStaffVisible(int staffIdx, bool visible) { _mstaves[staffIdx]->setVisible(visible); }
void Measure::setStaffStemless(int staffIdx, bool stemless) { _mstaves[staffIdx]->setStemless(stemless); }
2018-10-24 10:40:03 +02:00
#ifndef NDEBUG
2016-12-12 14:55:35 +01:00
bool Measure::corrupted(int staffIdx) const { return _mstaves[staffIdx]->corrupted(); }
void Measure::setCorrupted(int staffIdx, bool val) { _mstaves[staffIdx]->setCorrupted(val); }
#endif
2018-10-24 10:40:03 +02:00
void Measure::setNoText(int staffIdx, MeasureNumber* t) { _mstaves[staffIdx]->setNoText(t); }
MeasureNumber* Measure::noText(int staffIdx) const { return _mstaves[staffIdx]->noText(); }
2016-12-12 14:55:35 +01:00
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// Measure
//---------------------------------------------------------
Measure::~Measure()
{
for (Segment* s = first(); s;) {
Segment* ns = s->next();
delete s;
s = ns;
}
2016-01-04 14:48:58 +01:00
qDeleteAll(_mstaves);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// AcEl
//---------------------------------------------------------
struct AcEl {
Note* note;
qreal x;
};
//---------------------------------------------------------
// findAccidental
2012-08-07 12:44:19 +02:00
/// return current accidental value at note position
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2012-08-08 20:46:29 +02:00
AccidentalVal Measure::findAccidental(Note* note) const
2012-05-26 14:26:10 +02:00
{
Chord* chord = note->chord();
2012-05-26 14:26:10 +02:00
AccidentalState tversatz; // state of already set accidentals for this measure
2017-02-13 12:42:54 +01:00
tversatz.init(chord->staff()->keySigEvent(tick()), chord->staff()->clef(tick()));
2012-05-26 14:26:10 +02:00
for (Segment* segment = first(); segment; segment = segment->next()) {
int startTrack = chord->staffIdx() * VOICES;
2016-10-18 15:41:00 +02:00
if (segment->isKeySigType()) {
KeySig* ks = toKeySig(segment->element(startTrack));
if (!ks)
2012-05-26 14:26:10 +02:00
continue;
2017-02-13 12:42:54 +01:00
tversatz.init(chord->staff()->keySigEvent(segment->tick()), chord->staff()->clef(segment->tick()));
}
2017-03-08 13:12:26 +01:00
else if (segment->segmentType() == SegmentType::ChordRest) {
int endTrack = startTrack + VOICES;
for (int track = startTrack; track < endTrack; ++track) {
Element* e = segment->element(track);
2016-10-18 15:41:00 +02:00
if (!e || !e->isChord())
continue;
Chord* crd = toChord(e);
for (Chord* chord1 : crd->graceNotes()) {
for (Note* note1 : chord1->notes()) {
if (note1->tieBack() && note1->accidental() == 0)
continue;
//
// compute accidental
//
int tpc = note1->tpc();
int line = absStep(tpc, note1->epitch());
if (note == note1)
return tversatz.accidentalVal(line);
tversatz.setAccidentalVal(line, tpc2alter(tpc));
}
}
for (Note* note1 : crd->notes()) {
if (note1->tieBack() && note1->accidental() == 0)
continue;
//
// compute accidental
//
int tpc = note1->tpc();
int line = absStep(tpc, note1->epitch());
2012-05-26 14:26:10 +02:00
if (note == note1)
return tversatz.accidentalVal(line);
tversatz.setAccidentalVal(line, tpc2alter(tpc));
}
}
2012-05-26 14:26:10 +02:00
}
}
qDebug("Measure::findAccidental: note not found");
return AccidentalVal::NATURAL;
2012-05-26 14:26:10 +02:00
}
2012-08-07 12:44:19 +02:00
//---------------------------------------------------------
// findAccidental
/// Compute accidental state at segment/staffIdx for
/// relative staff line.
//---------------------------------------------------------
AccidentalVal Measure::findAccidental(Segment* s, int staffIdx, int line, bool &error) const
2012-08-06 21:55:51 +02:00
{
AccidentalState tversatz; // state of already set accidentals for this measure
Staff* staff = score()->staff(staffIdx);
2017-02-13 12:42:54 +01:00
tversatz.init(staff->keySigEvent(tick()), staff->clef(tick()));
2012-08-06 21:55:51 +02:00
2017-03-08 13:12:26 +01:00
SegmentType st = SegmentType::ChordRest;
2014-06-01 20:24:29 +02:00
int startTrack = staffIdx * VOICES;
int endTrack = startTrack + VOICES;
2012-08-06 21:55:51 +02:00
for (Segment* segment = first(st); segment; segment = segment->next(st)) {
2016-12-13 13:16:17 +01:00
if (segment == s && staff->isPitchedStaff(tick())) {
2012-08-07 12:44:19 +02:00
ClefType clef = staff->clef(s->tick());
2012-08-07 16:05:37 +02:00
int l = relStep(line, clef);
return tversatz.accidentalVal(l, error);
2012-08-06 21:55:51 +02:00
}
for (int track = startTrack; track < endTrack; ++track) {
Element* e = segment->element(track);
2016-10-18 15:41:00 +02:00
if (!e || !e->isChord())
2012-08-06 21:55:51 +02:00
continue;
2016-10-18 15:41:00 +02:00
Chord* chord = toChord(e);
for (Chord* chord1 : chord->graceNotes()) {
for (Note* note : chord1->notes()) {
if (note->tieBack() && note->accidental() == 0)
continue;
int tpc = note->tpc();
int l = absStep(tpc, note->epitch());
tversatz.setAccidentalVal(l, tpc2alter(tpc));
}
}
2012-08-06 21:55:51 +02:00
for (Note* note : chord->notes()) {
if (note->tieBack() && note->accidental() == 0)
2012-08-06 21:55:51 +02:00
continue;
int tpc = note->tpc();
int l = absStep(tpc, note->epitch());
2012-08-06 21:55:51 +02:00
tversatz.setAccidentalVal(l, tpc2alter(tpc));
}
}
}
qDebug("segment not found");
return AccidentalVal::NATURAL;
2012-08-06 21:55:51 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// tick2pos
2013-06-19 16:25:29 +02:00
// return x position for tick relative to System
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
qreal Measure::tick2pos(Fraction tck) const
2012-05-26 14:26:10 +02:00
{
2016-10-20 11:32:07 +02:00
tck -= ticks();
if (isMMRest()) {
2017-03-08 13:12:26 +01:00
Segment* s = first(SegmentType::ChordRest);
2016-10-20 11:32:07 +02:00
qreal x1 = s->x();
qreal w = width() - x1;
return x1 + (tck.ticks() * w) / (ticks().ticks() * mmRestCount());
}
2012-05-26 14:26:10 +02:00
Segment* s;
2016-10-20 11:32:07 +02:00
qreal x1 = 0;
qreal x2 = 0;
Fraction tick1 = Fraction(0,1);
Fraction tick2 = Fraction(0,1);
2017-03-08 13:12:26 +01:00
for (s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
2013-06-19 16:25:29 +02:00
x2 = s->x();
2016-10-20 11:32:07 +02:00
tick2 = s->rtick();
2013-06-19 16:25:29 +02:00
if (tck == tick2)
return x2 + pos().x();
if (tck <= tick2)
2012-05-26 14:26:10 +02:00
break;
x1 = x2;
tick1 = tick2;
}
if (s == 0) {
x2 = width();
2016-10-20 11:32:07 +02:00
tick2 = ticks();
2012-05-26 14:26:10 +02:00
}
2013-06-19 16:25:29 +02:00
qreal dx = x2 - x1;
Fraction dt = tick2 - tick1;
x1 += dt.isZero() ? 0.0 : (dx * (tck.ticks() - tick1.ticks()) / dt.ticks());
2013-06-19 16:25:29 +02:00
return x1 + pos().x();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// layoutMeasureNumber
//---------------------------------------------------------
void Measure::layoutMeasureNumber()
{
bool smn = false;
if (_noMode == MeasureNumberMode::SHOW)
smn = true;
else if (_noMode == MeasureNumberMode::HIDE)
smn = false;
else {
if (score()->styleB(Sid::showMeasureNumber)
&& !irregular()
&& (no() || score()->styleB(Sid::showMeasureNumberOne))) {
if (score()->styleB(Sid::measureNumberSystem))
smn = (system()->firstMeasure() == this) || (prevMeasure() && prevMeasure()->irregular() && system()->firstMeasure() == prevMeasure());
else {
smn = (no() == 0 && score()->styleB(Sid::showMeasureNumberOne)) ||
( ((no() + 1) % score()->styleI(Sid::measureNumberInterval)) == (score()->styleB(Sid::showMeasureNumberOne) ? 1 : 0) ) ||
(score()->styleI(Sid::measureNumberInterval) == 1);
}
}
}
QString s;
if (smn)
s = QString("%1").arg(no() + 1);
int nn = 1;
bool nas = score()->styleB(Sid::measureNumberAllStaffs);
if (!nas) {
//find first non invisible staff
for (unsigned staffIdx = 0; staffIdx < _mstaves.size(); ++staffIdx) {
MStaff* ms = _mstaves[staffIdx];
SysStaff* ss = system()->staff(staffIdx);
Staff* staff = score()->staff(staffIdx);
if (ms->visible() && staff->show() && ss->show()) {
nn = staffIdx;
break;
}
}
}
for (int staffIdx = 0; staffIdx < int(_mstaves.size()); ++staffIdx) {
MStaff* ms = _mstaves[staffIdx];
MeasureNumber* t = ms->noText();
if (t)
t->setTrack(staffIdx * VOICES);
if (smn && ((staffIdx == nn) || nas)) {
if (t == 0) {
t = new MeasureNumber(score());
t->setTrack(staffIdx * VOICES);
t->setGenerated(true);
t->setParent(this);
add(t);
}
t->setXmlText(s);
t->layout();
}
else {
if (t) {
if (t->generated())
score()->removeElement(t);
else
score()->undo(new RemoveElement(t));
}
}
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// layout2
2016-01-04 14:48:58 +01:00
// called after layout of page
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Measure::layout2()
{
2016-02-09 09:20:54 +01:00
Q_ASSERT(parent());
2016-02-08 15:10:03 +01:00
Q_ASSERT(score()->nstaves() == int(_mstaves.size()));
2012-05-26 14:26:10 +02:00
qreal _spatium = spatium();
2016-01-04 14:48:58 +01:00
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
MStaff* ms = _mstaves[staffIdx];
2016-12-12 12:02:18 +01:00
Spacer* sp = ms->vspacerDown();
2016-01-04 14:48:58 +01:00
if (sp) {
sp->layout();
Staff* staff = score()->staff(staffIdx);
int n = staff->lines(tick()) - 1;
2016-01-04 14:48:58 +01:00
qreal y = system()->staff(staffIdx)->y();
sp->setPos(_spatium * .5, y + n * _spatium * staff->mag(tick()));
2012-05-26 14:26:10 +02:00
}
2016-12-12 12:02:18 +01:00
sp = ms->vspacerUp();
2016-01-04 14:48:58 +01:00
if (sp) {
sp->layout();
2012-05-26 14:26:10 +02:00
qreal y = system()->staff(staffIdx)->y();
2016-01-04 14:48:58 +01:00
sp->setPos(_spatium * .5, y - sp->gap());
2012-05-26 14:26:10 +02:00
}
}
MeasureBase::layout(); // layout LAYOUT_BREAK elements
#if 0
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
2012-05-26 14:26:10 +02:00
// set measure number
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
2012-05-26 14:26:10 +02:00
bool smn = false;
2012-10-17 10:39:39 +02:00
2014-08-11 15:25:55 +02:00
if (_noMode == MeasureNumberMode::SHOW)
smn = true;
else if (_noMode == MeasureNumberMode::HIDE)
smn = false;
else {
2018-03-27 15:36:00 +02:00
if (score()->styleB(Sid::showMeasureNumber)
2016-01-04 14:48:58 +01:00
&& !irregular()
2018-03-27 15:36:00 +02:00
&& (no() || score()->styleB(Sid::showMeasureNumberOne))) {
if (score()->styleB(Sid::measureNumberSystem))
smn = (system()->firstMeasure() == this) || (prevMeasure() && prevMeasure()->irregular() && system()->firstMeasure() == prevMeasure());
2014-08-11 15:25:55 +02:00
else {
2018-03-27 15:36:00 +02:00
smn = (no() == 0 && score()->styleB(Sid::showMeasureNumberOne)) ||
( ((no() + 1) % score()->styleI(Sid::measureNumberInterval)) == (score()->styleB(Sid::showMeasureNumberOne) ? 1 : 0) ) ||
(score()->styleI(Sid::measureNumberInterval) == 1);
}
}
2014-08-11 15:25:55 +02:00
}
QString s;
if (smn)
2016-01-04 14:48:58 +01:00
s = QString("%1").arg(no() + 1);
2014-08-11 15:25:55 +02:00
int nn = 1;
2018-03-27 15:36:00 +02:00
bool nas = score()->styleB(Sid::measureNumberAllStaffs);
2014-08-11 15:25:55 +02:00
if (!nas) {
//find first non invisible staff
2016-02-06 22:03:43 +01:00
for (unsigned staffIdx = 0; staffIdx < _mstaves.size(); ++staffIdx) {
MStaff* ms = _mstaves[staffIdx];
SysStaff* ss = system()->staff(staffIdx);
2014-08-11 15:25:55 +02:00
Staff* staff = score()->staff(staffIdx);
if (ms->visible() && staff->show() && ss->show()) {
2014-08-11 15:25:55 +02:00
nn = staffIdx;
break;
}
2014-08-11 15:25:55 +02:00
}
}
2016-02-08 15:10:03 +01:00
for (int staffIdx = 0; staffIdx < int(_mstaves.size()); ++staffIdx) {
MStaff* ms = _mstaves[staffIdx];
2018-10-24 10:40:03 +02:00
MeasureNumber* t = ms->noText();
2016-02-04 11:27:47 +01:00
if (t)
2014-08-11 15:25:55 +02:00
t->setTrack(staffIdx * VOICES);
if (smn && ((staffIdx == nn) || nas)) {
if (t == 0) {
2018-10-24 10:40:03 +02:00
t = new MeasureNumber(score());
2014-08-11 15:25:55 +02:00
t->setTrack(staffIdx * VOICES);
t->setGenerated(true);
t->setParent(this);
2016-10-18 15:41:00 +02:00
add(t);
2012-10-17 10:39:39 +02:00
}
t->setXmlText(s);
2014-08-11 15:25:55 +02:00
t->layout();
}
else {
2016-10-18 15:41:00 +02:00
if (t) {
if (t->generated())
score()->removeElement(t);
else
score()->undo(new RemoveElement(t));
}
2012-05-26 14:26:10 +02:00
}
2014-08-11 15:25:55 +02:00
}
#endif
2012-05-26 14:26:10 +02:00
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
// layout ties
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
Fraction stick = system()->measures().front()->tick();
2016-01-04 14:48:58 +01:00
int tracks = score()->ntracks();
2017-03-08 13:12:26 +01:00
static const SegmentType st { SegmentType::ChordRest };
2016-01-04 14:48:58 +01:00
for (int track = 0; track < tracks; ++track) {
if (!score()->staff(track / VOICES)->show()) {
track += VOICES-1;
continue;
}
for (Segment* seg = first(st); seg; seg = seg->next(st)) {
ChordRest* cr = seg->cr(track);
2014-07-02 09:55:50 +02:00
if (!cr)
continue;
2016-10-18 15:41:00 +02:00
if (cr->isChord()) {
Chord* c = toChord(cr);
2014-07-02 09:55:50 +02:00
for (const Note* note : c->notes()) {
Tie* t = note->tieFor();
2019-03-31 00:21:25 +01:00
if (t)
t->layoutFor(system());
t = note->tieBack();
if (t) {
2019-03-31 00:21:25 +01:00
if (t->startNote()->tick() < stick)
t->layoutBack(system());
}
2016-01-04 14:48:58 +01:00
for (Spanner* sp : note->spannerFor())
2014-07-02 09:55:50 +02:00
sp->layout();
2012-05-26 14:26:10 +02:00
}
}
}
}
}
//---------------------------------------------------------
// findChord
2013-06-24 13:46:21 +02:00
/// Search for chord at position \a tick in \a track
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Chord* Measure::findChord(Fraction t, int track)
2012-05-26 14:26:10 +02:00
{
2016-10-20 11:32:07 +02:00
t -= tick();
2012-05-26 14:26:10 +02:00
for (Segment* seg = last(); seg; seg = seg->prev()) {
2016-10-20 11:32:07 +02:00
if (seg->rtick() < t)
2012-05-26 14:26:10 +02:00
return 0;
2016-10-20 11:32:07 +02:00
if (seg->rtick() == t) {
2012-05-26 14:26:10 +02:00
Element* el = seg->element(track);
2016-03-08 17:58:04 +01:00
if (el && el->isChord())
2016-02-17 14:54:23 +01:00
return toChord(el);
2012-05-26 14:26:10 +02:00
}
}
return 0;
}
//---------------------------------------------------------
// findChordRest
2013-06-24 13:46:21 +02:00
/// Search for chord or rest at position \a tick at \a staff in \a voice.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
ChordRest* Measure::findChordRest(Fraction t, int track)
2012-05-26 14:26:10 +02:00
{
2016-10-20 11:32:07 +02:00
t -= tick();
2016-02-09 09:20:54 +01:00
for (const Segment& seg : _segments) {
2016-10-20 11:32:07 +02:00
if (seg.rtick() > t)
2012-05-26 14:26:10 +02:00
return 0;
2016-10-20 11:32:07 +02:00
if (seg.rtick() == t) {
2016-02-09 09:20:54 +01:00
Element* el = seg.element(track);
if (el && el->isChordRest())
2016-02-17 14:54:23 +01:00
return toChordRest(el);
2012-05-26 14:26:10 +02:00
}
}
return 0;
}
//---------------------------------------------------------
// tick2segment
//---------------------------------------------------------
Segment* Measure::tick2segment(const Fraction& _t, SegmentType st)
2012-05-26 14:26:10 +02:00
{
Fraction t = _t - tick();
2016-02-09 09:20:54 +01:00
for (Segment& s : _segments) {
2016-10-20 11:32:07 +02:00
if (s.rtick() == t) {
2016-02-09 09:20:54 +01:00
if (s.segmentType() & st)
return &s;
2012-05-26 14:26:10 +02:00
}
2016-10-20 11:32:07 +02:00
if (s.rtick() > t)
2016-02-09 09:20:54 +01:00
break;
2012-05-26 14:26:10 +02:00
}
return 0;
}
//---------------------------------------------------------
// findSegmentR
// Search for a segment of type st at measure relative
// position t.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Segment* Measure::findSegmentR(SegmentType st, const Fraction& t) const
2012-05-26 14:26:10 +02:00
{
Segment* s;
if (t > (ticks() * Fraction(1,2))) {
2016-10-20 11:32:07 +02:00
// search backwards
for (s = last(); s && s->rtick() > t; s = s->prev())
;
while (s && s->prev() && s->prev()->rtick() == t)
s = s->prev();
}
else {
// search forwards
for (s = first(); s && s->rtick() < t; s = s->next())
;
}
for (; s && s->rtick() == t; s = s->next()) {
2014-08-21 15:01:54 +02:00
if (s->segmentType() & st)
return s;
}
return 0;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// undoGetSegmentR
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Segment* Measure::undoGetSegmentR(SegmentType type, const Fraction& t)
2012-05-26 14:26:10 +02:00
{
Segment* s = findSegmentR(type, t);
if (s == 0) {
s = new Segment(this, type, t);
score()->undoAddElement(s);
2016-10-20 11:32:07 +02:00
}
return s;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// findFirstR
// return first segment of type st at relative
// position t.
//---------------------------------------------------------
Segment* Measure::findFirstR(SegmentType st, const Fraction& t) const
{
Segment* s;
// search forwards
for (s = first(); s && s->rtick() <= t; s = s->next()) {
if (s->segmentType() == st)
return s;
}
return 0;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2016-10-20 11:32:07 +02:00
// getSegmentR
/// Get a segment of type st at relative tick position t.
2012-09-10 16:10:25 +02:00
/// If the segment does not exist, it is created.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Segment* Measure::getSegmentR(SegmentType st, const Fraction& t)
2012-05-26 14:26:10 +02:00
{
2016-10-20 11:32:07 +02:00
Segment* s = findSegmentR(st, t);
2012-05-26 14:26:10 +02:00
if (!s) {
2016-10-20 11:32:07 +02:00
s = new Segment(this, st, t);
2012-05-26 14:26:10 +02:00
add(s);
}
return s;
}
//---------------------------------------------------------
// add
/// Add new Element \a el to Measure.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
void Measure::add(Element* e)
2012-05-26 14:26:10 +02:00
{
2016-01-04 14:48:58 +01:00
e->setParent(this);
2017-01-18 14:16:33 +01:00
ElementType type = e->type();
2012-05-26 14:26:10 +02:00
switch (type) {
2017-01-18 14:16:33 +01:00
case ElementType::SEGMENT:
{
Segment* seg = toSegment(e);
Fraction t = seg->rtick();
2017-03-08 13:12:26 +01:00
SegmentType st = seg->segmentType();
Segment* s;
for (s = first(); s && s->rtick() < t; s = s->next())
;
while (s && s->rtick() == t) {
if (!seg->isChordRestType() && (seg->segmentType() == s->segmentType())) {
qDebug("there is already a <%s> segment", seg->subTypeName());
return;
}
if (s->segmentType() > st)
break;
s = s->next();
}
seg->setParent(this);
_segments.insert(seg, s);
//
// update measure flags
//
if (seg->header())
seg->measure()->setHeader(true);
if (seg->trailer())
seg->measure()->setTrailer(true);
}
break;
2018-10-24 10:40:03 +02:00
case ElementType::MEASURE_NUMBER:
2016-02-08 15:10:03 +01:00
if (e->staffIdx() < int(_mstaves.size()))
2018-10-24 10:40:03 +02:00
_mstaves[e->staffIdx()]->setNoText(toMeasureNumber(e));
2012-10-17 10:39:39 +02:00
break;
2017-01-18 14:16:33 +01:00
case ElementType::SPACER:
2012-05-26 14:26:10 +02:00
{
2016-10-12 20:06:46 +02:00
Spacer* sp = toSpacer(e);
switch (sp->spacerType()) {
case SpacerType::UP:
2016-12-12 12:02:18 +01:00
_mstaves[e->staffIdx()]->setVspacerUp(sp);
2016-10-12 20:06:46 +02:00
break;
case SpacerType::DOWN:
case SpacerType::FIXED:
2016-12-12 12:02:18 +01:00
_mstaves[e->staffIdx()]->setVspacerDown(sp);
2016-10-12 20:06:46 +02:00
break;
}
sp->setGap(sp->gap()); // trigger relayout
2012-05-26 14:26:10 +02:00
}
break;
2017-01-18 14:16:33 +01:00
case ElementType::JUMP:
2016-02-04 11:27:47 +01:00
setRepeatJump(true);
// fall through
2017-01-18 14:16:33 +01:00
case ElementType::MARKER:
2016-01-04 14:48:58 +01:00
el().push_back(e);
2012-05-26 14:26:10 +02:00
break;
2017-01-18 14:16:33 +01:00
case ElementType::HBOX:
2016-01-04 14:48:58 +01:00
if (e->staff())
2016-12-23 12:05:18 +01:00
e->setMag(e->staff()->mag(tick())); // ?!
2016-01-04 14:48:58 +01:00
el().push_back(e);
2012-05-26 14:26:10 +02:00
break;
2017-01-18 14:16:33 +01:00
case ElementType::MEASURE:
2016-10-18 15:41:00 +02:00
_mmRest = toMeasure(e);
2013-10-30 14:21:08 +01:00
break;
case ElementType::STAFFTYPE_CHANGE:
{
StaffTypeChange* stc = toStaffTypeChange(e);
Staff* staff = stc->staff();
const StaffType* st = stc->staffType();
StaffType* nst;
// st needs to point to the stafftype element within the stafftypelist for the staff
if (st) {
// executed on read, undo/redo, clone
// setStaffType adds a copy to list and returns a pointer to that element within list
// we won't need the original after that
// this requires that st was allocated via new to begin with!
nst = staff->setStaffType(tick(), *st);
delete st;
}
else {
// executed on add from palette
// staffType returns a pointer to the current stafftype element in the list
// setStaffType will make a copy and return a pointer to that element within list
st = staff->staffType(tick());
nst = staff->setStaffType(tick(), *st);
}
staff->staffTypeListChanged(tick());
stc->setStaffType(nst);
MeasureBase::add(e);
}
break;
2012-05-26 14:26:10 +02:00
default:
2016-01-04 14:48:58 +01:00
MeasureBase::add(e);
2012-05-26 14:26:10 +02:00
break;
}
}
//---------------------------------------------------------
// remove
2012-08-08 20:46:29 +02:00
/// Remove Element \a el from Measure.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
void Measure::remove(Element* e)
2012-05-26 14:26:10 +02:00
{
2016-01-04 14:48:58 +01:00
Q_ASSERT(e->parent() == this);
Q_ASSERT(e->score() == score());
2014-08-25 19:30:56 +02:00
2016-10-12 20:06:46 +02:00
switch (e->type()) {
2017-01-18 14:16:33 +01:00
case ElementType::SEGMENT:
{
Segment* s = toSegment(e);
_segments.remove(s);
//
// update measure flags
//
if (s->header())
s->measure()->checkHeader();
if (s->trailer())
s->measure()->checkTrailer();
}
break;
case ElementType::MEASURE_NUMBER:
2016-10-18 15:41:00 +02:00
_mstaves[e->staffIdx()]->setNoText(nullptr);
2012-10-17 10:39:39 +02:00
break;
2017-01-18 14:16:33 +01:00
case ElementType::SPACER:
2016-10-12 20:06:46 +02:00
switch (toSpacer(e)->spacerType()) {
case SpacerType::DOWN:
case SpacerType::FIXED:
2016-12-12 12:02:18 +01:00
_mstaves[e->staffIdx()]->setVspacerDown(0);
2016-10-12 20:06:46 +02:00
break;
case SpacerType::UP:
2016-12-12 12:02:18 +01:00
_mstaves[e->staffIdx()]->setVspacerUp(0);
2016-10-12 20:06:46 +02:00
break;
}
2012-05-26 14:26:10 +02:00
break;
2017-01-18 14:16:33 +01:00
case ElementType::JUMP:
2016-02-04 11:27:47 +01:00
setRepeatJump(false);
2012-05-26 14:26:10 +02:00
// fall through
2017-01-18 14:16:33 +01:00
case ElementType::MARKER:
case ElementType::HBOX:
2016-01-04 14:48:58 +01:00
if (!el().remove(e)) {
qDebug("Measure(%p)::remove(%s,%p) not found", this, e->name(), e);
2012-05-26 14:26:10 +02:00
}
break;
2017-01-18 14:16:33 +01:00
case ElementType::CLEF:
case ElementType::CHORD:
case ElementType::REST:
case ElementType::TIMESIG:
2012-05-26 14:26:10 +02:00
for (Segment* segment = first(); segment; segment = segment->next()) {
2016-03-10 10:41:31 +01:00
int staves = score()->nstaves();
2012-05-26 14:26:10 +02:00
int tracks = staves * VOICES;
for (int track = 0; track < tracks; ++track) {
2016-01-04 14:48:58 +01:00
Element* ee = segment->element(track);
if (ee == e) {
2012-05-26 14:26:10 +02:00
segment->setElement(track, 0);
return;
}
}
}
2016-01-04 14:48:58 +01:00
qDebug("Measure::remove: %s %p not found", e->name(), e);
2012-05-26 14:26:10 +02:00
break;
2017-01-18 14:16:33 +01:00
case ElementType::MEASURE:
2013-10-30 14:21:08 +01:00
_mmRest = 0;
break;
case ElementType::STAFFTYPE_CHANGE:
{
StaffTypeChange* stc = toStaffTypeChange(e);
Staff* staff = stc->staff();
if (staff) {
// st currently points to an list element that is about to be removed
// make a copy now to use on undo/redo
StaffType* st = new StaffType(*stc->staffType());
staff->removeStaffType(tick());
stc->setStaffType(st);
}
MeasureBase::remove(e);
}
break;
2012-05-26 14:26:10 +02:00
default:
2016-01-04 14:48:58 +01:00
MeasureBase::remove(e);
2012-05-26 14:26:10 +02:00
break;
}
}
//---------------------------------------------------------
// change
//---------------------------------------------------------
void Measure::change(Element* o, Element* n)
{
2016-10-18 15:41:00 +02:00
if (o->isTuplet()) {
Tuplet* t = toTuplet(n);
2016-02-09 09:20:54 +01:00
for (DurationElement* e : t->elements())
2012-05-26 14:26:10 +02:00
e->setTuplet(t);
}
else {
remove(o);
add(n);
}
}
//---------------------------------------------------------
// spatiumChanged
//---------------------------------------------------------
void Measure::spatiumChanged(qreal /*oldValue*/, qreal /*newValue*/)
{
}
2012-05-26 14:26:10 +02:00
//-------------------------------------------------------------------
// moveTicks
// Also adjust endBarLine if measure len has changed. For this
// diff == 0 cannot be optimized away
//-------------------------------------------------------------------
void Measure::moveTicks(const Fraction& diff)
2012-05-26 14:26:10 +02:00
{
std::set<Tuplet*> tuplets;
2012-05-26 14:26:10 +02:00
setTick(tick() + diff);
2016-05-19 13:15:34 +02:00
for (Segment* segment = last(); segment; segment = segment->prev()) {
2017-03-08 13:12:26 +01:00
if (segment->segmentType() & (SegmentType::EndBarLine | SegmentType::TimeSigAnnounce))
segment->setRtick(ticks());
else if (segment->isChordRestType()) {
// Tuplet ticks are stored as absolute ticks, so they must be adjusted.
// But each tuplet must only be adjusted once.
for (Element* e : segment->elist()) {
if (e) {
ChordRest* cr = toChordRest(e);
Tuplet* tuplet = cr->tuplet();
if (tuplet && tuplets.count(tuplet) == 0)
tuplets.insert(tuplet);
}
}
}
2012-05-26 14:26:10 +02:00
}
tuplets.clear();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// removeStaves
//---------------------------------------------------------
void Measure::removeStaves(int sStaff, int eStaff)
{
for (Segment* s = first(); s; s = s->next()) {
for (int staff = eStaff-1; staff >= sStaff; --staff) {
s->removeStaff(staff);
}
}
2016-01-04 14:48:58 +01:00
for (Element* e : el()) {
2012-05-26 14:26:10 +02:00
if (e->track() == -1)
continue;
int voice = e->voice();
int staffIdx = e->staffIdx();
if (staffIdx >= eStaff) {
staffIdx -= eStaff - sStaff;
e->setTrack(staffIdx * VOICES + voice);
}
}
}
//---------------------------------------------------------
// insertStaves
//---------------------------------------------------------
void Measure::insertStaves(int sStaff, int eStaff)
{
2016-01-04 14:48:58 +01:00
for (Element* e : el()) {
2012-05-26 14:26:10 +02:00
if (e->track() == -1)
continue;
int staffIdx = e->staffIdx();
if (staffIdx >= sStaff && !e->systemFlag()) {
2012-05-26 14:26:10 +02:00
int voice = e->voice();
staffIdx += eStaff - sStaff;
e->setTrack(staffIdx * VOICES + voice);
}
}
for (Segment* s = first(); s; s = s->next()) {
for (int staff = sStaff; staff < eStaff; ++staff) {
s->insertStaff(staff);
}
}
}
//---------------------------------------------------------
// cmdRemoveStaves
//---------------------------------------------------------
void Measure::cmdRemoveStaves(int sStaff, int eStaff)
{
int sTrack = sStaff * VOICES;
int eTrack = eStaff * VOICES;
for (Segment* s = first(); s; s = s->next()) {
for (int track = eTrack - 1; track >= sTrack; --track) {
Element* el = s->element(track);
2013-07-15 07:53:16 +02:00
if (el) {
2014-05-21 20:08:37 +02:00
el->undoUnlink();
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveElement(el));
2012-05-26 14:26:10 +02:00
}
}
2014-05-21 20:08:37 +02:00
foreach (Element* e, s->annotations()) {
2012-05-26 14:26:10 +02:00
int staffIdx = e->staffIdx();
if ((staffIdx >= sStaff) && (staffIdx < eStaff) && !e->systemFlag()) {
2014-05-21 20:08:37 +02:00
e->undoUnlink();
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveElement(e));
2012-05-26 14:26:10 +02:00
}
}
}
2016-01-04 14:48:58 +01:00
for (Element* e : el()) {
2012-05-26 14:26:10 +02:00
if (e->track() == -1)
continue;
int staffIdx = e->staffIdx();
if (staffIdx >= sStaff && (staffIdx < eStaff) && !e->systemFlag()) {
2014-05-21 20:08:37 +02:00
e->undoUnlink();
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveElement(e));
2014-05-21 20:08:37 +02:00
}
2012-05-26 14:26:10 +02:00
}
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveStaves(this, sStaff, eStaff));
2012-05-26 14:26:10 +02:00
2014-08-25 19:30:56 +02:00
for (int i = eStaff - 1; i >= sStaff; --i) {
2016-01-04 14:48:58 +01:00
MStaff* ms = *(_mstaves.begin()+i);
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveMStaff(this, ms, i));
2014-08-25 19:30:56 +02:00
}
2012-05-26 14:26:10 +02:00
// barLine
// TODO
}
//---------------------------------------------------------
// cmdAddStaves
//---------------------------------------------------------
void Measure::cmdAddStaves(int sStaff, int eStaff, bool createRest)
{
2016-03-10 10:41:31 +01:00
score()->undo(new InsertStaves(this, sStaff, eStaff));
2012-05-26 14:26:10 +02:00
2017-03-08 13:12:26 +01:00
Segment* ts = findSegment(SegmentType::TimeSig, tick());
Segment* bs = findSegmentR(SegmentType::EndBarLine, ticks());
2012-05-26 14:26:10 +02:00
for (int i = sStaff; i < eStaff; ++i) {
2016-03-10 10:41:31 +01:00
Staff* staff = score()->staff(i);
2012-05-26 14:26:10 +02:00
MStaff* ms = new MStaff;
2016-12-12 12:02:18 +01:00
ms->setLines(new StaffLines(score()));
ms->lines()->setTrack(i * VOICES);
ms->lines()->setParent(this);
ms->lines()->setVisible(!staff->invisible());
2016-03-10 10:41:31 +01:00
score()->undo(new InsertMStaff(this, ms, i));
2014-07-27 15:06:49 +02:00
}
2012-05-26 14:26:10 +02:00
2014-07-27 15:06:49 +02:00
if (!createRest && !ts)
return;
// create list of unique staves (only one instance for linked staves):
QList<int> sl;
for (int staffIdx = sStaff; staffIdx < eStaff; ++staffIdx) {
2016-03-10 10:41:31 +01:00
Staff* s = score()->staff(staffIdx);
2018-04-27 13:29:20 +02:00
if (s->links()) {
2014-07-27 15:06:49 +02:00
bool alreadyInList = false;
for (int idx : sl) {
2018-04-27 13:29:20 +02:00
if (s->links()->contains(score()->staff(idx))) {
2014-07-27 15:06:49 +02:00
alreadyInList = true;
break;
}
}
2014-07-27 15:06:49 +02:00
if (alreadyInList)
continue;
2012-05-26 14:26:10 +02:00
}
2014-07-27 15:06:49 +02:00
sl.append(staffIdx);
}
for (int staffIdx : sl) {
if (createRest)
score()->setRest(tick(), staffIdx * VOICES, ticks(), false, 0, _timesig == ticks());
2012-05-26 14:26:10 +02:00
// replicate time signature
if (ts) {
TimeSig* ots = 0;
bool constructed = false;
2016-02-08 15:10:03 +01:00
for (unsigned track = 0; track < _mstaves.size() * VOICES; ++track) {
2012-05-26 14:26:10 +02:00
if (ts->element(track)) {
2016-10-18 15:41:00 +02:00
ots = toTimeSig(ts->element(track));
2012-05-26 14:26:10 +02:00
break;
}
}
if (!ots) {
// no time signature found; use measure timesig to construct one
ots = new TimeSig(score());
ots->setSig(timesig());
constructed = true;
}
// do no replicate local time signatures
if (ots && !ots->isLocal()) {
2012-05-26 14:26:10 +02:00
TimeSig* timesig = new TimeSig(*ots);
2014-07-27 15:06:49 +02:00
timesig->setTrack(staffIdx * VOICES);
timesig->setParent(ts);
timesig->setSig(ots->sig(), ots->timeSigType());
2012-05-26 14:26:10 +02:00
score()->undoAddElement(timesig);
if (constructed)
delete ots;
2012-05-26 14:26:10 +02:00
}
}
// replicate barline
if (bs) {
BarLine* obl = nullptr;
for (unsigned track = 0; track < _mstaves.size() * VOICES; ++track) {
Element* e = bs->element(track);
if (e && !e->generated()) {
obl = toBarLine(e);
break;
}
}
if (obl) {
BarLine* barline = new BarLine(*obl);
barline->setSpanStaff(score()->staff(staffIdx)->barLineSpan());
barline->setTrack(staffIdx * VOICES);
barline->setParent(bs);
barline->setGenerated(false);
score()->undoAddElement(barline);
}
}
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// insertMStaff
//---------------------------------------------------------
void Measure::insertMStaff(MStaff* staff, int idx)
{
2016-02-06 22:03:43 +01:00
_mstaves.insert(_mstaves.begin()+idx, staff);
2016-02-08 15:10:03 +01:00
for (unsigned staffIdx = 0; staffIdx < _mstaves.size(); ++staffIdx)
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->setTrack(staffIdx * VOICES);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// removeMStaff
//---------------------------------------------------------
void Measure::removeMStaff(MStaff* /*staff*/, int idx)
{
2016-02-06 22:03:43 +01:00
_mstaves.erase(_mstaves.begin()+idx);
2016-02-08 15:10:03 +01:00
for (unsigned staffIdx = 0; staffIdx < _mstaves.size(); ++staffIdx)
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->setTrack(staffIdx * VOICES);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// insertStaff
//---------------------------------------------------------
void Measure::insertStaff(Staff* staff, int staffIdx)
{
for (Segment* s = first(); s; s = s->next())
s->insertStaff(staffIdx);
MStaff* ms = new MStaff;
2016-12-12 12:02:18 +01:00
ms->setLines(new StaffLines(score()));
ms->lines()->setParent(this);
ms->lines()->setTrack(staffIdx * VOICES);
ms->lines()->setVisible(!staff->invisible());
2012-05-26 14:26:10 +02:00
insertMStaff(ms, staffIdx);
}
//---------------------------------------------------------
// staffabbox
//---------------------------------------------------------
QRectF Measure::staffabbox(int staffIdx) const
{
System* s = system();
QRectF sb(s->staff(staffIdx)->bbox());
QRectF rrr(sb.translated(s->pagePos()));
QRectF rr(abbox());
QRectF r(rr.x(), rrr.y(), rr.width(), rrr.height());
return r;
}
//---------------------------------------------------------
// acceptDrop
//---------------------------------------------------------
/**
Return true if an Element of type \a type can be dropped on a Measure
*/
2017-03-31 13:03:15 +02:00
bool Measure::acceptDrop(EditData& data) const
2012-05-26 14:26:10 +02:00
{
2014-08-13 21:01:21 +02:00
MuseScoreView* viewer = data.view;
QPointF pos = data.pos;
Element* e = data.dropElement;
2016-12-18 14:31:13 +01:00
2014-08-13 21:01:21 +02:00
int staffIdx;
Segment* seg;
2016-12-18 14:31:13 +01:00
if (!score()->pos2measure(pos, &staffIdx, 0, &seg, 0))
2014-10-04 18:22:36 +02:00
return false;
2014-08-13 21:01:21 +02:00
QRectF staffR = system()->staff(staffIdx)->bbox().translated(system()->canvasPos());
staffR &= canvasBoundingRect();
2014-06-19 15:27:44 +02:00
switch (e->type()) {
2017-01-18 14:16:33 +01:00
case ElementType::MEASURE_LIST:
case ElementType::JUMP:
case ElementType::MARKER:
case ElementType::LAYOUT_BREAK:
case ElementType::STAFF_LIST:
2014-08-13 21:01:21 +02:00
viewer->setDropRectangle(canvasBoundingRect());
return true;
2017-01-18 14:16:33 +01:00
case ElementType::KEYSIG:
case ElementType::TIMESIG:
2014-08-13 21:01:21 +02:00
if (data.modifiers & Qt::ControlModifier)
viewer->setDropRectangle(staffR);
else
viewer->setDropRectangle(canvasBoundingRect());
return true;
2017-01-18 14:16:33 +01:00
case ElementType::BRACKET:
case ElementType::REPEAT_MEASURE:
case ElementType::MEASURE:
case ElementType::SPACER:
case ElementType::IMAGE:
case ElementType::BAR_LINE:
case ElementType::SYMBOL:
case ElementType::CLEF:
case ElementType::STAFFTYPE_CHANGE:
2014-08-13 21:01:21 +02:00
viewer->setDropRectangle(staffR);
2012-05-26 14:26:10 +02:00
return true;
2017-01-18 14:16:33 +01:00
case ElementType::ICON:
2016-10-18 15:41:00 +02:00
switch (toIcon(e)->iconType()) {
case IconType::VFRAME:
case IconType::HFRAME:
case IconType::TFRAME:
case IconType::FFRAME:
case IconType::MEASURE:
2014-06-19 15:27:44 +02:00
viewer->setDropRectangle(canvasBoundingRect());
2012-05-26 14:26:10 +02:00
return true;
default:
break;
2012-05-26 14:26:10 +02:00
}
break;
default:
break;
}
return false;
}
//---------------------------------------------------------
// drop
/// Drop element.
/// Handle a dropped element at position \a pos of given
/// element \a type and \a subtype.
//---------------------------------------------------------
2017-03-31 13:03:15 +02:00
Element* Measure::drop(EditData& data)
2012-05-26 14:26:10 +02:00
{
Element* e = data.dropElement;
int staffIdx = -1;
2012-05-26 14:26:10 +02:00
Segment* seg;
2016-03-10 10:41:31 +01:00
score()->pos2measure(data.pos, &staffIdx, 0, &seg, 0);
2012-05-26 14:26:10 +02:00
if (e->systemFlag())
staffIdx = 0;
if (staffIdx < 0)
return 0;
2012-05-26 14:26:10 +02:00
Staff* staff = score()->staff(staffIdx);
2017-01-16 22:16:10 +01:00
//bool fromPalette = (e->track() == -1);
2012-05-26 14:26:10 +02:00
switch (e->type()) {
2017-01-18 14:16:33 +01:00
case ElementType::MEASURE_LIST:
2012-05-26 14:26:10 +02:00
delete e;
break;
2017-01-18 14:16:33 +01:00
case ElementType::STAFF_LIST:
2012-05-26 14:26:10 +02:00
//TODO score()->pasteStaff(e, this, staffIdx);
delete e;
break;
2017-01-18 14:16:33 +01:00
case ElementType::MARKER:
case ElementType::JUMP:
e->setParent(this);
2012-05-26 14:26:10 +02:00
e->setTrack(0);
score()->undoAddElement(e);
return e;
2017-01-18 14:16:33 +01:00
case ElementType::DYNAMIC:
case ElementType::FRET_DIAGRAM:
2012-05-26 14:26:10 +02:00
e->setParent(seg);
e->setTrack(staffIdx * VOICES);
score()->undoAddElement(e);
return e;
2017-01-18 14:16:33 +01:00
case ElementType::IMAGE:
case ElementType::SYMBOL:
2012-05-26 14:26:10 +02:00
e->setParent(seg);
e->setTrack(staffIdx * VOICES);
e->layout();
{
QPointF uo(data.pos - e->canvasPos() - data.dragOffset);
e->setOffset(uo);
2012-05-26 14:26:10 +02:00
}
score()->undoAddElement(e);
return e;
2017-01-18 14:16:33 +01:00
case ElementType::BRACKET:
2013-06-28 17:46:24 +02:00
{
2016-10-18 15:41:00 +02:00
Bracket* b = toBracket(e);
2013-06-28 17:46:24 +02:00
int level = 0;
int firstStaff = 0;
2016-02-09 09:20:54 +01:00
for (Staff* s : score()->staves()) {
2017-03-31 13:03:15 +02:00
for (const BracketItem* bi : s->brackets()) {
int lastStaff = firstStaff + bi->bracketSpan() - 1;
2013-06-28 17:46:24 +02:00
if (staffIdx >= firstStaff && staffIdx <= lastStaff)
++level;
}
firstStaff++;
2013-06-28 17:46:24 +02:00
}
score()->undoAddBracket(staff, level, b->bracketType(), 1);
delete b;
}
return 0;
2012-05-26 14:26:10 +02:00
2017-01-18 14:16:33 +01:00
case ElementType::CLEF:
score()->undoChangeClef(staff, this, toClef(e)->clefType());
2012-05-26 14:26:10 +02:00
delete e;
break;
2017-01-18 14:16:33 +01:00
case ElementType::KEYSIG:
2012-05-26 14:26:10 +02:00
{
2016-05-18 16:32:53 +02:00
KeySigEvent k = toKeySig(e)->keySigEvent();
delete e;
2014-06-03 15:28:10 +02:00
2012-05-26 14:26:10 +02:00
if (data.modifiers & Qt::ControlModifier) {
// apply only to this stave
score()->undoChangeKeySig(staff, tick(), k);
}
else {
2012-05-26 14:26:10 +02:00
// apply to all staves:
2016-05-18 16:32:53 +02:00
for (Staff* s : score()->staves())
score()->undoChangeKeySig(s, tick(), k);
2012-05-26 14:26:10 +02:00
}
2012-08-10 10:14:17 +02:00
2012-05-26 14:26:10 +02:00
break;
}
2017-01-18 14:16:33 +01:00
case ElementType::TIMESIG:
score()->cmdAddTimeSig(this, staffIdx, toTimeSig(e), data.modifiers & Qt::ControlModifier);
2012-05-26 14:26:10 +02:00
return 0;
2017-01-18 14:16:33 +01:00
case ElementType::LAYOUT_BREAK: {
LayoutBreak* b = toLayoutBreak(e);
Measure* measure = isMMRest() ? mmRestLast() : this;
switch (b->layoutBreakType()) {
case LayoutBreak::PAGE:
if (measure->pageBreak()) {
delete b;
b = 0;
}
else
measure->setLineBreak(false);
break;
case LayoutBreak::LINE:
if (measure->lineBreak()) {
delete b;
b = 0;
}
else
measure->setPageBreak(false);
break;
case LayoutBreak::SECTION:
if (measure->sectionBreak()) {
delete b;
b = 0;
}
else
measure->setLineBreak(false);
break;
case LayoutBreak::NOBREAK:
if (measure->noBreak()) {
delete b;
b = 0;
}
else {
measure->setLineBreak(false);
measure->setPageBreak(false);
}
break;
2012-05-26 14:26:10 +02:00
}
if (b) {
b->setTrack(-1); // these are system elements
b->setParent(measure);
score()->undoAddElement(b);
}
measure->cleanupLayoutBreaks(true);
return b;
2012-05-26 14:26:10 +02:00
}
2017-01-18 14:16:33 +01:00
case ElementType::SPACER:
2012-05-26 14:26:10 +02:00
{
2016-10-18 15:41:00 +02:00
Spacer* spacer = toSpacer(e);
2012-05-26 14:26:10 +02:00
spacer->setTrack(staffIdx * VOICES);
spacer->setParent(this);
2016-10-12 20:06:46 +02:00
if (spacer->spacerType() == SpacerType::FIXED) {
qreal gap = spatium() * 10;
System* s = system();
const int nextVisStaffIdx = s->nextVisibleStaff(staffIdx);
const bool systemEnd = (nextVisStaffIdx == score()->nstaves());
if (systemEnd) {
2016-10-12 20:06:46 +02:00
System* ns = 0;
for (System* ts : score()->systems()) {
if (ns) {
ns = ts;
break;
}
if (ts == s)
ns = ts;
}
if (ns && ns->page() == s->page()) {
2016-10-12 20:06:46 +02:00
qreal y1 = s->staffYpage(staffIdx);
qreal y2 = ns->staffYpage(0);
gap = y2 - y1 - score()->staff(staffIdx)->height();
}
}
else {
qreal y1 = s->staffYpage(staffIdx);
qreal y2 = s->staffYpage(nextVisStaffIdx);
2016-10-12 20:06:46 +02:00
gap = y2 - y1 - score()->staff(staffIdx)->height();
}
spacer->setGap(gap);
}
2012-05-26 14:26:10 +02:00
score()->undoAddElement(spacer);
triggerLayout();
2012-05-26 14:26:10 +02:00
return spacer;
}
2017-01-18 14:16:33 +01:00
case ElementType::BAR_LINE:
{
2016-10-18 15:41:00 +02:00
BarLine* bl = toBarLine(e);
2016-02-04 11:27:47 +01:00
// if dropped bar line refers to span rather than to subtype
// or if Ctrl key used
2016-12-18 14:31:13 +01:00
if ((bl->spanFrom() && bl->spanTo()) || data.control()) {
// get existing bar line for this staff, and drop the change to it
seg = undoGetSegmentR(SegmentType::EndBarLine, ticks());
2016-10-18 15:41:00 +02:00
BarLine* cbl = toBarLine(seg->element(staffIdx * VOICES));
if (cbl)
cbl->drop(data);
}
else if (bl->barLineType() == BarLineType::START_REPEAT) {
Measure* m2 = isMMRest() ? mmRestFirst() : this;
for (Score* lscore : score()->scoreList()) {
Measure* lmeasure = lscore->tick2measure(m2->tick());
if (lmeasure)
lmeasure->undoChangeProperty(Pid::REPEAT_START, true);
}
}
else if (bl->barLineType() == BarLineType::END_REPEAT) {
Measure* m2 = isMMRest() ? mmRestLast() : this;
for (Score* lscore : score()->scoreList()) {
Measure* lmeasure = lscore->tick2measure(m2->tick());
if (lmeasure)
lmeasure->undoChangeProperty(Pid::REPEAT_END, true);
}
}
2019-04-06 07:54:38 +02:00
else if (bl->barLineType() == BarLineType::END_START_REPEAT) {
Measure* m2 = isMMRest() ? mmRestLast() : this;
for (Score* lscore : score()->scoreList()) {
Measure* lmeasure = lscore->tick2measure(m2->tick());
if (lmeasure) {
lmeasure->undoChangeProperty(Pid::REPEAT_END, true);
lmeasure = lmeasure->nextMeasure();
if (lmeasure)
lmeasure->undoChangeProperty(Pid::REPEAT_START, true);
}
2019-04-06 07:54:38 +02:00
}
}
else {
2018-01-04 12:41:42 +01:00
// drop to first end barline
seg = findSegmentR(SegmentType::EndBarLine, ticks());
2018-01-04 12:41:42 +01:00
if (seg) {
for (Element* ee : seg->elist()) {
if (ee) {
ee->drop(data);
break;
}
}
}
else
delete e;
}
2012-05-26 14:26:10 +02:00
break;
}
2012-05-26 14:26:10 +02:00
2017-01-18 14:16:33 +01:00
case ElementType::REPEAT_MEASURE:
2012-05-26 14:26:10 +02:00
{
delete e;
return cmdInsertRepeatMeasure(staffIdx);
2012-05-26 14:26:10 +02:00
}
2017-01-18 14:16:33 +01:00
case ElementType::ICON:
2016-10-18 15:41:00 +02:00
switch(toIcon(e)->iconType()) {
case IconType::VFRAME:
2017-01-18 14:16:33 +01:00
score()->insertMeasure(ElementType::VBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::HFRAME:
2017-01-18 14:16:33 +01:00
score()->insertMeasure(ElementType::HBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::TFRAME:
2017-01-18 14:16:33 +01:00
score()->insertMeasure(ElementType::TBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::FFRAME:
2017-01-18 14:16:33 +01:00
score()->insertMeasure(ElementType::FBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::MEASURE:
2017-01-18 14:16:33 +01:00
score()->insertMeasure(ElementType::MEASURE, this);
2012-05-26 14:26:10 +02:00
break;
default:
break;
2012-05-26 14:26:10 +02:00
}
break;
2017-01-18 14:16:33 +01:00
case ElementType::STAFFTYPE_CHANGE:
2016-12-18 14:31:13 +01:00
{
e->setParent(this);
e->setTrack(staffIdx * VOICES);
score()->undoAddElement(e);
}
break;
2012-05-26 14:26:10 +02:00
default:
qDebug("Measure: cannot drop %s here", e->name());
delete e;
break;
}
return 0;
}
//---------------------------------------------------------
// cmdInsertRepeatMeasure
//---------------------------------------------------------
2014-05-20 17:26:26 +02:00
RepeatMeasure* Measure::cmdInsertRepeatMeasure(int staffIdx)
{
//
// see also cmdDeleteSelection()
//
2016-03-10 10:41:31 +01:00
score()->select(0, SelectType::SINGLE, 0);
for (Segment* s = first(); s; s = s->next()) {
2017-03-08 13:12:26 +01:00
if (s->segmentType() & SegmentType::ChordRest) {
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
for (int track = strack; track < etrack; ++track) {
Element* el = s->element(track);
if (el)
2016-03-10 10:41:31 +01:00
score()->undoRemoveElement(el);
}
}
}
//
// add repeat measure
//
2017-03-08 13:12:26 +01:00
Segment* seg = undoGetSegment(SegmentType::ChordRest, tick());
2016-03-10 10:41:31 +01:00
RepeatMeasure* rm = new RepeatMeasure(score());
rm->setTrack(staffIdx * VOICES);
rm->setParent(seg);
rm->setDurationType(TDuration::DurationType::V_MEASURE);
rm->setTicks(stretchedLen(score()->staff(staffIdx)));
2016-03-10 10:41:31 +01:00
score()->undoAddCR(rm, this, tick());
2016-01-04 14:48:58 +01:00
for (Element* e : el()) {
2016-10-18 15:41:00 +02:00
if (e->isSlur() && e->staffIdx() == staffIdx)
2016-03-10 10:41:31 +01:00
score()->undoRemoveElement(e);
}
return rm;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// adjustToLen
// change actual measure len, adjust elements to
// new len
//---------------------------------------------------------
void Measure::adjustToLen(Fraction nf, bool appendRestsIfNecessary)
2012-05-26 14:26:10 +02:00
{
Fraction ol = ticks();
Fraction nl = nf;
Fraction diff = nl - ol;
Fraction startTick = endTick();
if (diff < Fraction(0,1))
startTick += diff;
2013-10-21 13:11:04 +02:00
2014-05-20 17:26:26 +02:00
score()->undoInsertTime(startTick, diff);
2014-07-27 12:38:45 +02:00
score()->undo(new InsertTime(score(), startTick, diff));
2012-05-26 14:26:10 +02:00
2014-05-20 17:26:26 +02:00
for (Score* s : score()->scoreList()) {
Measure* m = s->tick2measure(tick());
s->undo(new ChangeMeasureLen(m, nf));
if (nl > ol) {
// move EndBarLine, TimeSigAnnounce, KeySigAnnounce
for (Segment* seg = m->first(); seg; seg = seg->next()) {
if (seg->segmentType() & (SegmentType::EndBarLine|SegmentType::TimeSigAnnounce|SegmentType::KeySigAnnounce)) {
seg->setRtick(nl);
2014-05-20 17:26:26 +02:00
}
2012-05-26 14:26:10 +02:00
}
}
}
2016-03-10 10:41:31 +01:00
Score* s = score()->masterScore();
Measure* m = s->tick2measure(tick());
2014-05-22 16:18:35 +02:00
QList<int> sl = s->uniqueStaves();
2012-05-26 14:26:10 +02:00
2014-05-22 16:18:35 +02:00
for (int staffIdx : sl) {
2012-05-26 14:26:10 +02:00
int rests = 0;
int chords = 0;
Rest* rest = 0;
2014-05-20 17:26:26 +02:00
for (Segment* segment = m->first(); segment; segment = segment->next()) {
2012-05-26 14:26:10 +02:00
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
for (int track = strack; track < etrack; ++track) {
Element* e = segment->element(track);
2013-10-21 13:11:04 +02:00
if (e) {
if (e->isRest()) {
2013-10-21 13:11:04 +02:00
++rests;
rest = toRest(e);
2013-10-21 13:11:04 +02:00
}
else if (e->isChord())
2013-10-21 13:11:04 +02:00
++chords;
2012-05-26 14:26:10 +02:00
}
}
}
Fraction stretch = s->staff(staffIdx)->timeStretch(tick());
// if just a single rest
2013-10-21 13:11:04 +02:00
if (rests == 1 && chords == 0) {
// if measure value didn't change, stick to whole measure rest
if (_timesig == nf) {
rest->undoChangeProperty(Pid::DURATION, QVariant::fromValue<Fraction>(nf * stretch));
2018-03-27 15:36:00 +02:00
rest->undoChangeProperty(Pid::DURATION_TYPE, QVariant::fromValue<TDuration>(TDuration::DurationType::V_MEASURE));
}
2014-05-20 17:26:26 +02:00
else { // if measure value did change, represent with rests actual measure value
#if 0
// any reason not to do this instead?
s->undoRemoveElement(rest);
s->setRest(tick(), staffIdx * VOICES, nf * stretch, false, 0, false);
#else
// convert the measure duration in a list of values (no dots for rests)
std::vector<TDuration> durList = toDurationList(nf * stretch, false, 0);
2014-05-20 17:26:26 +02:00
// set the existing rest to the first value of the duration list
for (ScoreElement* e : rest->linkList()) {
2018-03-27 15:36:00 +02:00
e->undoChangeProperty(Pid::DURATION, QVariant::fromValue<Fraction>(durList[0].fraction()));
e->undoChangeProperty(Pid::DURATION_TYPE, QVariant::fromValue<TDuration>(durList[0]));
2014-09-29 11:58:44 +02:00
}
2014-05-20 17:26:26 +02:00
// add rests for any other duration list value
Fraction tickOffset = tick() + rest->actualTicks();
2016-02-08 15:10:03 +01:00
for (unsigned i = 1; i < durList.size(); i++) {
2014-05-20 17:26:26 +02:00
Rest* newRest = new Rest(s);
newRest->setDurationType(durList.at(i));
newRest->setTicks(durList.at(i).fraction());
newRest->setTrack(rest->track());
score()->undoAddCR(newRest, this, tickOffset);
tickOffset += newRest->actualTicks();
}
#endif
}
2014-05-20 17:26:26 +02:00
continue;
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
for (int trk = strack; trk < etrack; ++trk) {
Fraction n = diff;
2013-10-21 13:11:04 +02:00
bool rFlag = false;
if (n < Fraction(0,1)) {
2014-05-20 17:26:26 +02:00
for (Segment* segment = m->last(); segment;) {
2013-10-21 13:11:04 +02:00
Segment* pseg = segment->prev();
2017-03-08 13:12:26 +01:00
if (segment->segmentType() == SegmentType::ChordRest) {
for (Element* a : segment->annotations())
if (a->track() == trk)
s->undoRemoveElement(a);
Element* e = segment->element(trk);
if (e && e->isChordRest()) {
ChordRest* cr = toChordRest(e);
if (cr->durationType() == TDuration::DurationType::V_MEASURE) {
Fraction actualTicks = cr->actualTicks();
n += actualTicks;
cr->setDurationType(TDuration(actualTicks));
}
else
n += cr->actualTicks();
s->undoRemoveElement(e);
if (n >= Fraction(0,1))
break;
}
}
2017-03-08 13:12:26 +01:00
else if (segment->segmentType() == SegmentType::Breath) {
Element* e = segment->element(trk);
if (e)
s->undoRemoveElement(e);
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
segment = pseg;
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
rFlag = true;
}
int voice = trk % VOICES;
if (appendRestsIfNecessary && (n > Fraction(0,1)) && (rFlag || voice == 0)) {
2013-10-21 13:11:04 +02:00
// add rest to measure
Fraction rtick = tick() + nl - n;
2013-10-21 13:11:04 +02:00
int track = staffIdx * VOICES + voice;
s->setRest(rtick, track, n * stretch, false, 0, false);
2012-05-26 14:26:10 +02:00
}
}
}
if (diff < Fraction(0,1)) {
2012-05-26 14:26:10 +02:00
//
// CHECK: do not remove all slurs
//
2016-10-18 15:41:00 +02:00
foreach (Element* e, m->el()) {
if (e->isSlur())
2014-05-20 17:26:26 +02:00
s->undoRemoveElement(e);
2012-05-26 14:26:10 +02:00
}
}
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void Measure::write(XmlWriter& xml, int staff, bool writeSystemElements, bool forceTimeSig) const
2012-05-26 14:26:10 +02:00
{
if (MScore::debugMode) {
const int mno = no() + 1;
xml.comment(QString("Measure %1").arg(mno));
}
2012-05-26 14:26:10 +02:00
if (_len != _timesig) {
// this is an irregular measure
xml.stag(this, QString("len=\"%1/%2\"").arg(_len.numerator()).arg(_len.denominator()));
2012-05-26 14:26:10 +02:00
}
else
xml.stag(this);
2014-02-28 14:25:47 +01:00
2016-11-19 10:31:14 +01:00
xml.setCurTick(tick());
xml.setCurTrack(staff * VOICES);
2012-05-26 14:26:10 +02:00
2014-02-26 19:06:42 +01:00
if (_mmRestCount > 0)
xml.tag("multiMeasureRest", _mmRestCount);
2012-05-26 14:26:10 +02:00
if (writeSystemElements) {
2016-02-04 11:27:47 +01:00
if (repeatStart())
2012-05-26 14:26:10 +02:00
xml.tagE("startRepeat");
2016-02-04 11:27:47 +01:00
if (repeatEnd())
2012-05-26 14:26:10 +02:00
xml.tag("endRepeat", _repeatCount);
2018-03-27 15:36:00 +02:00
writeProperty(xml, Pid::IRREGULAR);
writeProperty(xml, Pid::BREAK_MMR);
writeProperty(xml, Pid::USER_STRETCH);
writeProperty(xml, Pid::NO_OFFSET);
writeProperty(xml, Pid::MEASURE_NUMBER_MODE);
2012-05-26 14:26:10 +02:00
}
qreal _spatium = spatium();
2016-01-04 14:48:58 +01:00
MStaff* mstaff = _mstaves[staff];
if (mstaff->noText() && !mstaff->noText()->generated()) {
xml.stag("MeasureNumber", mstaff->noText());
mstaff->noText()->writeProperties(xml);
xml.etag();
}
2016-12-12 12:02:18 +01:00
if (mstaff->vspacerUp())
xml.tag("vspacerUp", mstaff->vspacerUp()->gap() / _spatium);
if (mstaff->vspacerDown()) {
if (mstaff->vspacerDown()->spacerType() == SpacerType::FIXED)
xml.tag("vspacerFixed", mstaff->vspacerDown()->gap() / _spatium);
2016-10-12 20:06:46 +02:00
else
2016-12-12 12:02:18 +01:00
xml.tag("vspacerDown", mstaff->vspacerDown()->gap() / _spatium);
2016-10-12 20:06:46 +02:00
}
2016-12-12 12:02:18 +01:00
if (!mstaff->visible())
xml.tag("visible", mstaff->visible());
if (mstaff->stemless()) {
xml.tag("slashStyle", mstaff->stemless()); // for backwards compatibility
xml.tag("stemless", mstaff->stemless());
}
2012-05-26 14:26:10 +02:00
int strack = staff * VOICES;
int etrack = strack + VOICES;
2016-01-04 14:48:58 +01:00
for (const Element* e : el()) {
if (!e->generated() && ((e->staffIdx() == staff) || (e->systemFlag() && writeSystemElements)))
e->write(xml);
2012-05-26 14:26:10 +02:00
}
Q_ASSERT(first());
Q_ASSERT(last());
score()->writeSegments(xml, strack, etrack, first(), last()->next1(), writeSystemElements, forceTimeSig);
2012-05-26 14:26:10 +02:00
xml.etag();
}
//---------------------------------------------------------
// Measure::read
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
void Measure::read(XmlReader& e, int staffIdx)
2012-05-26 14:26:10 +02:00
{
qreal _spatium = spatium();
e.setCurrentMeasure(this);
int nextTrack = staffIdx * VOICES;
e.setTrack(nextTrack);
2013-01-23 14:14:09 +01:00
for (int n = int(_mstaves.size()); n <= staffIdx; ++n) {
2012-05-26 14:26:10 +02:00
Staff* staff = score()->staff(n);
2012-09-14 10:09:06 +02:00
MStaff* s = new MStaff;
2016-12-12 12:02:18 +01:00
s->setLines(new StaffLines(score()));
s->lines()->setParent(this);
s->lines()->setTrack(n * VOICES);
s->lines()->setVisible(!staff->invisible());
2016-02-06 22:03:43 +01:00
_mstaves.push_back(s);
2012-05-26 14:26:10 +02:00
}
2013-06-04 18:29:14 +02:00
bool irregular;
2013-01-11 18:10:18 +01:00
if (e.hasAttribute("len")) {
QStringList sl = e.attribute("len").split('/');
2012-05-26 14:26:10 +02:00
if (sl.size() == 2)
_len = Fraction(sl[0].toInt(), sl[1].toInt());
else
2013-01-11 18:10:18 +01:00
qDebug("illegal measure size <%s>", qPrintable(e.attribute("len")));
2012-05-26 14:26:10 +02:00
irregular = true;
score()->sigmap()->add(tick().ticks(), SigEvent(_len, _timesig));
score()->sigmap()->add((tick() + ticks()).ticks(), SigEvent(_timesig));
2012-05-26 14:26:10 +02:00
}
2013-06-04 18:29:14 +02:00
else
irregular = false;
2013-06-04 18:29:14 +02:00
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
if (tag == "voice") {
e.setTrack(nextTrack++);
e.setTick(tick());
readVoice(e, staffIdx, irregular);
}
else if (tag == "Marker" || tag == "Jump") {
Element* el = Element::name2Element(tag, score());
el->setTrack(e.track());
el->read(e);
add(el);
}
else if (tag == "stretch") {
double val = e.readDouble();
if (val < 0.0)
val = 0;
setUserStretch(val);
}
else if (tag == "noOffset")
setNoOffset(e.readInt());
else if (tag == "measureNumberMode")
setMeasureNumberMode(MeasureNumberMode(e.readInt()));
else if (tag == "irregular")
setIrregular(e.readBool());
else if (tag == "breakMultiMeasureRest")
_breakMultiMeasureRest = e.readBool();
else if (tag == "startRepeat") {
setRepeatStart(true);
e.readNext();
}
else if (tag == "endRepeat") {
_repeatCount = e.readInt();
setRepeatEnd(true);
}
else if (tag == "vspacer" || tag == "vspacerDown") {
if (!_mstaves[staffIdx]->vspacerDown()) {
Spacer* spacer = new Spacer(score());
spacer->setSpacerType(SpacerType::DOWN);
spacer->setTrack(staffIdx * VOICES);
add(spacer);
}
_mstaves[staffIdx]->vspacerDown()->setGap(e.readDouble() * _spatium);
}
else if (tag == "vspacerFixed") {
if (!_mstaves[staffIdx]->vspacerDown()) {
Spacer* spacer = new Spacer(score());
spacer->setSpacerType(SpacerType::FIXED);
spacer->setTrack(staffIdx * VOICES);
add(spacer);
}
_mstaves[staffIdx]->vspacerDown()->setGap(e.readDouble() * _spatium);
}
else if (tag == "vspacerUp") {
if (!_mstaves[staffIdx]->vspacerUp()) {
Spacer* spacer = new Spacer(score());
spacer->setSpacerType(SpacerType::UP);
spacer->setTrack(staffIdx * VOICES);
add(spacer);
}
_mstaves[staffIdx]->vspacerUp()->setGap(e.readDouble() * _spatium);
}
else if (tag == "visible")
_mstaves[staffIdx]->setVisible(e.readInt());
else if ((tag == "slashStyle") || (tag == "stemless"))
_mstaves[staffIdx]->setStemless(e.readInt());
else if (tag == "SystemDivider") {
SystemDivider* sd = new SystemDivider(score());
sd->read(e);
add(sd);
}
else if (tag == "multiMeasureRest") {
_mmRestCount = e.readInt();
// set tick to previous measure
setTick(e.lastMeasure()->tick());
e.setTick(e.lastMeasure()->tick());
}
else if (tag == "MeasureNumber") {
2018-10-24 10:40:03 +02:00
MeasureNumber* noText = new MeasureNumber(score());
noText->read(e);
noText->setTrack(e.track());
add(noText);
}
else if (MeasureBase::readProperties(e))
;
else
e.unknown();
}
e.checkConnectors();
if (isMMRest()) {
Measure* lm = e.lastMeasure();
e.setTick(lm->tick() + lm->ticks());
}
e.setCurrentMeasure(nullptr);
connectTremolo();
}
//---------------------------------------------------------
// Measure::readVoice
//---------------------------------------------------------
void Measure::readVoice(XmlReader& e, int staffIdx, bool irregular)
{
Segment* segment = nullptr;
QList<Chord*> graceNotes;
Beam* startingBeam = nullptr;
Tuplet* tuplet = nullptr;
Fermata* fermata = nullptr;
2012-05-26 14:26:10 +02:00
Staff* staff = score()->staff(staffIdx);
2012-06-28 15:12:17 +02:00
Fraction timeStretch(staff->timeStretch(tick()));
2012-05-26 14:26:10 +02:00
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
2012-05-26 14:26:10 +02:00
if (tag == "location") {
Location loc = Location::relative();
loc.read(e);
e.setLocation(loc);
}
else if (tag == "tick") { // obsolete?
qDebug("read midi tick");
e.setTick(Fraction::fromTicks(score()->fileDivision(e.readInt())));
}
2012-05-26 14:26:10 +02:00
else if (tag == "BarLine") {
BarLine* barLine = new BarLine(score());
2013-01-21 20:21:41 +01:00
barLine->setTrack(e.track());
barLine->read(e);
//
// StartRepeatBarLine: at rtick == 0, always BarLineType::START_REPEAT
2016-03-08 09:46:33 +01:00
// BarLine: in the middle of a measure, has no semantic
// EndBarLine: at the end of a measure
// BeginBarLine: first segment of a measure, systemic barline
SegmentType st = SegmentType::Invalid;
Fraction t = e.tick() - tick();
if (t.isNotZero() && (t != ticks()))
2017-03-08 13:12:26 +01:00
st = SegmentType::BarLine;
else if (barLine->barLineType() == BarLineType::START_REPEAT && t.isZero())
2017-03-08 13:12:26 +01:00
st = SegmentType::StartRepeatBarLine;
else if (barLine->barLineType() == BarLineType::START_REPEAT && t == ticks()) {
// old version, ignore
delete barLine;
barLine = 0;
2016-10-18 15:41:00 +02:00
}
else if (t.isZero() && segment == 0)
2017-03-08 13:12:26 +01:00
st = SegmentType::BeginBarLine;
2014-10-10 14:24:37 +02:00
else
2017-03-08 13:12:26 +01:00
st = SegmentType::EndBarLine;
if (barLine) {
segment = getSegmentR(st, t);
segment->add(barLine);
barLine->layout();
}
if (fermata) {
segment->add(fermata);
fermata = nullptr;
}
2012-05-26 14:26:10 +02:00
}
else if (tag == "Chord") {
2013-06-16 23:33:37 +02:00
Chord* chord = new Chord(score());
chord->setTrack(e.track());
chord->read(e);
2018-06-09 04:45:54 +02:00
if (startingBeam) {
startingBeam->add(chord); // also calls chord->setBeam(startingBeam)
startingBeam = nullptr;
}
// if (tuplet && !chord->isGrace())
// chord->readAddTuplet(tuplet);
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::ChordRest, e.tick());
2016-09-22 12:02:27 +02:00
if (chord->noteType() != NoteType::NORMAL)
2014-11-28 22:35:25 +01:00
graceNotes.push_back(chord);
2012-05-26 14:26:10 +02:00
else {
2013-06-16 23:33:37 +02:00
segment->add(chord);
for (int i = 0; i < graceNotes.size(); ++i) {
Chord* gc = graceNotes[i];
gc->setGraceIndex(i);
chord->add(gc);
}
graceNotes.clear();
if (tuplet)
tuplet->add(chord);
e.incTick(chord->actualTicks());
2012-05-26 14:26:10 +02:00
}
if (fermata) {
segment->add(fermata);
fermata = nullptr;
}
2012-05-26 14:26:10 +02:00
}
else if (tag == "Rest") {
Rest* rest = new Rest(score());
rest->setDurationType(TDuration::DurationType::V_MEASURE);
rest->setTicks(timesig()/timeStretch);
2013-01-21 20:21:41 +01:00
rest->setTrack(e.track());
rest->read(e);
2018-06-09 04:45:54 +02:00
if (startingBeam) {
startingBeam->add(rest); // also calls rest->setBeam(startingBeam)
startingBeam = nullptr;
}
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::ChordRest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(rest);
if (fermata) {
segment->add(fermata);
fermata = nullptr;
}
2014-07-28 15:54:47 +02:00
if (!rest->ticks().isValid()) // hack
rest->setTicks(timesig()/timeStretch);
2012-05-26 14:26:10 +02:00
if (tuplet)
tuplet->add(rest);
2014-07-28 15:54:47 +02:00
e.incTick(rest->actualTicks());
2012-05-26 14:26:10 +02:00
}
else if (tag == "Breath") {
Breath* breath = new Breath(score());
2013-01-21 20:21:41 +01:00
breath->setTrack(e.track());
2012-05-26 14:26:10 +02:00
breath->read(e);
segment = getSegment(SegmentType::Breath, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(breath);
}
else if (tag == "Spanner")
Spanner::readSpanner(e, this, e.track());
2012-05-26 14:26:10 +02:00
else if (tag == "RepeatMeasure") {
RepeatMeasure* rm = new RepeatMeasure(score());
2013-01-21 20:21:41 +01:00
rm->setTrack(e.track());
rm->read(e);
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::ChordRest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(rm);
2014-07-21 14:16:16 +02:00
e.incTick(ticks());
2012-05-26 14:26:10 +02:00
}
else if (tag == "Clef") {
Clef* clef = new Clef(score());
2013-01-21 20:21:41 +01:00
clef->setTrack(e.track());
2012-05-26 14:26:10 +02:00
clef->read(e);
clef->setGenerated(false);
2013-07-12 18:41:33 +02:00
// there may be more than one clef segment for same tick position
// the first clef may be missing and is added later in layout
bool header;
if (e.tick() != tick())
header = false;
else if (!segment)
header = true;
2013-07-12 18:41:33 +02:00
else {
header = true;
for (Segment* s = _segments.first(); s && s->rtick().isZero(); s = s->next()) {
if (s->isKeySigType() || s->isTimeSigType()) {
// hack: there may be other segment types which should
// generate a clef at current position
header = false;
2013-07-12 18:41:33 +02:00
break;
}
}
2012-05-26 14:26:10 +02:00
}
2017-03-08 13:12:26 +01:00
segment = getSegment(header ? SegmentType::HeaderClef : SegmentType::Clef, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(clef);
}
else if (tag == "TimeSig") {
TimeSig* ts = new TimeSig(score());
2013-01-21 20:21:41 +01:00
ts->setTrack(e.track());
2012-10-24 13:15:46 +02:00
ts->read(e);
// if time sig not at beginning of measure => courtesy time sig
Fraction currTick = e.tick();
2014-04-16 09:35:23 +02:00
bool courtesySig = (currTick > tick());
if (courtesySig) {
// if courtesy sig., just add it without map processing
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::TimeSigAnnounce, currTick);
segment->add(ts);
2014-07-28 15:54:47 +02:00
}
else {
// if 'real' time sig., do full process
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::TimeSig, currTick);
segment->add(ts);
2013-06-04 18:29:14 +02:00
2014-10-08 10:57:24 +02:00
timeStretch = ts->stretch().reduced();
_timesig = ts->sig() / timeStretch;
if (irregular) {
score()->sigmap()->add(tick().ticks(), SigEvent(_len, _timesig));
score()->sigmap()->add((tick() + ticks()).ticks(), SigEvent(_timesig));
}
else {
_len = _timesig;
score()->sigmap()->add(tick().ticks(), SigEvent(_timesig));
}
2012-06-28 15:12:17 +02:00
}
2012-05-26 14:26:10 +02:00
}
else if (tag == "KeySig") {
KeySig* ks = new KeySig(score());
2013-01-21 20:21:41 +01:00
ks->setTrack(e.track());
2012-05-26 14:26:10 +02:00
ks->read(e);
Fraction curTick = e.tick();
if (!ks->isCustom() && !ks->isAtonal() && ks->key() == Key::C && curTick.isZero()) {
2014-08-24 13:10:51 +02:00
// ignore empty key signature
qDebug("remove keysig c at tick 0");
}
else {
// if key sig not at beginning of measure => courtesy key sig
bool courtesySig = (curTick == endTick());
2017-03-08 13:12:26 +01:00
segment = getSegment(courtesySig ? SegmentType::KeySigAnnounce : SegmentType::KeySig, curTick);
2014-08-24 13:10:51 +02:00
segment->add(ks);
if (!courtesySig)
staff->setKey(curTick, ks->keySigEvent());
2014-08-24 13:10:51 +02:00
}
2012-05-26 14:26:10 +02:00
}
else if (tag == "Text") {
2017-12-27 11:51:00 +01:00
StaffText* t = new StaffText(score());
2013-01-21 20:21:41 +01:00
t->setTrack(e.track());
2012-05-26 14:26:10 +02:00
t->read(e);
2016-03-30 22:33:04 +02:00
if (t->empty()) {
qDebug("==reading empty text: deleted");
delete t;
}
2012-09-21 12:23:18 +02:00
else {
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::ChordRest, e.tick());
2012-09-21 12:23:18 +02:00
segment->add(t);
}
2012-05-26 14:26:10 +02:00
}
//----------------------------------------------------
// Annotation
else if (tag == "Dynamic") {
Dynamic* dyn = new Dynamic(score());
2013-01-21 20:21:41 +01:00
dyn->setTrack(e.track());
2012-05-26 14:26:10 +02:00
dyn->read(e);
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::ChordRest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(dyn);
}
else if (tag == "Harmony"
|| tag == "FretDiagram"
2014-08-26 15:07:24 +02:00
|| tag == "TremoloBar"
2012-05-26 14:26:10 +02:00
|| tag == "Symbol"
|| tag == "Tempo"
|| tag == "StaffText"
|| tag == "Sticking"
2017-01-20 11:05:52 +01:00
|| tag == "SystemText"
2012-05-26 14:26:10 +02:00
|| tag == "RehearsalMark"
|| tag == "InstrumentChange"
|| tag == "StaffState"
|| tag == "FiguredBass"
) {
2013-01-18 10:55:52 +01:00
Element* el = Element::name2Element(tag, score());
// hack - needed because tick tags are unreliable in 1.3 scores
// for symbols attached to anything but a measure
2013-01-21 20:21:41 +01:00
el->setTrack(e.track());
2012-05-26 14:26:10 +02:00
el->read(e);
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::ChordRest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(el);
}
else if (tag == "Fermata") {
fermata = new Fermata(score());
fermata->setTrack(e.track());
fermata->setPlacement(fermata->track() & 1 ? Placement::BELOW : Placement::ABOVE);
fermata->read(e);
}
else if (tag == "Image") {
if (MScore::noImages)
e.skipCurrentElement();
else {
Element* el = Element::name2Element(tag, score());
el->setTrack(e.track());
el->read(e);
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::ChordRest, e.tick());
segment->add(el);
}
}
2012-05-26 14:26:10 +02:00
//----------------------------------------------------
else if (tag == "Tuplet") {
2018-06-09 06:19:36 +02:00
Tuplet* oldTuplet = tuplet;
tuplet = new Tuplet(score());
2013-01-21 20:21:41 +01:00
tuplet->setTrack(e.track());
tuplet->setTick(e.tick());
2012-05-26 14:26:10 +02:00
tuplet->setParent(this);
tuplet->read(e);
2018-06-09 06:19:36 +02:00
if (oldTuplet)
oldTuplet->add(tuplet);
2018-06-09 06:19:36 +02:00
}
else if (tag == "endTuplet") {
if (!tuplet) {
qDebug("Measure::read: encountered <endTuplet/> when no tuplet was started");
e.skipCurrentElement();
continue;
}
Tuplet* oldTuplet = tuplet;
tuplet = tuplet->tuplet();
if (oldTuplet->elements().empty()) {
// this should not happen and is a sign of input file corruption
qDebug("Measure:read: empty tuplet in measure index=%d, input file corrupted?", e.currentMeasureIndex());
if (tuplet)
tuplet->remove(oldTuplet);
delete oldTuplet;
}
e.readNext();
2012-05-26 14:26:10 +02:00
}
else if (tag == "Beam") {
Beam* beam = new Beam(score());
2013-01-21 20:21:41 +01:00
beam->setTrack(e.track());
2012-05-26 14:26:10 +02:00
beam->read(e);
beam->setParent(0);
2018-06-09 04:45:54 +02:00
if (startingBeam) {
qDebug("The read beam was not used");
delete startingBeam;
}
startingBeam = beam;
2012-05-26 14:26:10 +02:00
}
else if (tag == "Segment" && segment)
2013-06-24 19:01:31 +02:00
segment->read(e);
2013-11-25 12:17:12 +01:00
else if (tag == "Ambitus") {
Ambitus* range = new Ambitus(score());
range->read(e);
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::Ambitus, e.tick());
range->setParent(segment); // a parent segment is needed for setTrack() to work
range->setTrack(trackZeroVoice(e.track()));
segment->add(range);
}
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
}
2018-06-09 04:45:54 +02:00
if (startingBeam) {
qDebug("The read beam was not used");
delete startingBeam;
}
2018-06-09 06:19:36 +02:00
if (tuplet) {
qDebug("Measure:readVoice: measure index=%d, <endTuplet/> not found", e.currentMeasureIndex());
2018-06-09 06:19:36 +02:00
if (tuplet->elements().empty()) {
if (tuplet->tuplet())
tuplet->tuplet()->remove(tuplet);
delete tuplet;
}
}
if (fermata) {
SegmentType st = (e.tick() == endTick() ? SegmentType::EndBarLine : SegmentType::ChordRest);
segment = getSegment(st, e.tick());
segment->add(fermata);
fermata = nullptr;
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// Measure::readAddConnector
//---------------------------------------------------------
void Measure::readAddConnector(ConnectorInfoReader* info, bool pasteMode)
{
const ElementType type = info->type();
switch(type) {
case ElementType::HAIRPIN:
case ElementType::PEDAL:
case ElementType::OTTAVA:
case ElementType::TRILL:
case ElementType::TEXTLINE:
case ElementType::LET_RING:
case ElementType::VIBRATO:
case ElementType::PALM_MUTE:
case ElementType::VOLTA:
{
Spanner* sp = toSpanner(info->connector());
const Location& l = info->location();
Fraction lTick = l.frac();
Fraction spTick = pasteMode ? lTick : (tick() + lTick);
if (info->isStart()) {
sp->setTrack(l.track());
sp->setTick(spTick);
score()->addSpanner(sp);
}
else if (info->isEnd()) {
sp->setTrack2(l.track());
sp->setTick2(spTick);
}
}
break;
default:
break;
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// visible
//---------------------------------------------------------
bool Measure::visible(int staffIdx) const
{
2014-11-10 14:18:42 +01:00
if (staffIdx >= score()->staves().size()) {
qDebug("Measure::visible: bad staffIdx: %d", staffIdx);
return false;
}
2016-02-06 22:03:43 +01:00
if (system() && (system()->staves()->empty() || !system()->staff(staffIdx)->show()))
2015-08-04 19:53:54 +02:00
return false;
if (score()->staff(staffIdx)->cutaway() && isEmpty(staffIdx))
return false;
2016-12-12 12:02:18 +01:00
return score()->staff(staffIdx)->show() && _mstaves[staffIdx]->visible();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// stemless
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
bool Measure::stemless(int staffIdx) const
2012-05-26 14:26:10 +02:00
{
const Staff* staff = score()->staff(staffIdx);
return staff->stemless(tick()) || _mstaves[staffIdx]->stemless() || staff->staffType(tick())->stemless();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// isFinalMeasureOfSection
// returns true if this measure is final actual measure of a section
2016-04-14 11:45:12 +02:00
// takes into consideration fact that subsequent measures base objects
// may have section break before encountering next actual measure
//---------------------------------------------------------
bool Measure::isFinalMeasureOfSection() const
{
const MeasureBase* mb = static_cast<const MeasureBase*>(this);
do {
if (mb->sectionBreak())
return true;
mb = mb->next();
} while (mb && !mb->isMeasure()); // loop until reach next actual measure or end of score
return false;
}
//---------------------------------------------------------
// isAnacrusis
//---------------------------------------------------------
bool Measure::isAnacrusis() const
{
TimeSigFrac timeSig = score()->sigmap()->timesig(tick().ticks()).nominal();
return irregular() && ticks() < Fraction::fromTicks(timeSig.ticksPerMeasure());
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// scanElements
//---------------------------------------------------------
void Measure::scanElements(void* data, void (*func)(void*, Element*), bool all)
{
MeasureBase::scanElements(data, func, all);
int nstaves = score()->nstaves();
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (!all && !(visible(staffIdx) && score()->staff(staffIdx)->show()))
2012-05-26 14:26:10 +02:00
continue;
2016-01-04 14:48:58 +01:00
MStaff* ms = _mstaves[staffIdx];
2016-12-12 12:02:18 +01:00
func(data, ms->lines());
if (ms->vspacerUp())
func(data, ms->vspacerUp());
if (ms->vspacerDown())
func(data, ms->vspacerDown());
if (ms->noText())
func(data, ms->noText());
2012-05-26 14:26:10 +02:00
}
2016-10-20 11:32:07 +02:00
for (Segment* s = first(); s; s = s->next()) {
if (!s->enabled())
continue;
s->scanElements(data, func, all);
2016-10-20 11:32:07 +02:00
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// connectTremolo
/// Connect two-notes tremolo and update duration types
/// for the involved chords.
//---------------------------------------------------------
void Measure::connectTremolo()
{
const int ntracks = score()->ntracks();
constexpr SegmentType st = SegmentType::ChordRest;
for (Segment* s = first(st); s; s = s->next(st)) {
for (int i = 0; i < ntracks; ++i) {
Element* e = s->element(i);
if (!e || !e->isChord())
continue;
Chord* c = toChord(e);
Tremolo* tremolo = c->tremolo();
if (tremolo && tremolo->twoNotes()) {
// Ensure correct duration type for chord
c->setDurationType(tremolo->durationType());
// If it is the first tremolo's chord, find the second
// chord for tremolo, if needed.
if (!tremolo->chord1())
tremolo->setChords(c, tremolo->chord2());
else if (tremolo->chord1() != c || tremolo->chord2())
continue;
for (Segment* ls = s->next(st); ls; ls = ls->next(st)) {
if (Element* element = ls->element(i)) {
if (!element->isChord()) {
qDebug("cannot connect tremolo");
continue;
}
Chord* nc = toChord(element);
tremolo->setChords(c, nc);
nc->setTremolo(tremolo);
break;
}
}
}
}
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// createVoice
// Create a voice on demand by filling the measure
// with a whole measure rest.
// Check if there are any chord/rests in track; if
// not create a whole measure rest
//---------------------------------------------------------
void Measure::createVoice(int track)
{
for (Segment* s = first(); s; s = s->next()) {
2017-03-08 13:12:26 +01:00
if (s->segmentType() != SegmentType::ChordRest)
2012-05-26 14:26:10 +02:00
continue;
if (s->element(track) == 0)
score()->setRest(s->tick(), track, ticks(), true, 0);
2012-05-26 14:26:10 +02:00
break;
}
}
//---------------------------------------------------------
// sortStaves
//---------------------------------------------------------
void Measure::sortStaves(QList<int>& dst)
{
2016-02-06 22:03:43 +01:00
std::vector<MStaff*> ms;
2016-02-09 09:20:54 +01:00
for (int idx : dst)
2016-01-04 14:48:58 +01:00
ms.push_back(_mstaves[idx]);
_mstaves = ms;
2012-05-26 14:26:10 +02:00
2016-02-08 15:10:03 +01:00
for (unsigned staffIdx = 0; staffIdx < _mstaves.size(); ++staffIdx)
2016-12-12 12:02:18 +01:00
_mstaves[staffIdx]->lines()->setTrack(staffIdx * VOICES);
2016-02-09 09:20:54 +01:00
for (Segment& s : _segments)
s.sortStaves(dst);
2012-05-26 14:26:10 +02:00
2016-01-04 14:48:58 +01:00
for (Element* e : el()) {
if (e->track() == -1 || e->systemFlag())
2012-05-26 14:26:10 +02:00
continue;
int voice = e->voice();
int staffIdx = e->staffIdx();
int idx = dst.indexOf(staffIdx);
e->setTrack(idx * VOICES + voice);
}
}
//---------------------------------------------------------
// exchangeVoice
//---------------------------------------------------------
2016-07-31 15:23:11 +02:00
void Measure::exchangeVoice(int strack, int dtrack, int staffIdx)
2012-05-26 14:26:10 +02:00
{
2017-03-08 13:12:26 +01:00
for (Segment* s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
2014-08-29 10:35:17 +02:00
s->swapElements(strack, dtrack);
2012-05-26 14:26:10 +02:00
}
auto spanners = score()->spannerMap().findOverlapping(tick().ticks(), endTick().ticks()-1);
Fraction start = tick();
Fraction end = start + ticks();
for (auto i = spanners.begin(); i < spanners.end(); i++) {
Spanner* sp = i->value;
Fraction spStart = sp->tick();
Fraction spEnd = spStart + sp->ticks();
qDebug("Start %d End %d Diff %d \n Measure Start %d End %d", spStart.ticks(), spEnd.ticks(), (spEnd-spStart).ticks(), start.ticks(), end.ticks());
2016-10-18 15:41:00 +02:00
if (sp->isSlur() && (spStart >= start || spEnd < end)) {
if (sp->track() == strack && spStart >= start){
sp->setTrack(dtrack);
}
else if (sp->track() == dtrack && spStart >= start){
sp->setTrack(strack);
}
if (sp->track2() == strack && spEnd < end){
sp->setTrack2(dtrack);
}
else if (sp->track2() == dtrack && spEnd < end){
sp->setTrack2(strack);
}
}
}
checkMultiVoices(staffIdx); // probably true, but check for invisible notes & rests
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// checkMultiVoices
2012-08-02 18:33:43 +02:00
/// Check for more than on voice in this measure and staff and
/// set MStaff->hasVoices
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Measure::checkMultiVoices(int staffIdx)
{
int strack = staffIdx * VOICES + 1;
int etrack = staffIdx * VOICES + VOICES;
2016-12-12 12:02:18 +01:00
_mstaves[staffIdx]->setHasVoices(false);
2017-03-08 13:12:26 +01:00
for (Segment* s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
2012-05-26 14:26:10 +02:00
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
if (e) {
bool v;
if (e->isChord()) {
v = false;
// consider chord visible if any note is visible
Chord* c = toChord(e);
for (Note* n : c->notes()) {
if (n->visible()) {
v = true;
break;
}
}
}
else
v = e->visible();
if (v) {
2016-12-12 12:02:18 +01:00
_mstaves[staffIdx]->setHasVoices(true);
return;
}
2012-05-26 14:26:10 +02:00
}
}
}
}
//---------------------------------------------------------
// hasVoice
//---------------------------------------------------------
bool Measure::hasVoice(int track) const
{
2016-12-12 14:55:35 +01:00
if (track >= score()->ntracks())
2016-07-31 15:23:11 +02:00
return false;
2012-05-26 14:26:10 +02:00
for (Segment* s = first(); s; s = s->next()) {
2017-03-08 13:12:26 +01:00
if (s->segmentType() != SegmentType::ChordRest)
2012-05-26 14:26:10 +02:00
continue;
if (s->element(track))
return true;
}
return false;
}
2012-08-02 18:33:43 +02:00
//-------------------------------------------------------------------
// isEmpty
/// Check if the measure is filled by a full-measure rest, or is
/// full of rests on this staff, that may have fermatas on them.
/// If staff is -1, then check for all staves.
2012-08-02 18:33:43 +02:00
//-------------------------------------------------------------------
2012-05-26 14:26:10 +02:00
bool Measure::isEmpty(int staffIdx) const
2012-05-26 14:26:10 +02:00
{
int strack;
int etrack;
if (staffIdx < 0) {
strack = 0;
etrack = score()->nstaves() * VOICES;
}
else {
strack = staffIdx * VOICES;
2014-08-26 21:01:21 +02:00
etrack = strack + VOICES;
2012-05-26 14:26:10 +02:00
}
2017-03-08 13:12:26 +01:00
for (Segment* s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
2012-05-26 14:26:10 +02:00
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
2016-10-18 15:41:00 +02:00
if (e && !e->isRest())
2012-05-26 14:26:10 +02:00
return false;
}
for (Element* a : s->annotations()) {
if (!a || a->systemFlag() || !a->visible() || a->isFermata())
continue;
int atrack = a->track();
if (atrack >= strack && atrack < etrack)
return false;
}
2012-05-26 14:26:10 +02:00
}
return true;
}
//---------------------------------------------------------
// isFullMeasureRest
// Check for an empty measure, filled with full measure
// rests.
//---------------------------------------------------------
2015-08-04 19:53:54 +02:00
bool Measure::isFullMeasureRest() const
2012-05-26 14:26:10 +02:00
{
int strack = 0;
int etrack = score()->nstaves() * VOICES;
2017-03-08 13:12:26 +01:00
Segment* s = first(SegmentType::ChordRest);
2012-05-26 14:26:10 +02:00
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
if (e) {
2016-10-18 15:41:00 +02:00
if (!e->isRest())
2012-05-26 14:26:10 +02:00
return false;
2016-10-18 15:41:00 +02:00
Rest* rest = toRest(e);
if (rest->durationType().type() != TDuration::DurationType::V_MEASURE)
2012-05-26 14:26:10 +02:00
return false;
}
}
return true;
}
//---------------------------------------------------------
// isRepeatMeasure
//---------------------------------------------------------
bool Measure::isRepeatMeasure(const Staff* staff) const
2012-05-26 14:26:10 +02:00
{
2016-09-28 21:13:05 +02:00
int staffIdx = staff->idx();
int strack = staffIdx * VOICES;
int etrack = (staffIdx + 1) * VOICES;
2017-03-08 13:12:26 +01:00
Segment* s = first(SegmentType::ChordRest);
2012-05-26 14:26:10 +02:00
2012-08-02 18:33:43 +02:00
if (s == 0)
2012-05-26 14:26:10 +02:00
return false;
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
2016-10-18 15:41:00 +02:00
if (e && e->isRepeatMeasure())
2012-05-26 14:26:10 +02:00
return true;
}
return false;
}
//---------------------------------------------------------
// isEmpty
//---------------------------------------------------------
2016-02-06 22:03:43 +01:00
bool Measure::empty() const
2012-05-26 14:26:10 +02:00
{
2016-01-04 14:48:58 +01:00
if (irregular())
2012-05-26 14:26:10 +02:00
return false;
int n = 0;
int tracks = int(_mstaves.size()) * VOICES;
2017-03-08 13:12:26 +01:00
static const SegmentType st = SegmentType::ChordRest ;
for (const Segment* s = first(st); s; s = s->next(st)) {
bool restFound = false;
for (int track = 0; track < tracks; ++track) {
if ((track % VOICES) == 0 && !score()->staff(track/VOICES)->show()) {
track += VOICES-1;
continue;
}
if (s->element(track)) {
2016-10-18 15:41:00 +02:00
if (!s->element(track)->isRest())
2012-05-26 14:26:10 +02:00
return false;
restFound = true;
2012-05-26 14:26:10 +02:00
}
}
if (restFound)
++n;
// measure is not empty if there is more than one rest
if (n > 1)
return false;
2012-05-26 14:26:10 +02:00
}
return true;
}
//---------------------------------------------------------
// isOnlyRests
//---------------------------------------------------------
bool Measure::isOnlyRests(int track) const
{
2017-03-08 13:12:26 +01:00
static const SegmentType st = SegmentType::ChordRest;
for (const Segment* s = first(st); s; s = s->next(st)) {
if (s->segmentType() != st || !s->element(track))
continue;
2016-10-18 15:41:00 +02:00
if (!s->element(track)->isRest())
return false;
}
return true;
}
//---------------------------------------------------------
// isOnlyDeletedRests
//---------------------------------------------------------
bool Measure::isOnlyDeletedRests(int track) const
{
2017-03-08 13:12:26 +01:00
static const SegmentType st { SegmentType::ChordRest };
for (const Segment* s = first(st); s; s = s->next(st)) {
if (s->segmentType() != st || !s->element(track))
continue;
if (s->element(track)->isRest() ? !toRest(s->element(track))->isGap() : !s->element(track)->isRest())
return false;
}
return true;
}
//---------------------------------------------------------
// isOnlyDeletedRests
//---------------------------------------------------------
bool Measure::isOnlyDeletedRests(int track, const Fraction& stick, const Fraction& etick) const
{
static const SegmentType st { SegmentType::ChordRest };
for (const Segment* s = first(st); s; s = s->next(st)) {
if (s->segmentType() != st || !s->element(track))
continue;
ChordRest* cr = toChordRest(s->element(track));
if (cr->tick() + cr->globalTicks() <= stick)
continue;
if (cr->tick() >= etick)
return true;
if (!cr->isRest() || !toRest(cr)->isGap())
return false;
}
return true;
}
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
// stretchedLen
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
Fraction Measure::stretchedLen(Staff* staff) const
{
return ticks() * staff->timeStretch(tick());
}
2016-01-04 14:48:58 +01:00
//---------------------------------------------------------
// cloneMeasure
//---------------------------------------------------------
Measure* Measure::cloneMeasure(Score* sc, const Fraction& tick, TieMap* tieMap)
{
2016-01-04 14:48:58 +01:00
Measure* m = new Measure(sc);
m->_timesig = _timesig;
m->_len = _len;
m->_repeatCount = _repeatCount;
Q_ASSERT(sc->staves().size() >= int(_mstaves.size())); // destination score we're cloning into must have at least as many staves as measure being cloned
2016-01-04 14:48:58 +01:00
m->setNo(no());
m->setNoOffset(noOffset());
m->setIrregular(irregular());
2012-05-26 14:26:10 +02:00
m->_userStretch = _userStretch;
m->_breakMultiMeasureRest = _breakMultiMeasureRest;
m->_playbackCount = _playbackCount;
m->setTick(tick);
2012-05-26 14:26:10 +02:00
m->setLineBreak(lineBreak());
m->setPageBreak(pageBreak());
2016-10-13 14:28:00 +02:00
m->setSectionBreak(sectionBreak() ? new LayoutBreak(*sectionBreakElement()) : 0);
2012-05-26 14:26:10 +02:00
m->setHeader(header()); m->setTrailer(trailer());
2012-05-26 14:26:10 +02:00
int tracks = sc->nstaves() * VOICES;
TupletMap tupletMap;
for (Segment* oseg = first(); oseg; oseg = oseg->next()) {
2016-10-20 11:32:07 +02:00
Segment* s = new Segment(m, oseg->segmentType(), oseg->rtick());
s->setEnabled(oseg->enabled()); s->setVisible(oseg->visible());
s->setHeader(oseg->header()); s->setTrailer(oseg->trailer());
2012-05-26 14:26:10 +02:00
m->_segments.push_back(s);
for (int track = 0; track < tracks; ++track) {
Element* oe = oseg->element(track);
2016-12-28 16:23:10 +01:00
for (Element* e : oseg->annotations()) {
2012-05-26 14:26:10 +02:00
if (e->generated() || e->track() != track)
continue;
Element* ne = e->clone();
ne->setTrack(track);
ne->setOffset(e->offset());
2014-11-10 13:33:32 +01:00
ne->setScore(sc);
2012-05-26 14:26:10 +02:00
s->add(ne);
}
2014-08-13 17:45:53 +02:00
if (!oe)
continue;
Element* ne = oe->clone();
if (oe->isChordRest()) {
2016-10-18 15:41:00 +02:00
ChordRest* ocr = toChordRest(oe);
ChordRest* ncr = toChordRest(ne);
2014-08-13 17:45:53 +02:00
Tuplet* ot = ocr->tuplet();
if (ot) {
Tuplet* nt = tupletMap.findNew(ot);
if (nt == 0) {
nt = new Tuplet(*ot);
nt->clear();
nt->setTrack(track);
nt->setScore(sc);
nt->setParent(m);
nt->setTick(m->tick() + ot->rtick());
2014-08-13 17:45:53 +02:00
tupletMap.add(ot, nt);
}
ncr->setTuplet(nt);
nt->add(ncr);
}
2016-10-18 15:41:00 +02:00
if (oe->isChord()) {
Chord* och = toChord(ocr);
Chord* nch = toChord(ncr);
size_t n = och->notes().size();
for (size_t i = 0; i < n; ++i) {
2014-08-13 17:45:53 +02:00
Note* on = och->notes().at(i);
Note* nn = nch->notes().at(i);
if (on->tieFor()) {
2014-11-25 16:53:43 +01:00
Tie* tie = on->tieFor()->clone();
tie->setScore(sc);
2014-08-13 17:45:53 +02:00
nn->setTieFor(tie);
tie->setStartNote(nn);
tieMap->add(on->tieFor(), tie);
}
if (on->tieBack()) {
Tie* tie = tieMap->findNew(on->tieBack());
if (tie) {
nn->setTieBack(tie);
tie->setEndNote(nn);
}
else {
qDebug("cloneMeasure: cannot find tie, track %d", track);
}
}
}
}
}
ne->setOffset(oe->offset());
2014-11-10 13:33:32 +01:00
ne->setScore(sc);
2014-08-13 17:45:53 +02:00
s->add(ne);
2012-05-26 14:26:10 +02:00
}
}
foreach(Element* e, el()) {
2012-05-26 14:26:10 +02:00
Element* ne = e->clone();
ne->setScore(sc);
ne->setOffset(e->offset());
2012-05-26 14:26:10 +02:00
m->add(ne);
}
return m;
}
//---------------------------------------------------------
// snap
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Fraction Measure::snap(const Fraction& tick, const QPointF p) const
2012-05-26 14:26:10 +02:00
{
Segment* s = first();
for (; s->next(); s = s->next()) {
qreal x = s->x();
qreal dx = s->next()->x() - x;
if (s->tick() == tick)
x += dx / 3.0 * 2.0;
else if (s->next()->tick() == tick)
x += dx / 3.0;
else
x += dx * .5;
if (p.x() < x)
break;
}
return s->tick();
}
//---------------------------------------------------------
// snapNote
//---------------------------------------------------------
Fraction Measure::snapNote(const Fraction& /*tick*/, const QPointF p, int staff) const
2012-05-26 14:26:10 +02:00
{
Segment* s = first();
for (;;) {
Segment* ns = s->next();
while (ns && ns->element(staff) == 0)
ns = ns->next();
if (ns == 0)
break;
qreal x = s->x();
qreal nx = x + (ns->x() - x) * .5;
if (p.x() < nx)
break;
s = ns;
}
return s->tick();
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
2018-03-27 15:36:00 +02:00
QVariant Measure::getProperty(Pid propertyId) const
{
switch(propertyId) {
2018-03-27 15:36:00 +02:00
case Pid::TIMESIG_NOMINAL:
return QVariant::fromValue(_timesig);
2018-03-27 15:36:00 +02:00
case Pid::TIMESIG_ACTUAL:
return QVariant::fromValue(_len);
2018-03-27 15:36:00 +02:00
case Pid::MEASURE_NUMBER_MODE:
return int(measureNumberMode());
2018-03-27 15:36:00 +02:00
case Pid::BREAK_MMR:
2016-01-04 14:48:58 +01:00
return breakMultiMeasureRest();
2018-03-27 15:36:00 +02:00
case Pid::REPEAT_COUNT:
2014-05-20 17:26:26 +02:00
return repeatCount();
2018-03-27 15:36:00 +02:00
case Pid::USER_STRETCH:
2014-05-20 17:26:26 +02:00
return userStretch();
default:
return MeasureBase::getProperty(propertyId);
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
2018-03-27 15:36:00 +02:00
bool Measure::setProperty(Pid propertyId, const QVariant& value)
{
switch (propertyId) {
2018-03-27 15:36:00 +02:00
case Pid::TIMESIG_NOMINAL:
_timesig = value.value<Fraction>();
break;
2018-03-27 15:36:00 +02:00
case Pid::TIMESIG_ACTUAL:
_len = value.value<Fraction>();
break;
2018-03-27 15:36:00 +02:00
case Pid::MEASURE_NUMBER_MODE:
setMeasureNumberMode(MeasureNumberMode(value.toInt()));
break;
2018-03-27 15:36:00 +02:00
case Pid::BREAK_MMR:
2014-05-20 17:26:26 +02:00
setBreakMultiMeasureRest(value.toBool());
break;
2018-03-27 15:36:00 +02:00
case Pid::REPEAT_COUNT:
2014-05-20 17:26:26 +02:00
setRepeatCount(value.toInt());
break;
2018-03-27 15:36:00 +02:00
case Pid::USER_STRETCH:
2014-05-20 17:26:26 +02:00
setUserStretch(value.toDouble());
break;
default:
return MeasureBase::setProperty(propertyId, value);
}
score()->setLayout(tick());
return true;
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
2018-03-27 15:36:00 +02:00
QVariant Measure::propertyDefault(Pid propertyId) const
{
switch(propertyId) {
2018-03-27 15:36:00 +02:00
case Pid::TIMESIG_NOMINAL:
case Pid::TIMESIG_ACTUAL:
return QVariant();
2018-03-27 15:36:00 +02:00
case Pid::MEASURE_NUMBER_MODE:
return int(MeasureNumberMode::AUTO);
2018-03-27 15:36:00 +02:00
case Pid::BREAK_MMR:
2014-05-20 17:26:26 +02:00
return false;
2018-03-27 15:36:00 +02:00
case Pid::REPEAT_COUNT:
2014-05-20 17:26:26 +02:00
return 2;
2018-03-27 15:36:00 +02:00
case Pid::USER_STRETCH:
2014-05-20 17:26:26 +02:00
return 1.0;
2018-03-27 15:36:00 +02:00
case Pid::NO_OFFSET:
2014-05-20 17:26:26 +02:00
return 0;
2018-03-27 15:36:00 +02:00
case Pid::IRREGULAR:
2014-05-20 17:26:26 +02:00
return false;
default:
break;
}
2016-02-04 11:27:47 +01:00
return MeasureBase::propertyDefault(propertyId);
}
2013-10-30 14:21:08 +01:00
//-------------------------------------------------------------------
// mmRestFirst
// this is a multi measure rest
// returns first measure of replaced sequence of empty measures
//-------------------------------------------------------------------
Measure* Measure::mmRestFirst() const
{
Q_ASSERT(isMMRest());
if (prev())
2016-10-18 15:41:00 +02:00
return toMeasure(prev()->next());
2013-10-30 14:21:08 +01:00
return score()->firstMeasure();
}
//-------------------------------------------------------------------
// mmRestLast
// this is a multi measure rest
// returns last measure of replaced sequence of empty measures
//-------------------------------------------------------------------
Measure* Measure::mmRestLast() const
{
Q_ASSERT(isMMRest());
if (next())
2016-10-18 15:41:00 +02:00
return toMeasure(next()->prev());
2013-10-30 14:21:08 +01:00
return score()->lastMeasure();
}
2014-04-24 10:42:42 +02:00
//---------------------------------------------------------
// mmRest1
// return the multi measure rest this measure is covered
// by
//---------------------------------------------------------
const Measure* Measure::mmRest1() const
2014-04-24 10:42:42 +02:00
{
if (_mmRest)
return _mmRest;
if (_mmRestCount != -1)
// return const_cast<Measure*>(this);
return this;
2014-04-24 10:42:42 +02:00
const Measure* m = this;
while (m && !m->_mmRest)
m = m->prevMeasure();
if (m)
return const_cast<Measure*>(m->_mmRest);
return 0;
}
2014-05-17 18:40:05 +02:00
//-------------------------------------------------------------------
// userStretch
//-------------------------------------------------------------------
2014-05-20 17:26:26 +02:00
2014-05-17 18:40:05 +02:00
qreal Measure::userStretch() const
{
return (score()->layoutMode() == LayoutMode::FLOAT ? 1.0 : _userStretch);
2014-05-17 18:40:05 +02:00
}
2014-04-24 10:42:42 +02:00
2016-05-02 13:41:41 +02:00
//---------------------------------------------------------
// nextElementStaff
//---------------------------------------------------------
Element* Measure::nextElementStaff(int staff)
{
Element* e = score()->selection().element();
if (!e && !score()->selection().elements().isEmpty())
e = score()->selection().elements().first();
// handle measure elements
if (e->parent() == this) {
auto i = std::find(el().begin(), el().end(), e);
if (i != el().end()) {
if (++i != el().end()) {
2019-10-14 18:27:06 +02:00
Element* resElement = *i;
if (resElement)
return resElement;
}
}
}
for (; e && e->type() != ElementType::SEGMENT; e = e->parent()) {
;
}
2017-12-20 16:49:30 +01:00
Segment* seg = toSegment(e);
Segment* nextSegment = seg ? seg->next() : first();
Element* next = seg->firstElementOfSegment(nextSegment, staff);
if (next)
return next;
return score()->lastElement();
}
2016-05-02 13:41:41 +02:00
//---------------------------------------------------------
// prevElementStaff
//---------------------------------------------------------
Element* Measure::prevElementStaff(int staff)
{
Element* e = score()->selection().element();
if (!e && !score()->selection().elements().isEmpty())
e = score()->selection().elements().first();
// handle measure elements
if (e->parent() == this) {
auto i = std::find(el().rbegin(), el().rend(), e);
if (i != el().rend()) {
if (++i != el().rend()) {
2019-10-14 18:27:06 +02:00
Element* resElement = *i;
if (resElement)
return resElement;
}
}
}
Measure* prevM = prevMeasureMM();
if (prevM) {
Segment* seg = prevM->last();
if (seg)
return seg->lastElement(staff);
}
return score()->firstElement();
}
//---------------------------------------------------------
// accessibleInfo
//---------------------------------------------------------
2016-02-04 17:06:32 +01:00
QString Measure::accessibleInfo() const
{
return QString("%1: %2").arg(Element::accessibleInfo()).arg(QString::number(no() + 1));
}
2016-01-04 14:48:58 +01:00
//-----------------------------------------------------------------------------
// stretchMeasure
2016-05-02 13:41:41 +02:00
// resize width of measure to targetWidth
2016-01-04 14:48:58 +01:00
//-----------------------------------------------------------------------------
2016-05-02 13:41:41 +02:00
void Measure::stretchMeasure(qreal targetWidth)
2016-01-04 14:48:58 +01:00
{
2016-05-02 13:41:41 +02:00
bbox().setWidth(targetWidth);
2016-01-04 14:48:58 +01:00
Fraction minTick = computeTicks();
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
2016-05-02 13:41:41 +02:00
// compute stretch
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
2016-05-02 13:41:41 +02:00
std::multimap<qreal, Segment*> springs;
2016-02-08 15:10:03 +01:00
Segment* seg = first();
while (seg && !seg->enabled())
seg = seg->next();
qreal minimumWidth = seg ? seg->x() : 0.0;
2016-05-02 13:41:41 +02:00
for (Segment& s : _segments) {
if (!s.enabled() || !s.visible())
continue;
Fraction t = s.ticks();
if (t.isNotZero()) {
qreal str = 1.0 + 0.865617 * log(qreal(t.ticks()) / qreal(minTick.ticks())); // .6 * log(t / minTick.ticks()) / log(2);
2016-05-02 13:41:41 +02:00
qreal d = s.width() / str;
s.setStretch(str);
springs.insert(std::pair<qreal, Segment*>(d, &s));
2016-01-04 14:48:58 +01:00
}
2016-05-02 13:41:41 +02:00
minimumWidth += s.width();
2016-01-04 14:48:58 +01:00
}
//---------------------------------------------------
2016-05-02 13:41:41 +02:00
// compute 1/Force for a given Extend
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
2016-05-02 13:41:41 +02:00
if (targetWidth > minimumWidth) {
qreal force = 0;
qreal c = 0.0;
for (auto i = springs.begin(); i != springs.end();) {
2016-05-02 13:41:41 +02:00
c += i->second->stretch();
minimumWidth -= i->second->width();
qreal f = (targetWidth - minimumWidth) / c;
++i;
if (i == springs.end() || f <= i->first) {
force = f;
break;
}
}
2016-05-02 13:41:41 +02:00
//---------------------------------------------------
// distribute stretch to segments
//---------------------------------------------------
2016-01-04 14:48:58 +01:00
2016-05-02 13:41:41 +02:00
for (auto& i : springs) {
qreal width = force * i.second->stretch();
if (width > i.second->width())
i.second->setWidth(width);
}
2016-01-04 14:48:58 +01:00
2016-05-02 13:41:41 +02:00
//---------------------------------------------------
// move segments to final position
//---------------------------------------------------
Segment* s = first();
while (s && !s->enabled())
s = s->next();
qreal x = s->pos().x();
while (s) {
s->rxpos() = x;
x += s->width();
2016-10-31 10:55:11 +01:00
s = s->nextEnabled();
2016-05-02 13:41:41 +02:00
}
2016-01-04 14:48:58 +01:00
}
//---------------------------------------------------
// layout individual elements
//---------------------------------------------------
2016-05-02 13:41:41 +02:00
for (Segment& s : _segments) {
if (!s.enabled())
continue;
2016-05-02 13:41:41 +02:00
for (Element* e : s.elist()) {
if (!e)
2016-01-04 14:48:58 +01:00
continue;
2017-01-18 14:16:33 +01:00
ElementType t = e->type();
2016-05-02 13:41:41 +02:00
int staffIdx = e->staffIdx();
2017-01-18 14:16:33 +01:00
if (t == ElementType::REPEAT_MEASURE || (t == ElementType::REST && (isMMRest() || toRest(e)->isFullMeasureRest()))) {
2016-01-04 14:48:58 +01:00
//
// element has to be centered in free space
// x1 - left measure position of free space
// x2 - right measure position of free space
2016-10-31 10:55:11 +01:00
Segment* s1;
for (s1 = s.prev(); s1 && !s1->enabled(); s1 = s1->prev())
;
2016-02-17 12:48:53 +01:00
Segment* s2;
2016-05-02 13:41:41 +02:00
for (s2 = s.next(); s2; s2 = s2->next()) {
2016-10-31 10:55:11 +01:00
if (s2->enabled() && !s2->isChordRestType() && s2->element(staffIdx * VOICES))
2016-01-04 14:48:58 +01:00
break;
}
2016-02-17 12:48:53 +01:00
qreal x1 = s1 ? s1->x() + s1->minRight() : 0;
2016-05-02 13:41:41 +02:00
qreal x2 = s2 ? s2->x() - s2->minLeft() : targetWidth;
2016-01-04 14:48:58 +01:00
if (isMMRest()) {
2016-05-02 13:41:41 +02:00
Rest* rest = toRest(e);
2016-01-04 14:48:58 +01:00
//
// center multi measure rest
//
2018-03-27 15:36:00 +02:00
qreal d = score()->styleP(Sid::multiMeasureRestMargin);
2016-01-04 14:48:58 +01:00
qreal w = x2 - x1 - 2 * d;
2017-10-17 14:28:03 +02:00
rest->layoutMMRest(w);
e->setPos(x1 - s.x() + d, e->staff()->height() * .5); // center vertically in measure
2016-05-02 13:41:41 +02:00
s.createShape(staffIdx);
2016-01-04 14:48:58 +01:00
}
else { // if (rest->isFullMeasureRest()) {
//
// center full measure rest
//
2016-05-02 13:41:41 +02:00
e->rxpos() = (x2 - x1 - e->width()) * .5 + x1 - s.x() - e->bbox().x();
s.createShape(staffIdx); // DEBUG
2016-01-04 14:48:58 +01:00
}
}
2017-01-18 14:16:33 +01:00
else if (t == ElementType::REST)
2016-01-04 14:48:58 +01:00
e->rxpos() = 0;
2017-01-18 14:16:33 +01:00
else if (t == ElementType::CHORD) {
2016-02-17 14:54:23 +01:00
Chord* c = toChord(e);
2016-02-16 21:21:28 +01:00
c->layout2();
2019-03-23 06:07:35 +01:00
if (c->tremolo()) {
Tremolo* tr = c->tremolo();
Chord* c1 = tr->chord1();
Chord* c2 = tr->chord2();
if (!tr->twoNotes() || (c1 && !c1->staffMove() && c2 && !c2->staffMove()))
tr->layout();
2019-03-23 06:07:35 +01:00
}
2016-02-16 21:21:28 +01:00
}
2017-01-18 14:16:33 +01:00
else if (t == ElementType::BAR_LINE) {
2017-08-02 18:19:08 +02:00
e->rypos() = 0.0;
2019-04-28 22:00:10 +02:00
// for end barlines, x position was set in createEndBarLines
if (s.segmentType() != SegmentType::EndBarLine)
e->rxpos() = 0.0;
2016-01-04 14:48:58 +01:00
}
}
}
}
//---------------------------------------------------
// computeTicks
// set ticks for all segments
// return minTick
//---------------------------------------------------
Fraction Measure::computeTicks()
{
Fraction minTick = ticks();
if (minTick <= Fraction(0,1)) {
qDebug("=====minTick %d measure %p", minTick.ticks(), this);
}
Q_ASSERT(minTick > Fraction(0,1));
Segment* ns = first();
while (ns && !ns->enabled())
ns = ns->next();
while (ns) {
Segment* s = ns;
ns = s->nextActive();
Fraction nticks = (ns ? ns->rtick() : ticks()) - s->rtick();
if (nticks.isNotZero()) {
if (nticks < minTick)
minTick = nticks;
}
s->setTicks(nticks);
}
return minTick;
}
//---------------------------------------------------------
// endBarLine
// return the first one
//---------------------------------------------------------
2016-10-18 15:41:00 +02:00
const BarLine* Measure::endBarLine() const
2016-01-04 14:48:58 +01:00
{
// search barline segment:
Segment* s = last();
while (s && !s->isEndBarLineType())
s = s->prev();
// search first element
if (s) {
for (const Element* e : s->elist()) {
if (e)
return toBarLine(e);
2016-10-18 15:41:00 +02:00
}
}
return 0;
}
2016-10-18 15:41:00 +02:00
//---------------------------------------------------------
// endBarLineType
// Assume all barlines have same type if there is more
// than one.
//---------------------------------------------------------
2016-10-18 15:41:00 +02:00
BarLineType Measure::endBarLineType() const
{
const BarLine* bl = endBarLine();
return bl ? bl->barLineType() : BarLineType::NORMAL;
}
2016-10-18 15:41:00 +02:00
//---------------------------------------------------------
// endBarLineType
// Assume all barlines have same visiblity if there is more
// than one.
//---------------------------------------------------------
2016-10-18 15:41:00 +02:00
bool Measure::endBarLineVisible() const
{
const BarLine* bl = endBarLine();
return bl ? bl->visible() : true;
}
2016-10-18 15:41:00 +02:00
//---------------------------------------------------------
// triggerLayout
//---------------------------------------------------------
2016-10-18 15:41:00 +02:00
void Measure::triggerLayout() const
{
score()->setLayout(tick());
score()->setLayout(endTick());
}
2016-10-18 15:41:00 +02:00
//---------------------------------------------------------
// setEndBarLineType
// Create a *generated* barline with the given type and
// properties if none exists. Modify if it exists.
// Useful for import filters.
//---------------------------------------------------------
2016-10-18 15:41:00 +02:00
void Measure::setEndBarLineType(BarLineType val, int track, bool visible, QColor color)
{
2017-03-08 13:12:26 +01:00
Segment* seg = undoGetSegment(SegmentType::EndBarLine, endTick());
// get existing bar line for this staff, if any
BarLine* bl = toBarLine(seg->element(track));
if (!bl) {
// no suitable bar line: create a new one
bl = new BarLine(score());
bl->setParent(seg);
bl->setTrack(track);
score()->addElement(bl);
2016-10-18 15:41:00 +02:00
}
bl->setGenerated(false);
bl->setBarLineType(val);
bl->setVisible(visible);
bl->setColor(color.isValid() ? color : curColor());
2016-10-18 15:41:00 +02:00
}
//---------------------------------------------------------
// barLinesSetSpan
2016-10-18 15:41:00 +02:00
//---------------------------------------------------------
void Measure::barLinesSetSpan(Segment* seg)
2016-10-18 15:41:00 +02:00
{
2016-12-23 12:05:18 +01:00
int track = 0;
for (Staff* staff : score()->staves()) {
BarLine* bl = toBarLine(seg->element(track)); // get existing bar line for this staff, if any
if (bl) {
if (bl->generated()) {
bl->setSpanStaff(staff->barLineSpan());
bl->setSpanFrom(staff->barLineFrom());
bl->setSpanTo(staff->barLineTo());
}
}
else {
2016-12-23 12:05:18 +01:00
bl = new BarLine(score());
bl->setParent(seg);
bl->setTrack(track);
bl->setGenerated(true);
bl->setSpanStaff(staff->barLineSpan());
bl->setSpanFrom(staff->barLineFrom());
bl->setSpanTo(staff->barLineTo());
bl->layout();
score()->addElement(bl);
2016-10-18 15:41:00 +02:00
}
2016-12-23 12:05:18 +01:00
track += VOICES;
2016-10-18 15:41:00 +02:00
}
}
//---------------------------------------------------------
// createEndBarLines
// actually creates or modifies barlines
// return the width change for measure
//---------------------------------------------------------
qreal Measure::createEndBarLines(bool isLastMeasureInSystem)
{
2016-12-23 12:05:18 +01:00
int nstaves = score()->nstaves();
2017-03-08 13:12:26 +01:00
Segment* seg = findSegmentR(SegmentType::EndBarLine, ticks());
2016-12-23 12:05:18 +01:00
Measure* nm = nextMeasure();
2019-04-28 22:00:10 +02:00
qreal blw = 0.0;
#if 0
#ifndef NDEBUG
computeMinWidth();
#endif
#endif
qreal oldWidth = width();
2016-10-18 15:41:00 +02:00
if (nm && nm->repeatStart() && !isLastMeasureInSystem && !repeatEnd()) {
2016-10-20 11:32:07 +02:00
// no barline, use StartBarLine of next measure
2016-10-18 15:41:00 +02:00
if (!seg)
return 0.0;
2016-10-20 11:32:07 +02:00
seg->setEnabled(false);
2016-10-18 15:41:00 +02:00
}
else {
2016-10-20 11:32:07 +02:00
BarLineType t = nm ? BarLineType::NORMAL : BarLineType::END;
2016-10-18 15:41:00 +02:00
if (!seg)
seg = getSegmentR(SegmentType::EndBarLine, ticks());
2016-10-20 11:32:07 +02:00
seg->setEnabled(true);
2016-10-18 15:41:00 +02:00
//
// Set flag "hasCourtesyKeySig" if this measure needs a courtesy key sig.
// This flag is later used to set a double end bar line and to actually
// create the courtesy key sig.
//
2018-03-27 15:36:00 +02:00
bool show = score()->styleB(Sid::genCourtesyKeysig) && !sectionBreak() && nm;
2016-10-18 15:41:00 +02:00
setHasCourtesyKeySig(false);
if (isLastMeasureInSystem && show) {
Fraction tick = endTick();
2016-10-18 15:41:00 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
Staff* staff = score()->staff(staffIdx);
KeySigEvent key1 = staff->keySigEvent(tick - Fraction::fromTicks(1));
2016-10-18 15:41:00 +02:00
KeySigEvent key2 = staff->keySigEvent(tick);
if (!(key1 == key2)) {
// locate a key sig. in next measure and, if found,
// check if it has court. sig turned off
2017-03-08 13:12:26 +01:00
Segment* s = nm->findSegment(SegmentType::KeySig, tick);
2016-10-18 15:41:00 +02:00
if (s) {
KeySig* ks = toKeySig(s->element(staffIdx * VOICES));
if (ks && !ks->showCourtesy())
continue;
}
setHasCourtesyKeySig(true);
t = BarLineType::DOUBLE;
break;
}
}
}
bool force = false;
2017-03-20 18:24:16 +01:00
if (repeatEnd()) {
2016-10-18 15:41:00 +02:00
t = BarLineType::END_REPEAT;
force = true;
}
else if (isLastMeasureInSystem && nextMeasure() && nextMeasure()->repeatStart()) {
t = BarLineType::NORMAL;
2018-01-08 16:31:31 +01:00
// force = true;
2016-10-18 15:41:00 +02:00
}
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
2017-03-07 18:01:56 +01:00
int track = staffIdx * VOICES;
BarLine* bl = toBarLine(seg->element(track));
Staff* staff = score()->staff(staffIdx);
2016-12-23 12:05:18 +01:00
if (!bl) {
bl = new BarLine(score());
bl->setParent(seg);
bl->setTrack(track);
bl->setGenerated(true);
bl->setSpanStaff(staff->barLineSpan());
bl->setSpanFrom(staff->barLineFrom());
bl->setSpanTo(staff->barLineTo());
bl->setBarLineType(t);
score()->addElement(bl);
}
else {
2016-10-18 15:41:00 +02:00
// do not change bar line type if bar line is user modified
// and its not a repeat start/end barline (forced)
if (bl->generated()) {
bl->setSpanStaff(staff->barLineSpan());
bl->setSpanFrom(staff->barLineFrom());
bl->setSpanTo(staff->barLineTo());
bl->setBarLineType(t);
}
else {
if (bl->barLineType() != t) {
2017-03-07 18:01:56 +01:00
if (force) {
2018-03-27 15:36:00 +02:00
bl->undoChangeProperty(Pid::BARLINE_TYPE, QVariant::fromValue(t));
2017-03-07 18:01:56 +01:00
bl->setGenerated(true);
2016-12-23 12:05:18 +01:00
}
2016-10-18 15:41:00 +02:00
}
}
}
2017-03-07 18:01:56 +01:00
bl->layout();
2019-04-28 22:00:10 +02:00
blw = qMax(blw, bl->width());
}
// right align within segment
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
int track = staffIdx * VOICES;
BarLine* bl = toBarLine(seg->element(track));
if (bl)
bl->rxpos() += blw - bl->width();
2016-10-18 15:41:00 +02:00
}
seg->createShapes();
2016-10-20 11:32:07 +02:00
}
2016-10-18 15:41:00 +02:00
// set relative position of end barline and clef
// if end repeat, clef goes after, otherwise clef goes before
Segment* clefSeg = findSegmentR(SegmentType::Clef, ticks());
if (clefSeg) {
if (clefSeg) {
Segment* s1;
Segment* s2;
if (repeatEnd()) {
s1 = seg;
s2 = clefSeg;
}
else {
s1 = clefSeg;
s2 = seg;
}
if (s1->next() != s2) {
_segments.remove(s1);
_segments.insert(s1, s2);
}
}
}
2016-10-20 11:32:07 +02:00
// fix segment layout
Segment* s = seg->prevActive();
if (s) {
qreal x = s->rxpos();
computeMinWidth(s, x, false);
}
2016-10-18 15:41:00 +02:00
2017-02-23 11:41:53 +01:00
#if 0
#ifndef NDEBUG
qreal w = width();
computeMinWidth();
if (!qFuzzyCompare(w, width()))
qDebug("width mismatch %f != %f at %d", w, width(), tick());
2017-02-23 11:41:53 +01:00
#endif
#endif
2016-10-18 15:41:00 +02:00
return width() - oldWidth;
}
//---------------------------------------------------------
// basicStretch
//---------------------------------------------------------
qreal Measure::basicStretch() const
{
2018-03-27 15:36:00 +02:00
qreal stretch = userStretch() * score()->styleD(Sid::measureSpacing);
2016-10-18 15:41:00 +02:00
if (stretch < 1.0)
stretch = 1.0;
return stretch;
}
//---------------------------------------------------------
// basicWidth
//---------------------------------------------------------
qreal Measure::basicWidth() const
{
Segment* ls = last();
qreal w = (ls->x() + ls->width()) * basicStretch();
2018-03-27 15:36:00 +02:00
qreal minMeasureWidth = score()->styleP(Sid::minMeasureWidth);
2016-10-18 15:41:00 +02:00
if (w < minMeasureWidth)
w = minMeasureWidth;
return w;
}
//---------------------------------------------------------
// layoutWeight
//---------------------------------------------------------
int Measure::layoutWeight(int maxMMRestLength) const
{
int w = ticks().ticks();
// reduce weight of mmrests
// so the nominal width is not directly proportional to duration (still linear, just not 1:1)
// and they are not so "greedy" in taking up available space on a system
if (isMMRest()) {
int timesigTicks = timesig().ticks();
// TODO: style setting
if (maxMMRestLength) {
int maxW = timesigTicks * maxMMRestLength;
w = qMin(w, maxW);
}
w -= timesigTicks;
w = timesigTicks + w / 32;
}
return w;
}
//-------------------------------------------------------------------
// addSystemHeader
/// Add elements to make this measure suitable as the first measure
/// of a system.
// The system header can contain a starting BarLine, a Clef,
// and a KeySig
//-------------------------------------------------------------------
void Measure::addSystemHeader(bool isFirstSystem)
{
int staffIdx = 0;
Segment* kSegment = findFirstR(SegmentType::KeySig, Fraction(0,1));
Segment* cSegment = findFirstR(SegmentType::HeaderClef, Fraction(0,1));
for (const Staff* staff : score()->staves()) {
const int track = staffIdx * VOICES;
if (isFirstSystem || score()->styleB(Sid::genClef)) {
// find the clef type at the previous tick
ClefTypeList cl = staff->clefType(tick() - Fraction::fromTicks(1));
Segment* s = nullptr;
if (prevMeasure())
// look for a clef change at the end of the previous measure
s = prevMeasure()->findSegment(SegmentType::Clef, tick());
else if (isMMRest())
// look for a header clef at the beginning of the first underlying measure
s = mmRestFirst()->findFirstR(SegmentType::HeaderClef, Fraction(0,1));
if (s) {
Clef* c = toClef(s->element(track));
if (c)
cl = c->clefTypeList();
}
Clef* clef;
if (!cSegment) {
cSegment = new Segment(this, SegmentType::HeaderClef, Fraction(0,1));
cSegment->setHeader(true);
add(cSegment);
clef = 0;
}
else
clef = toClef(cSegment->element(track));
if (staff->staffType(tick())->genClef()) {
if (!clef) {
//
// create missing clef
//
clef = new Clef(score());
clef->setTrack(track);
clef->setGenerated(true);
clef->setParent(cSegment);
cSegment->add(clef);
}
if (clef->generated())
clef->setClefType(cl);
clef->setSmall(false);
clef->layout();
}
else if (clef) {
clef->parent()->remove(clef);
delete clef;
}
//cSegment->createShape(staffIdx);
cSegment->setEnabled(true);
}
else {
if (cSegment)
cSegment->setEnabled(false);
}
// keep key sigs in TABs: TABs themselves should hide them
2018-03-27 15:36:00 +02:00
bool needKeysig = isFirstSystem || score()->styleB(Sid::genKeysig);
// If we need a Key::C KeySig (which would be invisible) and there is
// a courtesy key sig, dont create it and switch generated flags.
// This avoids creating an invisible KeySig which can distort layout.
KeySigEvent keyIdx = staff->keySigEvent(tick());
KeySig* ksAnnounce = 0;
if (needKeysig && (keyIdx.key() == Key::C)) {
Measure* pm = prevMeasure();
if (pm && pm->hasCourtesyKeySig()) {
2017-03-08 13:12:26 +01:00
Segment* ks = pm->first(SegmentType::KeySigAnnounce);
if (ks) {
ksAnnounce = toKeySig(ks->element(track));
if (ksAnnounce) {
needKeysig = false;
// if (keysig) {
// ksAnnounce->setGenerated(false);
2016-11-07 09:59:06 +01:00
//TODO keysig->setGenerated(true);
// }
}
}
}
}
needKeysig = needKeysig && (keyIdx.key() != Key::C || keyIdx.custom() || keyIdx.isAtonal());
if (needKeysig) {
KeySig* keysig;
if (!kSegment) {
kSegment = new Segment(this, SegmentType::KeySig, Fraction(0,1));
kSegment->setHeader(true);
add(kSegment);
keysig = 0;
}
else
keysig = toKeySig(kSegment->element(track));
if (!keysig) {
//
// create missing key signature
//
keysig = new KeySig(score());
keysig->setTrack(track);
keysig->setGenerated(true);
keysig->setParent(kSegment);
kSegment->add(keysig);
}
keysig->setKeySigEvent(keyIdx);
keysig->layout();
//kSegment->createShape(staffIdx);
kSegment->setEnabled(true);
}
else {
if (kSegment && staff->isPitchedStaff(tick())) {
// do not disable user modified keysigs
bool disable = true;
for (int i = 0; i < score()->nstaves(); ++i) {
Element* e = kSegment->element(i * VOICES);
Key key = score()->staff(i)->key(tick());
if ((e && !e->generated()) || (key != keyIdx.key())) {
disable = false;
}
else if (e && e->generated() && key == keyIdx.key() && keyIdx.key() == Key::C){
// If a key sig segment is disabled, it may be re-enabled if there is
// a transposing instrument using a different key sig.
// To prevent this from making the wrong key sig display, remove any key
// sigs on staves where the key in this measure is C.
kSegment->remove(e);
}
}
if (disable)
kSegment->setEnabled(false);
else {
Element* e = kSegment->element(track);
if (e && e->isKeySig()) {
KeySig* keysig = toKeySig(e);
keysig->layout();
}
}
}
}
++staffIdx;
}
if (cSegment)
cSegment->createShapes();
if (kSegment)
kSegment->createShapes();
//
// create systemic barline
//
2017-03-08 13:12:26 +01:00
Segment* s = findSegment(SegmentType::BeginBarLine, tick());
int n = score()->nstaves();
2018-03-27 15:36:00 +02:00
if ((n > 1 && score()->styleB(Sid::startBarlineMultiple)) || (n == 1 && score()->styleB(Sid::startBarlineSingle))) {
2016-12-23 12:05:18 +01:00
if (!s) {
s = new Segment(this, SegmentType::BeginBarLine, Fraction(0,1));
2016-12-23 12:05:18 +01:00
add(s);
}
for (int track = 0; track < score()->ntracks(); track += VOICES) {
BarLine* bl = toBarLine(s->element(track));
if (!bl) {
bl = new BarLine(score());
bl->setTrack(track);
bl->setGenerated(true);
bl->setParent(s);
2016-12-29 15:11:28 +01:00
bl->setBarLineType(BarLineType::NORMAL);
bl->setSpanStaff(true);
2016-12-23 12:05:18 +01:00
bl->layout();
s->add(bl);
}
}
s->createShapes();
2016-12-23 12:05:18 +01:00
s->setEnabled(true);
s->setHeader(true);
setHeader(true);
}
else if (s)
s->setEnabled(false);
checkHeader();
}
//---------------------------------------------------------
// addSystemTrailer
//---------------------------------------------------------
void Measure::addSystemTrailer(Measure* nm)
{
Fraction _rtick = ticks();
bool isFinalMeasure = isFinalMeasureOfSection();
// locate a time sig. in the next measure and, if found,
// check if it has court. sig. turned off
TimeSig* ts = nullptr;
bool showCourtesySig = false;
2017-03-08 13:12:26 +01:00
Segment* s = findSegmentR(SegmentType::TimeSigAnnounce, _rtick);
if (score()->genCourtesyTimesig() && !isFinalMeasure && !score()->floatMode()) {
Segment* tss = nm->findSegmentR(SegmentType::TimeSig, Fraction(0,1));
if (tss) {
int nstaves = score()->nstaves();
for (int track = 0; track < nstaves * VOICES; track += VOICES) {
ts = toTimeSig(tss->element(track));
if (ts)
break;
}
if (ts && ts->showCourtesySig()) {
showCourtesySig = true;
// if due, create a new courtesy time signature for each staff
if (!s) {
2017-03-08 13:12:26 +01:00
s = new Segment(this, SegmentType::TimeSigAnnounce, _rtick);
s->setTrailer(true);
add(s);
}
s->setEnabled(true);
for (int track = 0; track < nstaves * VOICES; track += VOICES) {
TimeSig* nts = toTimeSig(tss->element(track));
if (!nts)
continue;
ts = toTimeSig(s->element(track));
if (!ts) {
ts = new TimeSig(score());
ts->setTrack(track);
ts->setGenerated(true);
ts->setParent(s);
score()->undoAddElement(ts);
}
ts->setFrom(nts);
ts->layout();
//s->createShape(track / VOICES);
}
s->createShapes();
}
}
}
if (!showCourtesySig && s) {
// remove any existing time signatures
s->setEnabled(false);
}
// courtesy key signatures, clefs
int n = score()->nstaves();
bool show = hasCourtesyKeySig();
2017-03-08 13:12:26 +01:00
s = findSegmentR(SegmentType::KeySigAnnounce, _rtick);
2017-03-08 13:12:26 +01:00
Segment* clefSegment = findSegmentR(SegmentType::Clef, ticks());
for (int staffIdx = 0; staffIdx < n; ++staffIdx) {
int track = staffIdx * VOICES;
Staff* staff = score()->staff(staffIdx);
if (show) {
if (!s) {
2017-03-08 13:12:26 +01:00
s = new Segment(this, SegmentType::KeySigAnnounce, _rtick);
s->setTrailer(true);
add(s);
}
KeySig* ks = toKeySig(s->element(track));
KeySigEvent key2 = staff->keySigEvent(endTick());
if (!ks) {
ks = new KeySig(score());
ks->setTrack(track);
ks->setGenerated(true);
ks->setParent(s);
s->add(ks);
}
//else if (!(ks->keySigEvent() == key2)) {
// score()->undo(new ChangeKeySig(ks, key2, ks->showCourtesy()));
// }
ks->setKeySigEvent(key2);
ks->layout();
//s->createShape(track / VOICES);
s->setEnabled(true);
}
else {
// remove any existent courtesy key signature
if (s)
s->setEnabled(false);
}
if (clefSegment) {
Clef* clef = toClef(clefSegment->element(track));
if (clef) {
clef->setSmall(true);
if (!score()->genCourtesyClef() || isFinalMeasure || !clef->showCourtesy())
clef->clear(); // make invisible
}
}
}
if (s)
s->createShapes();
if (clefSegment)
clefSegment->createShapes();
checkTrailer();
}
//---------------------------------------------------------
// removeSystemHeader
//---------------------------------------------------------
void Measure::removeSystemHeader()
{
if (!header())
return;
for (Segment* seg = first(); seg; seg = seg->next()) {
if (!seg->header())
break;
seg->setEnabled(false);
}
setHeader(false);
}
//---------------------------------------------------------
// removeSystemTrailer
//---------------------------------------------------------
void Measure::removeSystemTrailer()
{
bool changed = false;
for (Segment* seg = last(); seg != first(); seg = seg->prev()) {
if (!seg->trailer())
break;
if (seg->enabled())
seg->setEnabled(false);
changed = true;
}
setTrailer(false);
if (system() && changed)
computeMinWidth();
}
//---------------------------------------------------------
// checkHeader
//---------------------------------------------------------
void Measure::checkHeader()
{
for (Segment* seg = first(); seg; seg = seg->next()) {
if (seg->enabled() && seg->header()) {
setHeader(seg->header());
break;
}
}
}
//---------------------------------------------------------
// checkTrailer
//---------------------------------------------------------
void Measure::checkTrailer()
{
for (Segment* seg = last(); seg != first(); seg = seg->prev()) {
if (seg->enabled() && seg->trailer()) {
setTrailer(seg->trailer());
break;
}
}
}
2016-10-31 10:55:11 +01:00
//---------------------------------------------------------
// setStretchedWidth
//---------------------------------------------------------
void Measure::setStretchedWidth(qreal w)
{
qreal minWidth = isMMRest() ? score()->styleP(Sid::minMMRestWidth) : score()->styleP(Sid::minMeasureWidth);
2016-10-31 10:55:11 +01:00
if (w < minWidth)
w = minWidth;
2017-10-18 13:09:35 +02:00
qreal stretchableWidth = 0.0;
for (Segment* s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
if (!s->enabled())
continue;
stretchableWidth += s->width();
}
const int maxMMRestLength = 32; // TODO: style
int weight = layoutWeight(maxMMRestLength);
w += stretchableWidth * (basicStretch() - 1.0) * weight / 1920.0;
2016-10-31 10:55:11 +01:00
setWidth(w);
}
2016-10-18 15:41:00 +02:00
2017-10-18 13:09:35 +02:00
//---------------------------------------------------------
// hasAccidental
//---------------------------------------------------------
static bool hasAccidental(Segment* s)
{
Score* score = s->score();
2017-10-18 13:09:35 +02:00
for (int track = 0; track < s->score()->ntracks(); ++track) {
Staff* staff = score->staff(track2staff(track));
if (!staff->show())
continue;
2017-10-18 13:09:35 +02:00
Element* e = s->element(track);
if (!e || !e->isChord())
continue;
Chord* c = toChord(e);
for (Note* n : c->notes()) {
if (n->accidental())
return true;
}
}
return false;
}
//---------------------------------------------------------
// computeMinWidth
// sets the minimum stretched width of segment list s
// set the width and x position for all segments
//---------------------------------------------------------
2016-11-07 09:59:06 +01:00
void Measure::computeMinWidth(Segment* s, qreal x, bool isSystemHeader)
{
Segment* fs = firstEnabled();
if (!fs->visible()) // first enabled could be a clef change on invisible staff
fs = fs->nextActive();
bool first = system()->firstMeasure() == this;
2016-11-07 09:59:06 +01:00
const Shape ls(first ? QRectF(0.0, -1000000.0, 0.0, 2000000.0) : QRectF(0.0, 0.0, 0.0, spatium() * 4));
if (isMMRest()) {
// Reset MM rest to initial size and position
Segment* seg = findSegmentR(SegmentType::ChordRest, Fraction(0,1));
const int nstaves = score()->nstaves();
for (int st = 0; st < nstaves; ++st) {
Rest* mmRest = toRest(seg->element(staff2track(st)));
if (mmRest) {
mmRest->rxpos() = 0;
mmRest->layoutMMRest(score()->styleP(Sid::minMMRestWidth) * mag());
mmRest->segment()->createShapes();
}
}
}
while (s) {
s->rxpos() = x;
if (!s->enabled() || !s->visible()) {
s->setWidth(0);
s = s->next();
continue;
}
Segment* ns = s->nextActive();
// end barline might be disabled
// but still consider it for spacing of previous segment
if (!ns)
ns = s->next(SegmentType::BarLineType);
qreal w;
if (ns) {
if (isSystemHeader && (ns->isChordRestType() || (ns->isClefType() && !ns->header()))) {
// this is the system header gap
w = s->minHorizontalDistance(ns, true);
isSystemHeader = false;
}
else {
w = s->minHorizontalDistance(ns, false);
}
// printf(" min %f <%s>(%d) <%s>(%d)\n", s->x(), s->subTypeName(), s->enabled(), ns->subTypeName(), ns->enabled());
#if 1
// look back for collisions with previous segments
// this is time consuming (ca. +5%) and probably requires more optimization
if (s == fs) // don't let the second segment cross measure start (not covered by the loop below)
w = std::max(w, ns->minLeft(ls) - s->x());
int n = 1;
2016-11-02 14:07:39 +01:00
for (Segment* ps = s; ps != fs;) {
qreal ww;
ps = ps->prevActive();
Q_ASSERT(ps); // ps should never be nullptr but better be safe.
if (!ps)
break;
if (ps->isChordRestType())
++n;
ww = ps->minHorizontalCollidingDistance(ns) - (s->x() - ps->x());
2016-11-02 14:07:39 +01:00
if (ps == fs)
ww = std::max(ww, ns->minLeft(ls) - s->x());
if (ww > w) {
// overlap !
// distribute extra space between segments ps - ss;
// only ChordRest segments get more space
// TODO: is there a special case n == 0 ?
qreal d = (ww - w) / n;
qreal xx = ps->x();
for (Segment* ss = ps; ss != s;) {
Segment* ns1 = ss->nextActive();
qreal ww1 = ss->width();
if (ss->isChordRestType()) {
ww1 += d;
ss->setWidth(ww1);
}
xx += ww1;
ns1->rxpos() = xx;
ss = ns1;
}
w += d;
x = xx;
break;
}
}
#endif
}
else
w = s->minRight();
s->setWidth(w);
x += w;
2016-11-07 09:59:06 +01:00
s = s->next();
}
setStretchedWidth(x);
}
2016-11-07 09:59:06 +01:00
void Measure::computeMinWidth()
{
Segment* s;
//
// skip disabled segment
//
for (s = first(); s && !s->enabled(); s = s->next()) {
s->rxpos() = 0;
s->setWidth(0);
}
if (!s) {
setWidth(0.0);
return;
}
qreal x;
bool first = system()->firstMeasure() == this;
// left barriere:
// Make sure no elements crosses the left boarder if first measure in a system.
//
Shape ls(first ? QRectF(0.0, -1000000.0, 0.0, 2000000.0) : QRectF(0.0, 0.0, 0.0, spatium() * 4));
x = s->minLeft(ls);
2017-12-19 12:16:38 +01:00
if (s->isStartRepeatBarLineType()) {
System* sys = system();
2017-12-19 12:16:38 +01:00
MeasureBase* pmb = prev();
if (pmb->isMeasure() && pmb->system() == sys && pmb->repeatEnd()) {
Segment* seg = toMeasure(pmb)->last();
2017-12-19 12:16:38 +01:00
// overlap end repeat barline with start repeat barline
if (seg->isEndBarLineType())
2018-03-27 15:36:00 +02:00
x -= score()->styleP(Sid::endBarWidth) * mag();
2017-12-19 12:16:38 +01:00
}
}
if (s->isChordRestType())
2018-03-27 15:36:00 +02:00
x += score()->styleP(hasAccidental(s) ? Sid::barAccidentalDistance : Sid::barNoteDistance);
else if (s->isClefType() || s->isHeaderClefType())
2018-03-27 15:36:00 +02:00
x += score()->styleP(Sid::clefLeftMargin);
2016-11-07 09:59:06 +01:00
else if (s->isKeySigType())
2018-03-27 15:36:00 +02:00
x = qMax(x, score()->styleP(Sid::keysigLeftMargin));
2016-11-07 09:59:06 +01:00
else if (s->isTimeSigType())
2018-03-27 15:36:00 +02:00
x = qMax(x, score()->styleP(Sid::timesigLeftMargin));
2016-11-07 09:59:06 +01:00
x += s->extraLeadingSpace().val() * spatium();
bool isSystemHeader = s->header();
computeMinWidth(s, x, isSystemHeader);
}
2013-05-13 18:49:17 +02:00
}