//============================================================================= // MuseScore // Music Composition & Notation // // Copyright (C) 2002-2011 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 "navigate.h" #include "element.h" #include "clef.h" #include "score.h" #include "note.h" #include "rest.h" #include "chord.h" #include "system.h" #include "segment.h" #include "harmony.h" #include "utils.h" #include "input.h" #include "measure.h" #include "page.h" #include "spanner.h" #include "system.h" #include "staff.h" #include "barline.h" namespace Ms { //--------------------------------------------------------- // nextChordRest // return next Chord or Rest //--------------------------------------------------------- ChordRest* nextChordRest(ChordRest* cr, bool skipGrace) { if (!cr) return 0; if (cr->isGrace()) { // // cr is a grace note Chord* c = toChord(cr); Chord* pc = toChord(cr->parent()); if (skipGrace) { cr = toChordRest(cr->parent()); } else if (cr->isGraceBefore()) { QVector cl = pc->graceNotesBefore(); auto i = std::find(cl.begin(), cl.end(), c); if (i == cl.end()) return 0; // unable to find self? ++i; if (i != cl.end()) return *i; // if this was last grace note before, return parent return pc; } else { QVector cl = pc->graceNotesAfter(); auto i = std::find(cl.begin(), cl.end(), c); if (i == cl.end()) return 0; // unable to find self? ++i; if (i != cl.end()) return *i; // if this was last grace note after, fall through to find next main note cr = pc; } } else { // // cr is not a grace note if (cr->isChord() && !skipGrace) { Chord* c = toChord(cr); if (!c->graceNotes().empty()) { QVector cl = c->graceNotesAfter(); if (!cl.empty()) return cl.first(); } } } int track = cr->track(); SegmentType st = SegmentType::ChordRest; for (Segment* seg = cr->segment()->next1MM(st); seg; seg = seg->next1MM(st)) { ChordRest* e = toChordRest(seg->element(track)); if (e) { if (e->isChord() && !skipGrace) { Chord* c = toChord(e); if (!c->graceNotes().empty()) { QVector cl = c->graceNotesBefore(); if (!cl.empty()) return cl.first(); } } return e; } } return 0; } //--------------------------------------------------------- // prevChordRest // return previous Chord or Rest // if grace is true, include grace notes //--------------------------------------------------------- ChordRest* prevChordRest(ChordRest* cr, bool skipGrace) { if (!cr) return 0; if (cr->isGrace()) { // // cr is a grace note Chord* c = toChord(cr); Chord* pc = toChord(cr->parent()); if (skipGrace) { cr = toChordRest(cr->parent()); } else if (cr->isGraceBefore()) { QVector cl = pc->graceNotesBefore(); auto i = std::find(cl.begin(), cl.end(), c); if (i == cl.end()) return 0; // unable to find self? if (i != cl.begin()) return *--i; // if this was first grace note before, fall through to find previous main note cr = pc; } else { QVector cl = pc->graceNotesAfter(); auto i = std::find(cl.begin(), cl.end(), c); if (i == cl.end()) return 0; // unable to find self? if (i != cl.begin()) return *--i; // if this was first grace note after, return parent return pc; } } else { // // cr is not a grace note if (cr->isChord() && !skipGrace) { Chord* c = toChord(cr); QVector cl = c->graceNotesBefore(); if (!cl.empty()) return cl.last(); } } int track = cr->track(); SegmentType st = SegmentType::ChordRest; for (Segment* seg = cr->segment()->prev1MM(st); seg; seg = seg->prev1MM(st)) { ChordRest* e = toChordRest(seg->element(track)); if (e) { if (e->type() == ElementType::CHORD && !skipGrace) { QVector cl = toChord(e)->graceNotesAfter(); if (!cl.empty()) return cl.last(); } return e; } } return 0; } //--------------------------------------------------------- // upAlt // element: Note() or Rest() // return: Note() or Rest() // // return next higher pitched note in chord // move to previous track if at top of chord //--------------------------------------------------------- Element* Score::upAlt(Element* element) { Element* re = 0; if (element->isRest()) re = prevTrack(toRest(element)); else if (element->isNote()) { Note* note = toNote(element); Chord* chord = note->chord(); const std::vector& notes = chord->notes(); auto i = std::find(notes.begin(), notes.end(), note); ++i; if (i != notes.end()) re = *i; else { re = prevTrack(chord); if (re->track() == chord->track()) re = element; } } if (re == 0) return 0; if (re->isChord()) re = toChord(re)->notes().front(); return re; } //--------------------------------------------------------- // upAltCtrl // select top note in chord //--------------------------------------------------------- Note* Score::upAltCtrl(Note* note) const { return note->chord()->upNote(); } //--------------------------------------------------------- // downAlt // return next lower pitched note in chord // move to next track if at bottom of chord //--------------------------------------------------------- Element* Score::downAlt(Element* element) { Element* re = 0; if (element->isRest()) re = nextTrack(toRest(element)); else if (element->isNote()) { Note* note = toNote(element); Chord* chord = note->chord(); const std::vector& notes = chord->notes(); auto i = std::find(notes.begin(), notes.end(), note); if (i != notes.begin()) { --i; re = *i; } else { re = nextTrack(chord); if (re->track() == chord->track()) re = element; } } if (re == 0) return 0; if (re->isChord()) re = toChord(re)->notes().back(); return re; } //--------------------------------------------------------- // downAltCtrl // niedrigste Note in Chord selektieren //--------------------------------------------------------- Note* Score::downAltCtrl(Note* note) const { return note->chord()->downNote(); } //--------------------------------------------------------- // firstElement //--------------------------------------------------------- Element* Score::firstElement(bool frame) { if (frame) { MeasureBase* mb = measures()->first(); if (mb && mb->isBox()) return mb; } Segment *s = firstSegmentMM(SegmentType::All); return s ? s->element(0) : nullptr; } //--------------------------------------------------------- // lastElement //--------------------------------------------------------- Element* Score::lastElement(bool frame) { if (frame) { MeasureBase* mb = measures()->last(); if (mb && mb->isBox()) return mb; } Element* re = 0; Segment* seg = lastSegmentMM(); if (!seg) return nullptr; while (true) { for (int i = (staves().size() -1) * VOICES; i < staves().size() * VOICES; i++) { if (seg->element(i)) re = seg->element(i); } if (re) { if (re->isChord()) { return toChord(re)->notes().front(); } return re; } seg = seg->prev1MM(SegmentType::All); } } //--------------------------------------------------------- // upStaff //--------------------------------------------------------- ChordRest* Score::upStaff(ChordRest* cr) { Segment* segment = cr->segment(); if (cr->staffIdx() == 0) return cr; for (int track = (cr->staffIdx() - 1) * VOICES; track >= 0; --track) { Element* el = segment->element(track); if (!el) continue; if (el->isNote()) el = toNote(el)->chord(); if (el->isChordRest()) return toChordRest(el); } return 0; } //--------------------------------------------------------- // downStaff //--------------------------------------------------------- ChordRest* Score::downStaff(ChordRest* cr) { Segment* segment = cr->segment(); int tracks = nstaves() * VOICES; if (cr->staffIdx() == nstaves() - 1) return cr; for (int track = (cr->staffIdx() + 1) * VOICES; track < tracks; --track) { Element* el = segment->element(track); if (!el) continue; if (el->isNote()) el = toNote(el)->chord(); if (el->isChordRest()) return toChordRest(el); } return 0; } //--------------------------------------------------------- // nextTrack // returns note at or just before current (cr) position // in next track for this measure // that contains such an element //--------------------------------------------------------- ChordRest* Score::nextTrack(ChordRest* cr) { if (!cr) return 0; ChordRest* el = 0; Measure* measure = cr->measure(); int track = cr->track(); int tracks = nstaves() * VOICES; while (!el) { // find next non-empty track while (++track < tracks) { if (measure->hasVoice(track)) break; } // no more tracks, return original element if (track == tracks) return cr; // find element at same or previous segment within this track for (Segment* segment = cr->segment(); segment; segment = segment->prev(SegmentType::ChordRest)) { el = toChordRest(segment->element(track)); if (el) break; } } return el; } //--------------------------------------------------------- // prevTrack // returns ChordRest at or just before current (cr) position // in previous track for this measure // that contains such an element //--------------------------------------------------------- ChordRest* Score::prevTrack(ChordRest* cr) { if (!cr) return 0; ChordRest* el = 0; Measure* measure = cr->measure(); int track = cr->track(); while (!el) { // find next non-empty track while (--track >= 0){ if (measure->hasVoice(track)) break; } // no more tracks, return original element if (track < 0) return cr; // find element at same or previous segment within this track for (Segment* segment = cr->segment(); segment; segment = segment->prev(SegmentType::ChordRest)) { el = toChordRest(segment->element(track)); if (el) break; } } return el; } //--------------------------------------------------------- // nextMeasure //--------------------------------------------------------- ChordRest* Score::nextMeasure(ChordRest* element, bool selectBehavior, bool mmRest) { if (!element) return 0; Measure* measure = 0; if (mmRest) measure = element->measure()->nextMeasureMM(); else measure = element->measure()->nextMeasure(); if (!measure) return 0; Fraction endTick = element->measure()->last()->nextChordRest(element->track(), true)->tick(); bool last = false; if (selection().isRange()) { if (element->tick() != endTick && selection().tickEnd() <= endTick) { measure = element->measure(); last = true; } else if (element->tick() == endTick && selection().isEndActive()) last = true; } else if (element->tick() != endTick && selectBehavior) { measure = element->measure(); last = true; } if (!measure) { measure = element->measure(); last = true; } int staff = element->staffIdx(); Segment* startSeg = last ? measure->last() : measure->first(); for (Segment* seg = startSeg; seg; seg = last ? seg->prev() : seg->next()) { int etrack = (staff+1) * VOICES; for (int track = staff * VOICES; track < etrack; ++track) { Element* pel = seg->element(track); if (pel && pel->isChordRest()) return toChordRest(pel); } } return 0; } //--------------------------------------------------------- // prevMeasure //--------------------------------------------------------- ChordRest* Score::prevMeasure(ChordRest* element, bool mmRest) { if (!element) return 0; Measure* measure = 0; if (mmRest) measure = element->measure()->prevMeasureMM(); else measure = element->measure()->prevMeasure(); Fraction startTick = element->measure()->first()->nextChordRest(element->track())->tick(); bool last = false; if (selection().isRange() && selection().isEndActive() && selection().startSegment()->tick() <= startTick) last = true; else if (element->tick() != startTick) { measure = element->measure(); } if (!measure) { measure = element->measure(); last = false; } int staff = element->staffIdx(); Segment* startSeg = last ? measure->last() : measure->first(); for (Segment* seg = startSeg; seg; seg = last ? seg->prev() : seg->next()) { int etrack = (staff+1) * VOICES; for (int track = staff * VOICES; track < etrack; ++track) { Element* pel = seg->element(track); if (pel && pel->isChordRest()) return toChordRest(pel); } } return 0; } //--------------------------------------------------------- // nextElement //--------------------------------------------------------- Element* Score::nextElement() { Element* e = getSelectedElement(); if (!e) return nullptr; int staffId = e->staffIdx(); while (e) { switch (e->type()) { case ElementType::NOTE: case ElementType::REST: case ElementType::CHORD: { Element* next = e->nextElement(); if (next) return next; else break; } case ElementType::SEGMENT: { Segment* s = toSegment(e); Element* next = s->nextElement(staffId); if (next) return next; else break; } case ElementType::MEASURE: { Measure* m = toMeasure(e); Element* next = m->nextElementStaff(staffId); if (next) return next; else break; } case ElementType::CLEF: case ElementType::KEYSIG: case ElementType::TIMESIG: case ElementType::BAR_LINE: { for (; e && e->type() != ElementType::SEGMENT; e = e->parent()) { ; } Segment* s = toSegment(e); Element* next = s->nextElement(staffId); if (next) return next; else return score()->firstElement(); } #if 1 case ElementType::VOLTA_SEGMENT: #else case ElementType::VOLTA_SEGMENT: { // TODO: see Spanner::nextSpanner() System* sys = toSpannerSegment(e)->system(); if (sys) staffId = sys->firstVisibleStaff(); } // fall through #endif case ElementType::SLUR_SEGMENT: case ElementType::TEXTLINE_SEGMENT: case ElementType::HAIRPIN_SEGMENT: case ElementType::OTTAVA_SEGMENT: case ElementType::TRILL_SEGMENT: case ElementType::VIBRATO_SEGMENT: case ElementType::LET_RING_SEGMENT: case ElementType::PALM_MUTE_SEGMENT: case ElementType::PEDAL_SEGMENT: { SpannerSegment* s = toSpannerSegment(e); Spanner* sp = s->spanner(); Spanner* nextSp = sp->nextSpanner(sp, staffId); if (nextSp) return nextSp->spannerSegments().front(); Segment* seg = tick2segment(sp->tick()); if (seg) { Segment* nextSegment = seg->next1(); while (nextSegment) { Element* nextEl = nextSegment->firstElementOfSegment(nextSegment, staffId); if (nextEl) return nextEl; nextSegment = nextSegment->next1MM(); } } break; } case ElementType::GLISSANDO_SEGMENT: case ElementType::TIE_SEGMENT: { SpannerSegment* s = toSpannerSegment(e); Spanner* sp = s->spanner(); Element* elSt = sp->startElement(); Note* n = toNote(elSt); Element* next = n->nextElement(); if (next) return next; else break; } case ElementType::VBOX: case ElementType::HBOX: case ElementType::TBOX: { MeasureBase* mb = toMeasureBase(e)->nextMM(); if (!mb) { break; } else if (mb->isMeasure()) { ChordRest* cr = selection().currentCR(); int si = cr ? cr->staffIdx() : 0; return toMeasure(mb)->nextElementStaff(si); } else { return mb; } } case ElementType::LAYOUT_BREAK: { staffId = 0; // otherwise it will equal -1, which breaks the navigation } default: break; } e = e->parent(); } return score()->lastElement(); } //--------------------------------------------------------- // prevElement //--------------------------------------------------------- Element* Score::prevElement() { Element* e = getSelectedElement(); if (!e) return nullptr; int staffId = e->staffIdx(); while (e) { switch (e->type()) { case ElementType::NOTE: case ElementType::REST: case ElementType::CHORD: { Element* prev = e->prevElement(); if (prev) return prev; else break; } case ElementType::SEGMENT: { Segment* s = toSegment(e); Element* prev = s->prevElement(staffId); if (prev) return prev; else break; } case ElementType::MEASURE: { Measure* m = toMeasure(e); return m->prevElementStaff(staffId); } case ElementType::CLEF: case ElementType::KEYSIG: case ElementType::TIMESIG: case ElementType::BAR_LINE: { for (; e && e->type() != ElementType::SEGMENT; e = e->parent()) { ; } Segment* s = toSegment(e); return s->prevElement(staffId); } #if 1 case ElementType::VOLTA_SEGMENT: #else case ElementType::VOLTA_SEGMENT: { // TODO: see Spanner::nextSpanner() System* sys = toSpannerSegment(e)->system(); if (sys) staffId = sys->firstVisibleStaff(); } // fall through #endif case ElementType::SLUR_SEGMENT: case ElementType::TEXTLINE_SEGMENT: case ElementType::HAIRPIN_SEGMENT: case ElementType::OTTAVA_SEGMENT: case ElementType::TRILL_SEGMENT: case ElementType::VIBRATO_SEGMENT: case ElementType::PEDAL_SEGMENT: { SpannerSegment* s = toSpannerSegment(e); Spanner* sp = s->spanner(); Element* stEl = sp->startElement(); Spanner* prevSp = sp->prevSpanner(sp, staffId); if (prevSp) return prevSp->spannerSegments().front(); else { Segment* startSeg = sp->startSegment(); if (!startSeg->annotations().empty()) { Element* last = startSeg->lastAnnotation(startSeg, staffId); if (last) return last; } Element* el = startSeg->lastElementOfSegment(startSeg, staffId); if (stEl->type() == ElementType::CHORD || stEl->type() == ElementType::REST || stEl->type() == ElementType::REPEAT_MEASURE || stEl->type() == ElementType::NOTE) { ChordRest* cr = startSeg->cr(stEl->track()); if (cr) { Element* elCr = cr->lastElementBeforeSegment(); if (elCr) { return elCr; } } } if (el->isChord()) return toChord(el)->lastElementBeforeSegment(); else if (el->isNote()) { Chord* c = toNote(el)->chord(); return c->lastElementBeforeSegment(); } else { return el; } } } case ElementType::GLISSANDO_SEGMENT: case ElementType::TIE_SEGMENT: { SpannerSegment* s = toSpannerSegment(e); Spanner* sp = s->spanner(); Element* elSt = sp->startElement(); Q_ASSERT(elSt->type() == ElementType::NOTE); Note* n = toNote(elSt); Element* prev = n->prevElement(); if(prev) return prev; else break; } case ElementType::VBOX: case ElementType::HBOX: case ElementType::TBOX: { MeasureBase* mb = toMeasureBase(e)->prevMM(); if (!mb) { break; } else if (mb->isMeasure()) { ChordRest* cr = selection().currentCR(); int si = cr ? cr->staffIdx() : 0; Segment* s = toMeasure(mb)->last(); if (s) return s->lastElement(si); } else { return mb; } } break; case ElementType::LAYOUT_BREAK: { staffId = 0; // otherwise it will equal -1, which breaks the navigation } default: break; } e = e->parent(); } return score()->firstElement(); } }