[engraving] moved spanner writer

This commit is contained in:
Igor Korsukov 2023-04-24 13:09:32 +03:00
parent 5cda56428e
commit 2f73287459
9 changed files with 255 additions and 200 deletions

View file

@ -93,6 +93,8 @@ set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/rw/400/tread.h
${CMAKE_CURRENT_LIST_DIR}/rw/400/twrite.cpp
${CMAKE_CURRENT_LIST_DIR}/rw/400/twrite.h
${CMAKE_CURRENT_LIST_DIR}/rw/400/connectorinfowriter.cpp
${CMAKE_CURRENT_LIST_DIR}/rw/400/connectorinfowriter.h
${CMAKE_CURRENT_LIST_DIR}/rw/compat/readstyle.cpp
${CMAKE_CURRENT_LIST_DIR}/rw/compat/readstyle.h

View file

@ -335,51 +335,6 @@ ConnectorInfoReader::ConnectorInfoReader(XmlReader& e, Score* current, int track
setCurrentUpdated(true);
}
//---------------------------------------------------------
// ConnectorInfoWriter
//---------------------------------------------------------
ConnectorInfoWriter::ConnectorInfoWriter(XmlWriter& xml, const EngravingItem* current, const EngravingItem* connector, int track,
Fraction frac)
: ConnectorInfo(current, track, frac), _xml(&xml), _connector(connector)
{
IF_ASSERT_FAILED(current) {
return;
}
_type = connector->type();
updateCurrentInfo(xml.context()->clipboardmode());
}
//---------------------------------------------------------
// ConnectorInfoWriter::write
//---------------------------------------------------------
void ConnectorInfoWriter::write()
{
XmlWriter& xml = *_xml;
WriteContext& ctx = *xml.context();
if (!ctx.canWrite(_connector)) {
return;
}
xml.startElement(tagName(), { { "type", _connector->typeName() } });
if (isStart()) {
rw400::TWrite::writeItem(_connector, xml, ctx);
}
if (hasPrevious()) {
xml.startElement("prev");
_prevLoc.toRelative(_currentLoc);
rw400::TWrite::write(&_prevLoc, xml, ctx);
xml.endElement();
}
if (hasNext()) {
xml.startElement("next");
_nextLoc.toRelative(_currentLoc);
rw400::TWrite::write(&_nextLoc, xml, ctx);
xml.endElement();
}
xml.endElement();
}
//---------------------------------------------------------
// ConnectorInfoReader::read
//---------------------------------------------------------

View file

@ -136,35 +136,5 @@ public:
static void readConnector(std::unique_ptr<ConnectorInfoReader> info, XmlReader& e);
};
//---------------------------------------------------------
// @@ ConnectorInfoWriter
/// Helper class for writing connecting elements.
/// Subclasses should fill _prevInfo and _nextInfo with
/// the proper information on the connector's endpoints.
//---------------------------------------------------------
class ConnectorInfoWriter : public ConnectorInfo
{
OBJECT_ALLOCATOR(engraving, ConnectorInfoWriter)
XmlWriter* _xml;
protected:
const EngravingItem* _connector;
virtual const char* tagName() const = 0;
public:
ConnectorInfoWriter(XmlWriter& xml, const EngravingItem* current, const EngravingItem* connector, int track = -1, Fraction = { -1, 1 });
virtual ~ConnectorInfoWriter() = default;
ConnectorInfoWriter* prev() const { return static_cast<ConnectorInfoWriter*>(_prev); }
ConnectorInfoWriter* next() const { return static_cast<ConnectorInfoWriter*>(_next); }
const EngravingItem* connector() const { return _connector; }
void write();
};
} // namespace mu::engraving
#endif

View file

