MuseScore/src/engraving/libmscore/scoretree.cpp

701 lines
16 KiB
C++

/*
* 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 "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 "instrumentname.h"
#include "ledgerline.h"
#include "lyrics.h"
#include "measure.h"
#include "measurenumber.h"
#include "mmrestrange.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"
#include "log.h"
using namespace mu;
namespace Ms {
//---------------------------------------------------------
// Score
//---------------------------------------------------------
EngravingObject* Score::scanParent() const
{
return nullptr; // Score is root node
}
EngravingObjectList Score::scanChildren() const
{
EngravingObjectList children;
for (Page* page : pages()) {
children.push_back(page);
}
return children;
}
//---------------------------------------------------------
// Page
//---------------------------------------------------------
EngravingObject* Page::scanParent() const
{
return score();
}
EngravingObjectList Page::scanChildren() const
{
EngravingObjectList children;
for (System* system : systems()) {
children.push_back(system);
}
return children;
}
//---------------------------------------------------------
// System
//---------------------------------------------------------
EngravingObject* System::scanParent() const
{
return page();
}
EngravingObjectList System::scanChildren() const
{
EngravingObjectList children;
for (Bracket* bracket : brackets()) {
children.push_back(bracket);
}
if (auto dividerLeft = systemDividerLeft()) {
children.push_back(dividerLeft);
}
if (auto dividerRight = systemDividerRight()) {
children.push_back(dividerRight);
}
for (SysStaff* staff : _staves) {
for (InstrumentName* instrName : staff->instrumentNames) {
children.push_back(instrName);
}
}
for (MeasureBase* measure : measures()) {
children.push_back(measure);
}
return children;
}
//---------------------------------------------------------
// MeasureBase
//---------------------------------------------------------
EngravingObject* MeasureBase::scanParent() const
{
return system();
}
EngravingObjectList MeasureBase::scanChildren() const
{
EngravingObjectList children;
for (EngravingItem* element : el()) {
children.push_back(element);
}
return children;
}
//---------------------------------------------------------
// Measure
//---------------------------------------------------------
EngravingObject* Measure::scanParent() const
{
// A MMRest measure will contain Measures that it has replaced
// System > MMR > Measure
if (isMMRest()) { // this is MMR
return system();
} else if (m_mmRestCount < 0) { // this is part of MMR
return const_cast<Measure*>(mmRest1());
}
// for a normal measure
return system();
}
EngravingObjectList Measure::scanChildren() const
{
EngravingObjectList children;
for (EngravingItem* element : el()) {
children.push_back(element);
}
if (isMMRest()) {
Measure* m1 = mmRestFirst();
Measure* m2 = mmRestLast();
while (m1 != m2) {
children.push_back(m1);
m1 = m1->nextMeasure();
}
return children;
}
Segment* seg = m_segments.first();
while (seg) {
children.push_back(seg);
seg = seg->next();
}
size_t nstaves = score()->nstaves();
for (staff_idx_t staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (auto _staffLines = m_mstaves[staffIdx]->lines()) {
children.push_back(_staffLines);
}
if (auto _vspacerUp = vspacerUp(staffIdx)) {
children.push_back(_vspacerUp);
}
if (auto _vspacerDown = vspacerDown(staffIdx)) {
children.push_back(_vspacerDown);
}
if (auto _noText = noText(staffIdx)) {
children.push_back(_noText);
}
if (auto _mmRangeText = mmRangeText(staffIdx)) {
children.push_back(_mmRangeText);
}
}
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) {
children.push_back(s);
}
}
const std::set<Spanner*>& unmanagedSpanners = score()->unmanagedSpanners();
for (Spanner* s : unmanagedSpanners) {
if (s->scanParent() == this) {
children.push_back(s);
}
}
for (EngravingObject* obj : MeasureBase::scanChildren()) {
children.push_back(obj);
}
return children;
}
//---------------------------------------------------------
// Segment
//---------------------------------------------------------
EngravingObject* Segment::scanParent() const
{
return measure();
}
EngravingObjectList Segment::scanChildren() const
{
EngravingObjectList children;
for (EngravingItem* element : _elist) {
if (element) {
children.push_back(element);
}
}
for (EngravingItem* annotation : _annotations) {
children.push_back(annotation);
}
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) {
children.push_back(s);
}
}
const std::set<Spanner*>& unmanagedSpanners = score()->unmanagedSpanners();
for (Spanner* s : unmanagedSpanners) {
if (s->scanParent() == this) {
children.push_back(s);
}
}
}
return children;
}
//---------------------------------------------------------
// ChordRest
//---------------------------------------------------------
EngravingObject* ChordRest::scanParent() const
{
if (isGrace()) {
// grace notes do not have a segment of their own
// their parent is the chord they are attached to
return explicitParent();
}
return segment();
}
EngravingObjectList ChordRest::scanChildren() const
{
EngravingObjectList children;
Beam* _b = beam();
if (_b && _b->scanParent() == this) {
children.push_back(_b);
}
for (Lyrics* lyrics : _lyrics) {
children.push_back(lyrics);
}
const DurationElement* de = this;
while (de->tuplet() && de->tuplet()->elements().front() == de) {
children.push_back(de->tuplet());
de = de->tuplet();
}
if (auto tabDuration = _tabDur) {
children.push_back(tabDuration);
}
for (EngravingItem* element : _el) {
children.push_back(element);
}
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->scanParent() == this) {
children.push_back(s);
}
}
const std::set<Spanner*>& unmanagedSpanners = score()->unmanagedSpanners();
for (Spanner* s : unmanagedSpanners) {
if (s->scanParent() == this) {
children.push_back(s);
}
}
return children;
}
//---------------------------------------------------------
// Chord
//---------------------------------------------------------
EngravingObject* Chord::scanParent() const
{
return ChordRest::scanParent();
}
EngravingObjectList Chord::scanChildren() const
{
EngravingObjectList children;
for (Note* note : notes()) {
children.push_back(note);
}
if (_arpeggio) {
children.push_back(_arpeggio);
}
if (_tremolo && _tremolo->chord1() == this) {
children.push_back(_tremolo);
}
for (Chord* chord : graceNotes()) {
children.push_back(chord);
}
for (Articulation* art : articulations()) {
children.push_back(art);
}
if (_stem) {
children.push_back(_stem);
}
if (_hook) {
children.push_back(_hook);
}
if (_stemSlash) {
children.push_back(_stemSlash);
}
LedgerLine* ledgerLines = _ledgerLines;
while (ledgerLines) {
children.push_back(ledgerLines);
ledgerLines = ledgerLines->next();
}
for (EngravingObject* child : ChordRest::scanChildren()) {
children.push_back(child);
}
return children;
}
//---------------------------------------------------------
// Rest
//---------------------------------------------------------
EngravingObject* Rest::scanParent() const
{
return ChordRest::scanParent();
}
EngravingObjectList Rest::scanChildren() const
{
EngravingObjectList children;
for (NoteDot* noteDot : m_dots) {
children.push_back(noteDot);
}
for (EngravingObject* child : ChordRest::scanChildren()) {
children.push_back(child);
}
return children;
}
//---------------------------------------------------------
// Note
//---------------------------------------------------------
EngravingObject* Note::scanParent() const
{
return chord();
}
EngravingObjectList Note::scanChildren() const
{
EngravingObjectList children;
if (_accidental) {
children.push_back(_accidental);
}
for (NoteDot* noteDot : _dots) {
children.push_back(noteDot);
}
if (_tieFor) {
children.push_back(_tieFor);
}
for (EngravingItem* element : el()) {
children.push_back(element);
}
for (Spanner* spanner : spannerFor()) {
children.push_back(spanner);
}
return children;
}
//---------------------------------------------------------
// Accidental
//---------------------------------------------------------
EngravingObject* Accidental::scanParent() const
{
if (explicitParent() && explicitParent()->isTrillSegment()) {
return explicitParent()->scanParent();
}
return note();
}
//---------------------------------------------------------
// Beam
//---------------------------------------------------------
EngravingObject* Beam::scanParent() const
{
return _elements[0];
}
//---------------------------------------------------------
// Ambitus
//---------------------------------------------------------
EngravingObject* Ambitus::scanParent() const
{
return segment();
}
EngravingObjectList Ambitus::scanChildren() const
{
EngravingObjectList children;
Accidental* topAccid = const_cast<Accidental*>(_topAccid);
if (topAccid && topAccid->accidentalType() != AccidentalType::NONE) {
children.push_back(topAccid);
}
Accidental* bottomAccid = const_cast<Accidental*>(_bottomAccid);
if (bottomAccid && bottomAccid->accidentalType() != AccidentalType::NONE) {
children.push_back(bottomAccid);
}
return children;
}
//---------------------------------------------------------
// FretDiagram
//---------------------------------------------------------
EngravingObject* FretDiagram::scanParent() const
{
return segment();
}
EngravingObjectList FretDiagram::scanChildren() const
{
EngravingObjectList children;
if (_harmony) {
children.push_back(_harmony);
}
return children;
}
//---------------------------------------------------------
// Spanner
//---------------------------------------------------------
EngravingObject* Spanner::scanParent() 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;
}
}
EngravingObjectList Spanner::scanChildren() const
{
EngravingObjectList children;
for (SpannerSegment* segment : spannerSegments()) {
children.push_back(segment);
}
return children;
}
//---------------------------------------------------------
// SpannerSegment
//---------------------------------------------------------
EngravingObject* SpannerSegment::scanParent() const
{
return spanner();
}
//---------------------------------------------------------
// BSymbol
//---------------------------------------------------------
EngravingObject* BSymbol::scanParent() const
{
return segment();
}
EngravingObjectList BSymbol::scanChildren() const
{
EngravingObjectList children;
for (EngravingItem* leaf : _leafs) {
children.push_back(leaf);
}
return children;
}
//---------------------------------------------------------
// Tuplet
//---------------------------------------------------------
EngravingObject* Tuplet::scanParent() const
{
return elements()[0];
}
EngravingObjectList Tuplet::scanChildren() const
{
EngravingObjectList children;
if (_number) {
children.push_back(_number);
}
return children;
}
//---------------------------------------------------------
// BarLine
//---------------------------------------------------------
EngravingObject* BarLine::scanParent() const
{
return segment();
}
EngravingObjectList BarLine::scanChildren() const
{
EngravingObjectList children;
for (EngravingItem* element : _el) {
children.push_back(element);
}
return children;
}
//---------------------------------------------------------
// Trill
//---------------------------------------------------------
EngravingObject* Trill::scanParent() const
{
return Spanner::scanParent();
}
EngravingObjectList Trill::scanChildren() const
{
EngravingObjectList children;
if (_accidental) {
children.push_back(_accidental);
}
for (EngravingObject* child : Spanner::scanChildren()) {
children.push_back(child);
}
return children;
}
//---------------------------------------------------------
// TBox
//---------------------------------------------------------
EngravingObject* TBox::scanParent() const
{
return explicitParent();
}
EngravingObjectList TBox::scanChildren() const
{
EngravingObjectList children;
if (_text) {
children.push_back(_text);
}
return children;
}
//---------------------------------------------------------
// dumpScoreTree
/// for debugging purposes
//---------------------------------------------------------
void _dumpScoreTree(EngravingObject* s, int depth)
{
LOGD() << qPrintable(QString(" ").repeated(4 * depth)) << s->typeName() << "at" << s;
for (EngravingObject* child : s->scanChildren()) {
_dumpScoreTree(child, depth + 1);
}
}
void Score::dumpScoreTree()
{
_dumpScoreTree(this, 0);
}
} // namespace Ms