MuseScore/libmscore/navigate.cpp
2017-07-13 23:52:00 +05:30

721 lines
25 KiB
C++

//=============================================================================
// 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<Chord*> 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<Chord*> 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<Chord*> 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 = static_cast<Chord*>(e);
if (!c->graceNotes().empty()) {
QVector<Chord*> 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<Chord*> 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<Chord*> 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<Chord*> 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<Chord*> 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<Note*>& notes = chord->notes();
auto i = std::find(notes.begin(), notes.end(), note);
if (i != notes.begin()) {
++i;
re = i != notes.end() ? *i : 0;
}
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<Note*>& 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()
{
Segment *s = firstSegment(SegmentType::All);
return s ? s->element(0) : nullptr;
}
//---------------------------------------------------------
// lastElement
//---------------------------------------------------------
Element* Score::lastElement()
{
Element* re = 0;
Segment* seg = lastSegment();
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;
int 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();
int 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::CHORD: {
Element* next = e->nextElement();
if (next)
return next;
else
break;
}
case ElementType::SEGMENT: {
Segment* s = static_cast<Segment*>(e);
Element* next = s->nextElement(staffId);
if (next)
return next;
else
break;
}
case ElementType::MEASURE: {
Measure* m = static_cast<Measure*>(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 = static_cast<Segment*>(e);
Element* next = s->nextElement(staffId);
if (next)
return next;
else
return score()->firstElement();
}
case ElementType::SLUR_SEGMENT:
case ElementType::TEXTLINE_SEGMENT:
case ElementType::HAIRPIN_SEGMENT:
case ElementType::OTTAVA_SEGMENT:
case ElementType::TRILL_SEGMENT:
case ElementType::VOLTA_SEGMENT:
case ElementType::PEDAL_SEGMENT: {
SpannerSegment* s = static_cast<SpannerSegment*>(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->next1();
}
}
break;
}
case ElementType::GLISSANDO_SEGMENT:
case ElementType::TIE_SEGMENT: {
SpannerSegment* s = static_cast<SpannerSegment*>(e);
Spanner* sp = s->spanner();
Element* elSt = sp->startElement();
Note* n = static_cast<Note*>(elSt);
Element* next = n->nextElement();
if (next)
return next;
else
break;
}
default:
break;
}
e = e->parent();
}
return score()->firstElement();
}
//---------------------------------------------------------
// 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 = static_cast<Segment*>(e);
Element* prev = s->prevElement(staffId);
if (prev)
return prev;
else
break;
}
case ElementType::MEASURE: {
Measure* m = static_cast<Measure*>(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 = static_cast<Segment*>(e);
return s->prevElement(staffId);
}
case ElementType::SLUR_SEGMENT:
case ElementType::TEXTLINE_SEGMENT:
case ElementType::HAIRPIN_SEGMENT:
case ElementType::OTTAVA_SEGMENT:
case ElementType::TRILL_SEGMENT:
case ElementType::VOLTA_SEGMENT:
case ElementType::PEDAL_SEGMENT: {
SpannerSegment* s = static_cast<SpannerSegment*>(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->type() == ElementType::CHORD) {
return static_cast<Chord*>(el)->lastElementBeforeSegment();
}
else if (el->type() == ElementType::NOTE) {
Chord* c = static_cast<Note*>(el)->chord();
return c->lastElementBeforeSegment();
}
else {
return el;
}
}
}
case ElementType::GLISSANDO_SEGMENT:
case ElementType::TIE_SEGMENT: {
SpannerSegment* s = static_cast<SpannerSegment*>(e);
Spanner* sp = s->spanner();
Element* elSt = sp->startElement();
Q_ASSERT(elSt->type() == ElementType::NOTE);
Note* n = static_cast<Note*>(elSt);
Element* prev = n->prevElement();
if(prev)
return prev;
else
break;
}
default:
break;
}
e = e->parent();
}
return score()->lastElement();
}
}