@ -43,22 +43,6 @@ using namespace mu;
using namespace mu::engraving;
namespace mu::engraving {
//-----------------------------------------------------------------------------
// @@ SpannerWriter
/// Helper class for writing Spanners
//-----------------------------------------------------------------------------
class SpannerWriter : public ConnectorInfoWriter
{
OBJECT_ALLOCATOR(engraving, SpannerWriter)
protected:
const char* tagName() const override { return "Spanner"; }
public:
SpannerWriter(XmlWriter& xml, const EngravingItem* current, const Spanner* spanner, int track, Fraction frac, bool start);
static void fillSpannerPosition(Location& l, const MeasureBase* endpoint, const Fraction& tick, bool clipboardmode);
};
//---------------------------------------------------------
// SpannerSegment
//---------------------------------------------------------
@ -1451,44 +1435,6 @@ void Spanner::layoutSystemsDone()
segments = std::move(validSegments);
}
//--------------------------------------------------
// fraction
//---------------------------------------------------------
static Fraction fraction(const XmlWriter& xml, const EngravingItem* current, const Fraction& t)
{
Fraction tick(t);
if (!xml.context()->clipboardmode()) {
const Measure* m = toMeasure(current->findMeasure());
if (m) {
tick -= m->tick();
}
}
return tick;
}
//--------------------------------------------------
// Spanner::writeSpannerStart
//---------------------------------------------------------
void Spanner::writeSpannerStart(XmlWriter& xml, const EngravingItem* current, track_idx_t track, Fraction tick) const
{
Fraction frac = fraction(xml, current, tick);
SpannerWriter w(xml, current, this, static_cast<int>(track), frac, true);
w.write();
}
//--------------------------------------------------
// Spanner::writeSpannerEnd
//---------------------------------------------------------
void Spanner::writeSpannerEnd(XmlWriter& xml, const EngravingItem* current, track_idx_t track, Fraction tick) const
{
Fraction frac = fraction(xml, current, tick);
SpannerWriter w(xml, current, this, static_cast<int>(track), frac, false);
w.write();
}
//--------------------------------------------------
// Spanner::readSpanner
//---------------------------------------------------------
@ -1509,66 +1455,6 @@ void Spanner::readSpanner(XmlReader& e, Score* current, track_idx_t track)
ConnectorInfoReader::readConnector(std::move(info), e);
}
//---------------------------------------------------------
// SpannerWriter::fillSpannerPosition
//---------------------------------------------------------
void SpannerWriter::fillSpannerPosition(Location& l, const MeasureBase* m, const Fraction& tick, bool clipboardmode)
{
if (clipboardmode) {
l.setMeasure(0);
l.setFrac(tick);
} else {
if (!m) {
LOGW("fillSpannerPosition: couldn't find spanner's endpoint's measure");
l.setMeasure(0);
l.setFrac(tick);
return;
}
l.setMeasure(m->measureIndex());
l.setFrac(tick - m->tick());
}
}
//---------------------------------------------------------
// SpannerWriter::SpannerWriter
//---------------------------------------------------------
SpannerWriter::SpannerWriter(XmlWriter& xml, const EngravingItem* current, const Spanner* sp, int track, Fraction frac, bool start)
: ConnectorInfoWriter(xml, current, sp, track, frac)
{
const bool clipboardmode = xml.context()->clipboardmode();
if (!sp->startElement() || !sp->endElement()) {
LOGW("SpannerWriter: spanner (%s) doesn't have an endpoint!", sp->typeName());
return;
}
if (current->isMeasure() || current->isSegment() || (sp->startElement()->type() != current->type())) {
// (The latter is the hairpins' case, for example, though they are
// covered by the other checks too.)
// We cannot determine position of the spanner from its start/end
// elements and will try to obtain this info from the spanner itself.
if (!start) {
_prevLoc.setTrack(static_cast<int>(sp->track()));
Measure* m = sp->score()->tick2measure(sp->tick());
fillSpannerPosition(_prevLoc, m, sp->tick(), clipboardmode);
} else {
const track_idx_t track2 = (sp->track2() != mu::nidx) ? sp->track2() : sp->track();
_nextLoc.setTrack(static_cast<int>(track2));
Measure* m = sp->score()->tick2measure(sp->tick2());
fillSpannerPosition(_nextLoc, m, sp->tick2(), clipboardmode);
}
} else {
// We can obtain the spanner position info from its start/end
// elements and will prefer this source of information.
// Reason: some spanners contain no or wrong information (e.g. Ties).
if (!start) {
updateLocation(sp->startElement(), _prevLoc, clipboardmode);
} else {
updateLocation(sp->endElement(), _nextLoc, clipboardmode);
}
}
}
//---------------------------------------------------------
// autoplaceSpannerSegment
//---------------------------------------------------------

