Create Score Tree Model

This commit adds virtual functions treeChild, treeParent and
treeChildCount to ScoreElement and implements them in most non-leaf-node
classes. An iterator is also added to ScoreElement class to iterate over
the children of any element.

In this model, Spanners, Beams and Ties are given a single parent, which
is the starting element of the spanner, beam or tie. Also, to ensure
consistency in the model, spanners, beams, and ties appear in the
children list only for their starting element. Children of spanner
elements are SpannerSegments, one for each system the spanner appears
in.
This commit is contained in:
Kumar Kartikay 2020-06-19 23:16:59 +05:30
parent 4650a2fe3c
commit a87cc9e6cc
27 changed files with 1139 additions and 62 deletions

View file

@ -72,7 +72,7 @@ add_library (
measure.cpp navigate.cpp note.cpp noteevent.cpp ottava.cpp
page.cpp part.cpp pedal.cpp letring.cpp vibrato.cpp palmmute.cpp pitch.cpp pitchspelling.cpp
rendermidi.cpp repeat.cpp repeatlist.cpp rest.cpp
score.cpp segment.cpp select.cpp shadownote.cpp slur.cpp tie.cpp slurtie.cpp
score.cpp scoretree.cpp segment.cpp select.cpp shadownote.cpp slur.cpp tie.cpp slurtie.cpp
spacer.cpp spanner.cpp staff.cpp staffstate.cpp
stafftextbase.cpp stafftext.cpp systemtext.cpp stafftype.cpp stem.cpp style.cpp symbol.cpp
sym.cpp system.cpp stringdata.cpp tempotext.cpp text.cpp measurenumber.cpp textbase.cpp textedit.cpp

View file

@ -80,6 +80,11 @@ public:
Accidental* clone() const override { return new Accidental(*this); }
ElementType type() const override { return ElementType::ACCIDENTAL; }
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
QString subtypeUserName() const;
void setSubtype(const QString& s);
void setAccidentalType(AccidentalType t) { _accidentalType = t; }

View file

@ -46,6 +46,11 @@ public:
ElementType type() const override { return ElementType::AMBITUS; }
Ambitus* clone() const override { return new Ambitus(*this); }
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
qreal mag() const override;
void initFrom(Ambitus* a);

View file

@ -76,6 +76,11 @@ public:
BarLine(const BarLine&);
BarLine& operator=(const BarLine&) = delete;
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
BarLine* clone() const override { return new BarLine(*this); }
ElementType type() const override { return ElementType::BAR_LINE; }
Fraction playTick() const override;

View file

@ -80,6 +80,12 @@ public:
Beam(Score* = 0);
Beam(const Beam&);
~Beam();
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
Beam* clone() const override { return new Beam(*this); }
ElementType type() const override { return ElementType::BEAM; }
QPointF pagePos() const override; ///< position in page coordinates

View file

@ -30,6 +30,11 @@ public:
BSymbol(Score* s, ElementFlags f = ElementFlag::NOTHING);
BSymbol(const BSymbol&);
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
BSymbol& operator=(const BSymbol&) = delete;
virtual void add(Element*) override;

View file

@ -94,6 +94,11 @@ public:
~Chord();
Chord& operator=(const Chord&) = delete;
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
Chord* clone() const override { return new Chord(*this, false); }
Element* linkedClone() override { return new Chord(*this, true); }
void undoUnlink() override;

View file

@ -74,6 +74,11 @@ public:
virtual ElementType type() const = 0;
// Score Tree functions
virtual ScoreElement* treeParent() const override;
virtual ScoreElement* treeChild(int idx) const override;
virtual int treeChildCount() const override;
virtual Element* drop(EditData&) override;
virtual void undoUnlink() override;

View file

@ -200,6 +200,8 @@ public:
Element* parent() const { return _parent; }
void setParent(Element* e) { _parent = e; }
virtual ScoreElement* treeParent() const override { return _parent; }
Element* findAncestor(ElementType t);
const Element* findAncestor(ElementType t) const;

View file

@ -164,10 +164,15 @@ public:
FretDiagram(const FretDiagram&);
~FretDiagram();
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
void draw(QPainter*) const override;
FretDiagram* clone() const override { return new FretDiagram(*this); }
Segment* segment() { return toSegment(parent()); }
Segment* segment() const { return toSegment(parent()); }
static FretDiagram* fromString(Score* score, const QString& s);

View file

@ -88,54 +88,6 @@ namespace Ms {
/// Per staff values of measure.
//---------------------------------------------------------
class MStaff
{
MeasureNumber* _noText { 0 }; ///< Measure number text object
StaffLines* _lines { 0 };
Spacer* _vspacerUp { 0 };
Spacer* _vspacerDown { 0 };
bool _hasVoices { false }; ///< indicates that MStaff contains more than one voice,
///< this changes some layout rules
bool _visible { true };
bool _stemless { false };
#ifndef NDEBUG
bool _corrupted { false };
#endif
public:
MStaff() {}
~MStaff();
MStaff(const MStaff&);
void setScore(Score*);
void setTrack(int);
MeasureNumber* noText() const { return _noText; }
void setNoText(MeasureNumber* t) { _noText = t; }
StaffLines* lines() const { return _lines; }
void setLines(StaffLines* l) { _lines = l; }
Spacer* vspacerUp() const { return _vspacerUp; }
void setVspacerUp(Spacer* s) { _vspacerUp = s; }
Spacer* vspacerDown() const { return _vspacerDown; }
void setVspacerDown(Spacer* s) { _vspacerDown = s; }
bool hasVoices() const { return _hasVoices; }
void setHasVoices(bool val) { _hasVoices = val; }
bool visible() const { return _visible; }
void setVisible(bool val) { _visible = val; }
bool stemless() const { return _stemless; }
void setStemless(bool val) { _stemless = val; }
#ifndef NDEBUG
bool corrupted() const { return _corrupted; }
void setCorrupted(bool val) { _corrupted = val; }
#endif
};
MStaff::~MStaff()
{
delete _noText;

View file

@ -53,6 +53,59 @@ enum class MeasureNumberMode : char {
HIDE // dont show measure number
};
//---------------------------------------------------------
// MStaff
/// Per staff values of measure.
//---------------------------------------------------------
class MStaff
{
MeasureNumber* _noText { 0 }; ///< Measure number text object
StaffLines* _lines { 0 };
Spacer* _vspacerUp { 0 };
Spacer* _vspacerDown { 0 };
bool _hasVoices { false }; ///< indicates that MStaff contains more than one voice,
///< this changes some layout rules
bool _visible { true };
bool _stemless { false };
#ifndef NDEBUG
bool _corrupted { false };
#endif
public:
MStaff() {}
~MStaff();
MStaff(const MStaff&);
void setScore(Score*);
void setTrack(int);
MeasureNumber* noText() const { return _noText; }
void setNoText(MeasureNumber* t) { _noText = t; }
StaffLines* lines() const { return _lines; }
void setLines(StaffLines* l) { _lines = l; }
Spacer* vspacerUp() const { return _vspacerUp; }
void setVspacerUp(Spacer* s) { _vspacerUp = s; }
Spacer* vspacerDown() const { return _vspacerDown; }
void setVspacerDown(Spacer* s) { _vspacerDown = s; }
bool hasVoices() const { return _hasVoices; }
void setHasVoices(bool val) { _hasVoices = val; }
bool visible() const { return _visible; }
void setVisible(bool val) { _visible = val; }
bool stemless() const { return _stemless; }
void setStemless(bool val) { _stemless = val; }
#ifndef NDEBUG
bool corrupted() const { return _corrupted; }
void setCorrupted(bool val) { _corrupted = val; }
#endif
};
//---------------------------------------------------------
// @@ Measure
/// one measure in a system
@ -101,6 +154,11 @@ public:
void setScore(Score* s) override;
Measure* cloneMeasure(Score*, const Fraction& tick, TieMap*);
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
void read(XmlReader&, int idx);
void read(XmlReader& d) { read(d, 0); }
void readAddConnector(ConnectorInfoReader* info, bool pasteMode) override;

View file

@ -80,6 +80,11 @@ public:
~MeasureBase();
MeasureBase(const MeasureBase&);
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
virtual MeasureBase* clone() const = 0;
virtual ElementType type() const = 0;

View file

@ -320,6 +320,11 @@ public:
Note(const Note&, bool link = false);
~Note();
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
Note& operator=(const Note&) = delete;
virtual Note* clone() const override { return new Note(*this, false); }
ElementType type() const override { return ElementType::NOTE; }

View file

@ -47,6 +47,11 @@ public:
Page(Score*);
~Page();
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
Page* clone() const override { return new Page(*this); }
ElementType type() const override { return ElementType::PAGE; }
const QList<System*>& systems() const { return _systems; }

View file

@ -47,6 +47,11 @@ public:
Rest(const Rest&, bool link = false);
~Rest() { qDeleteAll(_dots); }
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
virtual ElementType type() const override { return ElementType::REST; }
Rest& operator=(const Rest&) = delete;

View file

@ -605,6 +605,11 @@ public:
static void onElementDestruction(Element* se);
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
virtual inline QList<Excerpt*>& excerpts();
virtual inline const QList<Excerpt*>& excerpts() const;

View file

@ -164,7 +164,7 @@ ScoreElement::ScoreElement(const ScoreElement& se)
}
//---------------------------------------------------------
// ~Element
// ~ScoreElement
//---------------------------------------------------------
ScoreElement::~ScoreElement()
@ -179,6 +179,22 @@ ScoreElement::~ScoreElement()
delete[] _propertyFlagsList;
}
//---------------------------------------------------------
// treeChildIdx
//---------------------------------------------------------
int ScoreElement::treeChildIdx(ScoreElement* child) const
{
int i = 0;
for (const ScoreElement* el : (*this)) {
if (el == child) {
return i;
}
i++;
}
return -1;
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------

View file

@ -187,6 +187,43 @@ public:
virtual ~ScoreElement();
// Score Tree functions
virtual ScoreElement* treeParent() const { return nullptr; }
virtual ScoreElement* treeChild(int n) const { Q_UNUSED(n); return nullptr; }
virtual int treeChildCount() const { return 0; }
int treeChildIdx(ScoreElement* child) const;
// For iterating over child elements
class iterator
{
ScoreElement* el;
int i;
public:
iterator(ScoreElement* el, int pos)
: el(el), i(pos) {}
iterator operator++() { return iterator(el, i++); }
ScoreElement* operator*() { return el->treeChild(i); }
bool operator!=(const iterator& o) { return o.el != el || o.i != i; }
};
class const_iterator
{
const ScoreElement* el;
int i;
public:
const_iterator(const ScoreElement* el, int pos)
: el(el), i(pos) {}
const_iterator operator++() { return const_iterator(el, i++); }
const ScoreElement* operator*() { return el->treeChild(i); }
bool operator!=(const const_iterator& o) { return o.el != el || o.i != i; }
};
iterator begin() { return iterator(this, 0); }
iterator end() { return iterator(this, treeChildCount()); }
const_iterator begin() const { return const_iterator(this, 0); }
const_iterator end() const { return const_iterator(this, treeChildCount()); }
Score* score() const { return _score; }
MasterScore* masterScore() const;
virtual void setScore(Score* s) { _score = s; }

862
libmscore/scoretree.cpp Normal file
View file

@ -0,0 +1,862 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2020 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 2.
//
// 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#include "accidental.h"
#include "ambitus.h"
#include "arpeggio.h"
#include "articulation.h"
#include "barline.h"
#include "beam.h"
#include "bracket.h"
#include "bsymbol.h"
#include "chord.h"
#include "duration.h"
#include "fret.h"
#include "glissando.h"
#include "hook.h"
#include "iname.h"
#include "ledgerline.h"
#include "lyrics.h"
#include "measure.h"
#include "measurenumber.h"
#include "note.h"
#include "page.h"
#include "rest.h"
#include "score.h"
#include "segment.h"
#include "spacer.h"
#include "spanner.h"
#include "staff.h"
#include "stafflines.h"
#include "stem.h"
#include "stemslash.h"
#include "system.h"
#include "systemdivider.h"
#include "textframe.h"
#include "tie.h"
#include "tremolo.h"
#include "trill.h"
#include "tuplet.h"
namespace Ms {
//---------------------------------------------------------
// Score
//---------------------------------------------------------
ScoreElement* Score::treeParent() const
{
return nullptr; // Score is root node
}
ScoreElement* Score::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
// Should measure be the child instead of page?
return pages()[idx];
}
int Score::treeChildCount() const
{
return pages().size();
}
//---------------------------------------------------------
// Page
//---------------------------------------------------------
ScoreElement* Page::treeParent() const
{
return score();
}
ScoreElement* Page::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
return systems()[idx];
}
int Page::treeChildCount() const
{
return systems().size();
}
//---------------------------------------------------------
// System
//---------------------------------------------------------
ScoreElement* System::treeParent() const
{
return page();
}
ScoreElement* System::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
if (idx < int(brackets().size())) {
return brackets()[idx];
}
idx -= brackets().size();
if (systemDividerLeft()) {
if (idx == 0) {
return systemDividerLeft();
}
idx--;
}
if (systemDividerRight()) {
if (idx == 0) {
return systemDividerRight();
}
idx--;
}
for (SysStaff* ss : _staves) {
if (idx < int(ss->instrumentNames.size())) {
return ss->instrumentNames[idx];
}
idx -= ss->instrumentNames.size();
}
if (idx < int(measures().size())) {
return measures()[idx];
}
idx -= measures().size();
return nullptr;
}
int System::treeChildCount() const
{
int numChildren = 0;
numChildren += brackets().size();
if (systemDividerLeft()) {
numChildren++;
}
if (systemDividerRight()) {
numChildren++;
}
for (SysStaff* ss : _staves) {
numChildren += ss->instrumentNames.size();
}
numChildren += measures().size();
return numChildren;
}
//---------------------------------------------------------
// MeasureBase
//---------------------------------------------------------
ScoreElement* MeasureBase::treeParent() const
{
return system();
}
ScoreElement* MeasureBase::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
return el()[idx];
}
int MeasureBase::treeChildCount() const
{
return el().size();
}
//---------------------------------------------------------
// Measure
//---------------------------------------------------------
ScoreElement* Measure::treeParent() const
{
return system();
}
ScoreElement* Measure::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
// TODO: check for MMRest
Segment* s = _segments.first();
while (s) {
if (idx == 0) {
return s;
}
idx--;
s = s->next();
}
int nstaves = score()->nstaves();
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (_mstaves[staffIdx]->lines()) {
if (idx == 0) {
return _mstaves[staffIdx]->lines();
}
idx--;
}
if (vspacerUp(staffIdx)) {
if (idx == 0) {
return vspacerUp(staffIdx);
}
idx--;
}
if (vspacerDown(staffIdx)) {
if (idx == 0) {
return vspacerDown(staffIdx);
}
idx--;
}
if (noText(staffIdx)) {
if (idx == 0) {
return noText(staffIdx);
}
idx--;
}
}
const std::multimap<int, Ms::Spanner*> spannerMap = score()->spanner();
int start_tick = tick().ticks();
for (auto i = spannerMap.lower_bound(start_tick); i != spannerMap.upper_bound(start_tick); ++i) {
Spanner* s = i->second;
if (s->anchor() == Spanner::Anchor::MEASURE) {
if (idx == 0) {
return s;
}
idx--;
}
}
return nullptr;
}
int Measure::treeChildCount() const
{
int numChildren = 0;
numChildren += _segments.size();
int nstaves = score()->nstaves();
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (_mstaves[staffIdx]->lines()) {
numChildren++;
}
if (vspacerUp(staffIdx)) {
numChildren++;
}
if (vspacerDown(staffIdx)) {
numChildren++;
}
if (noText(staffIdx)) {
numChildren++;
}
}
const std::multimap<int, Ms::Spanner*> spannerMap = score()->spanner();
int start_tick = tick().ticks();
for (auto i = spannerMap.lower_bound(start_tick); i != spannerMap.upper_bound(start_tick); ++i) {
Spanner* s = i->second;
if (s->anchor() == Spanner::Anchor::MEASURE) {
numChildren++;
}
}
return numChildren;
}
//---------------------------------------------------------
// Segment
//---------------------------------------------------------
ScoreElement* Segment::treeParent() const
{
return measure();
}
ScoreElement* Segment::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
if (idx < int(_elist.size())) {
return _elist[idx];
}
idx -= _elist.size();
if (idx < int(_annotations.size())) {
return _annotations[idx];
}
idx -= _annotations.size();
if (segmentType() == SegmentType::ChordRest) {
const std::multimap<int, Ms::Spanner*> spannerMap = score()->spanner();
int start_tick = tick().ticks();
for (auto i = spannerMap.lower_bound(start_tick); i != spannerMap.upper_bound(start_tick); ++i) {
Spanner* s = i->second;
if (s->anchor() == Spanner::Anchor::SEGMENT) {
if (idx == 0) {
return s;
}
idx--;
}
}
}
return nullptr;
}
int Segment::treeChildCount() const
{
int numChildren = _elist.size() + _annotations.size();
if (segmentType() == SegmentType::ChordRest) {
const std::multimap<int, Ms::Spanner*> spannerMap = score()->spanner();
int start_tick = tick().ticks();
for (auto i = spannerMap.lower_bound(start_tick); i != spannerMap.upper_bound(start_tick); ++i) {
Spanner* s = i->second;
if (s->anchor() == Spanner::Anchor::SEGMENT) {
numChildren++;
}
}
}
return numChildren;
}
//---------------------------------------------------------
// ChordRest
//---------------------------------------------------------
ScoreElement* ChordRest::treeParent() const
{
if (isGrace()) {
// grace notes do not have a segment of their own
// their parent is the chord they are attached to
return parent();
}
return segment();
}
ScoreElement* ChordRest::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
if (beam() && beam()->treeParent() == this) {
if (idx == 0) {
return beam();
}
idx--;
}
if (idx < int(_lyrics.size())) {
return _lyrics[idx];
}
idx -= _lyrics.size();
// TODO: add durationElement/tuplet?
if (_tabDur) {
if (idx == 0) {
return _tabDur;
}
idx--;
}
const std::multimap<int, Ms::Spanner*> spannerMap = score()->spanner();
int start_tick = tick().ticks();
for (auto i = spannerMap.lower_bound(start_tick); i != spannerMap.upper_bound(start_tick); ++i) {
Spanner* s = i->second;
if (s->anchor() == Spanner::Anchor::CHORD && s->treeParent() == this) {
if (idx == 0) {
return s;
}
idx--;
}
}
return nullptr;
}
int ChordRest::treeChildCount() const
{
int numChildren = 0;
if (beam() && beam()->treeParent() == this) {
numChildren++;
}
numChildren += _lyrics.size();
if (_tabDur) {
numChildren++;
}
const std::multimap<int, Ms::Spanner*> spannerMap = score()->spanner();
int start_tick = tick().ticks();
for (auto i = spannerMap.lower_bound(start_tick); i != spannerMap.upper_bound(start_tick); ++i) {
Spanner* s = i->second;
if (s->anchor() == Spanner::Anchor::CHORD) {
numChildren++;
}
}
return numChildren;
}
//---------------------------------------------------------
// Chord
//---------------------------------------------------------
ScoreElement* Chord::treeParent() const
{
return ChordRest::treeParent();
}
ScoreElement* Chord::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
if (idx < int(notes().size())) {
return notes()[idx];
}
idx -= notes().size();
if (_arpeggio) {
if (idx == 0) {
return _arpeggio;
}
idx--;
}
if (_tremolo) {
if (idx == 0) {
return _tremolo;
}
idx--;
}
if (idx < int(graceNotes().size())) {
return graceNotes()[idx];
}
idx -= graceNotes().size();
if (idx < int(articulations().size())) {
return articulations()[idx];
}
idx -= articulations().size();
if (stem()) {
if (idx == 0) {
return stem();
}
idx--;
}
if (hook()) {
if (idx == 0) {
return hook();
}
idx--;
}
if (stemSlash()) {
if (idx == 0) {
return stemSlash();
}
idx--;
}
LedgerLine* ll = _ledgerLines;
while (ll) {
if (idx == 0) {
return ll;
}
idx--;
ll = ll->next();
}
return ChordRest::treeChild(idx);
}
int Chord::treeChildCount() const
{
int numChildren = 0;
numChildren += notes().size();
if (_arpeggio) {
numChildren++;
}
if (_tremolo) {
numChildren++;
}
numChildren += graceNotes().size();
numChildren += articulations().size();
if (stem()) {
numChildren++;
}
if (hook()) {
numChildren++;
}
if (stemSlash()) {
numChildren++;
}
LedgerLine* ll = _ledgerLines;
while (ll) {
numChildren++;
ll = ll->next();
}
numChildren += ChordRest::treeChildCount();
return numChildren;
}
//---------------------------------------------------------
// Rest
//---------------------------------------------------------
ScoreElement* Rest::treeParent() const
{
return ChordRest::treeParent();
}
ScoreElement* Rest::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
if (idx < int(_dots.size())) {
return _dots[idx];
}
idx -= _dots.size();
return ChordRest::treeChild(idx);
}
int Rest::treeChildCount() const
{
return _dots.size() + ChordRest::treeChildCount();
}
//---------------------------------------------------------
// Note
//---------------------------------------------------------
ScoreElement* Note::treeParent() const
{
return chord();
}
ScoreElement* Note::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
if (accidental()) {
if (idx == 0) {
return accidental();
}
idx--;
}
if (idx < int(dots().size())) {
return dots()[idx];
}
idx -= dots().size();
if (tieFor()) {
if (idx == 0) {
return tieFor();
}
idx--;
}
if (idx < int(el().size())) {
return el()[idx];
}
idx -= el().size();
if (idx < int(spannerFor().size())) {
return spannerFor()[idx];
}
idx -= spannerFor().size();
return nullptr;
}
int Note::treeChildCount() const
{
int numChildren = 0;
if (accidental()) {
numChildren++;
}
numChildren += dots().size();
if (tieFor()) {
numChildren++;
}
numChildren += el().size();
numChildren += spannerFor().size();
return numChildren;
}
//---------------------------------------------------------
// Accidental
//---------------------------------------------------------
ScoreElement* Accidental::treeParent() const
{
if (parent()->isTrillSegment()) {
return parent()->treeParent();
}
return note();
}
ScoreElement* Accidental::treeChild(int idx) const
{
Q_UNUSED(idx);
return nullptr;
}
int Accidental::treeChildCount() const
{
return 0;
}
//---------------------------------------------------------
// Beam
//---------------------------------------------------------
ScoreElement* Beam::treeParent() const
{
return _elements[0];
}
ScoreElement* Beam::treeChild(int idx) const
{
Q_UNUSED(idx);
return nullptr;
}
int Beam::treeChildCount() const
{
return 0;
}
//---------------------------------------------------------
// Ambitus
//---------------------------------------------------------
ScoreElement* Ambitus::treeParent() const
{
return segment();
}
ScoreElement* Ambitus::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
Accidental* topAccid = const_cast<Accidental*>(&_topAccid);
Accidental* bottomAccid = const_cast<Accidental*>(&_bottomAccid);
// TODO: check if accidentalType() == AccidentalType::NONE?
if (topAccid) {
if (idx == 0) {
return topAccid;
}
idx--;
}
if (bottomAccid) {
if (idx == 0) {
return bottomAccid;
}
idx--;
}
return nullptr;
}
int Ambitus::treeChildCount() const
{
int numChildren = 0;
Accidental* topAccid = const_cast<Accidental*>(&_topAccid);
Accidental* bottomAccid = const_cast<Accidental*>(&_bottomAccid);
if (topAccid) {
numChildren++;
}
if (bottomAccid) {
numChildren++;
}
return numChildren;
}
//---------------------------------------------------------
// FretDiagram
//---------------------------------------------------------
ScoreElement* FretDiagram::treeParent() const
{
return segment();
}
ScoreElement* FretDiagram::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
if (idx == 0) {
return harmony();
}
return nullptr;
}
int FretDiagram::treeChildCount() const
{
if (harmony()) {
return 1;
}
return 0;
}
//---------------------------------------------------------
// Spanner
//---------------------------------------------------------
ScoreElement* Spanner::treeParent() const
{
switch (anchor()) {
case Anchor::SEGMENT:
return startSegment();
case Anchor::MEASURE:
return startMeasure();
case Anchor::CHORD:
return findStartCR();
case Anchor::NOTE:
return startElement();
default:
return nullptr;
}
}
ScoreElement* Spanner::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
return spannerSegments()[idx];
}
int Spanner::treeChildCount() const
{
return spannerSegments().size();
}
//---------------------------------------------------------
// SpannerSegment
//---------------------------------------------------------
ScoreElement* SpannerSegment::treeParent() const
{
return spanner();
}
ScoreElement* SpannerSegment::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
return nullptr;
}
int SpannerSegment::treeChildCount() const
{
return 0;
}
//---------------------------------------------------------
// BSymbol
//---------------------------------------------------------
ScoreElement* BSymbol::treeParent() const
{
return segment();
}
ScoreElement* BSymbol::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
return _leafs[idx];
}
int BSymbol::treeChildCount() const
{
return _leafs.size();
}
//---------------------------------------------------------
// Tuplet
//---------------------------------------------------------
ScoreElement* Tuplet::treeParent() const
{
return measure();
}
ScoreElement* Tuplet::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
if (idx == 0) {
return _number;
}
return nullptr;
}
int Tuplet::treeChildCount() const
{
if (_number) {
return 1;
}
return 0;
}
//---------------------------------------------------------
// BarLine
//---------------------------------------------------------
ScoreElement* BarLine::treeParent() const
{
return segment();
}
ScoreElement* BarLine::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
return _el[idx];
}
int BarLine::treeChildCount() const
{
return _el.size();
}
//---------------------------------------------------------
// Trill
//---------------------------------------------------------
ScoreElement* Trill::treeParent() const
{
return Spanner::treeParent();
}
ScoreElement* Trill::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
if (accidental()) {
if (idx == 0) {
return accidental();
}
idx--;
}
return Spanner::treeChild(idx);
}
int Trill::treeChildCount() const
{
if (accidental()) {
return 1 + Spanner::treeChildCount();
}
return Spanner::treeChildCount();
}
//---------------------------------------------------------
// TBox
//---------------------------------------------------------
ScoreElement* TBox::treeParent() const
{
return parent();
}
ScoreElement* TBox::treeChild(int idx) const
{
Q_ASSERT(0 <= idx && idx <= treeChildCount());
if (idx == 0) {
return _text;
}
return nullptr;
}
int TBox::treeChildCount() const
{
if (_text) {
return 1;
}
return 0;
}
} // namespace Ms

