MuseScore/libmscore/trill.cpp

494 lines
15 KiB
C++
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2002-2011 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#include "trill.h"
#include "style.h"
#include "system.h"
#include "measure.h"
#include "xml.h"
#include "utils.h"
#include "sym.h"
#include "score.h"
#include "accidental.h"
#include "segment.h"
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// draw
//---------------------------------------------------------
void TrillSegment::draw(QPainter* painter) const
{
2014-05-07 12:10:28 +02:00
painter->setPen(spanner()->curColor());
2013-11-19 16:06:08 +01:00
drawSymbols(_symbols, painter);
2012-05-26 14:26:10 +02:00
}
2013-08-30 16:03:46 +02:00
//---------------------------------------------------------
// add
//---------------------------------------------------------
void TrillSegment::add(Element* e)
{
e->setParent(this);
if (e->type() == Element::Type::ACCIDENTAL) {
2013-08-30 16:03:46 +02:00
// accidental is part of trill
trill()->setAccidental(static_cast<Accidental*>(e));
}
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void TrillSegment::remove(Element* e)
{
if (trill()->accidental() == e) {
// accidental is part of trill
trill()->setAccidental(0);
}
}
2013-11-19 16:06:08 +01:00
//---------------------------------------------------------
// symbolLine
//---------------------------------------------------------
void TrillSegment::symbolLine(SymId start, SymId fill)
{
qreal x1 = 0;
qreal x2 = pos2().x();
qreal w = x2 - x1;
qreal mag = magS();
ScoreFont* f = score()->scoreFont();
_symbols.clear();
_symbols.append(f->toString(start));
qreal w1 = f->bbox(start, mag).width();
qreal w2 = f->width(fill, mag);
int n = lrint((w - w1) / w2);
for (int i = 0; i < n; ++i)
_symbols.append(f->toString(fill));
QRectF r(f->bbox(_symbols, mag));
setbbox(r);
}
void TrillSegment::symbolLine(SymId start, SymId fill, SymId end)
{
qreal x1 = 0;
qreal x2 = pos2().x();
qreal w = x2 - x1;
qreal mag = magS();
ScoreFont* f = score()->scoreFont();
_symbols.clear();
_symbols.append(f->toString(start));
_symbols.append(f->toString(end));
qreal w1 = f->bbox(start, mag).width();
qreal w2 = f->width(fill, mag);
qreal w3 = f->width(end, mag);
int n = lrint((w - w1 - w3) / w2);
for (int i = 0; i < n; ++i)
_symbols.insert(1, f->toString(fill));
QRectF r(f->bbox(_symbols, mag));
setbbox(r);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void TrillSegment::layout()
{
2012-11-08 12:59:30 +01:00
if (parent())
2014-05-26 15:31:36 +02:00
rypos() += score()->styleS(StyleIdx::trillY).val() * spatium();
if (spannerSegmentType() == SpannerSegmentType::SINGLE || spannerSegmentType() == SpannerSegmentType::BEGIN) {
2013-08-30 16:03:46 +02:00
Accidental* a = trill()->accidental();
if (a) {
a->layout();
a->setMag(a->mag() * .6);
qreal _spatium = spatium();
2013-11-21 12:37:19 +01:00
a->setPos(_spatium * 1.3, -2.2 * _spatium);
2013-08-30 16:03:46 +02:00
a->adjustReadPos();
}
2013-11-19 16:06:08 +01:00
switch (trill()->trillType()) {
2014-05-25 18:51:19 +02:00
case Trill::TrillType::TRILL_LINE:
2013-11-19 16:06:08 +01:00
symbolLine(SymId::ornamentTrill, SymId::wiggleTrill);
break;
2014-05-25 18:51:19 +02:00
case Trill::TrillType::PRALLPRALL_LINE:
case Trill::TrillType::PURE_LINE:
2013-11-19 16:06:08 +01:00
symbolLine(SymId::wiggleTrill, SymId::wiggleTrill);
break;
2014-05-25 18:51:19 +02:00
case Trill::TrillType::UPPRALL_LINE:
2013-11-22 14:29:09 +01:00
if (score()->scoreFont()->isValid(SymId::ornamentBottomLeftConcaveStroke))
symbolLine(SymId::ornamentBottomLeftConcaveStroke,
SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd);
else
symbolLine(SymId::ornamentUpPrall,
// SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd);
SymId::ornamentZigZagLineNoRightEnd);
2013-11-19 16:06:08 +01:00
break;
2014-05-25 18:51:19 +02:00
case Trill::TrillType::DOWNPRALL_LINE:
2013-11-22 14:29:09 +01:00
if (score()->scoreFont()->isValid(SymId::ornamentLeftVerticalStroke))
symbolLine(SymId::ornamentLeftVerticalStroke,
SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd);
else
symbolLine(SymId::ornamentDownPrall,
// SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd);
SymId::ornamentZigZagLineNoRightEnd);
2013-11-19 16:06:08 +01:00
break;
}
2013-08-30 16:03:46 +02:00
}
2013-11-19 16:06:08 +01:00
else
symbolLine(SymId::wiggleTrill, SymId::wiggleTrill);
2012-10-27 14:46:35 +02:00
adjustReadPos();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// acceptDrop
//---------------------------------------------------------
bool TrillSegment::acceptDrop(MuseScoreView*, const QPointF&, Element* e) const
{
if (e->type() == Element::Type::ACCIDENTAL)
2012-05-26 14:26:10 +02:00
return true;
return false;
}
//---------------------------------------------------------
// drop
//---------------------------------------------------------
Element* TrillSegment::drop(const DropData& data)
{
Element* e = data.element;
switch(e->type()) {
case Element::Type::ACCIDENTAL:
2012-05-26 14:26:10 +02:00
e->setParent(trill());
score()->undoAddElement(e);
break;
default:
delete e;
e = 0;
break;
}
return e;
}
2013-05-02 16:12:17 +02:00
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
QVariant TrillSegment::getProperty(P_ID id) const
{
switch (id) {
2014-05-26 18:18:01 +02:00
case P_ID::TRILL_TYPE:
2013-05-02 16:12:17 +02:00
return trill()->getProperty(id);
default:
return LineSegment::getProperty(id);
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool TrillSegment::setProperty(P_ID id, const QVariant& v)
{
switch (id) {
2014-05-26 18:18:01 +02:00
case P_ID::TRILL_TYPE:
2013-05-02 16:12:17 +02:00
return trill()->setProperty(id, v);
default:
return LineSegment::setProperty(id, v);
}
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
QVariant TrillSegment::propertyDefault(P_ID id) const
{
switch (id) {
2014-05-26 18:18:01 +02:00
case P_ID::TRILL_TYPE:
2013-05-02 16:12:17 +02:00
return trill()->propertyDefault(id);
default:
return LineSegment::propertyDefault(id);
}
}
2013-09-02 12:29:25 +02:00
//---------------------------------------------------------
// scanElements
//---------------------------------------------------------
2013-10-24 12:09:00 +02:00
void TrillSegment::scanElements(void* data, void (*func)(void*, Element*), bool /*all*/)
2013-09-02 12:29:25 +02:00
{
func(data, this);
if (spannerSegmentType() == SpannerSegmentType::SINGLE || spannerSegmentType() == SpannerSegmentType::BEGIN) {
2013-09-02 12:29:25 +02:00
Accidental* a = trill()->accidental();
if (a)
func(data, a);
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// Trill
//---------------------------------------------------------
Trill::Trill(Score* s)
: SLine(s)
{
2014-05-25 18:51:19 +02:00
_trillType = TrillType::TRILL_LINE;
2013-08-30 16:03:46 +02:00
_accidental = 0;
}
Trill::~Trill()
{
delete _accidental;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// add
//---------------------------------------------------------
void Trill::add(Element* e)
{
if (e->type() == Element::Type::ACCIDENTAL) {
2012-05-26 14:26:10 +02:00
e->setParent(this);
2013-08-30 16:03:46 +02:00
_accidental = static_cast<Accidental*>(e);
2012-05-26 14:26:10 +02:00
}
else
SLine::add(e);
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void Trill::remove(Element* e)
{
2013-08-30 16:03:46 +02:00
if (e == _accidental)
_accidental = 0;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void Trill::layout()
{
qreal _spatium = spatium();
SLine::layout();
2013-06-20 18:48:28 +02:00
if (score() == gscore)
return;
2013-08-30 16:03:46 +02:00
TrillSegment* ls = static_cast<TrillSegment*>(frontSegment());
2012-05-26 14:26:10 +02:00
//
// special case:
// if end segment is first chord/rest segment in measure,
// shorten trill line so it ends at end of previous measure
//
2013-06-10 11:03:34 +02:00
Segment* seg1 = startSegment();
Segment* seg2 = endSegment();
2012-05-26 14:26:10 +02:00
if (seg2
&& (seg1->system() == seg2->system())
&& (spannerSegments().size() == 1)
&& (seg2->tick() == seg2->measure()->tick())
) {
qreal x1 = seg2->pagePos().x();
Measure* m = seg2->measure()->prevMeasure();
if (m) {
Segment* s2 = m->last();
qreal x2 = s2->pagePos().x();
qreal dx = x1 - x2 + _spatium * .3;
ls->setPos2(ls->ipos2() + QPointF(-dx, 0.0));
ls->layout();
}
}
2013-08-30 16:03:46 +02:00
if (_accidental)
_accidental->setParent(ls);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// createLineSegment
//---------------------------------------------------------
LineSegment* Trill::createLineSegment()
{
TrillSegment* seg = new TrillSegment(score());
seg->setTrack(track());
seg->setColor(color());
return seg;
}
//---------------------------------------------------------
// Trill::write
//---------------------------------------------------------
void Trill::write(Xml& xml) const
{
xml.stag(QString("%1 id=\"%2\"").arg(name()).arg(id()));
xml.tag("subtype", trillTypeName());
2012-05-26 14:26:10 +02:00
SLine::writeProperties(xml);
2013-08-30 16:03:46 +02:00
if (_accidental)
_accidental->write(xml);
2012-05-26 14:26:10 +02:00
xml.etag();
}
//---------------------------------------------------------
// Trill::read
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
void Trill::read(XmlReader& e)
2012-05-26 14:26:10 +02:00
{
2013-01-11 18:10:18 +01:00
qDeleteAll(spannerSegments());
2012-05-26 14:26:10 +02:00
spannerSegments().clear();
2013-01-11 18:10:18 +01:00
setId(e.intAttribute("id", -1));
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
2012-05-26 14:26:10 +02:00
if (tag == "subtype")
setTrillType(e.readElementText());
2012-05-26 14:26:10 +02:00
else if (tag == "Accidental") {
2013-08-30 16:03:46 +02:00
_accidental = new Accidental(score());
_accidental->read(e);
_accidental->setParent(this);
2012-05-26 14:26:10 +02:00
}
else if (!SLine::readProperties(e))
2013-01-11 18:10:18 +01:00
e.unknown();
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// setTrillType
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Trill::setTrillType(const QString& s)
2012-05-26 14:26:10 +02:00
{
if (s == "trill" || s == "0")
2014-05-25 18:51:19 +02:00
_trillType = TrillType::TRILL_LINE;
2012-05-26 14:26:10 +02:00
else if (s == "upprall")
2014-05-25 18:51:19 +02:00
_trillType = TrillType::UPPRALL_LINE;
2012-05-26 14:26:10 +02:00
else if (s == "downprall")
2014-05-25 18:51:19 +02:00
_trillType = TrillType::DOWNPRALL_LINE;
2012-05-26 14:26:10 +02:00
else if (s == "prallprall")
2014-05-25 18:51:19 +02:00
_trillType = TrillType::PRALLPRALL_LINE;
2012-10-15 23:58:40 +02:00
else if (s == "pure")
2014-05-25 18:51:19 +02:00
_trillType = TrillType::PURE_LINE;
2012-05-26 14:26:10 +02:00
else
qDebug("Trill::setSubtype: unknown <%s>", qPrintable(s));
}
//---------------------------------------------------------
// trillTypeName
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
QString Trill::trillTypeName() const
2012-05-26 14:26:10 +02:00
{
switch(trillType()) {
2014-05-25 18:51:19 +02:00
case TrillType::TRILL_LINE:
2012-05-26 14:26:10 +02:00
return "trill";
2014-05-25 18:51:19 +02:00
case TrillType::UPPRALL_LINE:
2012-05-26 14:26:10 +02:00
return "upprall";
2014-05-25 18:51:19 +02:00
case TrillType::DOWNPRALL_LINE:
2012-05-26 14:26:10 +02:00
return "downprall";
2014-05-25 18:51:19 +02:00
case TrillType::PRALLPRALL_LINE:
2012-05-26 14:26:10 +02:00
return "prallprall";
2014-05-25 18:51:19 +02:00
case TrillType::PURE_LINE:
2012-10-15 23:58:40 +02:00
return "pure";
2012-05-26 14:26:10 +02:00
default:
qDebug("unknown Trill subtype %hhd", trillType());
2012-05-26 14:26:10 +02:00
return "?";
}
}
//---------------------------------------------------------
// scanElements
//---------------------------------------------------------
void Trill::scanElements(void* data, void (*func)(void*, Element*), bool all)
{
2013-08-30 16:03:46 +02:00
if (_accidental)
_accidental->scanElements(data, func, all);
func(data, this); // ?
2012-05-26 14:26:10 +02:00
SLine::scanElements(data, func, all);
}
2012-09-17 18:09:30 +02:00
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
QVariant Trill::getProperty(P_ID propertyId) const
{
switch(propertyId) {
2014-05-26 18:18:01 +02:00
case P_ID::TRILL_TYPE:
2014-05-25 18:51:19 +02:00
return int(trillType());
2012-09-17 18:09:30 +02:00
default:
break;
}
return SLine::getProperty(propertyId);
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool Trill::setProperty(P_ID propertyId, const QVariant& val)
{
switch(propertyId) {
2014-05-26 18:18:01 +02:00
case P_ID::TRILL_TYPE:
setTrillType(TrillType(val.toInt()));
2012-09-17 18:09:30 +02:00
break;
default:
if (!SLine::setProperty(propertyId, val))
return false;
break;
}
score()->setLayoutAll(true);
return true;
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
QVariant Trill::propertyDefault(P_ID propertyId) const
{
switch(propertyId) {
2014-05-26 18:18:01 +02:00
case P_ID::TRILL_TYPE:
2012-09-17 18:09:30 +02:00
return 0;
default:
return SLine::propertyDefault(propertyId);
}
return QVariant();
}
//---------------------------------------------------------
// undoSetTrillType
2012-09-17 18:09:30 +02:00
//---------------------------------------------------------
void Trill::undoSetTrillType(TrillType val)
2012-09-17 18:09:30 +02:00
{
2014-05-26 18:18:01 +02:00
score()->undoChangeProperty(this, P_ID::TRILL_TYPE, int(val));
2012-09-17 18:09:30 +02:00
}
2012-10-27 14:46:35 +02:00
//---------------------------------------------------------
// setYoff
//---------------------------------------------------------
void Trill::setYoff(qreal val)
{
2014-05-26 15:31:36 +02:00
rUserYoffset() += (val - score()->styleS(StyleIdx::trillY).val()) * spatium();
2012-10-27 14:46:35 +02:00
}
2013-05-13 18:49:17 +02:00
}