View file

@ -189,8 +189,6 @@ public:
virtual void setScore(Score* s) override;
void writeSpannerStart(XmlWriter& xml, const EngravingItem* current, track_idx_t track, Fraction frac = { -1, 1 }) const;
void writeSpannerEnd(XmlWriter& xml, const EngravingItem* current, track_idx_t track, Fraction frac = { -1, 1 }) const;
static void readSpanner(XmlReader& e, EngravingItem* current, track_idx_t track);
static void readSpanner(XmlReader& e, Score* current, track_idx_t track);

View file

@ -0,0 +1,134 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "connectorinfowriter.h"
#include "../../libmscore/engravingitem.h"
#include "../../libmscore/spanner.h"
#include "../../libmscore/measurebase.h"
#include "../../libmscore/measure.h"
#include "../../libmscore/score.h"
#include "../xmlwriter.h"
#include "twrite.h"
#include "log.h"
using namespace mu::engraving;
using namespace mu::engraving::rw400;
ConnectorInfoWriter::ConnectorInfoWriter(XmlWriter& xml, const EngravingItem* current, const EngravingItem* connector, int track,
Fraction frac)
: ConnectorInfo(current, track, frac), _xml(&xml), _connector(connector)
{
IF_ASSERT_FAILED(current) {
return;
}
_type = connector->type();
updateCurrentInfo(xml.context()->clipboardmode());
}
void ConnectorInfoWriter::write()
{
XmlWriter& xml = *_xml;
WriteContext& ctx = *xml.context();
if (!ctx.canWrite(_connector)) {
return;
}
xml.startElement(tagName(), { { "type", _connector->typeName() } });
if (isStart()) {
rw400::TWrite::writeItem(_connector, xml, ctx);
}
if (hasPrevious()) {
xml.startElement("prev");
_prevLoc.toRelative(_currentLoc);
rw400::TWrite::write(&_prevLoc, xml, ctx);
xml.endElement();
}
if (hasNext()) {
xml.startElement("next");
_nextLoc.toRelative(_currentLoc);
rw400::TWrite::write(&_nextLoc, xml, ctx);
xml.endElement();
}
xml.endElement();
}
//---------------------------------------------------------
// SpannerWriter::fillSpannerPosition
//---------------------------------------------------------
void SpannerWriter::fillSpannerPosition(Location& l, const MeasureBase* m, const Fraction& tick, bool clipboardmode)
{
if (clipboardmode) {
l.setMeasure(0);
l.setFrac(tick);
} else {
if (!m) {
LOGW("fillSpannerPosition: couldn't find spanner's endpoint's measure");
l.setMeasure(0);
l.setFrac(tick);
return;
}
l.setMeasure(m->measureIndex());
l.setFrac(tick - m->tick());
}
}
//---------------------------------------------------------
// SpannerWriter::SpannerWriter
//---------------------------------------------------------
SpannerWriter::SpannerWriter(XmlWriter& xml, const EngravingItem* current, const Spanner* sp, int track, Fraction frac, bool start)
: ConnectorInfoWriter(xml, current, sp, track, frac)
{
const bool clipboardmode = xml.context()->clipboardmode();
if (!sp->startElement() || !sp->endElement()) {
LOGW("SpannerWriter: spanner (%s) doesn't have an endpoint!", sp->typeName());
return;
}
if (current->isMeasure() || current->isSegment() || (sp->startElement()->type() != current->type())) {
// (The latter is the hairpins' case, for example, though they are
// covered by the other checks too.)
// We cannot determine position of the spanner from its start/end
// elements and will try to obtain this info from the spanner itself.
if (!start) {
_prevLoc.setTrack(static_cast<int>(sp->track()));
Measure* m = sp->score()->tick2measure(sp->tick());
fillSpannerPosition(_prevLoc, m, sp->tick(), clipboardmode);
} else {
const track_idx_t track2 = (sp->track2() != mu::nidx) ? sp->track2() : sp->track();
_nextLoc.setTrack(static_cast<int>(track2));
Measure* m = sp->score()->tick2measure(sp->tick2());
fillSpannerPosition(_nextLoc, m, sp->tick2(), clipboardmode);
}
} else {
// We can obtain the spanner position info from its start/end
// elements and will prefer this source of information.
// Reason: some spanners contain no or wrong information (e.g. Ties).
if (!start) {
updateLocation(sp->startElement(), _prevLoc, clipboardmode);
} else {
updateLocation(sp->endElement(), _nextLoc, clipboardmode);
}
}
}

