MuseScore/libmscore/segment.cpp

1444 lines
46 KiB
C++
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2002-2011 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#include "mscore.h"
#include "segment.h"
#include "element.h"
#include "chord.h"
#include "note.h"
#include "score.h"
#include "beam.h"
#include "tuplet.h"
#include "text.h"
#include "measure.h"
#include "barline.h"
#include "part.h"
#include "repeat.h"
#include "staff.h"
#include "line.h"
#include "hairpin.h"
#include "ottava.h"
#include "sig.h"
2014-06-02 13:07:19 +02:00
#include "keysig.h"
2012-05-26 14:26:10 +02:00
#include "staffstate.h"
#include "instrchange.h"
#include "clef.h"
#include "timesig.h"
#include "system.h"
2014-04-09 16:09:21 +02:00
#include "xml.h"
2014-08-05 14:10:22 +02:00
#include "undo.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
//---------------------------------------------------------
// subTypeName
//---------------------------------------------------------
const char* Segment::subTypeName() const
{
2013-06-25 19:52:00 +02:00
return subTypeName(_segmentType);
2013-06-24 13:02:45 +02:00
}
const char* Segment::subTypeName(Type t)
2013-06-24 13:02:45 +02:00
{
switch(t) {
case Type::Invalid: return "Invalid";
2016-02-04 11:27:47 +01:00
case Type::BeginBarLine: return "BeginBarLine";
case Type::Clef: return "Clef";
case Type::KeySig: return "Key Signature";
case Type::Ambitus: return "Ambitus";
case Type::TimeSig: return "Time Signature";
case Type::StartRepeatBarLine: return "Begin Repeat";
case Type::BarLine: return "BarLine";
case Type::Breath: return "Breath";
2016-02-04 11:27:47 +01:00
case Type::ChordRest: return "ChordRest";
case Type::EndBarLine: return "EndBarLine";
case Type::KeySigAnnounce: return "Key Sig Precaution";
2016-02-04 11:27:47 +01:00
case Type::TimeSigAnnounce: return "Time Sig Precaution";
2012-05-26 14:26:10 +02:00
default:
2014-06-17 15:34:11 +02:00
return "??";
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// setElement
//---------------------------------------------------------
void Segment::setElement(int track, Element* el)
{
if (el) {
el->setParent(this);
_elist[track] = el;
2016-02-06 22:03:43 +01:00
_empty = false;
2012-05-26 14:26:10 +02:00
}
else {
_elist[track] = 0;
checkEmpty();
}
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void Segment::removeElement(int track)
{
Element* el = element(track);
if (el->isChordRest()) {
ChordRest* cr = (ChordRest*)el;
Beam* beam = cr->beam();
if (beam)
beam->remove(cr);
Tuplet* tuplet = cr->tuplet();
if (tuplet)
tuplet->remove(cr);
}
}
//---------------------------------------------------------
// Segment
//---------------------------------------------------------
Segment::Segment(Measure* m)
: Element(m->score())
{
setParent(m);
init();
2016-02-06 22:03:43 +01:00
_empty = true;
2012-05-26 14:26:10 +02:00
}
Segment::Segment(Measure* m, Type st, int t)
2012-05-26 14:26:10 +02:00
: Element(m->score())
{
setParent(m);
2013-06-25 19:52:00 +02:00
_segmentType = st;
2012-05-26 14:26:10 +02:00
setTick(t);
init();
2016-02-06 22:03:43 +01:00
_empty = true;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// Segment
//---------------------------------------------------------
Segment::Segment(const Segment& s)
: Element(s)
{
2016-02-06 22:03:43 +01:00
_next = 0;
_prev = 0;
_empty = s._empty; // cached value
2013-06-25 19:52:00 +02:00
_segmentType = s._segmentType;
_tick = s._tick;
_extraLeadingSpace = s._extraLeadingSpace;
2012-05-26 14:26:10 +02:00
2016-02-06 22:03:43 +01:00
for (Element* e : s._annotations)
add(e->clone());
2012-05-26 14:26:10 +02:00
_elist.reserve(s._elist.size());
2016-02-06 22:03:43 +01:00
for (Element* e : s._elist) {
2012-05-26 14:26:10 +02:00
Element* ne = 0;
if (e) {
ne = e->clone();
ne->setParent(this);
}
2016-02-06 22:03:43 +01:00
_elist.push_back(ne);
2012-05-26 14:26:10 +02:00
}
_dotPosX = s._dotPosX;
2016-01-04 14:48:58 +01:00
_shapes = s._shapes;
2012-05-26 14:26:10 +02:00
}
2016-02-06 22:03:43 +01:00
//---------------------------------------------------------
// setSegmentType
//---------------------------------------------------------
void Segment::setSegmentType(Type t)
2013-06-25 19:52:00 +02:00
{
Q_ASSERT(_segmentType != Type::Clef || t != Type::ChordRest);
2013-06-25 19:52:00 +02:00
_segmentType = t;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// setScore
//---------------------------------------------------------
void Segment::setScore(Score* score)
{
Element::setScore(score);
2016-01-04 14:48:58 +01:00
for (Element* e : _elist) {
2012-05-26 14:26:10 +02:00
if (e)
e->setScore(score);
}
2016-01-04 14:48:58 +01:00
for (Element* e : _annotations)
2012-05-26 14:26:10 +02:00
e->setScore(score);
}
Segment::~Segment()
{
2016-02-06 22:03:43 +01:00
for (Element* e : _elist) {
2012-05-26 14:26:10 +02:00
if (!e)
continue;
if (e->type() == Element::Type::TIMESIG)
2012-05-26 14:26:10 +02:00
e->staff()->removeTimeSig(static_cast<TimeSig*>(e));
delete e;
}
}
//---------------------------------------------------------
// init
//---------------------------------------------------------
void Segment::init()
{
int staves = score()->nstaves();
int tracks = staves * VOICES;
2016-02-06 22:03:43 +01:00
_elist.assign(tracks, 0);
_dotPosX.assign(staves, 0.0);
_shapes.assign(staves, Shape());
2012-05-26 14:26:10 +02:00
_prev = 0;
_next = 0;
}
//---------------------------------------------------------
// next1
2012-08-01 18:00:27 +02:00
/// return next \a Segment, dont stop searching at end
/// of \a Measure
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2012-08-02 16:07:08 +02:00
Segment* Segment::next1() const
2012-05-26 14:26:10 +02:00
{
if (next())
return next();
2012-08-01 18:00:27 +02:00
Measure* m = measure()->nextMeasure();
if (m == 0)
return 0;
return m->first();
2012-05-26 14:26:10 +02:00
}
2013-09-23 12:26:16 +02:00
//---------------------------------------------------------
// next1MM
//---------------------------------------------------------
Segment* Segment::next1MM() const
{
if (next())
return next();
Measure* m = measure()->nextMeasureMM();
if (m == 0)
return 0;
return m->first();
}
Segment* Segment::next1(Type types) const
2012-05-26 14:26:10 +02:00
{
for (Segment* s = next1(); s; s = s->next1()) {
if (s->segmentType() & types)
2012-05-26 14:26:10 +02:00
return s;
}
return 0;
}
Segment* Segment::next1MM(Type types) const
2013-09-27 18:43:25 +02:00
{
for (Segment* s = next1MM(); s; s = s->next1MM()) {
if (s->segmentType() & types)
return s;
}
return 0;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// next
// got to next segment which has subtype in types
//---------------------------------------------------------
Segment* Segment::next(Type types) const
2012-05-26 14:26:10 +02:00
{
for (Segment* s = next(); s; s = s->next()) {
if (s->segmentType() & types)
2012-05-26 14:26:10 +02:00
return s;
}
return 0;
}
//---------------------------------------------------------
// prev
// got to previous segment which has subtype in types
//---------------------------------------------------------
Segment* Segment::prev(Type types) const
2012-05-26 14:26:10 +02:00
{
for (Segment* s = prev(); s; s = s->prev()) {
if (s->segmentType() & types)
2012-05-26 14:26:10 +02:00
return s;
}
return 0;
}
//---------------------------------------------------------
// prev1
2012-08-01 18:00:27 +02:00
/// return previous \a Segment, dont stop searching at
/// \a Measure begin
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Segment* Segment::prev1() const
{
if (prev())
return prev();
Measure* m = measure()->prevMeasure();
if (m == 0)
return 0;
return m->last();
}
2013-09-27 18:43:25 +02:00
Segment* Segment::prev1MM() const
{
if (prev())
return prev();
Measure* m = measure()->prevMeasureMM();
if (m == 0)
return 0;
return m->last();
}
Segment* Segment::prev1(Type types) const
2012-05-26 14:26:10 +02:00
{
for (Segment* s = prev1(); s; s = s->prev1()) {
if (s->segmentType() & types)
2012-05-26 14:26:10 +02:00
return s;
}
return 0;
}
Segment* Segment::prev1MM(Type types) const
2013-09-27 18:43:25 +02:00
{
for (Segment* s = prev1MM(); s; s = s->prev1MM()) {
if (s->segmentType() & types)
return s;
}
return 0;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// nextCR
// get next ChordRest Segment
//---------------------------------------------------------
Segment* Segment::nextCR(int track, bool sameStaff) const
2012-05-26 14:26:10 +02:00
{
int strack = track;
int etrack = track + 1;
if (sameStaff && track != -1) {
strack = (track / VOICES) * VOICES;
etrack = strack + VOICES;
}
2012-05-26 14:26:10 +02:00
Segment* seg = next1();
for (; seg; seg = seg->next1()) {
if (seg->segmentType() == Type::ChordRest) {
if (track == -1)
return seg;
for (int t = strack; t < etrack; ++t) {
if (seg->element(t))
return seg;
}
2012-05-26 14:26:10 +02:00
}
}
return 0;
}
//---------------------------------------------------------
// nextChordRest
// get the next ChordRest, start at this segment
//---------------------------------------------------------
ChordRest* Segment::nextChordRest(int track, bool backwards) const
{
for (const Segment* seg = this; seg; seg = backwards ? seg->prev1() : seg->next1()) {
Element* el = seg->element(track);
if (el && el->isChordRest())
return static_cast<ChordRest*>(el);
}
return 0;
}
//---------------------------------------------------------
// insertStaff
//---------------------------------------------------------
void Segment::insertStaff(int staff)
{
int track = staff * VOICES;
for (int voice = 0; voice < VOICES; ++voice)
2016-02-06 22:03:43 +01:00
_elist.insert(_elist.begin() + track, 0);
_dotPosX.insert(_dotPosX.begin()+staff, 0.0);
_shapes.insert(_shapes.begin()+staff, Shape());
2013-08-09 11:22:02 +02:00
2016-02-06 22:03:43 +01:00
for (Element* e : _annotations) {
2013-08-09 11:22:02 +02:00
int staffIdx = e->staffIdx();
2013-08-09 12:03:15 +02:00
if (staffIdx >= staff && !e->systemFlag())
2013-08-09 11:22:02 +02:00
e->setTrack(e->track() + VOICES);
}
2012-05-26 14:26:10 +02:00
fixStaffIdx();
}
//---------------------------------------------------------
// removeStaff
//---------------------------------------------------------
void Segment::removeStaff(int staff)
{
int track = staff * VOICES;
_elist.erase(_elist.begin() + track, _elist.begin() + track + VOICES);
2016-02-06 22:03:43 +01:00
_dotPosX.erase(_dotPosX.begin() + staff);
_shapes.erase(_shapes.begin()+staff);
2012-05-26 14:26:10 +02:00
2016-02-06 22:03:43 +01:00
for (Element* e : _annotations) {
2012-05-26 14:26:10 +02:00
int staffIdx = e->staffIdx();
2013-08-09 12:03:15 +02:00
if (staffIdx > staff && !e->systemFlag())
2012-05-26 14:26:10 +02:00
e->setTrack(e->track() - VOICES);
}
fixStaffIdx();
}
2014-06-02 13:07:19 +02:00
//---------------------------------------------------------
// checkElement
//---------------------------------------------------------
void Segment::checkElement(Element* el, int track)
{
if (_elist[track]) {
qDebug("Segment::add(%s) there is already a %s at %s(%d) track %d. score %p",
el->name(), _elist[track]->name(),
2014-08-07 10:18:50 +02:00
qPrintable(score()->sigmap()->pos(tick())), tick(), track, score());
2016-03-02 13:20:19 +01:00
// abort();
2014-06-02 13:07:19 +02:00
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// add
//---------------------------------------------------------
void Segment::add(Element* el)
{
// qDebug("%p segment %s add(%d, %d, %s)", this, subTypeName(), tick(), el->track(), el->name());
2016-03-31 14:31:39 +02:00
2012-05-26 14:26:10 +02:00
el->setParent(this);
int track = el->track();
2013-06-25 19:52:00 +02:00
Q_ASSERT(track != -1);
2014-08-25 19:30:56 +02:00
Q_ASSERT(el->score() == score());
2016-02-08 15:10:03 +01:00
Q_ASSERT(score()->nstaves() * VOICES == int(_elist.size()));
2012-05-26 14:26:10 +02:00
2013-06-25 19:52:00 +02:00
switch (el->type()) {
case Element::Type::REPEAT_MEASURE:
2012-05-26 14:26:10 +02:00
_elist[track] = el;
2016-02-06 22:03:43 +01:00
_empty = false;
2012-05-26 14:26:10 +02:00
break;
case Element::Type::DYNAMIC:
case Element::Type::HARMONY:
case Element::Type::SYMBOL:
case Element::Type::FRET_DIAGRAM:
case Element::Type::TEMPO_TEXT:
case Element::Type::STAFF_TEXT:
case Element::Type::REHEARSAL_MARK:
case Element::Type::MARKER:
case Element::Type::IMAGE:
case Element::Type::TEXT:
2014-07-30 12:59:48 +02:00
case Element::Type::TREMOLOBAR:
case Element::Type::TAB_DURATION_SYMBOL:
case Element::Type::FIGURED_BASS:
2013-05-06 14:20:31 +02:00
_annotations.push_back(el);
2012-05-26 14:26:10 +02:00
break;
2016-02-06 11:41:16 +01:00
case Element::Type::STAFF_STATE:
if (static_cast<StaffState*>(el)->staffStateType() == StaffStateType::INSTRUMENT) {
2012-05-26 14:26:10 +02:00
StaffState* ss = static_cast<StaffState*>(el);
Part* part = el->part();
2012-05-26 14:26:10 +02:00
part->setInstrument(ss->instrument(), tick());
}
2013-05-06 14:20:31 +02:00
_annotations.push_back(el);
2012-05-26 14:26:10 +02:00
break;
case Element::Type::INSTRUMENT_CHANGE: {
2012-05-26 14:26:10 +02:00
InstrumentChange* is = static_cast<InstrumentChange*>(el);
Part* part = is->part();
2012-05-26 14:26:10 +02:00
part->setInstrument(is->instrument(), tick());
2013-05-06 14:20:31 +02:00
_annotations.push_back(el);
2012-05-26 14:26:10 +02:00
break;
}
case Element::Type::CLEF:
Q_ASSERT(_segmentType == Type::Clef);
2014-06-02 13:07:19 +02:00
checkElement(el, track);
2012-05-26 14:26:10 +02:00
_elist[track] = el;
2014-08-05 14:10:22 +02:00
if (!el->generated()) {
2014-07-25 17:13:27 +02:00
el->staff()->setClef(static_cast<Clef*>(el));
2014-08-05 14:10:22 +02:00
updateNoteLines(this, el->track());
}
2016-02-06 22:03:43 +01:00
_empty = false;
2012-05-26 14:26:10 +02:00
break;
case Element::Type::TIMESIG:
Q_ASSERT(segmentType() == Type::TimeSig || segmentType() == Type::TimeSigAnnounce);
2014-06-02 13:07:19 +02:00
checkElement(el, track);
2012-05-26 14:26:10 +02:00
_elist[track] = el;
el->staff()->addTimeSig(static_cast<TimeSig*>(el));
2016-02-06 22:03:43 +01:00
_empty = false;
2012-05-26 14:26:10 +02:00
break;
case Element::Type::KEYSIG:
Q_ASSERT(_segmentType == Type::KeySig || _segmentType == Type::KeySigAnnounce);
2014-06-02 13:07:19 +02:00
checkElement(el, track);
_elist[track] = el;
2014-06-04 10:20:14 +02:00
if (!el->generated())
el->staff()->setKey(tick(), static_cast<KeySig*>(el)->keySigEvent());
2016-02-06 22:03:43 +01:00
_empty = false;
2014-06-02 13:07:19 +02:00
break;
case Element::Type::CHORD:
case Element::Type::REST:
Q_ASSERT(_segmentType == Type::ChordRest);
if (track % VOICES) {
bool v;
if (el->type() == Element::Type::CHORD) {
v = false;
// consider chord visible if any note is visible
Chord* c = static_cast<Chord*>(el);
for (Note* n : c->notes()) {
if (n->visible()) {
v = true;
break;
}
}
}
else
v = el->visible();
2016-07-31 15:23:11 +02:00
if (v && int(measure()->mstaves().size() * VOICES) > track)
measure()->mstaff(track / VOICES)->hasVoices = true;
}
2012-05-26 14:26:10 +02:00
// fall through
case Element::Type::BAR_LINE:
case Element::Type::BREATH:
2014-08-25 19:30:56 +02:00
if (track < score()->nstaves() * VOICES) {
checkElement(el, track);
_elist[track] = el;
}
2016-02-06 22:03:43 +01:00
_empty = false;
2012-05-26 14:26:10 +02:00
break;
2014-06-02 13:07:19 +02:00
case Element::Type::AMBITUS:
Q_ASSERT(_segmentType == Type::Ambitus);
2014-06-02 13:07:19 +02:00
checkElement(el, track);
_elist[track] = el;
2016-02-06 22:03:43 +01:00
_empty = false;
break;
2012-05-26 14:26:10 +02:00
default:
qFatal("Segment::add() unknown %s", el->name());
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void Segment::remove(Element* el)
{
2012-09-11 21:10:44 +02:00
// qDebug("%p Segment::remove %s %p", this, el->name(), el);
2012-05-26 14:26:10 +02:00
int track = el->track();
switch(el->type()) {
case Element::Type::CHORD:
case Element::Type::REST:
2012-05-26 14:26:10 +02:00
{
_elist[track] = 0;
int staffIdx = el->staffIdx();
measure()->checkMultiVoices(staffIdx);
// spanners with this cr as start or end element will need relayout
SpannerMap& smap = score()->spannerMap();
auto spanners = smap.findOverlapping(tick(), tick());
for (auto interval : spanners) {
Spanner* s = interval.value;
if (s->startElement() == el)
s->setStartElement(nullptr);
if (s->endElement() == el)
s->setEndElement(nullptr);
}
2012-05-26 14:26:10 +02:00
}
break;
case Element::Type::REPEAT_MEASURE:
2012-05-26 14:26:10 +02:00
_elist[track] = 0;
break;
case Element::Type::DYNAMIC:
case Element::Type::FIGURED_BASS:
case Element::Type::FRET_DIAGRAM:
case Element::Type::HARMONY:
case Element::Type::IMAGE:
case Element::Type::MARKER:
case Element::Type::REHEARSAL_MARK:
case Element::Type::STAFF_TEXT:
case Element::Type::SYMBOL:
case Element::Type::TAB_DURATION_SYMBOL:
case Element::Type::TEMPO_TEXT:
case Element::Type::TEXT:
case Element::Type::TREMOLOBAR:
2013-05-06 14:20:31 +02:00
removeAnnotation(el);
2012-05-26 14:26:10 +02:00
break;
case Element::Type::STAFF_STATE:
if (static_cast<StaffState*>(el)->staffStateType() == StaffStateType::INSTRUMENT) {
Part* part = el->part();
2012-05-26 14:26:10 +02:00
part->removeInstrument(tick());
}
2013-05-06 14:20:31 +02:00
removeAnnotation(el);
2012-05-26 14:26:10 +02:00
break;
case Element::Type::INSTRUMENT_CHANGE:
2012-05-26 14:26:10 +02:00
{
InstrumentChange* is = static_cast<InstrumentChange*>(el);
Part* part = is->part();
2012-05-26 14:26:10 +02:00
part->removeInstrument(tick());
}
2013-05-06 14:20:31 +02:00
removeAnnotation(el);
2012-05-26 14:26:10 +02:00
break;
case Element::Type::TIMESIG:
2012-05-26 14:26:10 +02:00
_elist[track] = 0;
el->staff()->removeTimeSig(static_cast<TimeSig*>(el));
break;
case Element::Type::KEYSIG:
2014-06-04 10:20:14 +02:00
Q_ASSERT(_elist[track] == el);
_elist[track] = 0;
if (!el->generated())
el->staff()->removeKey(tick());
break;
case Element::Type::CLEF:
2016-03-18 09:29:16 +01:00
el->staff()->removeClef(static_cast<Clef*>(el));
// updateNoteLines(this, el->track());
2014-08-05 14:10:22 +02:00
// fall through
2014-07-25 17:13:27 +02:00
case Element::Type::BAR_LINE:
case Element::Type::AMBITUS:
2012-05-26 14:26:10 +02:00
_elist[track] = 0;
break;
case Element::Type::BREATH:
_elist[track] = 0;
score()->setPause(tick(), 0);
break;
2012-05-26 14:26:10 +02:00
default:
qFatal("Segment::remove() unknown %s", el->name());
2012-05-26 14:26:10 +02:00
}
2016-03-08 09:46:33 +01:00
score()->setLayout(tick());
2012-05-26 14:26:10 +02:00
checkEmpty();
}
//---------------------------------------------------------
// segmentType
// returns segment type suitable for storage of Element
//---------------------------------------------------------
Segment::Type Segment::segmentType(Element::Type type)
2012-05-26 14:26:10 +02:00
{
switch (type) {
case Element::Type::CHORD:
case Element::Type::REST:
case Element::Type::REPEAT_MEASURE:
case Element::Type::JUMP:
case Element::Type::MARKER:
return Type::ChordRest;
case Element::Type::CLEF:
return Type::Clef;
case Element::Type::KEYSIG:
return Type::KeySig;
case Element::Type::TIMESIG:
return Type::TimeSig;
case Element::Type::BAR_LINE:
return Type::StartRepeatBarLine;
case Element::Type::BREATH:
return Type::Breath;
2012-05-26 14:26:10 +02:00
default:
2012-09-11 21:10:44 +02:00
qDebug("Segment:segmentType(): bad type: <%s>", Element::name(type));
return Type::Invalid;
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// sortStaves
//---------------------------------------------------------
void Segment::sortStaves(QList<int>& dst)
{
2016-02-06 22:03:43 +01:00
std::vector<Element*> dl;
dl.reserve(dst.size());
2012-05-26 14:26:10 +02:00
for (int i = 0; i < dst.size(); ++i) {
int startTrack = dst[i] * VOICES;
int endTrack = startTrack + VOICES;
for (int k = startTrack; k < endTrack; ++k)
2016-02-06 22:03:43 +01:00
dl.push_back(_elist[k]);
2012-05-26 14:26:10 +02:00
}
2016-02-06 22:03:43 +01:00
std::swap(_elist, dl);
2013-08-09 12:03:15 +02:00
QMap<int, int> map;
for (int k = 0; k < dst.size(); ++k) {
map.insert(dst[k], k);
}
2016-02-06 22:03:43 +01:00
for (Element* e : _annotations) {
if (!e->systemFlag())
2013-08-09 12:03:15 +02:00
e->setTrack(map[e->staffIdx()] * VOICES + e->voice());
}
2012-05-26 14:26:10 +02:00
fixStaffIdx();
}
//---------------------------------------------------------
// fixStaffIdx
//---------------------------------------------------------
void Segment::fixStaffIdx()
{
int track = 0;
2016-01-04 14:48:58 +01:00
for (Element* e : _elist) {
2012-05-26 14:26:10 +02:00
if (e)
e->setTrack(track);
++track;
}
}
//---------------------------------------------------------
// checkEmpty
//---------------------------------------------------------
void Segment::checkEmpty() const
{
2014-02-24 13:53:43 +01:00
if (!_annotations.empty()) {
2016-02-06 22:03:43 +01:00
_empty = false;
2014-02-24 13:53:43 +01:00
return;
}
2016-02-06 22:03:43 +01:00
_empty = true;
2016-01-04 14:48:58 +01:00
for (const Element* e : _elist) {
2012-05-26 14:26:10 +02:00
if (e) {
2016-02-06 22:03:43 +01:00
_empty = false;
2012-05-26 14:26:10 +02:00
break;
}
}
}
//---------------------------------------------------------
// tick
//---------------------------------------------------------
2016-05-02 13:41:41 +02:00
#if 0
2012-05-26 14:26:10 +02:00
int Segment::tick() const
{
return _tick + measure()->tick();
}
2016-05-02 13:41:41 +02:00
#endif
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// setTick
//---------------------------------------------------------
void Segment::setTick(int t)
{
_tick = t - measure()->tick();
}
//---------------------------------------------------------
// swapElements
//---------------------------------------------------------
void Segment::swapElements(int i1, int i2)
{
2016-02-06 22:03:43 +01:00
std::iter_swap(_elist.begin() + i1, _elist.begin() + i2);
2012-05-26 14:26:10 +02:00
if (_elist[i1])
_elist[i1]->setTrack(i1);
if (_elist[i2])
_elist[i2]->setTrack(i2);
2016-08-24 14:49:34 +02:00
score()->setLayout(tick());
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void Segment::write(Xml& xml) const
{
if (_written)
return;
_written = true;
2016-01-04 14:48:58 +01:00
if (_extraLeadingSpace.isZero())
2012-05-26 14:26:10 +02:00
return;
xml.stag(name());
xml.tag("leadingSpace", _extraLeadingSpace.val());
xml.etag();
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
void Segment::read(XmlReader& e)
2012-05-26 14:26:10 +02:00
{
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
2012-05-26 14:26:10 +02:00
2013-06-25 19:52:00 +02:00
if (tag == "subtype")
e.skipCurrentElement();
2012-05-26 14:26:10 +02:00
else if (tag == "leadingSpace")
2013-01-11 18:10:18 +01:00
_extraLeadingSpace = Spatium(e.readDouble());
2016-01-04 14:48:58 +01:00
else if (tag == "trailingSpace") // obsolete
e.readDouble();
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
}
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
QVariant Segment::getProperty(P_ID propertyId) const
{
2016-08-02 17:00:49 +02:00
switch (propertyId) {
case P_ID::TICK:
return _tick;
2016-03-05 15:31:26 +01:00
case P_ID::LEADING_SPACE:
return extraLeadingSpace();
2012-05-26 14:26:10 +02:00
default:
return Element::getProperty(propertyId);
}
}
2013-03-14 13:30:25 +01:00
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
QVariant Segment::propertyDefault(P_ID propertyId) const
{
2016-08-07 11:26:15 +02:00
switch (propertyId) {
case P_ID::LEADING_SPACE:
return Spatium(0.0);
2013-03-14 13:30:25 +01:00
default:
return Element::getProperty(propertyId);
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool Segment::setProperty(P_ID propertyId, const QVariant& v)
{
2016-01-04 14:48:58 +01:00
switch (propertyId) {
2016-08-02 17:00:49 +02:00
case P_ID::TICK:
_tick = v.toInt();
break;
2016-03-05 15:31:26 +01:00
case P_ID::LEADING_SPACE:
setExtraLeadingSpace(v.value<Spatium>());
break;
2012-05-26 14:26:10 +02:00
default:
return Element::setProperty(propertyId, v);
}
2016-08-02 17:00:49 +02:00
score()->setLayout(tick());
2012-05-26 14:26:10 +02:00
return true;
}
//---------------------------------------------------------
// splitsTuplet
//---------------------------------------------------------
bool Segment::splitsTuplet() const
{
if (segmentType() != Type::ChordRest)
2012-05-26 14:26:10 +02:00
return false;
int tracks = score()->nstaves() * VOICES;
for (int track = 0; track < tracks; ++track) {
ChordRest* cr = static_cast<ChordRest*>(element(track));
if (cr == 0)
continue;
if (cr->tuplet() && cr->tuplet()->elements().front() != cr)
return true;
}
return false;
}
2012-08-09 12:12:43 +02:00
//---------------------------------------------------------
// operator<
/// return true if segment is before s in list
//---------------------------------------------------------
bool Segment::operator<(const Segment& s) const
{
if (tick() < s.tick())
return true;
if (tick() > s.tick())
return false;
for (Segment* ns = next1(); ns && (ns->tick() == s.tick()); ns = ns->next1()) {
if (ns == &s)
return true;
}
return false;
}
//---------------------------------------------------------
// operator>
/// return true if segment is after s in list
//---------------------------------------------------------
bool Segment::operator>(const Segment& s) const
{
if (tick() > s.tick())
return true;
if (tick() < s.tick())
return false;
for (Segment* ns = prev1(); ns && (ns->tick() == s.tick()); ns = ns->prev1()) {
if (ns == &s)
return true;
}
return false;
}
//---------------------------------------------------------
2013-03-16 12:57:43 +01:00
// findAnnotationOrElement
/// return true if an annotation of type type or and element is found in the track range
//---------------------------------------------------------
bool Segment::findAnnotationOrElement(Element::Type type, int minTrack, int maxTrack)
2013-03-16 12:57:43 +01:00
{
2013-05-06 14:20:31 +02:00
for (const Element* e : _annotations)
2013-03-16 12:57:43 +01:00
if (e->type() == type && e->track() >= minTrack && e->track() <= maxTrack)
return true;
for (int curTrack = minTrack; curTrack <= maxTrack; curTrack++)
if (element(curTrack))
return true;
return false;
}
2012-08-09 12:12:43 +02:00
2013-05-06 14:20:31 +02:00
//---------------------------------------------------------
// removeAnnotation
//---------------------------------------------------------
void Segment::removeAnnotation(Element* e)
{
for (auto i = _annotations.begin(); i != _annotations.end(); ++i) {
if (*i == e) {
2013-05-06 14:20:31 +02:00
_annotations.erase(i);
break;
}
2013-05-06 14:20:31 +02:00
}
}
2013-10-30 14:21:08 +01:00
//---------------------------------------------------------
// clearAnnotations
//---------------------------------------------------------
void Segment::clearAnnotations()
{
_annotations.clear();
}
Fixes the following Q_INVOKABLE methods returning a QObject* by turning them into a property: - Measure: -- firstSegment -- lastSegment - MeasureBase: -- nextMeasure -- nextMeasureMM (new) -- prevMeasure -- prevMeasureMM (new) - Score: -- firstMeasure -- firstMeasureMM (new) -- (for firstSegment(), see special cases below) -- lastMeasure -- lastMeasureMM (new) -- lastSegment - Segment: -- next (renamed from `next1`) -- nextInMeasure (renamed from `next`) -- prev (renamed from `prev1`) -- prevInMeasure (renamed from prev) Special cases: - Cursor: The prototype of the `Q_INVOKABLE Ms::Note* Cursor::addNote(int pitch)` was wrong: corrected in `Q_INVOKABLE void Cursor::addNote(int pitch)`. - QmlPlugin: `Q_INVOKABLE Score* QmlPlugin::readScore()` and `Q_INVOKABLE Score* QmlPlugin::newScore()` has been kept, as they are intended to be called from QML; code has been added to ensure the C++ ownership of the returned object. - Score: `Q_INVOKABLE Segment* Score::firstSegment(Segment::Type segType)` is kept (as it needs a parameters), but code is added to ensure C++ ownership of the returned Segment*. - Segment: `Ms::Element* Segment::element(int track)` has been made NOT Q_INVOKABLE; a variant `Q_INVOKABLE Ms::Element* elementAt(int track)` has been added specifically for QML with code to ensure the C++ ownership of the returned Element* (this was the cause for the crash of the Walk plug-in). - FiguredBass: `Q_INVOKABLE Ms::FiguredBassItem* FiguredBass::addItem()` has been removed; plugin interface for FiguredBass needs to be redesigned anyway. The few occurrences in the supplied plug-ins of the methods whose names did change have been updated.
2014-07-06 01:56:30 +02:00
//---------------------------------------------------------
// elementAt
// A variant of the element(int) function,
// specifically intended to be called from QML plugins
//---------------------------------------------------------
2016-02-06 22:03:43 +01:00
Ms::Element* Segment::elementAt(int track) const
{
2016-02-08 15:10:03 +01:00
Element* e = track < int(_elist.size()) ? _elist[track] : 0;
2016-02-06 22:03:43 +01:00
Fixes the following Q_INVOKABLE methods returning a QObject* by turning them into a property: - Measure: -- firstSegment -- lastSegment - MeasureBase: -- nextMeasure -- nextMeasureMM (new) -- prevMeasure -- prevMeasureMM (new) - Score: -- firstMeasure -- firstMeasureMM (new) -- (for firstSegment(), see special cases below) -- lastMeasure -- lastMeasureMM (new) -- lastSegment - Segment: -- next (renamed from `next1`) -- nextInMeasure (renamed from `next`) -- prev (renamed from `prev1`) -- prevInMeasure (renamed from prev) Special cases: - Cursor: The prototype of the `Q_INVOKABLE Ms::Note* Cursor::addNote(int pitch)` was wrong: corrected in `Q_INVOKABLE void Cursor::addNote(int pitch)`. - QmlPlugin: `Q_INVOKABLE Score* QmlPlugin::readScore()` and `Q_INVOKABLE Score* QmlPlugin::newScore()` has been kept, as they are intended to be called from QML; code has been added to ensure the C++ ownership of the returned object. - Score: `Q_INVOKABLE Segment* Score::firstSegment(Segment::Type segType)` is kept (as it needs a parameters), but code is added to ensure C++ ownership of the returned Segment*. - Segment: `Ms::Element* Segment::element(int track)` has been made NOT Q_INVOKABLE; a variant `Q_INVOKABLE Ms::Element* elementAt(int track)` has been added specifically for QML with code to ensure the C++ ownership of the returned Element* (this was the cause for the crash of the Walk plug-in). - FiguredBass: `Q_INVOKABLE Ms::FiguredBassItem* FiguredBass::addItem()` has been removed; plugin interface for FiguredBass needs to be redesigned anyway. The few occurrences in the supplied plug-ins of the methods whose names did change have been updated.
2014-07-06 01:56:30 +02:00
#ifdef SCRIPT_INTERFACE
// if called from QML/JS, tell QML engine not to garbage collect this object
if (e)
QQmlEngine::setObjectOwnership(e, QQmlEngine::CppOwnership);
#endif
return e;
}
2013-05-13 18:49:17 +02:00
//---------------------------------------------------------
// scanElements
//---------------------------------------------------------
void Segment::scanElements(void* data, void (*func)(void*, Element*), bool all)
{
// bar line visibility depends on spanned staves,
// not simply on visibility of first staff
2016-02-15 12:23:28 +01:00
if (segmentType() & (Segment::Type::BarLine | Segment::Type::EndBarLine
| Segment::Type::StartRepeatBarLine | Segment::Type::BeginBarLine)) {
2016-03-10 10:41:31 +01:00
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
Element* e = element(staffIdx*VOICES);
if (e == 0) // if no element, skip
continue;
// if staff not visible
2016-03-10 10:41:31 +01:00
if (!all && !(/*measure()->visible(staffIdx) && */score()->staff(staffIdx)->show())) {
// if bar line spans just this staff...
if (static_cast<BarLine*>(e)->span() <= 1
// ...or span another staff but without entering INTO it...
|| (static_cast<BarLine*>(e)->span() < 2 &&
static_cast<BarLine*>(e)->spanTo() < 1) )
continue; // ...skip
}
e->scanElements(data, func, all);
}
}
else
2016-03-10 10:41:31 +01:00
for (int track = 0; track < score()->nstaves() * VOICES; ++track) {
int staffIdx = track/VOICES;
2016-03-10 10:41:31 +01:00
if (!all && !(measure()->visible(staffIdx) && score()->staff(staffIdx)->show())) {
track += VOICES - 1;
continue;
}
Element* e = element(track);
if (e == 0)
continue;
e->scanElements(data, func, all);
}
2016-02-06 22:03:43 +01:00
for (Element* e : annotations()) {
if (all || e->systemFlag() || measure()->visible(e->staffIdx()))
e->scanElements(data, func, all);
}
}
//---------------------------------------------------------
// firstElement
// This function returns the first main element from a
// segment, or a barline if it spanns in the staff
//---------------------------------------------------------
Element* Segment::firstElement(int staff)
{
2016-01-04 14:48:58 +01:00
if (segmentType() == Segment::Type::ChordRest) {
for (int v = staff * VOICES; v/VOICES == staff; v++) {
2016-01-04 14:48:58 +01:00
Element* el = element(v);
if (!el) { //there is no chord or rest on this voice
continue;
}
if (el->type() == Element::Type::CHORD) {
return static_cast<Chord*>(el)->notes().back();
}
else {
return el;
}
}
}
else {
2016-01-04 14:48:58 +01:00
return getElement(staff);
}
return 0;
}
//---------------------------------------------------------
// lastElement
// This function returns the last main element from a
// segment, or a barline if it spanns in the staff
//---------------------------------------------------------
Element* Segment::lastElement(int staff)
{
2016-01-04 14:48:58 +01:00
if (segmentType() == Segment::Type::ChordRest) {
for (int voice = staff * VOICES + (VOICES - 1); voice/VOICES == staff; voice--) {
2016-01-04 14:48:58 +01:00
Element* el = element(voice);
if (!el) { //there is no chord or rest on this voice
continue;
}
if (el->type() == Element::Type::CHORD) {
return static_cast<Chord*>(el)->notes().front();
}
else {
return el;
}
}
}
else {
2016-01-04 14:48:58 +01:00
return getElement(staff);
}
return 0;
}
//---------------------------------------------------------
// getElement
// protected because it is used by the firstElement and
// lastElement functions when segment types that have
// just one elemnt to avoid duplicated code
//
// Use firstElement, or lastElement instead of this
//---------------------------------------------------------
Element* Segment::getElement(int staff)
{
2016-02-04 11:27:47 +01:00
if (segmentType() == Segment::Type::ChordRest)
return firstElement(staff);
2016-02-04 11:27:47 +01:00
else if (segmentType() & (Type::EndBarLine | Type::BarLine | Type::StartRepeatBarLine)) {
for (int i = staff; i >= 0; i--) {
2016-02-04 11:27:47 +01:00
if (!element(i * VOICES))
continue;
2016-01-04 14:48:58 +01:00
BarLine* b = static_cast<BarLine*>(element(i*VOICES));
2016-02-04 11:27:47 +01:00
if (i + b->span() - 1 >= staff)
2016-01-04 14:48:58 +01:00
return element(i*VOICES);
}
}
2016-02-04 11:27:47 +01:00
else
return element(staff * VOICES);
return 0;
}
//--------------------------------------------------------
// firstInNextSegments
// Searches for the next segment that has elements on the
// active staff and returns its first element
//
// Uses firstElement so it also returns a barline if it
// spans into the active staff
//--------------------------------------------------------
Element* Segment::firstInNextSegments(int activeStaff)
{
Element* re = 0;
Segment* seg = this;
while (!re) {
seg = seg->next1MM(Segment::Type::All);
if (!seg) //end of staff, or score
break;
re = seg->firstElement(activeStaff);
}
if (re)
return re;
if (!seg) { //end of staff
seg = score()->firstSegment();
return seg->element( (activeStaff + 1) * VOICES );
}
return 0;
}
//--------------------------------------------------------
// firstInNextSegments
// Searches for the previous segment that has elements on
// the active staff and returns its last element
//
// Uses lastElement so it also returns a barline if it
// spans into the active staff
//--------------------------------------------------------
Element* Segment::lastInPrevSegments(int activeStaff)
{
Element* re = 0;
Segment* seg = this;
while (!re) {
seg = seg->prev1MM(Segment::Type::All);
if (!seg) //end of staff, or score
break;
re = seg->lastElement(activeStaff);
}
if (re)
return re;
if (!seg) { //end of staff
if (activeStaff -1 < 0) //end of score
return 0;
re = 0;
seg = score()->lastSegment();
while (true) {
if (seg->segmentType() == Segment::Type::EndBarLine)
score()->inputState().setTrack( (activeStaff -1) * VOICES ); //correction
if ((re = seg->lastElement(activeStaff -1)) != 0)
return re;
seg = seg->prev1(Segment::Type::All);
}
}
return 0;
}
//---------------------------------------------------------
// accessibleExtraInfo
//---------------------------------------------------------
2016-02-04 17:06:32 +01:00
QString Segment::accessibleExtraInfo() const
{
QString rez = "";
2016-01-04 14:48:58 +01:00
if (!annotations().empty()) {
QString temp = "";
2016-02-06 22:03:43 +01:00
for (const Element* a : annotations()) {
if (!score()->selectionFilter().canSelect(a)) continue;
switch(a->type()) {
case Element::Type::DYNAMIC:
//they are added in the chordrest, because they are for only one staff
break;
default:
temp = temp + " " + a->accessibleInfo();
}
}
if(!temp.isEmpty())
rez = rez + tr("Annotations:") + temp;
}
QString startSpanners = "";
QString endSpanners = "";
auto spanners = score()->spannerMap().findOverlapping(this->tick(), this->tick());
for (auto interval : spanners) {
Spanner* s = interval.value;
if (!score()->selectionFilter().canSelect(s)) continue;
2016-01-04 14:48:58 +01:00
if (segmentType() == Segment::Type::EndBarLine ||
segmentType() == Segment::Type::BarLine ||
segmentType() == Segment::Type::StartRepeatBarLine) {
if (s->type() != Element::Type::VOLTA)
continue;
}
else {
if (s->type() == Element::Type::VOLTA ||
s->type() == Element::Type::TIE ) //ties are added in Note
continue;
}
2016-01-04 14:48:58 +01:00
if (s->tick() == tick())
startSpanners += tr("Start of ") + s->accessibleInfo();
2016-02-04 17:06:32 +01:00
const Segment* seg = 0;
switch (s->type()) {
case Element::Type::VOLTA:
case Element::Type::SLUR:
seg = this;
break;
default:
2016-01-04 14:48:58 +01:00
seg = next1MM(Segment::Type::ChordRest);
break;
}
if (seg && s->tick2() == seg->tick())
endSpanners += tr("End of ") + s->accessibleInfo();
}
return rez + " " + startSpanners + " " + endSpanners;
}
2016-01-04 14:48:58 +01:00
//---------------------------------------------------------
// createShapes
//---------------------------------------------------------
void Segment::createShapes()
{
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx)
createShape(staffIdx);
}
//---------------------------------------------------------
// createShape
//---------------------------------------------------------
void Segment::createShape(int staffIdx)
{
Shape& s = _shapes[staffIdx];
s.clear();
2016-02-04 11:27:47 +01:00
if (segmentType() & (Type::BarLine | Type::EndBarLine | Type::StartRepeatBarLine | Type::BeginBarLine)) {
BarLine* bl = static_cast<BarLine*>(element(0));
if (bl) {
qreal w = BarLine::layoutWidth(score(), bl->barLineType(), 1.0);
s.add(QRectF(bl->x(), 0.0, w, spatium() * 4.0));
}
return;
}
2016-03-18 14:35:15 +01:00
#if 0
2016-01-04 14:48:58 +01:00
for (int voice = 0; voice < VOICES; ++voice) {
Element* e = element(staffIdx * VOICES + voice);
2016-03-18 14:35:15 +01:00
if (e && e->visible()) {
if (e->isChordRest()) {
ChordRest* cr = toChordRest(e);
int si = cr->vStaffIdx();
_shapes[si].add(e->shape());
}
else
s.add(e->shape());
}
}
#endif
for (Element* e : _elist) {
2016-03-19 11:41:38 +01:00
if (e && e->vStaffIdx() == staffIdx && e->visible())
2016-01-04 14:48:58 +01:00
s.add(e->shape());
}
2016-02-06 11:41:16 +01:00
for (Element* e : _annotations) {
// probably only allow for lyrics and chordnames
2016-06-01 13:24:32 +02:00
if (e->staffIdx() == staffIdx
&& e->visible()
&& !e->isRehearsalMark()
&& !e->isTempoText()
2016-06-14 16:00:16 +02:00
&& !e->isDynamic()
&& !e->isSymbol()
&& !e->isFSymbol()
2016-06-01 13:24:32 +02:00
&& !e->isStaffText())
2016-02-06 11:41:16 +01:00
s.add(e->shape());
}
2016-01-04 14:48:58 +01:00
}
//---------------------------------------------------------
// minRight
// calculate minimum distance needed to the right
//---------------------------------------------------------
qreal Segment::minRight() const
{
qreal distance = 0.0;
for (const Shape& sh : shapes())
distance = qMax(distance, sh.right());
return distance;
}
//---------------------------------------------------------
// minLeft
// Calculate minimum distance needed to the left shape
// sl. Sl is the same for all staves.
2016-01-04 14:48:58 +01:00
//---------------------------------------------------------
qreal Segment::minLeft(const Shape& sl) const
{
qreal distance = 0.0;
2016-05-02 13:41:41 +02:00
for (const Shape& sh : shapes()) {
qreal d = sl.minHorizontalDistance(sh);
if (d > distance)
distance = d;
}
return distance;
}
2016-01-04 14:48:58 +01:00
qreal Segment::minLeft() const
{
qreal distance = 0.0;
2016-05-02 13:41:41 +02:00
for (const Shape& sh : shapes()) {
qreal l = sh.left();
if (l > distance)
distance = l;
}
return distance;
2016-01-04 14:48:58 +01:00
}
2016-02-04 11:27:47 +01:00
//---------------------------------------------------------
// minHorizontalDistance
//---------------------------------------------------------
qreal Segment::minHorizontalDistance(Segment* ns, bool systemHeaderGap) const
2016-02-04 11:27:47 +01:00
{
Segment::Type st = segmentType();
Segment::Type nst = ns ? ns->segmentType() : Segment::Type::Invalid;
2016-04-01 14:57:24 +02:00
2016-02-04 11:27:47 +01:00
qreal w = 0.0;
2016-02-06 22:03:43 +01:00
for (unsigned staffIdx = 0; staffIdx < _shapes.size(); ++staffIdx) {
qreal d = staffShape(staffIdx).minHorizontalDistance(ns->staffShape(staffIdx));
2016-02-04 11:27:47 +01:00
w = qMax(w, d);
}
2016-03-02 13:20:19 +01:00
if (isChordRestType()) {
2016-02-04 11:27:47 +01:00
if (nst == Segment::Type::EndBarLine)
2016-04-15 16:44:48 +02:00
w += score()->styleP(StyleIdx::noteBarDistance);
2016-02-04 11:27:47 +01:00
else if (nst == Segment::Type::Clef)
2016-03-02 13:20:19 +01:00
w = qMax(w, score()->styleP(StyleIdx::clefLeftMargin));
else {
bool isGap = false;
for (int i = 0; i < score()->nstaves() * VOICES; i++) {
Element* el = element(i);
if (el && el->isRest() && toRest(el)->isGap())
isGap = true;
else if (el) {
isGap = false;
break;
}
}
if (isGap)
return 0.0;
2016-03-02 13:20:19 +01:00
w = qMax(w, score()->noteHeadWidth()) + score()->styleP(StyleIdx::minNoteDistance);
}
2016-02-04 11:27:47 +01:00
}
else if (nst == Segment::Type::ChordRest) {
qreal d;
if (systemHeaderGap) {
if (st == Segment::Type::TimeSig)
d = score()->styleP(StyleIdx::systemHeaderTimeSigDistance);
else
d = score()->styleP(StyleIdx::systemHeaderDistance);
}
else
d = score()->styleP(StyleIdx::barNoteDistance);
2016-05-02 13:41:41 +02:00
qreal dd = minRight() + ns->minLeft() + spatium();
w = qMax(d, dd);
2016-04-28 16:23:32 +02:00
// d -= ns->minLeft() * .7; // hack
// d = qMax(d, ns->minLeft());
// d = qMax(d, spatium()); // minimum distance is one spatium
// w = qMax(w, minRight()) + d;
}
else if (st == Segment::Type::Clef) {
if (nst == Segment::Type::KeySig)
w += score()->styleP(StyleIdx::clefKeyDistance);
else if (nst == Segment::Type::TimeSig)
w += score()->styleP(StyleIdx::clefTimesigDistance);
else if (nst & (Segment::Type::EndBarLine | Segment::Type::StartRepeatBarLine))
w += score()->styleP(StyleIdx::clefBarlineDistance);
else if (nst == Segment::Type::Ambitus)
w += score()->styleP(StyleIdx::ambitusMargin);
}
else if ((st & (Segment::Type::KeySig | Segment::Type::KeySigAnnounce))
&& (nst & (Segment::Type::TimeSig | Segment::Type::TimeSigAnnounce))) {
2016-03-02 13:20:19 +01:00
w += score()->styleP(StyleIdx::keyTimesigDistance);
}
else if (st == Segment::Type::KeySig && nst == Segment::Type::StartRepeatBarLine)
w += score()->styleP(StyleIdx::keyBarlineDistance);
2016-02-04 11:27:47 +01:00
else if (st == Segment::Type::StartRepeatBarLine)
2016-03-02 13:20:19 +01:00
w += score()->styleP(StyleIdx::noteBarDistance);
2016-02-04 11:27:47 +01:00
else if (st == Segment::Type::BeginBarLine && nst == Segment::Type::Clef)
2016-03-02 13:20:19 +01:00
w += score()->styleP(StyleIdx::clefLeftMargin);
else if (st == Segment::Type::EndBarLine) {
if (nst == Segment::Type::KeySigAnnounce)
w += score()->styleP(StyleIdx::keysigLeftMargin);
else if (nst == Segment::Type::TimeSigAnnounce)
w += score()->styleP(StyleIdx::timesigLeftMargin);
}
else if (st == Segment::Type::TimeSig && nst == Segment::Type::StartRepeatBarLine)
w += score()->styleP(StyleIdx::timesigBarlineDistance);
else if (st == Segment::Type::Breath)
2016-03-02 13:20:19 +01:00
w += spatium() * 1.5;
else if (st == Segment::Type::Ambitus)
w += score()->styleP(StyleIdx::ambitusMargin);
2016-02-04 11:27:47 +01:00
if (w < 0.0)
w = 0.0;
if (ns)
2016-03-02 13:20:19 +01:00
w += ns->extraLeadingSpace().val() * spatium();
2016-02-04 11:27:47 +01:00
return w;
}
Fixes the following Q_INVOKABLE methods returning a QObject* by turning them into a property: - Measure: -- firstSegment -- lastSegment - MeasureBase: -- nextMeasure -- nextMeasureMM (new) -- prevMeasure -- prevMeasureMM (new) - Score: -- firstMeasure -- firstMeasureMM (new) -- (for firstSegment(), see special cases below) -- lastMeasure -- lastMeasureMM (new) -- lastSegment - Segment: -- next (renamed from `next1`) -- nextInMeasure (renamed from `next`) -- prev (renamed from `prev1`) -- prevInMeasure (renamed from prev) Special cases: - Cursor: The prototype of the `Q_INVOKABLE Ms::Note* Cursor::addNote(int pitch)` was wrong: corrected in `Q_INVOKABLE void Cursor::addNote(int pitch)`. - QmlPlugin: `Q_INVOKABLE Score* QmlPlugin::readScore()` and `Q_INVOKABLE Score* QmlPlugin::newScore()` has been kept, as they are intended to be called from QML; code has been added to ensure the C++ ownership of the returned object. - Score: `Q_INVOKABLE Segment* Score::firstSegment(Segment::Type segType)` is kept (as it needs a parameters), but code is added to ensure C++ ownership of the returned Segment*. - Segment: `Ms::Element* Segment::element(int track)` has been made NOT Q_INVOKABLE; a variant `Q_INVOKABLE Ms::Element* elementAt(int track)` has been added specifically for QML with code to ensure the C++ ownership of the returned Element* (this was the cause for the crash of the Walk plug-in). - FiguredBass: `Q_INVOKABLE Ms::FiguredBassItem* FiguredBass::addItem()` has been removed; plugin interface for FiguredBass needs to be redesigned anyway. The few occurrences in the supplied plug-ins of the methods whose names did change have been updated.
2014-07-06 01:56:30 +02:00
} // namespace Ms