Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "navigation.h"
24 :
25 : #include "../dom/box.h"
26 : #include "../dom/chord.h"
27 : #include "../dom/engravingitem.h"
28 : #include "../dom/fret.h"
29 : #include "../dom/guitarbend.h"
30 : #include "../dom/hammeronpulloff.h"
31 : #include "../dom/harmony.h"
32 : #include "../dom/lyrics.h"
33 : #include "../dom/measure.h"
34 : #include "../dom/measurerepeat.h"
35 : #include "../dom/mscore.h"
36 : #include "../dom/note.h"
37 : #include "../dom/pagelockindicator.h"
38 : #include "../dom/rest.h"
39 : #include "../dom/score.h"
40 : #include "../dom/segment.h"
41 : #include "../dom/soundflag.h"
42 : #include "../dom/spanner.h"
43 : #include "../dom/staff.h"
44 : #include "../dom/system.h"
45 : #include "../dom/systemlockindicator.h"
46 : #include "../dom/tapping.h"
47 : #include "../style/style.h"
48 :
49 : #include "mscoreview.h"
50 :
51 : using namespace mu;
52 :
53 : namespace mu::engraving {
54 : using ElementPair = std::pair<EngravingItem*, int>; // element and its index as a child
55 :
56 : //---------------------------------------------------------
57 : // isChild1beforeChild2
58 : // compares if two children are order correctly
59 : // from top-left to bottom-right
60 : //---------------------------------------------------------
61 :
62 0 : static bool isChild1beforeChild2(const ElementPair& child1, const ElementPair& child2)
63 : {
64 0 : assert(child1.first->parent() == child2.first->parent());
65 :
66 0 : PointF p1 = child1.first->pos() + child1.first->ldata()->bbox().center();
67 0 : PointF p2 = child2.first->pos() + child2.first->ldata()->bbox().center();
68 :
69 : // If one child is *clearly* above the other then visit the higher one first
70 0 : double verticalSeparation = p2.y() - p1.y();
71 0 : if (verticalSeparation > 10) {
72 0 : return true;
73 0 : } else if (verticalSeparation < -10) {
74 0 : return false;
75 : }
76 :
77 : // Children are roughly aligned vertically. Visit the one on the left first
78 0 : double horizontalSeparation = p2.x() - p1.x();
79 0 : if (horizontalSeparation > 0.0) {
80 0 : return true;
81 0 : } else if (horizontalSeparation < 0.0) {
82 0 : return false;
83 : }
84 :
85 : // Children are aligned horizontally so check exact vertical position.
86 0 : if (verticalSeparation > 0.0) {
87 0 : return true;
88 0 : } else if (verticalSeparation < 0.0) {
89 0 : return false;
90 : }
91 :
92 : // Elements are at exact same position so fall back to using child index to determine order.
93 0 : if (child1.second < child2.second) {
94 0 : return true;
95 : }
96 :
97 0 : return false;
98 : }
99 :
100 : //---------------------------------------------------------
101 : // toChildPairsSet
102 : // return a set of children ordered
103 : // on the basis of position
104 : //---------------------------------------------------------
105 :
106 0 : static std::set<ElementPair, decltype(& isChild1beforeChild2)> toChildPairsSet(const EngravingItem* element)
107 : {
108 0 : std::set<ElementPair, decltype(& isChild1beforeChild2)> children(&isChild1beforeChild2);
109 0 : int index = 0;
110 :
111 0 : for (EngravingObject* object : element->children()) {
112 0 : EngravingItem* engravingItem = toEngravingItem(object);
113 :
114 0 : if (!engravingItem) {
115 0 : continue;
116 : }
117 :
118 0 : children.insert(std::pair<EngravingItem*, int>(engravingItem, index));
119 0 : index++;
120 : }
121 :
122 0 : return children;
123 0 : }
124 :
125 0 : static EngravingItem* nextElementForSpannerSegment(const SpannerSegment* spannerSegment)
126 : {
127 0 : Spanner* spanner = spannerSegment->spanner();
128 0 : EngravingItem* elSt = spanner->startElement();
129 0 : IF_ASSERT_FAILED(elSt->isNote()) {
130 0 : return nullptr;
131 : }
132 :
133 0 : Note* note = toNote(elSt);
134 0 : return note->nextElement();
135 : }
136 :
137 0 : static EngravingItem* prevElementForSpannerSegment(const SpannerSegment* spannerSegment)
138 : {
139 0 : Spanner* spanner = spannerSegment->spanner();
140 0 : EngravingItem* elSt = spanner->startElement();
141 0 : IF_ASSERT_FAILED(elSt->isNote()) {
142 0 : return nullptr;
143 : }
144 :
145 0 : Note* note = toNote(elSt);
146 0 : return note->prevElement();
147 : }
148 :
149 : //---------------------------------------------------------
150 : // nextChordRest
151 : // return next Chord or Rest
152 : //---------------------------------------------------------
153 :
154 810 : ChordRest* Navigation::nextChordRest(const ChordRest* cr, const ChordRestNavigateOptions& options)
155 : {
156 810 : if (!cr) {
157 0 : return nullptr;
158 : }
159 :
160 810 : if (cr->isGrace()) {
161 13 : const Chord* c = toChord(cr);
162 13 : Chord* pc = toChord(cr->ownershipParent());
163 :
164 13 : if (options.skipGrace) {
165 0 : cr = toChordRest(cr->ownershipParent());
166 13 : } else if (cr->isGraceBefore()) {
167 5 : const GraceNotesGroup& group = pc->graceNotesBefore();
168 5 : auto i = std::find(group.begin(), group.end(), c);
169 5 : if (i == group.end()) {
170 0 : return nullptr; // unable to find self?
171 : }
172 5 : ++i;
173 5 : if (i != group.end()) {
174 0 : return *i;
175 : }
176 : // if this was last grace note before, return parent
177 5 : return pc;
178 : } else {
179 8 : const GraceNotesGroup& group = pc->graceNotesAfter();
180 8 : auto i = std::find(group.begin(), group.end(), c);
181 8 : if (i == group.end()) {
182 3 : return nullptr; // unable to find self?
183 : }
184 8 : ++i;
185 8 : if (i != group.end()) {
186 3 : return *i;
187 : }
188 : // if this was last grace note after, fall through to find next main note
189 5 : cr = pc;
190 : }
191 : } else { // cr is not a grace note
192 797 : if (cr->isChord() && !options.skipGrace) {
193 468 : const Chord* c = toChord(cr);
194 468 : if (!c->graceNotes().empty()) {
195 21 : const GraceNotesGroup& group = c->graceNotesAfter();
196 21 : if (!group.empty()) {
197 4 : return group.front();
198 : }
199 : }
200 : }
201 : }
202 :
203 798 : track_idx_t track = cr->track();
204 798 : SegmentType st = SegmentType::ChordRest;
205 798 : Segment* curSeg = cr->segment();
206 820 : for (Segment* seg = curSeg->next1MM(st); seg; seg = seg->next1MM(st)) {
207 787 : if (options.disableOverRepeats && !segmentsAreAdjacent(curSeg, seg)) {
208 0 : return nullptr;
209 : }
210 787 : ChordRest* e = toChordRest(seg->element(track));
211 787 : if (e) {
212 766 : if (options.skipMeasureRepeatRests && e->isRest() && e->measure()->isMeasureRepeatGroup(track2staff(track))) {
213 1 : continue; // these rests are not shown, skip them
214 : }
215 765 : if (e->isChord() && !options.skipGrace) {
216 272 : Chord* c = toChord(e);
217 272 : if (!c->graceNotes().empty()) {
218 16 : const GraceNotesGroup& group = c->graceNotesBefore();
219 16 : if (!group.empty()) {
220 12 : return group.front();
221 : }
222 : }
223 : }
224 753 : return e;
225 : }
226 : }
227 :
228 33 : return nullptr;
229 : }
230 :
231 : //---------------------------------------------------------
232 : // prevChordRest
233 : // return previous Chord or Rest
234 : // if grace is true, include grace notes
235 : //---------------------------------------------------------
236 :
237 869 : ChordRest* Navigation::prevChordRest(const ChordRest* cr, const ChordRestNavigateOptions& options)
238 : {
239 869 : if (!cr) {
240 0 : return nullptr;
241 : }
242 :
243 869 : if (cr->isGrace()) {
244 563 : const Chord* c = toChord(cr);
245 563 : Chord* pc = toChord(cr->ownershipParent());
246 :
247 563 : if (options.skipGrace) {
248 0 : cr = toChordRest(cr->ownershipParent());
249 563 : } else if (cr->isGraceBefore()) {
250 563 : const GraceNotesGroup& group = pc->graceNotesBefore();
251 563 : auto i = std::find(group.begin(), group.end(), c);
252 563 : if (i == group.end()) {
253 0 : return nullptr; // unable to find self?
254 : }
255 563 : if (i != group.begin()) {
256 0 : return *--i;
257 : }
258 : // if this was first grace note before, fall through to find previous main note
259 563 : cr = pc;
260 : } else {
261 0 : const GraceNotesGroup& group = pc->graceNotesAfter();
262 0 : auto i = std::find(group.begin(), group.end(), c);
263 0 : if (i == group.end()) {
264 0 : return nullptr; // unable to find self?
265 : }
266 0 : if (i != group.begin()) {
267 0 : return *--i;
268 : }
269 : // if this was first grace note after, return parent
270 0 : return pc;
271 : }
272 : } else {
273 : //
274 : // cr is not a grace note
275 306 : if (cr->isChord() && !options.skipGrace) {
276 306 : const Chord* c = toChord(cr);
277 306 : const GraceNotesGroup& group = c->graceNotesBefore();
278 306 : if (!group.empty()) {
279 0 : return group.back();
280 : }
281 : }
282 : }
283 :
284 869 : track_idx_t track = cr->track();
285 869 : SegmentType st = SegmentType::ChordRest;
286 869 : Segment* curSeg = cr->segment();
287 882 : for (Segment* seg = cr->segment()->prev1MM(st); seg; seg = seg->prev1MM(st)) {
288 679 : if (options.disableOverRepeats && !segmentsAreAdjacent(curSeg, seg)) {
289 0 : return nullptr;
290 : }
291 :
292 679 : ChordRest* e = toChordRest(seg->element(track));
293 679 : if (e) {
294 666 : if (options.skipMeasureRepeatRests && e->isRest() && e->measure()->isMeasureRepeatGroup(track2staff(track))) {
295 0 : continue; // these rests are not shown, skip them
296 : }
297 666 : if (e->isChord() && !options.skipGrace) {
298 543 : const GraceNotesGroup& group = toChord(e)->graceNotesAfter();
299 543 : if (!group.empty()) {
300 117 : return group.back();
301 : }
302 : }
303 549 : return e;
304 : }
305 : }
306 :
307 203 : return nullptr;
308 : }
309 :
310 : //---------------------------------------------------------
311 : // chordNoteAbove
312 : // element: Note, Rest, MMRest, or MeasureRepeat
313 : // return: Note, Rest, MMRest, or MeasureRepeat
314 : //
315 : // return next higher pitched note in chord
316 : // move to previous track if at top of chord
317 : //---------------------------------------------------------
318 :
319 0 : EngravingItem* Navigation::chordNoteAbove(Score* score, EngravingItem* element)
320 : {
321 0 : EngravingItem* re = 0;
322 0 : if (element->isRestFamily()) {
323 0 : re = score->prevTrack(toRest(element));
324 0 : } else if (element->isNote()) {
325 0 : Note* note = toNote(element);
326 0 : Chord* chord = note->chord();
327 0 : const std::vector<Note*>& notes = chord->notes();
328 0 : auto i = std::find(notes.begin(), notes.end(), note);
329 0 : ++i;
330 0 : if (i != notes.end()) {
331 0 : re = *i;
332 : } else {
333 0 : re = score->prevTrack(chord);
334 0 : if (re->track() == chord->track()) {
335 0 : re = element;
336 : }
337 : }
338 : }
339 0 : if (re == 0) {
340 0 : return 0;
341 : }
342 0 : if (re->isChord()) {
343 0 : re = toChord(re)->notes().front();
344 : }
345 0 : return re;
346 : }
347 :
348 : //---------------------------------------------------------
349 : // topNoteInChord
350 : //---------------------------------------------------------
351 :
352 0 : Note* Navigation::topNoteInChord(Note* note)
353 : {
354 0 : return note->chord()->upNote();
355 : }
356 :
357 : //---------------------------------------------------------
358 : // chordNoteBelow
359 : // return next lower pitched note in chord
360 : // move to next track if at bottom of chord
361 : //---------------------------------------------------------
362 :
363 0 : EngravingItem* Navigation::chordNoteBelow(Score* score, EngravingItem* element)
364 : {
365 0 : EngravingItem* re = 0;
366 0 : if (element->isRestFamily()) {
367 0 : re = score->nextTrack(toRest(element));
368 0 : } else if (element->isNote()) {
369 0 : Note* note = toNote(element);
370 0 : Chord* chord = note->chord();
371 0 : const std::vector<Note*>& notes = chord->notes();
372 0 : auto i = std::find(notes.begin(), notes.end(), note);
373 0 : if (i != notes.begin()) {
374 0 : --i;
375 0 : re = *i;
376 : } else {
377 0 : re = score->nextTrack(chord);
378 0 : if (re->track() == chord->track()) {
379 0 : re = element;
380 : }
381 : }
382 : }
383 0 : if (re == 0) {
384 0 : return 0;
385 : }
386 0 : if (re->isChord()) {
387 0 : re = toChord(re)->notes().back();
388 : }
389 0 : return re;
390 : }
391 :
392 : //---------------------------------------------------------
393 : // bottomNoteInChord
394 : //---------------------------------------------------------
395 :
396 0 : Note* Navigation::bottomNoteInChord(Note* note)
397 : {
398 0 : return note->chord()->downNote();
399 : }
400 :
401 : //---------------------------------------------------------
402 : // firstElement
403 : //---------------------------------------------------------
404 :
405 0 : EngravingItem* Navigation::firstElement(Score* score, bool frame)
406 : {
407 0 : if (frame) {
408 0 : MeasureBase* mb = score->measures()->first();
409 0 : if (mb && mb->isBox()) {
410 0 : return mb;
411 : }
412 : }
413 0 : Segment* s = score->firstSegmentMM(SegmentType::All);
414 0 : return s ? s->element(0) : nullptr;
415 : }
416 :
417 : //---------------------------------------------------------
418 : // lastElement
419 : //---------------------------------------------------------
420 :
421 4 : EngravingItem* Navigation::lastElement(Score* score, bool frame)
422 : {
423 4 : if (frame) {
424 4 : MeasureBase* mb = score->measures()->last();
425 4 : if (mb && mb->isBox()) {
426 0 : auto boxChildren = toChildPairsSet(mb);
427 0 : if (!boxChildren.empty()) {
428 0 : return boxChildren.rbegin()->first;
429 : }
430 0 : return mb;
431 0 : }
432 : }
433 4 : EngravingItem* re = 0;
434 4 : Segment* seg = score->lastSegmentMM();
435 4 : if (!seg) {
436 0 : return nullptr;
437 : }
438 : while (true) {
439 20 : for (size_t i = (score->staves().size() - 1) * VOICES; i < score->staves().size() * VOICES; i++) {
440 16 : if (seg->element(i)) {
441 4 : re = seg->element(i);
442 : }
443 : }
444 4 : if (re) {
445 4 : if (re->isChord()) {
446 0 : return toChord(re)->notes().front();
447 : }
448 4 : return re;
449 : }
450 0 : seg = seg->prev1MM(SegmentType::All);
451 0 : }
452 : }
453 :
454 : //---------------------------------------------------------
455 : // upStaff
456 : //---------------------------------------------------------
457 :
458 0 : ChordRest* Navigation::upStaff(ChordRest* cr)
459 : {
460 0 : Segment* segment = cr->segment();
461 :
462 0 : if (cr->staffIdx() == 0) {
463 0 : return cr;
464 : }
465 :
466 0 : for (int track = (static_cast<int>(cr->staffIdx()) - 1) * VOICES; track >= 0; --track) {
467 0 : EngravingItem* el = segment->element(track);
468 0 : if (!el) {
469 0 : continue;
470 : }
471 0 : if (el->isNote()) {
472 0 : el = toNote(el)->chord();
473 : }
474 0 : if (el->isChordRest()) {
475 0 : return toChordRest(el);
476 : }
477 : }
478 0 : return 0;
479 : }
480 :
481 : //---------------------------------------------------------
482 : // downStaff
483 : //---------------------------------------------------------
484 :
485 0 : ChordRest* Navigation::downStaff(Score* score, ChordRest* cr)
486 : {
487 0 : Segment* segment = cr->segment();
488 0 : track_idx_t tracks = score->nstaves() * VOICES;
489 :
490 0 : if (cr->staffIdx() == score->nstaves() - 1) {
491 0 : return cr;
492 : }
493 :
494 0 : for (track_idx_t track = (cr->staffIdx() + 1) * VOICES; track < tracks; --track) {
495 0 : EngravingItem* el = segment->element(track);
496 0 : if (!el) {
497 0 : continue;
498 : }
499 0 : if (el->isNote()) {
500 0 : el = toNote(el)->chord();
501 : }
502 0 : if (el->isChordRest()) {
503 0 : return toChordRest(el);
504 : }
505 : }
506 0 : return 0;
507 : }
508 :
509 : //---------------------------------------------------------
510 : // topStaff
511 : //---------------------------------------------------------
512 :
513 0 : ChordRest* Navigation::topStaff(Score* score, ChordRest* cr)
514 : {
515 : // Go to top-most staff of current or first measure depending upon active selection
516 0 : const auto* destinationMeasure = cr ? cr->measure() : score->firstMeasure();
517 0 : if (destinationMeasure) {
518 : // Accommodate for MMRest
519 0 : if (score->style().styleB(Sid::createMultiMeasureRests) && destinationMeasure->hasMMRest()) {
520 0 : destinationMeasure = destinationMeasure->coveringMMRestOrThis();
521 : }
522 : // Get first ChordRest of top staff
523 0 : cr = destinationMeasure->first()->nextChordRest(0, false);
524 : }
525 0 : return cr;
526 : }
527 :
528 : //---------------------------------------------------------
529 : // nextTrack
530 : // returns note at or just before current (cr) position
531 : // in next track for this measure
532 : // that contains such an element
533 : //---------------------------------------------------------
534 :
535 0 : ChordRest* Score::nextTrack(ChordRest* cr, bool skipMeasureRepeatRests)
536 : {
537 0 : if (!cr) {
538 0 : return 0;
539 : }
540 :
541 0 : ChordRest* el = nullptr;
542 0 : Measure* measure = cr->measure();
543 0 : track_idx_t track = cr->track();
544 0 : size_t tracks = nstaves() * VOICES;
545 :
546 0 : while (!el) {
547 : // find next non-empty track
548 0 : while (++track < tracks) {
549 0 : if (measure->hasVoice(track)) {
550 0 : break;
551 : }
552 : }
553 : // no more tracks, return original element
554 0 : if (track == tracks) {
555 0 : return cr;
556 : }
557 : // treat MeasureRepeat as if it starts in the first measure of its group even if internally it's farther along
558 0 : if (cr->isMeasureRepeat()) {
559 0 : measure = measure->firstOfMeasureRepeatGroup(cr->staffIdx());
560 0 : return toChordRest(measure->first(SegmentType::ChordRest)->element(track));
561 : }
562 : // find element at same or previous segment within this track
563 0 : for (Segment* segment = cr->segment(); segment; segment = segment->prev(SegmentType::ChordRest)) {
564 0 : el = toChordRest(segment->element(track));
565 0 : if (el) {
566 0 : break;
567 : }
568 : }
569 : }
570 0 : if (skipMeasureRepeatRests && el->isRest() && measure->isMeasureRepeatGroup(track2staff(track))) {
571 0 : el = measure->measureRepeatElement(track2staff(track));
572 : }
573 0 : return el;
574 : }
575 :
576 : //---------------------------------------------------------
577 : // prevTrack
578 : // returns ChordRest at or just before current (cr) position
579 : // in previous track for this measure
580 : // that contains such an element
581 : //---------------------------------------------------------
582 :
583 0 : ChordRest* Score::prevTrack(ChordRest* cr, bool skipMeasureRepeatRests)
584 : {
585 0 : if (!cr) {
586 0 : return 0;
587 : }
588 :
589 0 : ChordRest* el = nullptr;
590 0 : Measure* measure = cr->measure();
591 0 : int track = static_cast<int>(cr->track());
592 :
593 0 : while (!el) {
594 : // find next non-empty track
595 0 : while (--track >= 0) {
596 0 : if (measure->hasVoice(track)) {
597 0 : break;
598 : }
599 : }
600 : // no more tracks, return original element
601 0 : if (track < 0) {
602 0 : return cr;
603 : }
604 : // treat MeasureRepeat as if it starts in the first measure of its group even if internally it's farther along
605 0 : if (cr->isMeasureRepeat()) {
606 0 : measure = measure->firstOfMeasureRepeatGroup(cr->staffIdx());
607 0 : return toChordRest(measure->first(SegmentType::ChordRest)->element(track));
608 : }
609 : // find element at same or previous segment within this track
610 0 : for (Segment* segment = cr->segment(); segment; segment = segment->prev(SegmentType::ChordRest)) {
611 0 : el = toChordRest(segment->element(track));
612 0 : if (el) {
613 0 : break;
614 : }
615 : }
616 : }
617 0 : if (skipMeasureRepeatRests && el->isRest() && measure->isMeasureRepeatGroup(track2staff(track))) {
618 0 : el = measure->measureRepeatElement(track2staff(track));
619 : }
620 0 : return el;
621 : }
622 :
623 : //---------------------------------------------------------
624 : // nextMeasure
625 : //---------------------------------------------------------
626 :
627 0 : ChordRest* Navigation::nextMeasure(Score* score, ChordRest* element, bool selectBehavior, bool mmRest)
628 : {
629 0 : if (!element) {
630 0 : return nullptr;
631 : }
632 :
633 0 : Measure* measure = nullptr;
634 0 : if (mmRest) {
635 0 : measure = element->measure()->nextMeasureMM();
636 : } else {
637 0 : measure = element->measure()->nextMeasure();
638 : }
639 :
640 0 : Fraction endTick = element->measure()->last()->nextChordRest(element->track(), true)->tick();
641 0 : bool last = false;
642 :
643 0 : if (score->selection().isRange()) {
644 0 : if (element->tick() != endTick && score->selection().tickEnd() <= endTick) {
645 0 : measure = element->measure();
646 0 : last = true;
647 0 : } else if (element->tick() == endTick && score->selection().isEndActive()) {
648 0 : last = true;
649 : }
650 0 : } else if (element->tick() != endTick && selectBehavior) {
651 0 : measure = element->measure();
652 0 : last = true;
653 : }
654 0 : if (!measure) {
655 0 : measure = element->measure();
656 0 : last = true;
657 : }
658 0 : staff_idx_t staff = element->staffIdx();
659 :
660 0 : Segment* startSeg = last ? measure->last() : measure->first();
661 0 : for (Segment* seg = startSeg; seg; seg = last ? seg->prev() : seg->next()) {
662 0 : track_idx_t etrack = (staff + 1) * VOICES;
663 0 : for (track_idx_t track = staff * VOICES; track < etrack; ++track) {
664 0 : EngravingItem* pel = seg->element(track);
665 :
666 0 : if (pel && pel->isChordRest()) {
667 0 : return toChordRest(pel);
668 : }
669 : }
670 : }
671 0 : return nullptr;
672 : }
673 :
674 : //---------------------------------------------------------
675 : // prevMeasure
676 : //---------------------------------------------------------
677 :
678 0 : ChordRest* Navigation::prevMeasure(Score* score, ChordRest* element, bool mmRest)
679 : {
680 0 : if (!element) {
681 0 : return nullptr;
682 : }
683 :
684 0 : Measure* measure = nullptr;
685 0 : if (mmRest) {
686 0 : measure = element->measure()->prevMeasureMM();
687 : } else {
688 0 : measure = element->measure()->prevMeasure();
689 : }
690 :
691 0 : Fraction startTick = element->measure()->first()->nextChordRest(element->track())->tick();
692 0 : bool last = false;
693 :
694 0 : if (score->selection().isRange() && score->selection().isEndActive() && score->selection().startSegment()->tick() <= startTick) {
695 0 : last = true;
696 0 : } else if (element->tick() != startTick) {
697 0 : measure = element->measure();
698 : }
699 0 : if (!measure) {
700 0 : measure = element->measure();
701 0 : last = false;
702 : }
703 :
704 0 : staff_idx_t staff = element->staffIdx();
705 :
706 0 : Segment* startSeg = last ? measure->last() : measure->first();
707 0 : for (Segment* seg = startSeg; seg; seg = last ? seg->prev() : seg->next()) {
708 0 : track_idx_t etrack = (staff + 1) * VOICES;
709 0 : for (track_idx_t track = staff * VOICES; track < etrack; ++track) {
710 0 : EngravingItem* pel = seg->element(track);
711 :
712 0 : if (pel && pel->isChordRest()) {
713 0 : return toChordRest(pel);
714 : }
715 : }
716 : }
717 0 : return nullptr;
718 : }
719 :
720 : //---------------------------------------------------------
721 : // nextElement
722 : //---------------------------------------------------------
723 :
724 0 : EngravingItem* Score::nextElement()
725 : {
726 0 : EngravingItem* e = getSelectedElement();
727 0 : if (!e) {
728 0 : return nullptr;
729 : }
730 0 : staff_idx_t staffId = e->staffIdx();
731 0 : while (e) {
732 0 : switch (e->type()) {
733 0 : case ElementType::NOTE:
734 : case ElementType::REST:
735 : case ElementType::MMREST:
736 : case ElementType::CHORD:
737 : case ElementType::TUPLET: {
738 0 : EngravingItem* next = e->nextElement();
739 0 : if (next) {
740 0 : return next;
741 : } else {
742 0 : break;
743 : }
744 : }
745 0 : case ElementType::SEGMENT: {
746 0 : Segment* s = toSegment(e);
747 0 : EngravingItem* next = s->nextElement(staffId);
748 0 : if (next) {
749 0 : return next;
750 : } else {
751 0 : break;
752 : }
753 : }
754 0 : case ElementType::MEASURE: {
755 0 : Measure* m = toMeasure(e);
756 0 : EngravingItem* next = m->nextElementStaff(staffId);
757 0 : if (next) {
758 0 : return next;
759 : } else {
760 0 : break;
761 : }
762 : }
763 0 : case ElementType::CLEF:
764 : case ElementType::KEYSIG:
765 : case ElementType::TIMESIG:
766 : case ElementType::BAR_LINE: {
767 0 : for (; e && !e->isSegment(); e = e->layoutParent()) {
768 : }
769 0 : Segment* s = toSegment(e);
770 0 : EngravingItem* next = s->nextElement(staffId);
771 0 : if (next) {
772 0 : return next;
773 : } else {
774 0 : return Navigation::firstElement(score());
775 : }
776 : }
777 0 : case ElementType::TAPPING:
778 : {
779 0 : TappingHalfSlur* halfSlurAbove = toTapping(e)->halfSlurAbove();
780 0 : EngravingItem* selEl = getSelectedElement();
781 0 : if (halfSlurAbove && !(selEl && selEl->isTappingHalfSlurSegment())) {
782 0 : return halfSlurAbove->frontSegment();
783 : }
784 0 : break;
785 : }
786 0 : case ElementType::HAMMER_ON_PULL_OFF_TEXT:
787 0 : return toHammerOnPullOffText(e)->endChord()->upNote();
788 0 : case ElementType::HAMMER_ON_PULL_OFF_SEGMENT:
789 : {
790 0 : HammerOnPullOffSegment* hopoSeg = toHammerOnPullOffSegment(e);
791 0 : if (!hopoSeg->hopoText().empty()) {
792 0 : return hopoSeg->hopoText().front();
793 : }
794 : [[fallthrough]];
795 : }
796 : case ElementType::TAPPING_HALF_SLUR_SEGMENT:
797 : {
798 0 : TappingHalfSlur* halfSlur = toTappingHalfSlurSegment(e)->tappingHalfSlur();
799 0 : Tapping* tapping = halfSlur->tapping();
800 0 : if (halfSlur->isHalfSlurAbove() && tapping->halfSlurBelow()) {
801 0 : return tapping->halfSlurBelow()->frontSegment();
802 : }
803 : [[fallthrough]];
804 : }
805 : case ElementType::VOLTA_SEGMENT:
806 : case ElementType::SLUR_SEGMENT:
807 : case ElementType::TEXTLINE_SEGMENT:
808 : case ElementType::HAIRPIN_SEGMENT:
809 : case ElementType::OTTAVA_SEGMENT:
810 : case ElementType::TRILL_SEGMENT:
811 : case ElementType::VIBRATO_SEGMENT:
812 : case ElementType::LET_RING_SEGMENT:
813 : case ElementType::GRADUAL_TEMPO_CHANGE_SEGMENT:
814 : case ElementType::PALM_MUTE_SEGMENT:
815 : case ElementType::WHAMMY_BAR_SEGMENT:
816 : case ElementType::RASGUEADO_SEGMENT:
817 : case ElementType::HARMONIC_MARK_SEGMENT:
818 : case ElementType::PICK_SCRAPE_SEGMENT:
819 : case ElementType::PEDAL_SEGMENT: {
820 0 : SpannerSegment* s = toSpannerSegment(e);
821 0 : Spanner* sp = s->spanner();
822 0 : Spanner* nextSp = sp->nextSpanner(sp, staffId);
823 0 : if (nextSp) {
824 0 : return nextSp->spannerSegments().front();
825 : }
826 :
827 0 : Segment* seg = tick2segment(sp->tick());
828 0 : if (seg) {
829 0 : Segment* nextSegment = seg->next1();
830 0 : while (nextSegment) {
831 0 : if (nextSegment->isTimeTickType()) {
832 0 : if (EngravingItem* annotation = nextSegment->firstAnnotation(staffId)) {
833 0 : return annotation;
834 : }
835 0 : if (Spanner* spanner = nextSegment->firstSpanner(staffId)) {
836 0 : return spanner->spannerSegments().front();
837 : }
838 0 : } else if (EngravingItem* nextEl = nextSegment->firstElementOfSegment(staffId)) {
839 0 : return nextEl;
840 : }
841 0 : nextSegment = nextSegment->next1MM();
842 : }
843 : }
844 0 : break;
845 : }
846 0 : case ElementType::GUITAR_BEND_SEGMENT:
847 : case ElementType::GUITAR_BEND_HOLD_SEGMENT: {
848 : GuitarBend* bend
849 0 : = e->isGuitarBendSegment() ? toGuitarBendSegment(e)->guitarBend() : toGuitarBendHoldSegment(e)->guitarBendHold()->
850 0 : guitarBend();
851 0 : if (bend->bendType() != GuitarBendType::SLIGHT_BEND) {
852 0 : return bend->endNote();
853 : } else {
854 0 : EngravingItem* next = nextElementForSpannerSegment(toSpannerSegment(e));
855 0 : if (next) {
856 0 : return next;
857 : }
858 : }
859 :
860 0 : break;
861 : }
862 0 : case ElementType::GLISSANDO_SEGMENT:
863 : case ElementType::NOTELINE_SEGMENT:
864 : case ElementType::LAISSEZ_VIB_SEGMENT:
865 : case ElementType::PARTIAL_TIE_SEGMENT:
866 : case ElementType::TIE_SEGMENT: {
867 0 : EngravingItem* next = nextElementForSpannerSegment(toSpannerSegment(e));
868 0 : if (next) {
869 0 : return next;
870 : } else {
871 0 : break;
872 : }
873 : }
874 0 : case ElementType::VBOX:
875 : case ElementType::HBOX:
876 : case ElementType::TBOX:
877 : case ElementType::FBOX: {
878 0 : auto boxChildren = toChildPairsSet(e);
879 :
880 0 : EngravingItem* selectedElement = getSelectedElement();
881 :
882 0 : if ((selectedElement->isVBox()
883 0 : || selectedElement->isHBox()
884 0 : || selectedElement->isTBox()) && !boxChildren.empty()) {
885 0 : return boxChildren.begin()->first;
886 : }
887 :
888 0 : if (selectedElement->isFBox()) {
889 0 : for (EngravingItem* child : toFBox(selectedElement)->el()) {
890 0 : if (child->isFretDiagram() && child->visible()) {
891 0 : return toFretDiagram(child)->harmony();
892 : }
893 : }
894 : }
895 :
896 0 : for (auto child = boxChildren.begin(); child != boxChildren.end(); child++) {
897 0 : if (selectedElement != child->first) {
898 0 : continue;
899 : }
900 :
901 0 : auto targetElement = std::next(child);
902 :
903 0 : if (targetElement != boxChildren.end()) {
904 0 : return targetElement->first;
905 : }
906 : }
907 :
908 0 : MeasureBase* mb = toMeasureBase(e)->nextMM();
909 0 : if (!mb) {
910 0 : break;
911 0 : } else if (mb->isMeasure()) {
912 0 : ChordRest* cr = selection().currentCR();
913 0 : staff_idx_t si = cr ? cr->staffIdx() : 0;
914 0 : return toMeasure(mb)->nextElementStaff(si);
915 : } else {
916 0 : return mb;
917 : }
918 0 : }
919 0 : case ElementType::LAYOUT_BREAK: {
920 0 : staffId = 0; // otherwise it will equal -1, which breaks the navigation
921 0 : break;
922 : }
923 : // TODO: case ElementType::STAFF_VISIBILITY_INDICATOR:
924 0 : case ElementType::SYSTEM_LOCK_INDICATOR:
925 : {
926 0 : staffId = 0;
927 0 : SystemLockIndicator* sli = toSystemLockIndicator(e);
928 0 : System* system = sli->system();
929 0 : if (system && system->pageLockIndicator()) {
930 0 : return system->pageLockIndicator();
931 : } else {
932 0 : e = toSystemLockIndicator(e)->systemLock()->endMB();
933 : }
934 0 : continue;
935 0 : }
936 0 : case ElementType::PAGE_LOCK_INDICATOR:
937 : {
938 0 : staffId = 0;
939 0 : e = toPageLockIndicator(e)->pageLock()->endMB();
940 0 : continue;
941 : }
942 0 : case ElementType::SOUND_FLAG:
943 0 : if (EngravingItem* parent = toSoundFlag(e)->ownershipParentItem()) {
944 0 : return parent;
945 : }
946 0 : break;
947 0 : case ElementType::HARMONY: {
948 0 : if (EngravingItem* parent = toHarmony(e)->ownershipParentItem()) {
949 0 : if (parent->isFretDiagram()) {
950 0 : return parent;
951 : }
952 : }
953 0 : break;
954 : }
955 0 : case ElementType::FRET_DIAGRAM: {
956 0 : FretDiagram* fretDiagram = toFretDiagram(e);
957 0 : if (fretDiagram->isInFretBox()) {
958 0 : const ElementList& diagrams = toFBox(fretDiagram->ownershipParent())->el();
959 :
960 0 : size_t index = muse::indexOf(diagrams, fretDiagram);
961 0 : if (index != muse::nidx) {
962 0 : while (++index < diagrams.size()) {
963 0 : FretDiagram* fretDiagramI = toFretDiagram(diagrams[index]);
964 0 : if (fretDiagramI->visible()) {
965 0 : return fretDiagramI->harmony();
966 : }
967 : }
968 : }
969 : }
970 0 : break;
971 : }
972 0 : default:
973 0 : break;
974 0 : }
975 0 : e = e->layoutParent();
976 : }
977 0 : return Navigation::lastElement(score());
978 : }
979 :
980 : //---------------------------------------------------------
981 : // prevElement
982 : //---------------------------------------------------------
983 :
984 0 : EngravingItem* Score::prevElement()
985 : {
986 0 : EngravingItem* e = getSelectedElement();
987 0 : if (!e) {
988 0 : return nullptr;
989 : }
990 0 : staff_idx_t staffId = e->staffIdx();
991 0 : while (e) {
992 0 : switch (e->type()) {
993 0 : case ElementType::NOTE:
994 : case ElementType::REST:
995 : case ElementType::MMREST:
996 : case ElementType::CHORD:
997 : case ElementType::TUPLET: {
998 0 : EngravingItem* prev = e->prevElement();
999 0 : if (prev) {
1000 0 : return prev;
1001 : } else {
1002 0 : break;
1003 : }
1004 : }
1005 0 : case ElementType::SEGMENT: {
1006 0 : Segment* s = toSegment(e);
1007 0 : EngravingItem* prev = s->prevElement(staffId);
1008 0 : if (prev) {
1009 0 : return prev;
1010 : } else {
1011 0 : break;
1012 : }
1013 : }
1014 0 : case ElementType::MEASURE: {
1015 0 : Measure* m = toMeasure(e);
1016 0 : return m->prevElementStaff(staffId);
1017 : }
1018 0 : case ElementType::CLEF:
1019 : case ElementType::KEYSIG:
1020 : case ElementType::TIMESIG:
1021 : case ElementType::BAR_LINE: {
1022 0 : for (; e && !e->isSegment(); e = e->layoutParent()) {
1023 : }
1024 0 : EngravingItem* previousElement = toSegment(e)->prevElement(staffId);
1025 :
1026 0 : if (!previousElement->isBox()) {
1027 0 : return previousElement;
1028 : }
1029 :
1030 0 : if (previousElement->isFretDiagram()) {
1031 0 : return previousElement;
1032 : }
1033 :
1034 0 : auto boxChildren = toChildPairsSet(previousElement);
1035 :
1036 0 : if (boxChildren.size() > 0) {
1037 0 : return boxChildren.rbegin()->first;
1038 : }
1039 :
1040 0 : return previousElement;
1041 0 : }
1042 0 : case ElementType::HAMMER_ON_PULL_OFF_TEXT:
1043 : {
1044 0 : HammerOnPullOffText* hopoText = toHammerOnPullOffText(e);
1045 0 : HammerOnPullOffSegment* hopoSegment = toHammerOnPullOffSegment(hopoText->parent());
1046 0 : DO_ASSERT(hopoSegment);
1047 0 : if (hopoSegment->hopoText().size() > 0 && hopoSegment->hopoText().front() == hopoText) {
1048 0 : return hopoSegment;
1049 : } else {
1050 0 : return hopoText->startChord()->downNote();
1051 : }
1052 : }
1053 0 : case ElementType::TAPPING_HALF_SLUR_SEGMENT:
1054 : {
1055 0 : TappingHalfSlur* halfSlur = toTappingHalfSlurSegment(e)->tappingHalfSlur();
1056 0 : Tapping* tapping = halfSlur->tapping();
1057 0 : if (!halfSlur->isHalfSlurAbove()) {
1058 0 : IF_ASSERT_FAILED(tapping->halfSlurAbove()) {
1059 0 : return tapping;
1060 : }
1061 0 : return tapping->halfSlurAbove()->frontSegment();
1062 : } else {
1063 0 : return tapping;
1064 : }
1065 : }
1066 0 : case ElementType::VOLTA_SEGMENT:
1067 : case ElementType::SLUR_SEGMENT:
1068 : case ElementType::HAMMER_ON_PULL_OFF_SEGMENT:
1069 : case ElementType::TEXTLINE_SEGMENT:
1070 : case ElementType::HAIRPIN_SEGMENT:
1071 : case ElementType::OTTAVA_SEGMENT:
1072 : case ElementType::TRILL_SEGMENT:
1073 : case ElementType::VIBRATO_SEGMENT:
1074 : case ElementType::PEDAL_SEGMENT: {
1075 0 : SpannerSegment* s = toSpannerSegment(e);
1076 0 : Spanner* sp = s->spanner();
1077 0 : EngravingItem* stEl = sp->startElement();
1078 0 : Spanner* prevSp = sp->prevSpanner(sp, staffId);
1079 0 : if (prevSp) {
1080 0 : return prevSp->spannerSegments().front();
1081 : } else {
1082 0 : Segment* startSeg = sp->startSegment();
1083 0 : if (EngravingItem* annotation = startSeg->lastAnnotation(staffId)) {
1084 0 : return annotation;
1085 : }
1086 0 : if (startSeg->isTimeTickType()) {
1087 0 : startSeg = startSeg->prev1MMenabled();
1088 0 : for (; startSeg && startSeg->isTimeTickType(); startSeg = startSeg->prev1MMenabled()) {
1089 0 : if (Spanner* spanner = startSeg->lastSpanner(staffId)) {
1090 0 : return spanner->spannerSegments().front();
1091 : }
1092 0 : if (EngravingItem* annotation = startSeg->lastAnnotation(staffId)) {
1093 0 : return annotation;
1094 : }
1095 : }
1096 0 : if (!startSeg) {
1097 0 : break;
1098 : }
1099 : // Also check first non-timeTick segment encountered.
1100 0 : if (Spanner* spanner = startSeg->lastSpanner(staffId)) {
1101 0 : return spanner->spannerSegments().front();
1102 : }
1103 0 : if (EngravingItem* annotation = startSeg->lastAnnotation(staffId)) {
1104 0 : return annotation;
1105 : }
1106 : }
1107 0 : EngravingItem* el = startSeg->lastElementOfSegment(staffId);
1108 0 : if (stEl->isChordRest() || stEl->isNote()) {
1109 0 : ChordRest* cr = startSeg->cr(stEl->track());
1110 0 : if (cr) {
1111 0 : EngravingItem* elCr = cr->lastElementBeforeSegment();
1112 0 : if (elCr) {
1113 0 : return elCr;
1114 : }
1115 : }
1116 : }
1117 0 : if (el->isChord()) {
1118 0 : return toChord(el)->lastElementBeforeSegment();
1119 0 : } else if (el->isNote()) {
1120 0 : Chord* c = toNote(el)->chord();
1121 0 : return c->lastElementBeforeSegment();
1122 : } else {
1123 0 : return el;
1124 : }
1125 : }
1126 : }
1127 0 : case ElementType::GUITAR_BEND_SEGMENT:
1128 : case ElementType::GUITAR_BEND_HOLD_SEGMENT: {
1129 0 : GuitarBend* bend = e->isGuitarBendSegment() ? toGuitarBendSegment(e)->guitarBend()
1130 0 : : toGuitarBendHoldSegment(e)->guitarBendHold()->guitarBend();
1131 0 : return bend->startNote();
1132 : }
1133 0 : case ElementType::GLISSANDO_SEGMENT:
1134 : case ElementType::NOTELINE_SEGMENT:
1135 : case ElementType::LAISSEZ_VIB_SEGMENT:
1136 : case ElementType::PARTIAL_TIE_SEGMENT:
1137 : case ElementType::TIE_SEGMENT: {
1138 0 : EngravingItem* prev = prevElementForSpannerSegment(toSpannerSegment(e));
1139 0 : if (prev) {
1140 0 : return prev;
1141 : }
1142 :
1143 0 : break;
1144 : }
1145 0 : case ElementType::VBOX:
1146 : case ElementType::HBOX:
1147 : case ElementType::TBOX:
1148 : case ElementType::FBOX: {
1149 0 : auto boxChildren = toChildPairsSet(e);
1150 :
1151 0 : EngravingItem* selectedElement = getSelectedElement();
1152 :
1153 0 : for (auto child = boxChildren.rbegin(); child != boxChildren.rend(); child++) {
1154 0 : if (selectedElement != child->first) {
1155 0 : continue;
1156 : }
1157 :
1158 0 : auto targetElement = std::next(child);
1159 :
1160 0 : if (targetElement != boxChildren.rend()) {
1161 0 : return targetElement->first;
1162 : }
1163 : }
1164 :
1165 0 : MeasureBase* mb = toMeasureBase(e)->prevMM();
1166 0 : if (!mb) {
1167 0 : break;
1168 0 : } else if (mb->isMeasure()) {
1169 0 : ChordRest* cr = selection().currentCR();
1170 0 : staff_idx_t si = cr ? cr->staffIdx() : 0;
1171 0 : Segment* s = toMeasure(mb)->last();
1172 0 : if (s) {
1173 0 : return s->lastElementForNavigation(si);
1174 : }
1175 : } else {
1176 0 : return mb;
1177 : }
1178 0 : }
1179 0 : break;
1180 0 : case ElementType::LAYOUT_BREAK: {
1181 0 : staffId = 0; // otherwise it will equal -1, which breaks the navigation
1182 0 : break;
1183 : }
1184 : // TODO: case ElementType::STAFF_VISIBILITY_INDICATOR:
1185 0 : case ElementType::SYSTEM_LOCK_INDICATOR:
1186 : {
1187 0 : staffId = 0;
1188 0 : e = toSystemLockIndicator(e)->systemLock()->endMB();
1189 0 : continue;
1190 : }
1191 0 : case ElementType::PAGE_LOCK_INDICATOR:
1192 : {
1193 0 : staffId = 0;
1194 0 : PageLockIndicator* pli = toPageLockIndicator(e);
1195 0 : System* system = pli->system();
1196 0 : if (system && !system->systemLockIndicators().empty()) {
1197 0 : return system->systemLockIndicators().front();
1198 : } else {
1199 0 : e = toPageLockIndicator(e)->pageLock()->endMB();
1200 : }
1201 0 : continue;
1202 0 : }
1203 0 : case ElementType::HARMONY: {
1204 0 : Harmony* harmony = toHarmony(e);
1205 0 : if (harmony->isInFretBox()) {
1206 0 : FretDiagram* fretDiagram = toFretDiagram(harmony->ownershipParent());
1207 0 : FBox* fretBox = toFBox(fretDiagram->ownershipParent());
1208 0 : const ElementList& diagrams = fretBox->el();
1209 :
1210 0 : size_t index = muse::indexOf(diagrams, fretDiagram);
1211 0 : while (--index != muse::nidx) {
1212 0 : FretDiagram* fretDiagramI = toFretDiagram(diagrams[index]);
1213 0 : if (fretDiagramI->visible()) {
1214 0 : return fretDiagramI;
1215 : }
1216 : }
1217 :
1218 0 : return fretBox;
1219 0 : } else if (harmony->ownershipParent()->isFretDiagram()) {
1220 0 : EngravingItem* prev = harmony->getParentSeg()->prevAnnotation(toFretDiagram(harmony->ownershipParent()));
1221 0 : if (prev) {
1222 0 : return prev;
1223 : }
1224 :
1225 0 : e = toFretDiagram(harmony->ownershipParent());
1226 : }
1227 0 : break;
1228 : }
1229 0 : case ElementType::FRET_DIAGRAM: {
1230 0 : FretDiagram* fretDiagram = toFretDiagram(e);
1231 0 : EngravingItem* harmony = fretDiagram->harmony();
1232 0 : if (harmony) {
1233 0 : return harmony;
1234 : }
1235 0 : break;
1236 : }
1237 0 : default:
1238 0 : break;
1239 0 : }
1240 0 : e = e->layoutParent();
1241 : }
1242 0 : return Navigation::firstElement(score());
1243 : }
1244 :
1245 : //---------------------------------------------------------
1246 : // prevLyrics
1247 : // - find the lyric (if any) before this one (not including lines)
1248 : // - currently used to determine the first lyric of a melisma
1249 : //---------------------------------------------------------
1250 :
1251 9 : Lyrics* Navigation::lastLyricsInMeasure(const Segment* seg, const staff_idx_t staffIdx, const int no, const PlacementV& placement)
1252 : {
1253 15 : while (seg) {
1254 9 : const track_idx_t strack = staffIdx * VOICES;
1255 9 : const track_idx_t etrack = strack + VOICES;
1256 34 : for (track_idx_t track = strack; track < etrack; ++track) {
1257 28 : EngravingItem* el = seg->element(track);
1258 28 : Lyrics* prevLyrics = el && el->isChord() ? toChordRest(el)->lyrics(no, placement) : nullptr;
1259 28 : if (prevLyrics) {
1260 3 : return prevLyrics;
1261 : }
1262 : }
1263 6 : seg = seg->prev1(mu::engraving::SegmentType::ChordRest);
1264 : }
1265 6 : return nullptr;
1266 : }
1267 :
1268 48 : Lyrics* Navigation::prevLyrics(const Lyrics* lyrics)
1269 : {
1270 48 : Segment* seg = lyrics->ownershipParent() ? lyrics->segment() : nullptr;
1271 48 : if (!seg) {
1272 0 : return nullptr;
1273 : }
1274 101 : while ((seg = seg->prev1(mu::engraving::SegmentType::ChordRest))) {
1275 53 : const track_idx_t strack = lyrics->staffIdx() * VOICES;
1276 53 : const track_idx_t etrack = strack + VOICES;
1277 265 : for (track_idx_t track = strack; track < etrack; ++track) {
1278 212 : EngravingItem* el = seg->element(track);
1279 212 : Lyrics* prevLyrics = el && el->isChord() ? toChordRest(el)->lyrics(lyrics->verse(), lyrics->placement()) : nullptr;
1280 212 : if (prevLyrics) {
1281 0 : return prevLyrics;
1282 : }
1283 : }
1284 : }
1285 48 : return nullptr;
1286 : }
1287 :
1288 0 : Lyrics* Navigation::nextLyrics(const Lyrics* lyrics)
1289 : {
1290 0 : Segment* seg = lyrics->ownershipParent() ? lyrics->segment() : nullptr;
1291 0 : if (!seg) {
1292 0 : return nullptr;
1293 : }
1294 0 : Segment* nextSegment = seg;
1295 0 : while ((nextSegment = nextSegment->next1(mu::engraving::SegmentType::ChordRest))) {
1296 0 : const track_idx_t strack = lyrics->staffIdx() * VOICES;
1297 0 : const track_idx_t etrack = strack + VOICES;
1298 0 : for (track_idx_t track = strack; track < etrack; ++track) {
1299 0 : EngravingItem* el = nextSegment->element(track);
1300 0 : Lyrics* nextLyrics = el && el->isChord() ? toChordRest(el)->lyrics(lyrics->verse(), lyrics->placement()) : nullptr;
1301 0 : if (nextLyrics) {
1302 0 : return nextLyrics;
1303 : }
1304 : }
1305 : }
1306 0 : return nullptr;
1307 : }
1308 :
1309 : //---------------------------------------------------------
1310 : // move
1311 : // move current selection
1312 : //---------------------------------------------------------
1313 :
1314 0 : EngravingItem* Navigation::move(Score* score, const String& cmd)
1315 : {
1316 0 : ChordRest* cr { nullptr };
1317 0 : Box* box { nullptr };
1318 0 : if (score->noteEntryMode()) {
1319 : // if selection exists and is grace note, use it
1320 : // otherwise use chord/rest at input position
1321 : // also use it if we are moving to next chord
1322 : // to catch up with the cursor and not move the selection by 2 positions
1323 0 : cr = score->selection().cr();
1324 0 : if (cr && (cr->isGrace() || cmd == u"next-chord" || cmd == u"prev-chord")) {
1325 : } else {
1326 0 : cr = score->inputState().cr();
1327 : }
1328 0 : } else if (score->selection().activeCR()) {
1329 0 : cr = score->selection().activeCR();
1330 : } else {
1331 0 : cr = score->selection().lastChordRest();
1332 : }
1333 :
1334 : // no chord/rest found? look for another type of element,
1335 : // but commands [empty-trailing-measure] and [top-staff] don't
1336 : // necessarily need an active selection for appropriate functioning
1337 0 : if (!cr && cmd != u"empty-trailing-measure" && cmd != u"top-staff") {
1338 0 : if (score->selection().elements().empty()) {
1339 0 : return 0;
1340 : }
1341 : // retrieve last element of section list
1342 0 : EngravingItem* el = score->selection().elements().back();
1343 0 : EngravingItem* trg = nullptr;
1344 :
1345 : // get parent of element and process accordingly:
1346 : // trg is the element to select on "next-chord" cmd
1347 : // cr is the ChordRest to move from on other cmd's
1348 0 : track_idx_t track = el->track(); // keep note of element track
1349 0 : if (!el->isBox()) {
1350 0 : el = el->ownershipParentItem();
1351 : }
1352 : // element with no parent (eg, a newly-added line) - no way to find context
1353 0 : if (!el) {
1354 0 : return 0;
1355 : }
1356 0 : switch (el->type()) {
1357 0 : case ElementType::NOTE: // a note is a valid target
1358 0 : trg = el;
1359 0 : cr = toNote(el)->chord();
1360 0 : break;
1361 0 : case ElementType::CHORD: // a chord or a rest are valid targets
1362 : case ElementType::REST:
1363 : case ElementType::MMREST:
1364 0 : trg = el;
1365 0 : cr = toChordRest(trg);
1366 0 : break;
1367 0 : case ElementType::SEGMENT: { // from segment go to top chordrest in segment
1368 0 : Segment* seg = toSegment(el);
1369 : // if segment is not chord/rest or grace, move to next chord/rest or grace segment
1370 0 : if (!seg->isChordRest()) {
1371 0 : seg = seg->next1(SegmentType::ChordRest);
1372 0 : if (!seg) { // if none found, return failure
1373 0 : return 0;
1374 : }
1375 : }
1376 : // segment for sure contains chords/rests,
1377 0 : size_t size = seg->elist().size();
1378 : // if segment has a chord/rest in original element track, use it
1379 0 : if (track < size && seg->element(track)) {
1380 0 : trg = seg->element(track);
1381 0 : cr = toChordRest(trg);
1382 0 : break;
1383 : }
1384 : // if not, get topmost chord/rest
1385 0 : for (size_t i = 0; i < size; i++) {
1386 0 : if (seg->element(i)) {
1387 0 : trg = seg->element(i);
1388 0 : cr = toChordRest(trg);
1389 0 : break;
1390 : }
1391 : }
1392 0 : break;
1393 : }
1394 0 : case ElementType::HBOX: // fallthrough
1395 : case ElementType::VBOX: // fallthrough
1396 : case ElementType::TBOX:
1397 : case ElementType::FBOX:
1398 0 : box = toBox(el);
1399 0 : break;
1400 0 : default: // on anything else, return failure
1401 0 : return 0;
1402 : }
1403 :
1404 : // if something found and command is forward, the element found is the destination
1405 0 : if (trg && cmd == u"next-chord") {
1406 : // if chord, go to topmost note
1407 0 : if (trg->isChord()) {
1408 0 : trg = toChord(trg)->upNote();
1409 : }
1410 0 : score->setPlayNote(true);
1411 0 : score->select(trg, SelectType::SINGLE, 0);
1412 0 : return trg;
1413 : }
1414 : // if no chordrest and no box (frame) found, do nothing
1415 0 : if (!cr && !box) {
1416 0 : return 0;
1417 : }
1418 : // if some chordrest found, continue with default processing
1419 : }
1420 :
1421 0 : EngravingItem* el = nullptr;
1422 0 : Segment* ois = score->noteEntryMode() ? score->inputState().segment() : nullptr;
1423 0 : Measure* oim = ois ? ois->measure() : nullptr;
1424 :
1425 0 : if (cmd == u"next-chord" && cr) {
1426 : // note input cursor
1427 0 : if (score->noteEntryMode()) {
1428 0 : score->inputState().moveToNextInputPos();
1429 : }
1430 :
1431 : // selection "cursor"
1432 : // find next chordrest, which might be a grace note
1433 : // this may override note input cursor
1434 0 : el = Navigation::nextChordRest(cr);
1435 :
1436 : // Skip gap rests if we're not in note entry mode...
1437 0 : while (!score->noteEntryMode() && el && el->isRest() && toRest(el)->isGap()) {
1438 0 : el = Navigation::nextChordRest(toChordRest(el));
1439 : }
1440 0 : if (el && score->noteEntryMode()) {
1441 : // do not use if not in original or new measure (don't skip measures)
1442 0 : Measure* m = toChordRest(el)->measure();
1443 0 : Segment* nis = score->inputState().segment();
1444 0 : Measure* nim = nis ? nis->measure() : nullptr;
1445 0 : if (m != oim && m != nim) {
1446 0 : el = cr;
1447 : }
1448 : // do not use if new input segment is current cr
1449 : // this means input cursor just caught up to current selection
1450 0 : else if (cr && nis == cr->segment()) {
1451 0 : el = cr;
1452 : }
1453 0 : } else if (!el) {
1454 0 : if (score->noteEntryMode()) {
1455 0 : score->inputState().setBeyondScore(true);
1456 : }
1457 0 : el = cr;
1458 : }
1459 0 : } else if (cmd == u"prev-chord" && cr) {
1460 : // note input cursor
1461 0 : if (score->noteEntryMode()) {
1462 0 : if (score->inputState().beyondScore()) {
1463 0 : score->inputState().setBeyondScore(false);
1464 0 : } else if (score->inputState().segment()) {
1465 0 : Measure* m = score->inputState().segment()->measure();
1466 0 : Segment* s = score->inputState().segment()->prev1(SegmentType::ChordRest);
1467 0 : track_idx_t track = score->inputState().track();
1468 0 : for (; s; s = s->prev1(SegmentType::ChordRest)) {
1469 0 : if (s->element(track) || (s->measure() != m && s->rtick().isZero())) {
1470 0 : if (s->element(track)) {
1471 0 : if (s->element(track)->isRest() && toRest(s->element(track))->isGap()) {
1472 0 : continue;
1473 : }
1474 : }
1475 0 : break;
1476 : }
1477 : }
1478 0 : score->inputState().moveInputPos(s);
1479 : }
1480 : }
1481 :
1482 : // selection "cursor"
1483 : // find previous chordrest, which might be a grace note
1484 : // this may override note input cursor
1485 0 : el = Navigation::prevChordRest(cr);
1486 :
1487 : // Skip gap rests if we're not in note entry mode...
1488 0 : while (!score->noteEntryMode() && el && el->isRest() && toRest(el)->isGap()) {
1489 0 : el = Navigation::prevChordRest(toChordRest(el));
1490 : }
1491 0 : if (el && score->noteEntryMode()) {
1492 : // do not use if not in original or new measure (don't skip measures)
1493 0 : Measure* m = toChordRest(el)->measure();
1494 0 : Segment* nis = score->inputState().segment();
1495 0 : Measure* nim = nis ? nis->measure() : nullptr;
1496 0 : if (m != oim && m != nim) {
1497 0 : el = cr;
1498 : }
1499 : // do not use if new input segment is current cr
1500 : // this means input cursor just caught up to current selection
1501 0 : else if (cr && nis == cr->segment()) {
1502 0 : el = cr;
1503 : }
1504 0 : } else if (!el) {
1505 0 : el = cr;
1506 : }
1507 0 : } else if (cmd == u"next-measure") {
1508 0 : if (box && box->nextMeasure() && box->nextMeasure()->first()) {
1509 0 : el = box->nextMeasure()->first()->nextChordRest(0, false);
1510 : }
1511 0 : if (cr) {
1512 0 : if (score->noteEntryMode() && cr->measure() == score->lastMeasure()) {
1513 0 : score->inputState().setBeyondScore(true);
1514 0 : el = score->lastMeasure()->lastChordRest(cr->track());
1515 : } else {
1516 0 : el = Navigation::nextMeasure(score, cr);
1517 : }
1518 : }
1519 0 : if (el && score->noteEntryMode()) {
1520 0 : score->inputState().moveInputPos(el);
1521 : }
1522 0 : } else if (cmd == u"prev-measure") {
1523 0 : if (box && box->prevMeasure() && box->prevMeasure()->first()) {
1524 0 : el = box->prevMeasure()->first()->nextChordRest(0, false);
1525 : }
1526 0 : if (score->noteEntryMode() && score->inputState().beyondScore()) {
1527 0 : score->inputState().setBeyondScore(false);
1528 0 : el = score->lastMeasure()->first()->nextChordRest(score->inputState().track(), false);
1529 0 : } else if (cr) {
1530 0 : el = Navigation::prevMeasure(score, cr);
1531 : }
1532 0 : if (el && score->noteEntryMode()) {
1533 0 : score->inputState().moveInputPos(el);
1534 : }
1535 0 : } else if (cmd == u"next-system" && cr) {
1536 0 : if (score->noteEntryMode() && cr->measure()->system()->endTick() == score->endTick()) {
1537 0 : score->inputState().setBeyondScore(true);
1538 0 : el = score->lastMeasure()->lastChordRest(cr->track());
1539 : } else {
1540 0 : el = score->cmdNextPrevSystem(cr, true);
1541 : }
1542 0 : if (el && score->noteEntryMode()) {
1543 0 : score->inputState().moveInputPos(el);
1544 : }
1545 0 : } else if (cmd == u"prev-system" && cr) {
1546 0 : if (score->noteEntryMode() && score->inputState().beyondScore()) {
1547 0 : score->inputState().setBeyondScore(false);
1548 : }
1549 0 : el = score->cmdNextPrevSystem(cr, false);
1550 0 : if (score->noteEntryMode()) {
1551 0 : score->inputState().moveInputPos(el);
1552 : }
1553 0 : } else if (cmd == u"next-frame") {
1554 0 : auto measureBase = cr ? cr->measure()->findMeasureBase() : box->findMeasureBase();
1555 0 : el = measureBase ? score->cmdNextPrevFrame(measureBase, true) : nullptr;
1556 0 : } else if (cmd == u"prev-frame") {
1557 0 : auto measureBase = cr ? cr->measure()->findMeasureBase() : box->findMeasureBase();
1558 0 : el = measureBase ? score->cmdNextPrevFrame(measureBase, false) : nullptr;
1559 0 : } else if (cmd == u"next-section") {
1560 0 : if (!(el = box)) {
1561 0 : el = cr;
1562 : }
1563 0 : el = score->cmdNextPrevSection(el, true);
1564 0 : } else if (cmd == u"prev-section") {
1565 0 : if (!(el = box)) {
1566 0 : el = cr;
1567 : }
1568 0 : el = score->cmdNextPrevSection(el, false);
1569 0 : } else if (cmd == u"next-track" && cr) {
1570 0 : el = score->nextTrack(cr);
1571 0 : if (score->noteEntryMode()) {
1572 0 : score->inputState().moveInputPos(el);
1573 : }
1574 0 : } else if (cmd == u"prev-track" && cr) {
1575 0 : el = score->prevTrack(cr);
1576 0 : if (score->noteEntryMode()) {
1577 0 : score->inputState().moveInputPos(el);
1578 : }
1579 0 : } else if (cmd == u"top-staff") {
1580 0 : el = cr ? Navigation::topStaff(score, cr) : Navigation::topStaff(score);
1581 0 : if (score->noteEntryMode()) {
1582 0 : score->inputState().moveInputPos(el);
1583 : }
1584 0 : } else if (cmd == u"empty-trailing-measure") {
1585 0 : const Measure* ftm = nullptr;
1586 0 : if (!cr) {
1587 0 : ftm = score->firstTrailingMeasure() ? score->firstTrailingMeasure() : score->lastMeasure();
1588 : } else {
1589 0 : ftm = score->firstTrailingMeasure(&cr) ? score->firstTrailingMeasure(&cr) : score->lastMeasure();
1590 : }
1591 0 : if (ftm) {
1592 0 : if (score->style().styleB(Sid::createMultiMeasureRests) && ftm->hasMMRest()) {
1593 0 : ftm = ftm->coveringMMRestOrThis();
1594 : }
1595 0 : el = !cr ? ftm->first()->nextChordRest(0, false) : ftm->first()->nextChordRest(trackZeroVoice(cr->track()), false);
1596 : }
1597 : // Note: Due to the nature of this command as being preparatory for input,
1598 : // Note-Entry is activated from within ScoreView::cmd()
1599 0 : score->inputState().moveInputPos(el);
1600 : }
1601 :
1602 0 : if (el) {
1603 0 : if (el->isChord()) {
1604 0 : el = toChord(el)->upNote(); // originally downNote
1605 : }
1606 0 : score->setPlayNote(true);
1607 0 : if (score->noteEntryMode()) {
1608 0 : if (score->inputState().beyondScore()) {
1609 : // don't select el when cursor is beyond score
1610 0 : score->deselectAll();
1611 0 : } else if (score->inputState().cr() || !el->selected()) {
1612 : // if cursor moved into a gap, selection cannot follow
1613 : // only select & play el if it was not already selected (does not normally happen)
1614 0 : score->select(el, SelectType::SINGLE, 0);
1615 : } else {
1616 0 : score->setPlayNote(false);
1617 : }
1618 0 : for (MuseScoreView* view : score->getViewer()) {
1619 0 : view->moveCursor();
1620 : }
1621 : } else {
1622 0 : score->select(el, SelectType::SINGLE, 0);
1623 : }
1624 : }
1625 0 : return el;
1626 : }
1627 :
1628 : //---------------------------------------------------------
1629 : // selectMove
1630 : //---------------------------------------------------------
1631 :
1632 0 : EngravingItem* Navigation::selectMove(Score* score, const String& cmd)
1633 : {
1634 : ChordRest* cr;
1635 0 : if (score->selection().activeCR()) {
1636 0 : cr = score->selection().activeCR();
1637 : } else {
1638 0 : cr = score->selection().lastChordRest();
1639 : }
1640 0 : if (!cr && score->noteEntryMode()) {
1641 0 : cr = score->inputState().cr();
1642 : }
1643 0 : if (!cr) {
1644 0 : return 0;
1645 : }
1646 :
1647 0 : ChordRest* el = nullptr;
1648 0 : ChordRestNavigateOptions options;
1649 0 : options.skipGrace = true;
1650 0 : options.skipMeasureRepeatRests = false;
1651 0 : if (cmd == u"select-next-chord") {
1652 0 : el = Navigation::nextChordRest(cr, options);
1653 0 : } else if (cmd == u"select-prev-chord") {
1654 0 : el = Navigation::prevChordRest(cr, options);
1655 0 : } else if (cmd == u"select-next-measure") {
1656 0 : el = Navigation::nextMeasure(score, cr, true, true);
1657 0 : } else if (cmd == u"select-prev-measure") {
1658 0 : el = Navigation::prevMeasure(score, cr, true);
1659 0 : } else if (cmd == u"select-begin-line") {
1660 0 : Measure* measure = cr->segment()->measure()->system()->firstMeasure();
1661 0 : if (!measure) {
1662 0 : return 0;
1663 : }
1664 0 : el = measure->first()->nextChordRest(cr->track());
1665 0 : } else if (cmd == u"select-end-line") {
1666 0 : Measure* measure = cr->segment()->measure()->system()->lastMeasure();
1667 0 : if (!measure) {
1668 0 : return 0;
1669 : }
1670 0 : el = measure->last()->nextChordRest(cr->track(), true);
1671 0 : } else if (cmd == u"select-begin-score") {
1672 0 : Measure* measure = score->firstMeasureMM();
1673 0 : if (!measure) {
1674 0 : return 0;
1675 : }
1676 0 : el = measure->first()->nextChordRest(cr->track());
1677 0 : } else if (cmd == u"select-end-score") {
1678 0 : Measure* measure = score->lastMeasureMM();
1679 0 : if (!measure) {
1680 0 : return 0;
1681 : }
1682 0 : el = measure->last()->nextChordRest(cr->track(), true);
1683 0 : } else if (cmd == u"select-staff-above") {
1684 0 : el = Navigation::upStaff(cr);
1685 0 : } else if (cmd == u"select-staff-below") {
1686 0 : el = Navigation::downStaff(score, cr);
1687 : }
1688 0 : if (el) {
1689 0 : score->select(el, SelectType::RANGE, el->staffIdx());
1690 : }
1691 0 : return el;
1692 : }
1693 : }
|