815 lines
28 KiB
C++
815 lines
28 KiB
C++
//=============================================================================
|
|
// 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"
|
|
#include "textline.h"
|
|
#include "segment.h"
|
|
#include "measure.h"
|
|
#include "score.h"
|
|
#include "xml.h"
|
|
#include "system.h"
|
|
#include "utils.h"
|
|
#include "barline.h"
|
|
#include "chord.h"
|
|
|
|
namespace Ms {
|
|
|
|
enum { GRIP_LINE_START, GRIP_LINE_END, GRIP_LINE_MIDDLE };
|
|
|
|
//---------------------------------------------------------
|
|
// LineSegment
|
|
//---------------------------------------------------------
|
|
|
|
LineSegment::LineSegment(Score* s)
|
|
: SpannerSegment(s)
|
|
{
|
|
}
|
|
|
|
LineSegment::LineSegment(const LineSegment& s)
|
|
: SpannerSegment(s)
|
|
{
|
|
_p2 = s._p2;
|
|
_userOff2 = s._userOff2;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// readProperties
|
|
//---------------------------------------------------------
|
|
|
|
bool LineSegment::readProperties(XmlReader& e)
|
|
{
|
|
const QStringRef& tag(e.name());
|
|
if (tag == "subtype")
|
|
setSpannerSegmentType(SpannerSegmentType(e.readInt()));
|
|
else if (tag == "off1") // obsolete
|
|
setUserOff(e.readPoint() * spatium());
|
|
else if (tag == "off2")
|
|
setUserOff2(e.readPoint() * spatium());
|
|
else if (tag == "pos") {
|
|
if (score()->mscVersion() > 114) {
|
|
qreal _spatium = spatium();
|
|
setUserOff(QPointF());
|
|
setReadPos(e.readPoint() * _spatium);
|
|
}
|
|
else
|
|
e.readNext();
|
|
}
|
|
else if (!Element::readProperties(e)) {
|
|
e.unknown();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// read
|
|
//---------------------------------------------------------
|
|
|
|
void LineSegment::read(XmlReader& e)
|
|
{
|
|
while (e.readNextStartElement())
|
|
readProperties(e);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// isEdited
|
|
//---------------------------------------------------------
|
|
|
|
bool LineSegment::isEdited(SpannerSegment* ss) const
|
|
{
|
|
LineSegment* ls = static_cast<LineSegment*>(ss);
|
|
if (pos() != ls->pos() || pos2() != ls->pos2())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateGrips
|
|
//---------------------------------------------------------
|
|
|
|
void LineSegment::updateGrips(int* grips, QRectF* grip) const
|
|
{
|
|
*grips = 3;
|
|
QPointF pp(pagePos());
|
|
grip[GRIP_LINE_START].translate(pp);
|
|
grip[GRIP_LINE_END].translate(pos2() + pp);
|
|
grip[GRIP_LINE_MIDDLE].translate(pos2() * .5 + pp);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setGrip
|
|
//---------------------------------------------------------
|
|
|
|
void LineSegment::setGrip(int grip, const QPointF& p)
|
|
{
|
|
QPointF pt(p * spatium());
|
|
|
|
switch (grip) {
|
|
case GRIP_LINE_START: {
|
|
QPointF delta(pt - userOff());
|
|
setUserOff(pt);
|
|
setUserOff2(userOff2() - delta);
|
|
}
|
|
break;
|
|
case GRIP_LINE_END:
|
|
setUserOff2(pt);
|
|
break;
|
|
case GRIP_LINE_MIDDLE:
|
|
setUserOff(pt);
|
|
break;
|
|
}
|
|
layout();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getGrip
|
|
//---------------------------------------------------------
|
|
|
|
QPointF LineSegment::getGrip(int grip) const
|
|
{
|
|
QPointF p;
|
|
switch(grip) {
|
|
case GRIP_LINE_START:
|
|
p = userOff();
|
|
break;
|
|
case GRIP_LINE_END:
|
|
p = userOff2();
|
|
break;
|
|
case GRIP_LINE_MIDDLE:
|
|
p = userOff();
|
|
break;
|
|
}
|
|
p /= spatium();
|
|
return p;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// pagePos
|
|
// return position in canvas coordinates
|
|
//---------------------------------------------------------
|
|
|
|
QPointF LineSegment::pagePos() const
|
|
{
|
|
QPointF pt(pos());
|
|
if (parent())
|
|
pt += parent()->pos();
|
|
return pt;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// gripAnchor
|
|
//---------------------------------------------------------
|
|
|
|
QPointF LineSegment::gripAnchor(int grip) const
|
|
{
|
|
if (spannerSegmentType() == SEGMENT_MIDDLE) {
|
|
qreal y = system()->staffY(staffIdx());
|
|
qreal x;
|
|
switch(grip) {
|
|
case GRIP_LINE_START:
|
|
x = system()->firstMeasure()->abbox().left();
|
|
break;
|
|
case GRIP_LINE_END:
|
|
x = system()->lastMeasure()->abbox().right();
|
|
break;
|
|
default:
|
|
case GRIP_LINE_MIDDLE:
|
|
x = 0; // No Anchor
|
|
y = 0;
|
|
break;
|
|
}
|
|
return QPointF(x, y);
|
|
}
|
|
else {
|
|
if (grip == GRIP_LINE_MIDDLE) // center grip
|
|
return QPointF(0, 0);
|
|
else {
|
|
System* s;
|
|
QPointF pt(line()->linePos(grip, &s));
|
|
return pt + s->pagePos();
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// edit
|
|
// return true if event is accepted
|
|
//---------------------------------------------------------
|
|
|
|
bool LineSegment::edit(MuseScoreView* sv, int curGrip, int key, Qt::KeyboardModifiers modifiers, const QString&)
|
|
{
|
|
if (!((modifiers & Qt::ShiftModifier)
|
|
&& ((spannerSegmentType() == SEGMENT_SINGLE)
|
|
|| (spannerSegmentType() == SEGMENT_BEGIN && curGrip == GRIP_LINE_START)
|
|
|| (spannerSegmentType() == SEGMENT_END && curGrip == GRIP_LINE_END))))
|
|
return false;
|
|
|
|
LineSegment* ls = 0;
|
|
SLine* l = line();
|
|
bool bspDirty = false;
|
|
SpannerSegmentType st = spannerSegmentType();
|
|
int track = l->track();
|
|
|
|
if (l->anchor() == Spanner::ANCHOR_SEGMENT) {
|
|
Segment* s1 = score()->tick2nearestSegment(spanner()->tick());
|
|
Segment* s2 = score()->tick2nearestSegment(spanner()->tick2());
|
|
if (!s1 || !s2)
|
|
return true;
|
|
|
|
if (key == Qt::Key_Left) {
|
|
if (curGrip == GRIP_LINE_START)
|
|
s1 = prevSeg1(s1, track);
|
|
else if (curGrip == GRIP_LINE_END || curGrip == GRIP_LINE_MIDDLE)
|
|
s2 = prevSeg1(s2, track);
|
|
}
|
|
else if (key == Qt::Key_Right) {
|
|
if (curGrip == GRIP_LINE_START)
|
|
s1 = nextSeg1(s1, track);
|
|
else if (curGrip == GRIP_LINE_END || curGrip == GRIP_LINE_MIDDLE) {
|
|
if ((s2->system()->firstMeasure() == s2->measure())
|
|
&& (s2->tick() == s2->measure()->tick()))
|
|
bspDirty = true;
|
|
s2 = nextSeg1(s2, track);
|
|
}
|
|
}
|
|
if (s1 == 0 || s2 == 0 || s1->tick() >= s2->tick())
|
|
return true;
|
|
if (s1->tick() != spanner()->tick())
|
|
spanner()->setTick(s1->tick());
|
|
if (s2->tick() != spanner()->tick2())
|
|
spanner()->setTick2(s2->tick());
|
|
}
|
|
else {
|
|
Measure* m1 = static_cast<Measure*>(l->startElement());
|
|
Measure* m2 = static_cast<Measure*>(l->endElement());
|
|
|
|
bool removeSegment = false;
|
|
|
|
if (key == Qt::Key_Left) {
|
|
if (curGrip == GRIP_LINE_START) {
|
|
if (m1->prevMeasure())
|
|
m1 = m1->prevMeasure();
|
|
}
|
|
else if (curGrip == GRIP_LINE_END || curGrip == GRIP_LINE_MIDDLE) {
|
|
if (m2 && (m2->system()->firstMeasure() == m2))
|
|
removeSegment = true;
|
|
Measure* m = m2->prevMeasure();
|
|
if (m)
|
|
m2 = m;
|
|
}
|
|
}
|
|
else if (key == Qt::Key_Right) {
|
|
if (curGrip == GRIP_LINE_START) {
|
|
if (m1->nextMeasure())
|
|
m1 = m1->nextMeasure();
|
|
}
|
|
else if (curGrip == GRIP_LINE_END || curGrip == GRIP_LINE_MIDDLE) {
|
|
if (m2->nextMeasure())
|
|
m2 = m2->nextMeasure();
|
|
if (m2->system()->firstMeasure() == m2)
|
|
bspDirty = true;
|
|
}
|
|
}
|
|
if (m1->tick() > m2->tick())
|
|
return true;
|
|
|
|
if (l->startElement() != m1) {
|
|
if (m1->system() != (static_cast<Measure*>(l->startElement())->system())) {
|
|
bspDirty = true;
|
|
if (key == Qt::Key_Right)
|
|
ls = l->takeFirstSegment();
|
|
}
|
|
l->startElement()->remove(l);
|
|
l->setTick(m1->tick());
|
|
m1->add(l);
|
|
}
|
|
else if (l->endElement() != m2) {
|
|
if (removeSegment) {
|
|
bspDirty = true;
|
|
if (key == Qt::Key_Left)
|
|
ls = l->takeLastSegment();
|
|
}
|
|
l->setTick2(m2->endTick());
|
|
}
|
|
}
|
|
l->layout();
|
|
|
|
LineSegment* nls = 0;
|
|
if (st == SEGMENT_SINGLE) {
|
|
if (curGrip == GRIP_LINE_START)
|
|
nls = l->frontSegment();
|
|
else if (curGrip == GRIP_LINE_END)
|
|
nls = l->backSegment();
|
|
}
|
|
else if (st == SEGMENT_BEGIN)
|
|
nls = l->frontSegment();
|
|
else if (st == SEGMENT_END)
|
|
nls = l->backSegment();
|
|
|
|
if (nls && (nls != this))
|
|
sv->changeEditElement(nls);
|
|
if (bspDirty)
|
|
_score->rebuildBspTree();
|
|
if (ls)
|
|
_score->undoRemoveElement(ls);
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// editDrag
|
|
//---------------------------------------------------------
|
|
|
|
void LineSegment::editDrag(const EditData& ed)
|
|
{
|
|
// Only for resizing according to the diagonal properties
|
|
QPointF deltaResize(ed.delta.x(), line()->diagonal() ? ed.delta.y() : 0.0);
|
|
|
|
// Only for moving, no y limitaion
|
|
QPointF deltaMove(ed.delta.x(), ed.delta.y());
|
|
|
|
switch (ed.curGrip) {
|
|
case GRIP_LINE_START: // Resize the begin of element (left grip)
|
|
setUserOff(userOff() + deltaResize);
|
|
_userOff2 -= deltaResize;
|
|
break;
|
|
case GRIP_LINE_END: // Resize the end of element (rigth grip)
|
|
_userOff2 += deltaResize;
|
|
break;
|
|
case GRIP_LINE_MIDDLE: // Move the element (middle grip)
|
|
setUserOff(userOff() + deltaMove);
|
|
break;
|
|
}
|
|
if ((line()->anchor() == Spanner::ANCHOR_NOTE)
|
|
&& (ed.curGrip == GRIP_LINE_START || ed.curGrip == GRIP_LINE_END)) {
|
|
//
|
|
// if we touch a different note, change anchor
|
|
//
|
|
Element* e = ed.view->elementNear(ed.pos);
|
|
if (e && e->type() == NOTE) {
|
|
SLine* l = line();
|
|
if (ed.curGrip == GRIP_LINE_END && e != line()->endElement()) {
|
|
qDebug("LineSegment: move end anchor");
|
|
Note* noteOld = static_cast<Note*>(l->endElement());
|
|
Note* noteNew = static_cast<Note*>(e);
|
|
|
|
noteOld->removeSpannerBack(l);
|
|
noteNew->addSpannerBack(l);
|
|
l->setEndElement(noteNew);
|
|
|
|
_userOff2 += noteOld->canvasPos() - noteNew->canvasPos();
|
|
}
|
|
else if (ed.curGrip == GRIP_LINE_START && e != l->startElement()) {
|
|
qDebug("LineSegment: move start anchor (not impl.)");
|
|
}
|
|
}
|
|
}
|
|
line()->layout();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// spatiumChanged
|
|
//---------------------------------------------------------
|
|
|
|
void LineSegment::spatiumChanged(qreal ov, qreal nv)
|
|
{
|
|
Element::spatiumChanged(ov, nv);
|
|
_userOff2 *= nv / ov;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// reset
|
|
// TODO: make undoable
|
|
//---------------------------------------------------------
|
|
|
|
void LineSegment::reset()
|
|
{
|
|
Element::reset();
|
|
setUserOff2(QPointF());
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// SLine
|
|
//---------------------------------------------------------
|
|
|
|
SLine::SLine(Score* s)
|
|
: Spanner(s)
|
|
{
|
|
_diagonal = false;
|
|
setTrack(0);
|
|
}
|
|
|
|
SLine::SLine(const SLine& s)
|
|
: Spanner(s)
|
|
{
|
|
_diagonal = s._diagonal;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// linePos
|
|
// return System() coordinates
|
|
//---------------------------------------------------------
|
|
|
|
QPointF SLine::linePos(int grip, System** sys)
|
|
{
|
|
qreal _spatium = spatium();
|
|
qreal x = 0.0;
|
|
switch(anchor()) {
|
|
case Spanner::ANCHOR_SEGMENT:
|
|
{
|
|
if (grip == GRIP_LINE_START) {
|
|
int t = tick();
|
|
Measure* m = score()->tick2measure(t);
|
|
*sys = m->system();
|
|
x = m->tick2pos(t);
|
|
}
|
|
else {
|
|
int t = tick2();
|
|
Measure* m = score()->tick2measure(t);
|
|
if (m->tick() == t) {
|
|
m = m->prevMeasure();
|
|
x = m->pos().x() + m->width();
|
|
}
|
|
else
|
|
x = m->tick2pos(t);
|
|
*sys = m->system();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Spanner::ANCHOR_MEASURE:
|
|
{
|
|
// anchor() == ANCHOR_MEASURE
|
|
Measure* m;
|
|
if (grip == GRIP_LINE_START) {
|
|
Q_ASSERT(startElement()->type() == MEASURE);
|
|
m = static_cast<Measure*>(startElement());
|
|
x = m->pos().x();
|
|
}
|
|
else {
|
|
Q_ASSERT(endElement()->type() == MEASURE);
|
|
m = static_cast<Measure*>(endElement());
|
|
x = m->pos().x() + m->bbox().right();
|
|
if (type() == VOLTA) {
|
|
if (score()->styleB(ST_createMultiMeasureRests)) {
|
|
//find the actual measure where the volta should stop
|
|
Measure* sm = static_cast<Measure*>(startElement());
|
|
bool foundMeasure = false;
|
|
while(sm != m) {
|
|
Measure* mm = sm;
|
|
int nn = mm->multiMeasure() - 1;
|
|
if (nn > 0) {
|
|
// skip to last rest measure of multi measure rest
|
|
for (int k = 0; k < nn; ++k) {
|
|
mm = mm->nextMeasure();
|
|
if(mm == m) {
|
|
m = sm;
|
|
foundMeasure = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (foundMeasure)
|
|
break;
|
|
sm = sm->nextMeasure();
|
|
}
|
|
x = m->pos().x() + m->bbox().right();
|
|
}
|
|
Segment* seg = m->last();
|
|
if (seg->segmentType() == Segment::SegEndBarLine) {
|
|
Element* e = seg->element(0);
|
|
if (e && e->type() == BAR_LINE) {
|
|
if (static_cast<BarLine*>(e)->barLineType() == START_REPEAT)
|
|
x -= e->width() - _spatium * .5;
|
|
else
|
|
x -= _spatium * .5;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Q_ASSERT(m->system());
|
|
*sys = m->system();
|
|
}
|
|
break;
|
|
|
|
case Spanner::ANCHOR_NOTE:
|
|
{
|
|
System* s = static_cast<Note*>(startElement())->chord()->segment()->system();
|
|
*sys = s;
|
|
if (grip == GRIP_LINE_START)
|
|
return startElement()->pagePos() - s->pagePos();
|
|
else
|
|
return endElement()->pagePos() - s->pagePos();
|
|
}
|
|
|
|
case Spanner::ANCHOR_CHORD:
|
|
qFatal("Sline::linePos(): anchor not implemented\n");
|
|
break;
|
|
}
|
|
qreal y = (*sys)->staves()->isEmpty() ? 0.0 : (*sys)->staff(staffIdx())->y();
|
|
return QPointF(x, y);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// layout
|
|
// compute segments from tick1 tick2
|
|
//---------------------------------------------------------
|
|
|
|
void SLine::layout()
|
|
{
|
|
if (score() == gscore || tick() == -1) {
|
|
//
|
|
// when used in a palette, SLine has no parent and
|
|
// tick and tick2 has no meaning so no layout is
|
|
// possible and needed
|
|
//
|
|
if (!spannerSegments().isEmpty()) {
|
|
LineSegment* s = frontSegment();
|
|
s->layout();
|
|
setbbox(s->bbox());
|
|
}
|
|
return;
|
|
}
|
|
|
|
computeStartElement();
|
|
computeEndElement();
|
|
|
|
System* s1;
|
|
System* s2;
|
|
QPointF p1 = linePos(GRIP_LINE_START, &s1);
|
|
QPointF p2 = linePos(GRIP_LINE_END, &s2);
|
|
|
|
QList<System*>* systems = score()->systems();
|
|
int sysIdx1 = systems->indexOf(s1);
|
|
int sysIdx2 = systems->indexOf(s2);
|
|
int segmentsNeeded = 0;
|
|
for (int i = sysIdx1; i < sysIdx2+1; ++i) {
|
|
if (systems->at(i)->isVbox())
|
|
continue;
|
|
++segmentsNeeded;
|
|
}
|
|
|
|
int segCount = spannerSegments().size();
|
|
|
|
if (segmentsNeeded != segCount) {
|
|
if (segmentsNeeded > segCount) {
|
|
int n = segmentsNeeded - segCount;
|
|
for (int i = 0; i < n; ++i) {
|
|
LineSegment* ls = createLineSegment();
|
|
add(ls);
|
|
// set user offset to previous segment's offset
|
|
if (segCount > 0)
|
|
ls->setUserOff(QPointF(0, segmentAt(segCount+i-1)->userOff().y()));
|
|
}
|
|
}
|
|
else {
|
|
int n = segCount - segmentsNeeded;
|
|
// qDebug("SLine: segments %d needed %d, remove %d", segCount, segmentsNeeded, n);
|
|
for (int i = 0; i < n; ++i) {
|
|
if (spannerSegments().isEmpty()) {
|
|
qDebug("SLine::layout(): no segment %d, %d expected", i, n);
|
|
break;
|
|
}
|
|
else {
|
|
// LineSegment* seg = takeLastSegment();
|
|
// TODO delete seg;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int segIdx = 0;
|
|
int si = staffIdx();
|
|
for (int i = sysIdx1; i <= sysIdx2; ++i) {
|
|
System* system = systems->at(i);
|
|
if (system->isVbox())
|
|
continue;
|
|
LineSegment* seg = segmentAt(segIdx++);
|
|
seg->setTrack(track()); // DEBUG
|
|
seg->setSystem(system);
|
|
|
|
Measure* m = system->firstMeasure();
|
|
Segment* mseg = m->first(Segment::SegChordRest);
|
|
qreal x1 = (mseg ? mseg->pos().x() : 0) + m->pos().x();
|
|
qreal x2 = system->bbox().right();
|
|
qreal y = system->staff(si)->y();
|
|
|
|
if (sysIdx1 == sysIdx2) {
|
|
// single segment
|
|
seg->setSpannerSegmentType(SEGMENT_SINGLE);
|
|
seg->setPos(p1);
|
|
seg->setPos2(p2 - p1);
|
|
}
|
|
else if (i == sysIdx1) {
|
|
// start segment
|
|
seg->setSpannerSegmentType(SEGMENT_BEGIN);
|
|
seg->setPos(p1);
|
|
seg->setPos2(QPointF(x2 - p1.x(), 0.0));
|
|
}
|
|
else if (i > 0 && i != sysIdx2) {
|
|
// middle segment
|
|
seg->setSpannerSegmentType(SEGMENT_MIDDLE);
|
|
seg->setPos(QPointF(x1, y));
|
|
seg->setPos2(QPointF(x2 - x1, 0.0));
|
|
}
|
|
else if (i == sysIdx2) {
|
|
// end segment
|
|
seg->setSpannerSegmentType(SEGMENT_END);
|
|
seg->setPos(QPointF(x1, y));
|
|
seg->setPos2(QPointF(p2.x() - x1, 0.0));
|
|
}
|
|
seg->layout();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// writeProperties
|
|
// write properties different from prototype
|
|
//---------------------------------------------------------
|
|
|
|
void SLine::writeProperties(Xml& xml, const SLine* proto) const
|
|
{
|
|
Element::writeProperties(xml);
|
|
if (_diagonal && (proto == 0 || proto->diagonal() != _diagonal))
|
|
xml.tag("diagonal", _diagonal);
|
|
if (anchor() != Spanner::ANCHOR_SEGMENT && (proto == 0 || proto->anchor() != anchor()))
|
|
xml.tag("anchor", anchor());
|
|
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");
|
|
xml.tag("subtype", seg->spannerSegmentType());
|
|
xml.tag("off2", seg->userOff2() / _spatium);
|
|
seg->Element::writeProperties(xml);
|
|
xml.etag();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// readProperties
|
|
//---------------------------------------------------------
|
|
|
|
bool SLine::readProperties(XmlReader& e)
|
|
{
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "tick2") // obsolete
|
|
setTick2(e.readInt());
|
|
else if (tag == "tick") // obsolete
|
|
setTick(e.readInt());
|
|
else if (tag == "Segment") {
|
|
LineSegment* ls = createLineSegment();
|
|
ls->read(e);
|
|
add(ls);
|
|
}
|
|
else if (tag == "length")
|
|
setLen(e.readDouble());
|
|
else if (tag == "diagonal")
|
|
setDiagonal(e.readInt());
|
|
else if (tag == "anchor")
|
|
setAnchor(Anchor(e.readInt()));
|
|
else if (Element::readProperties(e))
|
|
;
|
|
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
|
|
//---------------------------------------------------------
|
|
|
|
const QRectF& SLine::bbox() const
|
|
{
|
|
if (spannerSegments().isEmpty())
|
|
setbbox(QRectF());
|
|
else
|
|
setbbox(segmentAt(0)->bbox());
|
|
return Element::bbox();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// write
|
|
//---------------------------------------------------------
|
|
|
|
void SLine::write(Xml& xml) const
|
|
{
|
|
xml.stag(QString("%1 id=\"%2\"").arg(name()).arg(id()));
|
|
SLine::writeProperties(xml);
|
|
xml.etag();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// read
|
|
//---------------------------------------------------------
|
|
|
|
void SLine::read(XmlReader& e)
|
|
{
|
|
foreach(SpannerSegment* seg, spannerSegments())
|
|
delete seg;
|
|
spannerSegments().clear();
|
|
setId(e.intAttribute("id", -1));
|
|
|
|
while (e.readNextStartElement()) {
|
|
if (!SLine::readProperties(e))
|
|
e.unknown();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getProperty
|
|
//---------------------------------------------------------
|
|
|
|
QVariant SLine::getProperty(P_ID id) const
|
|
{
|
|
switch(id) {
|
|
case P_DIAGONAL:
|
|
return _diagonal;
|
|
default:
|
|
return Spanner::getProperty(id);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setProperty
|
|
//---------------------------------------------------------
|
|
|
|
bool SLine::setProperty(P_ID id, const QVariant& v)
|
|
{
|
|
switch(id) {
|
|
case P_DIAGONAL:
|
|
_diagonal = v.toBool();
|
|
break;
|
|
default:
|
|
return Spanner::setProperty(id, v);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// propertyDefault
|
|
//---------------------------------------------------------
|
|
|
|
QVariant SLine::propertyDefault(P_ID id) const
|
|
{
|
|
switch(id) {
|
|
case P_DIAGONAL: return false;
|
|
default: return Spanner::propertyDefault(id);
|
|
}
|
|
}
|
|
|
|
}
|
|
|