View file

@ -0,0 +1,80 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MU_ENGRAVING_CONNECTORINFOWRITER_H
#define MU_ENGRAVING_CONNECTORINFOWRITER_H
#include "../../libmscore/connector.h"
//---------------------------------------------------------
// @@ ConnectorInfoWriter
/// Helper class for writing connecting elements.
/// Subclasses should fill _prevInfo and _nextInfo with
/// the proper information on the connector's endpoints.
//---------------------------------------------------------
namespace mu::engraving {
class Spanner;
class MeasureBase;
}
namespace mu::engraving::rw400 {
class ConnectorInfoWriter : public ConnectorInfo
{
OBJECT_ALLOCATOR(engraving, ConnectorInfoWriter)
XmlWriter* _xml;
protected:
const EngravingItem* _connector;
virtual const char* tagName() const = 0;
public:
ConnectorInfoWriter(XmlWriter& xml, const EngravingItem* current, const EngravingItem* connector, int track = -1, Fraction = { -1, 1 });
virtual ~ConnectorInfoWriter() = default;
ConnectorInfoWriter* prev() const { return static_cast<ConnectorInfoWriter*>(_prev); }
ConnectorInfoWriter* next() const { return static_cast<ConnectorInfoWriter*>(_next); }
const EngravingItem* connector() const { return _connector; }
void write();
};
//-----------------------------------------------------------------------------
// @@ SpannerWriter
/// Helper class for writing Spanners
//-----------------------------------------------------------------------------
class SpannerWriter : public ConnectorInfoWriter
{
OBJECT_ALLOCATOR(engraving, SpannerWriter)
protected:
const char* tagName() const override { return "Spanner"; }
public:
SpannerWriter(XmlWriter& xml, const EngravingItem* current, const Spanner* spanner, int track, Fraction frac, bool start);
static void fillSpannerPosition(Location& l, const MeasureBase* endpoint, const Fraction& tick, bool clipboardmode);
};
}
#endif // MU_ENGRAVING_CONNECTORINFOWRITER_H

View file

