MuseScore/libmscore/measure.cpp

3424 lines
132 KiB
C++
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2002-2011 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
/**
\file
Implementation of most part of class Measure.
*/
#include "measure.h"
#include "accidental.h"
#include "ambitus.h"
#include "articulation.h"
#include "barline.h"
#include "beam.h"
#include "box.h"
#include "bracket.h"
#include "breath.h"
2012-05-26 14:26:10 +02:00
#include "chord.h"
#include "clef.h"
#include "drumset.h"
#include "duration.h"
2012-05-26 14:26:10 +02:00
#include "dynamic.h"
#include "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"
2012-05-26 14:26:10 +02:00
#include "lyrics.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"
#include "text.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"
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
//---------------------------------------------------------
MStaff::~MStaff()
{
delete _noText;
2012-05-26 14:26:10 +02:00
delete lines;
delete _vspacerUp;
delete _vspacerDown;
}
MStaff::MStaff(const MStaff& m)
{
_noText = 0;
2015-10-28 09:42:14 +01:00
lines = new StaffLines(*m.lines);
hasVoices = m.hasVoices;
_vspacerUp = 0;
_vspacerDown = 0;
_visible = m._visible;
_slashStyle = m._slashStyle;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// Measure
//---------------------------------------------------------
Measure::Measure(Score* s)
2016-01-04 14:48:58 +01:00
: MeasureBase(s), _timesig(4,4), _len(4,4)
2012-05-26 14:26:10 +02:00
{
_repeatCount = 2;
2016-03-10 10:41:31 +01:00
int n = score()->nstaves();
2016-01-04 14:48:58 +01:00
_mstaves.reserve(n);
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < n; ++staffIdx) {
MStaff* s = new MStaff;
Staff* staff = score()->staff(staffIdx);
s->lines = new StaffLines(score());
s->lines->setTrack(staffIdx * VOICES);
s->lines->setParent(this);
s->lines->setVisible(!staff->invisible());
2016-01-04 14:48:58 +01:00
_mstaves.push_back(s);
2012-05-26 14:26:10 +02:00
}
2016-01-04 14:48:58 +01:00
setIrregular(false);
2016-02-04 11:27:47 +01:00
_noMode = MeasureNumberMode::AUTO;
2016-02-09 09:20:54 +01:00
_userStretch = 1.0;
2016-02-04 11:27:47 +01:00
_breakMultiMeasureRest = false;
_mmRest = 0;
_mmRestCount = 0;
setFlag(ElementFlag::MOVABLE, true);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// measure
//---------------------------------------------------------
Measure::Measure(const Measure& m)
: MeasureBase(m)
{
2016-02-04 11:27:47 +01:00
_segments = m._segments.clone();
_timesig = m._timesig;
_len = m._len;
_repeatCount = m._repeatCount;
_userStretch = m._userStretch;
2012-05-26 14:26:10 +02:00
2016-01-04 14:48:58 +01:00
_mstaves.reserve(m._mstaves.size());
for (MStaff* ms : m._mstaves)
2016-02-06 22:03:43 +01:00
_mstaves.push_back(new MStaff(*ms));
2012-05-26 14:26:10 +02:00
_breakMultiMeasureRest = m._breakMultiMeasureRest;
_mmRest = m._mmRest;
_mmRestCount = m._mmRestCount;
2012-05-26 14:26:10 +02:00
_playbackCount = m._playbackCount;
}
//---------------------------------------------------------
// setScore
//---------------------------------------------------------
void Measure::setScore(Score* score)
{
MeasureBase::setScore(score);
for (Segment* s = first(); s; s = s->next())
s->setScore(score);
}
//---------------------------------------------------------
// MStaff::setScore
//---------------------------------------------------------
void MStaff::setScore(Score* score)
{
2016-01-04 14:48:58 +01:00
lines->setScore(score);
2012-05-26 14:26:10 +02:00
if (_vspacerUp)
_vspacerUp->setScore(score);
if (_vspacerDown)
_vspacerDown->setScore(score);
}
//---------------------------------------------------------
// 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
tversatz.init(chord->staff()->key(tick()));
2012-05-26 14:26:10 +02:00
for (Segment* segment = first(); segment; segment = segment->next()) {
int startTrack = chord->staffIdx() * VOICES;
if (segment->segmentType() == Segment::Type::KeySig) {
KeySig* ks = static_cast<KeySig*>(segment->element(startTrack));
if (!ks)
2012-05-26 14:26:10 +02:00
continue;
tversatz.init(chord->staff()->key(segment->tick()));
}
else if (segment->segmentType() == Segment::Type::ChordRest) {
int endTrack = startTrack + VOICES;
for (int track = startTrack; track < endTrack; ++track) {
Element* e = segment->element(track);
if (!e || e->type() != Element::Type::CHORD)
continue;
Chord* chord = static_cast<Chord*>(e);
for (Chord* chord1 : chord->graceNotes()) {
for (Note* note1 : chord1->notes()) {
if (note1->tieBack())
continue;
//
// compute accidental
//
int tpc = note1->tpc();
int line = absStep(tpc, note1->epitch());
if (note == note1)
return tversatz.accidentalVal(line);
tversatz.setAccidentalVal(line, tpc2alter(tpc));
}
}
for (Note* note1 : chord->notes()) {
if (note1->tieBack())
continue;
//
// compute accidental
//
int tpc = note1->tpc();
int line = absStep(tpc, note1->epitch());
2012-05-26 14:26:10 +02:00
if (note == note1)
return tversatz.accidentalVal(line);
tversatz.setAccidentalVal(line, tpc2alter(tpc));
}
}
2012-05-26 14:26:10 +02:00
}
}
qDebug("Measure::findAccidental: note not found");
return AccidentalVal::NATURAL;
2012-05-26 14:26:10 +02:00
}
2012-08-07 12:44:19 +02:00
//---------------------------------------------------------
// findAccidental
/// Compute accidental state at segment/staffIdx for
/// relative staff line.
//---------------------------------------------------------
AccidentalVal Measure::findAccidental(Segment* s, int staffIdx, int line, bool &error) const
2012-08-06 21:55:51 +02:00
{
AccidentalState tversatz; // state of already set accidentals for this measure
Staff* staff = score()->staff(staffIdx);
2014-06-03 15:28:10 +02:00
tversatz.init(staff->key(tick()));
2012-08-06 21:55:51 +02:00
Segment::Type st = Segment::Type::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)) {
if (segment == s && staff->isPitchedStaff()) {
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);
if (!e || e->type() != Element::Type::CHORD)
2012-08-06 21:55:51 +02:00
continue;
Chord* chord = static_cast<Chord*>(e);
for (Chord* chord1 : chord->graceNotes()) {
for (Note* note : chord1->notes()) {
if (note->tieBack())
continue;
int tpc = note->tpc();
int l = absStep(tpc, note->epitch());
tversatz.setAccidentalVal(l, tpc2alter(tpc));
}
}
2012-08-06 21:55:51 +02:00
for (Note* note : chord->notes()) {
2012-08-06 21:55:51 +02:00
if (note->tieBack())
continue;
int tpc = note->tpc();
int l = absStep(tpc, note->epitch());
2012-08-06 21:55:51 +02:00
tversatz.setAccidentalVal(l, tpc2alter(tpc));
}
}
}
qDebug("segment not found");
return AccidentalVal::NATURAL;
2012-08-06 21:55:51 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// tick2pos
2013-06-19 16:25:29 +02:00
// return x position for tick relative to System
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
qreal Measure::tick2pos(int tck) const
{
if (isMMRest()) {
Segment* s = first(Segment::Type::ChordRest);
qreal x1 = s->x();
qreal w = width() - x1;
return x1 + (tck * w) / (ticks() * mmRestCount());
}
2012-05-26 14:26:10 +02:00
Segment* s;
qreal x1 = 0;
qreal x2 = 0;
int tick1 = tick();
int tick2 = tick1;
for (s = first(Segment::Type::ChordRest); s; s = s->next(Segment::Type::ChordRest)) {
2013-06-19 16:25:29 +02:00
x2 = s->x();
2012-05-26 14:26:10 +02:00
tick2 = s->tick();
2013-06-19 16:25:29 +02:00
if (tck == tick2)
return x2 + pos().x();
if (tck <= tick2)
2012-05-26 14:26:10 +02:00
break;
x1 = x2;
tick1 = tick2;
}
if (s == 0) {
x2 = width();
2013-06-19 16:25:29 +02:00
tick2 = endTick();
2012-05-26 14:26:10 +02:00
}
2013-06-19 16:25:29 +02:00
qreal dx = x2 - x1;
int dt = tick2 - tick1;
x1 += (dt == 0) ? 0.0 : (dx * (tck - tick1) / dt);
return x1 + pos().x();
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];
ms->lines->setWidth(width());
Spacer* sp = ms->_vspacerDown;
if (sp) {
sp->layout();
int n = score()->staff(staffIdx)->lines() - 1;
qreal y = system()->staff(staffIdx)->y();
sp->setPos(_spatium * .5, y + n * _spatium);
2012-05-26 14:26:10 +02:00
}
2016-01-04 14:48:58 +01:00
sp = ms->_vspacerUp;
if (sp) {
sp->layout();
2012-05-26 14:26:10 +02:00
qreal y = system()->staff(staffIdx)->y();
2016-01-04 14:48:58 +01:00
sp->setPos(_spatium * .5, y - sp->gap());
2012-05-26 14:26:10 +02:00
}
}
MeasureBase::layout(); // layout LAYOUT_BREAK elements
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
2012-05-26 14:26:10 +02:00
// set measure number
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
2012-05-26 14:26:10 +02:00
bool smn = false;
2012-10-17 10:39:39 +02:00
2014-08-11 15:25:55 +02:00
if (_noMode == MeasureNumberMode::SHOW)
smn = true;
else if (_noMode == MeasureNumberMode::HIDE)
smn = false;
else {
if (score()->styleB(StyleIdx::showMeasureNumber)
2016-01-04 14:48:58 +01:00
&& !irregular()
&& (no() || score()->styleB(StyleIdx::showMeasureNumberOne))) {
2014-08-11 15:25:55 +02:00
if (score()->styleB(StyleIdx::measureNumberSystem))
smn = system()->firstMeasure() == this;
else {
2016-01-04 14:48:58 +01:00
smn = (no() == 0 && score()->styleB(StyleIdx::showMeasureNumberOne)) ||
( ((no()+1) % score()->style(StyleIdx::measureNumberInterval).toInt()) == 0 );
}
}
2014-08-11 15:25:55 +02:00
}
QString s;
if (smn)
2016-01-04 14:48:58 +01:00
s = QString("%1").arg(no() + 1);
2014-08-11 15:25:55 +02:00
int nn = 1;
bool nas = score()->styleB(StyleIdx::measureNumberAllStaffs);
if (!nas) {
//find first non invisible staff
2016-02-06 22:03:43 +01:00
for (unsigned staffIdx = 0; staffIdx < _mstaves.size(); ++staffIdx) {
MStaff* ms = _mstaves[staffIdx];
2014-08-11 15:25:55 +02:00
SysStaff* s = system()->staff(staffIdx);
Staff* staff = score()->staff(staffIdx);
if (ms->visible() && staff->show() && s->show()) {
nn = staffIdx;
break;
}
2014-08-11 15:25:55 +02:00
}
}
2016-02-08 15:10:03 +01:00
for (int staffIdx = 0; staffIdx < int(_mstaves.size()); ++staffIdx) {
2016-02-06 22:03:43 +01:00
MStaff* ms = _mstaves[staffIdx];
2014-08-11 15:25:55 +02:00
Text* t = ms->noText();
2016-02-04 11:27:47 +01:00
if (t)
2014-08-11 15:25:55 +02:00
t->setTrack(staffIdx * VOICES);
if (smn && ((staffIdx == nn) || nas)) {
if (t == 0) {
t = new Text(score());
t->setFlag(ElementFlag::ON_STAFF, true);
t->setTrack(staffIdx * VOICES);
t->setGenerated(true);
t->setTextStyleType(TextStyleType::MEASURE_NUMBER);
t->setParent(this);
2014-08-25 19:30:56 +02:00
score()->undo(new AddElement(t));
// score()->undoAddElement(t);
2012-10-17 10:39:39 +02:00
}
t->setXmlText(s);
2014-08-11 15:25:55 +02:00
t->layout();
}
else {
if (t)
2014-08-25 19:30:56 +02:00
score()->undo(new RemoveElement(t));
2012-05-26 14:26:10 +02:00
}
2014-08-11 15:25:55 +02:00
}
2012-05-26 14:26:10 +02:00
2016-01-04 14:48:58 +01:00
//---------------------------------------------------
// layout ties, spanners and tuples
//---------------------------------------------------
int tracks = score()->ntracks();
static const Segment::Type st { Segment::Type::ChordRest };
for (int track = 0; track < tracks; ++track) {
if (!score()->staff(track / VOICES)->show()) {
track += VOICES-1;
continue;
}
for (Segment* s = first(st); s; s = s->next(st)) {
ChordRest* cr = s->cr(track);
2014-07-02 09:55:50 +02:00
if (!cr)
continue;
if (cr->type() == Element::Type::CHORD) {
Chord* c = static_cast<Chord*>(cr);
for (const Note* note : c->notes()) {
Tie* tie = note->tieFor();
if (tie)
tie->layout();
2016-01-04 14:48:58 +01:00
for (Spanner* sp : note->spannerFor())
2014-07-02 09:55:50 +02:00
sp->layout();
2012-05-26 14:26:10 +02:00
}
}
2014-07-02 09:55:50 +02:00
DurationElement* de = cr;
while (de->tuplet() && de->tuplet()->elements().front() == de) {
de->tuplet()->layout();
de = de->tuplet();
}
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
//---------------------------------------------------------
2013-06-24 13:46:21 +02:00
Chord* Measure::findChord(int tick, int track)
2012-05-26 14:26:10 +02:00
{
for (Segment* seg = last(); seg; seg = seg->prev()) {
if (seg->tick() < tick)
return 0;
if (seg->tick() == tick) {
Element* el = seg->element(track);
2016-03-08 17:58:04 +01:00
if (el && el->isChord())
2016-02-17 14:54:23 +01:00
return toChord(el);
2012-05-26 14:26:10 +02:00
}
}
return 0;
}
//---------------------------------------------------------
// findChordRest
2013-06-24 13:46:21 +02:00
/// Search for chord or rest at position \a tick at \a staff in \a voice.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
ChordRest* Measure::findChordRest(int tick, int track)
{
2016-02-09 09:20:54 +01:00
for (const Segment& seg : _segments) {
if (seg.tick() > tick)
2012-05-26 14:26:10 +02:00
return 0;
2016-02-09 09:20:54 +01:00
if (seg.tick() == tick) {
Element* el = seg.element(track);
if (el->isChordRest())
2016-02-17 14:54:23 +01:00
return toChordRest(el);
2012-05-26 14:26:10 +02:00
}
}
return 0;
}
//---------------------------------------------------------
// tick2segment
//---------------------------------------------------------
2016-02-09 09:20:54 +01:00
Segment* Measure::tick2segment(int tick, Segment::Type st)
2012-05-26 14:26:10 +02:00
{
2016-02-09 09:20:54 +01:00
for (Segment& s : _segments) {
if (s.tick() == tick) {
if (s.segmentType() & st)
return &s;
2012-05-26 14:26:10 +02:00
}
2016-02-09 09:20:54 +01:00
if (s.tick() > tick)
break;
2012-05-26 14:26:10 +02:00
}
return 0;
}
//---------------------------------------------------------
// findSegment
2013-05-29 10:31:26 +02:00
/// Search for a segment of type \a st at position \a t.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Segment* Measure::findSegment(Segment::Type st, int t)
2012-05-26 14:26:10 +02:00
{
Segment* s;
for (s = first(); s && s->tick() < t; s = s->next())
;
2013-06-25 19:52:00 +02:00
for (; s && s->tick() == t; s = s->next()) {
2014-08-21 15:01:54 +02:00
if (s->segmentType() & st)
return s;
}
return 0;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// undoGetSegment
//---------------------------------------------------------
Segment* Measure::undoGetSegment(Segment::Type type, int tick)
2012-05-26 14:26:10 +02:00
{
Segment* s = findSegment(type, tick);
if (s == 0) {
s = new Segment(this, type, tick);
score()->undoAddElement(s);
}
return s;
}
//---------------------------------------------------------
// getSegment
//---------------------------------------------------------
Segment* Measure::getSegment(Element* e, int tick)
{
2013-06-25 19:52:00 +02:00
return getSegment(Segment::segmentType(e->type()), tick);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// getSegment
2012-09-10 16:10:25 +02:00
/// Get a segment of type \a st at tick position \a t.
/// If the segment does not exist, it is created.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Segment* Measure::getSegment(Segment::Type st, int tick)
2012-05-26 14:26:10 +02:00
{
Segment* s = findSegment(st, tick);
2012-05-26 14:26:10 +02:00
if (!s) {
s = new Segment(this, st, tick);
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);
Element::Type type = e->type();
2012-05-26 14:26:10 +02:00
switch (type) {
case Element::Type::TEXT:
2016-02-08 15:10:03 +01:00
if (e->staffIdx() < int(_mstaves.size()))
2016-01-04 14:48:58 +01:00
_mstaves[e->staffIdx()]->setNoText(static_cast<Text*>(e));
2012-10-17 10:39:39 +02:00
break;
case Element::Type::SPACER:
2012-05-26 14:26:10 +02:00
{
2016-01-04 14:48:58 +01:00
Spacer* sp = static_cast<Spacer*>(e);
if (sp->spacerType() == SpacerType::UP)
2016-01-04 14:48:58 +01:00
_mstaves[e->staffIdx()]->_vspacerUp = sp;
else if (sp->spacerType() == SpacerType::DOWN)
2016-01-04 14:48:58 +01:00
_mstaves[e->staffIdx()]->_vspacerDown = sp;
2012-05-26 14:26:10 +02:00
}
break;
case Element::Type::SEGMENT:
2012-05-26 14:26:10 +02:00
{
2016-01-04 14:48:58 +01:00
Segment* seg = static_cast<Segment*>(e);
2012-05-26 14:26:10 +02:00
int t = seg->tick();
Segment::Type st = seg->segmentType();
Segment* s;
2013-06-12 14:23:57 +02:00
for (s = first(); s && s->tick() < t; s = s->next())
;
if (s) {
if (st == Segment::Type::ChordRest) {
// add ChordRest segment after all other segments with same tick
// except EndBarLine
2013-06-12 14:23:57 +02:00
while (s && s->segmentType() != st && s->tick() == t) {
if (s->segmentType() == Segment::Type::EndBarLine) {
2013-06-12 14:23:57 +02:00
break;
}
2013-06-12 14:23:57 +02:00
s = s->next();
}
2013-06-12 14:23:57 +02:00
}
else {
// use order of segments in segment.h
if (s && s->tick() == t) {
while (s && s->segmentType() <= st) {
s = s->next();
if (s && s->tick() != t)
break;
}
2012-05-26 14:26:10 +02:00
}
}
}
seg->setParent(this);
_segments.insert(seg, s);
2012-05-26 14:26:10 +02:00
}
break;
case Element::Type::JUMP:
2016-02-04 11:27:47 +01:00
setRepeatJump(true);
// fall through
case Element::Type::MARKER:
2016-01-04 14:48:58 +01:00
el().push_back(e);
2012-05-26 14:26:10 +02:00
break;
case Element::Type::HBOX:
2016-01-04 14:48:58 +01:00
if (e->staff())
e->setMag(e->staff()->mag()); // ?!
el().push_back(e);
2012-05-26 14:26:10 +02:00
break;
case Element::Type::MEASURE:
2016-01-04 14:48:58 +01:00
_mmRest = static_cast<Measure*>(e);
2013-10-30 14:21:08 +01:00
break;
2012-05-26 14:26:10 +02:00
default:
2016-01-04 14:48:58 +01:00
MeasureBase::add(e);
2012-05-26 14:26:10 +02:00
break;
}
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());
2014-08-25 19:30:56 +02:00
2016-01-04 14:48:58 +01:00
switch(e->type()) {
case Element::Type::TEXT:
2016-01-04 14:48:58 +01:00
_mstaves[e->staffIdx()]->setNoText(static_cast<Text*>(0));
2012-10-17 10:39:39 +02:00
break;
case Element::Type::SPACER:
2016-01-04 14:48:58 +01:00
if (static_cast<Spacer*>(e)->spacerType() == SpacerType::DOWN)
_mstaves[e->staffIdx()]->_vspacerDown = 0;
else if (static_cast<Spacer*>(e)->spacerType() == SpacerType::UP)
_mstaves[e->staffIdx()]->_vspacerUp = 0;
2012-05-26 14:26:10 +02:00
break;
case Element::Type::SEGMENT:
2016-03-24 12:39:18 +01:00
_segments.remove(toSegment(e));
2012-05-26 14:26:10 +02:00
break;
case Element::Type::JUMP:
2016-02-04 11:27:47 +01:00
setRepeatJump(false);
2012-05-26 14:26:10 +02:00
// fall through
case Element::Type::MARKER:
case Element::Type::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;
case Element::Type::CLEF:
case Element::Type::CHORD:
case Element::Type::REST:
case Element::Type::TIMESIG:
2012-05-26 14:26:10 +02:00
for (Segment* segment = first(); segment; segment = segment->next()) {
2016-03-10 10:41:31 +01:00
int staves = score()->nstaves();
2012-05-26 14:26:10 +02:00
int tracks = staves * VOICES;
for (int track = 0; track < tracks; ++track) {
2016-01-04 14:48:58 +01:00
Element* ee = segment->element(track);
if (ee == e) {
2012-05-26 14:26:10 +02:00
segment->setElement(track, 0);
return;
}
}
}
2016-01-04 14:48:58 +01:00
qDebug("Measure::remove: %s %p not found", e->name(), e);
2012-05-26 14:26:10 +02:00
break;
case Element::Type::MEASURE:
2013-10-30 14:21:08 +01:00
_mmRest = 0;
break;
2012-05-26 14:26:10 +02:00
default:
2016-01-04 14:48:58 +01:00
MeasureBase::remove(e);
2012-05-26 14:26:10 +02:00
break;
}
}
//---------------------------------------------------------
// change
//---------------------------------------------------------
void Measure::change(Element* o, Element* n)
{
if (o->type() == Element::Type::TUPLET) {
2012-05-26 14:26:10 +02:00
Tuplet* t = static_cast<Tuplet*>(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(int diff)
{
setTick(tick() + diff);
for (Segment* segment = first(); segment; segment = segment->next()) {
if (segment->segmentType() & (Segment::Type::EndBarLine | Segment::Type::TimeSigAnnounce))
2012-05-26 14:26:10 +02:00
segment->setTick(tick() + ticks());
}
}
//---------------------------------------------------------
// removeStaves
//---------------------------------------------------------
void Measure::removeStaves(int sStaff, int eStaff)
{
for (Segment* s = first(); s; s = s->next()) {
for (int staff = eStaff-1; staff >= sStaff; --staff) {
s->removeStaff(staff);
}
}
2016-01-04 14:48:58 +01:00
for (Element* e : el()) {
2012-05-26 14:26:10 +02:00
if (e->track() == -1)
continue;
int voice = e->voice();
int staffIdx = e->staffIdx();
if (staffIdx >= eStaff) {
staffIdx -= eStaff - sStaff;
e->setTrack(staffIdx * VOICES + voice);
}
}
}
//---------------------------------------------------------
// insertStaves
//---------------------------------------------------------
void Measure::insertStaves(int sStaff, int eStaff)
{
2016-01-04 14:48:58 +01:00
for (Element* e : el()) {
2012-05-26 14:26:10 +02:00
if (e->track() == -1)
continue;
int staffIdx = e->staffIdx();
if (staffIdx >= sStaff && !e->systemFlag()) {
2012-05-26 14:26:10 +02:00
int voice = e->voice();
staffIdx += eStaff - sStaff;
e->setTrack(staffIdx * VOICES + voice);
}
}
for (Segment* s = first(); s; s = s->next()) {
for (int staff = sStaff; staff < eStaff; ++staff) {
s->insertStaff(staff);
}
}
}
//---------------------------------------------------------
// cmdRemoveStaves
//---------------------------------------------------------
void Measure::cmdRemoveStaves(int sStaff, int eStaff)
{
int sTrack = sStaff * VOICES;
int eTrack = eStaff * VOICES;
for (Segment* s = first(); s; s = s->next()) {
for (int track = eTrack - 1; track >= sTrack; --track) {
Element* el = s->element(track);
2013-07-15 07:53:16 +02:00
if (el) {
2014-05-21 20:08:37 +02:00
el->undoUnlink();
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveElement(el));
2012-05-26 14:26:10 +02:00
}
}
2014-05-21 20:08:37 +02:00
foreach (Element* e, s->annotations()) {
2012-05-26 14:26:10 +02:00
int staffIdx = e->staffIdx();
if ((staffIdx >= sStaff) && (staffIdx < eStaff) && !e->systemFlag()) {
2014-05-21 20:08:37 +02:00
e->undoUnlink();
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveElement(e));
2012-05-26 14:26:10 +02:00
}
}
}
2016-01-04 14:48:58 +01:00
for (Element* e : el()) {
2012-05-26 14:26:10 +02:00
if (e->track() == -1)
continue;
int staffIdx = e->staffIdx();
if (staffIdx >= sStaff && (staffIdx < eStaff) && !e->systemFlag()) {
2014-05-21 20:08:37 +02:00
e->undoUnlink();
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveElement(e));
2014-05-21 20:08:37 +02:00
}
2012-05-26 14:26:10 +02:00
}
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveStaves(this, sStaff, eStaff));
2012-05-26 14:26:10 +02:00
2014-08-25 19:30:56 +02:00
for (int i = eStaff - 1; i >= sStaff; --i) {
2016-01-04 14:48:58 +01:00
MStaff* ms = *(_mstaves.begin()+i);
2014-08-25 19:30:56 +02:00
Text* t = ms->noText();
if (t) {
// t->undoUnlink();
2016-03-10 10:41:31 +01:00
// score()->undo(new RemoveElement(t));
2014-08-25 19:30:56 +02:00
}
2016-03-10 10:41:31 +01:00
score()->undo(new RemoveMStaff(this, ms, i));
2014-08-25 19:30:56 +02:00
}
2012-05-26 14:26:10 +02:00
// barLine
// TODO
}
//---------------------------------------------------------
// cmdAddStaves
//---------------------------------------------------------
void Measure::cmdAddStaves(int sStaff, int eStaff, bool createRest)
{
2016-03-10 10:41:31 +01:00
score()->undo(new InsertStaves(this, sStaff, eStaff));
2012-05-26 14:26:10 +02:00
Segment* ts = findSegment(Segment::Type::TimeSig, tick());
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;
ms->lines = new StaffLines(score());
ms->lines->setTrack(i * VOICES);
ms->lines->setParent(this);
ms->lines->setVisible(!staff->invisible());
2016-03-10 10:41:31 +01:00
score()->undo(new InsertMStaff(this, ms, i));
2014-07-27 15:06:49 +02:00
}
2012-05-26 14:26:10 +02:00
2014-07-27 15:06:49 +02:00
if (!createRest && !ts)
return;
// create list of unique staves (only one instance for linked staves):
QList<int> sl;
for (int staffIdx = sStaff; staffIdx < eStaff; ++staffIdx) {
2016-03-10 10:41:31 +01:00
Staff* s = score()->staff(staffIdx);
2014-07-27 15:06:49 +02:00
if (s->linkedStaves()) {
bool alreadyInList = false;
for (int idx : sl) {
2016-03-10 10:41:31 +01:00
if (s->linkedStaves()->staves().contains(score()->staff(idx))) {
2014-07-27 15:06:49 +02:00
alreadyInList = true;
break;
}
}
2014-07-27 15:06:49 +02:00
if (alreadyInList)
continue;
2012-05-26 14:26:10 +02:00
}
2014-07-27 15:06:49 +02:00
sl.append(staffIdx);
}
for (int staffIdx : sl) {
if (createRest)
score()->setRest(tick(), staffIdx * VOICES, len(), false, 0, _timesig == len());
2012-05-26 14:26:10 +02:00
// replicate time signature
if (ts) {
TimeSig* ots = 0;
bool constructed = false;
2016-02-08 15:10:03 +01:00
for (unsigned track = 0; track < _mstaves.size() * VOICES; ++track) {
2012-05-26 14:26:10 +02:00
if (ts->element(track)) {
2014-07-27 15:06:49 +02:00
ots = static_cast<TimeSig*>(ts->element(track));
2012-05-26 14:26:10 +02:00
break;
}
}
if (!ots) {
// no time signature found; use measure length to construct one
ots = new TimeSig(score());
ots->setSig(len());
constructed = true;
}
// do no replicate local time signatures
if (ots && !ots->isLocal()) {
2012-05-26 14:26:10 +02:00
TimeSig* timesig = new TimeSig(*ots);
2014-07-27 15:06:49 +02:00
timesig->setTrack(staffIdx * VOICES);
timesig->setParent(ts);
timesig->setSig(ots->sig(), ots->timeSigType());
timesig->setNeedLayout(true);
2012-05-26 14:26:10 +02:00
score()->undoAddElement(timesig);
if (constructed)
delete ots;
2012-05-26 14:26:10 +02:00
}
}
}
}
//---------------------------------------------------------
// setTrack
//---------------------------------------------------------
void MStaff::setTrack(int track)
{
2016-01-04 14:48:58 +01:00
lines->setTrack(track);
2012-05-26 14:26:10 +02:00
if (_vspacerUp)
_vspacerUp->setTrack(track);
if (_vspacerDown)
_vspacerDown->setTrack(track);
}
//---------------------------------------------------------
// insertMStaff
//---------------------------------------------------------
void Measure::insertMStaff(MStaff* staff, int idx)
{
2016-02-06 22:03:43 +01:00
_mstaves.insert(_mstaves.begin()+idx, staff);
2016-02-08 15:10:03 +01:00
for (unsigned staffIdx = 0; staffIdx < _mstaves.size(); ++staffIdx)
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->setTrack(staffIdx * VOICES);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// removeMStaff
//---------------------------------------------------------
void Measure::removeMStaff(MStaff* /*staff*/, int idx)
{
2016-02-06 22:03:43 +01:00
_mstaves.erase(_mstaves.begin()+idx);
2016-02-08 15:10:03 +01:00
for (unsigned staffIdx = 0; staffIdx < _mstaves.size(); ++staffIdx)
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->setTrack(staffIdx * VOICES);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// insertStaff
//---------------------------------------------------------
void Measure::insertStaff(Staff* staff, int staffIdx)
{
for (Segment* s = first(); s; s = s->next())
s->insertStaff(staffIdx);
MStaff* ms = new MStaff;
ms->lines = new StaffLines(score());
ms->lines->setParent(this);
ms->lines->setTrack(staffIdx * VOICES);
ms->lines->setVisible(!staff->invisible());
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
*/
2014-08-13 21:01:21 +02:00
bool Measure::acceptDrop(const DropData& 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.element;
int staffIdx;
Segment* seg;
2016-03-10 10:41:31 +01:00
if (score()->pos2measure(pos, &staffIdx, 0, &seg, 0) == nullptr)
2014-10-04 18:22:36 +02:00
return false;
2014-08-13 21:01:21 +02:00
QRectF staffR = system()->staff(staffIdx)->bbox().translated(system()->canvasPos());
staffR &= canvasBoundingRect();
2014-06-19 15:27:44 +02:00
switch (e->type()) {
case Element::Type::MEASURE_LIST:
case Element::Type::JUMP:
case Element::Type::MARKER:
case Element::Type::LAYOUT_BREAK:
case Element::Type::STAFF_LIST:
2014-08-13 21:01:21 +02:00
viewer->setDropRectangle(canvasBoundingRect());
return true;
case Element::Type::KEYSIG:
2014-08-13 21:01:21 +02:00
case Element::Type::TIMESIG:
if (data.modifiers & Qt::ControlModifier)
viewer->setDropRectangle(staffR);
else
viewer->setDropRectangle(canvasBoundingRect());
return true;
case Element::Type::BRACKET:
case Element::Type::REPEAT_MEASURE:
case Element::Type::MEASURE:
case Element::Type::SPACER:
case Element::Type::IMAGE:
case Element::Type::BAR_LINE:
case Element::Type::SYMBOL:
case Element::Type::CLEF:
2014-08-13 21:01:21 +02:00
viewer->setDropRectangle(staffR);
2012-05-26 14:26:10 +02:00
return true;
case Element::Type::ICON:
switch(static_cast<Icon*>(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.
//---------------------------------------------------------
Element* Measure::drop(const DropData& data)
{
Element* e = data.element;
int staffIdx = -1;
2012-05-26 14:26:10 +02:00
Segment* seg;
2016-03-10 10:41:31 +01:00
score()->pos2measure(data.pos, &staffIdx, 0, &seg, 0);
2012-05-26 14:26:10 +02:00
if (e->systemFlag())
staffIdx = 0;
if (staffIdx < 0)
return 0;
2012-05-26 14:26:10 +02:00
Staff* staff = score()->staff(staffIdx);
bool fromPalette = (e->track() == -1);
2012-05-26 14:26:10 +02:00
switch(e->type()) {
case Element::Type::MEASURE_LIST:
2012-05-26 14:26:10 +02:00
delete e;
break;
case Element::Type::STAFF_LIST:
2012-05-26 14:26:10 +02:00
//TODO score()->pasteStaff(e, this, staffIdx);
delete e;
break;
case Element::Type::MARKER:
case Element::Type::JUMP:
e->setParent(this);
2012-05-26 14:26:10 +02:00
e->setTrack(0);
{
// code borrowed from ChordRest::drop()
Text* t = static_cast<Text*>(e);
TextStyleType st = t->textStyleType();
// for palette items, we want to use current score text style settings
// except where the source element had explicitly overridden these via text properties
// palette text style will be relative to baseStyle, so rebase this to score
if (st >= TextStyleType::DEFAULT && fromPalette)
t->textStyle().restyle(MScore::baseStyle()->textStyle(st), score()->textStyle(st));
}
2012-05-26 14:26:10 +02:00
score()->undoAddElement(e);
return e;
case Element::Type::DYNAMIC:
case Element::Type::FRET_DIAGRAM:
2012-05-26 14:26:10 +02:00
e->setParent(seg);
e->setTrack(staffIdx * VOICES);
score()->undoAddElement(e);
return e;
case Element::Type::IMAGE:
case Element::Type::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->setUserOff(uo);
}
score()->undoAddElement(e);
return e;
case Element::Type::BRACKET:
2013-06-28 17:46:24 +02:00
{
Bracket* b = static_cast<Bracket*>(e);
int level = 0;
int firstStaff = 0;
2016-02-09 09:20:54 +01:00
for (Staff* s : score()->staves()) {
for (const BracketItem& bi : s->brackets()) {
2013-06-28 17:46:24 +02:00
int lastStaff = firstStaff + bi._bracketSpan - 1;
if (staffIdx >= firstStaff && staffIdx <= lastStaff)
++level;
}
firstStaff++;
2013-06-28 17:46:24 +02:00
}
score()->undoAddBracket(staff, level, b->bracketType(), 1);
delete b;
}
return 0;
2012-05-26 14:26:10 +02:00
case Element::Type::CLEF:
2012-05-26 14:26:10 +02:00
score()->undoChangeClef(staff, first(), static_cast<Clef*>(e)->clefType());
delete e;
break;
case Element::Type::KEYSIG:
2012-05-26 14:26:10 +02:00
{
KeySig* ks = static_cast<KeySig*>(e);
KeySigEvent k = ks->keySigEvent();
delete ks;
2014-06-03 15:28:10 +02:00
2012-05-26 14:26:10 +02:00
if (data.modifiers & Qt::ControlModifier) {
// apply only to this stave
score()->undoChangeKeySig(staff, tick(), k);
}
else {
2012-05-26 14:26:10 +02:00
// apply to all staves:
2016-01-04 14:48:58 +01:00
for(Staff* s : score()->staves())
score()->undoChangeKeySig(s, tick(), k);
2012-05-26 14:26:10 +02:00
}
2012-08-10 10:14:17 +02:00
2012-05-26 14:26:10 +02:00
break;
}
case Element::Type::TIMESIG:
score()->cmdAddTimeSig(this, staffIdx, static_cast<TimeSig*>(e),
data.modifiers & Qt::ControlModifier);
2012-05-26 14:26:10 +02:00
return 0;
case Element::Type::LAYOUT_BREAK:
2012-05-26 14:26:10 +02:00
{
LayoutBreak* lb = static_cast<LayoutBreak*>(e);
if (
2016-01-04 14:48:58 +01:00
(lb->layoutBreakType() == LayoutBreak::Type::PAGE && pageBreak())
|| (lb->layoutBreakType() == LayoutBreak::Type::LINE && lineBreak())
|| (lb->layoutBreakType() == LayoutBreak::Type::SECTION && sectionBreak())
2012-05-26 14:26:10 +02:00
) {
//
// if break already set
//
delete lb;
break;
}
// make sure there is only LayoutBreak::Type::LINE or LayoutBreak::Type::PAGE
2016-01-04 14:48:58 +01:00
if ((lb->layoutBreakType() != LayoutBreak::Type::SECTION) && (pageBreak() || lineBreak())) {
for (Element* le : el()) {
if (le->type() == Element::Type::LAYOUT_BREAK
&& (static_cast<LayoutBreak*>(le)->layoutBreakType() == LayoutBreak::Type::LINE
|| static_cast<LayoutBreak*>(le)->layoutBreakType() == LayoutBreak::Type::PAGE)) {
2012-05-26 14:26:10 +02:00
score()->undoChangeElement(le, e);
break;
}
}
break;
}
lb->setTrack(-1); // these are system elements
2012-05-26 14:26:10 +02:00
lb->setParent(this);
score()->undoAddElement(lb);
return lb;
}
case Element::Type::SPACER:
2012-05-26 14:26:10 +02:00
{
Spacer* spacer = static_cast<Spacer*>(e);
spacer->setTrack(staffIdx * VOICES);
spacer->setParent(this);
score()->undoAddElement(spacer);
return spacer;
}
case Element::Type::BAR_LINE:
{
BarLine* bl = static_cast<BarLine*>(e);
2016-02-04 11:27:47 +01:00
// if dropped bar line refers to span rather than to subtype
// or if Ctrl key used
2016-02-04 11:27:47 +01:00
if ((bl->spanFrom() != 0 && bl->spanTo() != DEFAULT_BARLINE_TO) || data.control()) {
// get existing bar line for this staff, and drop the change to it
Segment* seg = undoGetSegment(Segment::Type::EndBarLine, tick() + ticks());
BarLine* cbl = static_cast<BarLine*>(seg->element(staffIdx * VOICES));
if (cbl)
cbl->drop(data);
}
else {
2016-02-04 11:27:47 +01:00
// if dropped bar line refers to line subtype
score()->undoChangeBarLine(this, bl->barLineType());
delete e;
}
2012-05-26 14:26:10 +02:00
break;
}
2012-05-26 14:26:10 +02:00
case Element::Type::REPEAT_MEASURE:
2012-05-26 14:26:10 +02:00
{
delete e;
return cmdInsertRepeatMeasure(staffIdx);
2012-05-26 14:26:10 +02:00
}
case Element::Type::ICON:
switch(static_cast<Icon*>(e)->iconType()) {
case IconType::VFRAME:
score()->insertMeasure(Element::Type::VBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::HFRAME:
score()->insertMeasure(Element::Type::HBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::TFRAME:
score()->insertMeasure(Element::Type::TBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::FFRAME:
score()->insertMeasure(Element::Type::FBOX, this);
2012-05-26 14:26:10 +02:00
break;
case IconType::MEASURE:
score()->insertMeasure(Element::Type::MEASURE, this);
2012-05-26 14:26:10 +02:00
break;
default:
break;
2012-05-26 14:26:10 +02:00
}
break;
default:
qDebug("Measure: cannot drop %s here", e->name());
delete e;
break;
}
return 0;
}
//---------------------------------------------------------
// cmdInsertRepeatMeasure
//---------------------------------------------------------
2014-05-20 17:26:26 +02:00
RepeatMeasure* Measure::cmdInsertRepeatMeasure(int staffIdx)
{
//
// see also cmdDeleteSelection()
//
2016-03-10 10:41:31 +01:00
score()->select(0, SelectType::SINGLE, 0);
for (Segment* s = first(); s; s = s->next()) {
if (s->segmentType() & Segment::Type::ChordRest) {
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
for (int track = strack; track < etrack; ++track) {
Element* el = s->element(track);
if (el)
2016-03-10 10:41:31 +01:00
score()->undoRemoveElement(el);
}
}
}
//
// add repeat measure
//
Segment* seg = undoGetSegment(Segment::Type::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);
2016-03-10 10:41:31 +01:00
rm->setDuration(stretchedLen(score()->staff(staffIdx)));
score()->undoAddCR(rm, this, tick());
2016-01-04 14:48:58 +01:00
for (Element* e : el()) {
if (e->type() == Element::Type::SLUR && e->staffIdx() == staffIdx)
2016-03-10 10:41:31 +01:00
score()->undoRemoveElement(e);
}
return rm;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// adjustToLen
// change actual measure len, adjust elements to
// new len
//---------------------------------------------------------
void Measure::adjustToLen(Fraction nf)
{
2014-05-20 17:26:26 +02:00
int ol = len().ticks();
int nl = nf.ticks();
int diff = nl - ol;
int startTick = endTick();
if (diff < 0)
startTick += diff;
2013-10-21 13:11:04 +02:00
2014-05-20 17:26:26 +02:00
score()->undoInsertTime(startTick, diff);
2014-07-27 12:38:45 +02:00
score()->undo(new InsertTime(score(), startTick, diff));
2012-05-26 14:26:10 +02:00
2014-05-20 17:26:26 +02:00
for (Score* s : score()->scoreList()) {
Measure* m = s->tick2measure(tick());
s->undo(new ChangeMeasureLen(m, nf));
if (nl > ol) {
// move EndBarLine, TimeSigAnnounce, KeySigAnnounce
for (Segment* s = m->first(); s; s = s->next()) {
if (s->segmentType() & (Segment::Type::EndBarLine|Segment::Type::TimeSigAnnounce|Segment::Type::KeySigAnnounce)) {
2014-05-20 17:26:26 +02:00
s->setTick(tick() + nl);
}
2012-05-26 14:26:10 +02:00
}
}
}
2016-03-10 10:41:31 +01:00
Score* s = score()->masterScore();
2014-05-22 16:18:35 +02:00
Measure* m = this;
QList<int> sl = s->uniqueStaves();
2012-05-26 14:26:10 +02:00
2014-05-22 16:18:35 +02:00
for (int staffIdx : sl) {
2012-05-26 14:26:10 +02:00
int rests = 0;
int chords = 0;
Rest* rest = 0;
2014-05-20 17:26:26 +02:00
for (Segment* segment = m->first(); segment; segment = segment->next()) {
2012-05-26 14:26:10 +02:00
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
for (int track = strack; track < etrack; ++track) {
Element* e = segment->element(track);
2013-10-21 13:11:04 +02:00
if (e) {
if (e->type() == Element::Type::REST) {
2013-10-21 13:11:04 +02:00
++rests;
rest = static_cast<Rest*>(e);
}
else if (e->type() == Element::Type::CHORD)
2013-10-21 13:11:04 +02:00
++chords;
2012-05-26 14:26:10 +02:00
}
}
}
// 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(P_ID::DURATION, QVariant::fromValue<Fraction>(nf));
rest->undoChangeProperty(P_ID::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
// convert the measure duration in a list of values (no dots for rests)
2016-02-06 22:03:43 +01:00
std::vector<TDuration> durList = toDurationList(nf, false, 0);
2014-05-20 17:26:26 +02:00
// set the existing rest to the first value of the duration list
for (ScoreElement* e : rest->linkList()) {
e->undoChangeProperty(P_ID::DURATION, QVariant::fromValue<Fraction>(durList[0].fraction()));
e->undoChangeProperty(P_ID::DURATION_TYPE, QVariant::fromValue<TDuration>(durList[0]));
2014-09-29 11:58:44 +02:00
}
2014-05-20 17:26:26 +02:00
// add rests for any other duration list value
int tickOffset = tick() + durList[0].ticks();
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->setDuration(durList.at(i).fraction());
newRest->setTrack(rest->track());
score()->undoAddCR(newRest, this, tickOffset);
tickOffset += durList.at(i).ticks();
}
}
2014-05-20 17:26:26 +02:00
continue;
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
for (int trk = strack; trk < etrack; ++trk) {
int n = diff;
bool rFlag = false;
if (n < 0) {
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();
Element* e = segment->element(trk);
if (e && e->isChordRest()) {
ChordRest* cr = static_cast<ChordRest*>(e);
if (cr->durationType() == TDuration::DurationType::V_MEASURE) {
int actualTicks = cr->actualTicks();
n += actualTicks;
cr->setDurationType(TDuration(actualTicks));
}
2013-10-21 13:11:04 +02:00
else
n += cr->actualTicks();
2014-05-20 17:26:26 +02:00
s->undoRemoveElement(e);
2013-10-21 13:11:04 +02:00
if (n >= 0)
break;
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
segment = pseg;
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
rFlag = true;
}
int voice = trk % VOICES;
if ((n > 0) && (rFlag || voice == 0)) {
// add rest to measure
int rtick = tick() + nl - n;
int track = staffIdx * VOICES + voice;
2014-05-20 17:26:26 +02:00
s->setRest(rtick, track, Fraction::fromTicks(n), false, 0, false);
2012-05-26 14:26:10 +02:00
}
}
}
if (diff < 0) {
//
// CHECK: do not remove all slurs
//
foreach(Element* e, m->el()) {
if (e->type() == Element::Type::SLUR)
2014-05-20 17:26:26 +02:00
s->undoRemoveElement(e);
2012-05-26 14:26:10 +02:00
}
}
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void Measure::write(Xml& xml, int staff, bool writeSystemElements) const
{
2016-01-04 14:48:58 +01:00
int mno = no() + 1;
2012-05-26 14:26:10 +02:00
if (_len != _timesig) {
// this is an irregular measure
xml.stag(QString("Measure number=\"%1\" len=\"%2/%3\"").arg(mno).arg(_len.numerator()).arg(_len.denominator()));
}
else
xml.stag(QString("Measure number=\"%1\"").arg(mno));
2014-02-28 14:25:47 +01:00
2012-05-26 14:26:10 +02:00
xml.curTick = tick();
2014-02-26 19:06:42 +01:00
if (_mmRestCount > 0)
xml.tag("multiMeasureRest", _mmRestCount);
2012-05-26 14:26:10 +02:00
if (writeSystemElements) {
2016-02-04 11:27:47 +01:00
if (repeatStart())
2012-05-26 14:26:10 +02:00
xml.tagE("startRepeat");
2016-02-04 11:27:47 +01:00
if (repeatEnd())
2012-05-26 14:26:10 +02:00
xml.tag("endRepeat", _repeatCount);
writeProperty(xml, P_ID::IRREGULAR);
writeProperty(xml, P_ID::BREAK_MMR);
writeProperty(xml, P_ID::USER_STRETCH);
writeProperty(xml, P_ID::NO_OFFSET);
writeProperty(xml, P_ID::MEASURE_NUMBER_MODE);
2012-05-26 14:26:10 +02:00
}
qreal _spatium = spatium();
2016-01-04 14:48:58 +01:00
MStaff* mstaff = _mstaves[staff];
if (mstaff->noText() && !mstaff->noText()->generated()) {
xml.stag("MeasureNumber");
mstaff->noText()->writeProperties(xml);
xml.etag();
}
2012-05-26 14:26:10 +02:00
if (mstaff->_vspacerUp)
xml.tag("vspacerUp", mstaff->_vspacerUp->gap() / _spatium);
if (mstaff->_vspacerDown)
xml.tag("vspacerDown", mstaff->_vspacerDown->gap() / _spatium);
if (!mstaff->_visible)
xml.tag("visible", mstaff->_visible);
if (mstaff->_slashStyle)
xml.tag("slashStyle", mstaff->_slashStyle);
int strack = staff * VOICES;
int etrack = strack + VOICES;
2016-01-04 14:48:58 +01:00
for (const Element* e : el()) {
if (!e->generated() && ((e->staffIdx() == staff) || (e->systemFlag() && writeSystemElements)))
e->write(xml);
2012-05-26 14:26:10 +02:00
}
Q_ASSERT(first());
Q_ASSERT(last());
2013-10-13 13:06:32 +02:00
score()->writeSegments(xml, strack, etrack, first(), last()->next1(), writeSystemElements, false, false);
2012-05-26 14:26:10 +02:00
xml.etag();
}
2014-02-26 19:06:42 +01:00
//---------------------------------------------------------
// ticks
//---------------------------------------------------------
int Measure::ticks() const
{
return _len.ticks();
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// 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
{
Segment* segment = 0;
qreal _spatium = spatium();
2013-06-16 23:33:37 +02:00
QList<Chord*> graceNotes;
//sort tuplet elements. needed for nested tuplets #22537
if (score()->mscVersion() <= 114) {
2014-04-23 20:59:32 +02:00
for (Tuplet* t : e.tuplets()) {
t->sortElements();
}
}
2013-01-23 14:14:09 +01:00
e.tuplets().clear();
2013-06-10 21:13:04 +02:00
e.setTrack(staffIdx * VOICES);
2013-01-23 14:14:09 +01:00
2016-01-04 14:48:58 +01:00
for (int n = _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;
2012-05-26 14:26:10 +02:00
s->lines = new StaffLines(score());
s->lines->setParent(this);
s->lines->setTrack(n * VOICES);
s->lines->setVisible(!staff->invisible());
2016-02-06 22:03:43 +01:00
_mstaves.push_back(s);
2012-05-26 14:26:10 +02:00
}
// tick is obsolete
2013-01-11 18:10:18 +01:00
if (e.hasAttribute("tick"))
2014-07-21 14:16:16 +02:00
e.initTick(score()->fileDivision(e.intAttribute("tick")));
2012-05-26 14:26:10 +02:00
2013-06-04 18:29:14 +02:00
bool irregular;
2013-01-11 18:10:18 +01:00
if (e.hasAttribute("len")) {
QStringList sl = e.attribute("len").split('/');
2012-05-26 14:26:10 +02:00
if (sl.size() == 2)
_len = Fraction(sl[0].toInt(), sl[1].toInt());
else
2013-01-11 18:10:18 +01:00
qDebug("illegal measure size <%s>", qPrintable(e.attribute("len")));
2012-05-26 14:26:10 +02:00
irregular = true;
score()->sigmap()->add(tick(), SigEvent(_len, _timesig));
score()->sigmap()->add(tick() + ticks(), SigEvent(_timesig));
}
2013-06-04 18:29:14 +02:00
else
irregular = false;
2013-06-04 18:29:14 +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()));
2012-05-26 14:26:10 +02:00
// keep track of tick of previous element
// this allows markings that need to apply to previous element to do so
// even though we may have already advanced to next tick position
int lastTick = e.tick();
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
2012-05-26 14:26:10 +02:00
if (tag == "tick") {
e.initTick(score()->fileDivision(e.readInt()));
lastTick = e.tick();
}
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());
2012-05-26 14:26:10 +02:00
barLine->read(e);
//
2016-03-08 09:46:33 +01:00
// StartRepeatBarLine: always at the beginning tick of a measure, always BarLineType::START_REPEAT
// BarLine: in the middle of a measure, has no semantic
// EndBarLine: at the end tick of a measure
// BeginBarLine: first segment of a measure
2016-03-08 09:46:33 +01:00
Segment::Type st;
2014-10-10 14:24:37 +02:00
if ((e.tick() != tick()) && (e.tick() != endTick()))
st = Segment::Type::BarLine;
else if (barLine->barLineType() == BarLineType::START_REPEAT && e.tick() == tick())
st = Segment::Type::StartRepeatBarLine;
2016-02-04 11:27:47 +01:00
else if (e.tick() == tick() && segment == 0)
st = Segment::Type::BeginBarLine;
2014-10-10 14:24:37 +02:00
else
st = Segment::Type::EndBarLine;
2016-02-04 11:27:47 +01:00
segment = getSegment(st, e.tick());
segment->add(barLine);
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);
segment = getSegment(Segment::Type::ChordRest, e.tick());
2014-11-28 22:35:25 +01:00
if (chord->noteType() != NoteType::NORMAL) {
graceNotes.push_back(chord);
if (chord->tremolo() && chord->tremolo()->tremoloType() < TremoloType::R8) {
// old style tremolo found
Tremolo* tremolo = chord->tremolo();
TremoloType st;
switch (tremolo->tremoloType()) {
default:
case TremoloType::OLD_R8: st = TremoloType::R8; break;
case TremoloType::OLD_R16: st = TremoloType::R16; break;
case TremoloType::OLD_R32: st = TremoloType::R32; break;
case TremoloType::OLD_C8: st = TremoloType::C8; break;
case TremoloType::OLD_C16: st = TremoloType::C16; break;
case TremoloType::OLD_C32: st = TremoloType::C32; break;
}
tremolo->setTremoloType(st);
}
}
2012-05-26 14:26:10 +02:00
else {
2013-06-16 23:33:37 +02:00
segment->add(chord);
Q_ASSERT(segment->segmentType() == Segment::Type::ChordRest);
2013-06-24 13:46:21 +02:00
2013-06-16 23:33:37 +02:00
for (int i = 0; i < graceNotes.size(); ++i) {
Chord* gc = graceNotes[i];
gc->setGraceIndex(i);
chord->add(gc);
}
graceNotes.clear();
2014-07-28 15:54:47 +02:00
int crticks = chord->actualTicks();
2013-06-10 21:13:04 +02:00
if (chord->tremolo() && chord->tremolo()->tremoloType() < TremoloType::R8) {
2013-06-10 21:13:04 +02:00
// old style tremolo found
2014-11-28 22:35:25 +01:00
2013-06-10 21:13:04 +02:00
Tremolo* tremolo = chord->tremolo();
2014-11-28 22:35:25 +01:00
TremoloType st;
switch (tremolo->tremoloType()) {
default:
case TremoloType::OLD_R8: st = TremoloType::R8; break;
case TremoloType::OLD_R16: st = TremoloType::R16; break;
case TremoloType::OLD_R32: st = TremoloType::R32; break;
case TremoloType::OLD_C8: st = TremoloType::C8; break;
case TremoloType::OLD_C16: st = TremoloType::C16; break;
case TremoloType::OLD_C32: st = TremoloType::C32; break;
}
tremolo->setTremoloType(st);
2013-06-10 21:13:04 +02:00
if (tremolo->twoNotes()) {
int track = chord->track();
Segment* ss = 0;
for (Segment* ps = first(Segment::Type::ChordRest); ps; ps = ps->next(Segment::Type::ChordRest)) {
2013-06-10 21:13:04 +02:00
if (ps->tick() >= e.tick())
break;
if (ps->element(track))
ss = ps;
}
Chord* pch = 0; // previous chord
if (ss) {
ChordRest* cr = static_cast<ChordRest*>(ss->element(track));
if (cr && cr->type() == Element::Type::CHORD)
2013-06-10 21:13:04 +02:00
pch = static_cast<Chord*>(cr);
}
if (pch) {
tremolo->setParent(pch);
pch->setTremolo(tremolo);
chord->setTremolo(0);
// force duration to half
2013-06-27 10:03:36 +02:00
Fraction pts(timeStretch * pch->globalDuration());
int pcrticks = pts.ticks();
pch->setDuration(Fraction::fromTicks(pcrticks / 2));
chord->setDuration(Fraction::fromTicks(crticks / 2));
2013-06-10 21:13:04 +02:00
}
else {
qDebug("tremolo: first note not found");
}
crticks /= 2;
}
2014-11-28 22:35:25 +01:00
else {
tremolo->setParent(chord);
}
2013-06-10 21:13:04 +02:00
}
lastTick = e.tick();
2014-07-21 14:16:16 +02:00
e.incTick(crticks);
2012-05-26 14:26:10 +02:00
}
}
else if (tag == "Rest") {
Rest* rest = new Rest(score());
rest->setDurationType(TDuration::DurationType::V_MEASURE);
2012-05-26 14:26:10 +02:00
rest->setDuration(timesig()/timeStretch);
2013-01-21 20:21:41 +01:00
rest->setTrack(e.track());
rest->read(e);
2013-01-21 20:21:41 +01:00
segment = getSegment(rest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(rest);
2014-07-28 15:54:47 +02:00
2012-05-26 14:26:10 +02:00
if (!rest->duration().isValid()) // hack
rest->setDuration(timesig()/timeStretch);
lastTick = e.tick();
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());
int tick = e.tick();
2012-05-26 14:26:10 +02:00
breath->read(e);
if (score()->mscVersion() < 205) {
// older scores placed the breath segment right after the chord to which it applies
// rather than before the next chordrest segment with an element for the staff
// result would be layout too far left if there are other segments due to notes in other staves
// we need to find tick of chord to which this applies, and add its duration
int prevTick;
if (e.tick() < tick)
prevTick = e.tick(); // use our own tick if we explicitly reset to earlier position
else
prevTick = lastTick; // otherwise use tick of previous tick/chord/rest tag
// find segment
Segment* prev = findSegment(Segment::Type::ChordRest, prevTick);
if (prev) {
// find chordrest
ChordRest* lastCR = static_cast<ChordRest*>(prev->element(e.track()));
if (lastCR)
tick = prevTick + lastCR->actualTicks();
}
}
segment = getSegment(Segment::Type::Breath, tick);
2012-05-26 14:26:10 +02:00
segment->add(breath);
}
else if (tag == "endSpanner") {
int id = e.attribute("id").toInt();
2014-07-21 13:24:21 +02:00
Spanner* spanner = e.findSpanner(id);
2013-01-11 18:10:18 +01:00
if (spanner) {
2014-08-13 15:42:40 +02:00
spanner->setTicks(e.tick() - spanner->tick());
// if (spanner->track2() == -1)
// the absence of a track tag [?] means the
// track is the same as the beginning of the slur
2014-03-15 12:57:36 +01:00
if (spanner->track2() == -1)
spanner->setTrack2(spanner->track() ? spanner->track() : e.track());
2012-05-26 14:26:10 +02:00
}
2013-10-13 13:06:32 +02:00
else {
// remember "endSpanner" values
SpannerValues sv;
sv.spannerId = id;
sv.track2 = e.track();
sv.tick2 = e.tick();
e.addSpannerValues(sv);
}
2013-01-11 18:10:18 +01:00
e.readNext();
2012-05-26 14:26:10 +02:00
}
else if (tag == "Slur") {
Slur *sl = new Slur(score());
sl->setTick(e.tick());
sl->read(e);
//
// check if we already saw "endSpanner"
//
2014-07-21 13:24:21 +02:00
int id = e.spannerId(sl);
const SpannerValues* sv = e.spannerValues(id);
if (sv) {
sl->setTick2(sv->tick2);
2015-03-03 15:45:25 +01:00
sl->setTrack2(sv->track2);
}
2015-03-03 15:45:25 +01:00
score()->addSpanner(sl);
}
2012-05-26 14:26:10 +02:00
else if (tag == "HairPin"
|| tag == "Pedal"
|| tag == "Ottava"
|| tag == "Trill"
|| tag == "TextLine"
|| tag == "Volta") {
2013-01-18 10:55:52 +01:00
Spanner* sp = static_cast<Spanner*>(Element::name2Element(tag, score()));
2013-06-10 11:03:34 +02:00
sp->setTrack(e.track());
sp->setTick(e.tick());
2014-06-18 20:57:45 +02:00
// ?? sp->setAnchor(Spanner::Anchor::SEGMENT);
2012-05-26 14:26:10 +02:00
sp->read(e);
2013-06-20 13:57:15 +02:00
score()->addSpanner(sp);
2013-10-13 13:06:32 +02:00
//
// check if we already saw "endSpanner"
//
2014-07-21 13:24:21 +02:00
int id = e.spannerId(sp);
const SpannerValues* sv = e.spannerValues(id);
2013-10-13 13:06:32 +02:00
if (sv) {
2014-08-13 15:42:40 +02:00
sp->setTicks(sv->tick2 - sp->tick());
2013-10-13 13:06:32 +02:00
sp->setTrack2(sv->track2);
}
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);
segment = getSegment(Segment::Type::ChordRest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(rm);
if (rm->actualDuration().isZero()) { // might happen with 1.3 scores
rm->setDuration(len());
}
lastTick = e.tick();
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);
// in some 1.3 scores, clefs can be in score but not in cleflist
2014-07-25 17:13:27 +02:00
// if (score()->mscVersion() > 114)
// staff->setClef(e.tick(), clef->clefTypeList());
2013-07-12 18:41:33 +02:00
// there may be more than one clef segment for same tick position
2014-05-05 17:56:13 +02:00
if (!segment) {
// this is the first segment of measure
segment = getSegment(Segment::Type::Clef, e.tick());
2014-05-05 17:56:13 +02:00
}
2013-07-12 18:41:33 +02:00
else {
2014-05-05 17:56:13 +02:00
bool firstSegment = false;
// the first clef may be missing and is added later in layout
2014-05-05 17:56:13 +02:00
for (Segment* s = _segments.first(); s && s->tick() == e.tick(); s = s->next()) {
if (s->segmentType() == Segment::Type::Clef
// hack: there may be other segment types which should
// generate a clef at current position
|| s->segmentType() == Segment::Type::StartRepeatBarLine
) {
2014-05-05 17:56:13 +02:00
firstSegment = true;
2013-07-12 18:41:33 +02:00
break;
}
}
2014-05-05 17:56:13 +02:00
if (firstSegment) {
Segment* ns = 0;
if (segment->next()) {
ns = segment->next();
while (ns && ns->tick() < e.tick())
ns = ns->next();
}
segment = 0;
for (Segment* s = ns; s && s->tick() == e.tick(); s = s->next()) {
if (s->segmentType() == Segment::Type::Clef) {
2014-05-05 17:56:13 +02:00
segment = s;
break;
}
}
if (!segment) {
segment = new Segment(this, Segment::Type::Clef, e.tick());
2014-05-05 17:56:13 +02:00
_segments.insert(segment, ns);
}
}
else {
// this is the first clef: move to left
segment = getSegment(Segment::Type::Clef, e.tick());
2013-07-12 18:41:33 +02:00
}
2012-05-26 14:26:10 +02:00
}
2014-10-28 11:47:04 +01:00
if (e.tick() != tick())
clef->setSmall(true); // layout does this ?
2012-05-26 14:26:10 +02:00
segment->add(clef);
}
else if (tag == "TimeSig") {
TimeSig* ts = new TimeSig(score());
2013-01-21 20:21:41 +01:00
ts->setTrack(e.track());
2012-10-24 13:15:46 +02:00
ts->read(e);
// if time sig not at begining of measure => courtesy time sig
2014-04-16 09:35:23 +02:00
int currTick = e.tick();
bool courtesySig = (currTick > tick());
if (courtesySig) {
// if courtesy sig., just add it without map processing
segment = getSegment(Segment::Type::TimeSigAnnounce, currTick);
segment->add(ts);
2014-07-28 15:54:47 +02:00
}
else {
// if 'real' time sig., do full process
segment = getSegment(Segment::Type::TimeSig, currTick);
segment->add(ts);
2013-06-04 18:29:14 +02:00
2014-10-08 10:57:24 +02:00
timeStretch = ts->stretch().reduced();
_timesig = ts->sig() / timeStretch;
if (score()->mscVersion() > 114) {
if (irregular) {
score()->sigmap()->add(tick(), SigEvent(_len, _timesig));
score()->sigmap()->add(tick() + ticks(), SigEvent(_timesig));
}
else {
_len = _timesig;
score()->sigmap()->add(tick(), SigEvent(_timesig));
}
}
2012-06-28 15:12:17 +02:00
}
2012-05-26 14:26:10 +02:00
}
else if (tag == "KeySig") {
KeySig* ks = new KeySig(score());
2013-01-21 20:21:41 +01:00
ks->setTrack(e.track());
2012-05-26 14:26:10 +02:00
ks->read(e);
2014-08-24 13:10:51 +02:00
int curTick = e.tick();
if (!ks->isCustom() && !ks->isAtonal() && ks->key() == Key::C && curTick == 0) {
2014-08-24 13:10:51 +02:00
// ignore empty key signature
qDebug("remove keysig c at tick 0");
2016-03-30 22:33:04 +02:00
if (ks->links()) {
if (ks->links()->size() == 1)
e.linkIds().remove(ks->links()->lid());
}
2014-08-24 13:10:51 +02:00
}
else {
// if key sig not at beginning of measure => courtesy key sig
// bool courtesySig = (curTick > tick());
bool courtesySig = (curTick == endTick());
2014-08-24 13:10:51 +02:00
segment = getSegment(courtesySig ? Segment::Type::KeySigAnnounce : Segment::Type::KeySig, curTick);
segment->add(ks);
if (!courtesySig)
staff->setKey(curTick, ks->keySigEvent());
2014-08-24 13:10:51 +02:00
}
2012-05-26 14:26:10 +02:00
}
else if (tag == "Lyrics") { // obsolete, keep for compatibility with version 114
Element* element = Element::name2Element(tag, score());
element->setTrack(e.track());
element->read(e);
segment = getSegment(Segment::Type::ChordRest, e.tick());
ChordRest* cr = static_cast<ChordRest*>(segment->element(element->track()));
if (!cr)
cr = static_cast<ChordRest*>(segment->element(e.track())); // in case lyric itself has bad track info
2012-05-26 14:26:10 +02:00
if (!cr)
qDebug("Internal error: no chord/rest for lyrics");
2012-05-26 14:26:10 +02:00
else
cr->add(element);
2012-05-26 14:26:10 +02:00
}
else if (tag == "Text") {
2014-10-06 18:44:08 +02:00
Text* t = new StaffText(score());
2013-01-21 20:21:41 +01:00
t->setTrack(e.track());
2012-05-26 14:26:10 +02:00
t->read(e);
2016-03-30 22:33:04 +02:00
if (t->empty()) {
qDebug("reading empty text: deleted");
delete t;
}
2012-09-21 12:23:18 +02:00
else {
segment = getSegment(Segment::Type::ChordRest, e.tick());
2012-09-21 12:23:18 +02:00
segment->add(t);
}
2012-05-26 14:26:10 +02:00
}
//----------------------------------------------------
// Annotation
else if (tag == "Dynamic") {
Dynamic* dyn = new Dynamic(score());
2013-01-21 20:21:41 +01:00
dyn->setTrack(e.track());
2012-05-26 14:26:10 +02:00
dyn->read(e);
2013-02-14 13:50:59 +01:00
if (score()->mscVersion() <= 114)
dyn->setDynamicType(dyn->xmlText());
segment = getSegment(Segment::Type::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 == "RehearsalMark"
|| tag == "InstrumentChange"
|| tag == "StaffState"
|| tag == "FiguredBass"
) {
2013-01-18 10:55:52 +01:00
Element* el = Element::name2Element(tag, score());
// hack - needed because tick tags are unreliable in 1.3 scores
// for symbols attached to anything but a measure
if (score()->mscVersion() <= 114 && el->type() == Element::Type::SYMBOL)
el->setParent(this); // this will get reset when adding to segment
2013-01-21 20:21:41 +01:00
el->setTrack(e.track());
2012-05-26 14:26:10 +02:00
el->read(e);
segment = getSegment(Segment::Type::ChordRest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(el);
}
else if (tag == "Marker"
|| tag == "Jump"
) {
Element* el = Element::name2Element(tag, score());
el->setTrack(e.track());
el->read(e);
add(el);
}
else if (tag == "Image") {
if (MScore::noImages)
e.skipCurrentElement();
else {
Element* el = Element::name2Element(tag, score());
el->setTrack(e.track());
el->read(e);
segment = getSegment(Segment::Type::ChordRest, e.tick());
segment->add(el);
}
}
2012-05-26 14:26:10 +02:00
//----------------------------------------------------
else if (tag == "stretch") {
double val = e.readDouble();
if (val < 0.0)
val = 0;
setUserStretch(val);
}
2012-05-26 14:26:10 +02:00
else if (tag == "noOffset")
2016-01-04 14:48:58 +01:00
setNoOffset(e.readInt());
else if (tag == "measureNumberMode")
setMeasureNumberMode(MeasureNumberMode(e.readInt()));
else if (tag == "irregular")
2016-01-04 14:48:58 +01:00
setIrregular(e.readBool());
else if (tag == "breakMultiMeasureRest")
_breakMultiMeasureRest = e.readBool();
else if (tag == "sysInitBarLineType") {
2016-01-04 14:48:58 +01:00
const QString& val(e.readElementText());
2016-02-04 11:27:47 +01:00
BarLine* barLine = new BarLine(score());
barLine->setTrack(e.track());
barLine->setBarLineType(val);
segment = getSegment(Segment::Type::BeginBarLine, tick());
segment->add(barLine);
}
2012-05-26 14:26:10 +02:00
else if (tag == "Tuplet") {
Tuplet* tuplet = new Tuplet(score());
2013-01-21 20:21:41 +01:00
tuplet->setTrack(e.track());
tuplet->setTick(e.tick());
2012-05-26 14:26:10 +02:00
tuplet->setParent(this);
tuplet->read(e);
2013-01-21 20:21:41 +01:00
e.addTuplet(tuplet);
2012-05-26 14:26:10 +02:00
}
2013-01-11 18:10:18 +01:00
else if (tag == "startRepeat") {
2016-02-04 11:27:47 +01:00
setRepeatStart(true);
2013-01-11 18:10:18 +01:00
e.readNext();
}
2012-05-26 14:26:10 +02:00
else if (tag == "endRepeat") {
2013-01-11 18:10:18 +01:00
_repeatCount = e.readInt();
2016-02-04 11:27:47 +01:00
setRepeatEnd(true);
2012-05-26 14:26:10 +02:00
}
else if (tag == "vspacer" || tag == "vspacerDown") {
2016-01-04 14:48:58 +01:00
if (_mstaves[staffIdx]->_vspacerDown == 0) {
2012-05-26 14:26:10 +02:00
Spacer* spacer = new Spacer(score());
spacer->setSpacerType(SpacerType::DOWN);
2012-05-26 14:26:10 +02:00
spacer->setTrack(staffIdx * VOICES);
add(spacer);
}
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->_vspacerDown->setGap(e.readDouble() * _spatium);
2012-05-26 14:26:10 +02:00
}
else if (tag == "vspacer" || tag == "vspacerUp") {
2016-01-04 14:48:58 +01:00
if (_mstaves[staffIdx]->_vspacerUp == 0) {
2012-05-26 14:26:10 +02:00
Spacer* spacer = new Spacer(score());
spacer->setSpacerType(SpacerType::UP);
2012-05-26 14:26:10 +02:00
spacer->setTrack(staffIdx * VOICES);
add(spacer);
}
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->_vspacerUp->setGap(e.readDouble() * _spatium);
2012-05-26 14:26:10 +02:00
}
else if (tag == "visible")
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->_visible = e.readInt();
2012-05-26 14:26:10 +02:00
else if (tag == "slashStyle")
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->_slashStyle = e.readInt();
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);
2013-01-21 20:21:41 +01:00
e.addBeam(beam);
2012-05-26 14:26:10 +02:00
}
else if (tag == "Segment")
2013-06-24 19:01:31 +02:00
segment->read(e);
2012-10-17 10:39:39 +02:00
else if (tag == "MeasureNumber") {
Text* noText = new Text(score());
noText->read(e);
noText->setFlag(ElementFlag::ON_STAFF, true);
// noText->setFlag(ElementFlag::MOVABLE, false); ??
noText->setTrack(e.track());
noText->setParent(this);
2016-01-04 14:48:58 +01:00
_mstaves[noText->staffIdx()]->setNoText(noText);
2012-10-17 10:39:39 +02:00
}
2015-07-25 08:43:02 +02:00
else if (tag == "SystemDivider") {
SystemDivider* sd = new SystemDivider(score());
sd->read(e);
add(sd);
}
2013-11-25 12:17:12 +01:00
else if (tag == "Ambitus") {
Ambitus* range = new Ambitus(score());
range->read(e);
segment = getSegment(Segment::Type::Ambitus, e.tick());
range->setParent(segment); // a parent segment is needed for setTrack() to work
range->setTrack(trackZeroVoice(e.track()));
segment->add(range);
}
else if (tag == "multiMeasureRest") {
2014-02-26 19:06:42 +01:00
_mmRestCount = e.readInt();
// set tick to previous measure
setTick(e.lastMeasure()->tick());
e.initTick(e.lastMeasure()->tick());
}
2016-01-04 14:48:58 +01:00
else if (MeasureBase::readProperties(e))
2013-01-17 12:56:14 +01:00
;
2012-05-26 14:26:10 +02:00
else
2013-01-11 18:10:18 +01:00
e.unknown();
2012-05-26 14:26:10 +02:00
}
2016-01-04 14:48:58 +01:00
#if 0
2012-05-26 14:26:10 +02:00
if (staffIdx == 0) {
Segment* s = last();
if (s && s->segmentType() == Segment::Type::BarLine) {
2012-05-26 14:26:10 +02:00
BarLine* b = static_cast<BarLine*>(s->element(0));
setEndBarLineType(b->barLineType(), false, b->visible(), b->color());
2012-05-26 14:26:10 +02:00
// s->remove(b);
// delete b;
}
}
2016-01-04 14:48:58 +01:00
#endif
2012-05-26 14:26:10 +02:00
//
// for compatibility with 1.22:
//
if (score()->mscVersion() == 122) {
int ticks1 = 0;
for (Segment* s = last(); s; s = s->prev()) {
if (s->segmentType() == Segment::Type::ChordRest) {
if (s->element(0)) {
ChordRest* cr = static_cast<ChordRest*>(s->element(0));
if (cr->type() == Element::Type::REPEAT_MEASURE)
ticks1 = ticks();
else
ticks1 = s->rtick() + cr->actualTicks();
break;
}
}
}
if (ticks() != ticks1) {
// this is a irregular measure
_len = Fraction::fromTicks(ticks1);
_len.reduce();
for (Segment* s = last(); s; s = s->prev()) {
if (s->tick() < tick() + ticks())
break;
if (s->segmentType() == Segment::Type::BarLine) {
qDebug("reduce BarLine to EndBarLine");
s->setSegmentType(Segment::Type::EndBarLine);
}
}
}
2012-05-26 14:26:10 +02:00
}
2013-01-21 20:21:41 +01:00
foreach (Tuplet* tuplet, e.tuplets()) {
2016-02-06 22:03:43 +01:00
if (tuplet->elements().empty()) {
2012-05-26 14:26:10 +02:00
// this should not happen and is a sign of input file corruption
2013-01-24 09:31:41 +01:00
qDebug("Measure:read(): empty tuplet id %d (%p), input file corrupted?",
tuplet->id(), tuplet);
2012-05-26 14:26:10 +02:00
delete tuplet;
}
else
tuplet->setParent(this);
}
}
//---------------------------------------------------------
// visible
//---------------------------------------------------------
bool Measure::visible(int staffIdx) const
{
2014-11-10 14:18:42 +01:00
if (staffIdx >= score()->staves().size()) {
qDebug("Measure::visible: bad staffIdx: %d", staffIdx);
return false;
}
2016-02-06 22:03:43 +01:00
if (system() && (system()->staves()->empty() || !system()->staff(staffIdx)->show()))
2015-08-04 19:53:54 +02:00
return false;
if (score()->staff(staffIdx)->cutaway() && isMeasureRest(staffIdx))
return false;
2016-01-04 14:48:58 +01:00
return score()->staff(staffIdx)->show() && _mstaves[staffIdx]->_visible;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// slashStyle
//---------------------------------------------------------
bool Measure::slashStyle(int staffIdx) const
{
2016-01-04 14:48:58 +01:00
return score()->staff(staffIdx)->slashStyle() || _mstaves[staffIdx]->_slashStyle || score()->staff(staffIdx)->staffType()->slashStyle();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// isFinalMeasureOfSection
// returns true if this measure is final actual measure of a section
2016-04-14 11:45:12 +02:00
// takes into consideration fact that subsequent measures base objects
// may have section break before encountering next actual measure
//---------------------------------------------------------
bool Measure::isFinalMeasureOfSection() const
{
const MeasureBase* mb = static_cast<const MeasureBase*>(this);
do {
if (mb->sectionBreak())
return true;
mb = mb->next();
} while (mb && !mb->isMeasure()); // loop until reach next actual measure or end of score
return false;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// scanElements
//---------------------------------------------------------
void Measure::scanElements(void* data, void (*func)(void*, Element*), bool all)
{
MeasureBase::scanElements(data, func, all);
int nstaves = score()->nstaves();
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (!all && !(visible(staffIdx) && score()->staff(staffIdx)->show()))
2012-05-26 14:26:10 +02:00
continue;
2016-01-04 14:48:58 +01:00
MStaff* ms = _mstaves[staffIdx];
func(data, ms->lines);
2012-05-26 14:26:10 +02:00
if (ms->_vspacerUp)
func(data, ms->_vspacerUp);
if (ms->_vspacerDown)
func(data, ms->_vspacerDown);
if (ms->noText())
func(data, ms->noText());
2012-05-26 14:26:10 +02:00
}
for (Segment* s = first(); s; s = s->next())
s->scanElements(data, func, all);
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()) {
if (s->segmentType() != Segment::Type::ChordRest)
2012-05-26 14:26:10 +02:00
continue;
if (s->element(track) == 0)
score()->setRest(s->tick(), track, len(), true, 0);
break;
}
}
//---------------------------------------------------------
// setStartRepeatBarLine
// return true if bar line type changed
//---------------------------------------------------------
2016-02-04 11:27:47 +01:00
void Measure::setStartRepeatBarLine()
2012-05-26 14:26:10 +02:00
{
2016-02-04 11:27:47 +01:00
bool val = repeatStart();
2014-07-17 09:32:30 +02:00
Segment* s = findSegment(Segment::Type::StartRepeatBarLine, tick());
bool customSpan = false;
int numStaves = score()->nstaves();
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < numStaves;) {
2012-05-26 14:26:10 +02:00
int track = staffIdx * VOICES;
Staff* staff = score()->staff(staffIdx);
2016-02-04 11:27:47 +01:00
BarLine* bl = s ? static_cast<BarLine*>(s->element(track)) : 0;
int span, spanFrom, spanTo;
2016-02-09 13:51:19 +01:00
// if there is a bar line, take span from it
2016-03-08 09:46:33 +01:00
if (bl && bl->customSpan()) { // if there is a bar line and has custom span,
2016-02-04 11:27:47 +01:00
span = bl->span();
spanFrom = bl->spanFrom();
spanTo = bl->spanTo();
2016-03-08 09:46:33 +01:00
customSpan = true;
}
else {
2016-02-04 11:27:47 +01:00
span = staff->barLineSpan();
spanFrom = staff->barLineFrom();
spanTo = staff->barLineTo();
if (span == 0 && customSpan) {
// spanned staves have already been skipped by the loop at the end;
// if a staff with span 0 is found and the previous bar line had custom span
// this staff shall have an aditional bar line, because the previous staff bar
// line has been shortened
int staffLines = staff->lines();
span = 1;
spanFrom = staffLines == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0;
spanTo = staffLines == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (staffLines-1) * 2;
}
}
// make sure we do not span more staves than actually exist
if (staffIdx + span > numStaves)
span = numStaves - staffIdx;
2012-05-26 14:26:10 +02:00
2016-03-08 09:46:33 +01:00
if (span && val && !bl) {
2012-05-26 14:26:10 +02:00
// no barline were we need one:
2016-02-04 11:27:47 +01:00
if (s == 0)
s = undoGetSegment(Segment::Type::StartRepeatBarLine, tick());
Bar lines: fixing custom type and generated management There are some inconsistencies in the current management of bar line `_generated` flag and user-modified type: - Bar lines created by the New Score Wizard are flagged as non-generated, as well as bar lines of measures manually **appended** by the user, while bar lines of measures **inserted** are flagged as generated. - If a generated bar line is individually changed of typed, it remains flagged as generated, it is not saved and the change is lost upon saving and re-loading. - The management of the internal flag `BarLine::_customSubtype` is not always consistent. - The `Measure::_endBarLineGenerated` flag was not always restored properly by undo. This PR introduces the following fixes: - The `_generated` flag is consistently used for bar lines whose type can be reconstructed from the context and then do not need to be saved to the output file. - Normal bar lines are **always** created as generated: initially created by the Wizard, manually appended or inserted. - Bar lines with custom type (i.e. different from the type which can be expected according to the bar line context) are always flagged as non-generated, ensuring the custom type is written to the output file. - The `Measure::_endBarLineGenerated` flag is stored by `ChangeEndBarLineType()` and restore upon undo. - Some test reference scores, based on the inconsistent bar line `_generated` flag, have been uniformed. Notes: - Tests about measure (and then bar line) appending, inserting and relative undo's are already included in the `tst_parts` test suite. - Some inconsistencies remain in the management of custom bar line span and of system-initial bar lines: for the sake of simplicity, they will be dealt with in separate PR's.
2014-09-06 10:36:35 +02:00
bl = new BarLine(score());
bl->setBarLineType(BarLineType::START_REPEAT);
2016-02-04 11:27:47 +01:00
bl->setGenerated(true);
bl->setTrack(track);
bl->setParent(s);
2012-05-26 14:26:10 +02:00
score()->undoAddElement(bl);
}
else if (bl && !val) {
// barline were we do not need one:
2013-10-25 12:17:42 +02:00
if (!score()->undoRedo()) // DEBUG
score()->undoRemoveElement(bl);
2012-05-26 14:26:10 +02:00
}
if (bl && val && span) {
2012-05-26 14:26:10 +02:00
bl->setSpan(span);
bl->setSpanFrom(spanFrom);
bl->setSpanTo(spanTo);
}
2012-05-26 14:26:10 +02:00
++staffIdx;
//
// remove any unwanted barlines:
//
// if spanning several staves but not entering INTO last staff,
if (span > 1 && spanTo <= 0)
span--; // count one span less
2012-05-26 14:26:10 +02:00
if (s) {
for (int i = 1; i < span; ++i) {
2016-02-04 11:27:47 +01:00
Element* e = s->element(staffIdx * VOICES);
if (e)
2016-02-17 14:54:23 +01:00
score()->undoRemoveElement(toBarLine(e));
2012-05-26 14:26:10 +02:00
++staffIdx;
}
}
}
2016-02-04 11:27:47 +01:00
if (s)
2016-01-04 14:48:58 +01:00
s->createShapes();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// createEndBarLines
// actually creates or modifies barlines
2016-02-04 11:27:47 +01:00
// return the width change for measure
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
qreal Measure::createEndBarLines(bool isLastMeasureInSystem)
2012-05-26 14:26:10 +02:00
{
int nstaves = score()->nstaves();
Segment* seg = undoGetSegment(Segment::Type::EndBarLine, endTick());
2016-02-04 11:27:47 +01:00
BarLine* bl = 0;
int span = 0; // span counter
int aspan = 0; // actual span
bool mensur = false; // keep note of Mensurstrich case
int spanTot; // to keep track of the target span as we count down
int lastIdx;
int spanFrom = 0;
int spanTo = 0;
static const int unknownSpanFrom = 9999;
2012-09-19 14:13:07 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
2016-01-04 14:48:58 +01:00
Staff* staff = score()->staff(staffIdx);
int track = staffIdx * VOICES;
int staffLines = staff->lines();
2014-07-17 09:32:30 +02:00
2012-10-14 09:25:33 +02:00
// get existing bar line for this staff, if any
2016-03-08 09:46:33 +01:00
BarLine* cbl = toBarLine(seg->element(track));
2014-07-17 09:32:30 +02:00
// if span counter has been counted off, get new span values
// and forget about any previous bar line
2014-07-17 09:32:30 +02:00
2012-09-19 14:13:07 +02:00
if (span == 0) {
2016-03-08 09:46:33 +01:00
if (cbl && cbl->customSpan()) { // if there is a bar line and has custom span,
span = cbl->span(); // get span values from it
2016-02-09 13:51:19 +01:00
spanFrom = cbl->spanFrom();
spanTo = cbl->spanTo();
}
else { // otherwise, get from staff
span = staff->barLineSpan();
// if some span OR last staff (span==0) of a Mensurstrich case, get From/To from staff
if (span || mensur) {
2016-02-09 13:51:19 +01:00
spanFrom = staff->barLineFrom();
spanTo = staff->barLineTo();
mensur = false;
}
// but if staff is set to no span, a multi-staff spanning bar line
// has been shortened to span less staves and following staves left without bars;
// set bar line span values to default
2016-02-09 13:51:19 +01:00
2015-07-15 03:35:03 +02:00
else if (staff->show()) {
span = 1;
spanFrom = staffLines == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0;
spanTo = staffLines == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (staff->lines() - 1) * 2;
}
}
2015-07-15 03:35:03 +02:00
if (!staff->show()) {
// this staff is not visible
// we should recalculate spanFrom when we find a valid staff
spanFrom = unknownSpanFrom;
}
if ((staffIdx + span) > nstaves) // sanity check, don't span more than available staves
2012-09-19 14:13:07 +02:00
span = nstaves - staffIdx;
2016-01-04 14:48:58 +01:00
spanTot = span;
lastIdx = staffIdx + span - 1;
bl = nullptr;
}
2015-07-15 03:35:03 +02:00
else if (spanFrom == unknownSpanFrom && staff->show()) {
// we started a span earlier, but had not found a valid staff yet
spanFrom = staffLines == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0;
2012-09-19 14:13:07 +02:00
}
if (staff->show() && span) {
//
// there should be a barline in this staff
// this is true even for a staff not shown because of hide empty staves
// but not for a staff not shown because it is made invisible
2012-09-19 14:13:07 +02:00
//
// if we already have a bar line, keep extending this bar line down until span exhausted;
// if no barline yet, re-use the bar line existing in this staff if any,
// restarting actual span
2016-01-04 14:48:58 +01:00
2012-09-19 14:13:07 +02:00
if (!bl) {
2016-01-04 14:48:58 +01:00
bl = cbl;
2012-09-19 14:13:07 +02:00
aspan = 0;
2012-05-26 14:26:10 +02:00
}
2012-09-19 14:13:07 +02:00
if (!bl) {
// no suitable bar line: create a new one
2012-09-19 14:13:07 +02:00
bl = new BarLine(score());
2016-01-04 14:48:58 +01:00
bl->setParent(seg);
2012-09-19 14:13:07 +02:00
bl->setTrack(track);
2016-01-04 14:48:58 +01:00
bl->setGenerated(true);
score()->addElement(bl);
2012-09-19 14:13:07 +02:00
}
else {
// if a bar line exists for this staff (cbl) but
// it is not the bar line we are dealing with (bl),
// we are extending down the bar line of a staff above (bl)
// and the bar line for this staff (cbl) is not needed:
// DELETE it
2016-02-10 13:40:34 +01:00
2012-09-19 14:13:07 +02:00
if (cbl && cbl != bl) {
2016-02-10 13:40:34 +01:00
// Mensurstrich special case:
// if span arrives inside the end staff (spanTo>0) OR
// span is not multi-staff (spanTot<=1) OR
// current staff is not the last spanned staff (span!=1) OR
// staff is the last score staff
// remove bar line for this staff
// If NONE of the above conditions holds, the staff is the last staff of
// a Mensurstrich(-like) span: keep its bar line, as it may span to next staff
2016-02-10 13:40:34 +01:00
if (spanTo > 0 || spanTot <= 1 || span != 1 || staffIdx == nstaves-1)
score()->undoRemoveElement(cbl);
2012-05-26 14:26:10 +02:00
}
}
}
2012-09-19 14:13:07 +02:00
else {
//
2012-09-19 14:13:07 +02:00
// there should be no barline in this staff
//
2016-01-04 14:48:58 +01:00
if (cbl)
2012-09-19 14:13:07 +02:00
score()->undoRemoveElement(cbl);
}
2016-02-10 13:40:34 +01:00
// if span not counted off AND we have a bar line AND this staff is shown,
// set bar line span values (this may result in extending down a bar line
// for a previous staff, if we are counting off a span > 1)
2016-02-10 13:40:34 +01:00
2012-09-19 14:13:07 +02:00
if (span) {
if (bl) {
++aspan;
if (staff->show()) { // count visible staves only (whether hidden or not)
bl->setSpan(aspan); // need to update span & spanFrom even for hidden staves
2012-10-14 09:25:33 +02:00
bl->setSpanFrom(spanFrom);
// if current actual span < target span, set spanTo to full staff height
2015-07-15 03:35:03 +02:00
if (aspan < spanTot && staffIdx < lastIdx)
bl->setSpanTo(staffLines == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (staffLines - 1) * 2);
// if we reached target span, set spanTo to intended value
else
bl->setSpanTo(spanTo);
2012-10-14 09:25:33 +02:00
}
2012-09-19 14:13:07 +02:00
}
--span;
}
// if just finished (span==0) a multi-staff span (spanTot>1) ending at the top of a staff (spanTo<=0)
// scan this staff again, as it may have its own bar lines (Mensurstrich(-like) span)
if (spanTot > 1 && spanTo <= 0 && span == 0) {
mensur = true;
staffIdx--;
}
2012-05-26 14:26:10 +02:00
}
2016-02-12 19:14:24 +01: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.
//
Measure* nm = nextMeasure();
BarLineType t = nm ? BarLineType::NORMAL : BarLineType::END;
bool show = score()->styleB(StyleIdx::genCourtesyKeysig) && !sectionBreak() && nm;
setHasCourtesyKeySig(false);
if (isLastMeasureInSystem && show) {
int tick = endTick();
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
int track = staffIdx * VOICES;
Staff* staff = score()->staff(staffIdx);
KeySigEvent key1 = staff->keySigEvent(tick - 1);
KeySigEvent key2 = staff->keySigEvent(tick);
if (show && !(key1 == key2)) {
// locate a key sig. in next measure and, if found,
// check if it has court. sig turned off
Segment* s = nm->findSegment(Segment::Type::KeySig, tick);
if (s) {
2016-02-17 14:54:23 +01:00
KeySig* ks = toKeySig(s->element(track));
2016-02-12 19:14:24 +01:00
if (ks && !ks->showCourtesy())
show = false; // this key change has court. sig turned off
}
if (show) {
setHasCourtesyKeySig(true);
t = BarLineType::DOUBLE;
break;
}
}
}
}
2016-02-04 11:27:47 +01:00
bool force = false;
if (!isLastMeasureInSystem && repeatEnd() && nextMeasure()->repeatStart()) {
2016-01-04 14:48:58 +01:00
t = BarLineType::END_START_REPEAT;
2016-02-04 11:27:47 +01:00
force = true;
}
else if (repeatEnd()) {
2016-01-04 14:48:58 +01:00
t = BarLineType::END_REPEAT;
2016-02-04 11:27:47 +01:00
force = true;
}
else if (!isLastMeasureInSystem && nextMeasure()->repeatStart()) {
2016-01-04 14:48:58 +01:00
t = BarLineType::START_REPEAT;
2016-02-04 11:27:47 +01:00
force = true;
}
2012-05-26 14:26:10 +02:00
2016-01-04 14:48:58 +01:00
qreal w = 0.0;
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
BarLine* bl = static_cast<BarLine*>(seg->element(staffIdx * VOICES));
if (bl) {
2016-02-10 13:40:34 +01:00
// do not change bar line type if bar line is user modified
// and its not a repeat start/end barline
2016-01-04 14:48:58 +01:00
if (bl->generated())
bl->setBarLineType(t);
2016-02-04 11:27:47 +01:00
else {
if (force) {
2016-02-10 13:40:34 +01:00
score()->undoChangeProperty(bl, P_ID::BARLINE_TYPE, QVariant::fromValue(t));
bl->setGenerated(true);
2016-02-04 11:27:47 +01:00
}
}
2016-01-04 14:48:58 +01:00
bl->layout();
w = bl->width();
}
}
seg->setWidth(w);
seg->createShapes();
2016-02-04 11:27:47 +01:00
// fix previous segment width
Segment* ps = seg->prev();
qreal www = ps->minHorizontalDistance(seg);
w += www - ps->width();
ps->setWidth(www);
2016-02-12 19:14:24 +01:00
setWidth(width() + w);
2016-01-04 14:48:58 +01:00
return w;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// sortStaves
//---------------------------------------------------------
void Measure::sortStaves(QList<int>& dst)
{
2016-02-06 22:03:43 +01:00
std::vector<MStaff*> ms;
2016-02-09 09:20:54 +01:00
for (int idx : dst)
2016-01-04 14:48:58 +01:00
ms.push_back(_mstaves[idx]);
_mstaves = ms;
2012-05-26 14:26:10 +02:00
2016-02-08 15:10:03 +01:00
for (unsigned staffIdx = 0; staffIdx < _mstaves.size(); ++staffIdx)
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->lines->setTrack(staffIdx * VOICES);
2016-02-09 09:20:54 +01:00
for (Segment& s : _segments)
s.sortStaves(dst);
2012-05-26 14:26:10 +02:00
2016-01-04 14:48:58 +01:00
for (Element* e : el()) {
if (e->track() == -1 || e->systemFlag())
2012-05-26 14:26:10 +02:00
continue;
int voice = e->voice();
int staffIdx = e->staffIdx();
int idx = dst.indexOf(staffIdx);
e->setTrack(idx * VOICES + voice);
}
}
//---------------------------------------------------------
// exchangeVoice
//---------------------------------------------------------
2014-08-29 10:35:17 +02:00
void Measure::exchangeVoice(int v1, int v2, int staffIdx)
2012-05-26 14:26:10 +02:00
{
2014-08-29 10:35:17 +02:00
for (Segment* s = first(Segment::Type::ChordRest); s; s = s->next(Segment::Type::ChordRest)) {
int strack = staffIdx * VOICES + v1;
int dtrack = staffIdx * VOICES + v2;
s->swapElements(strack, dtrack);
2012-05-26 14:26:10 +02:00
}
// MStaff* ms = mstaff(staffIdx);
// ms->hasVoices = true;
checkMultiVoices(staffIdx); // probably true, but check for invisible notes & rests
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// checkMultiVoices
2012-08-02 18:33:43 +02:00
/// Check for more than on voice in this measure and staff and
/// set MStaff->hasVoices
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Measure::checkMultiVoices(int staffIdx)
{
int strack = staffIdx * VOICES + 1;
int etrack = staffIdx * VOICES + VOICES;
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->hasVoices = false;
2012-05-26 14:26:10 +02:00
for (Segment* s = first(); s; s = s->next()) {
2016-03-02 13:20:19 +01:00
if (s->isChordRestType())
2012-05-26 14:26:10 +02:00
continue;
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
if (e) {
bool v;
if (e->type() == Element::Type::CHORD) {
v = false;
// consider chord visible if any note is visible
Chord* c = static_cast<Chord*>(e);
for (Note* n : c->notes()) {
if (n->visible()) {
v = true;
break;
}
}
}
else
v = e->visible();
if (v) {
2016-01-04 14:48:58 +01:00
_mstaves[staffIdx]->hasVoices = true;
return;
}
2012-05-26 14:26:10 +02:00
}
}
}
}
//---------------------------------------------------------
// hasVoice
//---------------------------------------------------------
bool Measure::hasVoice(int track) const
{
for (Segment* s = first(); s; s = s->next()) {
if (s->segmentType() != Segment::Type::ChordRest)
2012-05-26 14:26:10 +02:00
continue;
if (s->element(track))
return true;
}
return false;
}
2012-08-02 18:33:43 +02:00
//-------------------------------------------------------------------
2012-05-26 14:26:10 +02:00
// isMeasureRest
2012-08-02 18:33:43 +02:00
/// Check if the measure is filled by a full-measure rest or full
/// of rests on this staff. If staff is -1, then check for
/// all staves.
//-------------------------------------------------------------------
2012-05-26 14:26:10 +02:00
2015-08-04 19:53:54 +02:00
bool Measure::isMeasureRest(int staffIdx) const
2012-05-26 14:26:10 +02:00
{
int strack;
int etrack;
if (staffIdx < 0) {
strack = 0;
etrack = score()->nstaves() * VOICES;
}
else {
strack = staffIdx * VOICES;
2014-08-26 21:01:21 +02:00
etrack = strack + VOICES;
2012-05-26 14:26:10 +02:00
}
for (Segment* s = first(Segment::Type::ChordRest); s; s = s->next(Segment::Type::ChordRest)) {
2012-05-26 14:26:10 +02:00
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
if (e && e->type() != Element::Type::REST)
2012-05-26 14:26:10 +02:00
return false;
}
for (Element* a : s->annotations()) {
if (!a || a->systemFlag())
continue;
int atrack = a->track();
if (atrack >= strack && atrack < etrack)
return false;
}
2012-05-26 14:26:10 +02:00
}
return true;
}
//---------------------------------------------------------
// isFullMeasureRest
// Check for an empty measure, filled with full measure
// rests.
//---------------------------------------------------------
2015-08-04 19:53:54 +02:00
bool Measure::isFullMeasureRest() const
2012-05-26 14:26:10 +02:00
{
int strack = 0;
int etrack = score()->nstaves() * VOICES;
Segment* s = first(Segment::Type::ChordRest);
2012-05-26 14:26:10 +02:00
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
if (e) {
if (e->type() != Element::Type::REST)
2012-05-26 14:26:10 +02:00
return false;
Rest* rest = static_cast<Rest*>(e);
if (rest->durationType().type() != TDuration::DurationType::V_MEASURE)
2012-05-26 14:26:10 +02:00
return false;
}
}
return true;
}
//---------------------------------------------------------
// isRepeatMeasure
//---------------------------------------------------------
2015-08-04 19:53:54 +02:00
bool Measure::isRepeatMeasure(Staff* staff) const
2012-05-26 14:26:10 +02:00
{
int staffIdx = score()->staffIdx(staff);
int strack = staffIdx * VOICES;
int etrack = (staffIdx + 1) * VOICES;
Segment* s = first(Segment::Type::ChordRest);
2012-05-26 14:26:10 +02:00
2012-08-02 18:33:43 +02:00
if (s == 0)
2012-05-26 14:26:10 +02:00
return false;
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
if (e && e->type() == Element::Type::REPEAT_MEASURE)
2012-05-26 14:26:10 +02:00
return true;
}
return false;
}
//---------------------------------------------------------
// isEmpty
//---------------------------------------------------------
2016-02-06 22:03:43 +01:00
bool Measure::empty() const
2012-05-26 14:26:10 +02:00
{
2016-01-04 14:48:58 +01:00
if (irregular())
2012-05-26 14:26:10 +02:00
return false;
int n = 0;
2016-01-04 14:48:58 +01:00
int tracks = _mstaves.size() * VOICES;
static const Segment::Type st { Segment::Type::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)) {
if (s->element(track)->type() != Element::Type::REST)
2012-05-26 14:26:10 +02:00
return false;
restFound = true;
2012-05-26 14:26:10 +02:00
}
}
if (restFound)
++n;
// measure is not empty if there is more than one rest
if (n > 1)
return false;
2012-05-26 14:26:10 +02:00
}
return true;
}
//---------------------------------------------------------
// isOnlyRests
//---------------------------------------------------------
bool Measure::isOnlyRests(int track) const
{
static const Segment::Type st { Segment::Type::ChordRest };
for (const Segment* s = first(st); s; s = s->next(st)) {
if (s->segmentType() != Segment::Type::ChordRest || !s->element(track))
continue;
if (s->element(track)->type() != Element::Type::REST)
return false;
}
return true;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
// minWidth1
/// return minimum width of measure excluding system
/// header
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
qreal Measure::minWidth1() const
2012-05-26 14:26:10 +02:00
{
2016-01-04 14:48:58 +01:00
int nstaves = score()->nstaves();
2016-04-01 18:32:10 +02:00
Segment::Type st = Segment::Type::Clef | Segment::Type::KeySig
| Segment::Type::StartRepeatBarLine | Segment::Type::BeginBarLine;
2016-01-04 14:48:58 +01:00
Segment* s = first();
while ((s->segmentType() & st) && s->next()) {
// found a segment that we might be able to skip
// we can do so only if it contains no non-generated elements
// note that it is possible for the same segment to contain both generated and non-generated elements
// consider, a keysig segment at the start of a system in which one staff has a local key change
bool generated = true;
for (int i = 0; i < nstaves; ++i) {
Element* e = s->element(i * VOICES);
if (e && !e->generated()) {
generated = false;
break;
}
}
if (!generated)
break;
s = s->next();
}
return score()->computeMinWidth(s, false);
}
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
// layoutCR0
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
void Measure::layoutCR0(ChordRest* cr, qreal mm, AccidentalState* as)
{
2016-01-04 14:48:58 +01:00
qreal m = mm;
if (cr->small())
m *= score()->styleD(StyleIdx::smallNoteMag);
2016-01-04 14:48:58 +01:00
if (cr->type() == Element::Type::CHORD) {
Chord* chord = static_cast<Chord*>(cr);
for (Chord* c : chord->graceNotes())
layoutCR0(c, mm, as);
if (!chord->isGrace())
chord->cmdUpdateNotes(as);
2016-01-04 14:48:58 +01:00
if (chord->noteType() != NoteType::NORMAL)
m *= score()->styleD(StyleIdx::graceNoteMag);
const Drumset* drumset = 0;
if (cr->part()->instrument()->useDrumset())
drumset = cr->part()->instrument()->drumset();
if (drumset) {
for (Note* note : chord->notes()) {
int pitch = note->pitch();
if (!drumset->isValid(pitch)) {
// qDebug("unmapped drum note %d", pitch);
}
else if (!note->fixed()) {
note->undoChangeProperty(P_ID::HEAD_GROUP, int(drumset->noteHead(pitch)));
// note->setHeadGroup(drumset->noteHead(pitch));
note->setLine(drumset->line(pitch));
continue;
}
}
2012-08-01 18:00:27 +02:00
}
2016-01-04 14:48:58 +01:00
chord->computeUp();
chord->layoutStem1();
2012-10-08 09:34:46 +02:00
}
2016-01-04 14:48:58 +01:00
if (m != mag())
cr->setMag(m);
}
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
// stretchedLen
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
Fraction Measure::stretchedLen(Staff* staff) const
{
2016-01-04 14:48:58 +01:00
return len() * staff->timeStretch(tick());
}
2016-01-04 14:48:58 +01:00
//---------------------------------------------------------
// cloneMeasure
//---------------------------------------------------------
2016-01-04 14:48:58 +01:00
Measure* Measure::cloneMeasure(Score* sc, TieMap* tieMap)
{
2016-01-04 14:48:58 +01:00
Measure* m = new Measure(sc);
m->_timesig = _timesig;
m->_len = _len;
m->_repeatCount = _repeatCount;
2016-02-09 09:20:54 +01:00
for (MStaff* ms : _mstaves)
2016-02-06 22:03:43 +01:00
m->_mstaves.push_back(new MStaff(*ms));
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;
2012-05-26 14:26:10 +02:00
m->setTick(tick());
m->setLineBreak(lineBreak());
m->setPageBreak(pageBreak());
m->setSectionBreak(sectionBreak() ? new LayoutBreak(*sectionBreak()) : 0);
int tracks = sc->nstaves() * VOICES;
TupletMap tupletMap;
for (Segment* oseg = first(); oseg; oseg = oseg->next()) {
Segment* s = new Segment(m);
s->setSegmentType(oseg->segmentType());
2012-05-26 14:26:10 +02:00
s->setRtick(oseg->rtick());
m->_segments.push_back(s);
for (int track = 0; track < tracks; ++track) {
Element* oe = oseg->element(track);
2014-08-13 17:45:53 +02:00
foreach (Element* e, oseg->annotations()) {
2012-05-26 14:26:10 +02:00
if (e->generated() || e->track() != track)
continue;
Element* ne = e->clone();
ne->setTrack(track);
ne->setUserOff(e->userOff());
2014-11-10 13:33:32 +01:00
ne->setScore(sc);
2012-05-26 14:26:10 +02:00
s->add(ne);
}
2014-08-13 17:45:53 +02:00
if (!oe)
continue;
Element* ne = oe->clone();
if (oe->isChordRest()) {
ChordRest* ocr = static_cast<ChordRest*>(oe);
ChordRest* ncr = static_cast<ChordRest*>(ne);
Tuplet* ot = ocr->tuplet();
if (ot) {
Tuplet* nt = tupletMap.findNew(ot);
if (nt == 0) {
nt = new Tuplet(*ot);
nt->clear();
nt->setTrack(track);
nt->setScore(sc);
tupletMap.add(ot, nt);
}
ncr->setTuplet(nt);
nt->add(ncr);
}
if (oe->type() == Element::Type::CHORD) {
Chord* och = static_cast<Chord*>(ocr);
Chord* nch = static_cast<Chord*>(ncr);
int n = och->notes().size();
for (int i = 0; i < n; ++i) {
Note* on = och->notes().at(i);
Note* nn = nch->notes().at(i);
if (on->tieFor()) {
2014-11-25 16:53:43 +01:00
Tie* tie = on->tieFor()->clone();
tie->setScore(sc);
2014-08-13 17:45:53 +02:00
nn->setTieFor(tie);
tie->setStartNote(nn);
tieMap->add(on->tieFor(), tie);
}
if (on->tieBack()) {
Tie* tie = tieMap->findNew(on->tieBack());
if (tie) {
nn->setTieBack(tie);
tie->setEndNote(nn);
}
else {
qDebug("cloneMeasure: cannot find tie, track %d", track);
}
}
}
}
}
ne->setUserOff(oe->userOff());
2014-11-10 13:33:32 +01:00
ne->setScore(sc);
2014-08-13 17:45:53 +02:00
s->add(ne);
2012-05-26 14:26:10 +02:00
}
}
foreach(Element* e, el()) {
2012-05-26 14:26:10 +02:00
Element* ne = e->clone();
ne->setScore(sc);
ne->setUserOff(e->userOff());
2012-05-26 14:26:10 +02:00
m->add(ne);
}
return m;
}
//---------------------------------------------------------
// pos2sel
//---------------------------------------------------------
int Measure::snap(int tick, const QPointF p) const
{
Segment* s = first();
for (; s->next(); s = s->next()) {
qreal x = s->x();
qreal dx = s->next()->x() - x;
if (s->tick() == tick)
x += dx / 3.0 * 2.0;
else if (s->next()->tick() == tick)
x += dx / 3.0;
else
x += dx * .5;
if (p.x() < x)
break;
}
return s->tick();
}
//---------------------------------------------------------
// snapNote
//---------------------------------------------------------
int Measure::snapNote(int /*tick*/, const QPointF p, int staff) const
{
Segment* s = first();
for (;;) {
Segment* ns = s->next();
while (ns && ns->element(staff) == 0)
ns = ns->next();
if (ns == 0)
break;
qreal x = s->x();
qreal nx = x + (ns->x() - x) * .5;
if (p.x() < nx)
break;
s = ns;
}
return s->tick();
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
QVariant Measure::getProperty(P_ID propertyId) const
{
switch(propertyId) {
2014-05-26 18:18:01 +02:00
case P_ID::TIMESIG_NOMINAL:
return QVariant::fromValue(_timesig);
2014-05-26 18:18:01 +02:00
case P_ID::TIMESIG_ACTUAL:
return QVariant::fromValue(_len);
2014-05-26 18:18:01 +02:00
case P_ID::MEASURE_NUMBER_MODE:
return int(measureNumberMode());
2014-05-26 18:18:01 +02:00
case P_ID::BREAK_MMR:
2016-01-04 14:48:58 +01:00
return breakMultiMeasureRest();
2014-05-26 18:18:01 +02:00
case P_ID::REPEAT_COUNT:
2014-05-20 17:26:26 +02:00
return repeatCount();
2014-05-26 18:18:01 +02:00
case P_ID::USER_STRETCH:
2014-05-20 17:26:26 +02:00
return userStretch();
2014-05-26 18:18:01 +02:00
case P_ID::NO_OFFSET:
2014-05-20 17:26:26 +02:00
return noOffset();
2014-05-26 18:18:01 +02:00
case P_ID::IRREGULAR:
2014-05-20 17:26:26 +02:00
return irregular();
default:
return MeasureBase::getProperty(propertyId);
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool Measure::setProperty(P_ID propertyId, const QVariant& value)
{
switch(propertyId) {
2014-05-26 18:18:01 +02:00
case P_ID::TIMESIG_NOMINAL:
_timesig = value.value<Fraction>();
break;
2014-05-26 18:18:01 +02:00
case P_ID::TIMESIG_ACTUAL:
_len = value.value<Fraction>();
break;
2014-05-26 18:18:01 +02:00
case P_ID::MEASURE_NUMBER_MODE:
setMeasureNumberMode(MeasureNumberMode(value.toInt()));
break;
2014-05-26 18:18:01 +02:00
case P_ID::BREAK_MMR:
2014-05-20 17:26:26 +02:00
setBreakMultiMeasureRest(value.toBool());
break;
2014-05-26 18:18:01 +02:00
case P_ID::REPEAT_COUNT:
2014-05-20 17:26:26 +02:00
setRepeatCount(value.toInt());
break;
2014-05-26 18:18:01 +02:00
case P_ID::USER_STRETCH:
2014-05-20 17:26:26 +02:00
setUserStretch(value.toDouble());
break;
2014-05-26 18:18:01 +02:00
case P_ID::NO_OFFSET:
2014-05-20 17:26:26 +02:00
setNoOffset(value.toInt());
break;
2014-05-26 18:18:01 +02:00
case P_ID::IRREGULAR:
2014-05-20 17:26:26 +02:00
setIrregular(value.toBool());
break;
default:
return MeasureBase::setProperty(propertyId, value);
}
2016-03-02 13:20:19 +01:00
score()->setLayoutAll();
return true;
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
QVariant Measure::propertyDefault(P_ID propertyId) const
{
switch(propertyId) {
2014-05-26 18:18:01 +02:00
case P_ID::TIMESIG_NOMINAL:
case P_ID::TIMESIG_ACTUAL:
return QVariant();
2014-05-26 18:18:01 +02:00
case P_ID::MEASURE_NUMBER_MODE:
return int(MeasureNumberMode::AUTO);
2014-05-26 18:18:01 +02:00
case P_ID::BREAK_MMR:
2014-05-20 17:26:26 +02:00
return false;
2014-05-26 18:18:01 +02:00
case P_ID::REPEAT_COUNT:
2014-05-20 17:26:26 +02:00
return 2;
2014-05-26 18:18:01 +02:00
case P_ID::USER_STRETCH:
2014-05-20 17:26:26 +02:00
return 1.0;
2014-05-26 18:18:01 +02:00
case P_ID::NO_OFFSET:
2014-05-20 17:26:26 +02:00
return 0;
2014-05-26 18:18:01 +02:00
case P_ID::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())
return static_cast<Measure*>(prev()->next());
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())
return static_cast<Measure*>(next()->prev());
return score()->lastMeasure();
}
2014-04-24 10:42:42 +02:00
//---------------------------------------------------------
// mmRest1
// return the multi measure rest this measure is covered
// by
//---------------------------------------------------------
const Measure* Measure::mmRest1() const
2014-04-24 10:42:42 +02:00
{
if (_mmRest)
return _mmRest;
if (_mmRestCount != -1)
// return const_cast<Measure*>(this);
return this;
2014-04-24 10:42:42 +02:00
const Measure* m = this;
while (m && !m->_mmRest)
m = m->prevMeasure();
if (m)
return const_cast<Measure*>(m->_mmRest);
return 0;
}
2014-05-17 18:40:05 +02:00
//-------------------------------------------------------------------
// userStretch
//-------------------------------------------------------------------
2014-05-20 17:26:26 +02:00
2014-05-17 18:40:05 +02:00
qreal Measure::userStretch() const
{
return (score()->layoutMode() == LayoutMode::FLOAT ? 1.0 : _userStretch);
2014-05-17 18:40:05 +02:00
}
2014-04-24 10:42:42 +02:00
Element* Measure::nextElementStaff(int staff)
{
2016-02-11 18:20:16 +01:00
Segment* firstSeg = segments().first();
if (firstSeg)
return firstSeg->firstElement(staff);
return score()->firstElement();
}
Element* Measure::prevElementStaff(int staff)
{
Measure* prevM = prevMeasureMM();
if (prevM) {
Segment* seg = prevM->last();
if (seg)
seg->lastElement(staff);
}
return score()->lastElement();
}
//---------------------------------------------------------
// 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-02-08 15:10:03 +01:00
// resize width of measure to stretch
2016-01-04 14:48:58 +01:00
//-----------------------------------------------------------------------------
void Measure::stretchMeasure(qreal stretch)
{
bbox().setWidth(stretch);
2016-03-10 10:41:31 +01:00
int nstaves = score()->nstaves();
2016-01-04 14:48:58 +01:00
int minTick = 100000;
2016-02-08 15:10:03 +01:00
for (auto& s : _segments) {
2016-01-04 14:48:58 +01:00
int nticks;
2016-03-02 13:20:19 +01:00
if (s.isChordRestType()) {
2016-02-08 15:10:03 +01:00
const Segment* nseg = s.next(Segment::Type::ChordRest);
nticks = (nseg ? nseg->rtick() : ticks()) - s.rtick();
2016-01-04 14:48:58 +01:00
if (nticks) {
if (nticks < minTick)
minTick = nticks;
}
}
else
nticks = 0;
2016-02-08 15:10:03 +01:00
s.setTicks(nticks);
2016-01-04 14:48:58 +01:00
}
//---------------------------------------------------
// computeStretch
//---------------------------------------------------
SpringMap springs;
qreal minimum = first()->pos().x();
2016-02-08 15:10:03 +01:00
for (auto& s : _segments) {
2016-01-04 14:48:58 +01:00
qreal str = 1.0;
qreal d;
2016-02-08 15:10:03 +01:00
int t = s.ticks();
2016-01-04 14:48:58 +01:00
if (t) {
if (minTick > 0)
// str += .6 * log(qreal(t) / qreal(minTick)) / log(2.0);
str = 1.0 + 0.865617 * log(qreal(t) / qreal(minTick));
2016-02-08 15:10:03 +01:00
d = s.width() / str;
2016-01-04 14:48:58 +01:00
}
else {
str = 0.0; // dont stretch timeSig and key
d = 100000000.0; // CHECK
}
2016-02-08 15:10:03 +01:00
springs.insert(std::pair<qreal, Spring>(d, Spring(&s, str)));
minimum += s.width();
2016-01-04 14:48:58 +01:00
}
//---------------------------------------------------
// distribute stretch to segments
//---------------------------------------------------
qreal force = sff(stretch, minimum, springs);
2016-02-08 15:10:03 +01:00
for (auto& i : springs) {
qreal stretch = force * i.second.stretch;
if (stretch < i.second.fix)
stretch = i.second.fix;
i.second.seg->setWidth(stretch);
2016-01-04 14:48:58 +01:00
}
qreal x = first()->pos().x();
for (Segment* s = first(); s; s = s->next()) {
s->rxpos() = x;
x += s->width();
}
//---------------------------------------------------
// layout individual elements
//---------------------------------------------------
int tracks = nstaves * VOICES;
for (Segment* s = first(); s; s = s->next()) {
for (int track = 0; track < tracks; ++track) {
if (!score()->staff(track/VOICES)->show()) {
track += VOICES-1;
continue;
}
Element* e = s->element(track);
if (e == 0)
continue;
Element::Type t = e->type();
Rest* rest = static_cast<Rest*>(e);
if (t == Element::Type::REPEAT_MEASURE || (t == Element::Type::REST && (isMMRest() || rest->isFullMeasureRest()))) {
//
// element has to be centered in free space
// x1 - left measure position of free space
// x2 - right measure position of free space
2016-02-17 12:48:53 +01:00
Segment* s1 = s->prev() ? s->prev() : 0;
Segment* s2;
for (s2 = s->next(); s2; s2 = s2->next()) {
2016-03-02 13:20:19 +01:00
if (!s2->isChordRestType())
2016-01-04 14:48:58 +01:00
break;
}
2016-02-17 12:48:53 +01:00
qreal x1 = s1 ? s1->x() + s1->minRight() : 0;
qreal x2 = s2 ? s2->x() - s2->minLeft() : width();
2016-01-04 14:48:58 +01:00
if (isMMRest()) {
//
// center multi measure rest
//
qreal d = point(score()->styleS(StyleIdx::multiMeasureRestMargin));
qreal w = x2 - x1 - 2 * d;
rest->setMMWidth(w);
StaffLines* sl = _mstaves[track/VOICES]->lines;
2016-02-17 12:48:53 +01:00
qreal x = x1 - s->x() + d;
2016-01-04 14:48:58 +01:00
e->setPos(x, sl->staffHeight() * .5); // center vertically in measure
2016-02-04 11:27:47 +01:00
rest->layout();
s->createShape(track/VOICES);
2016-01-04 14:48:58 +01:00
}
else { // if (rest->isFullMeasureRest()) {
//
// center full measure rest
//
rest->rxpos() = (x2 - x1 - e->width()) * .5 + x1 - s->x() - e->bbox().x();
rest->adjustReadPos();
2016-02-17 12:48:53 +01:00
s->createShape(track/VOICES); // DEBUG
2016-01-04 14:48:58 +01:00
}
}
else if (t == Element::Type::REST)
e->rxpos() = 0;
2016-02-16 21:21:28 +01:00
else if (t == Element::Type::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())
c->tremolo()->layout();
}
2016-01-04 14:48:58 +01:00
else if (t == Element::Type::BAR_LINE) {
e->setPos(QPointF());
e->adjustReadPos();
}
2016-02-04 11:27:47 +01:00
else
2016-01-04 14:48:58 +01:00
e->adjustReadPos();
}
}
}
//---------------------------------------------------------
// removeSystemHeader
//---------------------------------------------------------
void Measure::removeSystemHeader()
{
for (Segment* seg = first(); seg; seg = seg->next()) {
Segment::Type st = seg->segmentType();
if (st & (Segment::Type::BeginBarLine | Segment::Type::StartRepeatBarLine))
score()->undoRemoveElement(seg);
else if (st == Segment::Type::ChordRest)
break;
else if (st & (Segment::Type::Clef | Segment::Type::KeySig)) {
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
Element* el = seg->element(staffIdx * VOICES);
// remove Clefs and Keysigs if generated
if (el && el->generated())
score()->undoRemoveElement(el);
}
}
}
}
//---------------------------------------------------------
// removeSystemTrailer
//---------------------------------------------------------
void Measure::removeSystemTrailer()
{
for (Segment* seg = last(); seg != first(); seg = seg->prev()) {
Segment::Type st = seg->segmentType();
if (st == Segment::Type::ChordRest)
break;
else if (st & (Segment::Type::TimeSigAnnounce | Segment::Type::KeySigAnnounce)) {
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
Element* el = seg->element(staffIdx * VOICES);
// courtesy time sigs and key sigs: remove if not in last measure
// (generated or not!)
if (el)
score()->undoRemoveElement(el);
}
}
}
}
2013-05-13 18:49:17 +02:00
}