View file

@ -76,6 +76,11 @@ public:
Segment(const Segment&);
~Segment();
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
Segment* clone() const override { return new Segment(*this); }
ElementType type() const override { return ElementType::SEGMENT; }

View file

@ -812,7 +812,7 @@ Chord* Spanner::startChord()
{
Q_ASSERT(_anchor == Anchor::CHORD);
if (!_startElement) {
_startElement = score()->findCR(tick(), track());
_startElement = findStartChord();
}
return toChord(_startElement);
}
@ -824,13 +824,8 @@ Chord* Spanner::startChord()
Chord* Spanner::endChord()
{
Q_ASSERT(_anchor == Anchor::CHORD);
if (!_endElement && type() == ElementType::SLUR) {
Segment* s = score()->tick2segmentMM(tick2(), false, SegmentType::ChordRest);
_endElement = s ? toChordRest(s->element(track2())) : nullptr;
if (!_endElement->isChord()) {
_endElement = nullptr;
}
_endElement = findEndChord();
}
return toChord(_endElement);
}
@ -843,7 +838,7 @@ ChordRest* Spanner::startCR()
{
Q_ASSERT(_anchor == Anchor::SEGMENT || _anchor == Anchor::CHORD);
if (!_startElement || _startElement->score() != score()) {
_startElement = score()->findCR(tick(), track());
_startElement = findStartCR();
}
return toChordRest(_startElement);
}
@ -856,13 +851,60 @@ ChordRest* Spanner::endCR()
{
Q_ASSERT(_anchor == Anchor::SEGMENT || _anchor == Anchor::CHORD);
if ((!_endElement || _endElement->score() != score())) {
Segment* s = score()->tick2segmentMM(tick2(), false, SegmentType::ChordRest);
const int tr2 = effectiveTrack2();
_endElement = s ? toChordRest(s->element(tr2)) : nullptr;
_endElement = findEndCR();
}
return toChordRest(_endElement);
}
//---------------------------------------------------------
// findStartChord
//---------------------------------------------------------
Chord* Spanner::findStartChord() const
{
Q_ASSERT(_anchor == Anchor::CHORD);
ChordRest* cr = score()->findCR(tick(), track());
return cr->isChord() ? toChord(cr) : nullptr;
}
//---------------------------------------------------------
// findEndChord
//---------------------------------------------------------
Chord* Spanner::findEndChord() const
{
Q_ASSERT(_anchor == Anchor::CHORD);
Segment* s = score()->tick2segmentMM(tick2(), false, SegmentType::ChordRest);
ChordRest* endCR = s ? toChordRest(s->element(track2())) : nullptr;
if (!endCR->isChord()) {
endCR = nullptr;
}
return toChord(endCR);
}
//---------------------------------------------------------
// findStartCR
//---------------------------------------------------------
ChordRest* Spanner::findStartCR() const
{
Q_ASSERT(_anchor == Anchor::SEGMENT || _anchor == Anchor::CHORD);
return score()->findCR(tick(), track());
}
//---------------------------------------------------------
// findEndCR
//---------------------------------------------------------
ChordRest* Spanner::findEndCR() const
{
Q_ASSERT(_anchor == Anchor::SEGMENT || _anchor == Anchor::CHORD);
Segment* s = score()->tick2segmentMM(tick2(), false, SegmentType::ChordRest);
const int tr2 = effectiveTrack2();
ChordRest* endCR = s ? toChordRest(s->element(tr2)) : nullptr;
return endCR;
}
//---------------------------------------------------------
// startSegment
//---------------------------------------------------------

