MuseScore/libmscore/chordrest.cpp

1343 lines
48 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 "chordrest.h"
#include "chord.h"
#include "xml.h"
#include "style.h"
#include "system.h"
#include "measure.h"
#include "staff.h"
#include "tuplet.h"
#include "score.h"
#include "sym.h"
#include "slur.h"
#include "beam.h"
#include "breath.h"
#include "barline.h"
#include "articulation.h"
#include "tempo.h"
#include "tempotext.h"
#include "note.h"
#include "arpeggio.h"
#include "dynamic.h"
#include "stafftext.h"
#include "sig.h"
#include "clef.h"
#include "lyrics.h"
#include "segment.h"
#include "stafftype.h"
#include "undo.h"
#include "stem.h"
#include "harmony.h"
#include "hairpin.h"
2012-05-26 14:26:10 +02:00
#include "figuredbass.h"
#include "icon.h"
#include "utils.h"
#include "keysig.h"
#include "page.h"
2016-01-04 14:48:58 +01:00
#include "hook.h"
2018-10-25 16:26:44 +02:00
#include "rehearsalmark.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
//---------------------------------------------------------
// ChordRest
//---------------------------------------------------------
ChordRest::ChordRest(Score* s)
: DurationElement(s)
{
2013-07-11 14:44:35 +02:00
_staffMove = 0;
_beam = 0;
2013-07-11 14:44:35 +02:00
_tabDur = 0;
_up = true;
2016-05-19 13:15:34 +02:00
_beamMode = Beam::Mode::AUTO;
2013-07-11 14:44:35 +02:00
_small = false;
_crossMeasure = CrossMeasure::UNKNOWN;
2012-05-26 14:26:10 +02:00
}
2014-06-27 13:41:49 +02:00
ChordRest::ChordRest(const ChordRest& cr, bool link)
2012-05-26 14:26:10 +02:00
: DurationElement(cr)
{
_durationType = cr._durationType;
_staffMove = cr._staffMove;
2013-07-11 14:44:35 +02:00
_beam = 0;
2012-05-26 14:26:10 +02:00
_tabDur = 0; // tab sur. symb. depends upon context: can't be
// simply copied from another CR
2013-07-11 14:44:35 +02:00
_beamMode = cr._beamMode;
_up = cr._up;
_small = cr._small;
_crossMeasure = cr._crossMeasure;
2012-05-26 14:26:10 +02:00
2016-08-17 12:52:35 +02:00
for (Lyrics* l : cr._lyrics) { // make deep copy
2012-05-26 14:26:10 +02:00
Lyrics* nl = new Lyrics(*l);
2014-06-27 13:41:49 +02:00
if (link)
nl->linkTo(l);
2012-05-26 14:26:10 +02:00
nl->setParent(this);
nl->setTrack(track());
2016-08-24 14:49:34 +02:00
_lyrics.push_back(nl);
2012-05-26 14:26:10 +02:00
}
}
2014-08-07 10:55:36 +02:00
//---------------------------------------------------------
// undoUnlink
//---------------------------------------------------------
void ChordRest::undoUnlink()
{
DurationElement::undoUnlink();
2016-08-24 14:49:34 +02:00
for (Lyrics* l : _lyrics)
l->undoUnlink();
2014-08-07 10:55:36 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// ChordRest
//---------------------------------------------------------
ChordRest::~ChordRest()
{
2016-08-17 12:52:35 +02:00
qDeleteAll(_lyrics);
2016-12-06 09:35:52 +01:00
qDeleteAll(_el);
2016-08-17 12:52:35 +02:00
delete _tabDur;
2019-03-19 13:48:38 +01:00
if (_beam && _beam->contains(this))
delete _beam; // Beam destructor removes references to the deleted object
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// scanElements
//---------------------------------------------------------
void ChordRest::scanElements(void* data, void (*func)(void*, Element*), bool all)
{
if (_beam && (_beam->elements().front() == this)
&& !measure()->stemless(staffIdx()))
2012-05-26 14:26:10 +02:00
_beam->scanElements(data, func, all);
2016-08-24 14:49:34 +02:00
for (Lyrics* l : _lyrics)
l->scanElements(data, func, all);
2012-05-26 14:26:10 +02:00
DurationElement* de = this;
while (de->tuplet() && de->tuplet()->elements().front() == de) {
de->tuplet()->scanElements(data, func, all);
2012-05-26 14:26:10 +02:00
de = de->tuplet();
}
if (_tabDur)
func(data, _tabDur);
}
//---------------------------------------------------------
// writeProperties
//---------------------------------------------------------
2016-11-19 11:51:21 +01:00
void ChordRest::writeProperties(XmlWriter& xml) const
2012-05-26 14:26:10 +02:00
{
DurationElement::writeProperties(xml);
//
// Beam::Mode default:
// REST - Beam::Mode::NONE
// CHORD - Beam::Mode::AUTO
2012-05-26 14:26:10 +02:00
//
2018-03-28 10:43:28 +02:00
if ((isRest() && _beamMode != Beam::Mode::NONE) || (isChord() && _beamMode != Beam::Mode::AUTO)) {
2012-05-26 14:26:10 +02:00
QString s;
switch(_beamMode) {
case Beam::Mode::AUTO: s = "auto"; break;
case Beam::Mode::BEGIN: s = "begin"; break;
case Beam::Mode::MID: s = "mid"; break;
case Beam::Mode::END: s = "end"; break;
case Beam::Mode::NONE: s = "no"; break;
case Beam::Mode::BEGIN32: s = "begin32"; break;
case Beam::Mode::BEGIN64: s = "begin64"; break;
case Beam::Mode::INVALID: s = "?"; break;
2012-05-26 14:26:10 +02:00
}
xml.tag("BeamMode", s);
}
2018-03-27 15:36:00 +02:00
writeProperty(xml, Pid::SMALL);
2013-05-12 12:51:42 +02:00
if (actualDurationType().dots())
xml.tag("dots", actualDurationType().dots());
2018-03-27 15:36:00 +02:00
writeProperty(xml, Pid::STAFF_MOVE);
2014-08-20 09:50:42 +02:00
2013-05-12 12:51:42 +02:00
if (actualDurationType().isValid())
xml.tag("durationType", actualDurationType().name());
2012-05-26 14:26:10 +02:00
if (!ticks().isZero() && (!actualDurationType().fraction().isValid()
|| (actualDurationType().fraction() != ticks()))) {
xml.tag("duration", ticks());
//xml.tagE("duration z=\"%d\" n=\"%d\"", ticks().numerator(), ticks().denominator());
}
2014-10-10 14:24:37 +02:00
2016-08-24 14:49:34 +02:00
for (Lyrics* lyrics : _lyrics)
lyrics->write(xml);
2013-06-19 16:25:29 +02:00
if (!isGrace()) {
Fraction t(globalTicks());
2013-06-19 16:25:29 +02:00
if (staff())
2016-11-19 10:31:14 +01:00
t /= staff()->timeStretch(xml.curTick());
xml.incCurTick(t);
2013-06-19 16:25:29 +02:00
}
for (auto i : score()->spanner()) { // TODO: dont search whole list
2014-11-01 13:05:18 +01:00
Spanner* s = i.second;
2016-10-26 11:33:51 +02:00
if (s->generated() || !s->isSlur() || toSlur(s)->broken() || !xml.canWrite(s))
2014-11-01 13:05:18 +01:00
continue;
if (s->startElement() == this)
s->writeSpannerStart(xml, this, track());
else if (s->endElement() == this)
s->writeSpannerEnd(xml, this, track());
2014-11-01 13:05:18 +01:00
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// readProperties
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
bool ChordRest::readProperties(XmlReader& e)
2012-05-26 14:26:10 +02:00
{
2013-01-11 18:10:18 +01:00
const QStringRef& tag(e.name());
2012-05-26 14:26:10 +02:00
2013-05-29 10:31:26 +02:00
if (tag == "durationType") {
setDurationType(e.readElementText());
if (actualDurationType().type() != TDuration::DurationType::V_MEASURE) {
2017-01-18 14:16:33 +01:00
if (score()->mscVersion() < 112 && (type() == ElementType::REST) &&
2013-05-29 10:31:26 +02:00
// for backward compatibility, convert V_WHOLE rests to V_MEASURE
// if long enough to fill a measure.
// OTOH, freshly created (un-initialized) rests have numerator == 0 (< 4/4)
// (see Fraction() constructor in fraction.h; this happens for instance
// when pasting selection from clipboard): they should not be converted
ticks().numerator() != 0 &&
2013-05-29 10:31:26 +02:00
// rest durations are initialized to full measure duration when
// created upon reading the <Rest> tag (see Measure::read() )
// so a V_WHOLE rest in a measure of 4/4 or less => V_MEASURE
(actualDurationType()==TDuration::DurationType::V_WHOLE && ticks() <= Fraction(4, 4)) ) {
2013-05-29 10:31:26 +02:00
// old pre 2.0 scores: convert
setDurationType(TDuration::DurationType::V_MEASURE);
2013-05-29 10:31:26 +02:00
}
else // not from old score: set duration fraction from duration type
setTicks(actualDurationType().fraction());
2013-05-29 10:31:26 +02:00
}
else {
if (score()->mscVersion() <= 114) {
2013-05-29 10:31:26 +02:00
SigEvent event = score()->sigmap()->timesig(e.tick());
setTicks(event.timesig());
2013-05-29 10:31:26 +02:00
}
}
}
else if (tag == "BeamMode") {
2013-01-11 18:10:18 +01:00
QString val(e.readElementText());
Beam::Mode bm = Beam::Mode::AUTO;
2012-05-26 14:26:10 +02:00
if (val == "auto")
bm = Beam::Mode::AUTO;
2012-05-26 14:26:10 +02:00
else if (val == "begin")
bm = Beam::Mode::BEGIN;
2012-05-26 14:26:10 +02:00
else if (val == "mid")
bm = Beam::Mode::MID;
2012-05-26 14:26:10 +02:00
else if (val == "end")
bm = Beam::Mode::END;
2012-05-26 14:26:10 +02:00
else if (val == "no")
bm = Beam::Mode::NONE;
2012-05-26 14:26:10 +02:00
else if (val == "begin32")
bm = Beam::Mode::BEGIN32;
2012-05-26 14:26:10 +02:00
else if (val == "begin64")
bm = Beam::Mode::BEGIN64;
2012-05-26 14:26:10 +02:00
else
bm = Beam::Mode(val.toInt());
_beamMode = Beam::Mode(bm);
2012-05-26 14:26:10 +02:00
}
2016-10-06 12:21:28 +02:00
else if (tag == "Articulation") {
2012-05-26 14:26:10 +02:00
Articulation* atr = new Articulation(score());
atr->setTrack(track());
2012-05-26 14:26:10 +02:00
atr->read(e);
add(atr);
}
2016-01-04 14:48:58 +01:00
else if (tag == "leadingSpace" || tag == "trailingSpace") {
qDebug("ChordRest: %s obsolete", tag.toLocal8Bit().data());
2013-01-22 21:53:45 +01:00
e.skipCurrentElement();
2012-05-26 14:26:10 +02:00
}
else if (tag == "small")
2013-01-11 18:10:18 +01:00
_small = e.readInt();
2012-05-26 14:26:10 +02:00
else if (tag == "duration")
setTicks(e.readFraction());
2012-05-26 14:26:10 +02:00
else if (tag == "ticklen") { // obsolete (version < 1.12)
2013-01-21 20:21:41 +01:00
int mticks = score()->sigmap()->timesig(e.tick()).timesig().ticks();
2013-01-11 18:10:18 +01:00
int i = e.readInt();
2012-05-26 14:26:10 +02:00
if (i == 0)
i = mticks;
2017-01-18 14:16:33 +01:00
if ((type() == ElementType::REST) && (mticks == i)) {
setDurationType(TDuration::DurationType::V_MEASURE);
setTicks(Fraction::fromTicks(i));
2012-05-26 14:26:10 +02:00
}
else {
Fraction f = Fraction::fromTicks(i);
setTicks(f);
2012-05-26 14:26:10 +02:00
setDurationType(TDuration(f));
}
}
else if (tag == "dots")
2013-01-11 18:10:18 +01:00
setDots(e.readInt());
else if (tag == "staffMove") {
2013-01-11 18:10:18 +01:00
_staffMove = e.readInt();
if (vStaffIdx() < part()->staves()->first()->idx() || vStaffIdx() > part()->staves()->last()->idx())
_staffMove = 0;
}
else if (tag == "Spanner")
Spanner::readSpanner(e, this, track());
else if (tag == "Lyrics") {
Element* element = new Lyrics(score());
element->setTrack(e.track());
element->read(e);
add(element);
}
else if (tag == "pos") {
QPointF pt = e.readPoint();
setOffset(pt * spatium());
}
// else if (tag == "offset")
// DurationElement::readProperties(e);
else if (!DurationElement::readProperties(e))
return false;
return true;
}
2015-03-03 15:45:25 +01:00
//---------------------------------------------------------
// ChordRest::readAddConnector
//---------------------------------------------------------
void ChordRest::readAddConnector(ConnectorInfoReader* info, bool pasteMode)
{
const ElementType type = info->type();
2018-11-19 13:32:15 +01:00
switch (type) {
case ElementType::SLUR:
{
Spanner* spanner = toSpanner(info->connector());
const Location& l = info->location();
if (info->isStart()) {
spanner->setTrack(l.track());
spanner->setTick(tick());
spanner->setStartElement(this);
if (pasteMode) {
score()->undoAddElement(spanner);
for (ScoreElement* ee : spanner->linkList()) {
if (ee == spanner)
2014-07-30 12:34:56 +02:00
continue;
2018-11-19 13:32:15 +01:00
Spanner* ls = toSpanner(ee);
2014-08-07 10:18:50 +02:00
ls->setTick(spanner->tick());
for (ScoreElement* eee : linkList()) {
ChordRest* cr = toChordRest(eee);
if (cr->score() == eee->score() && cr->staffIdx() == ls->staffIdx()) {
2014-07-30 12:34:56 +02:00
ls->setTrack(cr->track());
2018-11-19 13:32:15 +01:00
if (ls->isSlur())
2014-08-07 10:18:50 +02:00
ls->setStartElement(cr);
2014-07-30 12:34:56 +02:00
break;
}
}
}
}
else
score()->addSpanner(spanner);
2014-07-18 18:14:46 +02:00
}
else if (info->isEnd()) {
spanner->setTrack2(l.track());
spanner->setTick2(tick());
spanner->setEndElement(this);
if (pasteMode) {
for (ScoreElement* ee : spanner->linkList()) {
if (ee == spanner)
2014-07-30 12:34:56 +02:00
continue;
Spanner* ls = static_cast<Spanner*>(ee);
2014-08-07 10:18:50 +02:00
ls->setTick2(spanner->tick2());
for (ScoreElement* eee : linkList()) {
ChordRest* cr = toChordRest(eee);
if (cr->score() == eee->score() && cr->staffIdx() == ls->staffIdx()) {
2014-07-30 12:34:56 +02:00
ls->setTrack2(cr->track());
2017-01-18 14:16:33 +01:00
if (ls->type() == ElementType::SLUR)
2014-08-07 10:18:50 +02:00
ls->setEndElement(cr);
2014-07-30 12:34:56 +02:00
break;
}
}
}
}
2014-07-18 18:14:46 +02:00
}
else
qDebug("ChordRest::readAddConnector(): Slur end is neither start nor end");
2014-07-18 18:14:46 +02:00
}
break;
default:
break;
2014-05-06 15:47:57 +02:00
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// setSmall
//---------------------------------------------------------
void ChordRest::setSmall(bool val)
{
2013-05-28 15:42:02 +02:00
_small = val;
}
//---------------------------------------------------------
// undoSetSmall
//---------------------------------------------------------
void ChordRest::undoSetSmall(bool val)
{
2018-03-27 15:36:00 +02:00
undoChangeProperty(Pid::SMALL, val);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// drop
//---------------------------------------------------------
2017-03-31 13:03:15 +02:00
Element* ChordRest::drop(EditData& data)
2012-05-26 14:26:10 +02:00
{
Element* e = data.dropElement;
Measure* m = measure();
bool fromPalette = (e->track() == -1);
2012-05-26 14:26:10 +02:00
switch (e->type()) {
2017-01-18 14:16:33 +01:00
case ElementType::BREATH:
2012-05-26 14:26:10 +02:00
{
2016-05-02 13:41:41 +02:00
Breath* b = toBreath(e);
b->setPos(QPointF());
int track = staffIdx() * VOICES;
b->setTrack(track);
// find start tick of next note in staff
#if 0
int bt = tick() + actualTicks(); // this could make sense if we allowed breath marks in voice > 1
#else
Segment* next = segment()->nextCR(track);
Fraction bt = next ? next->tick() : score()->lastSegment()->tick();
#endif
2012-05-26 14:26:10 +02:00
// TODO: insert automatically in all staves?
2017-03-08 13:12:26 +01:00
Segment* seg = m->undoGetSegment(SegmentType::Breath, bt);
2012-05-26 14:26:10 +02:00
b->setParent(seg);
score()->undoAddElement(b);
}
return e;
2017-01-18 14:16:33 +01:00
case ElementType::BAR_LINE:
2016-08-09 17:17:27 +02:00
if (data.control())
score()->splitMeasure(segment());
2016-08-09 17:17:27 +02:00
else {
2016-08-06 10:33:32 +02:00
BarLine* bl = toBarLine(e);
bl->setPos(QPointF());
2016-08-06 10:33:32 +02:00
bl->setTrack(staffIdx() * VOICES);
bl->setGenerated(false);
if (tick() == m->tick())
return m->drop(data);
BarLine* obl = 0;
for (Staff* st : staff()->staffList()) {
Score* score = st->score();
Measure* measure = score->tick2measure(m->tick());
2017-03-08 13:12:26 +01:00
Segment* seg = measure->undoGetSegmentR(SegmentType::BarLine, rtick());
2016-08-06 10:33:32 +02:00
BarLine* l;
if (obl == 0)
obl = l = bl->clone();
else
l = toBarLine(obl->linkedClone());
2016-08-06 10:33:32 +02:00
l->setTrack(st->idx() * VOICES);
l->setScore(score);
l->setParent(seg);
score->undoAddElement(l);
l->layout();
2016-08-06 10:33:32 +02:00
}
}
delete e;
return 0;
2012-05-26 14:26:10 +02:00
2017-01-18 14:16:33 +01:00
case ElementType::CLEF:
score()->cmdInsertClef(toClef(e), this);
2012-05-26 14:26:10 +02:00
break;
2017-01-18 14:16:33 +01:00
case ElementType::TIMESIG:
if (measure()->system()) {
2017-03-31 13:03:15 +02:00
EditData ndd = data;
2015-09-28 16:08:59 +02:00
// adding from palette sets pos, but normal paste does not
if (!fromPalette)
ndd.pos = pagePos();
// convert page-relative pos to score-relative
ndd.pos += measure()->system()->page()->pos();
return measure()->drop(ndd);
}
else {
delete e;
return 0;
}
case ElementType::FERMATA:
e->setPlacement(track() & 1 ? Placement::BELOW : Placement::ABOVE);
for (Element* el: segment()->annotations())
if (el->isFermata() && (el->track() == track())) {
if (el->subtype() == e->subtype()) {
delete e;
return el;
}
else {
e->setPlacement(el->placement());
e->setTrack(track());
e->setParent(segment());
score()->undoChangeElement(el, e);
return e;
}
}
// fall through
2017-01-18 14:16:33 +01:00
case ElementType::TEMPO_TEXT:
case ElementType::DYNAMIC:
case ElementType::FRET_DIAGRAM:
case ElementType::TREMOLOBAR:
case ElementType::SYMBOL:
2012-05-26 14:26:10 +02:00
e->setTrack(track());
e->setParent(segment());
score()->undoAddElement(e);
return e;
2017-12-20 16:49:30 +01:00
case ElementType::NOTE: {
Note* note = toNote(e);
2012-05-26 14:26:10 +02:00
NoteVal nval;
nval.pitch = note->pitch();
nval.tpc1 = note->tpc1();
2012-05-26 14:26:10 +02:00
nval.headGroup = note->headGroup();
nval.fret = note->fret();
nval.string = note->string();
score()->setNoteRest(segment(), track(), nval, ticks(), Direction::AUTO);
2012-05-26 14:26:10 +02:00
delete e;
}
break;
2017-01-18 14:16:33 +01:00
case ElementType::HARMONY:
{
// transpose
2017-12-20 16:49:30 +01:00
Harmony* harmony = toHarmony(e);
Interval interval = staff()->part()->instrument(tick())->transpose();
2018-03-27 15:36:00 +02:00
if (!score()->styleB(Sid::concertPitch) && !interval.isZero()) {
interval.flip();
int rootTpc = transposeTpc(harmony->rootTpc(), interval, true);
int baseTpc = transposeTpc(harmony->baseTpc(), interval, true);
score()->undoTransposeHarmony(harmony, rootTpc, baseTpc);
}
// render
harmony->render();
}
2012-05-26 14:26:10 +02:00
// fall through
2017-01-18 14:16:33 +01:00
case ElementType::TEXT:
case ElementType::STAFF_TEXT:
2017-01-23 10:54:57 +01:00
case ElementType::SYSTEM_TEXT:
2017-01-18 14:16:33 +01:00
case ElementType::STAFF_STATE:
case ElementType::INSTRUMENT_CHANGE:
if (e->isInstrumentChange() && part()->instruments()->find(tick().ticks()) != part()->instruments()->end()) {
qDebug()<<"InstrumentChange already exists at tick = "<<tick().ticks();
delete e;
return 0;
}
// fall through
2017-01-18 14:16:33 +01:00
case ElementType::REHEARSAL_MARK:
{
2012-05-26 14:26:10 +02:00
e->setParent(segment());
e->setTrack((track() / VOICES) * VOICES);
if (e->isRehearsalMark()) {
RehearsalMark* r = toRehearsalMark(e);
if (fromPalette)
r->setXmlText(score()->createRehearsalMarkText(r));
}
2012-05-26 14:26:10 +02:00
score()->undoAddElement(e);
return e;
}
2017-01-18 14:16:33 +01:00
case ElementType::FIGURED_BASS:
2012-05-26 14:26:10 +02:00
{
bool bNew;
2017-12-20 16:49:30 +01:00
FiguredBass * fb = toFiguredBass(e);
2012-05-26 14:26:10 +02:00
fb->setParent( segment() );
fb->setTrack( (track() / VOICES) * VOICES );
fb->setTicks(ticks() );
2012-05-26 14:26:10 +02:00
fb->setOnNote(true);
FiguredBass::addFiguredBassToSegment(segment(), fb->track(), fb->ticks(), &bNew);
2012-05-26 14:26:10 +02:00
if (bNew)
score()->undoAddElement(e);
return e;
}
2017-01-18 14:16:33 +01:00
case ElementType::IMAGE:
2012-05-26 14:26:10 +02:00
e->setParent(segment());
score()->undoAddElement(e);
return e;
2017-01-18 14:16:33 +01:00
case ElementType::ICON:
2012-05-26 14:26:10 +02:00
{
2017-12-20 16:49:30 +01:00
switch (toIcon(e)->iconType()) {
case IconType::SBEAM:
2018-03-27 15:36:00 +02:00
undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::BEGIN));
2012-05-26 14:26:10 +02:00
break;
case IconType::MBEAM:
2018-03-27 15:36:00 +02:00
undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::MID));
2012-05-26 14:26:10 +02:00
break;
case IconType::NBEAM:
2018-03-27 15:36:00 +02:00
undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::NONE));
2012-05-26 14:26:10 +02:00
break;
case IconType::BEAM32:
2018-03-27 15:36:00 +02:00
undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::BEGIN32));
2012-05-26 14:26:10 +02:00
break;
case IconType::BEAM64:
2018-03-27 15:36:00 +02:00
undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::BEGIN64));
2012-05-26 14:26:10 +02:00
break;
case IconType::AUTOBEAM:
2018-03-27 15:36:00 +02:00
undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::AUTO));
2012-05-26 14:26:10 +02:00
break;
default:
break;
2012-05-26 14:26:10 +02:00
}
}
delete e;
break;
2017-01-18 14:16:33 +01:00
case ElementType::KEYSIG:
{
2017-12-20 16:49:30 +01:00
KeySig* ks = toKeySig(e);
KeySigEvent k = ks->keySigEvent();
delete ks;
// apply only to this stave
score()->undoChangeKeySig(staff(), tick(), k);
}
break;
2012-05-26 14:26:10 +02:00
case ElementType::HAIRPIN:
{
const Hairpin* hairpin = toHairpin(e);
ChordRest* endCR = this;
if (hairpin->ticks().isNotZero()) {
const Fraction tick2 = tick() + hairpin->ticks() - Fraction::eps();
endCR = score()->findCR(tick2, track());
}
score()->addHairpin(hairpin->hairpinType(), this, endCR);
delete e;
}
return nullptr;
2012-05-26 14:26:10 +02:00
default:
qDebug("cannot drop %s", e->name());
delete e;
return 0;
}
return 0;
}
//---------------------------------------------------------
// setBeam
//---------------------------------------------------------
void ChordRest::setBeam(Beam* b)
{
_beam = b;
}
//---------------------------------------------------------
// setDurationType
//---------------------------------------------------------
void ChordRest::setDurationType(TDuration::DurationType t)
{
_durationType.setType(t);
_crossMeasure = CrossMeasure::UNKNOWN;
2012-05-26 14:26:10 +02:00
}
void ChordRest::setDurationType(const QString& s)
{
_durationType.setType(s);
_crossMeasure = CrossMeasure::UNKNOWN;
2012-05-26 14:26:10 +02:00
}
void ChordRest::setDurationType(const Fraction& ticks)
2012-05-26 14:26:10 +02:00
{
_durationType.setVal(ticks.ticks());
_crossMeasure = CrossMeasure::UNKNOWN;
2012-05-26 14:26:10 +02:00
}
void ChordRest::setDurationType(TDuration v)
2012-05-26 14:26:10 +02:00
{
_durationType = v;
_crossMeasure = CrossMeasure::UNKNOWN;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// durationUserName
//---------------------------------------------------------
2016-02-04 17:06:32 +01:00
QString ChordRest::durationUserName() const
{
QString tupletType = "";
if (tuplet()) {
switch (tuplet()->ratio().numerator()) {
case 2:
tupletType = QObject::tr("Duplet");
break;
case 3:
tupletType = QObject::tr("Triplet");
break;
case 4:
tupletType = QObject::tr("Quadruplet");
break;
case 5:
tupletType = QObject::tr("Quintuplet");
break;
case 6:
tupletType = QObject::tr("Sextuplet");
break;
case 7:
tupletType = QObject::tr("Septuplet");
break;
case 8:
tupletType = QObject::tr("Octuplet");
break;
case 9:
tupletType = QObject::tr("Nonuplet");
break;
default:
tupletType = QObject::tr("Custom tuplet");
}
}
QString dotString = "";
if(!tupletType.isEmpty())
dotString += " ";
switch (dots()) {
case 1:
dotString += QObject::tr("Dotted %1").arg(durationType().durationTypeUserName()).trimmed();
break;
case 2:
dotString += QObject::tr("Double dotted %1").arg(durationType().durationTypeUserName()).trimmed();
break;
case 3:
dotString += QObject::tr("Triple dotted %1").arg(durationType().durationTypeUserName()).trimmed();
break;
2016-06-01 12:35:20 +02:00
case 4:
dotString += QObject::tr("Quadruple dotted %1").arg(durationType().durationTypeUserName()).trimmed();
2016-06-01 12:35:20 +02:00
break;
default:
dotString += durationType().durationTypeUserName();
}
return QString("%1%2").arg(tupletType).arg(dotString);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// add
//---------------------------------------------------------
void ChordRest::add(Element* e)
{
e->setParent(this);
e->setTrack(track());
2016-12-06 09:35:52 +01:00
switch (e->type()) {
2018-04-09 11:51:35 +02:00
case ElementType::ARTICULATION: // for backward compatibility
qDebug("ChordRest::add: unknown element %s", e->name());
break;
2017-01-18 14:16:33 +01:00
case ElementType::LYRICS:
if (e->isStyled(Pid::OFFSET))
e->setOffset(e->propertyDefault(Pid::OFFSET).toPointF());
2016-08-24 14:49:34 +02:00
_lyrics.push_back(toLyrics(e));
2012-05-26 14:26:10 +02:00
break;
default:
qFatal("ChordRest::add: unknown element %s", e->name());
2012-05-26 14:26:10 +02:00
break;
}
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void ChordRest::remove(Element* e)
{
switch (e->type()) {
2017-01-18 14:16:33 +01:00
case ElementType::LYRICS: {
2016-08-24 14:49:34 +02:00
toLyrics(e)->removeFromScore();
auto i = std::find(_lyrics.begin(), _lyrics.end(), toLyrics(e));
if (i != _lyrics.end())
_lyrics.erase(i);
else
qDebug("ChordRest::remove: %s %p not found", e->name(), e);
2012-05-26 14:26:10 +02:00
}
break;
default:
qFatal("ChordRest::remove: unknown element <%s>", e->name());
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// removeDeleteBeam
2013-07-11 12:25:25 +02:00
// beamed - the chordrest is beamed (will get a (new) beam)
// remove ChordRest from beam
// delete beam if empty
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2017-03-21 10:39:04 +01:00
void ChordRest::removeDeleteBeam(bool beamed)
2012-05-26 14:26:10 +02:00
{
if (_beam) {
Beam* b = _beam;
2013-05-22 15:20:14 +02:00
_beam->remove(this);
2016-02-06 22:03:43 +01:00
if (b->empty())
2013-05-22 15:20:14 +02:00
score()->undoRemoveElement(b);
else
b->layout1();
2012-05-26 14:26:10 +02:00
}
2017-03-21 10:39:04 +01:00
if (!beamed && isChord())
toChord(this)->layoutStem();
2012-05-26 14:26:10 +02:00
}
2013-03-01 10:07:27 +01:00
//---------------------------------------------------------
// undoSetBeamMode
//---------------------------------------------------------
void ChordRest::undoSetBeamMode(Beam::Mode mode)
2013-03-01 10:07:27 +01:00
{
2018-03-27 15:36:00 +02:00
undoChangeProperty(Pid::BEAM_MODE, int(mode));
2013-03-01 10:07:27 +01:00
}
//---------------------------------------------------------
// localSpatiumChanged
//---------------------------------------------------------
void ChordRest::localSpatiumChanged(qreal oldValue, qreal newValue)
{
DurationElement::localSpatiumChanged(oldValue, newValue);
for (Element* e : lyrics())
e->localSpatiumChanged(oldValue, newValue);
for (Element* e : el())
e->localSpatiumChanged(oldValue, newValue);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
2018-03-27 15:36:00 +02:00
QVariant ChordRest::getProperty(Pid propertyId) const
2012-05-26 14:26:10 +02:00
{
2016-05-25 19:41:36 +02:00
switch (propertyId) {
2018-03-27 15:36:00 +02:00
case Pid::SMALL: return QVariant(small());
case Pid::BEAM_MODE: return int(beamMode());
case Pid::STAFF_MOVE: return staffMove();
case Pid::DURATION_TYPE: return QVariant::fromValue(actualDurationType());
2014-08-20 09:50:42 +02:00
default: return DurationElement::getProperty(propertyId);
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
2018-03-27 15:36:00 +02:00
bool ChordRest::setProperty(Pid propertyId, const QVariant& v)
2012-05-26 14:26:10 +02:00
{
2016-05-25 19:41:36 +02:00
switch (propertyId) {
2018-03-27 15:36:00 +02:00
case Pid::SMALL:
setSmall(v.toBool());
break;
2018-03-27 15:36:00 +02:00
case Pid::BEAM_MODE:
setBeamMode(Beam::Mode(v.toInt()));
break;
2018-03-27 15:36:00 +02:00
case Pid::STAFF_MOVE:
setStaffMove(v.toInt());
break;
2018-03-27 15:36:00 +02:00
case Pid::VISIBLE:
setVisible(v.toBool());
measure()->checkMultiVoices(staffIdx());
break;
2018-03-27 15:36:00 +02:00
case Pid::DURATION_TYPE:
setDurationType(v.value<TDuration>());
break;
default:
return DurationElement::setProperty(propertyId, v);
2012-05-26 14:26:10 +02:00
}
triggerLayout();
2012-05-26 14:26:10 +02:00
return true;
}
2012-08-12 11:44:36 +02:00
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
2018-03-27 15:36:00 +02:00
QVariant ChordRest::propertyDefault(Pid propertyId) const
2012-08-12 11:44:36 +02:00
{
2016-05-25 19:41:36 +02:00
switch (propertyId) {
2018-03-27 15:36:00 +02:00
case Pid::SMALL:
return false;
2018-03-27 15:36:00 +02:00
case Pid::BEAM_MODE:
return int(Beam::Mode::AUTO);
2018-03-27 15:36:00 +02:00
case Pid::STAFF_MOVE:
return 0;
default:
return DurationElement::propertyDefault(propertyId);
2012-08-12 11:44:36 +02:00
}
// Prevent unreachable code warning
This commit contains changes required for MuseScore to compile under MSVC with no warnings. This commit contains changes required for MuseScore to compile under MSVC with no warnings. MuseScore is being compiled with the /W4 setting (warning level 4), which is similar to -wall -wextra on clang. This generates lots of warnings on MSVC, mainly for non-standard constructs and for constructs which might be bugs or might lead to bugs. Most warnings are in the following categories: - Name hiding: a variable hides a variable with the same name on a larger scope (or a field, or a function parameter). This can easily lead to bugs, and it is a best practice to avoid hiding variable names (see recommendation ES.12 in the C++ Core Guidelines by Stroustrop & Sutter (http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-reuse : ES.12: Do not reuse names in nested scopes) - Narrowing conversion: a numeric conversion results in loss of significant digits (for example, double -> float). The general recommendation is to use a cast to indicate this is designed behaviour. - Unreachable code: in several instances, there is unreachable code. The unreachable code is commented out. - (Potentially) uninitialized local variable. Just initialized the vars. - foreach(,) -> for(:): this does not generate a warning per-se (only a few of these generate warnings due to name hiding), but changed in keeping with "MuseScore Coding Rules" (https://musescore.org/en/handbook/musescore-coding-rules#Loops), which tells explicitly "Use C++11's "for" instead of Qt's "foreach":" ... "If you happen to be fixing some code and see a "foreach", please change that loop into a "for"." Most changes are in the categories indicated above. The next listing shows detailed changes for files which are *not* of the aforementioned types. - all.h: Disable warning C4127 (conditional expression is constant - generated in Qt header file qvector.h) - awl/aslider.h: unreachable code. - awl/knob.cpp: name hiding - awl/mslider.cpp: name hiding - awl/slider.cpp: name hiding - bww2mxml/parser.cpp: name hiding - effects/compressor/compressor.cpp: narrowing conversion - effects/zita1/zitagui.cpp: name hiding - fluid/fluid.cpp: foreach replacement. Name hiding. - fluid/mod.cpp: name hiding. - fluid/sfont.cpp: foreach replacement. Name hiding. Initialize vars. - fluid/voice.cpp: Name hiding. - libmscore/accidental.cpp: Name hiding. - libmscore/ambitus.cpp: Initialize vars. - libmscore/barline.cpp: Name hiding. Unreachable code. - libmscore/beam.cpp: Name hiding. - libmscore/chordrest.cpp: Unreachable code. - libmscore/scorefile.cpp: Name hiding. - manual/genManual.cpp: Name hiding. foreach replacement. - midi/midifile.cpp: Name hiding. Unreachable code. - omr/importpdf.cpp: Name hiding. foreach replacement. - omr/omr.cpp: Name hiding. foreach replacement. - omr/omrpage.cpp: Name hiding. foreach replacement. - omr/omrview.cpp: Name hiding. foreach replacement. - synthesizer/event.cpp: Unreachable code. - zerberus\channel.cpp: Narrowing conversion. - zerberus\instrument.cpp: Name hiding. - zerberus\sfz.cpp: Name hiding. - zerberus\voice.h: Suppress warning C4201: "nonstandard extension used: nameless struct/union" - zerberus\zerberus.cpp: Name hiding. Unreferenced parameter. - zerberus\zerberusgui.cpp: Name hiding.
2018-05-03 03:04:08 +02:00
// triggerLayout();
2012-08-12 11:44:36 +02:00
}
2013-06-19 16:25:29 +02:00
//---------------------------------------------------------
// isGrace
//---------------------------------------------------------
2013-06-16 23:33:37 +02:00
bool ChordRest::isGrace() const
{
2017-07-06 09:59:29 +02:00
return isChord() && toChord(this)->isGrace();
2013-06-16 23:33:37 +02:00
}
2013-06-19 16:25:29 +02:00
2014-04-23 18:07:38 +02:00
//---------------------------------------------------------
// isGraceBefore
//---------------------------------------------------------
bool ChordRest::isGraceBefore() const
{
return isChord()
&& (toChord(this)->noteType() & (
NoteType::ACCIACCATURA | NoteType::APPOGGIATURA | NoteType::GRACE4 | NoteType::GRACE16 | NoteType::GRACE32
));
2014-04-23 18:07:38 +02:00
}
//---------------------------------------------------------
// isGraceAfter
//---------------------------------------------------------
bool ChordRest::isGraceAfter() const
{
return isChord()
&& (toChord(this)->noteType() & (NoteType::GRACE8_AFTER | NoteType::GRACE16_AFTER | NoteType::GRACE32_AFTER));
2014-04-23 18:07:38 +02:00
}
2013-06-19 16:25:29 +02:00
//---------------------------------------------------------
// writeBeam
//---------------------------------------------------------
2018-06-09 04:45:54 +02:00
void ChordRest::writeBeam(XmlWriter& xml) const
2013-06-19 16:25:29 +02:00
{
Beam* b = beam();
if (b && b->elements().front() == this && (MScore::testMode || !b->generated())) {
b->write(xml);
}
}
//---------------------------------------------------------
// nextSegmentAfterCR
// returns first segment at tick CR->tick + CR->actualTicks
// of given types
//---------------------------------------------------------
2017-03-08 13:12:26 +01:00
Segment* ChordRest::nextSegmentAfterCR(SegmentType types) const
{
Fraction end = tick() + actualTicks();
for (Segment* s = segment()->next1MM(types); s; s = s->next1MM(types)) {
// chordrest ends at afrac+actualFraction
// we return the segment at or after the end of the chordrest
// Segment::afrac() is based on ticks; use DurationElement::afrac() if possible
Element* e = s;
if (s->isChordRestType()) {
// Find the first non-NULL element in the segment
for (Element* ee : s->elist()) {
if (ee) {
e = ee;
break;
}
}
}
if (e->tick() >= end)
return s;
}
return 0;
}
//---------------------------------------------------------
// setTrack
//---------------------------------------------------------
void ChordRest::setTrack(int val)
{
Element::setTrack(val);
processSiblings([val] (Element* e) { e->setTrack(val); } );
}
//---------------------------------------------------------
// setScore
//---------------------------------------------------------
void ChordRest::setScore(Score* s)
{
Element::setScore(s);
processSiblings([s] (Element* e) { e->setScore(s); } );
}
//---------------------------------------------------------
// processSiblings
//---------------------------------------------------------
void ChordRest::processSiblings(std::function<void(Element*)> func)
{
if (_beam)
func(_beam);
if (_tabDur)
func(_tabDur);
2016-08-17 12:52:35 +02:00
for (Lyrics* l : _lyrics)
2016-08-24 14:49:34 +02:00
func(l);
if (tuplet())
func(tuplet());
}
//---------------------------------------------------------
// nextArticulationOrLyric
//---------------------------------------------------------
Element* ChordRest::nextArticulationOrLyric(Element* e)
2017-12-08 09:01:18 +01:00
{
if (isChord() && e->isArticulation()) {
Chord* c = toChord(this);
auto i = std::find(c->articulations().begin(), c->articulations().end(), e);
if (i != c->articulations().end()) {
if (i != c->articulations().end() - 1) {
return *(i+1);
}
else {
if (!_lyrics.empty())
return _lyrics[0];
else
return nullptr;
}
}
}
else {
auto i = std::find(_lyrics.begin(), _lyrics.end(), e);
if (i != _lyrics.end()) {
if (i != _lyrics.end()-1)
return *(i+1);
}
}
2018-01-17 13:25:23 +01:00
return 0;
}
//---------------------------------------------------------
// prevArticulationOrLyric
//---------------------------------------------------------
Element* ChordRest::prevArticulationOrLyric(Element* e)
{
auto i = std::find(_lyrics.begin(), _lyrics.end(), e);
if (i != _lyrics.end()) {
if (i != _lyrics.begin()) {
return *(i-1);
}
else {
if (isChord() && !toChord(this)->articulations().empty())
return toChord(this)->articulations().back();
else
return nullptr;
}
}
else if (isChord() && e->isArticulation()) {
Chord* c = toChord(this);
auto j = std::find(c->articulations().begin(), c->articulations().end(), e);
if (j != c->articulations().end()) {
if (j != c->articulations().begin())
return *(j-1);
}
}
2018-01-17 13:25:23 +01:00
return 0;
}
//---------------------------------------------------------
// nextElement
//---------------------------------------------------------
Element* ChordRest::nextElement()
{
Element* e = score()->selection().element();
2018-01-17 13:25:23 +01:00
if (!e && !score()->selection().elements().isEmpty())
e = score()->selection().elements().first();
switch (e->type()) {
case ElementType::ARTICULATION:
2017-12-08 09:01:18 +01:00
case ElementType::LYRICS: {
Element* next = nextArticulationOrLyric(e);
if (next)
return next;
else
break;
}
2017-12-08 09:01:18 +01:00
default: {
if (isChord() && !toChord(this)->articulations().empty())
return toChord(this)->articulations()[0];
else if (!_lyrics.empty())
2017-12-08 09:01:18 +01:00
return _lyrics[0];
else
break;
}
}
int staffId = e->staffIdx();
return segment()->nextElement(staffId);
}
//---------------------------------------------------------
// prevElement
//---------------------------------------------------------
Element* ChordRest::prevElement()
{
Element* e = score()->selection().element();
2018-01-17 13:25:23 +01:00
if (!e && !score()->selection().elements().isEmpty())
e = score()->selection().elements().last();
switch (e->type()) {
case ElementType::ARTICULATION:
case ElementType::LYRICS: {
Element* prev = prevArticulationOrLyric(e);
if (prev)
return prev;
else {
2017-12-20 16:49:30 +01:00
if (isChord())
return toChord(this)->lastElementBeforeSegment();
}
// fall through
2017-12-08 09:01:18 +01:00
}
default: {
2017-12-08 09:01:18 +01:00
break;
}
}
int staffId = e->staffIdx();
return segment()->prevElement(staffId);
}
//---------------------------------------------------------
// lastElementBeforeSegment
//---------------------------------------------------------
Element* ChordRest::lastElementBeforeSegment()
{
2018-01-17 13:25:23 +01:00
if (!_lyrics.empty())
return _lyrics.back();
2018-01-17 13:25:23 +01:00
// else if (!_articulations.empty()) { // TODO:fermata
// return _articulations.back();
// }
else
return 0;
}
//---------------------------------------------------------
// nextSegmentElement
//---------------------------------------------------------
Element* ChordRest::nextSegmentElement()
{
return segment()->firstInNextSegments(staffIdx());
}
//---------------------------------------------------------
// prevSegmentElement
//---------------------------------------------------------
Element* ChordRest::prevSegmentElement()
{
return segment()->lastInPrevSegments(staffIdx());
}
2016-02-04 17:06:32 +01:00
QString ChordRest::accessibleExtraInfo() const
{
QString rez = "";
2016-08-17 12:52:35 +02:00
for (Element* l : lyrics()) {
if (!score()->selectionFilter().canSelect(l))
continue;
rez = QString("%1 %2").arg(rez).arg(l->screenReaderInfo());
}
2014-08-19 14:10:43 +02:00
if (segment()) {
2016-08-17 12:52:35 +02:00
for (Element* e : segment()->annotations()) {
if (!score()->selectionFilter().canSelect(e))
continue;
if (e->track() == track())
rez = QString("%1 %2").arg(rez).arg(e->screenReaderInfo());
}
2014-08-19 14:10:43 +02:00
SpannerMap& smap = score()->spannerMap();
auto spanners = smap.findOverlapping(tick().ticks(), tick().ticks());
for (auto interval : spanners) {
Spanner* s = interval.value;
2016-08-17 12:52:35 +02:00
if (!score()->selectionFilter().canSelect(s))
continue;
2017-01-18 14:16:33 +01:00
if (s->type() == ElementType::VOLTA || //voltas are added for barlines
s->type() == ElementType::TIE ) //ties are added in notes
continue;
Segment* seg = 0;
2017-01-18 14:16:33 +01:00
if (s->type() == ElementType::SLUR) {
2014-08-19 14:10:43 +02:00
if (s->tick() == tick() && s->track() == track())
rez = QObject::tr("%1 Start of %2").arg(rez).arg(s->screenReaderInfo());
2014-08-19 14:10:43 +02:00
if (s->tick2() == tick() && s->track2() == track())
rez = QObject::tr("%1 End of %2").arg(rez).arg(s->screenReaderInfo());
}
else {
2014-08-19 14:10:43 +02:00
if (s->tick() == tick() && s->staffIdx() == staffIdx())
rez = QObject::tr("%1 Start of %2").arg(rez).arg(s->screenReaderInfo());
2017-03-08 13:12:26 +01:00
seg = segment()->next1MM(SegmentType::ChordRest);
if (!seg)
continue;
2014-08-19 14:10:43 +02:00
if (s->tick2() == seg->tick() && s->staffIdx() == staffIdx())
rez = QObject::tr("%1 End of %2").arg(rez).arg(s->screenReaderInfo());
}
}
}
return rez;
}
2016-01-04 14:48:58 +01:00
//---------------------------------------------------------
// shape
//---------------------------------------------------------
Shape ChordRest::shape() const
{
Shape shape;
{
qreal x1 = 1000000.0;
qreal x2 = -1000000.0;
bool adjustWidth = false;
for (Lyrics* l : _lyrics) {
if (!l || !l->addToSkyline())
continue;
qreal lmargin = score()->styleS(Sid::lyricsMinDistance).val() * spatium() * 0.5;
qreal rmargin = lmargin;
Lyrics::Syllabic syl = l->syllabic();
if ((syl == Lyrics::Syllabic::BEGIN || syl == Lyrics::Syllabic::MIDDLE) && score()->styleB(Sid::lyricsDashForce))
rmargin = qMax(rmargin, styleP(Sid::lyricsDashMinLength));
// for horizontal spacing we only need the lyrics width:
x1 = qMin(x1, l->bbox().x() - lmargin + l->pos().x());
x2 = qMax(x2, l->bbox().x() + l->bbox().width() + rmargin + l->pos().x());
if (l->ticks() == Fraction::fromTicks(Lyrics::TEMP_MELISMA_TICKS))
x2 += spatium();
adjustWidth = true;
}
if (adjustWidth)
shape.addHorizontalSpacing(Shape::SPACING_LYRICS, x1, x2);
}
{
qreal x1 = 1000000.0;
qreal x2 = -1000000.0;
bool adjustWidth = false;
for (Element* e : segment()->annotations()) {
if (!e || !e->addToSkyline())
continue;
if (e->isHarmony() && e->staffIdx() == staffIdx()) {
Harmony* h = toHarmony(e);
// calculate bbox only (do not reset position)
h->layout1();
const qreal margin = styleP(Sid::minHarmonyDistance) * 0.5;
x1 = qMin(x1, e->bbox().x() - margin + e->pos().x());
x2 = qMax(x2, e->bbox().x() + e->bbox().width() + margin + e->pos().x());
adjustWidth = true;
}
2016-01-04 14:48:58 +01:00
}
if (adjustWidth)
shape.addHorizontalSpacing(Shape::SPACING_HARMONY, x1, x2);
}
return shape;
2016-01-04 14:48:58 +01:00
}
2016-08-24 14:49:34 +02:00
//---------------------------------------------------------
// lyrics
//---------------------------------------------------------
Lyrics* ChordRest::lyrics(int no, Placement p) const
{
for (Lyrics* l : _lyrics) {
if (l->placement() == p && l->no() == no)
return l;
}
return 0;
}
//---------------------------------------------------------
// lastVerse
// return last verse number (starting from 0)
// return -1 if there are no lyrics;
//---------------------------------------------------------
int ChordRest::lastVerse(Placement p) const
{
int lastVerse = -1;
for (Lyrics* l : _lyrics) {
if (l->placement() == p && l->no() > lastVerse)
lastVerse = l->no();
}
return lastVerse;
}
2016-12-06 09:35:52 +01:00
//---------------------------------------------------------
// removeMarkings
// - this is normally called after cloning a chord to tie a note over the barline
// - there is no special undo handling; the assumption is that undo will simply remove the cloned chord
// - two note tremolos are converted into simple notes
// - single note tremolos are optionally retained
//---------------------------------------------------------
void ChordRest::removeMarkings(bool /* keepTremolo */)
{
qDeleteAll(el());
el().clear();
2016-12-06 09:35:52 +01:00
qDeleteAll(lyrics());
lyrics().clear();
2016-12-06 09:35:52 +01:00
}
//---------------------------------------------------------
// isBefore
//---------------------------------------------------------
bool ChordRest::isBefore(const ChordRest* o) const
{
if (!o || this == o)
return true;
int otick = o->tick().ticks();
int t = tick().ticks();
if (t == otick) { // At least one of the chord is a grace, order the grace notes
bool oGraceAfter = o->isGraceAfter();
bool graceAfter = isGraceAfter();
bool oGrace = o->isGrace();
bool grace = isGrace();
// normal note are initialized at graceIndex 0 and graceIndex is 0 based
int oGraceIndex = oGrace ? toChord(o)->graceIndex() + 1 : 0;
int graceIndex = grace ? toChord(this)->graceIndex() + 1 : 0;
if (oGrace)
oGraceIndex = toChord(o->parent())->graceNotes().size() - oGraceIndex;
if (grace)
graceIndex = toChord(parent())->graceNotes().size() - graceIndex;
otick = otick + (oGraceAfter ? 1 : -1) * oGraceIndex;
t = t + (graceAfter ? 1 : -1) * graceIndex;
}
return t < otick;
}
//---------------------------------------------------------
// undoAddAnnotation
//---------------------------------------------------------
void ChordRest::undoAddAnnotation(Element* a)
{
Segment* seg = segment();
Measure* m = measure();
if (m && m->isMMRest())
seg = m->mmRestFirst()->findSegmentR(SegmentType::ChordRest, Fraction(0,1));
a->setTrack(a->systemFlag() ? 0 : track());
a->setParent(seg);
score()->undoAddElement(a);
}
2013-05-13 18:49:17 +02:00
}