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 "figuredbass.h"
|
|
|
|
|
#include "icon.h"
|
2015-06-19 16:34:38 +02:00
|
|
|
|
#include "utils.h"
|
2015-07-19 17:18:38 +02:00
|
|
|
|
#include "keysig.h"
|
2015-09-05 15:16:03 +02:00
|
|
|
|
#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;
|
2013-01-03 16:56:56 +01:00
|
|
|
|
_beam = 0;
|
2013-07-11 14:44:35 +02:00
|
|
|
|
_tabDur = 0;
|
2013-01-03 16:56:56 +01:00
|
|
|
|
_up = true;
|
2016-05-19 13:15:34 +02:00
|
|
|
|
_beamMode = Beam::Mode::AUTO;
|
2013-07-11 14:44:35 +02:00
|
|
|
|
_small = false;
|
2014-05-21 15:41:23 +02:00
|
|
|
|
_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;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// scanElements
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void ChordRest::scanElements(void* data, void (*func)(void*, Element*), bool all)
|
|
|
|
|
{
|
2013-06-22 10:55:22 +02:00
|
|
|
|
if (_beam && (_beam->elements().front() == this)
|
|
|
|
|
&& !measure()->slashStyle(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) {
|
2015-06-05 11:55:37 +02:00
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
//
|
2014-06-26 07:45:09 +02:00
|
|
|
|
// 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) {
|
2014-06-26 07:45:09 +02:00
|
|
|
|
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
|
|
|
|
|
2013-05-12 12:51:42 +02:00
|
|
|
|
if (!duration().isZero() && (!actualDurationType().fraction().isValid()
|
2016-07-07 16:20:16 +02:00
|
|
|
|
|| (actualDurationType().fraction() != duration()))) {
|
|
|
|
|
xml.tag("duration", duration());
|
|
|
|
|
//xml.tagE("duration z=\"%d\" n=\"%d\"", duration().numerator(), duration().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(globalDuration());
|
|
|
|
|
if (staff())
|
2016-11-19 10:31:14 +01:00
|
|
|
|
t /= staff()->timeStretch(xml.curTick());
|
|
|
|
|
xml.incCurTick(t.ticks());
|
2013-06-19 16:25:29 +02:00
|
|
|
|
}
|
2018-11-27 22:49:18 +01:00
|
|
|
|
for (auto i : score()->spanner()) { // TODO: don’t 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;
|
|
|
|
|
|
2018-05-23 23:27:23 +02:00
|
|
|
|
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());
|
2014-05-21 15:43:19 +02:00
|
|
|
|
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
|
|
|
|
|
duration().numerator() != 0 &&
|
|
|
|
|
// 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
|
2014-05-21 15:43:19 +02:00
|
|
|
|
(actualDurationType()==TDuration::DurationType::V_WHOLE && duration() <= Fraction(4, 4)) ) {
|
2013-05-29 10:31:26 +02:00
|
|
|
|
// old pre 2.0 scores: convert
|
2014-05-21 15:43:19 +02:00
|
|
|
|
setDurationType(TDuration::DurationType::V_MEASURE);
|
2013-05-29 10:31:26 +02:00
|
|
|
|
}
|
|
|
|
|
else // not from old score: set duration fraction from duration type
|
|
|
|
|
setDuration(actualDurationType().fraction());
|
|
|
|
|
}
|
|
|
|
|
else {
|
2016-05-13 06:55:03 +02:00
|
|
|
|
if (score()->mscVersion() <= 114) {
|
2013-05-29 10:31:26 +02:00
|
|
|
|
SigEvent event = score()->sigmap()->timesig(e.tick());
|
|
|
|
|
setDuration(event.timesig());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (tag == "BeamMode") {
|
2013-01-11 18:10:18 +01:00
|
|
|
|
QString val(e.readElementText());
|
2014-06-26 07:45:09 +02:00
|
|
|
|
Beam::Mode bm = Beam::Mode::AUTO;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
if (val == "auto")
|
2014-06-26 07:45:09 +02:00
|
|
|
|
bm = Beam::Mode::AUTO;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (val == "begin")
|
2014-06-26 07:45:09 +02:00
|
|
|
|
bm = Beam::Mode::BEGIN;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (val == "mid")
|
2014-06-26 07:45:09 +02:00
|
|
|
|
bm = Beam::Mode::MID;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (val == "end")
|
2014-06-26 07:45:09 +02:00
|
|
|
|
bm = Beam::Mode::END;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (val == "no")
|
2014-06-26 07:45:09 +02:00
|
|
|
|
bm = Beam::Mode::NONE;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (val == "begin32")
|
2014-06-26 07:45:09 +02:00
|
|
|
|
bm = Beam::Mode::BEGIN32;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (val == "begin64")
|
2014-06-26 07:45:09 +02:00
|
|
|
|
bm = Beam::Mode::BEGIN64;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else
|
2014-06-26 07:45:09 +02:00
|
|
|
|
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());
|
2014-10-06 08:40:25 +02:00
|
|
|
|
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")
|
2013-01-11 18:10:18 +01:00
|
|
|
|
setDuration(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)) {
|
2014-05-21 15:43:19 +02:00
|
|
|
|
setDurationType(TDuration::DurationType::V_MEASURE);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
setDuration(Fraction::fromTicks(i));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Fraction f = Fraction::fromTicks(i);
|
|
|
|
|
setDuration(f);
|
|
|
|
|
setDurationType(TDuration(f));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (tag == "dots")
|
2013-01-11 18:10:18 +01:00
|
|
|
|
setDots(e.readInt());
|
2018-08-14 23:25:09 +02:00
|
|
|
|
else if (tag == "staffMove")
|
2013-01-11 18:10:18 +01:00
|
|
|
|
_staffMove = e.readInt();
|
2018-05-23 23:27:23 +02:00
|
|
|
|
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();
|
2018-10-18 11:53:01 +02:00
|
|
|
|
setOffset(pt * spatium());
|
2018-05-23 23:27:23 +02:00
|
|
|
|
}
|
2018-10-25 15:43:59 +02:00
|
|
|
|
// else if (tag == "offset")
|
|
|
|
|
// DurationElement::readProperties(e);
|
2018-05-23 23:27:23 +02:00
|
|
|
|
else if (!DurationElement::readProperties(e))
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2015-03-03 15:45:25 +01:00
|
|
|
|
|
2018-05-23 23:27:23 +02: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) {
|
2018-05-23 23:27:23 +02:00
|
|
|
|
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);
|
2018-08-14 10:03:49 +02:00
|
|
|
|
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());
|
2018-08-14 10:03:49 +02:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-23 23:27:23 +02:00
|
|
|
|
else
|
|
|
|
|
score()->addSpanner(spanner);
|
2014-07-18 18:14:46 +02:00
|
|
|
|
}
|
2018-05-23 23:27:23 +02:00
|
|
|
|
else if (info->isEnd()) {
|
|
|
|
|
spanner->setTrack2(l.track());
|
|
|
|
|
spanner->setTick2(tick());
|
|
|
|
|
spanner->setEndElement(this);
|
|
|
|
|
if (pasteMode) {
|
2018-08-14 10:03:49 +02:00
|
|
|
|
for (ScoreElement* ee : spanner->linkList()) {
|
|
|
|
|
if (ee == spanner)
|
2014-07-30 12:34:56 +02:00
|
|
|
|
continue;
|
2018-08-14 10:03:49 +02:00
|
|
|
|
Spanner* ls = static_cast<Spanner*>(ee);
|
2014-08-07 10:18:50 +02:00
|
|
|
|
ls->setTick2(spanner->tick2());
|
2018-08-14 10:03:49 +02:00
|
|
|
|
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
|
2018-05-23 23:27:23 +02:00
|
|
|
|
qDebug("ChordRest::readAddConnector(): Slur end is neither start nor end");
|
2014-07-18 18:14:46 +02:00
|
|
|
|
}
|
2018-05-23 23:27:23 +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;
|
2012-06-19 14:44:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-09 11:04:15 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// undoSetSmall
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void ChordRest::undoSetSmall(bool val)
|
|
|
|
|
{
|
2018-03-27 15:36:00 +02:00
|
|
|
|
undoChangeProperty(Pid::SMALL, val);
|
2014-05-09 11:04:15 +02:00
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
{
|
2018-11-13 13:31:48 +01:00
|
|
|
|
Element* e = data.dropElement;
|
2015-01-02 02:06:32 +01:00
|
|
|
|
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);
|
2016-09-03 18:35:29 +02:00
|
|
|
|
b->setPos(QPointF());
|
2015-02-06 17:01:41 +01:00
|
|
|
|
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);
|
|
|
|
|
int 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())
|
2016-10-25 17:30:55 +02:00
|
|
|
|
score()->splitMeasure(segment());
|
2016-08-09 17:17:27 +02:00
|
|
|
|
else {
|
2016-08-06 10:33:32 +02:00
|
|
|
|
BarLine* bl = toBarLine(e);
|
2016-09-03 18:28:58 +02:00
|
|
|
|
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
|
2016-09-03 18:28:58 +02:00
|
|
|
|
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);
|
2018-10-05 18:26:05 +02:00
|
|
|
|
l->layout();
|
2016-08-06 10:33:32 +02:00
|
|
|
|
}
|
2014-12-22 13:28:09 +01:00
|
|
|
|
}
|
|
|
|
|
delete e;
|
|
|
|
|
return 0;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
2017-01-18 14:16:33 +01:00
|
|
|
|
case ElementType::CLEF:
|
2016-09-03 18:28:58 +02:00
|
|
|
|
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:
|
2015-09-05 15:16:03 +02:00
|
|
|
|
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
|
2015-09-05 15:16:03 +02:00
|
|
|
|
ndd.pos += measure()->system()->page()->pos();
|
|
|
|
|
return measure()->drop(ndd);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
delete e;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-07-03 22:18:40 +02:00
|
|
|
|
|
2018-11-05 21:27:21 +01:00
|
|
|
|
case ElementType::FERMATA:
|
|
|
|
|
for (Element* el: segment()->annotations())
|
|
|
|
|
if (el->isFermata() && (el->track() == track())) {
|
|
|
|
|
if (el->subtype() == e->subtype()) {
|
|
|
|
|
delete e;
|
|
|
|
|
return el;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (el->placeBelow())
|
|
|
|
|
e->setPlacement(Placement::BELOW);
|
|
|
|
|
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();
|
2017-08-31 02:53:49 +02:00
|
|
|
|
nval.tpc1 = note->tpc1();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
nval.headGroup = note->headGroup();
|
2014-08-19 22:17:58 +02:00
|
|
|
|
nval.fret = note->fret();
|
|
|
|
|
nval.string = note->string();
|
2017-08-31 15:58:41 +02:00
|
|
|
|
score()->setNoteRest(segment(), track(), nval, duration(), Direction::AUTO);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
delete e;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2017-01-18 14:16:33 +01:00
|
|
|
|
case ElementType::HARMONY:
|
2015-06-19 16:34:38 +02:00
|
|
|
|
{
|
|
|
|
|
// transpose
|
2017-12-20 16:49:30 +01:00
|
|
|
|
Harmony* harmony = toHarmony(e);
|
2015-09-21 02:13:22 +02:00
|
|
|
|
Interval interval = staff()->part()->instrument(tick())->transpose();
|
2018-03-27 15:36:00 +02:00
|
|
|
|
if (!score()->styleB(Sid::concertPitch) && !interval.isZero()) {
|
2015-06-19 16:34:38 +02:00
|
|
|
|
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:
|
2017-01-16 20:51:12 +01:00
|
|
|
|
if (e->isInstrumentChange() && part()->instruments()->find(tick()) != part()->instruments()->end()) {
|
2015-02-08 20:55:18 +01:00
|
|
|
|
qDebug()<<"InstrumentChange already exists at tick = "<<tick();
|
|
|
|
|
delete e;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
// fall through
|
2018-06-19 14:00:00 +02:00
|
|
|
|
|
2017-01-18 14:16:33 +01:00
|
|
|
|
case ElementType::REHEARSAL_MARK:
|
2018-10-27 11:10:40 +02:00
|
|
|
|
{
|
2012-05-26 14:26:10 +02:00
|
|
|
|
e->setParent(segment());
|
|
|
|
|
e->setTrack((track() / VOICES) * VOICES);
|
2018-10-27 11:10:40 +02:00
|
|
|
|
if (e->isRehearsalMark()) {
|
2018-10-25 19:56:02 +02:00
|
|
|
|
RehearsalMark* r = toRehearsalMark(e);
|
2018-10-27 11:10:40 +02:00
|
|
|
|
if (fromPalette)
|
2018-10-25 19:56:02 +02:00
|
|
|
|
r->setXmlText(score()->createRehearsalMarkText(r));
|
2018-10-27 11:10:40 +02:00
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
score()->undoAddElement(e);
|
|
|
|
|
return e;
|
2018-10-27 11:10:40 +02:00
|
|
|
|
}
|
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( duration().ticks() );
|
|
|
|
|
fb->setOnNote(true);
|
2013-05-18 15:02:47 +02:00
|
|
|
|
FiguredBass::addFiguredBassToSegment(segment(),
|
2012-05-26 14:26:10 +02:00
|
|
|
|
fb->track(), fb->ticks(), &bNew);
|
|
|
|
|
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()) {
|
2014-05-30 10:14:57 +02:00
|
|
|
|
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;
|
2014-05-30 10:14:57 +02:00
|
|
|
|
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;
|
2014-05-30 10:14:57 +02:00
|
|
|
|
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;
|
2014-05-30 10:14:57 +02:00
|
|
|
|
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;
|
2014-05-30 10:14:57 +02:00
|
|
|
|
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;
|
2014-05-30 10:14:57 +02:00
|
|
|
|
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;
|
2014-05-30 10:14:57 +02:00
|
|
|
|
default:
|
|
|
|
|
break;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
delete e;
|
|
|
|
|
break;
|
2015-07-19 17:18:38 +02:00
|
|
|
|
|
2017-01-18 14:16:33 +01:00
|
|
|
|
case ElementType::KEYSIG:
|
2015-07-19 17:18:38 +02:00
|
|
|
|
{
|
2017-12-20 16:49:30 +01:00
|
|
|
|
KeySig* ks = toKeySig(e);
|
2015-07-19 17:18:38 +02:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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);
|
2014-05-21 15:41:23 +02:00
|
|
|
|
_crossMeasure = CrossMeasure::UNKNOWN;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChordRest::setDurationType(const QString& s)
|
|
|
|
|
{
|
|
|
|
|
_durationType.setType(s);
|
2014-05-21 15:41:23 +02:00
|
|
|
|
_crossMeasure = CrossMeasure::UNKNOWN;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChordRest::setDurationType(int ticks)
|
|
|
|
|
{
|
|
|
|
|
_durationType.setVal(ticks);
|
2014-05-21 15:41:23 +02:00
|
|
|
|
_crossMeasure = CrossMeasure::UNKNOWN;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-16 09:44:21 +01:00
|
|
|
|
void ChordRest::setDurationType(TDuration v)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
{
|
|
|
|
|
_durationType = v;
|
2014-05-21 15:41:23 +02:00
|
|
|
|
_crossMeasure = CrossMeasure::UNKNOWN;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-16 09:44:21 +01:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// durationUserName
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2016-02-04 17:06:32 +01:00
|
|
|
|
QString ChordRest::durationUserName() const
|
2014-07-10 14:13:37 +02:00
|
|
|
|
{
|
|
|
|
|
QString tupletType = "";
|
2015-02-16 09:44:21 +01:00
|
|
|
|
if (tuplet()) {
|
2014-07-10 14:13:37 +02:00
|
|
|
|
switch (tuplet()->ratio().numerator()) {
|
|
|
|
|
case 2:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
tupletType = QObject::tr("Duplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
|
|
|
|
case 3:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
tupletType = QObject::tr("Triplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
|
|
|
|
case 4:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
tupletType = QObject::tr("Quadruplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
|
|
|
|
case 5:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
tupletType = QObject::tr("Quintuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
|
|
|
|
case 6:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
tupletType = QObject::tr("Sextuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
|
|
|
|
case 7:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
tupletType = QObject::tr("Septuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
|
|
|
|
case 8:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
tupletType = QObject::tr("Octuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
|
|
|
|
case 9:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
tupletType = QObject::tr("Nonuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2018-11-24 21:08:07 +01:00
|
|
|
|
tupletType = QObject::tr("Custom tuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QString dotString = "";
|
2015-01-22 17:16:04 +01:00
|
|
|
|
if(!tupletType.isEmpty())
|
|
|
|
|
dotString += " ";
|
2014-07-10 14:13:37 +02:00
|
|
|
|
|
|
|
|
|
switch (dots()) {
|
|
|
|
|
case 1:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
dotString += QObject::tr("Dotted %1").arg(durationType().durationTypeUserName()).trimmed();
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
|
|
|
|
case 2:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
dotString += QObject::tr("Double dotted %1").arg(durationType().durationTypeUserName()).trimmed();
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
|
|
|
|
case 3:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
dotString += QObject::tr("Triple dotted %1").arg(durationType().durationTypeUserName()).trimmed();
|
2014-07-10 14:13:37 +02:00
|
|
|
|
break;
|
2016-06-01 12:35:20 +02:00
|
|
|
|
case 4:
|
2017-02-17 15:09:28 +01:00
|
|
|
|
dotString += QObject::tr("Quadruple dotted %1").arg(durationType().durationTypeUserName()).trimmed();
|
2016-06-01 12:35:20 +02:00
|
|
|
|
break;
|
2015-01-22 17:16:04 +01:00
|
|
|
|
default:
|
|
|
|
|
dotString += durationType().durationTypeUserName();
|
2014-07-10 14:13:37 +02:00
|
|
|
|
}
|
2015-01-22 17:16:04 +01:00
|
|
|
|
return QString("%1%2").arg(tupletType).arg(dotString);
|
2014-07-10 14:13:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
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:
|
2016-08-24 14:49:34 +02:00
|
|
|
|
_lyrics.push_back(toLyrics(e));
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2014-03-04 13:06:23 +01:00
|
|
|
|
qFatal("ChordRest::add: unknown element %s", e->name());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// remove
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void ChordRest::remove(Element* e)
|
|
|
|
|
{
|
2013-02-21 14:28:16 +01:00
|
|
|
|
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:
|
2014-03-04 13:06:23 +01:00
|
|
|
|
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);
|
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
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2014-06-26 07:45:09 +02:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
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:
|
2016-06-14 10:32:34 +02:00
|
|
|
|
setSmall(v.toBool());
|
|
|
|
|
break;
|
2018-03-27 15:36:00 +02:00
|
|
|
|
case Pid::BEAM_MODE:
|
2016-06-14 10:32:34 +02:00
|
|
|
|
setBeamMode(Beam::Mode(v.toInt()));
|
|
|
|
|
break;
|
2018-03-27 15:36:00 +02:00
|
|
|
|
case Pid::STAFF_MOVE:
|
2016-06-14 10:32:34 +02:00
|
|
|
|
setStaffMove(v.toInt());
|
|
|
|
|
break;
|
2018-03-27 15:36:00 +02:00
|
|
|
|
case Pid::VISIBLE:
|
2015-01-26 22:58:46 +01:00
|
|
|
|
setVisible(v.toBool());
|
|
|
|
|
measure()->checkMultiVoices(staffIdx());
|
|
|
|
|
break;
|
2018-03-27 15:36:00 +02:00
|
|
|
|
case Pid::DURATION_TYPE:
|
2015-02-16 09:44:21 +01:00
|
|
|
|
setDurationType(v.value<TDuration>());
|
|
|
|
|
break;
|
2015-01-26 22:58:46 +01:00
|
|
|
|
default:
|
|
|
|
|
return DurationElement::setProperty(propertyId, v);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2016-06-14 10:32:34 +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:
|
2016-06-14 10:32:34 +02:00
|
|
|
|
return false;
|
2018-03-27 15:36:00 +02:00
|
|
|
|
case Pid::BEAM_MODE:
|
2016-06-14 10:32:34 +02:00
|
|
|
|
return int(Beam::Mode::AUTO);
|
2018-03-27 15:36:00 +02:00
|
|
|
|
case Pid::STAFF_MOVE:
|
2016-06-14 10:32:34 +02:00
|
|
|
|
return 0;
|
|
|
|
|
default:
|
|
|
|
|
return DurationElement::propertyDefault(propertyId);
|
2012-08-12 11:44:36 +02:00
|
|
|
|
}
|
2018-10-18 11:53:01 +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
|
|
|
|
|
{
|
2016-06-14 10:32:34 +02:00
|
|
|
|
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
|
|
|
|
|
{
|
2016-06-14 10:32:34 +02:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-30 11:26:58 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// 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
|
2014-06-30 11:26:58 +02:00
|
|
|
|
{
|
|
|
|
|
for (Segment* s = segment()->next1MM(types); s; s = s->next1MM(types)) {
|
2018-06-02 20:41:28 +02:00
|
|
|
|
// chordrest ends at afrac+actualFraction
|
2014-06-30 11:26:58 +02:00
|
|
|
|
// we return the segment at or after the end of the chordrest
|
2018-06-02 20:41:28 +02:00
|
|
|
|
if (s->afrac() >= afrac() + actualFraction())
|
2014-06-30 11:26:58 +02:00
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-06-20 22:48:34 +02:00
|
|
|
|
|
2016-02-19 10:23:23 +01:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// 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);
|
2016-02-19 10:23:23 +01:00
|
|
|
|
if (tuplet())
|
|
|
|
|
func(tuplet());
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-12 20:16:02 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// nextArticulationOrLyric
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2018-02-20 15:43:28 +01:00
|
|
|
|
Element* ChordRest::nextArticulationOrLyric(Element* /*e*/)
|
2017-12-08 09:01:18 +01:00
|
|
|
|
{
|
2018-01-17 13:25:23 +01:00
|
|
|
|
#if 0 // TODO:fermata
|
2017-05-12 20:16:02 +02:00
|
|
|
|
auto i = std::find(_articulations.begin(), _articulations.end(), e);
|
|
|
|
|
if (i != _articulations.end()) {
|
|
|
|
|
if (i != _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
|
|
|
|
#endif
|
|
|
|
|
return 0;
|
2017-05-12 20:16:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// prevArticulationOrLyric
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2018-02-20 15:43:28 +01:00
|
|
|
|
Element* ChordRest::prevArticulationOrLyric(Element* /*e*/)
|
2017-05-12 20:16:02 +02:00
|
|
|
|
{
|
2018-01-17 13:25:23 +01:00
|
|
|
|
#if 0 // TODO:fermata
|
2017-05-12 20:16:02 +02:00
|
|
|
|
auto i = std::find(_lyrics.begin(), _lyrics.end(), e);
|
|
|
|
|
if (i != _lyrics.end()) {
|
|
|
|
|
if (i != _lyrics.begin()) {
|
|
|
|
|
return *(i-1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (!_articulations.empty())
|
|
|
|
|
return _articulations.back();
|
|
|
|
|
else
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
auto i = std::find(_articulations.begin(), _articulations.end(), e);
|
|
|
|
|
if (i != _articulations.end()) {
|
|
|
|
|
if (i != _articulations.begin())
|
|
|
|
|
return *(i-1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-17 13:25:23 +01:00
|
|
|
|
#endif
|
|
|
|
|
return 0;
|
2017-05-12 20:16:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-20 22:48:34 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// nextElement
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
Element* ChordRest::nextElement()
|
|
|
|
|
{
|
2017-05-12 20:16:02 +02:00
|
|
|
|
Element* e = score()->selection().element();
|
2018-01-17 13:25:23 +01:00
|
|
|
|
#if 0 // TODO:fermata
|
|
|
|
|
if (!e && !score()->selection().elements().isEmpty())
|
|
|
|
|
e = score()->selection().elements().first();
|
2017-05-12 20:16:02 +02:00
|
|
|
|
switch (e->type()) {
|
|
|
|
|
case ElementType::ARTICULATION:
|
2017-12-08 09:01:18 +01:00
|
|
|
|
case ElementType::LYRICS: {
|
2017-05-12 20:16:02 +02:00
|
|
|
|
Element* next = nextArticulationOrLyric(e);
|
|
|
|
|
if (next)
|
|
|
|
|
return next;
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-12-08 09:01:18 +01:00
|
|
|
|
default: {
|
2017-05-12 20:16:02 +02:00
|
|
|
|
if (!_articulations.empty())
|
|
|
|
|
return _articulations[0];
|
|
|
|
|
else if (!_lyrics.empty())
|
2017-12-08 09:01:18 +01:00
|
|
|
|
return _lyrics[0];
|
|
|
|
|
else
|
2017-05-12 20:16:02 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-17 13:25:23 +01:00
|
|
|
|
#endif
|
2017-05-12 20:16:02 +02:00
|
|
|
|
int staffId = e->staffIdx();
|
|
|
|
|
return segment()->nextElement(staffId);
|
2014-06-20 22:48:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// prevElement
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
Element* ChordRest::prevElement()
|
2017-05-12 20:16:02 +02:00
|
|
|
|
{
|
|
|
|
|
Element* e = score()->selection().element();
|
2018-01-17 13:25:23 +01:00
|
|
|
|
#if 0 // TODO:fermata
|
|
|
|
|
if (!e && !score()->selection().elements().isEmpty())
|
|
|
|
|
e = score()->selection().elements().last();
|
2017-05-12 20:16:02 +02:00
|
|
|
|
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();
|
2017-05-12 20:16:02 +02:00
|
|
|
|
}
|
|
|
|
|
// fall through
|
2017-12-08 09:01:18 +01:00
|
|
|
|
}
|
2017-05-12 20:16:02 +02:00
|
|
|
|
default: {
|
2017-12-08 09:01:18 +01:00
|
|
|
|
break;
|
2017-05-12 20:16:02 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-17 13:25:23 +01:00
|
|
|
|
#endif
|
2017-05-12 20:16:02 +02:00
|
|
|
|
int staffId = e->staffIdx();
|
|
|
|
|
return segment()->prevElement(staffId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// lastElementBeforeSegment
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
Element* ChordRest::lastElementBeforeSegment()
|
|
|
|
|
{
|
2018-01-17 13:25:23 +01:00
|
|
|
|
if (!_lyrics.empty())
|
2017-05-12 20:16:02 +02:00
|
|
|
|
return _lyrics.back();
|
2018-01-17 13:25:23 +01:00
|
|
|
|
// else if (!_articulations.empty()) { // TODO:fermata
|
|
|
|
|
// return _articulations.back();
|
|
|
|
|
// }
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
2017-05-12 20:16:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// nextSegmentElement
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
Element* ChordRest::nextSegmentElement()
|
|
|
|
|
{
|
|
|
|
|
return segment()->firstInNextSegments(staffIdx());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// prevSegmentElement
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
Element* ChordRest::prevSegmentElement()
|
2014-06-20 22:48:34 +02:00
|
|
|
|
{
|
|
|
|
|
return segment()->lastInPrevSegments(staffIdx());
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-04 17:06:32 +01:00
|
|
|
|
QString ChordRest::accessibleExtraInfo() const
|
2014-07-10 14:13:37 +02:00
|
|
|
|
{
|
|
|
|
|
QString rez = "";
|
2018-01-17 13:25:23 +01:00
|
|
|
|
#if 0 // TODO:fermata
|
2016-08-17 12:52:35 +02:00
|
|
|
|
for (Articulation* a : articulations()) {
|
|
|
|
|
if (!score()->selectionFilter().canSelect(a))
|
|
|
|
|
continue;
|
2014-08-21 18:32:52 +02:00
|
|
|
|
rez = QString("%1 %2").arg(rez).arg(a->screenReaderInfo());
|
2015-02-03 01:55:37 +01:00
|
|
|
|
}
|
2018-01-17 13:25:23 +01:00
|
|
|
|
#endif
|
2016-08-17 12:52:35 +02:00
|
|
|
|
for (Element* l : lyrics()) {
|
|
|
|
|
if (!score()->selectionFilter().canSelect(l))
|
|
|
|
|
continue;
|
2014-08-21 18:32:52 +02:00
|
|
|
|
rez = QString("%1 %2").arg(rez).arg(l->screenReaderInfo());
|
2014-08-30 01:36:11 +02:00
|
|
|
|
}
|
2014-07-10 14:13:37 +02:00
|
|
|
|
|
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;
|
2014-07-10 14:13:37 +02:00
|
|
|
|
if (e->staffIdx() == staffIdx() )
|
2014-08-21 18:32:52 +02:00
|
|
|
|
rez = QString("%1 %2").arg(rez).arg(e->screenReaderInfo());
|
2014-07-10 14:13:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-19 14:10:43 +02:00
|
|
|
|
SpannerMap& smap = score()->spannerMap();
|
|
|
|
|
auto spanners = smap.findOverlapping(tick(), tick());
|
2016-01-13 20:13:08 +01:00
|
|
|
|
for (auto interval : spanners) {
|
2014-07-10 14:13:37 +02:00
|
|
|
|
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
|
2014-07-10 14:13:37 +02:00
|
|
|
|
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())
|
2017-02-17 15:09:28 +01:00
|
|
|
|
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())
|
2017-02-17 15:09:28 +01:00
|
|
|
|
rez = QObject::tr("%1 End of %2").arg(rez).arg(s->screenReaderInfo());
|
2014-07-10 14:13:37 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
2014-08-19 14:10:43 +02:00
|
|
|
|
if (s->tick() == tick() && s->staffIdx() == staffIdx())
|
2017-02-17 15:09:28 +01:00
|
|
|
|
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);
|
2014-07-10 14:13:37 +02:00
|
|
|
|
if (!seg)
|
|
|
|
|
continue;
|
2014-08-19 14:10:43 +02:00
|
|
|
|
if (s->tick2() == seg->tick() && s->staffIdx() == staffIdx())
|
2017-02-17 15:09:28 +01:00
|
|
|
|
rez = QObject::tr("%1 End of %2").arg(rez).arg(s->screenReaderInfo());
|
2014-07-10 14:13:37 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return rez;
|
|
|
|
|
}
|
2016-01-04 14:48:58 +01:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// shape
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
Shape ChordRest::shape() const
|
|
|
|
|
{
|
2018-10-28 11:39:48 +01:00
|
|
|
|
Shape shape;
|
|
|
|
|
qreal x1 = 1000000.0;
|
|
|
|
|
qreal x2 = -1000000.0;
|
|
|
|
|
bool adjustWidth = false;
|
|
|
|
|
for (Lyrics* l : _lyrics) {
|
|
|
|
|
static const qreal margin = spatium() * .5;
|
|
|
|
|
// for horizontal spacing we only need the lyrics width:
|
|
|
|
|
x1 = qMin(x1, l->bbox().x() - margin + l->pos().x());
|
|
|
|
|
x2 = qMax(x2, l->bbox().x() + l->bbox().width() + margin + l->pos().x());
|
|
|
|
|
if (l->ticks() == Lyrics::TEMP_MELISMA_TICKS)
|
|
|
|
|
x2 += spatium();
|
|
|
|
|
adjustWidth = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (Element* e : segment()->annotations()) {
|
|
|
|
|
if (e->isHarmony() && e->staffIdx() == staffIdx()) {
|
|
|
|
|
e->layout();
|
2018-11-29 17:44:44 +01:00
|
|
|
|
qreal hx = e->bbox().x() - e->pos().x();
|
|
|
|
|
x1 = qMin(x1, hx);
|
|
|
|
|
x2 = qMax(x2, hx + e->bbox().width());
|
2018-10-28 11:39:48 +01:00
|
|
|
|
adjustWidth = true;
|
2018-07-19 17:12:45 +02:00
|
|
|
|
}
|
2016-01-04 14:48:58 +01:00
|
|
|
|
}
|
2018-10-28 11:39:48 +01:00
|
|
|
|
if (adjustWidth)
|
2018-11-29 17:44:44 +01:00
|
|
|
|
shape.add(QRectF(x1, 0.0, x2-x1, 0.0));
|
2018-10-28 11:39:48 +01:00
|
|
|
|
|
|
|
|
|
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());
|
2018-07-20 17:03:35 +02:00
|
|
|
|
el().clear();
|
2016-12-06 09:35:52 +01:00
|
|
|
|
qDeleteAll(lyrics());
|
2018-07-20 17:03:35 +02:00
|
|
|
|
lyrics().clear();
|
2016-12-06 09:35:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-12 16:03:30 +01:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// isBefore
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bool ChordRest::isBefore(ChordRest* o)
|
|
|
|
|
{
|
|
|
|
|
if (!o)
|
|
|
|
|
return true;
|
|
|
|
|
if (this == o)
|
|
|
|
|
return true;
|
|
|
|
|
int otick = o->tick();
|
|
|
|
|
int t = tick();
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
|
}
|
|
|
|
|
|