@ -149,6 +149,7 @@
#include "../xmlwriter.h"
#include "writecontext.h"
#include "connectorinfowriter.h"
#include "log.h"
@ -761,13 +762,39 @@ void TWrite::writeProperties(const ChordRest* item, XmlWriter& xml, WriteContext
}
if (s->startElement() == item) {
s->writeSpannerStart(xml, item, item->track());
writeSpannerStart(s, xml, item, item->track());
} else if (s->endElement() == item) {
s->writeSpannerEnd(xml, item, item->track());
writeSpannerEnd(s, xml, item, item->track());
}
}
}
static Fraction fraction(const XmlWriter& xml, const EngravingItem* current, const Fraction& t)
{
Fraction tick(t);
if (!xml.context()->clipboardmode()) {
const Measure* m = toMeasure(current->findMeasure());
if (m) {
tick -= m->tick();
}
}
return tick;
}
void TWrite::writeSpannerStart(Spanner* s, XmlWriter& xml, const EngravingItem* current, track_idx_t track, Fraction tick)
{
Fraction frac = fraction(xml, current, tick);
SpannerWriter w(xml, current, s, static_cast<int>(track), frac, true);
w.write();
}
void TWrite::writeSpannerEnd(Spanner* s, XmlWriter& xml, const EngravingItem* current, track_idx_t track, Fraction tick)
{
Fraction frac = fraction(xml, current, tick);
SpannerWriter w(xml, current, s, static_cast<int>(track), frac, false);
w.write();
}
void TWrite::write(const ChordLine* item, XmlWriter& xml, WriteContext& ctx)
{
xml.startElement(item);
@ -1631,10 +1658,10 @@ void TWrite::write(const Note* item, XmlWriter& xml, WriteContext& ctx)
}
}
if (item->tieFor()) {
item->tieFor()->writeSpannerStart(xml, item, item->track());
writeSpannerStart(item->tieFor(), xml, item, item->track());
}
if (item->tieBack()) {
item->tieBack()->writeSpannerEnd(xml, item, item->track());
writeSpannerEnd(item->tieBack(), xml, item, item->track());
}
if ((item->chord() == 0 || item->chord()->playEventType() != PlayEventType::Auto) && !item->playEvents().empty()) {
xml.startElement("Events");
@ -1650,10 +1677,10 @@ void TWrite::write(const Note* item, XmlWriter& xml, WriteContext& ctx)
}
for (Spanner* e : item->spannerFor()) {
e->writeSpannerStart(xml, item, item->track());
writeSpannerStart(e, xml, item, item->track());
}
for (Spanner* e : item->spannerBack()) {
e->writeSpannerEnd(xml, item, item->track());
writeSpannerEnd(e, xml, item, item->track());
}
for (EngravingItem* e : item->chord()->el()) {
@ -2592,7 +2619,7 @@ void TWrite::writeSegments(XmlWriter& xml, WriteContext& ctx, track_idx_t strack
voiceTagWritten |= writeVoiceMove(xml, ctx, segment, startTick, track, &lastTrackWritten);
needMove = false;
}
s->writeSpannerStart(xml, segment, track);
writeSpannerStart(s, xml, segment, track);
}
}
if ((s->tick2() == segment->tick())
@ -2604,7 +2631,7 @@ void TWrite::writeSegments(XmlWriter& xml, WriteContext& ctx, track_idx_t strack
voiceTagWritten |= writeVoiceMove(xml, ctx, segment, startTick, track, &lastTrackWritten);
needMove = false;
}
s->writeSpannerEnd(xml, segment, track);
writeSpannerEnd(s, xml, segment, track);
}
}
}
@ -2675,7 +2702,7 @@ void TWrite::writeSegments(XmlWriter& xml, WriteContext& ctx, track_idx_t strack
&& (s->track2() == track || (s->track2() == mu::nidx && s->track() == track))
&& (!clip || s->tick() >= sseg->tick())
) {
s->writeSpannerEnd(xml, score->lastMeasure(), track, endTick);
writeSpannerEnd(s, xml, score->lastMeasure(), track, endTick);
}
}
}

View file

@ -304,6 +304,9 @@ private:
static void writeProperties(const TextLineBase* item, XmlWriter& xml, WriteContext& ctx);
static void writeProperties(const TextBase* item, XmlWriter& xml, WriteContext& ctx, bool writeText);
static void writeSpannerStart(Spanner* s, XmlWriter& xml, const EngravingItem* current, track_idx_t track, Fraction frac = { -1, 1 });
static void writeSpannerEnd(Spanner* s, XmlWriter& xml, const EngravingItem* current, track_idx_t track, Fraction frac = { -1, 1 });
};
}