2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
|
|
|
// Copyright (C) 2002-2012 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 "line.h"
|
2015-01-16 11:54:17 +01:00
|
|
|
#include "barline.h"
|
|
|
|
#include "chord.h"
|
|
|
|
#include "lyrics.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
#include "measure.h"
|
|
|
|
#include "score.h"
|
2015-01-16 11:54:17 +01:00
|
|
|
#include "segment.h"
|
2014-08-21 04:01:14 +02:00
|
|
|
#include "staff.h"
|
2015-01-16 11:54:17 +01:00
|
|
|
#include "system.h"
|
|
|
|
#include "textline.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
#include "utils.h"
|
2015-01-16 11:54:17 +01:00
|
|
|
#include "xml.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
|
|
|
//---------------------------------------------------------
|
|
|
|
// LineSegment
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
LineSegment::LineSegment(const LineSegment& s)
|
|
|
|
: SpannerSegment(s)
|
|
|
|
{
|
|
|
|
_p2 = s._p2;
|
|
|
|
_userOff2 = s._userOff2;
|
|
|
|
}
|
|
|
|
|
2012-07-04 13:04:54 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readProperties
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
bool LineSegment::readProperties(XmlReader& e)
|
2012-07-04 13:04:54 +02:00
|
|
|
{
|
2013-01-11 18:10:18 +01:00
|
|
|
const QStringRef& tag(e.name());
|
2012-07-04 13:04:54 +02:00
|
|
|
if (tag == "subtype")
|
2013-03-05 20:23:59 +01:00
|
|
|
setSpannerSegmentType(SpannerSegmentType(e.readInt()));
|
2015-02-12 11:41:39 +01:00
|
|
|
else if (tag == "off1") // off1 is obsolete
|
2013-01-11 18:10:18 +01:00
|
|
|
setUserOff(e.readPoint() * spatium());
|
2012-07-04 13:04:54 +02:00
|
|
|
else if (tag == "off2")
|
2013-01-11 18:10:18 +01:00
|
|
|
setUserOff2(e.readPoint() * spatium());
|
2012-07-05 14:49:12 +02:00
|
|
|
else if (tag == "pos") {
|
|
|
|
if (score()->mscVersion() > 114) {
|
|
|
|
qreal _spatium = spatium();
|
|
|
|
setUserOff(QPointF());
|
2013-01-11 18:10:18 +01:00
|
|
|
setReadPos(e.readPoint() * _spatium);
|
2015-02-12 11:41:39 +01:00
|
|
|
if (e.pasteMode()) // x position will be wrong
|
|
|
|
setReadPos(QPointF());
|
2012-07-05 14:49:12 +02:00
|
|
|
}
|
2013-01-17 20:42:44 +01:00
|
|
|
else
|
|
|
|
e.readNext();
|
2012-07-05 14:49:12 +02:00
|
|
|
}
|
2013-08-29 11:08:09 +02:00
|
|
|
else if (!SpannerSegment::readProperties(e)) {
|
2013-01-11 18:10:18 +01:00
|
|
|
e.unknown();
|
2012-07-04 13:04:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// read
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
void LineSegment::read(XmlReader& e)
|
2012-07-04 13:04:54 +02:00
|
|
|
{
|
2013-01-11 18:10:18 +01:00
|
|
|
while (e.readNextStartElement())
|
|
|
|
readProperties(e);
|
2012-07-04 13:04:54 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// updateGrips
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
void LineSegment::updateGrips(Grip* defaultGrip, QVector<QRectF>& grip) const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2015-01-19 12:37:17 +01:00
|
|
|
*defaultGrip = Grip::END;
|
2012-05-26 14:26:10 +02:00
|
|
|
QPointF pp(pagePos());
|
2015-01-19 12:37:17 +01:00
|
|
|
grip[int(Grip::START)].translate(pp);
|
|
|
|
grip[int(Grip::END)].translate(pos2() + pp);
|
|
|
|
grip[int(Grip::MIDDLE)].translate(pos2() * .5 + pp);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setGrip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
void LineSegment::setGrip(Grip grip, const QPointF& p)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
QPointF pt(p * spatium());
|
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
switch (grip) {
|
|
|
|
case Grip::START: {
|
2013-04-15 19:16:47 +02:00
|
|
|
QPointF delta(pt - userOff());
|
|
|
|
setUserOff(pt);
|
|
|
|
setUserOff2(userOff2() - delta);
|
|
|
|
}
|
|
|
|
break;
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::END:
|
2013-04-15 19:16:47 +02:00
|
|
|
setUserOff2(pt);
|
|
|
|
break;
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::MIDDLE:
|
2013-04-15 19:16:47 +02:00
|
|
|
setUserOff(pt);
|
|
|
|
break;
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::APERTURE:
|
|
|
|
default:
|
2014-05-23 14:11:57 +02:00
|
|
|
break;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-08-29 11:08:09 +02:00
|
|
|
layout(); // needed?
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// getGrip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
QPointF LineSegment::getGrip(Grip grip) const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-04-15 19:16:47 +02:00
|
|
|
QPointF p;
|
2015-01-19 12:37:17 +01:00
|
|
|
switch (grip) {
|
|
|
|
case Grip::START:
|
2013-04-15 19:16:47 +02:00
|
|
|
p = userOff();
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::END:
|
2013-04-15 19:16:47 +02:00
|
|
|
p = userOff2();
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::MIDDLE:
|
2013-04-15 19:16:47 +02:00
|
|
|
p = userOff();
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::APERTURE:
|
|
|
|
default:
|
2014-05-23 14:11:57 +02:00
|
|
|
break;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-04-15 19:16:47 +02:00
|
|
|
p /= spatium();
|
|
|
|
return p;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// gripAnchor
|
2013-08-30 12:46:15 +02:00
|
|
|
// return page coordinates
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
QPointF LineSegment::gripAnchor(Grip grip) const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-07-09 18:05:58 +02:00
|
|
|
qreal y = system()->staffYpage(staffIdx());
|
2014-05-26 20:38:22 +02:00
|
|
|
if (spannerSegmentType() == SpannerSegmentType::MIDDLE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
qreal x;
|
2014-08-06 12:28:58 +02:00
|
|
|
switch (grip) {
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::START:
|
2012-05-26 14:26:10 +02:00
|
|
|
x = system()->firstMeasure()->abbox().left();
|
|
|
|
break;
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::END:
|
2012-05-26 14:26:10 +02:00
|
|
|
x = system()->lastMeasure()->abbox().right();
|
|
|
|
break;
|
|
|
|
default:
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::MIDDLE:
|
|
|
|
case Grip::APERTURE:
|
2012-05-26 14:26:10 +02:00
|
|
|
x = 0; // No Anchor
|
|
|
|
y = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return QPointF(x, y);
|
|
|
|
}
|
|
|
|
else {
|
2015-01-19 12:37:17 +01:00
|
|
|
if ((grip == Grip::MIDDLE || grip == Grip::APERTURE) // center grip or aperture grip
|
|
|
|
|| (grip == Grip::END && spannerSegmentType() == SpannerSegmentType::BEGIN)
|
|
|
|
|| (grip == Grip::START && spannerSegmentType() == SpannerSegmentType::END)
|
|
|
|
)
|
2012-05-26 14:26:10 +02:00
|
|
|
return QPointF(0, 0);
|
|
|
|
else {
|
|
|
|
System* s;
|
2015-01-19 12:37:17 +01:00
|
|
|
QPointF p(line()->linePos(grip, &s));
|
2014-07-09 18:05:58 +02:00
|
|
|
p.ry() += y - system()->pos().y();
|
2013-08-30 12:46:15 +02:00
|
|
|
if (s)
|
|
|
|
p += s->pos();
|
|
|
|
return p;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// edit
|
|
|
|
// return true if event is accepted
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
bool LineSegment::edit(MuseScoreView* sv, Grip curGrip, int key, Qt::KeyboardModifiers modifiers, const QString&)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
if (!((modifiers & Qt::ShiftModifier)
|
2014-05-26 20:38:22 +02:00
|
|
|
&& ((spannerSegmentType() == SpannerSegmentType::SINGLE)
|
2015-01-19 12:37:17 +01:00
|
|
|
|| (spannerSegmentType() == SpannerSegmentType::BEGIN && curGrip == Grip::START)
|
|
|
|
|| (spannerSegmentType() == SpannerSegmentType::END && curGrip == Grip::END))))
|
2012-05-26 14:26:10 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
LineSegment* ls = 0;
|
|
|
|
SLine* l = line();
|
2013-03-05 20:23:59 +01:00
|
|
|
SpannerSegmentType st = spannerSegmentType();
|
2012-05-26 14:26:10 +02:00
|
|
|
int track = l->track();
|
|
|
|
|
2014-05-26 20:48:27 +02:00
|
|
|
if (l->anchor() == Spanner::Anchor::SEGMENT) {
|
2013-09-03 16:34:56 +02:00
|
|
|
Segment* s1 = spanner()->startSegment();
|
|
|
|
Segment* s2 = spanner()->endSegment();
|
2014-10-08 06:54:39 +02:00
|
|
|
// check for line going to end of score
|
|
|
|
if (spanner()->tick2() >= score()->lastSegment()->tick()) {
|
|
|
|
// endSegment calculated above will be the last chord/rest of score
|
|
|
|
// but that is not correct - it should be an imaginary note *after* the end of the score
|
|
|
|
// best we can do is set s2 to lastSegment (probably the end barline)
|
|
|
|
s2 = score()->lastSegment();
|
|
|
|
}
|
2013-08-12 10:37:30 +02:00
|
|
|
if (!s1 && !s2) {
|
|
|
|
qDebug("LineSegment::edit: no start/end segment");
|
2013-06-19 16:25:29 +02:00
|
|
|
return true;
|
2013-08-11 11:46:04 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
if (key == Qt::Key_Left) {
|
2015-01-19 12:37:17 +01:00
|
|
|
if (curGrip == Grip::START)
|
2012-05-26 14:26:10 +02:00
|
|
|
s1 = prevSeg1(s1, track);
|
2015-01-19 12:37:17 +01:00
|
|
|
else if (curGrip == Grip::END || curGrip == Grip::MIDDLE)
|
2013-08-12 10:37:30 +02:00
|
|
|
s2 = prevSeg1(s2, track);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (key == Qt::Key_Right) {
|
2015-01-19 12:37:17 +01:00
|
|
|
if (curGrip == Grip::START)
|
2012-05-26 14:26:10 +02:00
|
|
|
s1 = nextSeg1(s1, track);
|
2015-01-19 12:37:17 +01:00
|
|
|
else if (curGrip == Grip::END || curGrip == Grip::MIDDLE) {
|
2014-08-21 09:58:21 +02:00
|
|
|
Segment* ns2 = nextSeg1(s2, track);
|
|
|
|
if (ns2)
|
|
|
|
s2 = ns2;
|
|
|
|
else
|
|
|
|
s2 = score()->lastSegment();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
2014-05-29 12:13:49 +02:00
|
|
|
if (s1 == 0 || s2 == 0 || s1->tick() >= s2->tick())
|
2012-05-26 14:26:10 +02:00
|
|
|
return true;
|
2013-06-19 16:25:29 +02:00
|
|
|
if (s1->tick() != spanner()->tick())
|
|
|
|
spanner()->setTick(s1->tick());
|
|
|
|
if (s2->tick() != spanner()->tick2())
|
|
|
|
spanner()->setTick2(s2->tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else {
|
2015-01-19 12:37:17 +01:00
|
|
|
Measure* m1 = l->startMeasure();
|
|
|
|
Measure* m2 = l->endMeasure();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
if (key == Qt::Key_Left) {
|
2015-01-19 12:37:17 +01:00
|
|
|
if (curGrip == Grip::START) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (m1->prevMeasure())
|
|
|
|
m1 = m1->prevMeasure();
|
|
|
|
}
|
2015-01-19 12:37:17 +01:00
|
|
|
else if (curGrip == Grip::END || curGrip == Grip::MIDDLE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Measure* m = m2->prevMeasure();
|
|
|
|
if (m)
|
|
|
|
m2 = m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (key == Qt::Key_Right) {
|
2015-01-19 12:37:17 +01:00
|
|
|
if (curGrip == Grip::START) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (m1->nextMeasure())
|
|
|
|
m1 = m1->nextMeasure();
|
|
|
|
}
|
2015-01-19 12:37:17 +01:00
|
|
|
else if (curGrip == Grip::END || curGrip == Grip::MIDDLE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (m2->nextMeasure())
|
|
|
|
m2 = m2->nextMeasure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m1->tick() > m2->tick())
|
|
|
|
return true;
|
|
|
|
if (l->startElement() != m1) {
|
2013-06-10 11:03:34 +02:00
|
|
|
l->setTick(m1->tick());
|
2015-01-19 12:37:17 +01:00
|
|
|
l->setTicks(m2->endTick() - m1->tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (l->endElement() != m2) {
|
2015-01-19 12:37:17 +01:00
|
|
|
l->setTicks(m2->endTick() - m1->tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
2015-01-19 12:37:17 +01:00
|
|
|
_score->doLayout(); // needed to compute multi measure rests
|
|
|
|
|
|
|
|
// l->layout();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
LineSegment* nls = 0;
|
2014-05-26 20:38:22 +02:00
|
|
|
if (st == SpannerSegmentType::SINGLE) {
|
2015-01-19 12:37:17 +01:00
|
|
|
if (curGrip == Grip::START)
|
2012-05-26 14:26:10 +02:00
|
|
|
nls = l->frontSegment();
|
2015-01-19 12:37:17 +01:00
|
|
|
else if (curGrip == Grip::END)
|
2012-05-26 14:26:10 +02:00
|
|
|
nls = l->backSegment();
|
|
|
|
}
|
2014-05-26 20:38:22 +02:00
|
|
|
else if (st == SpannerSegmentType::BEGIN)
|
2012-05-26 14:26:10 +02:00
|
|
|
nls = l->frontSegment();
|
2014-05-26 20:38:22 +02:00
|
|
|
else if (st == SpannerSegmentType::END)
|
2012-05-26 14:26:10 +02:00
|
|
|
nls = l->backSegment();
|
|
|
|
|
|
|
|
if (nls && (nls != this))
|
|
|
|
sv->changeEditElement(nls);
|
|
|
|
if (ls)
|
|
|
|
_score->undoRemoveElement(ls);
|
2014-07-09 18:05:58 +02:00
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
_score->setLayoutAll(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// editDrag
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void LineSegment::editDrag(const EditData& ed)
|
|
|
|
{
|
2012-09-15 17:12:15 +02:00
|
|
|
// Only for resizing according to the diagonal properties
|
2012-05-26 14:26:10 +02:00
|
|
|
QPointF deltaResize(ed.delta.x(), line()->diagonal() ? ed.delta.y() : 0.0);
|
2012-09-15 17:12:15 +02:00
|
|
|
|
|
|
|
// Only for moving, no y limitaion
|
2012-05-26 14:26:10 +02:00
|
|
|
QPointF deltaMove(ed.delta.x(), ed.delta.y());
|
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
switch (ed.curGrip) {
|
|
|
|
case Grip::START: // Resize the begin of element (left grip)
|
2012-05-26 14:26:10 +02:00
|
|
|
setUserOff(userOff() + deltaResize);
|
|
|
|
_userOff2 -= deltaResize;
|
|
|
|
break;
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::END: // Resize the end of element (rigth grip)
|
2012-05-26 14:26:10 +02:00
|
|
|
_userOff2 += deltaResize;
|
|
|
|
break;
|
2015-01-19 12:37:17 +01:00
|
|
|
case Grip::MIDDLE: // Move the element (middle grip)
|
2012-05-26 14:26:10 +02:00
|
|
|
setUserOff(userOff() + deltaMove);
|
|
|
|
break;
|
2014-05-23 14:11:57 +02:00
|
|
|
default:
|
|
|
|
break;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-05-26 20:48:27 +02:00
|
|
|
if ((line()->anchor() == Spanner::Anchor::NOTE)
|
2015-01-19 12:37:17 +01:00
|
|
|
&& (ed.curGrip == Grip::START || ed.curGrip == Grip::END)) {
|
2012-09-15 17:12:15 +02:00
|
|
|
//
|
|
|
|
// if we touch a different note, change anchor
|
|
|
|
//
|
|
|
|
Element* e = ed.view->elementNear(ed.pos);
|
2014-06-24 18:36:02 +02:00
|
|
|
if (e && e->type() == Element::Type::NOTE) {
|
2012-09-15 17:12:15 +02:00
|
|
|
SLine* l = line();
|
2015-01-19 12:37:17 +01:00
|
|
|
if (ed.curGrip == Grip::END && e != line()->endElement()) {
|
2012-09-15 17:12:15 +02:00
|
|
|
qDebug("LineSegment: move end anchor");
|
|
|
|
Note* noteOld = static_cast<Note*>(l->endElement());
|
|
|
|
Note* noteNew = static_cast<Note*>(e);
|
|
|
|
|
|
|
|
noteOld->removeSpannerBack(l);
|
|
|
|
noteNew->addSpannerBack(l);
|
2013-07-04 13:40:25 +02:00
|
|
|
l->setEndElement(noteNew);
|
2012-09-15 17:12:15 +02:00
|
|
|
|
|
|
|
_userOff2 += noteOld->canvasPos() - noteNew->canvasPos();
|
|
|
|
}
|
2015-01-19 12:37:17 +01:00
|
|
|
else if (ed.curGrip == Grip::START && e != l->startElement()) {
|
2012-09-15 17:12:15 +02:00
|
|
|
qDebug("LineSegment: move start anchor (not impl.)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-30 12:46:15 +02:00
|
|
|
line()->layout();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// spatiumChanged
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void LineSegment::spatiumChanged(qreal ov, qreal nv)
|
|
|
|
{
|
|
|
|
Element::spatiumChanged(ov, nv);
|
|
|
|
_userOff2 *= nv / ov;
|
|
|
|
}
|
|
|
|
|
2013-08-08 11:38:32 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// getProperty
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QVariant LineSegment::getProperty(P_ID id) const
|
|
|
|
{
|
2013-08-12 10:37:30 +02:00
|
|
|
switch (id) {
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::DIAGONAL:
|
|
|
|
case P_ID::LINE_COLOR:
|
|
|
|
case P_ID::LINE_WIDTH:
|
|
|
|
case P_ID::LINE_STYLE:
|
2013-08-12 10:37:30 +02:00
|
|
|
return line()->getProperty(id);
|
|
|
|
default:
|
|
|
|
return SpannerSegment::getProperty(id);
|
|
|
|
}
|
2013-08-08 11:38:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setProperty
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool LineSegment::setProperty(P_ID id, const QVariant& val)
|
|
|
|
{
|
2013-08-12 10:37:30 +02:00
|
|
|
switch (id) {
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::DIAGONAL:
|
|
|
|
case P_ID::LINE_COLOR:
|
|
|
|
case P_ID::LINE_WIDTH:
|
|
|
|
case P_ID::LINE_STYLE:
|
2013-08-12 10:37:30 +02:00
|
|
|
return line()->setProperty(id, val);
|
|
|
|
default:
|
|
|
|
return SpannerSegment::setProperty(id, val);
|
|
|
|
}
|
2013-08-08 11:38:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// propertyDefault
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QVariant LineSegment::propertyDefault(P_ID id) const
|
|
|
|
{
|
|
|
|
return line()->propertyDefault(id);
|
|
|
|
}
|
|
|
|
|
2014-08-06 12:28:58 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// dragAnchor
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QLineF LineSegment::dragAnchor() const
|
|
|
|
{
|
|
|
|
if (spannerSegmentType() != SpannerSegmentType::SINGLE && spannerSegmentType() != SpannerSegmentType::BEGIN)
|
|
|
|
return QLineF();
|
|
|
|
System* s;
|
2015-01-19 12:37:17 +01:00
|
|
|
QPointF p = line()->linePos(Grip::START, &s);
|
2014-08-06 12:28:58 +02:00
|
|
|
p += QPointF(s->canvasPos().x(), s->staffYpage(line()->staffIdx()));
|
|
|
|
|
|
|
|
return QLineF(p, canvasPos());
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// SLine
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
SLine::SLine(Score* s)
|
|
|
|
: Spanner(s)
|
|
|
|
{
|
2013-08-08 11:38:32 +02:00
|
|
|
_diagonal = false;
|
|
|
|
_lineColor = MScore::defaultColor;
|
|
|
|
_lineWidth = Spatium(0.15);
|
|
|
|
_lineStyle = Qt::SolidLine;
|
2012-05-26 14:26:10 +02:00
|
|
|
setTrack(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SLine::SLine(const SLine& s)
|
|
|
|
: Spanner(s)
|
|
|
|
{
|
2013-08-08 11:38:32 +02:00
|
|
|
_diagonal = s._diagonal;
|
|
|
|
_lineWidth = s._lineWidth;
|
|
|
|
_lineColor = s._lineColor;
|
|
|
|
_lineStyle = s._lineStyle;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// linePos
|
2014-07-09 18:05:58 +02:00
|
|
|
// return System/Staff coordinates
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
QPointF SLine::linePos(Grip grip, System** sys) const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2012-07-27 18:01:15 +02:00
|
|
|
qreal x = 0.0;
|
2014-10-10 05:52:37 +02:00
|
|
|
qreal sp = staff()->spatium();
|
2013-08-11 11:46:04 +02:00
|
|
|
switch (anchor()) {
|
2014-05-26 20:48:27 +02:00
|
|
|
case Spanner::Anchor::SEGMENT:
|
2012-09-12 16:19:03 +02:00
|
|
|
{
|
2014-07-31 13:33:50 +02:00
|
|
|
ChordRest* cr;
|
2015-01-19 12:37:17 +01:00
|
|
|
if (grip == Grip::START) {
|
2014-07-31 13:33:50 +02:00
|
|
|
cr = static_cast<ChordRest*>(startElement());
|
2014-10-10 05:52:37 +02:00
|
|
|
if (cr) {
|
|
|
|
// some sources say to center the text over the note head
|
|
|
|
// some say to start the text just to left of notehead
|
|
|
|
// our simple compromise - left align
|
|
|
|
if (cr->durationType() == TDuration::DurationType::V_MEASURE && type() == Element::Type::OTTAVA)
|
|
|
|
x = cr->x(); // center for measure rests
|
|
|
|
else if (cr->space().lw() > 0.0)
|
|
|
|
x = -cr->space().lw(); // account for accidentals, etc
|
|
|
|
}
|
2014-08-22 20:59:05 +02:00
|
|
|
}
|
2014-07-31 13:33:50 +02:00
|
|
|
else {
|
|
|
|
cr = static_cast<ChordRest*>(endElement());
|
2014-08-21 04:01:14 +02:00
|
|
|
if (type() == Element::Type::OTTAVA) {
|
2014-10-10 05:52:37 +02:00
|
|
|
if (cr && cr->durationType() == TDuration::DurationType::V_MEASURE) {
|
2014-10-18 21:31:09 +02:00
|
|
|
x = cr->x() + cr->width() + sp;
|
2014-10-10 05:52:37 +02:00
|
|
|
}
|
|
|
|
else if (cr) {
|
|
|
|
// lay out just past right edge of all notes for this segment on this staff
|
|
|
|
// note: the cheap solution is to simply use segment width,
|
|
|
|
// but that would account for notes in other staves unnecessarily
|
|
|
|
// and in any event, segment bboxes seem unreliable
|
|
|
|
qreal width = 0;
|
|
|
|
Segment* s = cr->segment();
|
|
|
|
int n = staffIdx() * VOICES;
|
|
|
|
for (int i = 0; i < VOICES; ++i) {
|
|
|
|
ChordRest* vcr = static_cast<ChordRest*>(s->element(n + i));
|
|
|
|
if (vcr)
|
|
|
|
width = qMax(width, vcr->space().rw());
|
|
|
|
}
|
|
|
|
// extend past chord/rest
|
|
|
|
x = width + sp;
|
|
|
|
// but don't overlap next chord/rest
|
|
|
|
Segment* ns = s->next();
|
|
|
|
bool crFound = false;
|
|
|
|
while (ns) {
|
|
|
|
for (int i = 0; i < VOICES; ++i) {
|
|
|
|
if (ns->element(n + i)) {
|
|
|
|
crFound = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (crFound)
|
|
|
|
break;
|
|
|
|
ns = ns->next();
|
|
|
|
}
|
|
|
|
if (crFound) {
|
2014-10-18 21:31:09 +02:00
|
|
|
qreal nextNoteDistance = ns->x() - s->x() + lineWidth().val() * sp;
|
2014-10-10 05:52:37 +02:00
|
|
|
if (x > nextNoteDistance)
|
|
|
|
x = qMax(width, nextNoteDistance);
|
|
|
|
}
|
|
|
|
}
|
2014-08-21 04:01:14 +02:00
|
|
|
}
|
2015-01-19 23:34:50 +01:00
|
|
|
else if (type() == Element::Type::LYRICSLINE && static_cast<Lyrics*>(parent())->ticks() > 0) {
|
|
|
|
// melisma line
|
2015-01-14 00:50:47 +01:00
|
|
|
// it is possible CR won't be in correct track
|
|
|
|
// prefer element in current track if available
|
2015-01-30 04:13:47 +01:00
|
|
|
if (!cr)
|
|
|
|
qDebug("no end for lyricsline segment - start %d, ticks %d", tick(), ticks());
|
|
|
|
else if (cr->track() != track()) {
|
2015-01-14 00:50:47 +01:00
|
|
|
Element* e = cr->segment()->element(track());
|
|
|
|
if (e)
|
|
|
|
cr = static_cast<ChordRest*>(e);
|
|
|
|
}
|
2015-01-12 21:03:03 +01:00
|
|
|
// layout to right edge of CR
|
2015-01-14 00:50:47 +01:00
|
|
|
if (cr) {
|
|
|
|
qreal maxRight = 0.0;
|
|
|
|
if (cr->type() == Element::Type::CHORD) {
|
|
|
|
// chord bbox() is unreliable, look at notes
|
2015-01-15 21:44:11 +01:00
|
|
|
// this also allows us to more easily ignore ledger lines
|
2015-01-14 00:50:47 +01:00
|
|
|
for (Note* n : static_cast<Chord*>(cr)->notes())
|
2015-01-15 21:44:11 +01:00
|
|
|
maxRight = qMax(maxRight, cr->x() + n->x() + n->headWidth());
|
2015-01-14 00:50:47 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// rest - won't normally happen
|
|
|
|
maxRight = cr->x() + cr->width();
|
|
|
|
}
|
|
|
|
x = maxRight; // cr->width()
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
else if (type() == Element::Type::HAIRPIN || type() == Element::Type::TRILL
|
2015-01-16 11:54:17 +01:00
|
|
|
|| type() == Element::Type::TEXTLINE || type() == Element::Type::LYRICSLINE) {
|
2015-01-19 23:34:50 +01:00
|
|
|
// (for LYRICSLINE, this is hyphen; melisma line is handled above)
|
2014-10-10 05:52:37 +02:00
|
|
|
// lay out to just before next CR or barline
|
2014-08-21 04:01:14 +02:00
|
|
|
if (cr && endElement()->parent() && endElement()->parent()->type() == Element::Type::SEGMENT) {
|
2014-10-10 05:52:37 +02:00
|
|
|
qreal x2 = cr->x() + cr->space().rw();
|
2014-08-21 09:23:39 +02:00
|
|
|
int t = track2();
|
2014-08-21 04:01:14 +02:00
|
|
|
Segment* seg = static_cast<Segment*>(endElement()->parent())->next();
|
|
|
|
for ( ; seg; seg = seg->next()) {
|
|
|
|
if (seg->segmentType() == Segment::Type::ChordRest) {
|
2014-08-22 20:59:05 +02:00
|
|
|
if (t != -1 && !seg->element(t)) {
|
2014-08-21 04:01:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
2014-10-10 05:52:37 +02:00
|
|
|
x2 = qMax(x2, seg->x() - sp);
|
2014-08-21 04:01:14 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (seg->segmentType() == Segment::Type::EndBarLine) {
|
2015-01-19 23:34:50 +01:00
|
|
|
// allow lyrics hyphen to extend to barline; other lines stop 1sp short
|
|
|
|
qreal gap = (type() == Element::Type::LYRICSLINE) ? 0.0 : sp;
|
|
|
|
x2 = qMax(x2, seg->x() - gap);
|
2014-08-21 04:01:14 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!seg) {
|
|
|
|
// no end segment found, use measure width
|
|
|
|
x2 = endElement()->parent()->parent()->width() - sp;
|
|
|
|
}
|
2014-10-10 05:52:37 +02:00
|
|
|
x = x2 - endElement()->parent()->x();
|
2014-08-21 04:01:14 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-31 13:33:50 +02:00
|
|
|
}
|
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
int t = grip == Grip::START ? tick() : tick2();
|
2014-07-31 13:33:50 +02:00
|
|
|
Measure* m = cr ? cr->measure() : score()->tick2measure(t);
|
|
|
|
|
|
|
|
if (m) {
|
2014-10-10 05:52:37 +02:00
|
|
|
x += cr ? cr->segment()->pos().x() + m->pos().x() : m->tick2pos(t);
|
2014-07-31 13:33:50 +02:00
|
|
|
*sys = m->system();
|
|
|
|
}
|
2014-03-05 10:27:21 +01:00
|
|
|
else
|
2014-07-27 16:11:59 +02:00
|
|
|
*sys = 0;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-09-12 16:19:03 +02:00
|
|
|
break;
|
|
|
|
|
2014-05-26 20:48:27 +02:00
|
|
|
case Spanner::Anchor::MEASURE:
|
2012-09-12 16:19:03 +02:00
|
|
|
{
|
2014-05-26 20:48:27 +02:00
|
|
|
// anchor() == Anchor::MEASURE
|
2015-01-19 12:37:17 +01:00
|
|
|
const Measure* m;
|
|
|
|
if (grip == Grip::START) {
|
|
|
|
m = startMeasure();
|
2014-10-05 00:01:25 +02:00
|
|
|
// start after clef/key
|
|
|
|
qreal offset = 0.0;
|
|
|
|
Segment* s = m->first(Segment::Type::ChordRest);
|
|
|
|
if (s) {
|
|
|
|
s = s->prev();
|
|
|
|
if (s) {
|
|
|
|
offset = s->x();
|
|
|
|
Element* e = s->element(staffIdx() * VOICES);
|
|
|
|
if (e)
|
|
|
|
offset += e->width();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
x = m->pos().x() + offset;
|
|
|
|
if (score()->styleB(StyleIdx::createMultiMeasureRests) && m->hasMMRest()) {
|
2014-02-12 10:13:55 +01:00
|
|
|
x = m->mmRest()->pos().x();
|
|
|
|
}
|
2012-09-12 16:19:03 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-31 13:33:50 +02:00
|
|
|
qreal _spatium = spatium();
|
|
|
|
|
2015-01-19 12:37:17 +01:00
|
|
|
m = endMeasure();
|
2012-09-12 16:19:03 +02:00
|
|
|
x = m->pos().x() + m->bbox().right();
|
2014-05-26 15:31:36 +02:00
|
|
|
if (score()->styleB(StyleIdx::createMultiMeasureRests)) {
|
2014-02-12 10:13:55 +01:00
|
|
|
//find the actual measure where the volta should stop
|
2015-01-19 12:37:17 +01:00
|
|
|
Measure* sm = startMeasure();
|
2014-02-12 10:13:55 +01:00
|
|
|
Measure* m = sm;
|
|
|
|
if (sm->hasMMRest())
|
|
|
|
m = sm->mmRest();
|
2014-09-29 13:49:16 +02:00
|
|
|
while (m->nextMeasureMM() && (m->endTick() < tick2()))
|
2014-02-12 10:13:55 +01:00
|
|
|
m = m->nextMeasureMM();
|
|
|
|
x = m->pos().x() + m->bbox().right();
|
|
|
|
}
|
|
|
|
Segment* seg = m->last();
|
2014-06-25 11:46:10 +02:00
|
|
|
if (seg->segmentType() == Segment::Type::EndBarLine) {
|
2014-02-12 10:13:55 +01:00
|
|
|
Element* e = seg->element(0);
|
2014-06-24 18:36:02 +02:00
|
|
|
if (e && e->type() == Element::Type::BAR_LINE) {
|
2014-05-30 10:14:09 +02:00
|
|
|
if (static_cast<BarLine*>(e)->barLineType() == BarLineType::START_REPEAT)
|
2014-02-12 10:13:55 +01:00
|
|
|
x -= e->width() - _spatium * .5;
|
|
|
|
else
|
|
|
|
x -= _spatium * .5;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-26 15:31:36 +02:00
|
|
|
if (score()->styleB(StyleIdx::createMultiMeasureRests))
|
2014-04-24 17:09:42 +02:00
|
|
|
m = m->mmRest1();
|
2013-01-23 16:43:22 +01:00
|
|
|
Q_ASSERT(m->system());
|
2012-09-12 16:19:03 +02:00
|
|
|
*sys = m->system();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-09-12 16:19:03 +02:00
|
|
|
break;
|
|
|
|
|
2014-05-26 20:48:27 +02:00
|
|
|
case Spanner::Anchor::NOTE:
|
2012-09-12 16:19:03 +02:00
|
|
|
{
|
2014-12-13 17:40:39 +01:00
|
|
|
// System* s = static_cast<Note*>(startElement())->chord()->segment()->system();
|
|
|
|
// *sys = s;
|
2015-01-28 23:42:04 +01:00
|
|
|
Element* e = grip == Grip::START ? startElement() : endElement();
|
2014-12-13 17:40:39 +01:00
|
|
|
System* s = static_cast<Note*>(e)->chord()->segment()->system();
|
2012-09-12 16:19:03 +02:00
|
|
|
*sys = s;
|
2014-12-13 17:40:39 +01:00
|
|
|
// for GLISSANDO returns the position of the anchor note relative to the system
|
|
|
|
// for others, returns the position of the anchor note relative to the staff
|
|
|
|
// QPointF elemPagePos = e->pagePos(); // DEBUG
|
|
|
|
// QPointF systPagePos = s->pagePos();
|
|
|
|
// qreal staffYPage = s->staffYpage(e->staffIdx());
|
|
|
|
return e->pagePos() -
|
|
|
|
(type() == Element::Type::GLISSANDO ? s->pagePos()
|
|
|
|
: QPointF(s->pagePos().x(), s->staffYpage(e->staffIdx())) );
|
2012-09-12 16:19:03 +02:00
|
|
|
}
|
|
|
|
|
2014-05-26 20:48:27 +02:00
|
|
|
case Spanner::Anchor::CHORD:
|
2014-06-05 20:58:05 +02:00
|
|
|
qFatal("Sline::linePos(): anchor not implemented");
|
2012-09-12 16:19:03 +02:00
|
|
|
break;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-07-09 18:05:58 +02:00
|
|
|
return QPointF(x, 0.0);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// layout
|
|
|
|
// compute segments from tick1 tick2
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void SLine::layout()
|
|
|
|
{
|
2014-08-18 15:58:35 +02:00
|
|
|
if (score() == gscore || tick() == -1 || tick2() == 1) {
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
2014-08-18 15:58:35 +02:00
|
|
|
// when used in a palette or while dragging from palette,
|
|
|
|
// SLine has no parent and
|
2012-05-26 14:26:10 +02:00
|
|
|
// tick and tick2 has no meaning so no layout is
|
|
|
|
// possible and needed
|
|
|
|
//
|
|
|
|
if (!spannerSegments().isEmpty()) {
|
2014-12-13 17:40:39 +01:00
|
|
|
LineSegment* lineSegm = frontSegment();
|
|
|
|
lineSegm->layout();
|
|
|
|
setbbox(lineSegm->bbox());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2012-09-15 17:12:15 +02:00
|
|
|
|
2013-06-19 18:20:09 +02:00
|
|
|
computeStartElement();
|
|
|
|
computeEndElement();
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
System* s1;
|
|
|
|
System* s2;
|
2015-01-19 12:37:17 +01:00
|
|
|
QPointF p1(linePos(Grip::START, &s1));
|
|
|
|
QPointF p2(linePos(Grip::END, &s2));
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
QList<System*>* systems = score()->systems();
|
|
|
|
int sysIdx1 = systems->indexOf(s1);
|
|
|
|
int sysIdx2 = systems->indexOf(s2);
|
|
|
|
int segmentsNeeded = 0;
|
2014-03-01 12:34:33 +01:00
|
|
|
|
|
|
|
if (sysIdx1 == -1 || sysIdx2 == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (int i = sysIdx1; i < sysIdx2+1; ++i) {
|
|
|
|
if (systems->at(i)->isVbox())
|
|
|
|
continue;
|
|
|
|
++segmentsNeeded;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-07-04 13:40:25 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
int segCount = spannerSegments().size();
|
|
|
|
|
|
|
|
if (segmentsNeeded != segCount) {
|
|
|
|
if (segmentsNeeded > segCount) {
|
|
|
|
int n = segmentsNeeded - segCount;
|
|
|
|
for (int i = 0; i < n; ++i) {
|
2014-12-13 17:40:39 +01:00
|
|
|
LineSegment* lineSegm = createLineSegment();
|
|
|
|
add(lineSegm);
|
2012-05-26 14:26:10 +02:00
|
|
|
// set user offset to previous segment's offset
|
|
|
|
if (segCount > 0)
|
2014-12-13 17:40:39 +01:00
|
|
|
lineSegm->setUserOff(QPointF(0, segmentAt(segCount+i-1)->userOff().y()));
|
2014-07-28 18:23:13 +02:00
|
|
|
else
|
2014-12-13 17:40:39 +01:00
|
|
|
lineSegm->setUserOff(QPointF(0, userOff().y()));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int n = segCount - segmentsNeeded;
|
2013-01-23 14:14:09 +01:00
|
|
|
// qDebug("SLine: segments %d needed %d, remove %d", segCount, segmentsNeeded, n);
|
2012-05-26 14:26:10 +02:00
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
if (spannerSegments().isEmpty()) {
|
2012-07-20 16:29:24 +02:00
|
|
|
qDebug("SLine::layout(): no segment %d, %d expected", i, n);
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
2014-12-13 17:40:39 +01:00
|
|
|
/*LineSegment* lineSegm =*/ takeLastSegment();
|
|
|
|
// delete lineSegm;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int segIdx = 0;
|
|
|
|
for (int i = sysIdx1; i <= sysIdx2; ++i) {
|
|
|
|
System* system = systems->at(i);
|
|
|
|
if (system->isVbox())
|
|
|
|
continue;
|
2014-12-13 17:40:39 +01:00
|
|
|
LineSegment* lineSegm = segmentAt(segIdx++);
|
|
|
|
lineSegm->setTrack(track()); // DEBUG
|
|
|
|
lineSegm->setSystem(system);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-12-13 17:40:39 +01:00
|
|
|
Measure* firstMeas = system->firstMeasure();
|
|
|
|
Segment* firstCRSeg = firstMeas->first(Segment::Type::ChordRest);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
if (sysIdx1 == sysIdx2) {
|
|
|
|
// single segment
|
2014-12-13 17:40:39 +01:00
|
|
|
lineSegm->setSpannerSegmentType(SpannerSegmentType::SINGLE);
|
2013-08-12 10:37:30 +02:00
|
|
|
qreal len = p2.x() - p1.x();
|
2014-10-18 21:31:09 +02:00
|
|
|
// enforcing a minimum length would be possible but inadvisable
|
|
|
|
// the line length calculations are tuned well enough that this should not be needed
|
|
|
|
//if (anchor() == Anchor::SEGMENT && type() != Element::Type::PEDAL)
|
|
|
|
// len = qMax(1.0 * spatium(), len);
|
2014-12-13 17:40:39 +01:00
|
|
|
lineSegm->setPos(p1);
|
|
|
|
lineSegm->setPos2(QPointF(len, p2.y() - p1.y()));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (i == sysIdx1) {
|
|
|
|
// start segment
|
2014-12-13 17:40:39 +01:00
|
|
|
lineSegm->setSpannerSegmentType(SpannerSegmentType::BEGIN);
|
|
|
|
lineSegm->setPos(p1);
|
2013-08-28 11:10:12 +02:00
|
|
|
qreal x2 = system->bbox().right();
|
2014-12-13 17:40:39 +01:00
|
|
|
lineSegm->setPos2(QPointF(x2 - p1.x(), 0.0));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (i > 0 && i != sysIdx2) {
|
|
|
|
// middle segment
|
2014-12-13 17:40:39 +01:00
|
|
|
lineSegm->setSpannerSegmentType(SpannerSegmentType::MIDDLE);
|
|
|
|
qreal x1 = (firstCRSeg ? firstCRSeg->pos().x() : 0) + firstMeas->pos().x();
|
2013-08-28 11:10:12 +02:00
|
|
|
qreal x2 = system->bbox().right();
|
2014-12-13 17:40:39 +01:00
|
|
|
lineSegm->setPos(QPointF(x1, p1.y()));
|
|
|
|
lineSegm->setPos2(QPointF(x2 - x1, 0.0));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (i == sysIdx2) {
|
|
|
|
// end segment
|
2014-10-05 00:01:25 +02:00
|
|
|
qreal offset = 0.0;
|
|
|
|
qreal minLen = 0.0;
|
|
|
|
if (anchor() == Anchor::SEGMENT || anchor() == Anchor::MEASURE) {
|
|
|
|
// start line just after previous element (eg, key signature)
|
2014-12-13 17:40:39 +01:00
|
|
|
firstCRSeg = firstCRSeg->prev();
|
|
|
|
Element* e = firstCRSeg ? firstCRSeg->element(staffIdx() * VOICES) : nullptr;
|
2014-10-05 00:01:25 +02:00
|
|
|
if (e)
|
|
|
|
offset = e->width();
|
2014-10-18 21:31:09 +02:00
|
|
|
// enforcing a minimum length would be possible but inadvisable
|
|
|
|
// the line length calculations are tuned well enough that this should not be needed
|
|
|
|
//if (type() != Element::Type::PEDAL)
|
|
|
|
// minLen = 1.0 * spatium();
|
2014-10-05 00:01:25 +02:00
|
|
|
}
|
2014-12-13 17:40:39 +01:00
|
|
|
// qreal firstCRSegX = firstCRSeg ? firstCRSeg->pos().x() : 0; // DEBUG
|
|
|
|
// qreal firstMeasX = firstMeas ? firstMeas->pos().x() : 0;
|
|
|
|
qreal x1 = (firstCRSeg ? firstCRSeg->pos().x() : 0) + firstMeas->pos().x() + offset;
|
2014-10-05 00:01:25 +02:00
|
|
|
qreal len = qMax(minLen, p2.x() - x1);
|
2014-12-13 17:40:39 +01:00
|
|
|
lineSegm->setSpannerSegmentType(SpannerSegmentType::END);
|
|
|
|
lineSegm->setPos(QPointF(p2.x() - len, p2.y()));
|
|
|
|
lineSegm->setPos2(QPointF(len, 0.0));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-12-13 17:40:39 +01:00
|
|
|
lineSegm->layout();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-04-13 00:11:23 +02:00
|
|
|
adjustReadPos();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// writeProperties
|
|
|
|
// write properties different from prototype
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-08-09 11:42:24 +02:00
|
|
|
void SLine::writeProperties(Xml& xml) const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-08-13 15:42:40 +02:00
|
|
|
if (!endElement()) {
|
|
|
|
xml.tag("ticks", ticks());
|
|
|
|
}
|
|
|
|
Spanner::writeProperties(xml);
|
2013-08-09 11:42:24 +02:00
|
|
|
if (_diagonal)
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.tag("diagonal", _diagonal);
|
2014-05-26 18:18:01 +02:00
|
|
|
if (propertyStyle(P_ID::LINE_WIDTH) != PropertyStyle::STYLED)
|
2013-08-08 11:38:32 +02:00
|
|
|
xml.tag("lineWidth", lineWidth().val());
|
2014-05-26 18:18:01 +02:00
|
|
|
if (propertyStyle(P_ID::LINE_STYLE) == PropertyStyle::UNSTYLED || (lineStyle() != Qt::SolidLine))
|
|
|
|
if (propertyStyle(P_ID::LINE_STYLE) != PropertyStyle::STYLED)
|
2013-08-26 14:33:05 +02:00
|
|
|
xml.tag("lineStyle", int(lineStyle()));
|
2014-05-26 18:18:01 +02:00
|
|
|
if (propertyStyle(P_ID::LINE_COLOR) == PropertyStyle::UNSTYLED || (lineColor() != MScore::defaultColor))
|
2013-08-08 11:38:32 +02:00
|
|
|
xml.tag("lineColor", lineColor());
|
|
|
|
|
2014-06-18 20:57:45 +02:00
|
|
|
writeProperty(xml, P_ID::ANCHOR);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (score() == gscore) {
|
|
|
|
// when used as icon
|
|
|
|
if (!spannerSegments().isEmpty()) {
|
|
|
|
LineSegment* s = frontSegment();
|
|
|
|
xml.tag("length", s->pos2().x());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
xml.tag("length", spatium() * 4);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// check if user has modified the default layout
|
|
|
|
//
|
|
|
|
bool modified = false;
|
|
|
|
int n = spannerSegments().size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
const LineSegment* seg = segmentAt(i);
|
|
|
|
if (!seg->userOff().isNull()
|
|
|
|
|| !seg->userOff2().isNull()
|
|
|
|
|| !seg->visible()) {
|
|
|
|
modified = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!modified)
|
|
|
|
return;
|
|
|
|
|
|
|
|
//
|
|
|
|
// write user modified layout
|
|
|
|
//
|
|
|
|
qreal _spatium = spatium();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
const LineSegment* seg = segmentAt(i);
|
|
|
|
xml.stag("Segment");
|
2014-05-26 20:38:22 +02:00
|
|
|
xml.tag("subtype", int(seg->spannerSegmentType()));
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.tag("off2", seg->userOff2() / _spatium);
|
|
|
|
seg->Element::writeProperties(xml);
|
|
|
|
xml.etag();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readProperties
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
bool SLine::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
|
|
|
|
2014-08-22 20:43:05 +02:00
|
|
|
if (tag == "tick2") { // obsolete
|
|
|
|
if (tick() == -1) // not necessarily set (for first note of score?) #30151
|
|
|
|
setTick(e.tick());
|
2013-06-25 14:29:18 +02:00
|
|
|
setTick2(e.readInt());
|
2014-08-22 20:43:05 +02:00
|
|
|
}
|
2013-06-25 14:29:18 +02:00
|
|
|
else if (tag == "tick") // obsolete
|
|
|
|
setTick(e.readInt());
|
2014-08-13 15:42:40 +02:00
|
|
|
else if (tag == "ticks")
|
|
|
|
setTicks(e.readInt());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "Segment") {
|
|
|
|
LineSegment* ls = createLineSegment();
|
2014-10-05 15:39:03 +02:00
|
|
|
ls->setTrack(track()); // needed in read to get the right staff mag
|
2012-07-04 13:04:54 +02:00
|
|
|
ls->read(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
add(ls);
|
2014-10-02 09:08:58 +02:00
|
|
|
// in v1.x "visible" is a property of the segment only;
|
|
|
|
// we must ensure that it propagates also to the parent element.
|
|
|
|
// That's why the visibility is set after adding the segment
|
|
|
|
// to the corresponding spanner
|
|
|
|
if (score()->mscVersion() <= 114)
|
|
|
|
ls->setVisible(ls->visible());
|
|
|
|
else
|
|
|
|
ls->setVisible(visible());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "length")
|
2013-01-11 18:10:18 +01:00
|
|
|
setLen(e.readDouble());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "diagonal")
|
2013-01-11 18:10:18 +01:00
|
|
|
setDiagonal(e.readInt());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "anchor")
|
2013-01-11 18:10:18 +01:00
|
|
|
setAnchor(Anchor(e.readInt()));
|
2013-08-08 11:38:32 +02:00
|
|
|
else if (tag == "lineWidth")
|
|
|
|
_lineWidth = Spatium(e.readDouble());
|
|
|
|
else if (tag == "lineStyle")
|
|
|
|
_lineStyle = Qt::PenStyle(e.readInt());
|
|
|
|
else if (tag == "lineColor")
|
|
|
|
_lineColor = e.readColor();
|
2013-01-24 14:38:35 +01:00
|
|
|
else if (Element::readProperties(e))
|
|
|
|
;
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setLen
|
|
|
|
// used to create an element suitable for palette
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void SLine::setLen(qreal l)
|
|
|
|
{
|
|
|
|
if (spannerSegments().isEmpty())
|
|
|
|
add(createLineSegment());
|
|
|
|
LineSegment* s = frontSegment();
|
|
|
|
s->setPos(QPointF());
|
|
|
|
s->setPos2(QPointF(l, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// bbox
|
|
|
|
// used by palette: only one segment
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-07-24 14:20:43 +02:00
|
|
|
const QRectF& SLine::bbox() const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
if (spannerSegments().isEmpty())
|
2012-07-24 14:20:43 +02:00
|
|
|
setbbox(QRectF());
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
2012-07-24 14:20:43 +02:00
|
|
|
setbbox(segmentAt(0)->bbox());
|
|
|
|
return Element::bbox();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// write
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void SLine::write(Xml& xml) const
|
|
|
|
{
|
2014-07-21 13:24:21 +02:00
|
|
|
int id = xml.spannerId(this);
|
|
|
|
xml.stag(QString("%1 id=\"%2\"").arg(name()).arg(id));
|
2012-05-26 14:26:10 +02:00
|
|
|
SLine::writeProperties(xml);
|
|
|
|
xml.etag();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// read
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
void SLine::read(XmlReader& e)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
foreach(SpannerSegment* seg, spannerSegments())
|
|
|
|
delete seg;
|
|
|
|
spannerSegments().clear();
|
2014-07-21 13:24:21 +02:00
|
|
|
e.addSpanner(e.intAttribute("id", -1), this);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
while (e.readNextStartElement()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (!SLine::readProperties(e))
|
2013-01-11 18:10:18 +01:00
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-27 17:52:26 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// getProperty
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QVariant SLine::getProperty(P_ID id) const
|
|
|
|
{
|
2013-08-08 11:38:32 +02:00
|
|
|
switch (id) {
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::DIAGONAL:
|
2013-03-27 17:52:26 +01:00
|
|
|
return _diagonal;
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::LINE_COLOR:
|
2013-08-08 11:38:32 +02:00
|
|
|
return _lineColor;
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::LINE_WIDTH:
|
2013-08-08 11:38:32 +02:00
|
|
|
return _lineWidth.val();
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::LINE_STYLE:
|
2013-08-08 11:38:32 +02:00
|
|
|
return QVariant(int(_lineStyle));
|
2013-03-27 17:52:26 +01:00
|
|
|
default:
|
|
|
|
return Spanner::getProperty(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setProperty
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool SLine::setProperty(P_ID id, const QVariant& v)
|
|
|
|
{
|
2013-08-08 11:38:32 +02:00
|
|
|
switch (id) {
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::DIAGONAL:
|
2013-03-27 17:52:26 +01:00
|
|
|
_diagonal = v.toBool();
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::LINE_COLOR:
|
2013-08-08 11:38:32 +02:00
|
|
|
_lineColor = v.value<QColor>();
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::LINE_WIDTH:
|
2013-08-08 11:38:32 +02:00
|
|
|
_lineWidth = Spatium(v.toDouble());
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::LINE_STYLE:
|
2013-08-08 11:38:32 +02:00
|
|
|
_lineStyle = Qt::PenStyle(v.toInt());
|
|
|
|
break;
|
2013-03-27 17:52:26 +01:00
|
|
|
default:
|
|
|
|
return Spanner::setProperty(id, v);
|
|
|
|
}
|
2014-02-24 11:13:46 +01:00
|
|
|
return true;
|
2013-03-27 17:52:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// propertyDefault
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QVariant SLine::propertyDefault(P_ID id) const
|
|
|
|
{
|
2013-08-08 11:38:32 +02:00
|
|
|
switch (id) {
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::DIAGONAL:
|
2013-08-08 11:38:32 +02:00
|
|
|
return false;
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::LINE_COLOR:
|
2013-08-08 11:38:32 +02:00
|
|
|
return MScore::defaultColor;
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::LINE_WIDTH:
|
2013-08-08 11:38:32 +02:00
|
|
|
return 0.15;
|
2014-05-26 18:18:01 +02:00
|
|
|
case P_ID::LINE_STYLE:
|
2013-08-09 11:42:24 +02:00
|
|
|
return int(Qt::SolidLine);
|
2013-08-08 11:38:32 +02:00
|
|
|
default:
|
|
|
|
return Spanner::propertyDefault(id);
|
2013-03-27 17:52:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|
|
|
|
|