MuseScore/libmscore/measure.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

4561 lines
146 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 "log.h"
2012-05-26 14:26:10 +02:00
#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);
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
if (_vspacerUp) {
_vspacerUp->setScore(score);
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
if (_vspacerDown) {
_vspacerDown->setScore(score);
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
if (_noText) {
_noText->setScore(score);
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
}
//---------------------------------------------------------
// setTrack
//---------------------------------------------------------
void MStaff::setTrack(int track)
{
if (_lines) {
_lines->setTrack(track);
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
if (_vspacerUp) {
_vspacerUp->setTrack(track);
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
if (_vspacerDown) {
_vspacerDown->setTrack(track);
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
if (_noText) {
_noText->setTrack(track);
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// Measure
//---------------------------------------------------------
2020-05-29 18:47:27 +02:00
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;
2020-05-26 15:54:26 +02:00
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
//---------------------------------------------------------
2020-05-29 18:47:27 +02:00
Measure::Measure(const Measure& m)
: MeasureBase(m)
2012-05-26 14:26:10 +02:00
{
2016-02-04 11:27:47 +01:00
_segments = m._segments.clone();
_timesig = m._timesig;
_len = m._len;
_repeatCount = m._repeatCount;
_noMode = m._noMode;
2016-02-04 11:27:47 +01:00
_userStretch = m._userStretch;
2020-05-26 15:54:26 +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));
2020-05-26 15:54:26 +02:00
}
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();
2020-05-26 15:54:26 +02:00
}
2016-12-12 14:55:35 +01:00
}
//---------------------------------------------------------
// 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);
}
2020-05-26 15:54:26 +02:00
}
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()));
2020-05-26 15:54:26 +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;
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
Chord* crd = toChord(e);
for (Chord* chord1 : crd->graceNotes()) {
for (Note* note1 : chord1->notes()) {
if (note1->tieBack() && note1->accidental() == 0) {
continue;
2020-05-26 15:54:26 +02:00
}
//
// compute accidental
//
int tpc = note1->tpc();
int line = absStep(tpc, note1->epitch());
2020-05-26 15:54:26 +02:00
if (note == note1) {
return tversatz.accidentalVal(line);
}
tversatz.setAccidentalVal(line, tpc2alter(tpc));
2012-05-26 14:26:10 +02:00
}
2020-05-26 15:54:26 +02:00
}
for (Note* note1 : crd->notes()) {
if (note1->tieBack() && note1->accidental() == 0) {
2012-08-06 21:55:51 +02:00
continue;
2020-05-26 15:54:26 +02:00
}
//
2012-08-07 12:44:19 +02:00
// compute accidental
2020-05-26 15:54:26 +02:00
//
int tpc = note1->tpc();
int line = absStep(tpc, note1->epitch());
2020-05-26 15:54:26 +02:00
if (note == note1) {
return tversatz.accidentalVal(line);
2020-05-26 15:54:26 +02:00
}
tversatz.setAccidentalVal(line, tpc2alter(tpc));
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
}
2020-05-26 15:54:26 +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()));
2020-05-26 15:54:26 +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;
2020-05-26 15:54:26 +02:00
}
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) {
2012-08-06 21:55:51 +02:00
continue;
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
2012-08-06 21:55:51 +02:00
int tpc = note->tpc();
int l = absStep(tpc, note->epitch());
2012-08-06 21:55:51 +02:00
tversatz.setAccidentalVal(l, tpc2alter(tpc));
}
2020-05-26 15:54:26 +02:00
}
}
2012-08-06 21:55:51 +02:00
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());
}
2020-05-26 15:54:26 +02:00
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();
2020-05-26 15:54:26 +02:00
}
2013-06-19 16:25:29 +02:00
if (tck <= tick2) {
2012-05-26 14:26:10 +02:00
break;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
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
}
//---------------------------------------------------------
2020-03-10 07:50:48 +01:00
// showsMeasureNumberInAutoMode
/// Wheter the measure will show measure number(s) when MeasureNumberMode is set to AUTO
//---------------------------------------------------------
2020-03-10 07:50:48 +01:00
bool Measure::showsMeasureNumberInAutoMode()
{
2020-03-10 07:50:48 +01:00
// Check wheter any measure number should be shown
if (!score()->styleB(Sid::showMeasureNumber)) {
return false;
2020-05-26 15:54:26 +02:00
}
2020-03-10 07:50:48 +01:00
// Measure numbers should not be shown on irregular measures.
if (irregular()) {
return false;
2020-05-26 15:54:26 +02:00
}
2020-03-10 07:50:48 +01:00
// Measure numbers should not show on first measure unless specified with Sid::showMeasureNumberOne
if (!no()) {
return score()->styleB(Sid::showMeasureNumberOne);
2020-05-26 15:54:26 +02:00
}
2020-03-10 07:50:48 +01:00
if (score()->styleB(Sid::measureNumberSystem)) {
// Show either if
// 1) This is the first measure of the system OR
// 2) The previous measure in the system is the first, and is irregular.
return isFirstInSystem()
|| (prevMeasure() && prevMeasure()->irregular() && prevMeasure()->isFirstInSystem());
} else {
// In the case of an interval, we should show the measure number either if:
// 1) We should show them every measure
int interval = score()->styleI(Sid::measureNumberInterval);
if (interval == 1) {
return true;
2020-05-26 15:54:26 +02:00
}
2020-03-10 07:50:48 +01:00
// 2) (measureNumber + 1) % interval == 0 (or 1 if measure number one is numbered.)
// If measure number 1 is numbered, and the interval is let's say 5, then we should number #1, 6, 11, 16, etc.
// If measure number 1 is not numbered, with the same interval (5), then we should number #5, 10, 15, 20, etc.
return ((no() + 1) % score()->styleI(Sid::measureNumberInterval))
== (score()->styleB(Sid::showMeasureNumberOne) ? 1 : 0);
}
}
2020-03-10 07:50:48 +01:00
//---------------------------------------------------------
// showsMeasureNumber
/// Wheter the Measure shows a MeasureNumber
//---------------------------------------------------------
bool Measure::showsMeasureNumber()
{
if (_noMode == MeasureNumberMode::SHOW) {
2020-03-10 07:50:48 +01:00
return true;
} else if (_noMode == MeasureNumberMode::HIDE) {
2020-03-10 07:50:48 +01:00
return false;
} else {
2020-03-10 07:50:48 +01:00
return showsMeasureNumberInAutoMode();
}
2020-03-10 07:50:48 +01:00
}
//---------------------------------------------------------
// layoutMeasureNumber
/// Layouts the Measure Numbers according to the Measure's MeasureNumberMode
//---------------------------------------------------------
void Measure::layoutMeasureNumber()
{
bool smn = showsMeasureNumber();
2020-05-26 15:54:26 +02:00
QString s;
if (smn) {
s = QString("%1").arg(no() + 1);
2020-05-26 15:54:26 +02:00
}
unsigned nn = 1;
2020-03-11 19:57:32 +01:00
bool nas = score()->styleB(Sid::measureNumberAllStaves);
2020-05-26 15:54:26 +02:00
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;
}
2020-05-26 15:54:26 +02:00
}
}
for (unsigned staffIdx = 0; staffIdx < _mstaves.size(); ++staffIdx) {
MStaff* ms = _mstaves[staffIdx];
MeasureNumber* t = ms->noText();
if (t) {
t->setTrack(staffIdx * VOICES);
2020-05-26 15:54:26 +02:00
}
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 {
2020-05-26 15:54:26 +02:00
if (t) {
if (t->generated()) {
score()->removeElement(t);
2020-05-26 15:54:26 +02:00
} else {
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveElement(t));
2020-05-26 15:54:26 +02:00
}
}
}
}
}
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());
2020-05-26 15:54:26 +02:00
}
}
2012-05-26 14:26:10 +02:00
MeasureBase::layout(); // layout LAYOUT_BREAK elements
2020-05-26 15:54:26 +02:00
2012-05-26 14:26:10 +02:00
//---------------------------------------------------
// layout ties
2012-05-26 14:26:10 +02:00
//---------------------------------------------------
2020-05-26 15:54:26 +02: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;
2014-07-02 09:55:50 +02:00
continue;
2012-05-26 14:26:10 +02:00
}
for (Segment* seg = first(st); seg; seg = seg->next(st)) {
ChordRest* cr = seg->cr(track);
2020-05-26 15:54:26 +02:00
if (!cr) {
2014-07-02 09:55:50 +02:00
continue;
2012-05-26 14:26:10 +02:00
}
2016-01-04 14:48:58 +01:00
if (cr->isChord()) {
2016-10-18 15:41:00 +02:00
Chord* c = toChord(cr);
c->layoutSpanners(system(), stick);
2012-05-26 14:26:10 +02:00
}
}
2020-05-26 15:54:26 +02:00
}
}
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;
2020-05-26 15:54:26 +02:00
}
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
}
2020-05-26 15:54:26 +02:00
}
}
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;
2020-05-26 15:54:26 +02:00
}
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
}
2020-05-26 15:54:26 +02:00
}
}
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
}
2020-05-26 15:54:26 +02:00
}
2016-10-20 11:32:07 +02:00
if (s.rtick() > t) {
2020-05-26 15:54:26 +02: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()) {
2020-05-26 15:54:26 +02:00
}
2016-10-20 11:32:07 +02:00
while (s && s->prev() && s->prev()->rtick() == t) {
s = s->prev();
}
} else {
// search forwards
for (s = first(); s && s->rtick() < t; s = s->next()) {
2020-05-26 15:54:26 +02:00
}
2016-10-20 11:32:07 +02:00
}
for (; s && s->rtick() == t; s = s->next()) {
2014-08-21 15:01:54 +02:00
if (s->segmentType() & st) {
return s;
2020-05-26 15:54:26 +02:00
}
}
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;
2020-05-26 15:54:26 +02:00
}
}
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();
2020-05-26 15:54:26 +02:00
switch (type) {
2018-10-24 10:40:03 +02:00
case ElementType::SEGMENT:
2012-05-26 14:26:10 +02:00
{
2016-10-12 20:06:46 +02:00
Segment* seg = toSegment(e);
Fraction t = seg->rtick();
2017-01-18 14:16:33 +01:00
SegmentType st = seg->segmentType();
Segment* s;
2020-05-26 15:54:26 +02:00
2016-12-23 12:05:18 +01:00
for (s = first(); s && s->rtick() < t; s = s->next()) {
2020-05-26 15:54:26 +02:00
}
while (s && s->rtick() == t) {
if (!seg->isChordRestType() && (seg->segmentType() == s->segmentType())) {
qDebug("there is already a <%s> segment", seg->subTypeName());
return;
2020-05-26 15:54:26 +02:00
}
if (s->segmentType() > st) {
break;
2012-05-26 14:26:10 +02:00
}
s = s->next();
2012-05-26 14:26:10 +02:00
}
seg->setParent(this);
_segments.insert(seg, s);
2020-05-26 15:54:26 +02:00
//
// update measure flags
2020-05-26 15:54:26 +02:00
//
if (seg->header()) {
seg->measure()->setHeader(true);
2020-05-26 15:54:26 +02:00
}
if (seg->trailer()) {
seg->measure()->setTrailer(true);
2020-05-26 15:54:26 +02:00
}
}
break;
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));
2020-05-26 15:54:26 +02:00
}
break;
2017-01-18 14:16:33 +01:00
case ElementType::SPACER:
2020-05-26 15:54:26 +02:00
{
2016-10-18 15:41:00 +02:00
Spacer* sp = toSpacer(e);
2016-10-12 20:06:46 +02:00
switch (sp->spacerType()) {
case SpacerType::UP:
2016-12-12 12:02:18 +01:00
_mstaves[e->staffIdx()]->setVspacerUp(sp);
2020-05-26 15:54:26 +02:00
break;
2016-10-12 20:06:46 +02:00
case SpacerType::DOWN:
case SpacerType::FIXED:
2016-12-12 12:02:18 +01:00
_mstaves[e->staffIdx()]->setVspacerDown(sp);
2020-05-26 15:54:26 +02:00
break;
}
sp->setGap(sp->gap()); // trigger relayout
2020-05-26 15:54:26 +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
2020-05-26 15:54:26 +02:00
2017-01-18 14:16:33 +01:00
case ElementType::MARKER:
2016-01-04 14:48:58 +01:00
el().push_back(e);
2020-05-26 15:54:26 +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())); // ?!
2020-05-26 15:54:26 +02:00
}
2016-01-04 14:48:58 +01:00
el().push_back(e);
2020-05-26 15:54:26 +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);
2020-05-26 15:54:26 +02:00
break;
case ElementType::STAFFTYPE_CHANGE:
2020-05-26 15:54:26 +02:00
{
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;
2020-05-26 15:54:26 +02:00
} 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);
2020-05-26 15:54:26 +02:00
}
staff->staffTypeListChanged(tick());
stc->setStaffType(nst);
2016-01-04 14:48:58 +01:00
MeasureBase::add(e);
2020-05-26 15:54:26 +02:00
}
break;
default:
2016-01-04 14:48:58 +01:00
MeasureBase::add(e);
2020-05-26 15:54:26 +02:00
break;
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// 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());
2020-05-26 15:54:26 +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();
2020-05-26 15:54:26 +02:00
}
if (s->trailer()) {
s->measure()->checkTrailer();
}
2020-05-26 15:54:26 +02:00
}
break;
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
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);
2012-05-26 14:26:10 +02:00
break;
2020-05-26 15:54:26 +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
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
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;
}
2020-05-26 15:54:26 +02:00
}
}
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;
2020-05-26 15:54:26 +02:00
2017-01-18 14:16:33 +01:00
case ElementType::MEASURE:
2013-10-30 14:21:08 +01:00
_mmRest = 0;
break;
2020-05-26 15:54:26 +02:00
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());
if (!tick().isZero()) {
staff->removeStaffType(tick());
2012-05-26 14:26:10 +02:00
}
stc->setStaffType(st);
2012-05-26 14:26:10 +02:00
}
2016-01-04 14:48:58 +01:00
MeasureBase::remove(e);
2020-05-26 15:54:26 +02:00
}
break;
default:
2016-01-04 14:48:58 +01:00
MeasureBase::remove(e);
2020-05-26 15:54:26 +02:00
break;
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// 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
}
2020-05-26 15:54:26 +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;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
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;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
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
}
2020-05-26 15:54:26 +02:00
}
2016-01-04 14:48:58 +01: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
}
2020-05-26 15:54:26 +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) {
2014-07-27 15:06:49 +02:00
continue;
2020-05-26 15:54:26 +02:00
}
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));
2020-05-26 15:54:26 +02:00
}
}
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveStaves(this, sStaff, eStaff));
2020-05-26 15:54:26 +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
}
2020-05-26 15:54:26 +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));
2020-05-26 15:54:26 +02:00
2017-03-08 13:12:26 +01:00
Segment* ts = findSegment(SegmentType::TimeSig, tick());
Segment* bs = findSegmentR(SegmentType::EndBarLine, ticks());
2020-05-26 15:54:26 +02:00
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));
2020-05-26 15:54:26 +02:00
}
2014-07-27 15:06:49 +02:00
if (!createRest && !ts) {
2020-05-26 15:54:26 +02:00
return;
}
2014-07-27 15:06:49 +02:00
// create list of unique staves (only one instance for linked staves):
2020-05-26 15:54:26 +02:00
2014-07-27 15:06:49 +02:00
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;
2020-05-26 15:54:26 +02:00
break;
}
2014-07-27 15:06:49 +02:00
}
if (alreadyInList) {
continue;
}
2020-05-26 15:54:26 +02:00
}
2014-07-27 15:06:49 +02:00
sl.append(staffIdx);
2020-05-26 15:54:26 +02:00
}
2014-07-27 15:06:49 +02:00
for (int staffIdx : sl) {
if (createRest) {
score()->setRest(tick(), staffIdx * VOICES, ticks(), false, 0, _timesig == ticks());
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
// replicate time signature
if (ts) {
TimeSig* ots = 0;
bool constructed = false;
2012-05-26 14:26:10 +02:00
for (unsigned track = 0; track < _mstaves.size() * VOICES; ++track) {
2016-10-18 15:41:00 +02:00
if (ts->element(track)) {
ots = toTimeSig(ts->element(track));
break;
}
2020-05-26 15:54:26 +02:00
}
if (!ots) {
// no time signature found; use measure timesig to construct one
2012-05-26 14:26:10 +02:00
ots = new TimeSig(score());
ots->setSig(timesig());
constructed = true;
2012-05-26 14:26:10 +02:00
}
// do no replicate local time signatures
if (ots && !ots->isLocal()) {
TimeSig* timesig = new TimeSig(*ots);
timesig->setTrack(staffIdx * VOICES);
timesig->setParent(ts);
timesig->setSig(ots->sig(), ots->timeSigType());
score()->undoAddElement(timesig);
if (constructed) {
delete ots;
}
2012-05-26 14:26:10 +02:00
}
}
2020-05-26 15:54:26 +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);
2020-05-26 15:54:26 +02:00
break;
}
}
if (obl) {
2012-05-26 14:26:10 +02:00
BarLine* barline = new BarLine(*obl);
barline->setSpanStaff(score()->staff(staffIdx)->barLineSpan());
2016-12-12 12:02:18 +01:00
barline->setTrack(staffIdx * VOICES);
barline->setParent(bs);
barline->setGenerated(false);
2012-05-26 14:26:10 +02:00
score()->undoAddElement(barline);
2020-05-26 15:54:26 +02:00
}
}
}
}
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);
2020-05-26 15:54:26 +02:00
}
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);
2020-05-26 15:54:26 +02:00
}
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);
2020-05-26 15:54:26 +02:00
}
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()->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;
2020-05-26 15:54:26 +02: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;
2020-05-26 15:54:26 +02:00
}
2014-08-13 21:01:21 +02:00
QRectF staffR = system()->staff(staffIdx)->bbox().translated(system()->canvasPos());
staffR &= canvasBoundingRect();
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
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());
2020-05-26 15:54:26 +02:00
}
2014-08-13 21:01:21 +02:00
return true;
2020-05-26 15:54:26 +02:00
2020-02-24 06:28:58 +01:00
case ElementType::MEASURE_NUMBER:
viewer->setDropRectangle(canvasBoundingRect());
return true;
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +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:
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);
2020-05-26 15:54:26 +02:00
2012-05-26 14:26:10 +02:00
if (e->systemFlag()) {
staffIdx = 0;
2020-05-26 15:54:26 +02:00
}
if (staffIdx < 0) {
return 0;
2020-05-26 15:54:26 +02:00
}
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);
2020-05-26 15:54:26 +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;
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
2020-02-24 06:28:58 +01:00
case ElementType::MEASURE_NUMBER:
undoChangeProperty(Pid::MEASURE_NUMBER_MODE, static_cast<int>(MeasureNumberMode::SHOW));
delete e;
break;
2020-05-26 15:54:26 +02:00
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;
}
2020-05-26 15:54:26 +02:00
}
firstStaff++;
2020-05-26 15:54:26 +02:00
}
Selection sel = score()->selection();
score()->undoAddBracket(staff, level, b->bracketType(), sel.staffEnd() - sel.staffStart());
2012-05-26 14:26:10 +02:00
delete b;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
break;
2020-05-26 15:54:26 +02:00
2017-01-18 14:16:33 +01:00
case ElementType::CLEF:
score()->undoChangeClef(staff, this, toClef(e)->clefType());
delete e;
2012-05-26 14:26:10 +02:00
break;
2020-05-26 15:54:26 +02:00
2017-01-18 14:16:33 +01:00
case ElementType::KEYSIG:
2020-05-26 15:54:26 +02:00
{
KeySigEvent k = toKeySig(e)->keySigEvent();
delete e;
2020-05-26 15:54:26 +02:00
if (data.modifiers & Qt::ControlModifier) {
// apply only to this stave
score()->undoChangeKeySig(staff, tick(), k);
2017-01-18 14:16:33 +01:00
} else {
// apply to all staves:
for (Staff* s : score()->staves()) {
score()->undoChangeKeySig(s, tick(), k);
2020-05-26 15:54:26 +02:00
}
}
break;
2020-05-26 15:54:26 +02:00
}
case ElementType::TIMESIG:
score()->cmdAddTimeSig(this, staffIdx, toTimeSig(e), data.modifiers & Qt::ControlModifier);
break;
2020-05-26 15:54:26 +02: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);
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
} else {
measure->setLineBreak(false);
}
break;
case LayoutBreak::NOBREAK:
2016-10-12 20:06:46 +02:00
if (measure->noBreak()) {
delete b;
2016-10-12 20:06:46 +02:00
b = 0;
2020-05-26 15:54:26 +02:00
} else {
measure->setLineBreak(false);
2016-10-12 20:06:46 +02:00
measure->setPageBreak(false);
2020-05-26 15:54:26 +02:00
}
break;
}
2016-10-12 20:06:46 +02:00
if (b) {
b->setTrack(-1); // these are system elements
b->setParent(measure);
score()->undoAddElement(b);
2020-05-26 15:54:26 +02:00
}
2016-10-12 20:06:46 +02:00
measure->cleanupLayoutBreaks(true);
return b;
}
2020-05-26 15:54:26 +02:00
case ElementType::SPACER:
{
2016-10-12 20:06:46 +02:00
Spacer* spacer = toSpacer(e);
spacer->setTrack(staffIdx * VOICES);
2012-05-26 14:26:10 +02:00
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);
2016-10-12 20:06:46 +02:00
const bool systemEnd = (nextVisStaffIdx == score()->nstaves());
2012-05-26 14:26:10 +02:00
if (systemEnd) {
System* ns = 0;
for (System* ts : score()->systems()) {
if (ns) {
2016-10-18 15:41:00 +02:00
ns = ts;
break;
2020-05-26 15:54:26 +02:00
}
if (ts == s) {
ns = ts;
2020-05-26 15:54:26 +02:00
}
}
2016-12-18 14:31:13 +01:00
if (ns && ns->page() == s->page()) {
2016-10-18 15:41:00 +02:00
qreal y1 = s->staffYpage(staffIdx);
qreal y2 = ns->staffYpage(0);
gap = y2 - y1 - score()->staff(staffIdx)->height();
2020-05-26 15:54:26 +02:00
}
} else {
qreal y1 = s->staffYpage(staffIdx);
qreal y2 = s->staffYpage(nextVisStaffIdx);
gap = y2 - y1 - score()->staff(staffIdx)->height();
2020-05-26 15:54:26 +02:00
}
spacer->setGap(gap);
2020-05-26 15:54:26 +02:00
}
score()->undoAddElement(spacer);
triggerLayout();
2019-04-06 07:54:38 +02:00
return spacer;
2020-05-26 15:54:26 +02:00
}
2019-04-06 07:54:38 +02:00
case ElementType::BAR_LINE:
{
BarLine* bl = toBarLine(e);
2020-05-26 15:54:26 +02:00
// if dropped bar line refers to span rather than to subtype
// or if Ctrl key used
if ((bl->spanFrom() && bl->spanTo()) || data.control()) {
2018-01-04 12:41:42 +01:00
// get existing bar line for this staff, and drop the change to it
seg = undoGetSegmentR(SegmentType::EndBarLine, ticks());
2018-01-04 12:41:42 +01:00
BarLine* cbl = toBarLine(seg->element(staffIdx * VOICES));
2020-05-26 15:54:26 +02:00
if (cbl) {
cbl->drop(data);
2020-05-26 15:54:26 +02:00
}
2018-01-04 12:41:42 +01:00
} else if (bl->barLineType() == BarLineType::START_REPEAT) {
Measure* m2 = isMMRest() ? mmRestFirst() : this;
2018-01-04 12:41:42 +01:00
for (Score* lscore : score()->scoreList()) {
2017-01-18 14:16:33 +01:00
Measure* lmeasure = lscore->tick2measure(m2->tick());
2012-05-26 14:26:10 +02:00
if (lmeasure) {
lmeasure->undoChangeProperty(Pid::REPEAT_START, true);
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
}
2017-01-18 14:16:33 +01:00
} else if (bl->barLineType() == BarLineType::END_REPEAT) {
Measure* m2 = isMMRest() ? mmRestLast() : this;
2016-10-18 15:41:00 +02:00
for (Score* lscore : score()->scoreList()) {
2017-01-18 14:16:33 +01:00
Measure* lmeasure = lscore->tick2measure(m2->tick());
if (lmeasure) {
2017-01-18 14:16:33 +01:00
lmeasure->undoChangeProperty(Pid::REPEAT_END, true);
2020-05-26 15:54:26 +02:00
}
}
2017-01-18 14:16:33 +01: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) {
2017-01-18 14:16:33 +01:00
lmeasure->undoChangeProperty(Pid::REPEAT_END, true);
2012-05-26 14:26:10 +02:00
lmeasure = lmeasure->nextMeasure();
if (lmeasure) {
2017-01-18 14:16:33 +01:00
lmeasure->undoChangeProperty(Pid::REPEAT_START, true);
2020-05-26 15:54:26 +02:00
}
}
}
2017-01-18 14:16:33 +01:00
} else {
2016-12-18 14:31:13 +01:00
// drop to first end barline
seg = findSegmentR(SegmentType::EndBarLine, ticks());
2018-01-04 12:41:42 +01:00
if (seg) {
2016-12-18 14:31:13 +01:00
for (Element* ee : seg->elist()) {
if (ee) {
2012-05-26 14:26:10 +02:00
ee->drop(data);
break;
2020-05-26 15:54:26 +02:00
}
}
} else {
2012-05-26 14:26:10 +02:00
delete e;
}
2020-05-26 15:54:26 +02:00
}
break;
}
2017-01-18 14:16:33 +01:00
case ElementType::REPEAT_MEASURE:
2020-05-26 15:54:26 +02:00
{
2012-05-26 14:26:10 +02:00
delete e;
return cmdInsertRepeatMeasure(staffIdx);
2020-05-26 15:54:26 +02: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);
2020-05-26 15:54:26 +02:00
break;
case IconType::HFRAME:
2017-01-18 14:16:33 +01:00
score()->insertMeasure(ElementType::HBOX, this);
2020-05-26 15:54:26 +02:00
break;
case IconType::TFRAME:
2017-01-18 14:16:33 +01:00
score()->insertMeasure(ElementType::TBOX, this);
2020-05-26 15:54:26 +02:00
break;
case IconType::FFRAME:
2017-01-18 14:16:33 +01:00
score()->insertMeasure(ElementType::FBOX, this);
2020-05-26 15:54:26 +02:00
break;
case IconType::MEASURE:
2017-01-18 14:16:33 +01:00
score()->insertMeasure(ElementType::MEASURE, this);
2020-05-26 15:54:26 +02:00
break;
default:
break;
}
break;
case ElementType::STAFFTYPE_CHANGE:
2020-05-26 15:54:26 +02:00
{
2012-05-26 14:26:10 +02:00
e->setParent(this);
e->setTrack(staffIdx * VOICES);
score()->undoAddElement(e);
2020-05-26 15:54:26 +02:00
}
break;
default:
2012-05-26 14:26:10 +02:00
qDebug("Measure: cannot drop %s here", e->name());
delete e;
2020-05-26 15:54:26 +02:00
break;
}
2012-05-26 14:26:10 +02:00
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) {
2017-03-08 13:12:26 +01:00
Element* el = s->element(track);
2016-01-04 14:48:58 +01:00
if (el) {
2016-03-10 10:41:31 +01:00
score()->undoRemoveElement(el);
2020-05-26 15:54:26 +02:00
}
}
2020-05-26 15:54:26 +02:00
}
}
//
// add repeat measure
2020-05-26 15:54:26 +02:00
//
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);
2020-05-26 15:54:26 +02:00
}
}
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;
2020-05-26 15:54:26 +02:00
Fraction startTick = endTick();
if (diff < Fraction(0,1)) {
startTick += diff;
2020-05-26 15:54:26 +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));
2020-05-26 15:54:26 +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);
2012-05-26 14:26:10 +02:00
}
}
2020-05-26 15:54:26 +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();
2020-05-26 15:54:26 +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);
} else if (e->isChord()) {
2013-10-21 13:11:04 +02:00
++chords;
2012-05-26 14:26:10 +02:00
}
}
}
2020-05-26 15:54:26 +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);
2020-05-26 15:54: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
}
2020-05-26 15:54: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
2020-05-26 15:54:26 +02:00
}
2014-05-20 17:26:26 +02:00
continue;
2020-05-26 15:54:26 +02:00
}
2013-10-21 13:11:04 +02:00
int strack = staffIdx * VOICES;
2012-05-26 14:26:10 +02:00
int etrack = strack + VOICES;
2020-05-26 15:54:26 +02:00
2013-10-21 13:11:04 +02:00
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);
2020-05-26 15:54:26 +02:00
}
}
2014-05-20 17:26:26 +02:00
Element* e = segment->element(trk);
2017-03-08 13:12:26 +01:00
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();
2020-05-26 15:54:26 +02:00
}
s->undoRemoveElement(e);
if (n >= Fraction(0,1)) {
break;
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
}
} else if (segment->segmentType() == SegmentType::Breath) {
2013-10-21 13:11:04 +02:00
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;
2020-05-26 15:54:26 +02:00
}
2013-10-21 13:11:04 +02:00
rFlag = true;
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
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;
2012-05-26 14:26:10 +02:00
int track = staffIdx * VOICES + voice;
s->setRest(rtick, track, n * stretch, false, 0, false);
2020-05-26 15:54:26 +02:00
}
}
}
if (diff < Fraction(0,1)) {
2012-05-26 14:26:10 +02:00
//
// CHECK: do not remove all slurs
//
2020-02-24 06:28:58 +01:00
for (Element* e : m->el()) {
2016-10-18 15:41:00 +02:00
if (e->isSlur()) {
2014-05-20 17:26:26 +02:00
s->undoRemoveElement(e);
2012-05-26 14:26:10 +02:00
}
}
2020-05-26 15:54:26 +02:00
}
}
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);
2020-05-26 15:54:26 +02:00
}
2016-11-19 10:31:14 +01:00
xml.setCurTick(tick());
xml.setCurTrack(staff * VOICES);
2020-05-26 15:54:26 +02:00
2014-02-26 19:06:42 +01:00
if (_mmRestCount > 0) {
xml.tag("multiMeasureRest", _mmRestCount);
2020-05-26 15:54:26 +02:00
}
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");
2020-05-26 15:54:26 +02:00
}
2016-02-04 11:27:47 +01:00
if (repeatEnd()) {
2012-05-26 14:26:10 +02:00
xml.tag("endRepeat", _repeatCount);
2020-05-26 15:54:26 +02:00
}
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()) {
mstaff->noText()->write(xml);
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
if (mstaff->vspacerUp()) {
xml.tag("vspacerUp", mstaff->vspacerUp()->gap() / _spatium);
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
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);
2020-05-26 15:54:26 +02:00
}
2016-10-12 20:06:46 +02:00
}
2016-12-12 12:02:18 +01:00
if (!mstaff->visible()) {
xml.tag("visible", mstaff->visible());
2020-05-26 15:54:26 +02:00
}
if (mstaff->stemless()) {
xml.tag("slashStyle", mstaff->stemless()); // for backwards compatibility
xml.tag("stemless", mstaff->stemless());
}
2020-05-26 15:54:26 +02:00
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);
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
}
Q_ASSERT(first());
Q_ASSERT(last());
2020-03-19 10:51:00 +01:00
if (first() && last()) {
score()->writeSegments(xml, strack, etrack, first(), last()->next1(), writeSystemElements, forceTimeSig);
2020-05-26 15:54:26 +02:00
}
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);
2020-05-26 15:54:26 +02: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);
2020-05-26 15:54:26 +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());
2020-05-26 15:54:26 +02:00
} else {
2013-01-11 18:10:18 +01:00
qDebug("illegal measure size <%s>", qPrintable(e.attribute("len")));
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
irregular = true;
if (_len.numerator() <= 0 || _len.denominator() <= 0) {
e.raiseError(QObject::tr("MSCX error at line %1: invalid measure length: %2").arg(e.lineNumber()).arg(_len.
toString()));
2020-05-26 15:54:26 +02:00
return;
}
score()->sigmap()->add(tick().ticks(), SigEvent(_len, _timesig));
score()->sigmap()->add((tick() + ticks()).ticks(), SigEvent(_timesig));
2020-05-26 15:54:26 +02:00
} else {
irregular = false;
2020-05-26 15:54:26 +02:00
}
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
2020-05-26 15:54:26 +02:00
if (tag == "voice") {
e.setTrack(nextTrack++);
e.setTick(tick());
readVoice(e, staffIdx, irregular);
} else if (tag == "Image") {
if (MScore::noImages) {
e.skipCurrentElement();
2020-05-26 15:54:26 +02:00
} else {
Element* el = Element::name2Element(tag, score());
el->setTrack(staffIdx * VOICES);
el->read(e);
2020-05-26 15:54:26 +02:00
add(el);
2012-05-26 14:26:10 +02:00
}
} 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) {
2020-05-26 15:54:26 +02:00
val = 0;
2012-05-26 14:26:10 +02:00
}
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);
2020-05-26 15:54:26 +02:00
}
_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);
2020-05-26 15:54:26 +02:00
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);
2013-01-21 20:21:41 +01:00
noText->setTrack(e.track());
2020-05-26 15:54:26 +02:00
add(noText);
} else if (MeasureBase::readProperties(e)) {
2020-05-26 15:54:26 +02:00
} else {
e.unknown();
2020-05-26 15:54:26 +02:00
}
}
e.checkConnectors();
2017-01-18 14:16:33 +01:00
if (isMMRest()) {
2019-04-06 07:54:38 +02:00
Measure* lm = e.lastMeasure();
e.setTick(lm->tick() + lm->ticks());
2020-05-26 15:54:26 +02:00
}
e.setCurrentMeasure(nullptr);
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
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()));
2020-05-26 15:54:26 +02:00
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
2020-05-26 15:54:26 +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
2020-05-26 15:54:26 +02:00
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;
} 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;
2020-05-26 15:54:26 +02:00
}
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);
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
if (!rest->ticks().isValid()) { // hack
rest->setTicks(timesig() / timeStretch);
}
2014-07-28 15:54:47 +02:00
if (tuplet) {
tuplet->add(rest);
2020-05-26 15:54:26 +02:00
}
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);
2020-05-26 15:54:26 +02:00
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
2020-05-26 15:54:26 +02:00
bool header;
if (e.tick() != tick()) {
header = false;
} else if (!segment) {
header = true;
2020-05-26 15:54:26 +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;
2020-05-26 15:54:26 +02:00
}
2013-07-12 18:41:33 +02:00
}
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());
2014-10-08 10:57:24 +02:00
ts->setTrack(e.track());
ts->read(e);
// if time sig not at beginning of measure => courtesy time sig
Fraction currTick = e.tick();
bool courtesySig = (currTick > tick());
if (courtesySig) {
2014-08-24 13:10:51 +02:00
// if courtesy sig., just add it without map processing
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::TimeSigAnnounce, currTick);
2014-08-24 13:10:51 +02:00
segment->add(ts);
2012-05-26 14:26:10 +02:00
} else {
// if 'real' time sig., do full process
2017-03-08 13:12:26 +01:00
segment = getSegment(SegmentType::TimeSig, currTick);
2012-09-21 12:23:18 +02:00
segment->add(ts);
2020-05-26 15:54:26 +02:00
2013-01-21 20:21:41 +01:00
timeStretch = ts->stretch().reduced();
2017-03-08 13:12:26 +01:00
_timesig = ts->sig() / timeStretch;
2020-05-26 15:54:26 +02:00
2012-05-26 14:26:10 +02:00
if (irregular) {
2013-01-18 10:55:52 +01:00
score()->sigmap()->add(tick().ticks(), SigEvent(_len, _timesig));
score()->sigmap()->add((tick() + ticks()).ticks(), SigEvent(_timesig));
2013-01-21 20:21:41 +01:00
} else {
2017-03-08 13:12:26 +01:00
_len = _timesig;
score()->sigmap()->add(tick().ticks(), SigEvent(_timesig));
}
2020-05-26 15:54:26 +02:00
}
} else if (tag == "KeySig") {
2018-06-09 06:19:36 +02:00
KeySig* ks = new KeySig(score());
2013-01-21 20:21:41 +01:00
ks->setTrack(e.track());
ks->read(e);
Fraction curTick = e.tick();
2018-06-09 06:19:36 +02:00
if (!ks->isCustom() && !ks->isAtonal() && ks->key() == Key::C && curTick.isZero()) {
// 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);
segment->add(ks);
2014-08-24 13:10:51 +02:00
if (!courtesySig) {
2013-01-11 18:10:18 +01:00
staff->setKey(curTick, ks->keySigEvent());
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
}
} else if (tag == "Text") {
2018-06-09 04:45:54 +02:00
StaffText* t = new StaffText(score());
2013-01-21 20:21:41 +01:00
t->setTrack(e.track());
2018-06-09 04:45:54 +02:00
t->read(e);
if (t->empty()) {
qDebug("==reading empty text: deleted");
delete t;
2020-05-26 15:54:26 +02:00
} else {
2018-06-09 04:45:54 +02:00
segment = getSegment(SegmentType::ChordRest, e.tick());
segment->add(t);
2018-06-09 04:45:54 +02:00
}
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
//----------------------------------------------------
// Annotation
2018-06-09 06:19:36 +02:00
else if (tag == "Dynamic") {
Dynamic* dyn = new Dynamic(score());
dyn->setTrack(e.track());
dyn->read(e);
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"
|| tag == "SystemText"
|| tag == "RehearsalMark"
2012-05-26 14:26:10 +02:00
|| tag == "InstrumentChange"
|| tag == "StaffState"
|| tag == "FiguredBass"
2020-05-26 15:54:26 +02: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
2018-06-09 06:19:36 +02:00
el->setTrack(e.track());
el->read(e);
2018-06-09 06:19:36 +02:00
segment = getSegment(SegmentType::ChordRest, e.tick());
segment->add(el);
} else if (tag == "Fermata") {
fermata = new Fermata(score());
2018-06-09 06:19:36 +02:00
fermata->setTrack(e.track());
fermata->setPlacement(fermata->track() & 1 ? Placement::BELOW : Placement::ABOVE);
fermata->read(e);
2020-05-26 15:54:26 +02:00
}
2018-06-09 06:19:36 +02:00
// There could be an Image here if the score was saved with an earlier version of MuseScore 3.
// This image would not have been visible upon reload. Let's read it in and add it directly
// to the measure so that it can be displayed.
else if (tag == "Image") {
if (MScore::noImages) {
2018-06-09 06:19:36 +02:00
e.skipCurrentElement();
} else {
Element* el = Element::name2Element(tag, score());
el->setTrack(e.track());
el->read(e);
2020-05-26 15:54:26 +02:00
add(el);
2018-06-09 06:19:36 +02:00
}
2020-05-26 15:54:26 +02:00
}
//----------------------------------------------------
else if (tag == "Tuplet") {
Tuplet* oldTuplet = tuplet;
tuplet = new Tuplet(score());
tuplet->setTrack(e.track());
tuplet->setTick(e.tick());
tuplet->setParent(this);
tuplet->read(e);
2018-06-09 06:19:36 +02:00
if (oldTuplet) {
oldTuplet->add(tuplet);
}
2012-05-26 14:26:10 +02:00
} else if (tag == "endTuplet") {
2018-06-09 06:19:36 +02:00
if (!tuplet) {
qDebug("Measure::read: encountered <endTuplet/> when no tuplet was started");
e.skipCurrentElement();
continue;
2020-05-26 15:54:26 +02:00
}
2018-06-09 06:19:36 +02:00
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);
2020-05-26 15:54:26 +02:00
}
2018-06-09 06:19:36 +02:00
delete oldTuplet;
2020-05-26 15:54:26 +02:00
}
2018-06-09 06:19:36 +02:00
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;
2020-05-26 15:54:26 +02:00
}
2018-06-09 04:45:54 +02:00
startingBeam = beam;
} 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()));
2012-05-26 14:26:10 +02:00
segment->add(range);
2020-05-26 15:54:26 +02:00
} else {
e.unknown();
2020-05-26 15:54:26 +02:00
}
}
2018-06-09 04:45:54 +02:00
if (startingBeam) {
qDebug("The read beam was not used");
delete startingBeam;
2020-05-26 15:54:26 +02:00
}
2018-06-09 06:19:36 +02:00
if (tuplet) {
qDebug("Measure:readVoice: measure index=%d, <endTuplet/> not found", e.currentMeasureIndex());
if (tuplet->elements().empty()) {
if (tuplet->tuplet()) {
tuplet->tuplet()->remove(tuplet);
2020-05-26 15:54:26 +02:00
}
2018-06-09 06:19:36 +02:00
delete tuplet;
2020-05-26 15:54:26 +02:00
}
}
if (fermata) {
SegmentType st = (e.tick() == endTick() ? SegmentType::EndBarLine : SegmentType::ChordRest);
2017-03-08 13:12:26 +01:00
segment = getSegment(st, e.tick());
segment->add(fermata);
fermata = nullptr;
2020-05-26 15:54:26 +02:00
}
}
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;
2020-05-26 15:54:26 +02:00
}
if (score()->staff(staffIdx)->cutaway() && isEmpty(staffIdx)) {
return false;
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
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());
}
//---------------------------------------------------------
// isFirstInSystem
//---------------------------------------------------------
bool Measure::isFirstInSystem() const
{
IF_ASSERT_FAILED(system()) {
return false;
}
return system()->firstMeasure() == this;
}
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);
2020-05-26 15:54:26 +02:00
2012-05-26 14:26:10 +02:00
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;
2020-05-26 15:54:26 +02:00
}
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());
2020-05-26 15:54:26 +02:00
}
2016-12-12 12:02:18 +01:00
if (ms->vspacerDown()) {
func(data, ms->vspacerDown());
2020-05-26 15:54:26 +02:00
}
if (ms->noText()) {
func(data, ms->noText());
2012-05-26 14:26:10 +02:00
}
2020-05-26 15:54:26 +02:00
}
2016-10-20 11:32:07 +02:00
for (Segment* s = first(); s; s = s->next()) {
if (!s->enabled()) {
continue;
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
Chord* c = toChord(e);
Tremolo* tremolo = c->tremolo();
if (tremolo && tremolo->twoNotes()) {
// Ensure correct duration type for chord
c->setDurationType(tremolo->durationType());
2020-05-26 15:54:26 +02:00
// 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;
2020-05-26 15:54:26 +02:00
}
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);
2020-05-26 15:54:26 +02:00
break;
}
2020-05-26 15:54:26 +02:00
}
}
}
2020-05-26 15:54:26 +02:00
}
}
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;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
if (s->element(track) == 0) {
score()->setRest(s->tick(), track, ticks(), true, 0);
2020-05-26 15:54:26 +02:00
}
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]);
2020-05-26 15:54:26 +02:00
}
2016-01-04 14:48:58 +01:00
_mstaves = ms;
2020-05-26 15:54:26 +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);
2020-05-26 15:54:26 +02:00
}
2016-02-09 09:20:54 +01:00
for (Segment& s : _segments) {
s.sortStaves(dst);
2020-05-26 15:54:26 +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;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
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);
2020-05-26 15:54:26 +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);
2012-05-26 14:26:10 +02:00
}
2016-10-18 15:41:00 +02:00
if (sp->track2() == strack && spEnd < end) {
sp->setTrack2(dtrack);
} else if (sp->track2() == dtrack && spEnd < end) {
sp->setTrack2(strack);
}
2020-05-26 15:54:26 +02:00
}
}
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)
{
if (hasVoices(staffIdx, tick(), ticks())) {
_mstaves[staffIdx]->setHasVoices(true);
} else {
_mstaves[staffIdx]->setHasVoices(false);
2020-05-26 15:54:26 +02:00
}
}
//---------------------------------------------------------
// hasVoices
//---------------------------------------------------------
bool Measure::hasVoices(int staffIdx, Fraction stick, Fraction len) const
2012-05-26 14:26:10 +02:00
{
int strack = staffIdx * VOICES + 1;
int etrack = staffIdx * VOICES + VOICES;
Fraction etick = stick + len;
2020-05-26 15:54:26 +02:00
2017-03-08 13:12:26 +01:00
for (Segment* s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
if (s->tick() >= etick) {
break;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
for (int track = strack; track < etrack; ++track) {
ChordRest* cr = toChordRest(s->element(track));
if (cr) {
if (cr->tick() + cr->actualTicks() <= stick) {
continue;
2020-05-26 15:54:26 +02:00
}
bool v = false;
if (cr->isChord()) {
// consider chord visible if any note is visible
Chord* c = toChord(cr);
for (Note* n : c->notes()) {
if (n->visible()) {
v = true;
break;
2012-05-26 14:26:10 +02:00
}
}
} else if (cr->isRest()) {
v = cr->visible() && !toRest(cr)->isGap();
2020-05-26 15:54:26 +02:00
}
if (v) {
2012-05-26 14:26:10 +02:00
return true;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
}
2020-05-26 15:54:26 +02:00
}
}
return false;
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;
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
if (s->element(track)) {
return true;
}
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
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;
2020-05-26 15:54:26 +02:00
} else {
2016-09-28 21:13:05 +02:00
strack = staffIdx * VOICES;
2014-08-26 21:01:21 +02:00
etrack = strack + VOICES;
2020-05-26 15:54:26 +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;
}
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
for (Element* a : s->annotations()) {
if (!a || a->systemFlag() || !a->visible() || a->isFermata()) {
2014-08-26 21:01:21 +02:00
continue;
2012-05-26 14:26:10 +02:00
}
int atrack = a->track();
if (atrack >= strack && atrack < etrack) {
return false;
2012-05-26 14:26:10 +02:00
}
2020-05-26 15:54:26 +02:00
}
}
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;
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
}
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;
}
2020-05-26 15:54:26 +02:00
}
}
2012-05-26 14:26:10 +02:00
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);
2020-05-26 15:54:26 +02:00
2012-08-02 18:33:43 +02:00
if (s == 0) {
2012-05-26 14:26:10 +02:00
return false;
2020-05-26 15:54:26 +02:00
}
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->isRepeatMeasure()) {
2012-05-26 14:26:10 +02:00
return true;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
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;
2020-05-26 15:54:26 +02:00
}
restFound = true;
2012-05-26 14:26:10 +02:00
}
2020-05-26 15:54:26 +02:00
}
if (restFound) {
2020-05-26 15:54:26 +02:00
++n;
}
// measure is not empty if there is more than one rest
2018-03-27 15:36:00 +02:00
if (n > 1) {
return false;
2020-05-26 15:54:26 +02:00
}
}
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;
2020-05-26 15:54:26 +02:00
}
2016-10-18 15:41:00 +02:00
if (!s->element(track)->isRest()) {
return false;
}
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
if (s->element(track)->isRest() ? !toRest(s->element(track))->isGap() : !s->element(track)->isRest()) {
return false;
}
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
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
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
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);
2020-05-26 15:54:26 +02:00
m->setHeader(header());
m->setTrailer(trailer());
2020-05-26 15:54:26 +02:00
int tracks = sc->nstaves() * VOICES;
2012-05-26 14:26:10 +02:00
TupletMap tupletMap;
2020-05-26 15:54:26 +02:00
2012-05-26 14:26:10 +02:00
for (Segment* oseg = first(); oseg; oseg = oseg->next()) {
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());
2020-05-26 15:54:26 +02:00
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);
for (Element* e : oseg->annotations()) {
if (e->generated() || e->track() != track) {
continue;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
Element* ne = e->clone();
ne->setTrack(track);
ne->setOffset(e->offset());
ne->setScore(sc);
2016-10-20 11:32:07 +02:00
s->add(ne);
2020-05-26 15:54:26 +02:00
}
if (!oe) {
2016-10-20 11:32:07 +02:00
continue;
2020-05-26 15:54:26 +02:00
}
2016-10-20 11:32:07 +02:00
Element* ne = oe->clone();
2014-08-13 17:45:53 +02:00
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) {
2016-10-20 11:32:07 +02:00
nt = new Tuplet(*ot);
2014-08-13 17:45:53 +02:00
nt->clear();
2016-10-20 11:32:07 +02:00
nt->setTrack(track);
nt->setScore(sc);
nt->setParent(m);
nt->setTick(m->tick() + ot->rtick());
tupletMap.add(ot, nt);
2020-05-26 15:54:26 +02:00
}
ncr->setTuplet(nt);
nt->add(ncr);
2020-05-26 15:54:26 +02:00
}
if (oe->isChord()) {
2016-10-18 15:41:00 +02:00
Chord* och = toChord(ocr);
Chord* nch = toChord(ncr);
size_t n = och->notes().size();
2012-05-26 14:26:10 +02:00
for (size_t i = 0; i < n; ++i) {
Note* on = och->notes().at(i);
2016-12-28 16:23:10 +01:00
Note* nn = nch->notes().at(i);
if (on->tieFor()) {
2012-05-26 14:26:10 +02:00
Tie* tie = on->tieFor()->clone();
2014-11-10 13:33:32 +01:00
tie->setScore(sc);
nn->setTieFor(tie);
2012-05-26 14:26:10 +02:00
tie->setStartNote(nn);
tieMap->add(on->tieFor(), tie);
}
2014-08-13 17:45:53 +02:00
if (on->tieBack()) {
Tie* tie = tieMap->findNew(on->tieBack());
if (tie) {
nn->setTieBack(tie);
2014-08-13 17:45:53 +02:00
tie->setEndNote(nn);
} else {
qDebug("cloneMeasure: cannot find tie, track %d", track);
}
}
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
}
}
ne->setOffset(oe->offset());
ne->setScore(sc);
2014-08-13 17:45:53 +02:00
s->add(ne);
2020-05-26 15:54:26 +02:00
}
}
2020-02-24 06:28:58 +01:00
for (Element* e : el()) {
2014-08-13 17:45:53 +02:00
Element* ne = e->clone();
2012-05-26 14:26:10 +02:00
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;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
if (p.x() < x) {
break;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
}
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();
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
if (ns == 0) {
break;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
qreal x = s->x();
qreal nx = x + (ns->x() - x) * .5;
if (p.x() < nx) {
break;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:26:10 +02:00
s = ns;
}
return s->tick();
}
//---------------------------------------------------------
// searchSegment
/// Finds a segment which x position is most close to the
/// given \p x.
/// \param x The x coordinate in measure coordinates.
/// \param st Type of segments to search.
/// \param strack start of track range (strack included)
/// in which the found segment should contain elements.
/// \param etrack end of track range (etrack excluded)
/// in which the found segment should contain elements.
/// \param preferredSegment If not nullptr, will give
/// more space to the given segment when searching it by
/// coordinate.
/// \returns The segment that was found.
//---------------------------------------------------------
Segment* Measure::searchSegment(qreal x, SegmentType st, int strack, int etrack, const Segment* preferredSegment,
qreal spacingFactor) const
{
const int lastTrack = etrack - 1;
for (Segment* segment = first(st); segment; segment = segment->next(st)) {
if (!segment->hasElements(strack, lastTrack)) {
continue;
2020-05-26 15:54:26 +02:00
}
Segment* ns = segment->next(st);
for (; ns; ns = ns->next(st)) {
if (ns->hasElements(strack, lastTrack)) {
break;
}
2020-05-26 15:54:26 +02:00
}
if (!ns) {
return segment;
2020-05-26 15:54:26 +02:00
}
if (preferredSegment == segment) {
if (x < (segment->x() + (ns->x() - segment->x()))) {
return segment;
}
} else if (preferredSegment == ns) {
if (x <= segment->x()) {
return segment;
2020-05-26 15:54:26 +02:00
}
} else {
if (x < (segment->x() + (ns->x() - segment->x()) * spacingFactor)) {
return segment;
2020-05-26 15:54:26 +02:00
}
}
}
return nullptr;
}
//---------------------------------------------------------
// 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);
}
2019-10-24 15:49:23 +02:00
triggerLayout();
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());
2020-05-26 15:54:26 +02:00
}
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());
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
2014-04-24 10:42:42 +02:00
if (_mmRestCount != -1) {
// return const_cast<Measure*>(this);
return this;
2020-05-26 15:54:26 +02:00
}
2014-04-24 10:42:42 +02:00
const Measure* m = this;
while (m && !m->_mmRest) {
m = m->prevMeasure();
2020-05-26 15:54:26 +02:00
}
2014-04-24 10:42:42 +02:00
if (m) {
return const_cast<Measure*>(m->_mmRest);
2020-05-26 15:54:26 +02:00
}
2014-04-24 10:42:42 +02:00
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();
2020-05-26 15:54:26 +02:00
}
// 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;
}
}
2020-05-26 15:54:26 +02:00
}
}
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;
2020-05-26 15:54:26 +02:00
}
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();
2020-05-26 15:54:26 +02:00
}
// 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;
}
}
2020-05-26 15:54:26 +02:00
}
}
Measure* prevM = prevMeasureMM();
if (prevM) {
Segment* seg = prevM->last();
if (seg) {
return seg->lastElement(staff);
2020-05-26 15:54:26 +02:00
}
}
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);
2020-05-26 15:54:26 +02:00
Fraction minTick = computeTicks();
2020-05-26 15:54:26 +02:00
//---------------------------------------------------
2016-05-02 13:41:41 +02:00
// compute stretch
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
2020-05-26 15:54:26 +02:00
2016-05-02 13:41:41 +02:00
std::multimap<qreal, Segment*> springs;
2020-05-26 15:54:26 +02:00
Segment* seg = first();
while (seg && !seg->enabled()) {
seg = seg->next();
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
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();
2020-05-26 15:54:26 +02:00
}
//---------------------------------------------------
2016-05-02 13:41:41 +02:00
// compute 1/Force for a given Extend
//---------------------------------------------------
2020-05-26 15:54:26 +02: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;
2020-05-26 15:54:26 +02:00
++i;
2016-05-02 13:41:41 +02:00
if (i == springs.end() || f <= i->first) {
force = f;
2020-05-26 15:54:26 +02:00
break;
2016-01-04 14:48:58 +01:00
}
2020-05-26 15:54:26 +02:00
}
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
// distribute stretch to segments
2016-05-02 13:41:41 +02:00
//---------------------------------------------------
2020-05-26 15:54:26 +02: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
}
2020-05-26 15:54:26 +02:00
}
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
// move segments to final position
//---------------------------------------------------
2016-05-02 13:41:41 +02:00
Segment* s = first();
2017-01-18 14:16:33 +01:00
while (s && !s->enabled()) {
2016-10-31 10:55:11 +01:00
s = s->next();
2020-05-26 15:54:26 +02:00
}
2016-02-17 12:48:53 +01:00
qreal x = s->pos().x();
2016-05-02 13:41:41 +02:00
while (s) {
s->rxpos() = x;
x += s->width();
2018-03-27 15:36:00 +02:00
s = s->nextEnabled();
2020-05-26 15:54:26 +02:00
}
}
2017-10-17 14:28:03 +02:00
//---------------------------------------------------
// layout individual elements
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
2020-05-26 15:54:26 +02:00
2017-01-18 14:16:33 +01:00
for (Segment& s : _segments) {
2019-03-23 06:07:35 +01:00
if (!s.enabled()) {
continue;
2019-03-23 06:07:35 +01:00
}
2017-01-18 14:16:33 +01:00
for (Element* e : s.elist()) {
2019-04-28 22:00:10 +02:00
if (!e) {
continue;
2016-01-04 14:48:58 +01:00
}
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()))) {
2020-05-26 15:54:26 +02:00
//
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
2020-05-26 15:54:26 +02:00
2016-10-31 10:55:11 +01:00
Segment* s1;
for (s1 = s.prev(); s1 && !s1->enabled(); s1 = s1->prev()) {
2016-01-04 14:48:58 +01:00
}
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)) {
2020-05-26 15:54:26 +02: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;
2020-05-26 15:54:26 +02:00
2016-01-04 14:48:58 +01:00
if (isMMRest()) {
2016-05-02 13:41:41 +02:00
Rest* rest = toRest(e);
2020-05-26 15:54:26 +02:00
//
2016-01-04 14:48:58 +01:00
// center multi measure rest
2020-05-26 15:54:26 +02:00
//
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;
2020-05-26 15:54:26 +02:00
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()) {
2020-05-26 15:54:26 +02:00
//
2016-01-04 14:48:58 +01:00
// center full measure rest
2020-05-26 15:54:26 +02:00
//
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
2020-05-26 15:54:26 +02:00
}
2017-01-18 14:16:33 +01:00
} else if (t == ElementType::REST) {
2019-04-28 22:00:10 +02: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();
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();
2020-05-26 15:54:26 +02: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;
2020-05-26 15:54:26 +02:00
}
}
}
}
}
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));
2020-05-26 15:54:26 +02:00
Segment* ns = first();
while (ns && !ns->enabled()) {
ns = ns->next();
2020-05-26 15:54:26 +02:00
}
while (ns) {
Segment* s = ns;
ns = s->nextActive();
Fraction nticks = (ns ? ns->rtick() : ticks()) - s->rtick();
if (nticks.isNotZero()) {
if (nticks < minTick) {
minTick = nticks;
}
2020-05-26 15:54:26 +02:00
}
s->setTicks(nticks);
2020-05-26 15:54:26 +02:00
}
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();
2020-05-26 15:54:26 +02:00
}
// search first element
if (s) {
for (const Element* e : s->elist()) {
if (e) {
return toBarLine(e);
}
2020-05-26 15:54:26 +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 visibility 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
{
2019-10-24 15:49:23 +02:00
if (prev() || next()) { // avoid triggering layout before getting added to a score
score()->setLayout(tick(), endTick(), 0, score()->nstaves() - 1, this);
2020-05-26 15:54:26 +02:00
}
}
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()) {
2016-12-23 12:05:18 +01:00
bl->setSpanStaff(staff->barLineSpan());
bl->setSpanFrom(staff->barLineFrom());
bl->setSpanTo(staff->barLineTo());
2016-10-18 15:41:00 +02:00
}
} else {
2016-12-23 12:05:18 +01:00
bl = new BarLine(score());
bl->setParent(seg);
bl->setTrack(track);
2017-03-07 18:01:56 +01:00
bl->setGenerated(true);
bl->setSpanStaff(staff->barLineSpan());
bl->setSpanFrom(staff->barLineFrom());
bl->setSpanTo(staff->barLineTo());
2017-03-07 18:01:56 +01:00
bl->layout();
2016-12-23 12:05:18 +01:00
score()->addElement(bl);
2020-05-26 15:54:26 +02:00
}
2016-12-23 12:05:18 +01:00
track += VOICES;
2020-05-26 15:54:26 +02:00
}
}
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();
2020-05-26 15:54:26 +02:00
if (nm && nm->repeatStart() && !repeatEnd() && !isLastMeasureInSystem && next() == nm) {
// we may skip barline at end of a measure immediately before a start repeat:
// next measure is repeat start, this measure is not a repeat end,
// this is not last measure of system, no intervening frame
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 {
BarLineType t = nm ? BarLineType::NORMAL : BarLineType::END;
if (!seg) {
2017-03-08 13:12:26 +01:00
seg = getSegmentR(SegmentType::EndBarLine, ticks());
2020-05-26 15:54:26 +02:00
}
2016-10-18 15:41:00 +02:00
seg->setEnabled(true);
2020-05-26 15:54:26 +02:00
//
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.
2020-05-26 15:54:26 +02:00
//
2016-10-18 15:41:00 +02:00
bool show = score()->styleB(Sid::genCourtesyKeysig) && !sectionBreak() && nm;
2020-05-26 15:54:26 +02:00
2016-10-18 15:41:00 +02:00
setHasCourtesyKeySig(false);
2020-05-26 15:54:26 +02:00
2016-10-18 15:41:00 +02:00
if (isLastMeasureInSystem && show) {
2018-01-08 16:31:31 +01:00
Fraction tick = endTick();
2016-10-18 15:41:00 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
Staff* staff = score()->staff(staffIdx);
2016-12-23 12:05:18 +01:00
KeySigEvent key1 = staff->keySigEvent(tick - Fraction::fromTicks(1));
2016-10-18 15:41:00 +02:00
KeySigEvent key2 = staff->keySigEvent(tick);
if (!(key1 == key2)) {
2016-12-23 12:05:18 +01:00
// locate a key sig. in next measure and, if found,
2016-10-18 15:41:00 +02:00
// check if it has court. sig turned off
2016-12-23 12:05:18 +01:00
Segment* s = nm->findSegment(SegmentType::KeySig, tick);
2020-05-26 15:54:26 +02:00
if (s) {
2016-12-23 12:05:18 +01:00
KeySig* ks = toKeySig(s->element(staffIdx * VOICES));
if (ks && !ks->showCourtesy()) {
continue;
}
2020-05-26 15:54:26 +02:00
}
setHasCourtesyKeySig(true);
2018-03-27 15:36:00 +02:00
t = BarLineType::DOUBLE;
2016-10-18 15:41:00 +02:00
break;
2020-05-26 15:54:26 +02:00
}
2016-10-20 11:32:07 +02:00
}
2020-05-26 15:54:26 +02:00
}
2016-10-18 15:41:00 +02:00
bool force = false;
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;
// force = true;
2020-05-26 15:54:26 +02:00
}
2016-10-18 15:41:00 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
int track = staffIdx * VOICES;
BarLine* bl = toBarLine(seg->element(track));
Staff* staff = score()->staff(staffIdx);
if (!bl) {
bl = new BarLine(score());
bl->setParent(seg);
2016-12-23 12:05:18 +01:00
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 {
// do not change bar line type if bar line is user modified
// and its not a repeat start/end barline (forced)
2020-05-26 15:54:26 +02:00
if (bl->generated()) {
bl->setSpanStaff(staff->barLineSpan());
bl->setSpanFrom(staff->barLineFrom());
bl->setSpanTo(staff->barLineTo());
2016-12-23 12:05:18 +01:00
bl->setBarLineType(t);
} else {
if (bl->barLineType() != t) {
2017-03-07 18:01:56 +01:00
if (force) {
bl->undoChangeProperty(Pid::BARLINE_TYPE, QVariant::fromValue(t));
bl->setGenerated(true);
}
}
2020-05-26 15:54:26 +02:00
}
}
2016-10-20 11:32:07 +02:00
bl->layout();
2019-04-28 22:00:10 +02:00
blw = qMax(blw, bl->width());
2020-05-26 15:54:26 +02:00
}
2016-10-20 11:32:07 +02:00
// 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();
}
2020-05-26 15:54:26 +02:00
}
seg->createShapes();
2020-05-26 15:54:26 +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) {
bool wasVisible = clefSeg->visible();
int visibleInt = 0;
2019-04-28 22:00:10 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
int track = staffIdx * VOICES;
Clef* clef = toClef(clefSeg->element(track));
if (clef) {
bool showCourtesy = score()->genCourtesyClef() && clef->showCourtesy(); // normally show a courtesy clef
// check if the measure is the last measure of the system or the last measure before a frame
bool lastMeasure = isLastMeasureInSystem || (nm ? !(next() == nm) : true);
if (!nm || isFinalMeasureOfSection() || (lastMeasure && !showCourtesy)) {
// hide the courtesy clef in the final measure of a section, or if the measure is the final measure of a system
// and the score style or the clef style is set to "not show courtesy clef",
// or if the clef is at the end of the very last measure of the score
clef->clear();
clefSeg->createShape(staffIdx);
if (visibleInt == 0) {
visibleInt = 1;
2020-05-26 15:54:26 +02:00
}
} else {
clef->layout();
clefSeg->createShape(staffIdx);
visibleInt = 2;
2020-05-26 15:54:26 +02:00
}
}
}
if (visibleInt == 2) { // there is at least one visible clef in the clef segment
clefSeg->setVisible(true);
} else if (visibleInt == 1) { // all (courtesy) clefs in the clef segment are not visible
clefSeg->setVisible(false);
} else { // should never happen
qDebug("Clef Segment without Clef elements at tick %d/%d",clefSeg->tick().numerator(),
clefSeg->tick().denominator());
2020-05-26 15:54:26 +02:00
}
if ((wasVisible != clefSeg->visible()) && system()) { // recompute the width only if necessary
computeMinWidth();
2020-05-26 15:54:26 +02:00
}
if (seg) {
Segment* s1;
Segment* s2;
2017-03-20 18:24:16 +01:00
if (repeatEnd()) {
2020-05-26 15:54:26 +02:00
s1 = seg;
s2 = clefSeg;
2020-05-26 15:54:26 +02:00
} else {
s1 = clefSeg;
s2 = seg;
2020-05-26 15:54:26 +02:00
}
2016-11-07 09:59:06 +01:00
if (s1->next() != s2) {
_segments.remove(s1);
_segments.insert(s1, s2);
2020-05-26 15:54:26 +02:00
}
}
}
// fix segment layout
Segment* s = seg->prevActive();
2020-05-26 15:54:26 +02:00
if (s) {
qreal x = s->rxpos();
computeMinWidth(s, x, false);
2020-05-26 15:54:26 +02:00
}
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());
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
2016-10-18 15:41:00 +02:00
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;
2020-05-26 15:54:26 +02:00
}
2016-10-18 15:41:00 +02:00
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));
2020-05-26 15:54:26 +02:00
for (const Staff* staff : score()->staves()) {
const int track = staffIdx * VOICES;
2020-05-26 15:54:26 +02:00
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));
2020-05-26 15:54:26 +02:00
}
if (s) {
Clef* c = toClef(s->element(track));
if (c) {
cl = c->clefTypeList();
}
2020-05-26 15:54:26 +02:00
}
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));
2020-05-26 15:54:26 +02:00
}
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);
2020-05-26 15:54:26 +02:00
}
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);
2020-05-26 15:54:26 +02:00
}
}
2020-05-26 15:54:26 +02:00
// 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);
2020-05-26 15:54:26 +02:00
// 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.
2020-05-26 15:54:26 +02:00
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);
// }
}
}
}
2020-05-26 15:54:26 +02:00
}
2018-03-27 15:36:00 +02:00
needKeysig = needKeysig && (keyIdx.key() != Key::C || keyIdx.custom() || keyIdx.isAtonal());
2020-05-26 15:54:26 +02:00
2018-03-27 15:36:00 +02:00
if (needKeysig) {
KeySig* keysig;
2016-12-23 12:05:18 +01:00
if (!kSegment) {
kSegment = new Segment(this, SegmentType::KeySig, Fraction(0,1));
kSegment->setHeader(true);
2016-12-23 12:05:18 +01:00
add(kSegment);
keysig = 0;
2016-12-23 12:05:18 +01:00
} else {
keysig = toKeySig(kSegment->element(track));
2020-05-26 15:54:26 +02:00
}
if (!keysig) {
2020-05-26 15:54:26 +02:00
//
// create missing key signature
2020-05-26 15:54:26 +02:00
//
2016-12-23 12:05:18 +01:00
keysig = new KeySig(score());
keysig->setTrack(track);
keysig->setGenerated(true);
keysig->setParent(kSegment);
kSegment->add(keysig);
2020-05-26 15:54:26 +02:00
}
keysig->setKeySigEvent(keyIdx);
keysig->layout();
//kSegment->createShape(staffIdx);
2016-12-23 12:05:18 +01:00
kSegment->setEnabled(true);
2020-05-26 15:54:26 +02:00
} else {
2016-12-23 12:05:18 +01:00
if (kSegment && staff->isPitchedStaff(tick())) {
// do not disable user modified keysigs
2016-12-23 12:05:18 +01:00
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;
2016-12-23 12:05:18 +01:00
} 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);
2020-05-26 15:54:26 +02:00
}
}
if (disable) {
kSegment->setEnabled(false);
2020-05-26 15:54:26 +02:00
} else {
2016-12-23 12:05:18 +01:00
Element* e = kSegment->element(track);
if (e && e->isKeySig()) {
KeySig* keysig = toKeySig(e);
keysig->layout();
2020-05-26 15:54:26 +02:00
}
}
}
}
++staffIdx;
2020-05-26 15:54:26 +02:00
}
if (cSegment) {
cSegment->createShapes();
2020-05-26 15:54:26 +02:00
}
if (kSegment) {
kSegment->createShapes();
2020-05-26 15:54:26 +02:00
}
//
2016-12-23 12:05:18 +01:00
// create systemic barline
2020-05-26 15:54:26 +02:00
//
2017-03-08 13:12:26 +01:00
Segment* s = findSegment(SegmentType::BeginBarLine, tick());
int n = score()->nstaves();
2016-12-23 12:05:18 +01:00
if ((n > 1 && score()->styleB(Sid::startBarlineMultiple)) || (n == 1 && score()->styleB(Sid::startBarlineSingle))) {
if (!s) {
s = new Segment(this, SegmentType::BeginBarLine, Fraction(0,1));
2020-05-26 15:54:26 +02:00
add(s);
}
2016-12-23 12:05:18 +01:00
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);
}
2020-05-26 15:54:26 +02:00
}
s->createShapes();
s->setEnabled(true);
2016-12-23 12:05:18 +01:00
s->setHeader(true);
setHeader(true);
} else if (s) {
s->setEnabled(false);
2020-05-26 15:54:26 +02:00
}
checkHeader();
}
//---------------------------------------------------------
// addSystemTrailer
//---------------------------------------------------------
void Measure::addSystemTrailer(Measure* nm)
{
Fraction _rtick = ticks();
bool isFinalMeasure = isFinalMeasureOfSection();
2020-05-26 15:54:26 +02:00
// 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 (nm && 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) {
s = new Segment(this, SegmentType::TimeSigAnnounce, _rtick);
s->setTrailer(true);
2020-05-26 15:54:26 +02:00
add(s);
}
s->setEnabled(true);
for (int track = 0; track < nstaves * VOICES; track += VOICES) {
TimeSig* nts = toTimeSig(tss->element(track));
if (!nts) {
continue;
2020-05-26 15:54:26 +02:00
}
ts = toTimeSig(s->element(track));
if (!ts) {
ts = new TimeSig(score());
ts->setTrack(track);
ts->setGenerated(true);
ts->setParent(s);
score()->undoAddElement(ts);
2020-05-26 15:54:26 +02:00
}
ts->setFrom(nts);
ts->layout();
//s->createShape(track / VOICES);
2020-05-26 15:54:26 +02:00
}
s->createShapes();
}
2020-05-26 15:54:26 +02:00
}
}
if (!showCourtesySig && s) {
// remove any existing time signatures
s->setEnabled(false);
2020-05-26 15:54:26 +02:00
}
// 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) {
s = new Segment(this, SegmentType::KeySigAnnounce, _rtick);
s->setTrailer(true);
add(s);
}
KeySig* ks = toKeySig(s->element(track));
KeySigEvent key2 = staff->keySigEvent(endTick());
2020-05-26 15:54:26 +02:00
if (!ks) {
ks = new KeySig(score());
ks->setTrack(track);
ks->setGenerated(true);
ks->setParent(s);
s->add(ks);
2020-05-26 15:54:26 +02:00
}
//else if (!(ks->keySigEvent() == key2)) {
// score()->undo(new ChangeKeySig(ks, key2, ks->showCourtesy()));
2020-05-26 15:54:26 +02:00
// }
ks->setKeySigEvent(key2);
ks->layout();
//s->createShape(track / VOICES);
2016-12-23 12:05:18 +01:00
s->setEnabled(true);
2020-05-26 15:54:26 +02:00
} else {
// remove any existent courtesy key signature
if (s) {
s->setEnabled(false);
2020-05-26 15:54:26 +02:00
}
}
if (clefSegment) {
Clef* clef = toClef(clefSegment->element(track));
if (clef) {
clef->setSmall(true);
2020-05-26 15:54:26 +02:00
}
}
}
if (s) {
s->createShapes();
2020-05-26 15:54:26 +02:00
}
if (clefSegment) {
clefSegment->createShapes();
2020-05-26 15:54:26 +02:00
}
checkTrailer();
}
//---------------------------------------------------------
// removeSystemHeader
//---------------------------------------------------------
void Measure::removeSystemHeader()
{
if (!header()) {
return;
2020-05-26 15:54:26 +02:00
}
for (Segment* seg = first(); seg; seg = seg->next()) {
if (!seg->header()) {
break;
2020-05-26 15:54:26 +02:00
}
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;
2020-05-26 15:54:26 +02:00
}
if (seg->enabled()) {
seg->setEnabled(false);
2020-05-26 15:54:26 +02:00
}
changed = true;
}
setTrailer(false);
if (system() && changed) {
computeMinWidth();
2020-05-26 15:54:26 +02:00
}
}
//---------------------------------------------------------
// 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;
2020-05-26 15:54:26 +02:00
}
qreal stretchableWidth = 0.0;
for (Segment* s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
if (!s->enabled()) {
continue;
2020-05-26 15:54:26 +02:00
}
stretchableWidth += s->width();
}
const int maxMMRestLength = 32; // TODO: style
int weight = layoutWeight(maxMMRestLength);
w += stretchableWidth * (basicStretch() - 1.0) * weight / 1920.0;
2020-05-26 15:54:26 +02:00
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;
2020-05-26 15:54:26 +02:00
}
2017-10-18 13:09:35 +02:00
Element* e = s->element(track);
if (!e || !e->isChord()) {
continue;
2020-05-26 15:54:26 +02:00
}
2017-10-18 13:09:35 +02:00
Chord* c = toChord(e);
for (Note* n : c->notes()) {
if (n->accidental()) {
return true;
}
2020-05-26 15:54:26 +02:00
}
}
2017-10-18 13:09:35 +02:00
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();
2020-05-26 15:54:26 +02:00
}
bool first = isFirstInSystem();
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));
2020-05-26 15:54:26 +02:00
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();
}
2020-05-26 15:54:26 +02:00
}
}
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);
2020-05-26 15:54:26 +02:00
}
qreal w;
2020-05-26 15:54:26 +02:00
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
2020-05-26 15:54:26 +02:00
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());
2020-05-26 15:54:26 +02:00
}
int n = 1;
2016-11-02 14:07:39 +01:00
for (Segment* ps = s; ps != fs;) {
qreal ww;
ps = ps->prevActive();
2020-05-26 15:54:26 +02:00
Q_ASSERT(ps); // ps should never be nullptr but better be safe.
if (!ps) {
break;
2020-05-26 15:54:26 +02:00
}
if (ps->isChordRestType()) {
++n;
2020-05-26 15:54:26 +02:00
}
ww = ps->minHorizontalCollidingDistance(ns) - (s->x() - ps->x());
2020-05-26 15:54:26 +02:00
2016-11-02 14:07:39 +01:00
if (ps == fs) {
ww = std::max(ww, ns->minLeft(ls) - s->x());
2020-05-26 15:54:26 +02:00
}
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 ?
2020-05-26 15:54:26 +02:00
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;
2016-11-07 09:59:06 +01:00
ns1->rxpos() = xx;
ss = ns1;
2020-05-26 15:54:26 +02:00
}
w += d;
x = xx;
break;
}
}
2020-05-26 15:54:26 +02:00
#endif
} else {
w = s->minRight();
2020-05-26 15:54:26 +02:00
}
s->setWidth(w);
2020-05-26 15:54:26 +02:00
x += w;
2016-11-07 09:59:06 +01:00
s = s->next();
2020-05-26 15:54:26 +02:00
}
setStretchedWidth(x);
}
2016-11-07 09:59:06 +01:00
void Measure::computeMinWidth()
{
Segment* s;
2020-05-26 15:54:26 +02:00
2016-11-07 09:59:06 +01:00
//
// 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 = isFirstInSystem();
2020-05-26 15:54:26 +02:00
2016-11-07 09:59:06 +01:00
// 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));
2020-05-26 15:54:26 +02:00
2016-11-07 09:59:06 +01:00
x = s->minLeft(ls);
2020-05-26 15:54:26 +02:00
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
}
2020-05-26 15:54:26 +02: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));
2020-05-26 15:54:26 +02:00
}
2016-11-07 09:59:06 +01:00
x += s->extraLeadingSpace().val() * spatium();
bool isSystemHeader = s->header();
2020-05-26 15:54:26 +02:00
2016-11-07 09:59:06 +01:00
computeMinWidth(s, x, isSystemHeader);
}
2013-05-13 18:49:17 +02:00
}