View file

@ -46,6 +46,11 @@ public:
SpannerSegment(const SpannerSegment&);
virtual SpannerSegment* clone() const = 0;
// Score Tree functions
virtual ScoreElement* treeParent() const override;
virtual ScoreElement* treeChild(int idx) const override;
virtual int treeChildCount() const override;
virtual qreal mag() const override;
virtual Fraction tick() const override;
@ -160,6 +165,11 @@ public:
Spanner(const Spanner&);
~Spanner();
// Score Tree functions
virtual ScoreElement* treeParent() const override;
virtual ScoreElement* treeChild(int idx) const override;
virtual int treeChildCount() const override;
virtual qreal mag() const override;
virtual ElementType type() const = 0;
@ -240,6 +250,12 @@ public:
Chord* startChord();
Chord* endChord();
ChordRest* findStartCR() const;
ChordRest* findEndCR() const;
Chord* findStartChord() const;
Chord* findEndChord() const;
Segment* startSegment() const;
Segment* endSegment() const;

View file

@ -101,6 +101,11 @@ public:
System(Score*);
~System();
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
System* clone() const override { return new System(*this); }
ElementType type() const override { return ElementType::SYSTEM; }

View file

@ -31,6 +31,12 @@ public:
TBox(Score* score);
TBox(const TBox&);
~TBox();
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
virtual TBox* clone() const { return new TBox(*this); }
virtual ElementType type() const { return ElementType::TBOX; }
virtual void write(XmlWriter&) const override;

View file

@ -81,6 +81,11 @@ public:
Trill(Score* s);
~Trill();
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
Trill* clone() const override { return new Trill(*this); }
ElementType type() const override { return ElementType::TRILL; }

View file

@ -64,6 +64,11 @@ public:
Tuplet(const Tuplet&);
~Tuplet();
// Score Tree functions
ScoreElement* treeParent() const override;
ScoreElement* treeChild(int idx) const override;
int treeChildCount() const override;
Tuplet* clone() const override { return new Tuplet(*this); }
ElementType type() const override { return ElementType::TUPLET; }
void setTrack(int val) override;