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"
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
namespace Ms {
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// hasArticulation
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Articulation* ChordRest::hasArticulation(const Articulation* aa)
|
|
|
|
{
|
2013-03-05 20:23:59 +01:00
|
|
|
ArticulationType idx = aa->articulationType();
|
2012-11-20 20:51:18 +01:00
|
|
|
foreach(Articulation* a, _articulations) {
|
2013-03-05 20:23:59 +01:00
|
|
|
if (idx == a->articulationType())
|
2012-05-26 14:26:10 +02:00
|
|
|
return a;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// 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;
|
2014-06-26 07:45:09 +02:00
|
|
|
_beamMode = Beam::Mode::AUTO;
|
2013-01-03 16:56:56 +01:00
|
|
|
_up = true;
|
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
|
|
|
|
|
2014-06-27 13:41:49 +02:00
|
|
|
for (Articulation* a : cr._articulations) { // make deep copy
|
2012-05-26 14:26:10 +02:00
|
|
|
Articulation* na = new Articulation(*a);
|
2014-06-27 13:41:49 +02:00
|
|
|
if (link)
|
|
|
|
na->linkTo(a);
|
2012-05-26 14:26:10 +02:00
|
|
|
na->setParent(this);
|
|
|
|
na->setTrack(track());
|
2012-11-20 20:51:18 +01:00
|
|
|
_articulations.append(na);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2013-07-11 14:44:35 +02:00
|
|
|
_beamMode = cr._beamMode;
|
|
|
|
_up = cr._up;
|
|
|
|
_small = cr._small;
|
|
|
|
_crossMeasure = cr._crossMeasure;
|
|
|
|
_space = cr._space;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-07-09 18:16:16 +02:00
|
|
|
for (Lyrics* l : cr._lyricsList) { // make deep copy
|
2014-11-26 19:51:31 +01:00
|
|
|
if (l == 0) {
|
|
|
|
_lyricsList.append(0);
|
2012-07-20 16:29:24 +02:00
|
|
|
continue;
|
2014-11-26 19:51:31 +01:00
|
|
|
}
|
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());
|
|
|
|
_lyricsList.append(nl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-07 10:55:36 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoUnlink
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChordRest::undoUnlink()
|
|
|
|
{
|
|
|
|
DurationElement::undoUnlink();
|
|
|
|
for (Articulation* a : _articulations)
|
|
|
|
a->undoUnlink();
|
|
|
|
for (Lyrics* l : _lyricsList)
|
|
|
|
l->undoUnlink();
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChordRest
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChordRest::~ChordRest()
|
|
|
|
{
|
2013-06-10 11:03:34 +02:00
|
|
|
foreach (Articulation* a, _articulations)
|
2012-05-26 14:26:10 +02:00
|
|
|
delete a;
|
2013-06-10 11:03:34 +02:00
|
|
|
foreach (Lyrics* l, _lyricsList)
|
2012-05-26 14:26:10 +02:00
|
|
|
delete l;
|
2013-06-10 11:03:34 +02:00
|
|
|
if (_tabDur)
|
2012-09-08 01:22:36 +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);
|
2012-11-20 20:51:18 +01:00
|
|
|
foreach(Articulation* a, _articulations)
|
2012-05-26 14:26:10 +02:00
|
|
|
func(data, a);
|
|
|
|
foreach(Lyrics* l, _lyricsList) {
|
|
|
|
if (l)
|
|
|
|
l->scanElements(data, func, all);
|
|
|
|
}
|
|
|
|
DurationElement* de = this;
|
|
|
|
while (de->tuplet() && de->tuplet()->elements().front() == de) {
|
|
|
|
func(data, de->tuplet());
|
|
|
|
de = de->tuplet();
|
|
|
|
}
|
|
|
|
if (_tabDur)
|
|
|
|
func(data, _tabDur);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// writeProperties
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChordRest::writeProperties(Xml& xml) const
|
|
|
|
{
|
|
|
|
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
|
|
|
//
|
2014-06-26 07:45:09 +02:00
|
|
|
if ((type() == Element::Type::REST && _beamMode != Beam::Mode::NONE)
|
|
|
|
|| (type() == Element::Type::CHORD && _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);
|
|
|
|
}
|
2014-05-26 18:18:01 +02:00
|
|
|
writeProperty(xml, P_ID::SMALL);
|
2013-05-12 12:51:42 +02:00
|
|
|
if (actualDurationType().dots())
|
|
|
|
xml.tag("dots", actualDurationType().dots());
|
2014-08-20 09:50:42 +02:00
|
|
|
writeProperty(xml, P_ID::STAFF_MOVE);
|
|
|
|
|
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()
|
|
|
|
|| (actualDurationType().fraction() != duration())))
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.fTag("duration", duration());
|
2014-10-10 14:24:37 +02:00
|
|
|
|
2012-11-20 20:51:18 +01:00
|
|
|
foreach(const Articulation* a, _articulations)
|
2012-05-26 14:26:10 +02:00
|
|
|
a->write(xml);
|
|
|
|
#ifndef NDEBUG
|
2013-03-28 11:09:31 +01:00
|
|
|
if (_beam && (MScore::testMode || !_beam->generated()))
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.tag("Beam", _beam->id());
|
|
|
|
#else
|
2014-03-05 09:56:32 +01:00
|
|
|
if (_beam && !_beam->generated())
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.tag("Beam", _beam->id());
|
|
|
|
#endif
|
|
|
|
foreach(Lyrics* lyrics, _lyricsList) {
|
|
|
|
if (lyrics)
|
|
|
|
lyrics->write(xml);
|
|
|
|
}
|
2013-06-19 16:25:29 +02:00
|
|
|
if (!isGrace()) {
|
|
|
|
Fraction t(globalDuration());
|
|
|
|
if (staff())
|
|
|
|
t *= staff()->timeStretch(xml.curTick);
|
|
|
|
xml.curTick += t.ticks();
|
|
|
|
}
|
2014-11-01 13:05:18 +01:00
|
|
|
for (auto i : score()->spanner()) { // TODO: dont search whole list
|
|
|
|
Spanner* s = i.second;
|
|
|
|
if (s->generated() || s->type() != Element::Type::SLUR || !xml.canWrite(s))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (s->startElement() == this) {
|
|
|
|
int id = xml.spannerId(s);
|
|
|
|
xml.tagE(QString("Slur type=\"start\" id=\"%1\"").arg(id));
|
|
|
|
}
|
|
|
|
else if (s->endElement() == this) {
|
|
|
|
int id = xml.spannerId(s);
|
|
|
|
xml.tagE(QString("Slur type=\"stop\" id=\"%1\"").arg(id));
|
|
|
|
}
|
|
|
|
}
|
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) {
|
2014-06-24 18:36:02 +02:00
|
|
|
if ((type() == Element::Type::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 {
|
|
|
|
if (score()->mscVersion() < 115) {
|
|
|
|
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
|
|
|
}
|
|
|
|
else if (tag == "Attribute" || tag == "Articulation") { // obsolete: "Attribute"
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
else if (tag == "leadingSpace") {
|
2013-01-11 18:10:18 +01:00
|
|
|
qDebug("ChordRest: leadingSpace obsolete"); // _extraLeadingSpace = Spatium(val.toDouble());
|
2013-01-22 21:53:45 +01:00
|
|
|
e.skipCurrentElement();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "trailingSpace") {
|
2013-01-11 18:10:18 +01:00
|
|
|
qDebug("ChordRest: trailingSpace obsolete"); // _extraTrailingSpace = Spatium(val.toDouble());
|
2013-01-22 21:53:45 +01:00
|
|
|
e.skipCurrentElement();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "Beam") {
|
2013-01-11 18:10:18 +01:00
|
|
|
int id = e.readInt();
|
2013-01-21 20:21:41 +01:00
|
|
|
Beam* beam = e.findBeam(id);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (beam)
|
|
|
|
beam->add(this); // also calls this->setBeam(beam)
|
|
|
|
else
|
2013-01-11 18:10:18 +01:00
|
|
|
qDebug("Beam id %d not found", id);
|
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;
|
2014-06-24 18:36:02 +02:00
|
|
|
if ((type() == Element::Type::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());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "move")
|
2013-01-11 18:10:18 +01:00
|
|
|
_staffMove = e.readInt();
|
2014-07-18 18:14:46 +02:00
|
|
|
else if (tag == "Slur") {
|
|
|
|
int id = e.intAttribute("id");
|
|
|
|
if (id == 0)
|
|
|
|
id = e.intAttribute("number"); // obsolete
|
2014-07-21 13:24:21 +02:00
|
|
|
Spanner* spanner = e.findSpanner(id);
|
2014-07-18 18:14:46 +02:00
|
|
|
if (!spanner)
|
|
|
|
qDebug("ChordRest::read(): Slur id %d not found", id);
|
|
|
|
else {
|
|
|
|
QString atype(e.attribute("type"));
|
|
|
|
if (atype == "start") {
|
2014-08-07 10:18:50 +02:00
|
|
|
spanner->setTick(e.tick());
|
2014-08-23 12:31:15 +02:00
|
|
|
if (spanner->ticks() > 0) // stop has been read first, ticks is tick2 - (-1)
|
|
|
|
spanner->setTick2(spanner->ticks() - 1);
|
2014-08-07 10:18:50 +02:00
|
|
|
spanner->setTrack(track());
|
|
|
|
if (spanner->type() == Element::Type::SLUR)
|
|
|
|
spanner->setStartElement(this);
|
2014-07-30 12:34:56 +02:00
|
|
|
if (e.pasteMode()) {
|
2014-08-07 10:18:50 +02:00
|
|
|
for (Element* e : spanner->linkList()) {
|
|
|
|
if (e == spanner)
|
2014-07-30 12:34:56 +02:00
|
|
|
continue;
|
2014-08-07 10:18:50 +02:00
|
|
|
Spanner* ls = static_cast<Spanner*>(e);
|
|
|
|
ls->setTick(spanner->tick());
|
2014-07-30 12:34:56 +02:00
|
|
|
for (Element* ee : linkList()) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(ee);
|
|
|
|
if (cr->score() == ee->score() && cr->staffIdx() == ls->staffIdx()) {
|
|
|
|
ls->setTrack(cr->track());
|
2014-08-07 10:18:50 +02:00
|
|
|
if (ls->type() == Element::Type::SLUR)
|
|
|
|
ls->setStartElement(cr);
|
2014-07-30 12:34:56 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-18 18:14:46 +02:00
|
|
|
}
|
|
|
|
else if (atype == "stop") {
|
2014-08-07 10:18:50 +02:00
|
|
|
spanner->setTick2(e.tick());
|
|
|
|
spanner->setTrack2(track());
|
|
|
|
if (spanner->type() == Element::Type::SLUR)
|
|
|
|
spanner->setEndElement(this);
|
|
|
|
Chord* start = static_cast<Chord*>(spanner->startElement());
|
2014-07-18 18:14:46 +02:00
|
|
|
if (start)
|
2014-08-07 10:18:50 +02:00
|
|
|
spanner->setTrack(start->track());
|
2014-07-30 12:34:56 +02:00
|
|
|
if (e.pasteMode()) {
|
2014-08-07 10:18:50 +02:00
|
|
|
for (Element* e : spanner->linkList()) {
|
|
|
|
if (e == spanner)
|
2014-07-30 12:34:56 +02:00
|
|
|
continue;
|
2014-08-07 10:18:50 +02:00
|
|
|
Spanner* ls = static_cast<Spanner*>(e);
|
|
|
|
ls->setTick2(spanner->tick2());
|
2014-07-30 12:34:56 +02:00
|
|
|
for (Element* ee : linkList()) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(ee);
|
|
|
|
if (cr->score() == ee->score() && cr->staffIdx() == ls->staffIdx()) {
|
|
|
|
ls->setTrack2(cr->track());
|
2014-08-07 10:18:50 +02:00
|
|
|
if (ls->type() == Element::Type::SLUR)
|
|
|
|
ls->setEndElement(cr);
|
2014-07-30 12:34:56 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-18 18:14:46 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
qDebug("ChordRest::read(): unknown Slur type <%s>", qPrintable(atype));
|
|
|
|
}
|
|
|
|
e.readNext();
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "Lyrics" /*|| tag == "FiguredBass"*/) {
|
2013-01-18 10:55:52 +01:00
|
|
|
Element* element = Element::name2Element(tag, score());
|
2013-01-21 20:21:41 +01:00
|
|
|
element->setTrack(e.track());
|
2012-05-26 14:26:10 +02:00
|
|
|
element->read(e);
|
|
|
|
add(element);
|
|
|
|
}
|
2013-08-13 19:31:50 +02:00
|
|
|
else if (tag == "pos") {
|
|
|
|
QPointF pt = e.readPoint();
|
|
|
|
if (score()->mscVersion() > 114)
|
|
|
|
setUserOff(pt * spatium());
|
|
|
|
}
|
2014-05-06 15:47:57 +02:00
|
|
|
else if (tag == "offset") {
|
2014-05-06 17:05:27 +02:00
|
|
|
if (score()->mscVersion() > 114) // || voice() >= 2) {
|
2014-05-06 15:47:57 +02:00
|
|
|
DurationElement::readProperties(e);
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (type() == Element::Type::REST) {
|
2014-05-06 15:47:57 +02:00
|
|
|
DurationElement::readProperties(e);
|
|
|
|
setUserXoffset(0.0); // honor Y offset but not X for rests in older scores
|
|
|
|
}
|
2014-05-06 17:05:27 +02:00
|
|
|
else
|
2014-05-06 15:47:57 +02:00
|
|
|
e.skipCurrentElement(); // ignore manual layout otherwise
|
|
|
|
}
|
2013-05-21 09:44:08 +02:00
|
|
|
else if (DurationElement::readProperties(e))
|
|
|
|
return true;
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// 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)
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
undoChangeProperty(P_ID::SMALL, val);
|
2014-05-09 11:04:15 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// layoutArticulations
|
|
|
|
// called from chord()->layout()
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChordRest::layoutArticulations()
|
|
|
|
{
|
2012-11-20 20:51:18 +01:00
|
|
|
if (parent() == 0 || _articulations.isEmpty())
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
|
|
|
qreal _spatium = spatium();
|
2013-03-09 09:58:43 +01:00
|
|
|
qreal _spStaff = _spatium * staff()->lineDistance(); // scaled to staff line distance for vert. pos. within a staff
|
2013-08-06 19:28:04 +02:00
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
if (type() == Element::Type::CHORD) {
|
2012-11-20 20:51:18 +01:00
|
|
|
if (_articulations.size() == 1) {
|
|
|
|
static_cast<Chord*>(this)->layoutArticulation(_articulations[0]);
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
|
|
|
}
|
2012-11-20 20:51:18 +01:00
|
|
|
if (_articulations.size() == 2) {
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
// staccato | tenuto + marcato
|
|
|
|
//
|
2012-11-20 20:51:18 +01:00
|
|
|
Articulation* a1 = _articulations[0];
|
|
|
|
Articulation* a2 = _articulations[1];
|
2013-03-05 20:23:59 +01:00
|
|
|
ArticulationType st1 = a1->articulationType();
|
|
|
|
ArticulationType st2 = a2->articulationType();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-05-26 21:55:26 +02:00
|
|
|
if ((st2 == ArticulationType::Tenuto || st2 == ArticulationType::Staccato)
|
|
|
|
&& (st1 == ArticulationType::Marcato)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
qSwap(a1, a2);
|
|
|
|
qSwap(st1, st2);
|
|
|
|
}
|
2014-05-26 21:55:26 +02:00
|
|
|
if ((st1 == ArticulationType::Tenuto || st1 == ArticulationType::Staccato)
|
|
|
|
&& (st2 == ArticulationType::Marcato)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
QPointF pt = static_cast<Chord*>(this)->layoutArticulation(a1);
|
2013-03-09 09:58:43 +01:00
|
|
|
pt.ry() += a1->up() ? -_spStaff * .5 : _spStaff * .5;
|
2012-07-30 16:22:56 +02:00
|
|
|
a2->layout();
|
2012-05-26 14:26:10 +02:00
|
|
|
a2->setUp(a1->up());
|
|
|
|
a2->setPos(pt);
|
|
|
|
a2->adjustReadPos();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// staccato | tenuto + sforzato
|
|
|
|
//
|
2014-05-26 21:55:26 +02:00
|
|
|
if ((st2 == ArticulationType::Tenuto || st2 == ArticulationType::Staccato)
|
|
|
|
&& (st1 == ArticulationType::Sforzatoaccent)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
qSwap(a1, a2);
|
|
|
|
qSwap(st1, st2);
|
|
|
|
}
|
2014-05-26 21:55:26 +02:00
|
|
|
if ((st1 == ArticulationType::Tenuto || st1 == ArticulationType::Staccato)
|
|
|
|
&& (st2 == ArticulationType::Sforzatoaccent)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
QPointF pt = static_cast<Chord*>(this)->layoutArticulation(a1);
|
2013-03-09 09:58:43 +01:00
|
|
|
pt.ry() += a1->up() ? -_spStaff * .7 : _spStaff * .7;
|
2012-07-30 16:22:56 +02:00
|
|
|
a2->layout();
|
2012-05-26 14:26:10 +02:00
|
|
|
a2->setUp(a1->up());
|
|
|
|
a2->setPos(pt);
|
|
|
|
a2->adjustReadPos();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-06 19:28:04 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
qreal x = centerX();
|
2014-05-26 15:31:36 +02:00
|
|
|
qreal distance0 = score()->styleS(StyleIdx::propertyDistance).val() * _spatium;
|
|
|
|
qreal distance1 = score()->styleS(StyleIdx::propertyDistanceHead).val() * _spatium;
|
|
|
|
qreal distance2 = score()->styleS(StyleIdx::propertyDistanceStem).val() * _spatium;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
qreal chordTopY = upPos(); // note position of highest note
|
|
|
|
qreal chordBotY = downPos(); // note position of lowest note
|
|
|
|
|
|
|
|
qreal staffTopY = -distance2;
|
|
|
|
qreal staffBotY = staff()->height() + distance2;
|
|
|
|
|
|
|
|
// avoid collisions of staff articulations with chord notes:
|
|
|
|
// gap between note and staff articulation is distance0 + 0.5 spatium
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
if (type() == Element::Type::CHORD) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Chord* chord = static_cast<Chord*>(this);
|
|
|
|
Stem* stem = chord->stem();
|
|
|
|
if (stem) {
|
|
|
|
qreal y = stem->pos().y() + pos().y();
|
|
|
|
if (up() && stem->stemLen() < 0.0)
|
|
|
|
y += stem->stemLen();
|
|
|
|
else if (!up() && stem->stemLen() > 0.0)
|
|
|
|
y -= stem->stemLen();
|
2013-01-02 09:29:17 +01:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
if (beam()) {
|
2014-05-26 15:31:36 +02:00
|
|
|
qreal bw = score()->styleS(StyleIdx::beamWidth).val() * _spatium;
|
2012-05-26 14:26:10 +02:00
|
|
|
y += up() ? -bw : bw;
|
|
|
|
}
|
|
|
|
if (up())
|
|
|
|
staffTopY = qMin(staffTopY, qreal(y - 0.5 * _spatium));
|
|
|
|
else
|
|
|
|
staffBotY = qMax(staffBotY, qreal(y + 0.5 * _spatium));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
staffTopY = qMin(staffTopY, qreal(chordTopY - distance0 - 0.5 * _spatium));
|
|
|
|
staffBotY = qMax(staffBotY, qreal(chordBotY + distance0 + 0.5 * _spatium));
|
|
|
|
|
|
|
|
qreal dy = 0.0;
|
|
|
|
|
2013-01-02 09:29:17 +01:00
|
|
|
int n = _articulations.size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
Articulation* a = _articulations.at(i);
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
2014-06-26 10:53:57 +02:00
|
|
|
// determine MScore::Direction
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
2014-06-26 10:53:57 +02:00
|
|
|
if (a->direction() != MScore::Direction::AUTO) {
|
|
|
|
a->setUp(a->direction() == MScore::Direction::UP);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-05-21 15:37:28 +02:00
|
|
|
if (a->anchor() == ArticulationAnchor::CHORD)
|
2012-05-26 14:26:10 +02:00
|
|
|
a->setUp(!up());
|
|
|
|
else
|
2014-05-21 15:37:28 +02:00
|
|
|
a->setUp(a->anchor() == ArticulationAnchor::TOP_STAFF || a->anchor() == ArticulationAnchor::TOP_CHORD);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// pass 1
|
|
|
|
// place tenuto and staccato
|
|
|
|
//
|
|
|
|
|
2013-01-02 09:29:17 +01:00
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
Articulation* a = _articulations.at(i);
|
2012-05-26 14:26:10 +02:00
|
|
|
a->layout();
|
|
|
|
ArticulationAnchor aa = a->anchor();
|
|
|
|
|
2014-05-26 21:55:26 +02:00
|
|
|
if ((a->articulationType() != ArticulationType::Tenuto)
|
|
|
|
&& (a->articulationType() != ArticulationType::Staccato))
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
|
2014-05-21 15:37:28 +02:00
|
|
|
if (aa != ArticulationAnchor::CHORD && aa != ArticulationAnchor::TOP_CHORD && aa != ArticulationAnchor::BOTTOM_CHORD)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
bool bottom;
|
2014-05-21 15:37:28 +02:00
|
|
|
if ((aa == ArticulationAnchor::CHORD) && measure()->hasVoices(a->staffIdx()))
|
2012-05-26 14:26:10 +02:00
|
|
|
bottom = !up();
|
|
|
|
else
|
2014-05-21 15:37:28 +02:00
|
|
|
bottom = (aa == ArticulationAnchor::BOTTOM_CHORD) || (aa == ArticulationAnchor::CHORD && up());
|
2012-05-26 14:26:10 +02:00
|
|
|
bool headSide = bottom == up();
|
|
|
|
|
|
|
|
dy += distance1;
|
|
|
|
qreal y;
|
|
|
|
Chord* chord = static_cast<Chord*>(this);
|
|
|
|
if (bottom) {
|
|
|
|
int line = downLine();
|
|
|
|
y = chordBotY + dy;
|
2014-06-24 18:36:02 +02:00
|
|
|
if (!headSide && type() == Element::Type::CHORD && chord->stem()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Stem* stem = chord->stem();
|
|
|
|
y = chordTopY + stem->stemLen();
|
|
|
|
if (chord->beam())
|
2014-05-26 15:31:36 +02:00
|
|
|
y += score()->styleS(StyleIdx::beamWidth).val() * _spatium * .5;
|
2014-12-28 23:41:09 +01:00
|
|
|
// aligning horizontally to stem makes sense only for staccato
|
|
|
|
// and only if no other articulations on this side
|
|
|
|
//x = stem->pos().x();
|
2012-05-26 14:26:10 +02:00
|
|
|
int line = lrint((y+0.5*_spatium) / _spatium);
|
|
|
|
if (line <= 4) // align between staff lines
|
|
|
|
y = line * _spatium + _spatium * .5;
|
|
|
|
else
|
|
|
|
y += _spatium;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int lines = (staff()->lines() - 1) * 2;
|
|
|
|
if (line < lines)
|
|
|
|
y = (line & ~1) + 3;
|
|
|
|
else
|
|
|
|
y = line + 2;
|
|
|
|
y *= _spatium * .5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int line = upLine();
|
|
|
|
y = chordTopY - dy;
|
2014-06-24 18:36:02 +02:00
|
|
|
if (!headSide && type() == Element::Type::CHORD && chord->stem()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Stem* stem = chord->stem();
|
|
|
|
y = chordBotY + stem->stemLen();
|
|
|
|
if (chord->beam())
|
2014-05-26 15:31:36 +02:00
|
|
|
y -= score()->styleS(StyleIdx::beamWidth).val() * _spatium * .5;
|
2014-12-28 23:41:09 +01:00
|
|
|
// aligning horizontally to stem makes sense only for staccato
|
|
|
|
// and only if no other articulations on this side
|
|
|
|
//x = stem->pos().x();
|
2012-05-26 14:26:10 +02:00
|
|
|
int line = lrint((y-0.5*_spatium) / _spatium);
|
|
|
|
if (line >= 0) // align between staff lines
|
|
|
|
y = line * _spatium - _spatium * .5;
|
|
|
|
else
|
|
|
|
y -= _spatium;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (line > 0)
|
|
|
|
y = ((line+1) & ~1) - 3;
|
|
|
|
else
|
|
|
|
y = line - 2;
|
|
|
|
y *= _spatium * .5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dy += _spatium * .5;
|
|
|
|
a->setPos(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
// reserve space for slur
|
|
|
|
bool botGap = false;
|
|
|
|
bool topGap = false;
|
2013-01-02 09:29:17 +01:00
|
|
|
|
2013-07-05 11:23:52 +02:00
|
|
|
#if 0 // TODO-S: optimize
|
2013-01-03 16:56:56 +01:00
|
|
|
for (Spanner* sp = _spannerFor; sp; sp = sp->next()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (sp->type() != SLUR)
|
|
|
|
continue;
|
|
|
|
Slur* s = static_cast<Slur*>(sp);
|
|
|
|
if (s->up())
|
|
|
|
topGap = true;
|
|
|
|
else
|
|
|
|
botGap = true;
|
|
|
|
}
|
2013-01-03 16:56:56 +01:00
|
|
|
for (Spanner* sp = _spannerBack; sp; sp = sp->next()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (sp->type() != SLUR)
|
|
|
|
continue;
|
|
|
|
Slur* s = static_cast<Slur*>(sp);
|
|
|
|
if (s->up())
|
|
|
|
topGap = true;
|
|
|
|
else
|
|
|
|
botGap = true;
|
|
|
|
}
|
2013-06-10 11:03:34 +02:00
|
|
|
#endif
|
2012-05-26 14:26:10 +02:00
|
|
|
if (botGap)
|
|
|
|
chordBotY += _spatium;
|
|
|
|
if (topGap)
|
|
|
|
chordTopY -= _spatium;
|
|
|
|
|
|
|
|
//
|
|
|
|
// pass 2
|
|
|
|
// place all articulations with anchor at chord/rest
|
|
|
|
//
|
2013-01-02 09:29:17 +01:00
|
|
|
n = _articulations.size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
Articulation* a = _articulations.at(i);
|
2012-05-26 14:26:10 +02:00
|
|
|
a->layout();
|
|
|
|
ArticulationAnchor aa = a->anchor();
|
2014-05-26 21:55:26 +02:00
|
|
|
if ((a->articulationType() == ArticulationType::Tenuto)
|
|
|
|
|| (a->articulationType() == ArticulationType::Staccato))
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
|
2014-05-21 15:37:28 +02:00
|
|
|
if (aa != ArticulationAnchor::CHORD && aa != ArticulationAnchor::TOP_CHORD && aa != ArticulationAnchor::BOTTOM_CHORD)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// for tenuto and staccate check for staff line collision
|
2014-05-26 21:55:26 +02:00
|
|
|
bool staffLineCT = a->articulationType() == ArticulationType::Tenuto
|
|
|
|
|| a->articulationType() == ArticulationType::Staccato;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
// qreal sh = a->bbox().height() * mag();
|
2014-05-21 15:37:28 +02:00
|
|
|
bool bottom = (aa == ArticulationAnchor::BOTTOM_CHORD) || (aa == ArticulationAnchor::CHORD && up());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
dy += distance1;
|
|
|
|
if (bottom) {
|
|
|
|
qreal y = chordBotY + dy;
|
|
|
|
if (staffLineCT && (y <= staffBotY -.1 - dy)) {
|
|
|
|
qreal l = y / _spatium;
|
|
|
|
qreal delta = fabs(l - round(l));
|
|
|
|
if (delta < 0.4) {
|
|
|
|
y += _spatium * .5;
|
|
|
|
dy += _spatium * .5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
a->setPos(x, y); // - a->bbox().y() + a->bbox().height() * .5);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
qreal y = chordTopY - dy;
|
|
|
|
if (staffLineCT && (y >= (staffTopY +.1 + dy))) {
|
|
|
|
qreal l = y / _spatium;
|
|
|
|
qreal delta = fabs(l - round(l));
|
|
|
|
if (delta < 0.4) {
|
|
|
|
y -= _spatium * .5;
|
|
|
|
dy += _spatium * .5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
a->setPos(x, y); // + a->bbox().y() - a->bbox().height() * .5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// pass 3
|
|
|
|
// now place all articulations with staff top or bottom anchor
|
|
|
|
//
|
|
|
|
qreal dyTop = staffTopY;
|
|
|
|
qreal dyBot = staffBotY;
|
|
|
|
|
|
|
|
/* if ((upPos() - _spatium) < dyTop)
|
|
|
|
dyTop = upPos() - _spatium;
|
|
|
|
if ((downPos() + _spatium) > dyBot)
|
|
|
|
dyBot = downPos() + _spatium;
|
|
|
|
*/
|
2013-01-02 09:29:17 +01:00
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
Articulation* a = _articulations.at(i);
|
2012-05-26 14:26:10 +02:00
|
|
|
ArticulationAnchor aa = a->anchor();
|
2014-05-21 15:37:28 +02:00
|
|
|
if (aa == ArticulationAnchor::TOP_STAFF || aa == ArticulationAnchor::BOTTOM_STAFF) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (a->up()) {
|
|
|
|
a->setPos(x, dyTop);
|
|
|
|
dyTop -= distance0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a->setPos(x, dyBot);
|
|
|
|
dyBot += distance0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
a->adjustReadPos();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// drop
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Element* ChordRest::drop(const DropData& data)
|
|
|
|
{
|
|
|
|
Element* e = data.element;
|
|
|
|
Measure* m = measure();
|
|
|
|
switch (e->type()) {
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::BREATH:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
Breath* b = static_cast<Breath*>(e);
|
|
|
|
b->setTrack(staffIdx() * VOICES);
|
|
|
|
|
|
|
|
// TODO: insert automatically in all staves?
|
|
|
|
|
2014-06-25 11:46:10 +02:00
|
|
|
Segment* seg = m->undoGetSegment(Segment::Type::Breath, tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
b->setParent(seg);
|
|
|
|
score()->undoAddElement(b);
|
|
|
|
}
|
|
|
|
return e;
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::BAR_LINE:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
BarLine* bl = static_cast<BarLine*>(e);
|
|
|
|
bl->setTrack(staffIdx() * VOICES);
|
|
|
|
|
|
|
|
if (tick() == m->tick())
|
|
|
|
return m->drop(data);
|
|
|
|
|
2014-12-22 13:28:09 +01:00
|
|
|
BarLine* obl = 0;
|
|
|
|
for (Staff* st : staff()->staffList()) {
|
|
|
|
Score* score = st->score();
|
|
|
|
Measure* measure = score->tick2measure(m->tick());
|
|
|
|
Segment* seg = measure->undoGetSegment(Segment::Type::BarLine, tick());
|
|
|
|
BarLine* l;
|
|
|
|
if (obl == 0)
|
|
|
|
obl = l = bl->clone();
|
|
|
|
else
|
|
|
|
l = static_cast<BarLine*>(obl->linkedClone());
|
|
|
|
l->setTrack(st->idx() * VOICES);
|
|
|
|
l->setScore(score);
|
|
|
|
l->setParent(seg);
|
|
|
|
score->undoAddElement(l);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-12-22 13:28:09 +01:00
|
|
|
delete e;
|
|
|
|
return 0;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::CLEF:
|
2014-07-25 17:13:27 +02:00
|
|
|
score()->cmdInsertClef(static_cast<Clef*>(e), this);
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::TEMPO_TEXT:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
TempoText* tt = static_cast<TempoText*>(e);
|
|
|
|
tt->setParent(segment());
|
2014-07-03 11:22:42 +02:00
|
|
|
TextStyleType st = tt->textStyleType();
|
2014-03-14 11:30:19 +01:00
|
|
|
tt->setTextStyleType(st);
|
2012-05-26 14:26:10 +02:00
|
|
|
score()->undoAddElement(tt);
|
|
|
|
}
|
|
|
|
return e;
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::DYNAMIC:
|
2014-07-26 18:01:53 +02:00
|
|
|
{
|
|
|
|
Dynamic* d = static_cast<Dynamic*>(e);
|
|
|
|
d->setTrack(track());
|
|
|
|
TextStyleType st = d->textStyleType();
|
|
|
|
d->setTextStyleType(st);
|
|
|
|
d->setParent(segment());
|
|
|
|
score()->undoAddElement(d);
|
|
|
|
}
|
|
|
|
return e;
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::FRET_DIAGRAM:
|
2014-08-26 15:07:24 +02:00
|
|
|
case Element::Type::TREMOLOBAR:
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::SYMBOL:
|
2012-05-26 14:26:10 +02:00
|
|
|
e->setTrack(track());
|
|
|
|
e->setParent(segment());
|
|
|
|
score()->undoAddElement(e);
|
|
|
|
return e;
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::NOTE:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
Note* note = static_cast<Note*>(e);
|
|
|
|
NoteVal nval;
|
|
|
|
nval.pitch = note->pitch();
|
|
|
|
nval.headGroup = note->headGroup();
|
2014-08-19 22:17:58 +02:00
|
|
|
nval.fret = note->fret();
|
|
|
|
nval.string = note->string();
|
2014-06-26 10:53:57 +02:00
|
|
|
score()->setNoteRest(segment(), track(), nval, data.duration, MScore::Direction::AUTO);
|
2012-05-26 14:26:10 +02:00
|
|
|
delete e;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::HARMONY:
|
2012-05-26 14:26:10 +02:00
|
|
|
static_cast<Harmony*>(e)->render();
|
|
|
|
// fall through
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::TEXT:
|
|
|
|
case Element::Type::STAFF_TEXT:
|
|
|
|
case Element::Type::STAFF_STATE:
|
|
|
|
case Element::Type::INSTRUMENT_CHANGE:
|
|
|
|
case Element::Type::REHEARSAL_MARK:
|
2012-05-26 14:26:10 +02:00
|
|
|
e->setParent(segment());
|
|
|
|
e->setTrack((track() / VOICES) * VOICES);
|
2012-10-25 16:21:07 +02:00
|
|
|
{
|
|
|
|
Text* f = static_cast<Text*>(e);
|
2014-07-03 11:22:42 +02:00
|
|
|
TextStyleType st = f->textStyleType();
|
2014-05-30 10:13:29 +02:00
|
|
|
if (st >= TextStyleType::DEFAULT)
|
2013-04-11 13:30:34 +02:00
|
|
|
f->setTextStyleType(st);
|
2014-11-15 16:29:48 +01:00
|
|
|
if (e->type() == Element::Type::REHEARSAL_MARK)
|
2014-12-09 08:45:30 +01:00
|
|
|
f->setText(score()->createRehearsalMarkText(static_cast<RehearsalMark*>(e)));
|
2012-10-25 16:21:07 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
score()->undoAddElement(e);
|
|
|
|
return e;
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::FIGURED_BASS:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
bool bNew;
|
|
|
|
FiguredBass * fb = static_cast<FiguredBass *>(e);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::IMAGE:
|
2012-05-26 14:26:10 +02:00
|
|
|
e->setParent(segment());
|
|
|
|
score()->undoAddElement(e);
|
|
|
|
return e;
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::ICON:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-03-05 20:23:59 +01:00
|
|
|
switch(static_cast<Icon*>(e)->iconType()) {
|
2014-05-30 10:14:57 +02:00
|
|
|
case IconType::SBEAM:
|
2014-06-26 07:45:09 +02:00
|
|
|
score()->undoChangeProperty(this, P_ID::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:
|
2014-06-26 07:45:09 +02:00
|
|
|
score()->undoChangeProperty(this, P_ID::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:
|
2014-06-26 07:45:09 +02:00
|
|
|
score()->undoChangeProperty(this, P_ID::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:
|
2014-06-26 07:45:09 +02:00
|
|
|
score()->undoChangeProperty(this, P_ID::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:
|
2014-06-26 07:45:09 +02:00
|
|
|
score()->undoChangeProperty(this, P_ID::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:
|
2014-06-26 07:45:09 +02:00
|
|
|
score()->undoChangeProperty(this, P_ID::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;
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void ChordRest::setDurationType(const TDuration& v)
|
|
|
|
{
|
|
|
|
_durationType = v;
|
2014-05-21 15:41:23 +02:00
|
|
|
_crossMeasure = CrossMeasure::UNKNOWN;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-07-10 14:13:37 +02:00
|
|
|
QString ChordRest::durationUserName()
|
|
|
|
{
|
|
|
|
QString tupletType = "";
|
|
|
|
if(tuplet()) {
|
|
|
|
switch (tuplet()->ratio().numerator()) {
|
|
|
|
case 2:
|
2014-11-05 15:10:09 +01:00
|
|
|
tupletType = tr("Duplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2014-11-05 15:10:09 +01:00
|
|
|
tupletType = tr("Triplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
2014-11-05 15:10:09 +01:00
|
|
|
tupletType = tr("Quadruplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
case 5:
|
2014-11-05 15:10:09 +01:00
|
|
|
tupletType = tr("Quintuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
case 6:
|
2014-11-05 15:10:09 +01:00
|
|
|
tupletType = tr("Sextuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
case 7:
|
2014-11-05 15:10:09 +01:00
|
|
|
tupletType = tr("Septuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
case 8:
|
2014-11-05 15:10:09 +01:00
|
|
|
tupletType = tr("Octuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
case 9:
|
2014-11-05 15:10:09 +01:00
|
|
|
tupletType = tr("Nonuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
default:
|
2014-11-05 15:10:09 +01:00
|
|
|
tupletType = tr("Custom Tuplet");
|
2014-07-10 14:13:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
QString dotString = "";
|
|
|
|
|
|
|
|
switch (dots()) {
|
|
|
|
case 1:
|
2015-01-17 18:46:43 +01:00
|
|
|
dotString += " " + tr("Dotted %1").arg(durationType().durationTypeUserName()).trimmed();
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2015-01-17 18:46:43 +01:00
|
|
|
dotString += " " + tr("Double dotted %1").arg(durationType().durationTypeUserName()).trimmed();
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2015-01-17 18:46:43 +01:00
|
|
|
dotString += " " + tr("Triple dotted %1").arg(durationType().durationTypeUserName()).trimmed();
|
2014-07-10 14:13:37 +02:00
|
|
|
break;
|
|
|
|
}
|
2015-01-17 18:46:43 +01:00
|
|
|
return QString("%2%3").arg(tupletType).arg(dotString);
|
2014-07-10 14:13:37 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// setTrack
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChordRest::setTrack(int val)
|
|
|
|
{
|
2012-11-20 20:51:18 +01:00
|
|
|
foreach(Articulation* a, _articulations)
|
2012-05-26 14:26:10 +02:00
|
|
|
a->setTrack(val);
|
|
|
|
Element::setTrack(val);
|
2014-06-24 18:36:02 +02:00
|
|
|
if (type() == Element::Type::CHORD) {
|
2012-05-26 14:26:10 +02:00
|
|
|
foreach(Note* n, static_cast<Chord*>(this)->notes())
|
|
|
|
n->setTrack(val);
|
|
|
|
}
|
|
|
|
if (_beam)
|
|
|
|
_beam->setTrack(val);
|
2012-09-24 10:54:08 +02:00
|
|
|
foreach(Lyrics* l, _lyricsList) {
|
|
|
|
if (l)
|
|
|
|
l->setTrack(val);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
if (tuplet())
|
|
|
|
tuplet()->setTrack(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// tick
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
int ChordRest::tick() const
|
|
|
|
{
|
|
|
|
return segment() ? segment()->tick() : -1;
|
|
|
|
}
|
|
|
|
|
2013-04-29 15:31:22 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// rtick
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
int ChordRest::rtick() const
|
|
|
|
{
|
|
|
|
return segment() ? segment()->rtick() : -1;
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// add
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChordRest::add(Element* e)
|
|
|
|
{
|
|
|
|
e->setParent(this);
|
|
|
|
e->setTrack(track());
|
|
|
|
switch(e->type()) {
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::ARTICULATION:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
Articulation* a = static_cast<Articulation*>(e);
|
2012-11-20 20:51:18 +01:00
|
|
|
_articulations.push_back(a);
|
2013-06-03 14:39:59 +02:00
|
|
|
if (a->timeStretch() != 1.0)
|
|
|
|
score()->fixTicks(); // update tempo map
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
break;
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::LYRICS:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
Lyrics* l = static_cast<Lyrics*>(e);
|
|
|
|
int size = _lyricsList.size();
|
|
|
|
if (l->no() >= size) {
|
|
|
|
for (int i = size-1; i < l->no(); ++i)
|
|
|
|
_lyricsList.append(0);
|
|
|
|
}
|
|
|
|
_lyricsList[l->no()] = l;
|
|
|
|
}
|
|
|
|
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()) {
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::ARTICULATION:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
Articulation* a = static_cast<Articulation*>(e);
|
2012-11-20 20:51:18 +01:00
|
|
|
if (!_articulations.removeOne(a))
|
2012-05-26 14:26:10 +02:00
|
|
|
qDebug("ChordRest::remove(): articulation not found");
|
2013-06-03 14:39:59 +02:00
|
|
|
if (a->timeStretch() != 1.0)
|
|
|
|
score()->fixTicks(); // update tempo map
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
break;
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::LYRICS:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
for (int i = 0; i < _lyricsList.size(); ++i) {
|
|
|
|
if (_lyricsList[i] != e)
|
|
|
|
continue;
|
Lyrics multi-system melisma and dashes
Implements melisma and dash lines for lyrics spanning several systems.
The melisma and dash line is based on the `SLine` class and its segments on the `LineSegment` class. Both the whole line and its segments are not selectable, marked as generated and not saved in the score file, which is not changed in any way.
For very wide dash segments, several dashes are drawn; the distance between the dashes is not configurable.
Lyrics layout code in `Measure` class and in `layout.cpp` file has been commented out as the lyrics line layout is all contained in the lyrics.cpp file
The line is registered with the `Score` (to have its layout delayed until all elements are positioned) with a mechanism similar to other `Spanner`'s, but in a different container (`_unmanagedSpanner`), as the owning `Lyrics` should decide when create, register, unregister and delete its line.
The line segments are registered with the `System` they belong to (to have them drawn), in the same way as other `Spanner`'s.
There is code for using the dash metrics of the lyrics font, but it is turned off via a conditional directive, as there does not seem to be a reliable way to determine the dash metrics; conventional values (determined by trials and errors and based on my taste!) are used when the conditional directive is off.
2015-01-11 10:11:44 +01:00
|
|
|
_lyricsList[i]->removeFromScore();
|
2012-05-26 14:26:10 +02:00
|
|
|
_lyricsList[i] = 0;
|
|
|
|
while (!_lyricsList.isEmpty() && _lyricsList.back() == 0)
|
|
|
|
_lyricsList.takeLast();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qDebug("ChordRest::remove: %s %p not found", e->name(), e);
|
|
|
|
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
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-07-11 12:25:25 +02: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);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (b->isEmpty())
|
2013-05-22 15:20:14 +02:00
|
|
|
score()->undoRemoveElement(b);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-06-24 18:36:02 +02:00
|
|
|
if (!beamed && type() == Element::Type::CHORD)
|
2013-07-14 12:02:55 +02:00
|
|
|
static_cast<Chord*>(this)->layoutHook1();
|
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
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
undoChangeProperty(P_ID::BEAM_MODE, int(mode));
|
2013-03-01 10:07:27 +01:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// getProperty
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QVariant ChordRest::getProperty(P_ID propertyId) const
|
|
|
|
{
|
|
|
|
switch(propertyId) {
|
2014-08-20 09:50:42 +02:00
|
|
|
case P_ID::SMALL: return QVariant(small());
|
|
|
|
case P_ID::BEAM_MODE: return int(beamMode());
|
|
|
|
case P_ID::STAFF_MOVE: return staffMove();
|
|
|
|
default: return DurationElement::getProperty(propertyId);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setProperty
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool ChordRest::setProperty(P_ID propertyId, const QVariant& v)
|
|
|
|
{
|
|
|
|
switch(propertyId) {
|
2014-08-20 09:50:42 +02:00
|
|
|
case P_ID::SMALL: setSmall(v.toBool()); break;
|
|
|
|
case P_ID::BEAM_MODE: setBeamMode(Beam::Mode(v.toInt())); break;
|
|
|
|
case P_ID::STAFF_MOVE: setStaffMove(v.toInt()); break;
|
|
|
|
default: return DurationElement::setProperty(propertyId, v);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
score()->setLayoutAll(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-08-12 11:44:36 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// propertyDefault
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QVariant ChordRest::propertyDefault(P_ID propertyId) const
|
|
|
|
{
|
|
|
|
switch(propertyId) {
|
2014-08-20 09:50:42 +02:00
|
|
|
case P_ID::SMALL: return false;
|
|
|
|
case P_ID::BEAM_MODE: return int(Beam::Mode::AUTO);
|
|
|
|
case P_ID::STAFF_MOVE: return 0;
|
2012-08-12 11:44:36 +02:00
|
|
|
default: return DurationElement::propertyDefault(propertyId);
|
|
|
|
}
|
|
|
|
score()->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
2013-06-19 16:25:29 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// isGrace
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-06-16 23:33:37 +02:00
|
|
|
bool ChordRest::isGrace() const
|
|
|
|
{
|
2014-06-24 18:36:02 +02:00
|
|
|
return type() == Element::Type::CHORD && ((Chord*)this)->noteType() != NoteType::NORMAL;
|
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
|
|
|
|
{
|
2014-06-24 18:36:02 +02:00
|
|
|
return (type() == Element::Type::CHORD && (((Chord*)this)->noteType() == NoteType::ACCIACCATURA
|
2014-05-27 10:35:28 +02:00
|
|
|
|| ((Chord*)this)->noteType() == NoteType::APPOGGIATURA
|
|
|
|
|| ((Chord*)this)->noteType() == NoteType::GRACE4
|
|
|
|
|| ((Chord*)this)->noteType() == NoteType::GRACE16
|
|
|
|
|| ((Chord*)this)->noteType() == NoteType::GRACE32));
|
2014-04-23 18:07:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// isGraceAfter
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool ChordRest::isGraceAfter() const
|
|
|
|
{
|
2014-06-24 18:36:02 +02:00
|
|
|
return (type() == Element::Type::CHORD && (((Chord*)this)->noteType() == NoteType::GRACE8_AFTER
|
2014-05-27 10:35:28 +02:00
|
|
|
|| ((Chord*)this)->noteType() == NoteType::GRACE16_AFTER
|
|
|
|
|| ((Chord*)this)->noteType() == NoteType::GRACE32_AFTER));
|
2014-04-23 18:07:38 +02:00
|
|
|
}
|
|
|
|
|
2013-06-19 16:25:29 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// writeBeam
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChordRest::writeBeam(Xml& xml)
|
|
|
|
{
|
|
|
|
Beam* b = beam();
|
|
|
|
#ifndef NDEBUG
|
|
|
|
if (b && b->elements().front() == this && (MScore::testMode || !b->generated())) {
|
|
|
|
b->setId(xml.beamId++);
|
|
|
|
b->write(xml);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (b && !b->generated() && b->elements().front() == this) {
|
|
|
|
b->setId(xml.beamId++);
|
|
|
|
b->write(xml);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-06-30 11:26:58 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// nextSegmentAfterCR
|
|
|
|
// returns first segment at tick CR->tick + CR->actualTicks
|
|
|
|
// of given types
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-05-31 17:22:45 +02:00
|
|
|
Segment* ChordRest::nextSegmentAfterCR(Segment::Type types) const
|
2014-06-30 11:26:58 +02:00
|
|
|
{
|
|
|
|
for (Segment* s = segment()->next1MM(types); s; s = s->next1MM(types)) {
|
|
|
|
// chordrest ends at tick+actualTicks
|
|
|
|
// we return the segment at or after the end of the chordrest
|
|
|
|
if (s->tick() >= tick() + actualTicks())
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2014-06-20 22:48:34 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// nextElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Element* ChordRest::nextElement()
|
|
|
|
{
|
|
|
|
return segment()->firstInNextSegments(staffIdx());
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// prevElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Element* ChordRest::prevElement()
|
|
|
|
{
|
|
|
|
return segment()->lastInPrevSegments(staffIdx());
|
|
|
|
}
|
|
|
|
|
2014-07-10 14:13:37 +02:00
|
|
|
QString ChordRest::accessibleExtraInfo()
|
|
|
|
{
|
|
|
|
QString rez = "";
|
|
|
|
foreach (Articulation* a, articulations())
|
2014-08-21 18:32:52 +02:00
|
|
|
rez = QString("%1 %2").arg(rez).arg(a->screenReaderInfo());
|
2014-07-10 14:13:37 +02:00
|
|
|
|
2014-08-30 01:36:11 +02:00
|
|
|
foreach (Element* l, lyricsList()) {
|
|
|
|
if (!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()) {
|
2014-07-10 14:13:37 +02:00
|
|
|
foreach (Element* e, segment()->annotations()) {
|
|
|
|
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());
|
|
|
|
for (auto i = spanners.begin(); i < spanners.end(); i++) {
|
|
|
|
const ::Interval<Spanner*> interval = *i;
|
2014-07-10 14:13:37 +02:00
|
|
|
Spanner* s = interval.value;
|
|
|
|
if (s->type() == Element::Type::VOLTA || //voltas are added for barlines
|
|
|
|
s->type() == Element::Type::TIE ) //ties are added in notes
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Segment* seg = 0;
|
|
|
|
if (s->type() == Element::Type::SLUR) {
|
2014-08-19 14:10:43 +02:00
|
|
|
if (s->tick() == tick() && s->track() == track())
|
2014-08-21 18:32:52 +02:00
|
|
|
rez = 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())
|
2014-08-21 18:32:52 +02:00
|
|
|
rez = 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())
|
2014-08-21 18:32:52 +02:00
|
|
|
rez = tr("%1 Start of %2").arg(rez).arg(s->screenReaderInfo());
|
2014-07-10 14:13:37 +02:00
|
|
|
seg = segment()->next1MM(Segment::Type::ChordRest);
|
|
|
|
if (!seg)
|
|
|
|
continue;
|
2014-08-19 14:10:43 +02:00
|
|
|
if (s->tick2() == seg->tick() && s->staffIdx() == staffIdx())
|
2014-08-21 18:32:52 +02:00
|
|
|
rez = tr("%1 End of %2").arg(rez).arg(s->screenReaderInfo());
|
2014-07-10 14:13:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rez;
|
|
|
|
}
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|
|
|
|
|