1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2002-2013 Werner Schweer
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License version 2
9 //  as published by the Free Software Foundation and appearing in
10 //  the file LICENCE.GPL
11 //=============================================================================
12 
13 /**
14  \file
15  Handling of several GUI commands.
16 */
17 
18 #include <assert.h>
19 
20 #include "types.h"
21 #include "musescoreCore.h"
22 #include "score.h"
23 #include "utils.h"
24 #include "key.h"
25 #include "clef.h"
26 #include "navigate.h"
27 #include "slur.h"
28 #include "tie.h"
29 #include "note.h"
30 #include "rest.h"
31 #include "chord.h"
32 #include "text.h"
33 #include "sig.h"
34 #include "staff.h"
35 #include "part.h"
36 #include "style.h"
37 #include "page.h"
38 #include "barline.h"
39 #include "tuplet.h"
40 #include "xml.h"
41 #include "ottava.h"
42 #include "trill.h"
43 #include "pedal.h"
44 #include "hairpin.h"
45 #include "textline.h"
46 #include "keysig.h"
47 #include "volta.h"
48 #include "dynamic.h"
49 #include "box.h"
50 #include "harmony.h"
51 #include "system.h"
52 #include "stafftext.h"
53 #include "articulation.h"
54 #include "layoutbreak.h"
55 #include "drumset.h"
56 #include "beam.h"
57 #include "lyrics.h"
58 #include "pitchspelling.h"
59 #include "measure.h"
60 #include "tempo.h"
61 #include "undo.h"
62 #include "timesig.h"
63 #include "repeat.h"
64 #include "tempotext.h"
65 #include "noteevent.h"
66 #include "breath.h"
67 #include "stringdata.h"
68 #include "stafftype.h"
69 #include "segment.h"
70 #include "chordlist.h"
71 #include "mscore.h"
72 #include "accidental.h"
73 #include "sequencer.h"
74 #include "tremolo.h"
75 #include "rehearsalmark.h"
76 #include "sym.h"
77 
78 namespace Ms {
79 
80 //---------------------------------------------------------
81 //   reset
82 //---------------------------------------------------------
83 
reset()84 void CmdState::reset()
85       {
86       layoutFlags         = LayoutFlag::NO_FLAGS;
87       _updateMode         = UpdateMode::DoNothing;
88       _startTick          = Fraction(-1,1);
89       _endTick            = Fraction(-1,1);
90 
91       _startStaff = -1;
92       _endStaff = -1;
93       _el = nullptr;
94       _oneElement = true;
95       _mb = nullptr;
96       _oneMeasureBase = true;
97       _locked = false;
98       }
99 
100 //---------------------------------------------------------
101 //   setTick
102 //---------------------------------------------------------
103 
setTick(const Fraction & t)104 void CmdState::setTick(const Fraction& t)
105       {
106       if (_locked)
107             return;
108 
109       if (_startTick == Fraction(-1,1) || t < _startTick)
110             _startTick = t;
111       if (_endTick == Fraction(-1,1) || t > _endTick)
112             _endTick = t;
113       setUpdateMode(UpdateMode::Layout);
114       }
115 
116 //---------------------------------------------------------
117 //   setStaff
118 //---------------------------------------------------------
119 
setStaff(int st)120 void CmdState::setStaff(int st)
121       {
122       Q_ASSERT(st > -2);
123       if (_locked || st == -1)
124             return;
125 
126       if (_startStaff == -1 || st < _startStaff)
127             _startStaff = st;
128       if (_endStaff == -1 || st > _endStaff)
129             _endStaff = st;
130       }
131 
132 //---------------------------------------------------------
133 //   setMeasureBase
134 //---------------------------------------------------------
135 
setMeasureBase(const MeasureBase * mb)136 void CmdState::setMeasureBase(const MeasureBase* mb)
137       {
138       if (!mb || _mb == mb || _locked)
139             return;
140 
141       _oneMeasureBase = !_mb;
142       _mb = mb;
143       }
144 
145 //---------------------------------------------------------
146 //   setElement
147 //---------------------------------------------------------
148 
setElement(const Element * e)149 void CmdState::setElement(const Element* e)
150       {
151       if (!e || _el == e || _locked)
152             return;
153 
154       _oneElement = !_el;
155       _el = e;
156 
157       if (_oneMeasureBase)
158             setMeasureBase(e->findMeasureBase());
159       }
160 
161 //---------------------------------------------------------
162 //   unsetElement
163 //---------------------------------------------------------
164 
unsetElement(const Element * e)165 void CmdState::unsetElement(const Element* e)
166       {
167       if (_el == e)
168             _el = nullptr;
169       if (_mb == e)
170             _mb = nullptr;
171       }
172 
173 //---------------------------------------------------------
174 //   element
175 //---------------------------------------------------------
176 
element() const177 const Element* CmdState::element() const
178       {
179       if (_oneElement)
180             return _el;
181       if (_oneMeasureBase)
182             return _mb;
183       return nullptr;
184       }
185 
186 //---------------------------------------------------------
187 //   setUpdateMode
188 //---------------------------------------------------------
189 
_setUpdateMode(UpdateMode m)190 void CmdState::_setUpdateMode(UpdateMode m)
191       {
192       _updateMode = m;
193       }
194 
setUpdateMode(UpdateMode m)195 void CmdState::setUpdateMode(UpdateMode m)
196       {
197       if (int(m) > int(_updateMode))
198             _setUpdateMode(m);
199       }
200 
201 //---------------------------------------------------------
202 //   startCmd
203 ///   Start a GUI command by clearing the redraw area
204 ///   and starting a user-visible undo.
205 //---------------------------------------------------------
206 
startCmd()207 void Score::startCmd()
208       {
209       if (MScore::debugMode)
210             qDebug("===startCmd()");
211 
212       cmdState().reset();
213 
214       // Start collecting low-level undo operations for a
215       // user-visible undo action.
216       if (undoStack()->active()) {
217             qDebug("Score::startCmd(): cmd already active");
218             return;
219             }
220       undoStack()->beginMacro(this);
221       }
222 
223 //---------------------------------------------------------
224 //   undoRedo
225 //---------------------------------------------------------
226 
undoRedo(bool undo,EditData * ed)227 void Score::undoRedo(bool undo, EditData* ed)
228       {
229       if (readOnly())
230             return;
231       cmdState().reset();
232       if (undo)
233             undoStack()->undo(ed);
234       else
235             undoStack()->redo(ed);
236       update(false);
237       masterScore()->setPlaylistDirty();  // TODO: flag all individual operations
238       updateSelection();
239       }
240 
241 //---------------------------------------------------------
242 //   endCmd
243 ///   End a GUI command by (if \a undo) ending a user-visble undo
244 ///   and (always) updating the redraw area.
245 //---------------------------------------------------------
246 
endCmd(bool rollback)247 void Score::endCmd(bool rollback)
248       {
249       if (!undoStack()->active()) {
250             qDebug("Score::endCmd(): no cmd active");
251             update();
252             return;
253             }
254       if (readOnly() || MScore::_error != MS_NO_ERROR)
255             rollback = true;
256 
257       if (rollback)
258             undoStack()->current()->unwind();
259 
260       update(false);
261 
262       if (MScore::debugMode)
263             qDebug("===endCmd() %d", undoStack()->current()->childCount());
264       const bool noUndo = undoStack()->current()->empty();       // nothing to undo?
265       undoStack()->endMacro(noUndo);
266 
267       if (dirty()) {
268             masterScore()->setPlaylistDirty();  // TODO: flag individual operations
269             masterScore()->setAutosaveDirty(true);
270             }
271       MuseScoreCore::mscoreCore->endCmd();
272       cmdState().reset();
273       }
274 
275 #ifndef NDEBUG
276 //---------------------------------------------------------
277 //   CmdState::dump
278 //---------------------------------------------------------
279 
dump()280 void CmdState::dump()
281       {
282       qDebug("CmdState: mode %d %d-%d", int(_updateMode), _startTick.ticks(), _endTick.ticks());
283       // bool _excerptsChanged     { false };
284       // bool _instrumentsChanged  { false };
285 
286       }
287 #endif
288 
289 //---------------------------------------------------------
290 //   update
291 //    layout & update
292 //---------------------------------------------------------
293 
update(bool resetCmdState)294 void Score::update(bool resetCmdState)
295       {
296       bool updateAll = false;
297       for (MasterScore* ms : *movements()) {
298             CmdState& cs = ms->cmdState();
299             ms->deletePostponed();
300             if (cs.layoutRange()) {
301                   for (Score* s : ms->scoreList())
302                         s->doLayoutRange(cs.startTick(), cs.endTick());
303                   updateAll = true;
304                   }
305             }
306 
307       for (MasterScore* ms : *movements()) {
308             CmdState& cs = ms->cmdState();
309             if (updateAll || cs.updateAll()) {
310                   for (Score* s : scoreList()) {
311                         for (MuseScoreView* v : qAsConst(s->viewer)) {
312                               v->updateAll();
313                               }
314                         }
315                   }
316             else if (cs.updateRange()) {
317                   // updateRange updates only current score
318                   qreal d = spatium() * .5;
319                   _updateState.refresh.adjust(-d, -d, 2 * d, 2 * d);
320                   for (MuseScoreView* v : qAsConst(viewer))
321                         v->dataChanged(_updateState.refresh);
322                   _updateState.refresh = QRectF();
323                   }
324             const InputState& is = inputState();
325             if (is.noteEntryMode() && is.segment()) {
326                   setPlayPos(is.segment()->tick());
327                   }
328             if (playlistDirty()) {
329                   for (Score* s : scoreList())
330                         emit s->playlistChanged();
331                   masterScore()->setPlaylistClean();
332                   }
333             if (resetCmdState)
334                   cs.reset();
335             }
336       if (_selection.isRange() && !_selection.isLocked())
337             _selection.updateSelectedElements();
338       }
339 
340 //---------------------------------------------------------
341 //   deletePostponed
342 //---------------------------------------------------------
343 
deletePostponed()344 void Score::deletePostponed()
345       {
346       for (ScoreElement* e : qAsConst(_updateState._deleteList)) {
347             if (e->isSystem()) {
348                   System* s = toSystem(e);
349                   for (SpannerSegment* ss : s->spannerSegments()) {
350                         if (ss->system() == s)
351                               ss->setSystem(0);
352                         }
353                   }
354             }
355       qDeleteAll(_updateState._deleteList);
356       _updateState._deleteList.clear();
357       }
358 
359 //---------------------------------------------------------
360 //   cmdAddSpanner
361 //   drop VOLTA, OTTAVA, TRILL, PEDAL, DYNAMIC
362 //        HAIRPIN, LET_RING, VIBRATO and TEXTLINE
363 //---------------------------------------------------------
364 
cmdAddSpanner(Spanner * spanner,const QPointF & pos,bool firstStaffOnly)365 void Score::cmdAddSpanner(Spanner* spanner, const QPointF& pos, bool firstStaffOnly)
366       {
367       int staffIdx;
368       Segment* segment;
369       MeasureBase* mb = pos2measure(pos, &staffIdx, 0, &segment, 0);
370       if (firstStaffOnly)
371             staffIdx = 0;
372       // ignore if we do not have a measure
373       if (mb == 0 || mb->type() != ElementType::MEASURE) {
374             qDebug("cmdAddSpanner: cannot put object here");
375             delete spanner;
376             return;
377             }
378 
379       // all spanners live in voice 0 (except slurs/ties)
380       int track = staffIdx == -1 ? -1 : staffIdx * VOICES;
381 
382       spanner->setTrack(track);
383       spanner->setTrack2(track);
384 
385       if (spanner->anchor() == Spanner::Anchor::SEGMENT) {
386             spanner->setTick(segment->tick());
387             Fraction lastTick = lastMeasure()->tick() + lastMeasure()->ticks();
388             Fraction tick2 = qMin(segment->measure()->tick() + segment->measure()->ticks(), lastTick);
389             spanner->setTick2(tick2);
390             }
391       else {      // Anchor::MEASURE, Anchor::CHORD, Anchor::NOTE
392             Measure* m = toMeasure(mb);
393             QRectF b(m->canvasBoundingRect());
394 
395             if (pos.x() >= (b.x() + b.width() * .5) && m != lastMeasureMM() && m->nextMeasure()->system() == m->system())
396                   m = m->nextMeasure();
397             spanner->setTick(m->tick());
398             spanner->setTick2(m->endTick());
399             }
400       spanner->eraseSpannerSegments();
401 
402       undoAddElement(spanner);
403       select(spanner, SelectType::SINGLE, 0);
404       }
405 
406 //---------------------------------------------------------
407 //   cmdAddSpanner
408 //    used when applying a spanner to a selection
409 //---------------------------------------------------------
410 
cmdAddSpanner(Spanner * spanner,int staffIdx,Segment * startSegment,Segment * endSegment)411 void Score::cmdAddSpanner(Spanner* spanner, int staffIdx, Segment* startSegment, Segment* endSegment)
412       {
413       int track = staffIdx * VOICES;
414       spanner->setTrack(track);
415       spanner->setTrack2(track);
416       for (auto ss : spanner->spannerSegments())
417             ss->setTrack(track);
418       spanner->setTick(startSegment->tick());
419       Fraction tick2;
420       if (!endSegment)
421             tick2 = lastSegment()->tick();
422       else if (endSegment == startSegment)
423             tick2 = startSegment->measure()->last()->tick();
424       else
425             tick2 = endSegment->tick();
426       spanner->setTick2(tick2);
427 #if 0 // TODO
428       TextLine* tl = toTextLine(spanner);
429       if (tl) {
430             StyledPropertyListIdx st;
431             Text* t;
432             // begin
433             t = tl->beginTextElement();
434             if (t) {
435                   st = t->textStyleType();
436                   if (st >= StyledPropertyListIdx::DEFAULT)
437                         t->textStyle().restyle(MScore::baseStyle().textStyle(st), textStyle(st));
438                   }
439             // continue
440             t = tl->continueTextElement();
441             if (t) {
442                   st = t->textStyleType();
443                   if (st >= StyledPropertyListIdx::DEFAULT)
444                         t->textStyle().restyle(MScore::baseStyle().textStyle(st), textStyle(st));
445                   }
446             // end
447             t = tl->endTextElement();
448             if (t) {
449                   st = t->textStyleType();
450                   if (st >= StyledPropertyListIdx::DEFAULT)
451                         t->textStyle().restyle(MScore::baseStyle().textStyle(st), textStyle(st));
452                   }
453             }
454 #endif
455       undoAddElement(spanner);
456       }
457 
458 //---------------------------------------------------------
459 //   expandVoice
460 //    fills gaps in voice with rests,
461 //    from previous cr (or beginning of measure) to next cr (or end of measure)
462 //---------------------------------------------------------
463 
expandVoice(Segment * s,int track)464 void Score::expandVoice(Segment* s, int track)
465       {
466       if (!s) {
467             qDebug("expand voice: no segment");
468             return;
469             }
470       if (s->element(track))
471             return;
472 
473       // find previous segment with cr in this track
474       Segment* ps;
475       for (ps = s; ps; ps = ps->prev(SegmentType::ChordRest)) {
476             if (ps->element(track))
477                   break;
478             }
479       if (ps) {
480             ChordRest* cr = toChordRest(ps->element(track));
481             Fraction tick = cr->tick() + cr->actualTicks();
482             if (tick > s->tick()) {
483                   // previous cr extends past current segment
484                   qDebug("expandVoice: cannot insert element here");
485                   return;
486                   }
487             if (cr->isChord()) {
488                   // previous cr ends on or before current segment
489                   // for chords, move ps to just after cr ends
490                   // so we can fill any gap that might exist
491                   // but don't move ps if previous cr is a rest
492                   // this will be combined with any new rests needed to fill up to s->tick() below
493                   ps = ps->measure()->undoGetSegment(SegmentType::ChordRest, tick);
494                   }
495             }
496       //
497       // fill up to s->tick() with rests
498       //
499       Measure* m = s->measure();
500       Fraction stick  = ps ?  ps->tick() : m->tick();
501       Fraction ticks  = s->tick() - stick;
502       if (ticks.isNotZero())
503             setRest(stick, track, ticks, false, 0);
504 
505       //
506       // fill from s->tick() until next chord/rest in measure
507       //
508       Segment* ns;
509       for (ns = s->next(SegmentType::ChordRest); ns; ns = ns->next(SegmentType::ChordRest)) {
510             if (ns->element(track))
511                   break;
512             }
513       ticks  = ns ? (ns->tick() - s->tick()) : (m->ticks() - s->rtick());
514       if (ticks == m->ticks())
515             addRest(s, track, TDuration(TDuration::DurationType::V_MEASURE), 0);
516       else
517             setRest(s->tick(), track, ticks, false, 0);
518       }
519 
expandVoice()520 void Score::expandVoice()
521       {
522       Segment* s = _is.segment();
523       int track  = _is.track();
524       expandVoice(s, track);
525       }
526 
527 //---------------------------------------------------------
528 //   cmdAddInterval
529 //---------------------------------------------------------
530 
cmdAddInterval(int val,const std::vector<Note * > & nl)531 void Score::cmdAddInterval(int val, const std::vector<Note*>& nl)
532       {
533       startCmd();
534       for (Note* on : nl) {
535             Note* note = new Note(this);
536             Chord* chord = on->chord();
537             note->setParent(chord);
538             note->setTrack(chord->track());
539             int valTmp = val < 0 ? val+1 : val-1;
540 
541             int npitch;
542             int ntpc1;
543             int ntpc2;
544             bool accidental = _is.noteEntryMode() && _is.accidentalType() != AccidentalType::NONE;
545             bool forceAccidental = false;
546             if (abs(valTmp) != 7 || accidental) {
547                   int line      = on->line() - valTmp;
548                   Fraction tick      = chord->tick();
549                   Staff* estaff = staff(on->staffIdx() + chord->staffMove());
550                   ClefType clef = estaff->clef(tick);
551                   Key key       = estaff->key(tick);
552                   int ntpc;
553                   if (accidental) {
554                         AccidentalVal acci = Accidental::subtype2value(_is.accidentalType());
555                         int step = absStep(line, clef);
556                         int octave = step / 7;
557                         npitch = step2pitch(step) + octave * 12 + int(acci);
558                         forceAccidental = (npitch == line2pitch(line, clef, key));
559                         ntpc = step2tpc(step % 7, acci);
560                         }
561                   else {
562                         npitch = line2pitch(line, clef, key);
563                         ntpc = pitch2tpc(npitch, key, Prefer::NEAREST);
564                         }
565 
566                   Interval v = on->part()->instrument(tick)->transpose();
567                   if (v.isZero())
568                         ntpc1 = ntpc2 = ntpc;
569                   else {
570                         if (styleB(Sid::concertPitch)) {
571                               v.flip();
572                               ntpc1 = ntpc;
573                               ntpc2 = Ms::transposeTpc(ntpc, v, true);
574                               }
575                         else {
576                               npitch += v.chromatic;
577                               ntpc2 = ntpc;
578                               ntpc1 = Ms::transposeTpc(ntpc, v, true);
579                               }
580                         }
581                   }
582             else { //special case for octave
583                   Interval interval(7, 12);
584                   if (val < 0)
585                         interval.flip();
586                   transposeInterval(on->pitch(), on->tpc(), &npitch, &ntpc1, interval, false);
587                   ntpc1 = on->tpc1();
588                   ntpc2 = on->tpc2();
589                   }
590             if (npitch < 0 || npitch > 127) {
591                   delete note;
592                   endCmd();
593                   return;
594                   }
595             note->setPitch(npitch, ntpc1, ntpc2);
596 
597             undoAddElement(note);
598             if (forceAccidental) {
599                   Accidental* a = new Accidental(this);
600                   a->setAccidentalType(_is.accidentalType());
601                   a->setRole(AccidentalRole::USER);
602                   a->setParent(note);
603                   undoAddElement(a);
604                   }
605             setPlayNote(true);
606 
607             select(note, SelectType::SINGLE, 0);
608             }
609       if (_is.noteEntryMode())
610             _is.setAccidentalType(AccidentalType::NONE);
611       _is.moveToNextInputPos();
612       endCmd();
613       }
614 
615 //---------------------------------------------------------
616 //   setGraceNote
617 ///   Create a grace note in front of a normal note.
618 ///   \arg ch is the chord of the normal note
619 ///   \arg pitch is the pitch of the grace note
620 ///   \arg is the grace note type
621 ///   \len is the visual duration of the grace note (1/16 or 1/32)
622 //---------------------------------------------------------
623 
setGraceNote(Chord * ch,int pitch,NoteType type,int len)624 Note* Score::setGraceNote(Chord* ch, int pitch, NoteType type, int len)
625       {
626       Note* note = new Note(this);
627       Chord* chord = new Chord(this);
628 
629       // allow grace notes to be added to other grace notes
630       // by really adding to parent chord
631       if (ch->noteType() != NoteType::NORMAL)
632             ch = toChord(ch->parent());
633 
634       chord->setTrack(ch->track());
635       chord->setParent(ch);
636       chord->add(note);
637 
638       note->setPitch(pitch);
639       // find corresponding note within chord and use its tpc information
640       for (Note* n : ch->notes()) {
641             if (n->pitch() == pitch) {
642                   note->setTpc1(n->tpc1());
643                   note->setTpc2(n->tpc2());
644                   break;
645                   }
646             }
647       // note with same pitch not found, derive tpc from pitch / key
648       if (!tpcIsValid(note->tpc1()) || !tpcIsValid(note->tpc2()))
649             note->setTpcFromPitch();
650 
651       TDuration d;
652       d.setVal(len);
653       chord->setDurationType(d);
654       chord->setTicks(d.fraction());
655       chord->setNoteType(type);
656       chord->setMag(ch->staff()->mag(chord->tick()) * styleD(Sid::graceNoteMag));
657 
658       undoAddElement(chord);
659       select(note, SelectType::SINGLE, 0);
660       return note;
661       }
662 
663 //---------------------------------------------------------
664 //   createCRSequence
665 //    Create a rest or chord of len f.
666 //    If f is not a basic len, create several rests or
667 //    tied chords.
668 //
669 //    f     total len of ChordRest
670 //    cr    prototype CR
671 //    tick  start position in measure
672 //---------------------------------------------------------
673 
createCRSequence(const Fraction & f,ChordRest * cr,const Fraction & t)674 void Score::createCRSequence(const Fraction& f, ChordRest* cr, const Fraction& t)
675       {
676       Fraction tick(t);
677       Measure* measure = cr->measure();
678       ChordRest* ocr = 0;
679       for (TDuration d : toDurationList(f, true)) {
680             ChordRest* ncr = toChordRest(cr->clone());
681             ncr->setDurationType(d);
682             ncr->setTicks(d.fraction());
683             undoAddCR(ncr, measure, measure->tick() + tick);
684             if (cr->isChord() && ocr) {
685                   Chord* nc = toChord(ncr);
686                   Chord* oc = toChord(ocr);
687                   for (unsigned int i = 0; i < oc->notes().size(); ++i) {
688                         Note* on = oc->notes()[i];
689                         Note* nn = nc->notes()[i];
690                         Tie* tie = new Tie(this);
691                         tie->setStartNote(on);
692                         tie->setEndNote(nn);
693                         tie->setTick(tie->startNote()->tick());
694                         tie->setTick2(tie->endNote()->tick());
695                         tie->setTrack(cr->track());
696                         on->setTieFor(tie);
697                         nn->setTieBack(tie);
698                         undoAddElement(tie);
699                         }
700                   }
701 
702             tick += ncr->actualTicks();
703             ocr = ncr;
704             }
705       }
706 
707 //---------------------------------------------------------
708 //   setNoteRest
709 //    pitch == -1  -> set rest
710 //    return segment of last created note/rest
711 //---------------------------------------------------------
712 
setNoteRest(Segment * segment,int track,NoteVal nval,Fraction sd,Direction stemDirection,bool forceAccidental,bool rhythmic,InputState * externalInputState)713 Segment* Score::setNoteRest(Segment* segment, int track, NoteVal nval, Fraction sd, Direction stemDirection, bool forceAccidental, bool rhythmic, InputState* externalInputState)
714       {
715       Q_ASSERT(segment->segmentType() == SegmentType::ChordRest);
716       InputState& is = externalInputState ? (*externalInputState) : _is;
717 
718       bool isRest   = nval.pitch == -1;
719       Fraction tick = segment->tick();
720       Element* nr   = 0;
721       Tie* tie      = 0;
722       ChordRest* cr = toChordRest(segment->element(track));
723 
724       Measure* measure = 0;
725       for (;;) {
726             if (track % VOICES)
727                   expandVoice(segment, track);
728 
729             // the returned gap ends at the measure boundary or at tuplet end
730             Fraction dd = makeGap(segment, track, sd, cr ? cr->tuplet() : 0);
731 
732             if (dd.isZero()) {
733                   qDebug("cannot get gap at %d type: %d/%d", tick.ticks(), sd.numerator(),
734                      sd.denominator());
735                   break;
736                   }
737 
738             measure = segment->measure();
739             std::vector<TDuration> dl;
740             if (rhythmic)
741                   dl = toRhythmicDurationList(dd, isRest, segment->rtick(), sigmap()->timesig(tick).nominal(), measure, 1);
742             else
743                   dl = toDurationList(dd, true);
744             size_t n = dl.size();
745             for (size_t i = 0; i < n; ++i) {
746                   const TDuration& d = dl[i];
747                   ChordRest* ncr;
748                   Note* note = 0;
749                   Tie* addTie = 0;
750                   if (isRest) {
751                         nr = ncr = new Rest(this);
752                         nr->setTrack(track);
753                         ncr->setDurationType(d);
754                         ncr->setTicks(d == TDuration::DurationType::V_MEASURE ? measure->ticks() : d.fraction());
755                         }
756                   else {
757                         nr = note = new Note(this);
758 
759                         if (tie) {
760                               tie->setEndNote(note);
761                               tie->setTick2(tie->endNote()->tick());
762                               note->setTieBack(tie);
763                               addTie = tie;
764                               }
765                         Chord* chord = new Chord(this);
766                         chord->setTrack(track);
767                         chord->setDurationType(d);
768                         chord->setTicks(d.fraction());
769                         chord->setStemDirection(stemDirection);
770                         chord->add(note);
771                         note->setNval(nval, tick);
772                         if (forceAccidental) {
773                               int tpc = styleB(Sid::concertPitch) ? nval.tpc1 : nval.tpc2;
774                               AccidentalVal alter = tpc2alter(tpc);
775                               AccidentalType at = Accidental::value2subtype(alter);
776                               Accidental* a = new Accidental(this);
777                               a->setAccidentalType(at);
778                               a->setRole(AccidentalRole::USER);
779                               note->add(a);
780                               }
781                         ncr = chord;
782                         if (i+1 < n) {
783                               tie = new Tie(this);
784                               tie->setStartNote(note);
785                               tie->setTick(tie->startNote()->tick());
786                               tie->setTrack(track);
787                               note->setTieFor(tie);
788                               }
789                         }
790                   ncr->setTuplet(cr ? cr->tuplet() : 0);
791                   undoAddCR(ncr, measure, tick);
792                   if (addTie)
793                         undoAddElement(addTie);
794                   setPlayNote(true);
795                   segment = ncr->segment();
796                   tick += ncr->actualTicks();
797                   }
798 
799             sd -= dd;
800             if (sd.isZero())
801                   break;
802 
803             Segment* nseg = tick2segment(tick, false, SegmentType::ChordRest);
804             if (nseg == 0) {
805                   qDebug("reached end of score");
806                   break;
807                   }
808             segment = nseg;
809 
810             cr = toChordRest(segment->element(track));
811 
812             if (!cr) {
813                   if (track % VOICES)
814                         cr = addRest(segment, track, TDuration(TDuration::DurationType::V_MEASURE), 0);
815                   else {
816                         qDebug("no rest in voice 0");
817                         break;
818                         }
819                   }
820             //
821             //  Note does not fit on current measure, create Tie to
822             //  next part of note
823             if (!isRest) {
824                   tie = new Tie(this);
825                   tie->setStartNote((Note*)nr);
826                   tie->setTick(tie->startNote()->tick());
827                   tie->setTrack(nr->track());
828                   ((Note*)nr)->setTieFor(tie);
829                   }
830             }
831       if (tie)
832             connectTies();
833       if (nr) {
834             if (is.slur() && nr->type() == ElementType::NOTE) {
835                   // If the start element was the same as the end element when the slur was created,
836                   // the end grip of the front slur segment was given an x-offset of 3.0 * spatium().
837                   // Now that the slur is about to be given a new end element, this should be reset.
838                   if (is.slur()->endElement() == is.slur()->startElement())
839                         is.slur()->frontSegment()->reset();
840                   //
841                   // extend slur
842                   //
843                   Chord* chord = toNote(nr)->chord();
844                   is.slur()->undoChangeProperty(Pid::SPANNER_TICKS, chord->tick() - is.slur()->tick());
845                   for (ScoreElement* se : is.slur()->linkList()) {
846                         Slur* slur = toSlur(se);
847                         for (ScoreElement* ee : chord->linkList()) {
848                               Element* e = static_cast<Element*>(ee);
849                               if (e->score() == slur->score() && e->track() == slur->track2()) {
850                                     slur->score()->undo(new ChangeSpannerElements(slur, slur->startElement(), e));
851                                     break;
852                                     }
853                               }
854                         }
855                   }
856             if (externalInputState) {
857                   is.setTrack(nr->track());
858                   cr = nr->isRest() ? toChordRest(nr) : toNote(nr)->chord();
859                   is.setLastSegment(is.segment());
860                   is.setSegment(cr->segment());
861                   }
862             else {
863                   select(nr, SelectType::SINGLE, 0);
864                   }
865             }
866       return segment;
867       }
868 
869 //---------------------------------------------------------
870 //   makeGap
871 //    make time gap at tick by removing/shortening
872 //    chord/rest
873 //
874 //    if keepChord, the chord at tick is not removed
875 //
876 //    gap does not exceed measure or scope of tuplet
877 //
878 //    return size of actual gap
879 //---------------------------------------------------------
880 
makeGap(Segment * segment,int track,const Fraction & _sd,Tuplet * tuplet,bool keepChord)881 Fraction Score::makeGap(Segment* segment, int track, const Fraction& _sd, Tuplet* tuplet, bool keepChord)
882       {
883       Q_ASSERT(_sd.numerator());
884 
885       Measure* measure = segment->measure();
886       Fraction accumulated;
887       Fraction sd = _sd;
888 
889       //
890       // remember first segment which should
891       // not be deleted (it may contain other elements we want to preserve)
892       //
893       Segment* firstSegment = segment;
894       const Fraction firstSegmentEnd = firstSegment->tick() + firstSegment->ticks();
895       Fraction nextTick = segment->tick();
896 
897       for (Segment* seg = firstSegment; seg; seg = seg->next(SegmentType::ChordRest)) {
898             //
899             // voices != 0 may have gaps:
900             //
901             ChordRest* cr = toChordRest(seg->element(track));
902             if (!cr) {
903                   if (seg->tick() < nextTick)
904                         continue;
905                   Segment* seg1 = seg->next(SegmentType::ChordRest);
906                   Fraction tick2     = seg1 ? seg1->tick() : seg->measure()->tick() + seg->measure()->ticks();
907                   segment       = seg;
908                   Fraction td(tick2 - seg->tick());
909                   if (td > sd)
910                         td = sd;
911                   accumulated += td;
912                   sd -= td;
913                   if (sd.isZero())
914                         break;
915                   nextTick = tick2;
916                   continue;
917                   }
918             if (seg->tick() > nextTick) {
919                   // there was a gap
920                   Fraction td(seg->tick() - nextTick);
921                   if (td > sd)
922                         td = sd;
923                   accumulated += td;
924                   sd -= td;
925                   if (sd.isZero())
926                         break;
927                   }
928             //
929             // limit to tuplet level
930             //
931             if (tuplet) {
932                   bool tupletEnd = true;
933                   Tuplet* t = cr->tuplet();
934                   while (t) {
935                         if (cr->tuplet() == tuplet) {
936                               tupletEnd = false;
937                               break;
938                               }
939                         t = t->tuplet();
940                         }
941                   if (tupletEnd)
942                         break;
943                   }
944             Fraction td(cr->ticks());
945 
946             // remove tremolo between 2 notes, if present
947             if (cr->isChord()) {
948                   Chord* c = toChord(cr);
949                   if (c->tremolo()) {
950                         Tremolo* tremolo = c->tremolo();
951                         if (tremolo->twoNotes())
952                               undoRemoveElement(tremolo);
953                         }
954                   }
955             Tuplet* ltuplet = cr->tuplet();
956             if (ltuplet != tuplet) {
957                   //
958                   // Current location points to the start of a (nested)tuplet.
959                   // We have to remove the complete tuplet.
960 
961                   // get top level tuplet
962                   while (ltuplet->tuplet())
963                         ltuplet = ltuplet->tuplet();
964 
965                   // get last segment of tuplet, drilling down to leaf nodes as necessary
966                   Tuplet* t = ltuplet;
967                   while (t->elements().back()->isTuplet())
968                         t = toTuplet(t->elements().back());
969                   seg = toChordRest(t->elements().back())->segment();
970 
971                   // now delete the full tuplet
972                   td = ltuplet->ticks();
973                   cmdDeleteTuplet(ltuplet, false);
974                   tuplet = 0;
975                   }
976             else {
977                   if (seg != firstSegment || !keepChord)
978                         undoRemoveElement(cr);
979                   // even if there was a tuplet, we didn't remove it
980                   ltuplet = 0;
981                   }
982             Fraction timeStretch = cr->staff()->timeStretch(cr->tick());
983             nextTick += actualTicks(td, tuplet, timeStretch);
984             if (sd < td) {
985                   //
986                   // we removed too much
987                   //
988                   accumulated = _sd;
989                   Fraction rd = td - sd;
990                   Fraction tick = cr->tick() + actualTicks(sd, tuplet, timeStretch);
991 
992                   std::vector<TDuration> dList;
993                   if (tuplet || staff(track / VOICES)->isLocalTimeSignature(tick)) {
994                         dList = toDurationList(rd, false);
995                         std::reverse(dList.begin(), dList.end());
996                         }
997                   else {
998                         dList = toRhythmicDurationList(rd, true, tick - measure->tick(), sigmap()->timesig(tick).nominal(), measure, 0);
999                         }
1000                   if (dList.empty())
1001                         break;
1002 
1003                   for (TDuration d : dList) {
1004                         if (ltuplet) {
1005                               // take care not to recreate tuplet we just deleted
1006                               Rest* r = setRest(tick, track, d.fraction(), false, 0, false);
1007                               tick += r->actualTicks();
1008                               }
1009                         else {
1010                               tick += addClone(cr, tick, d)->actualTicks();
1011                               }
1012                         }
1013                   break;
1014                   }
1015             accumulated += td;
1016             sd          -= td;
1017             if (sd.isZero())
1018                   break;
1019             }
1020 //      Fraction ticks = measure->tick() + measure->ticks() - segment->tick();
1021 //      Fraction td = Fraction::fromTicks(ticks);
1022 // NEEDS REVIEW !!
1023 // once the statement below is removed, these two lines do nothing
1024 //      if (td > sd)
1025 //            td = sd;
1026 // ???  accumulated should already contain the total value of the created gap: line 749, 811 or 838
1027 //      this line creates a qreal-sized gap if the needed gap crosses a measure boundary
1028 //      by adding again the duration already added in line 838
1029 //      accumulated += td;
1030 
1031       const Fraction t1 = firstSegmentEnd;
1032       const Fraction t2 = firstSegment->tick() + accumulated;
1033       if (t1 < t2) {
1034             Segment* s1 = tick2rightSegment(t1);
1035             Segment* s2 = tick2rightSegment(t2);
1036             typedef SelectionFilterType Sel;
1037             // chord symbols can exist without chord/rest so they should not be removed
1038             constexpr Sel filter = static_cast<Sel>(int(Sel::ALL) & ~int(Sel::CHORD_SYMBOL));
1039             deleteAnnotationsFromRange(s1, s2, track, track + 1, filter);
1040             deleteSpannersFromRange(t1, t2, track, track + 1, filter);
1041             }
1042 
1043       return accumulated;
1044       }
1045 
1046 //---------------------------------------------------------
1047 //   makeGap1
1048 //    make time gap for each voice
1049 //    starting at tick+voiceOffset[voice] by removing/shortening
1050 //    chord/rest
1051 //    - cr is top level (not part of a tuplet)
1052 //    - do not stop at measure end
1053 //---------------------------------------------------------
1054 
makeGap1(const Fraction & baseTick,int staffIdx,const Fraction & len,int voiceOffset[VOICES])1055 bool Score::makeGap1(const Fraction& baseTick, int staffIdx, const Fraction& len, int voiceOffset[VOICES])
1056       {
1057       Segment* seg = tick2segment(baseTick, true, SegmentType::ChordRest);
1058       if (!seg) {
1059             qDebug("no segment to paste at tick %d", baseTick.ticks());
1060             return false;
1061             }
1062       int strack = staffIdx * VOICES;
1063       for (int track = strack; track < strack + VOICES; track++) {
1064             if (voiceOffset[track-strack] == -1)
1065                   continue;
1066             Fraction tick = baseTick + Fraction::fromTicks(voiceOffset[track-strack]);
1067             Measure* m   = tick2measure(tick);
1068             if ((track % VOICES) && !m->hasVoices(staffIdx))
1069                   continue;
1070 
1071             Fraction newLen = len - Fraction::fromTicks(voiceOffset[track-strack]);
1072             Q_ASSERT(newLen.numerator() != 0);
1073 
1074             if (newLen > Fraction(0,1)) {
1075                   const Fraction endTick = tick + newLen;
1076                   typedef SelectionFilterType Sel;
1077                   // chord symbols can exist without chord/rest so they should not be removed
1078                   constexpr Sel filter = static_cast<Sel>(int(Sel::ALL) & ~int(Sel::CHORD_SYMBOL));
1079                   deleteAnnotationsFromRange(tick2rightSegment(tick), tick2rightSegment(endTick), track, track + 1, filter);
1080                   deleteSpannersFromRange(tick, endTick, track, track + 1, filter);
1081                   }
1082 
1083             seg = m->undoGetSegment(SegmentType::ChordRest, tick);
1084             bool result = makeGapVoice(seg, track, newLen, tick);
1085             if (track == strack && !result) // makeGap failed for first voice
1086                   return false;
1087             }
1088       return true;
1089       }
1090 
makeGapVoice(Segment * seg,int track,Fraction len,const Fraction & tick)1091 bool Score::makeGapVoice(Segment* seg, int track, Fraction len, const Fraction& tick)
1092       {
1093       ChordRest* cr = 0;
1094       cr = toChordRest(seg->element(track));
1095       if (!cr) {
1096             // check if we are in the middle of a chord/rest
1097             Segment* seg1 = seg->prev(SegmentType::ChordRest);
1098             for (;;) {
1099                   if (seg1 == 0) {
1100                         if (!(track % VOICES))
1101                               qDebug("no segment before tick %d", tick.ticks());
1102                         // this happens only for voices other than voice 1
1103                         expandVoice(seg, track);
1104                         return makeGapVoice(seg,track,len,tick);
1105                         }
1106                   if (seg1->element(track))
1107                         break;
1108                   seg1 = seg1->prev(SegmentType::ChordRest);
1109                   }
1110             ChordRest* cr1 = toChordRest(seg1->element(track));
1111             Fraction srcF = cr1->ticks();
1112             Fraction dstF = tick - cr1->tick();
1113             std::vector<TDuration> dList = toDurationList(dstF, true);
1114             size_t n = dList.size();
1115             undoChangeChordRestLen(cr1, TDuration(dList[0]));
1116             if (n > 1) {
1117                   Fraction crtick = cr1->tick() + cr1->actualTicks();
1118                   Measure* measure = tick2measure(crtick);
1119                   if (cr1->type() == ElementType::CHORD) {
1120                         // split Chord
1121                         Chord* c = toChord(cr1);
1122                         for (size_t i = 1; i < n; ++i) {
1123                               TDuration d = dList[i];
1124                               Chord* c2 = addChord(crtick, d, c, true, c->tuplet());
1125                               c = c2;
1126                               seg1 = c->segment();
1127                               crtick += c->actualTicks();
1128                               }
1129                         }
1130                   else {
1131                         // split Rest
1132                         Rest* r       = toRest(cr1);
1133                         for (size_t i = 1; i < n; ++i) {
1134                               TDuration d = dList[i];
1135                               Rest* r2      = toRest(r->clone());
1136                               r2->setTicks(d.fraction());
1137                               r2->setDurationType(d);
1138                               undoAddCR(r2, measure, crtick);
1139                               seg1 = r2->segment();
1140                               crtick += r2->actualTicks();
1141                               }
1142                         }
1143                   }
1144             setRest(tick, track, srcF - dstF, true, 0);
1145             for (;;) {
1146                   seg1 = seg1->next1(SegmentType::ChordRest);
1147                   if (seg1 == 0) {
1148                         qDebug("no segment");
1149                         return false;
1150                         }
1151                   if (seg1->element(track)) {
1152                         cr = toChordRest(seg1->element(track));
1153                         break;
1154                         }
1155                   }
1156             }
1157 
1158       for (;;) {
1159             if (!cr) {
1160                   qDebug("cannot make gap");
1161                   return false;
1162                   }
1163             Fraction l = makeGap(cr->segment(), cr->track(), len, 0);
1164             if (l.isZero()) {
1165                   qDebug("returns zero gap");
1166                   return false;
1167                   }
1168             len -= l;
1169             if (len.isZero())
1170                   break;
1171             // go to next cr
1172             Measure* m = cr->measure()->nextMeasure();
1173             if (m == 0) {
1174                   qDebug("EOS reached");
1175                   insertMeasure(ElementType::MEASURE, 0, false);
1176                   m = cr->measure()->nextMeasure();
1177                   if (m == 0) {
1178                         qDebug("===EOS reached");
1179                         return true;
1180                         }
1181                   }
1182             // first segment in measure was removed, have to recreate it
1183             Segment* s = m->undoGetSegment(SegmentType::ChordRest, m->tick());
1184             int t  = cr->track();
1185             cr = toChordRest(s->element(t));
1186             if (!cr) {
1187                   addRest(s, t, TDuration(TDuration::DurationType::V_MEASURE), 0);
1188                   cr = toChordRest(s->element(t));
1189                   }
1190             }
1191       return true;
1192       }
1193 
1194 //---------------------------------------------------------
1195 //   splitGapToMeasureBoundaries
1196 //    cr  - start of gap
1197 //    gap - gap len
1198 //---------------------------------------------------------
1199 
splitGapToMeasureBoundaries(ChordRest * cr,Fraction gap)1200 QList<Fraction> Score::splitGapToMeasureBoundaries(ChordRest* cr, Fraction gap)
1201       {
1202       QList<Fraction> flist;
1203 
1204       Tuplet* tuplet = cr->tuplet();
1205       if (tuplet) {
1206             Fraction rest = tuplet->elementsDuration();
1207             for (DurationElement* de : tuplet->elements()) {
1208                   if (de == cr)
1209                         break;
1210                   rest -= de->ticks();
1211                   }
1212             if (rest < gap)
1213                   qDebug("does not fit in tuplet");
1214             else
1215                   flist.append(gap);
1216             return flist;
1217             }
1218 
1219       Segment* s = cr->segment();
1220       while (gap > Fraction(0,1)) {
1221             Measure* m    = s->measure();
1222             Fraction timeStretch = cr->staff()->timeStretch(s->tick());
1223             Fraction rest = (m->ticks() - s->rtick()) * timeStretch;
1224             if (rest >= gap) {
1225                   flist.append(gap);
1226                   return flist;
1227                   }
1228             flist.append(rest);
1229             gap -= rest;
1230             m = m->nextMeasure();
1231             if (m == 0)
1232                   return flist;
1233             s = m->first(SegmentType::ChordRest);
1234             }
1235       return flist;
1236       }
1237 
1238 //---------------------------------------------------------
1239 //   changeCRlen
1240 //---------------------------------------------------------
1241 
changeCRlen(ChordRest * cr,const TDuration & d)1242 void Score::changeCRlen(ChordRest* cr, const TDuration& d)
1243       {
1244       Fraction dstF;
1245       if (d.type() == TDuration::DurationType::V_MEASURE)
1246             dstF = cr->measure()->stretchedLen(cr->staff());
1247       else
1248             dstF = d.fraction();
1249       changeCRlen(cr, dstF);
1250       }
1251 
changeCRlen(ChordRest * cr,const Fraction & dstF,bool fillWithRest)1252 void Score::changeCRlen(ChordRest* cr, const Fraction& dstF, bool fillWithRest)
1253       {
1254       if (cr->isRepeatMeasure()) {
1255             // it is not clear what should this
1256             // operation mean for measure repeats.
1257             return;
1258             }
1259       Fraction srcF(cr->ticks());
1260       if (srcF == dstF) {
1261             if (cr->isFullMeasureRest())
1262                   undoChangeChordRestLen(cr, dstF);
1263             return;
1264             }
1265 
1266       //keep selected element if any
1267       Element* selElement = selection().isSingle() ? getSelectedElement() : 0;
1268 
1269       int track      = cr->track();
1270       Tuplet* tuplet = cr->tuplet();
1271 
1272       if (srcF > dstF) {
1273             //
1274             // make shorter and fill with rest
1275             //
1276             deselectAll();
1277             if (cr->isChord()) {
1278                   //
1279                   // remove ties and tremolo between 2 notes
1280                   //
1281                   Chord* c = toChord(cr);
1282                   if (c->tremolo()) {
1283                         Tremolo* tremolo = c->tremolo();
1284                         if (tremolo->twoNotes())
1285                               undoRemoveElement(tremolo);
1286                         }
1287                   foreach (Note* n, c->notes()) {
1288                         if (n->tieFor())
1289                               undoRemoveElement(n->tieFor());
1290                         }
1291                   }
1292             Fraction timeStretch = cr->staff()->timeStretch(cr->tick());
1293             std::vector<TDuration> dList = toDurationList(dstF, true);
1294             undoChangeChordRestLen(cr, dList[0]);
1295             Fraction tick2 = cr->tick();
1296             for (unsigned i = 1; i < dList.size(); ++i) {
1297                   tick2 += actualTicks(dList[i-1].ticks(), tuplet, timeStretch);
1298                   TDuration d = dList[i];
1299                   setRest(tick2, track, d.fraction(), (d.dots() > 0), tuplet);
1300                   }
1301             if (fillWithRest)
1302                   setRest(cr->tick() + cr->actualTicks(), track, srcF - dstF, false, tuplet);
1303 
1304             if (selElement)
1305                   select(selElement, SelectType::SINGLE, 0);
1306             return;
1307             }
1308 
1309       //
1310       // make longer
1311       //
1312       // split required len into Measures
1313       QList<Fraction> flist = splitGapToMeasureBoundaries(cr, dstF);
1314       if (flist.empty())
1315             return;
1316 
1317       deselectAll();
1318 
1319       Fraction tick  = cr->tick();
1320       Fraction f     = dstF;
1321       ChordRest* cr1 = cr;
1322       Chord* oc      = 0;
1323 
1324       bool first = true;
1325       for (Fraction f2 : qAsConst(flist)) {
1326             f  -= f2;
1327             makeGap(cr1->segment(), cr1->track(), f2, tuplet, first);
1328 
1329             if (cr->isRest()) {
1330                   Fraction timeStretch = cr1->staff()->timeStretch(cr1->tick());
1331                   Rest* r = toRest(cr);
1332                   if (first) {
1333                         std::vector<TDuration> dList = toDurationList(f2, true);
1334                         undoChangeChordRestLen(cr, dList[0]);
1335                         Fraction tick2 = cr->tick();
1336                         for (unsigned i = 1; i < dList.size(); ++i) {
1337                               tick2 += actualTicks(dList[i-1].ticks(), tuplet, timeStretch);
1338                               TDuration d = dList[i];
1339                               setRest(tick2, track, d.fraction(), (d.dots() > 0), tuplet);
1340                               }
1341                         }
1342                   else {
1343                         r = setRest(tick, track, f2, false, tuplet);
1344                         }
1345                   if (first) {
1346                         select(r, SelectType::SINGLE, 0);
1347                         first = false;
1348                         }
1349                   tick += actualTicks(f2, tuplet, timeStretch);
1350                   }
1351             else {
1352                   std::vector<TDuration> dList = toDurationList(f2, true);
1353                   Measure* measure             = tick2measure(tick);
1354                   Fraction etick                    = measure->tick();
1355 
1356                   if (((tick - etick).ticks() % dList[0].ticks().ticks()) == 0) {
1357                         for (TDuration du : dList) {
1358                               Chord* cc;
1359                               if (oc) {
1360                                     cc = oc;
1361                                     oc = addChord(tick, du, cc, true, tuplet);
1362                                     }
1363                               else {
1364                                     cc = toChord(cr);
1365                                     undoChangeChordRestLen(cr, du);
1366                                     oc = cc;
1367                                     }
1368                               if (oc && first) {
1369                                     if (!selElement)
1370                                           select(oc, SelectType::SINGLE, 0);
1371                                     else
1372                                           select(selElement, SelectType::SINGLE, 0);
1373                                     first = false;
1374                                     }
1375                               if (oc)
1376                                     tick += oc->actualTicks();
1377                               }
1378                         }
1379                   else {
1380                         for (size_t i = dList.size(); i > 0; --i) { // loop probably needs to be in this reverse order
1381                               Chord* cc;
1382                               if (oc) {
1383                                     cc = oc;
1384                                     oc = addChord(tick, dList[i-1], cc, true, tuplet);
1385                                     }
1386                               else {
1387                                     cc = toChord(cr);
1388                                     undoChangeChordRestLen(cr, dList[i-1]);
1389                                     oc = cc;
1390                                     }
1391                               if (first) {
1392                                     // select(oc, SelectType::SINGLE, 0);
1393                                     if (selElement)
1394                                           select(selElement, SelectType::SINGLE, 0);
1395                                     first = false;
1396                                     }
1397                               tick += oc->actualTicks();
1398                               }
1399                         }
1400                   }
1401             Measure* m  = cr1->measure();
1402             Measure* m1 = m->nextMeasure();
1403             if (m1 == 0)
1404                   break;
1405             Segment* s = m1->first(SegmentType::ChordRest);
1406             expandVoice(s, track);
1407             cr1 = toChordRest(s->element(track));
1408             }
1409       connectTies();
1410       }
1411 
1412 //---------------------------------------------------------
1413 //   upDownChromatic
1414 //---------------------------------------------------------
1415 
upDownChromatic(bool up,int pitch,Note * n,Key key,int tpc1,int tpc2,int & newPitch,int & newTpc1,int & newTpc2)1416 static void upDownChromatic(bool up, int pitch, Note* n, Key key, int tpc1, int tpc2, int& newPitch, int& newTpc1, int& newTpc2)
1417       {
1418       if (up && pitch < 127) {
1419             newPitch = pitch + 1;
1420             if (n->concertPitch()) {
1421                   if (tpc1 > Tpc::TPC_A + int(key))
1422                         newTpc1 = tpc1 - 5;   // up semitone diatonic
1423                   else
1424                         newTpc1 = tpc1 + 7;   // up semitone chromatic
1425                   newTpc2 = n->transposeTpc(newTpc1);
1426                   }
1427             else {
1428                   if (tpc2 > Tpc::TPC_A + int(key))
1429                         newTpc2 = tpc2 - 5;   // up semitone diatonic
1430                   else
1431                         newTpc2 = tpc2 + 7;   // up semitone chromatic
1432                   newTpc1 = n->transposeTpc(newTpc2);
1433                   }
1434             }
1435       else if (!up && pitch > 0) {
1436             newPitch = pitch - 1;
1437             if (n->concertPitch()) {
1438                   if (tpc1 > Tpc::TPC_C + int(key))
1439                         newTpc1 = tpc1 - 7;   // down semitone chromatic
1440                   else
1441                         newTpc1 = tpc1 + 5;   // down semitone diatonic
1442                   newTpc2 = n->transposeTpc(newTpc1);
1443                   }
1444             else {
1445                   if (tpc2 > Tpc::TPC_C + int(key))
1446                         newTpc2 = tpc2 - 7;   // down semitone chromatic
1447                   else
1448                         newTpc2 = tpc2 + 5;   // down semitone diatonic
1449                   newTpc1 = n->transposeTpc(newTpc2);
1450                   }
1451             }
1452       }
1453 
1454 //---------------------------------------------------------
1455 //   setTpc
1456 //---------------------------------------------------------
1457 
setTpc(Note * oNote,int tpc,int & newTpc1,int & newTpc2)1458 static void setTpc(Note* oNote, int tpc, int& newTpc1, int& newTpc2)
1459       {
1460       if (oNote->concertPitch()) {
1461             newTpc1 = tpc;
1462             newTpc2 = oNote->transposeTpc(tpc);
1463             }
1464       else {
1465             newTpc2 = tpc;
1466             newTpc1 = oNote->transposeTpc(tpc);
1467             }
1468       }
1469 
1470 //---------------------------------------------------------
1471 //   upDown
1472 ///   Increment/decrement pitch of note by one or by an octave.
1473 //---------------------------------------------------------
1474 
upDown(bool up,UpDownMode mode)1475 void Score::upDown(bool up, UpDownMode mode)
1476       {
1477       QList<Note*> el = selection().uniqueNotes();
1478 
1479       for (Note* oNote : qAsConst(el)) {
1480             Fraction tick     = oNote->chord()->tick();
1481             Staff* staff = oNote->staff();
1482             Part* part   = staff->part();
1483             Key key      = staff->key(tick);
1484             int tpc1     = oNote->tpc1();
1485             int tpc2     = oNote->tpc2();
1486             int pitch    = oNote->pitch();
1487             int newTpc1  = tpc1;      // default to unchanged
1488             int newTpc2  = tpc2;      // default to unchanged
1489             int newPitch = pitch;     // default to unchanged
1490             int string   = oNote->string();
1491             int fret     = oNote->fret();
1492 
1493             StaffGroup staffGroup = staff->staffType(oNote->chord()->tick())->group();
1494             // if not tab, check for instrument instead of staffType (for pitched to unpitched instrument changes)
1495             if ( staffGroup != StaffGroup::TAB)
1496                   staffGroup = staff->part()->instrument(oNote->tick())->useDrumset() ? StaffGroup::PERCUSSION : StaffGroup::STANDARD;
1497 
1498             switch (staffGroup) {
1499                   case StaffGroup::PERCUSSION:
1500                         {
1501                         const Drumset* ds = part->instrument(tick)->drumset();
1502                         if (ds) {
1503                               newPitch = up ? ds->nextPitch(pitch) : ds->prevPitch(pitch);
1504                               newTpc1 = pitch2tpc(newPitch, Key::C, Prefer::NEAREST);
1505                               newTpc2 = newTpc1;
1506                               }
1507                         }
1508                         break;
1509                   case StaffGroup::TAB:
1510                         {
1511                         const StringData* stringData = part->instrument(tick)->stringData();
1512                         switch (mode) {
1513                               case UpDownMode::OCTAVE:          // move same note to next string, if possible
1514                                     {
1515                                     const StaffType* stt = staff->staffType(tick);
1516                                     string = stt->physStringToVisual(string);
1517                                     string += (up ? -1 : 1);
1518                                     if (string < 0 || string >= stringData->strings())
1519                                           return;           // no next string to move to
1520                                     string = stt->visualStringToPhys(string);
1521                                     fret = stringData->fret(pitch, string, staff, tick);
1522                                     if (fret == -1)          // can't have that note on that string
1523                                           return;
1524                                     // newPitch and newTpc remain unchanged
1525                                     }
1526                                     break;
1527 
1528                               case UpDownMode::DIATONIC:        // increase / decrease the pitch,
1529                                                             // letting the algorithm to choose fret & string
1530                                     upDownChromatic(up, pitch, oNote, key, tpc1, tpc2, newPitch, newTpc1, newTpc2);
1531                                     break;
1532 
1533                               case UpDownMode::CHROMATIC:       // increase / decrease the fret
1534                                     {                       // without changing the string
1535                                     // compute new fret
1536                                     if (!stringData->frets()) {
1537                                           qDebug("upDown tab chromatic: no frets?");
1538                                           return;
1539                                           }
1540                                     fret += (up ? 1 : -1);
1541                                     if (fret < 0 || fret > stringData->frets()) {
1542                                           qDebug("upDown tab in-string: out of fret range");
1543                                           return;
1544                                           }
1545                                     // update pitch and tpc's and check it matches stringData
1546                                     upDownChromatic(up, pitch, oNote, key, tpc1, tpc2, newPitch, newTpc1, newTpc2);
1547                                     if (newPitch != stringData->getPitch(string, fret, staff, tick) ) {
1548                                           // oh-oh: something went very wrong!
1549                                           qDebug("upDown tab in-string: pitch mismatch");
1550                                           return;
1551                                     }
1552                                     // store the fretting change before undoChangePitch() chooses
1553                                     // a fretting of its own liking!
1554                                     oNote->undoChangeProperty(Pid::FRET, fret);
1555                                     }
1556                                     break;
1557                               }
1558                         }
1559                         break;
1560                   case StaffGroup::STANDARD:
1561                         switch (mode) {
1562                               case UpDownMode::OCTAVE:
1563                                     if (up) {
1564                                           if (pitch < 116)
1565                                                 newPitch = pitch + 12;
1566                                           }
1567                                     else {
1568                                           if (pitch > 11)
1569                                                 newPitch = pitch - 12;
1570                                           }
1571                                     // newTpc remains unchanged
1572                                     break;
1573 
1574                               case UpDownMode::CHROMATIC:
1575                                     upDownChromatic(up, pitch, oNote, key, tpc1, tpc2, newPitch, newTpc1, newTpc2);
1576                                     break;
1577 
1578                               case UpDownMode::DIATONIC:
1579                                     {
1580                                     int tpc = oNote->tpc();
1581                                     if (up) {
1582                                           if (tpc > Tpc::TPC_A + int(key)) {
1583                                                 if (pitch < 127) {
1584                                                       newPitch = pitch + 1;
1585                                                       setTpc(oNote, tpc - 5, newTpc1, newTpc2);
1586                                                       }
1587                                                 }
1588                                           else {
1589                                                 if (pitch < 126) {
1590                                                       newPitch = pitch + 2;
1591                                                       setTpc(oNote, tpc + 2, newTpc1, newTpc2);
1592                                                       }
1593                                                 }
1594                                           }
1595                                     else {
1596                                           if (tpc > Tpc::TPC_C + int(key)) {
1597                                                 if (pitch > 1) {
1598                                                       newPitch = pitch - 2;
1599                                                       setTpc(oNote, tpc - 2, newTpc1, newTpc2);
1600                                                       }
1601                                                 }
1602                                           else {
1603                                                 if (pitch > 0) {
1604                                                       newPitch = pitch - 1;
1605                                                       setTpc(oNote, tpc + 5, newTpc1, newTpc2);
1606                                                       }
1607                                                 }
1608                                           }
1609                                     }
1610                                     break;
1611                               }
1612                         break;
1613                   }
1614 
1615             if ((oNote->pitch() != newPitch) || (oNote->tpc1() != newTpc1) || oNote->tpc2() != newTpc2) {
1616                   // remove accidental if present to make sure
1617                   // user added accidentals are removed here
1618                   // unless it's an octave change
1619                   // in this case courtesy accidentals are preserved
1620                   // because they're now harder to be re-entered due to the revised note-input workflow
1621                   if (mode != UpDownMode::OCTAVE) {
1622                         auto l = oNote->linkList();
1623                         for (ScoreElement* e : qAsConst(l)) {
1624                               Note* ln = toNote(e);
1625                               if (ln->accidental())
1626                                     undo(new RemoveElement(ln->accidental()));
1627                               }
1628                         }
1629                   undoChangePitch(oNote, newPitch, newTpc1, newTpc2);
1630                   }
1631 
1632             // store fret change only if undoChangePitch has not been called,
1633             // as undoChangePitch() already manages fret changes, if necessary
1634             else if (staff->staffType(tick)->group() == StaffGroup::TAB) {
1635                   bool refret = false;
1636                   if (oNote->string() != string) {
1637                         oNote->undoChangeProperty(Pid::STRING, string);
1638                         refret = true;
1639                         }
1640                   if (oNote->fret() != fret) {
1641                         oNote->undoChangeProperty(Pid::FRET, fret);
1642                         refret = true;
1643                         }
1644                   if (refret) {
1645                         const StringData* stringData = part->instrument(tick)->stringData();
1646                         stringData->fretChords(oNote->chord());
1647                         }
1648                   }
1649 
1650             // play new note with velocity 80 for 0.3 sec:
1651             setPlayNote(true);
1652             }
1653       setSelectionChanged(true);
1654       }
1655 
1656 //---------------------------------------------------------
1657 //   upDownDelta
1658 ///   Add the delta to the pitch of note.
1659 //---------------------------------------------------------
1660 
upDownDelta(int pitchDelta)1661 void Score::upDownDelta(int pitchDelta)
1662       {
1663       while (pitchDelta > 0) {
1664             upDown(true, UpDownMode::CHROMATIC);
1665             pitchDelta--;
1666             }
1667 
1668       while (pitchDelta < 0) {
1669             upDown(false, UpDownMode::CHROMATIC);
1670             pitchDelta++;
1671             }
1672       }
1673 
1674 //---------------------------------------------------------
1675 //   addArticulation
1676 ///   Add attribute \a attr to all selected notes/rests.
1677 ///
1678 ///   Called from padToggle() to add note prefix/accent.
1679 //---------------------------------------------------------
1680 
addArticulation(SymId attr)1681 void Score::addArticulation(SymId attr)
1682       {
1683       QSet<Chord*> set;
1684       int numAdded = 0;
1685       int numRemoved = 0;
1686       for (Element* el : selection().elements()) {
1687             if (el->isNote() || el->isChord()) {
1688                   Chord* cr = 0;
1689                   // apply articulation on a given chord only once
1690                   if (el->isNote()) {
1691                         cr = toNote(el)->chord();
1692                         if (set.contains(cr))
1693                               continue;
1694                         }
1695                   Articulation* na = new Articulation(this);
1696                   na->setSymId(attr);
1697                   if (addArticulation(el, na)) {
1698                         ++numAdded;
1699                         }
1700                   else {
1701                         delete na;
1702                         ++numRemoved;
1703                         }
1704                   if (cr)
1705                         set.insert(cr);
1706                   }
1707             }
1708       QString msg = Sym::id2userName(attr);
1709       if (numAdded == 1 && numRemoved == 0)
1710             msg = QObject::tr("%1 added").arg(msg);
1711       else if (numAdded == 0 && numRemoved == 1)
1712             msg = QObject::tr("%1 removed").arg(msg);
1713       else
1714             msg = QObject::tr("%1, added %2, removed %3")
1715                   .arg(msg).arg(numAdded).arg(numRemoved);
1716       setAccessibleMessage(msg);
1717       }
1718 
1719 //---------------------------------------------------------
1720 //   toggleAccidental
1721 //---------------------------------------------------------
1722 
toggleAccidental(AccidentalType at,const EditData & ed)1723 void Score::toggleAccidental(AccidentalType at, const EditData& ed)
1724       {
1725       if (_is.accidentalType() == at)
1726             at = AccidentalType::NONE;
1727       if (noteEntryMode()) {
1728             _is.setAccidentalType(at);
1729             _is.setRest(false);
1730             }
1731       else {
1732             if (selection().isNone()) {
1733                   ed.view->startNoteEntryMode();
1734                   _is.setAccidentalType(at);
1735                   _is.setDuration(TDuration::DurationType::V_QUARTER);
1736                   _is.setRest(false);
1737                   }
1738             else
1739                   changeAccidental(at);
1740             }
1741       }
1742 //---------------------------------------------------------
1743 //   changeAccidental
1744 ///   Change accidental to subtype \a idx for all selected
1745 ///   notes.
1746 //---------------------------------------------------------
1747 
changeAccidental(AccidentalType idx)1748 void Score::changeAccidental(AccidentalType idx)
1749       {
1750       foreach(Note* note, selection().noteList())
1751             changeAccidental(note, idx);
1752       }
1753 
1754 //---------------------------------------------------------
1755 //   changeAccidental2
1756 //---------------------------------------------------------
1757 
changeAccidental2(Note * n,int pitch,int tpc)1758 static void changeAccidental2(Note* n, int pitch, int tpc)
1759       {
1760       Score* score  = n->score();
1761       Chord* chord  = n->chord();
1762       Staff* st     = chord->staff();
1763       int fret      = n->fret();
1764       int string    = n->string();
1765 
1766       if (st->isTabStaff(chord->tick())) {
1767             if (pitch != n->pitch()) {
1768                   //
1769                   // as pitch has changed, calculate new
1770                   // string & fret
1771                   //
1772                   const StringData* stringData = n->part()->instrument(n->tick())->stringData();
1773                   if (stringData)
1774                         stringData->convertPitch(pitch, st, chord->tick(), &string, &fret);
1775                   }
1776             }
1777       int tpc1;
1778       int tpc2 = n->transposeTpc(tpc);
1779       if (score->styleB(Sid::concertPitch))
1780             tpc1 = tpc;
1781       else {
1782             tpc1 = tpc2;
1783             tpc2 = tpc;
1784             }
1785 
1786       if (!st->isTabStaff(chord->tick())) {
1787             //
1788             // handle ties
1789             //
1790             if (n->tieBack()) {
1791                   if (pitch != n->pitch()) {
1792                         score->undoRemoveElement(n->tieBack());
1793                         if (n->tieFor())
1794                               score->undoRemoveElement(n->tieFor());
1795                         }
1796                   }
1797             else {
1798                   Note* nn = n;
1799                   while (nn->tieFor()) {
1800                         nn = nn->tieFor()->endNote();
1801                         score->undo(new ChangePitch(nn, pitch, tpc1, tpc2));
1802                         }
1803                   }
1804             }
1805       score->undoChangePitch(n, pitch, tpc1, tpc2);
1806       }
1807 
1808 //---------------------------------------------------------
1809 //   changeAccidental
1810 ///   Change accidental to subtype \accidental for
1811 ///   note \a note.
1812 //---------------------------------------------------------
1813 
changeAccidental(Note * note,AccidentalType accidental)1814 void Score::changeAccidental(Note* note, AccidentalType accidental)
1815       {
1816       Chord* chord = note->chord();
1817       if (!chord)
1818             return;
1819       Segment* segment = chord->segment();
1820       if (!segment)
1821             return;
1822       Measure* measure = segment->measure();
1823       if (!measure)
1824             return;
1825       Fraction tick = segment->tick();
1826       Staff* estaff = staff(chord->staffIdx() + chord->staffMove());
1827       if (!estaff)
1828             return;
1829       ClefType clef = estaff->clef(tick);
1830       int step      = ClefInfo::pitchOffset(clef) - note->line();
1831       while (step < 0)
1832             step += 7;
1833       step %= 7;
1834       //
1835       // accidental change may result in pitch change
1836       //
1837       AccidentalVal acc2 = measure->findAccidental(note);
1838       AccidentalVal acc = (accidental == AccidentalType::NONE) ? acc2 : Accidental::subtype2value(accidental);
1839 
1840       int pitch = line2pitch(note->line(), clef, Key::C) + int(acc);
1841       if (!note->concertPitch())
1842             pitch += note->transposition();
1843 
1844       int tpc = step2tpc(step, acc);
1845 
1846       bool forceRemove = false;
1847       bool forceAdd = false;
1848 
1849       // delete accidental
1850       // both for this note and for any linked notes
1851       if (accidental == AccidentalType::NONE)
1852             forceRemove = true;
1853 
1854       // precautionary or microtonal accidental
1855       // either way, we display it unconditionally
1856       // both for this note and for any linked notes
1857       else if (acc == acc2 || (pitch == note->pitch() && !Accidental::isMicrotonal(note->accidentalType())) || Accidental::isMicrotonal(accidental))
1858             forceAdd = true;
1859 
1860       for (ScoreElement* se : note->linkList()) {
1861             Note* ln = toNote(se);
1862             if (ln->concertPitch() != note->concertPitch())
1863                   continue;
1864             Score* lns    = ln->score();
1865             Accidental* a = ln->accidental();
1866             if (forceRemove) {
1867                   if (a)
1868                         lns->undoRemoveElement(a);
1869                   if (ln->tieBack())
1870                         continue;
1871                   }
1872             else if (forceAdd) {
1873                   if (a)
1874                         undoRemoveElement(a);
1875                   Accidental* a1 = new Accidental(lns);
1876                   a1->setParent(ln);
1877                   a1->setAccidentalType(accidental);
1878                   a1->setRole(AccidentalRole::USER);
1879                   lns->undoAddElement(a1);
1880                   }
1881             else if (a && Accidental::isMicrotonal(a->accidentalType())) {
1882                   lns->undoRemoveElement(a);
1883                   }
1884             changeAccidental2(ln, pitch, tpc);
1885             }
1886       setPlayNote(true);
1887       setSelectionChanged(true);
1888       }
1889 
1890 //---------------------------------------------------------
1891 //   addArticulation
1892 //---------------------------------------------------------
1893 
addArticulation(Element * el,Articulation * a)1894 bool Score::addArticulation(Element* el, Articulation* a)
1895       {
1896       Chord* c;
1897       if (el->isNote())
1898             c = toNote(el)->chord();
1899       else if (el->isChord())
1900             c = toChord(el);
1901       else
1902             return false;
1903       Articulation* oa = c->hasArticulation(a);
1904       if (oa) {
1905             undoRemoveElement(oa);
1906             return false;
1907             }
1908       a->setParent(c);
1909       a->setTrack(c->track()); // make sure it propagates between score and parts
1910       undoAddElement(a);
1911       return true;
1912       }
1913 
1914 //---------------------------------------------------------
1915 //   resetUserStretch
1916 //---------------------------------------------------------
1917 
resetUserStretch()1918 void Score::resetUserStretch()
1919       {
1920       Measure* m1;
1921       Measure* m2;
1922       // retrieve span of selection
1923       Segment* s1 = _selection.startSegment();
1924       Segment* s2 = _selection.endSegment();
1925       // if either segment is not returned by the selection
1926       // (for instance, no selection) fall back to first/last measure
1927       if (!s1)
1928             m1 = firstMeasureMM();
1929       else
1930             m1 = s1->measure();
1931       if (!s2)
1932             m2 = lastMeasureMM();
1933       else
1934             m2 = s2->measure();
1935       if (!m1 || !m2)               // should not happen!
1936             return;
1937 
1938       for (Measure* m = m1; m; m = m->nextMeasureMM()) {
1939             m->undoChangeProperty(Pid::USER_STRETCH, 1.0);
1940             if (m == m2)
1941                   break;
1942             }
1943       }
1944 
1945 //---------------------------------------------------------
1946 //   moveUp
1947 //---------------------------------------------------------
1948 
moveUp(ChordRest * cr)1949 void Score::moveUp(ChordRest* cr)
1950       {
1951       Staff* staff  = cr->staff();
1952       Part* part    = staff->part();
1953       int rstaff    = staff->rstaff();
1954       int staffMove = cr->staffMove();
1955 
1956       if ((staffMove == -1) || (rstaff + staffMove <= 0))
1957             return;
1958 
1959       QList<Staff*>* staves = part->staves();
1960       // we know that staffMove+rstaff-1 index exists due to the previous condition.
1961       if (staff->staffType(cr->tick())->group() != StaffGroup::STANDARD ||
1962           staves->at(rstaff+staffMove-1)->staffType(cr->tick())->group() != StaffGroup::STANDARD) {
1963             qDebug("User attempted to move a note from/to a staff which does not use standard notation - ignoring.");
1964             }
1965       else  {
1966             // move the chord up a staff
1967             undo(new ChangeChordStaffMove(cr, staffMove - 1));
1968             }
1969       }
1970 
1971 //---------------------------------------------------------
1972 //   moveDown
1973 //---------------------------------------------------------
1974 
moveDown(ChordRest * cr)1975 void Score::moveDown(ChordRest* cr)
1976       {
1977       Staff* staff  = cr->staff();
1978       Part* part    = staff->part();
1979       int rstaff    = staff->rstaff();
1980       int staffMove = cr->staffMove();
1981       // calculate the number of staves available so that we know whether there is another staff to move down to
1982       int rstaves   = part->nstaves();
1983 
1984       if ((staffMove == 1) || (rstaff + staffMove >= rstaves - 1)) {
1985             qDebug("moveDown staffMove==%d  rstaff %d rstaves %d", staffMove, rstaff, rstaves);
1986             return;
1987             }
1988 
1989       QList<Staff*>* staves = part->staves();
1990       // we know that staffMove+rstaff+1 index exists due to the previous condition.
1991       if (staff->staffType(cr->tick())->group() != StaffGroup::STANDARD ||
1992           staves->at(staffMove+rstaff+1)->staffType(cr->tick())->group() != StaffGroup::STANDARD) {
1993             qDebug("User attempted to move a note from/to a staff which does not use standard notation - ignoring.");
1994             }
1995       else  {
1996             // move the chord down a staff
1997             undo(new ChangeChordStaffMove(cr, staffMove + 1));
1998             }
1999       }
2000 
2001 //---------------------------------------------------------
2002 //   cmdAddStretch
2003 //---------------------------------------------------------
2004 
cmdAddStretch(qreal val)2005 void Score::cmdAddStretch(qreal val)
2006       {
2007       if (!selection().isRange())
2008             return;
2009       Fraction startTick = selection().tickStart();
2010       Fraction endTick   = selection().tickEnd();
2011       for (Measure* m = firstMeasureMM(); m; m = m->nextMeasureMM()) {
2012             if (m->tick() < startTick)
2013                   continue;
2014             if (m->tick() >= endTick)
2015                   break;
2016             qreal stretch = m->userStretch();
2017             stretch += val;
2018             if (stretch < 0)
2019                   stretch = 0;
2020             m->undoChangeProperty(Pid::USER_STRETCH, stretch);
2021             }
2022       }
2023 
2024 //---------------------------------------------------------
2025 //   cmdResetBeamMode
2026 //---------------------------------------------------------
2027 
cmdResetBeamMode()2028 void Score::cmdResetBeamMode()
2029       {
2030       bool noSelection = selection().isNone();
2031       if (noSelection)
2032             cmdSelectAll();
2033       else if (!selection().isRange()) {
2034             qDebug("no system or staff selected");
2035             return;
2036             }
2037 
2038       Fraction endTick = selection().tickEnd();
2039 
2040       for (Segment* seg = selection().firstChordRestSegment(); seg && seg->tick() < endTick; seg = seg->next1(SegmentType::ChordRest)) {
2041             for (int track = selection().staffStart() * VOICES; track < selection().staffEnd() * VOICES; ++track) {
2042                   ChordRest* cr = toChordRest(seg->element(track));
2043                   if (!cr)
2044                         continue;
2045                   if (cr->type() == ElementType::CHORD) {
2046                         if (cr->beamMode() != Beam::Mode::AUTO)
2047                               cr->undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::AUTO));
2048                         }
2049                   else if (cr->type() == ElementType::REST) {
2050                         if (cr->beamMode() != Beam::Mode::NONE)
2051                               cr->undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::NONE));
2052                         }
2053                   }
2054             }
2055       if (noSelection)
2056             deselectAll();
2057       }
2058 
2059 //---------------------------------------------------------
2060 //   cmdResetStyle
2061 //---------------------------------------------------------
2062 
cmdResetAllStyle()2063 void Score::cmdResetAllStyle()
2064       {
2065       style().resetAllStyles(this);
2066       }
2067 
cmdResetTextStyleOverrides()2068 void Score::cmdResetTextStyleOverrides()
2069 {
2070     static const std::vector<Pid> propertiesToReset {
2071         Pid::FONT_FACE,
2072         Pid::FONT_SIZE,
2073         Pid::FONT_STYLE,
2074         Pid::SIZE_SPATIUM_DEPENDENT,
2075         Pid::FRAME_TYPE,
2076         Pid::TEXT_LINE_SPACING,
2077         Pid::FRAME_FG_COLOR,
2078         Pid::FRAME_BG_COLOR,
2079         Pid::FRAME_WIDTH,
2080         Pid::FRAME_PADDING,
2081         Pid::FRAME_ROUND,
2082         Pid::ALIGN
2083     };
2084 
2085     for (Page* page : pages()) {
2086         auto elements = page->elements();
2087 
2088         for (Element* element : elements) {
2089             if (!element || !element->isTextBase()) {
2090                 continue;
2091             }
2092 
2093             for (Pid propertyId : propertiesToReset) {
2094                 element->resetProperty(propertyId);
2095             }
2096         }
2097     }
2098 }
2099 
2100 //---------------------------------------------------------
2101 //   cmdResetNoteAndRestGroupings
2102 //---------------------------------------------------------
2103 
cmdResetNoteAndRestGroupings()2104 void Score::cmdResetNoteAndRestGroupings()
2105       {
2106       bool noSelection = selection().isNone();
2107       if (noSelection)
2108             cmdSelectAll();
2109       else if (!selection().isRange()) {
2110             qDebug("no system or staff selected");
2111             return;
2112             }
2113 
2114       // save selection values because selection changes during grouping
2115       Fraction sTick = selection().tickStart();
2116       Fraction eTick = selection().tickEnd();
2117       int sStaff = selection().staffStart();
2118       int eStaff = selection().staffEnd();
2119 
2120       startCmd();
2121       for (int staff = sStaff; staff < eStaff; staff++) {
2122             int sTrack = staff * VOICES;
2123             int eTrack = sTrack + VOICES;
2124             for (int track = sTrack; track < eTrack; track++) {
2125                   if (selectionFilter().canSelectVoice(track))
2126                         regroupNotesAndRests(sTick, eTick, track);
2127                   }
2128             }
2129       endCmd();
2130       if (noSelection)
2131             deselectAll();
2132       }
2133 
2134 //---------------------------------------------------------
2135 //   resetElementShapePosition
2136 //    For use with Score::scanElements.
2137 //    Reset positions and autoplacement for the given
2138 //    element.
2139 //---------------------------------------------------------
2140 
resetElementPosition(void *,Element * e)2141 static void resetElementPosition(void*, Element* e)
2142       {
2143       if (e->generated())
2144             return;
2145       e->undoResetProperty(Pid::AUTOPLACE);
2146       e->undoResetProperty(Pid::OFFSET);
2147       e->setOffsetChanged(false);
2148       if (e->isSpanner())
2149             e->undoResetProperty(Pid::OFFSET2);
2150       }
2151 
2152 //---------------------------------------------------------
2153 //   cmdResetAllPositions
2154 //---------------------------------------------------------
2155 
cmdResetAllPositions(bool undoable)2156 void Score::cmdResetAllPositions(bool undoable)
2157       {
2158       if (undoable)
2159             startCmd();
2160       resetAllPositions();
2161       if (undoable)
2162             endCmd();
2163       }
2164 
resetAllPositions()2165 void Score::resetAllPositions()
2166       {
2167       scanElements(nullptr, resetElementPosition);
2168       }
2169 
2170 //---------------------------------------------------------
2171 //   processMidiInput
2172 //---------------------------------------------------------
2173 
processMidiInput()2174 bool Score::processMidiInput()
2175       {
2176       if (midiInputQueue()->empty())
2177             return false;
2178 
2179       if (MScore::debugMode)
2180           qDebug("processMidiInput");
2181 
2182       NoteEntryMethod entryMethod = _is.noteEntryMethod();
2183       bool cmdActive = false;
2184       while (!midiInputQueue()->empty()) {
2185             MidiInputEvent ev = midiInputQueue()->dequeue();
2186             for (auto itr = activeMidiPitches()->begin(); itr != activeMidiPitches()->end();) {
2187                   if ((*itr).pitch == ev.pitch)
2188                         itr = activeMidiPitches()->erase(itr);
2189                   else
2190                         ++itr;
2191                   }
2192             if (MScore::debugMode)
2193                   qDebug("<-- !noteentry dequeue %i", ev.pitch);
2194             if (!noteEntryMode()
2195                         || entryMethod == NoteEntryMethod::REALTIME_AUTO
2196                         || entryMethod == NoteEntryMethod::REALTIME_MANUAL) {
2197                   int staffIdx = selection().staffStart();
2198                   Part* p;
2199                   if (staffIdx < 0 || staffIdx >= nstaves())
2200                         p = staff(0)->part();
2201                   else
2202                         p = staff(staffIdx)->part();
2203                   if (p) {
2204                         if (!styleB(Sid::concertPitch)) {
2205                               ev.pitch += p->instrument(selection().tickStart())->transpose().chromatic;
2206                               }
2207                         MScore::seq->startNote(
2208                                           p->instrument(selection().tickStart())->channel(0)->channel(),   // tick that way?
2209                                           ev.pitch,
2210                                           ev.velocity,
2211                                           0.0);
2212                         }
2213                   }
2214             if (noteEntryMode()) {
2215                   if (ev.velocity == 0) {
2216                         // delete note in realtime mode
2217                         //Chord* chord = toChord(_is.cr());
2218                         //std::vector<Note*> notes = chord->notes();
2219                         if (entryMethod == NoteEntryMethod::REALTIME_AUTO || entryMethod == NoteEntryMethod::REALTIME_MANUAL) {
2220                               if (_is.cr()->isChord()) {
2221                                     Note* n = toChord(_is.cr())->findNote(ev.pitch);
2222                                     if (n) {
2223                                           qDebug("Pitches match! Note %i, Pitch %i", n->pitch(), ev.pitch);
2224                                           if (!cmdActive) {
2225                                                 startCmd();
2226                                                 cmdActive = true;
2227                                                 }
2228                                           deleteItem(n->tieBack());
2229                                           deleteItem(n);
2230                                           }
2231                                     }
2232                               }
2233                         continue;
2234                         }
2235                   if (!cmdActive) {
2236                         startCmd();
2237                         cmdActive = true;
2238                         }
2239                   if (activeMidiPitches()->empty())
2240                         ev.chord = false;
2241                   else
2242                         ev.chord = true;
2243 
2244                   // holding shift while inputting midi will add the new pitch to the prior existing chord
2245                   if (qApp->keyboardModifiers() & Qt::ShiftModifier) {
2246                         Element* cr = _is.lastSegment()->element(_is.track());
2247                         if (cr && cr->isChord())
2248                               ev.chord = true;
2249                         }
2250 
2251                   // TODO: add shadow note instead of real note in realtime modes
2252                   // (note becomes real when realtime-advance triggered).
2253                   addMidiPitch(ev.pitch, ev.chord);
2254                   activeMidiPitches()->push_back(ev);
2255                   }
2256             }
2257       if (cmdActive) {
2258             endCmd();
2259             //after relayout
2260             Element* e = inputState().cr();
2261             if (e) {
2262                   for(MuseScoreView* v : qAsConst(viewer))
2263                         v->adjustCanvasPosition(e, false);
2264                   }
2265             return true;
2266             }
2267       return false;
2268       }
2269 
2270 //---------------------------------------------------------
2271 //   move
2272 //    move current selection
2273 //---------------------------------------------------------
2274 
move(const QString & cmd)2275 Element* Score::move(const QString& cmd)
2276       {
2277       ChordRest* cr { nullptr };
2278       Box* box { nullptr };
2279       if (noteEntryMode()) {
2280             // if selection exists and is grace note, use it
2281             // otherwise use chord/rest at input position
2282             // also use it if we are moving to next chord
2283             // to catch up with the cursor and not move the selection by 2 positions
2284             cr = selection().cr();
2285             if (cr && (cr->isGrace() || cmd == "next-chord" || cmd == "prev-chord"))
2286                   ;
2287             else
2288                   cr = inputState().cr();
2289             }
2290       else if (selection().activeCR())
2291             cr = selection().activeCR();
2292       else
2293             cr = selection().lastChordRest();
2294 
2295       // no chord/rest found? look for another type of element,
2296       // but commands [empty-trailing-measure] and [top-staff] don't
2297       // necessarily need an active selection for appropriate functioning
2298       if (!cr && cmd != "empty-trailing-measure" && cmd != "top-staff") {
2299             if (selection().elements().empty())
2300                   return 0;
2301             // retrieve last element of section list
2302             Element* el = selection().elements().last();
2303             Element* trg = 0;
2304 
2305             // get parent of element and process accordingly:
2306             // trg is the element to select on "next-chord" cmd
2307             // cr is the ChordRest to move from on other cmd's
2308             int track = el->track();            // keep note of element track
2309             if (!el->isBox())
2310                   el = el->parent();
2311             // element with no parent (eg, a newly-added line) - no way to find context
2312             if (!el)
2313                   return 0;
2314             switch (el->type()) {
2315                   case ElementType::NOTE:           // a note is a valid target
2316                         trg = el;
2317                         cr  = toNote(el)->chord();
2318                         break;
2319                   case ElementType::CHORD:          // a chord or a rest are valid targets
2320                   case ElementType::REST:
2321                         trg = el;
2322                         cr  = toChordRest(trg);
2323                         break;
2324                   case ElementType::SEGMENT: {      // from segment go to top chordrest in segment
2325                         Segment* seg  = toSegment(el);
2326                         // if segment is not chord/rest or grace, move to next chord/rest or grace segment
2327                         if (!seg->isChordRest()) {
2328                               seg = seg->next1(SegmentType::ChordRest);
2329                               if (seg == 0)     // if none found, return failure
2330                                     return 0;
2331                               }
2332                         // segment for sure contains chords/rests,
2333                         int size = int(seg->elist().size());
2334                         // if segment has a chord/rest in original element track, use it
2335                         if (track > -1 && track < size && seg->element(track)) {
2336                               trg  = seg->element(track);
2337                               cr = toChordRest(trg);
2338                               break;
2339                               }
2340                         // if not, get topmost chord/rest
2341                         for (int i = 0; i < size; i++)
2342                               if (seg->element(i)) {
2343                                     trg  = seg->element(i);
2344                                     cr = toChordRest(trg);
2345                                     break;
2346                                     }
2347                         break;
2348                         }
2349                   case ElementType::HBOX: // fallthrough
2350                   case ElementType::VBOX: // fallthrough
2351                   case ElementType::TBOX:
2352                         box = toBox(el);
2353                         break;
2354                   default:                      // on anything else, return failure
2355                         return 0;
2356                   }
2357 
2358             // if something found and command is forward, the element found is the destination
2359             if (trg && cmd == "next-chord") {
2360                   // if chord, go to topmost note
2361                   if (trg->type() == ElementType::CHORD)
2362                         trg = toChord(trg)->upNote();
2363                   setPlayNote(true);
2364                   select(trg, SelectType::SINGLE, 0);
2365                   return trg;
2366                   }
2367             // if no chordrest and no box (frame) found, do nothing
2368             if (!cr && !box)
2369                   return 0;
2370             // if some chordrest found, continue with default processing
2371             }
2372 
2373       Element* el = 0;
2374       Segment* ois = noteEntryMode() ? _is.segment() : nullptr;
2375       Measure* oim = ois ? ois->measure() : nullptr;
2376 
2377       if (cmd == "next-chord" && cr) {
2378             // note input cursor
2379             if (noteEntryMode())
2380                   _is.moveToNextInputPos();
2381 
2382             // selection "cursor"
2383             // find next chordrest, which might be a grace note
2384             // this may override note input cursor
2385             el = nextChordRest(cr);
2386             while (el && el->isRest() && toRest(el)->isGap())
2387                   el = nextChordRest(toChordRest(el));
2388             if (el && noteEntryMode()) {
2389                   // do not use if not in original or new measure (don't skip measures)
2390                   Measure* m = toChordRest(el)->measure();
2391                   Segment* nis = _is.segment();
2392                   Measure* nim = nis ? nis->measure() : nullptr;
2393                   if (m != oim && m != nim)
2394                         el = cr;
2395                   // do not use if new input segment is current cr
2396                   // this means input cursor just caught up to current selection
2397                   else if (cr && nis == cr->segment())
2398                         el = cr;
2399                   }
2400             else if (!el)
2401                   el = cr;
2402             }
2403       else if (cmd == "prev-chord" && cr) {
2404             // note input cursor
2405             if (noteEntryMode() && _is.segment()) {
2406                   Measure* m = _is.segment()->measure();
2407                   Segment* s = _is.segment()->prev1(SegmentType::ChordRest);
2408                   int track = _is.track();
2409                   for (; s; s = s->prev1(SegmentType::ChordRest)) {
2410                         if (s->element(track) || (s->measure() != m && s->rtick().isZero())) {
2411                               if (s->element(track)) {
2412                                     if (s->element(track)->isRest() && toRest(s->element(track))->isGap())
2413                                           continue;
2414                                     }
2415                               break;
2416                               }
2417                         }
2418                   _is.moveInputPos(s);
2419                   }
2420 
2421             // selection "cursor"
2422             // find previous chordrest, which might be a grace note
2423             // this may override note input cursor
2424             el = prevChordRest(cr);
2425             while (el && el->isRest() && toRest(el)->isGap())
2426                   el = prevChordRest(toChordRest(el));
2427             if (el && noteEntryMode()) {
2428                   // do not use if not in original or new measure (don't skip measures)
2429                   Measure* m = toChordRest(el)->measure();
2430                   Segment* nis = _is.segment();
2431                   Measure* nim = nis ? nis->measure() : nullptr;
2432                   if (m != oim && m != nim)
2433                         el = cr;
2434                   // do not use if new input segment is current cr
2435                   // this means input cursor just caught up to current selection
2436                   else if (cr && nis == cr->segment())
2437                         el = cr;
2438                   }
2439             else if (!el)
2440                   el = cr;
2441 
2442             }
2443       else if (cmd == "next-measure") {
2444             if (box && box->nextMeasure() && box->nextMeasure()->first())
2445                   el = box->nextMeasure()->first()->nextChordRest(0, false);
2446             if (cr)
2447                   el = nextMeasure(cr);
2448             if (el && noteEntryMode())
2449                   _is.moveInputPos(el);
2450             }
2451       else if (cmd == "prev-measure") {
2452             if (box && box->prevMeasure() && box->prevMeasure()->first())
2453                   el = box->prevMeasure()->first()->nextChordRest(0, false);
2454             if (cr)
2455                   el = prevMeasure(cr);
2456             if (el && noteEntryMode())
2457                   _is.moveInputPos(el);
2458             }
2459       else if (cmd == "next-system" && cr) {
2460             el = cmdNextPrevSystem(cr, true);
2461             if (noteEntryMode())
2462                   _is.moveInputPos(el);
2463             }
2464       else if (cmd == "prev-system" && cr) {
2465             el = cmdNextPrevSystem(cr, false);
2466             if (noteEntryMode())
2467                   _is.moveInputPos(el);
2468             }
2469       else if (cmd == "next-frame") {
2470             auto measureBase = cr ? cr->measure()->findMeasureBase() : box->findMeasureBase();
2471             el = measureBase ? cmdNextPrevFrame(measureBase, true) : nullptr;
2472             }
2473       else if (cmd == "prev-frame") {
2474             auto measureBase = cr ? cr->measure()->findMeasureBase() : box->findMeasureBase();
2475             el = measureBase ? cmdNextPrevFrame(measureBase, false) : nullptr;
2476             }
2477       else if (cmd == "next-section") {
2478             if (!(el = box))
2479                   el = cr;
2480             el = cmdNextPrevSection(el, true);
2481             }
2482       else if (cmd == "prev-section") {
2483             if (!(el = box))
2484                   el = cr;
2485             el = cmdNextPrevSection(el, false);
2486             }
2487       else if (cmd == "next-track" && cr) {
2488             el = nextTrack(cr);
2489             if (noteEntryMode())
2490                   _is.moveInputPos(el);
2491             }
2492       else if (cmd == "prev-track" && cr) {
2493             el = prevTrack(cr);
2494             if (noteEntryMode())
2495                   _is.moveInputPos(el);
2496             }
2497       else if (cmd == "top-staff") {
2498             el = cr ? cmdTopStaff(cr) : cmdTopStaff();
2499             if (noteEntryMode())
2500                   _is.moveInputPos(el);
2501             }
2502       else if (cmd == "empty-trailing-measure") {
2503             const Measure* ftm = nullptr;
2504             if (!cr)
2505                   ftm = firstTrailingMeasure() ? firstTrailingMeasure() : lastMeasure();
2506             else
2507                   ftm = firstTrailingMeasure(&cr) ? firstTrailingMeasure(&cr) : lastMeasure();
2508             if (ftm) {
2509                   if (score()->styleB(Sid::createMultiMeasureRests) && ftm->hasMMRest())
2510                         ftm = ftm->mmRest1();
2511                   el = !cr ? ftm->first()->nextChordRest(0, false) : ftm->first()->nextChordRest(trackZeroVoice(cr->track()), false);
2512                   }
2513             // Note: Due to the nature of this command as being preparatory for input,
2514             // Note-Entry is activated from within ScoreView::cmd()
2515             _is.moveInputPos(el);
2516             }
2517 
2518       if (el) {
2519             if (el->type() == ElementType::CHORD)
2520                   el = toChord(el)->upNote();       // originally downNote
2521             setPlayNote(true);
2522             if (noteEntryMode()) {
2523                   // if cursor moved into a gap, selection cannot follow
2524                   // only select & play el if it was not already selected (does not normally happen)
2525                   if (_is.cr() || !el->selected())
2526                         select(el, SelectType::SINGLE, 0);
2527                   else
2528                         setPlayNote(false);
2529                   for (MuseScoreView* view : qAsConst(viewer))
2530                         view->moveCursor();
2531                   }
2532             else {
2533                   select(el, SelectType::SINGLE, 0);
2534                   }
2535             }
2536       return el;
2537       }
2538 
2539 //---------------------------------------------------------
2540 //   selectMove
2541 //---------------------------------------------------------
2542 
selectMove(const QString & cmd)2543 Element* Score::selectMove(const QString& cmd)
2544       {
2545       ChordRest* cr;
2546       if (selection().activeCR())
2547             cr = selection().activeCR();
2548       else
2549             cr = selection().lastChordRest();
2550       if (!cr && noteEntryMode())
2551             cr = inputState().cr();
2552       if (!cr)
2553             return 0;
2554 
2555       ChordRest* el = 0;
2556       if (cmd == "select-next-chord")
2557             el = nextChordRest(cr, true);
2558       else if (cmd == "select-prev-chord")
2559             el = prevChordRest(cr, true);
2560       else if (cmd == "select-next-measure")
2561             el = nextMeasure(cr, true, true);
2562       else if (cmd == "select-prev-measure")
2563             el = prevMeasure(cr, true);
2564       else if (cmd == "select-begin-line") {
2565             Measure* measure = cr->segment()->measure()->system()->firstMeasure();
2566             if (!measure)
2567                   return 0;
2568             el = measure->first()->nextChordRest(cr->track());
2569             }
2570       else if (cmd == "select-end-line") {
2571             Measure* measure = cr->segment()->measure()->system()->lastMeasure();
2572             if (!measure)
2573                   return 0;
2574             el = measure->last()->nextChordRest(cr->track(), true);
2575             }
2576       else if (cmd == "select-begin-score") {
2577             Measure* measure = firstMeasureMM();
2578             if (!measure)
2579                   return 0;
2580             el = measure->first()->nextChordRest(cr->track());
2581             }
2582       else if (cmd == "select-end-score") {
2583             Measure* measure = lastMeasureMM();
2584             if (!measure)
2585                   return 0;
2586             el = measure->last()->nextChordRest(cr->track(), true);
2587             }
2588       else if (cmd == "select-staff-above")
2589             el = upStaff(cr);
2590       else if (cmd == "select-staff-below")
2591             el = downStaff(cr);
2592       if (el)
2593             select(el, SelectType::RANGE, el->staffIdx());
2594       return el;
2595       }
2596 
2597 //---------------------------------------------------------
2598 //   cmdMirrorNoteHead
2599 //---------------------------------------------------------
2600 
cmdMirrorNoteHead()2601 void Score::cmdMirrorNoteHead()
2602       {
2603       const QList<Element*>& el = selection().elements();
2604       for (Element* e : el) {
2605             if (e->isNote()) {
2606                   Note* note = toNote(e);
2607                   if (note->staff() && note->staff()->isTabStaff(note->chord()->tick()))
2608                         e->undoChangeProperty(Pid::GHOST, !note->ghost());
2609                   else {
2610                         MScore::DirectionH d = note->userMirror();
2611                         if (d == MScore::DirectionH::AUTO)
2612                               d = note->chord()->up() ? MScore::DirectionH::RIGHT : MScore::DirectionH::LEFT;
2613                         else
2614                               d = d == MScore::DirectionH::LEFT ? MScore::DirectionH::RIGHT : MScore::DirectionH::LEFT;
2615                         undoChangeUserMirror(note, d);
2616                         }
2617                   }
2618             else if (e->isHairpinSegment()) {
2619                   Hairpin* h = toHairpinSegment(e)->hairpin();
2620                   HairpinType st = h->hairpinType();
2621                   switch (st)  {
2622                         case HairpinType::CRESC_HAIRPIN:
2623                               st = HairpinType::DECRESC_HAIRPIN;
2624                               break;
2625                         case HairpinType::DECRESC_HAIRPIN:
2626                               st = HairpinType::CRESC_HAIRPIN;
2627                               break;
2628                         case HairpinType::CRESC_LINE:
2629                               st = HairpinType::DECRESC_LINE;
2630                               break;
2631                         case HairpinType::DECRESC_LINE:
2632                               st = HairpinType::CRESC_LINE;
2633                               break;
2634                         case HairpinType::INVALID:
2635                               break;
2636                         }
2637                   h->undoChangeProperty(Pid::HAIRPIN_TYPE, int(st));
2638                   }
2639             }
2640       }
2641 
2642 //---------------------------------------------------------
2643 //   cmdIncDecDuration
2644 //     When stepDotted is false and nSteps is 1 or -1, will halve or double the duration
2645 //     When stepDotted is true, will step by nearest dotted or undotted note
2646 //---------------------------------------------------------
2647 
cmdIncDecDuration(int nSteps,bool stepDotted)2648 void Score::cmdIncDecDuration(int nSteps, bool stepDotted)
2649       {
2650       Element* el = selection().element();
2651       if (el == 0)
2652             return;
2653       if (el->isNote())
2654             el = el->parent();
2655       if (!el->isChordRest())
2656             return;
2657 
2658       ChordRest* cr = toChordRest(el);
2659 
2660       // if measure rest is selected as input, then the correct initialDuration will be the
2661       // duration of the measure's time signature, else is just the input state's duration
2662       TDuration initialDuration = (cr->durationType() == TDuration::DurationType::V_MEASURE) ? TDuration(cr->measure()->timesig()) : _is.duration();
2663       TDuration d = initialDuration.shiftRetainDots(nSteps, stepDotted);
2664       if (!d.isValid())
2665             return;
2666       if (cr->isChord() && (toChord(cr)->noteType() != NoteType::NORMAL)) {
2667             //
2668             // handle appoggiatura and acciaccatura
2669             //
2670             undoChangeChordRestLen(cr, d);
2671             }
2672       else
2673             changeCRlen(cr, d);
2674       _is.setDuration(d);
2675       nextInputPos(cr, false);
2676       }
2677 
2678 //---------------------------------------------------------
2679 //   cmdAddBracket
2680 //---------------------------------------------------------
2681 
cmdAddBracket()2682 void Score::cmdAddBracket()
2683       {
2684       for (Element* el : selection().elements()) {
2685             if (el->type() == ElementType::ACCIDENTAL) {
2686                   Accidental* acc = toAccidental(el);
2687                   acc->undoChangeProperty(Pid::ACCIDENTAL_BRACKET, int(AccidentalBracket::BRACKET));
2688                   }
2689             }
2690       }
2691 
2692 //---------------------------------------------------------
2693 //   cmdAddParentheses
2694 //---------------------------------------------------------
2695 
cmdAddParentheses()2696 void Score::cmdAddParentheses()
2697       {
2698       for (Element* el : selection().elements()) {
2699             if (el->type() == ElementType::NOTE) {
2700                   Note* n = toNote(el);
2701                   n->addParentheses();
2702                   }
2703             else if (el->type() == ElementType::ACCIDENTAL) {
2704                   Accidental* acc = toAccidental(el);
2705                   acc->undoChangeProperty(Pid::ACCIDENTAL_BRACKET, int(AccidentalBracket::PARENTHESIS));
2706                   }
2707             else if (el->type() == ElementType::HARMONY) {
2708                   Harmony* h = toHarmony(el);
2709                   h->setLeftParen(true);
2710                   h->setRightParen(true);
2711                   h->render();
2712                   }
2713             else if (el->type() == ElementType::TIMESIG) {
2714                   TimeSig* ts = toTimeSig(el);
2715                   ts->setLargeParentheses(true);
2716                   }
2717             }
2718       }
2719 
2720 //---------------------------------------------------------
2721 //   cmdAddBraces
2722 //---------------------------------------------------------
2723 
cmdAddBraces()2724 void Score::cmdAddBraces()
2725       {
2726       for (Element* el : selection().elements()) {
2727             if (el->type() == ElementType::ACCIDENTAL) {
2728                   Accidental* acc = toAccidental(el);
2729                   acc->undoChangeProperty(Pid::ACCIDENTAL_BRACKET, int(AccidentalBracket::BRACE));
2730                   }
2731             }
2732       }
2733 
2734 //---------------------------------------------------------
2735 //   cmdMoveRest
2736 //---------------------------------------------------------
2737 
cmdMoveRest(Rest * rest,Direction dir)2738 void Score::cmdMoveRest(Rest* rest, Direction dir)
2739       {
2740       QPointF pos(rest->offset());
2741       if (dir == Direction::UP)
2742             pos.ry() -= spatium();
2743       else if (dir == Direction::DOWN)
2744             pos.ry() += spatium();
2745       rest->undoChangeProperty(Pid::OFFSET, pos);
2746       }
2747 
2748 //---------------------------------------------------------
2749 //   cmdMoveLyrics
2750 //---------------------------------------------------------
2751 
cmdMoveLyrics(Lyrics * lyrics,Direction dir)2752 void Score::cmdMoveLyrics(Lyrics* lyrics, Direction dir)
2753       {
2754       int verse = lyrics->no() + (dir == Direction::UP ? -1 : 1);
2755       if (verse < 0)
2756             return;
2757       lyrics->undoChangeProperty(Pid::VERSE, verse);
2758       }
2759 
2760 //---------------------------------------------------------
2761 //   cmdInsertClef
2762 //---------------------------------------------------------
2763 
cmdInsertClef(ClefType type)2764 void Score::cmdInsertClef(ClefType type)
2765       {
2766       undoChangeClef(staff(inputTrack()/VOICES), inputState().cr(), type);
2767       }
2768 
2769 //---------------------------------------------------------
2770 //   cmdInsertClef
2771 //    insert clef before cr
2772 //---------------------------------------------------------
2773 
cmdInsertClef(Clef * clef,ChordRest * cr)2774 void Score::cmdInsertClef(Clef* clef, ChordRest* cr)
2775       {
2776       undoChangeClef(cr->staff(), cr, clef->clefType());
2777       delete clef;
2778       }
2779 
2780 //---------------------------------------------------------
2781 //   cmdAddGrace
2782 ///   adds grace note of specified type to selected notes
2783 //---------------------------------------------------------
2784 
cmdAddGrace(NoteType graceType,int duration)2785 void Score::cmdAddGrace (NoteType graceType, int duration)
2786       {
2787       const QList<Element*> copyOfElements = selection().elements();
2788       for (Element* e : copyOfElements) {
2789             if (e->type() == ElementType::NOTE) {
2790                   Note* n = toNote(e);
2791                   setGraceNote(n->chord(), n->pitch(), graceType, duration);
2792                   }
2793             }
2794       }
2795 
2796 //---------------------------------------------------------
2797 //   cmdExplode
2798 ///   explodes contents of top selected staff into subsequent staves
2799 //---------------------------------------------------------
2800 
cmdExplode()2801 void Score::cmdExplode()
2802       {
2803       if (!selection().isRange())
2804             return;
2805 
2806       int srcStaff  = selection().staffStart();
2807       int lastStaff = selection().staffEnd();
2808       int srcTrack  = srcStaff * VOICES;
2809 
2810       // reset selection to top staff only
2811       // force complete measures
2812       Segment* startSegment = selection().startSegment();
2813       Segment* endSegment = selection().endSegment();
2814       Measure* startMeasure = startSegment->measure();
2815       Measure* endMeasure = endSegment ? endSegment->measure() : lastMeasure();
2816 
2817       Fraction lTick = endMeasure->endTick();
2818       bool voice = false;
2819 
2820       for (Measure* m = startMeasure; m && m->tick() != lTick; m = m->nextMeasure()) {
2821             if (m->hasVoices(srcStaff)) {
2822                   voice = true;
2823                   break;
2824                   }
2825             }
2826       if (! voice) {
2827             // force complete measures
2828             deselectAll();
2829             select(startMeasure, SelectType::RANGE, srcStaff);
2830             select(endMeasure, SelectType::RANGE, srcStaff);
2831             startSegment = selection().startSegment();
2832             endSegment = selection().endSegment();
2833             if (srcStaff == lastStaff - 1) {
2834                   // only one staff was selected up front - determine number of staves
2835                   // loop through all chords looking for maximum number of notes
2836                   int n = 0;
2837                   for (Segment* s = startSegment; s && s != endSegment; s = s->next1()) {
2838                         Element* e = s->element(srcTrack);
2839                         if (e && e->type() == ElementType::CHORD) {
2840                               Chord* c = toChord(e);
2841                               n = qMax(n, int(c->notes().size()));
2842                               }
2843                         }
2844                   lastStaff = qMin(nstaves(), srcStaff + n);
2845                   }
2846 
2847             const QByteArray mimeData(selection().mimeData());
2848             // copy to all destination staves
2849             Segment* firstCRSegment = startMeasure->tick2segment(startMeasure->tick());
2850             for (int i = 1; srcStaff + i < lastStaff; ++i) {
2851                   int track = (srcStaff + i) * VOICES;
2852                   ChordRest* cr = toChordRest(firstCRSegment->element(track));
2853                   if (cr) {
2854                         XmlReader e(mimeData);
2855                         e.setPasteMode(true);
2856                         pasteStaff(e, cr->segment(), cr->staffIdx());
2857                         }
2858                   }
2859 
2860             // loop through each staff removing all but one note from each chord
2861             for (int i = 0; srcStaff + i < lastStaff; ++i) {
2862                   int track = (srcStaff + i) * VOICES;
2863                   for (Segment* s = startSegment; s && s != endSegment; s = s->next1()) {
2864                         Element* e = s->element(track);
2865                         if (e && e->type() == ElementType::CHORD) {
2866                               Chord* c = toChord(e);
2867                               std::vector<Note*> notes = c->notes();
2868                               int nnotes = int(notes.size());
2869                               // keep note "i" from top, which is backwards from nnotes - 1
2870                               // reuse notes if there are more instruments than notes
2871                               int stavesPerNote = qMax((lastStaff - srcStaff) / nnotes, 1);
2872                               int keepIndex = qMax(nnotes - 1 - (i / stavesPerNote), 0);
2873                               Note* keepNote = c->notes()[keepIndex];
2874                               foreach (Note* n, notes) {
2875                                     if (n != keepNote)
2876                                           undoRemoveElement(n);
2877                                     }
2878                               }
2879                         }
2880                   }
2881             }
2882       else {
2883             int sTracks[VOICES];
2884             int dTracks[VOICES];
2885             if (srcStaff == lastStaff - 1)
2886                   lastStaff = qMin(nstaves(), srcStaff + VOICES);
2887 
2888             for (int i = 0; i < VOICES; i++) {
2889                   sTracks[i] = -1;
2890                   dTracks[i] = -1;
2891                   }
2892             int full = 0;
2893 
2894             for (Segment* seg = startSegment; seg && seg->tick() < lTick; seg = seg->next1()) {
2895                   for (int i = srcTrack; i < srcTrack + VOICES && full != VOICES; i++) {
2896                         bool t = true;
2897                         for (int j = 0; j < VOICES; j++) {
2898                               if (i == sTracks[j]) {
2899                                     t = false;
2900                                     break;
2901                                     }
2902                               }
2903 
2904                         if (!seg->measure()->hasVoice(i) || seg->measure()->isOnlyRests(i) || !t)
2905                               continue;
2906                         sTracks[full] = i;
2907 
2908                         for(int j = srcTrack + full * VOICES; j < lastStaff * VOICES; j++) {
2909                               if (i == j) {
2910                                     dTracks[full] = j;
2911                                     break;
2912                                     }
2913                               for(Measure* m = seg->measure(); m && m->tick() < lTick; m = m->nextMeasure()) {
2914                                     if (!m->hasVoice(j) || (m->hasVoice(j) && m->isOnlyRests(j)))
2915                                           dTracks[full] = j;
2916                                     else {
2917                                           dTracks[full] = -1;
2918                                           break;
2919                                           }
2920                                     }
2921                               if (dTracks[full] != -1)
2922                                     break;
2923                               }
2924                         full++;
2925                         }
2926                   }
2927 
2928             for (int i = srcTrack, j = 0; i < lastStaff * VOICES && j < VOICES ; i += VOICES, j++) {
2929                   int strack = sTracks[j % VOICES];
2930                   int dtrack = dTracks[j % VOICES];
2931                   if (strack != -1 && strack != dtrack && dtrack != -1)
2932                         undo(new CloneVoice(startSegment, lTick, startSegment, strack, dtrack, -1, false));
2933                   }
2934             }
2935 
2936       // select exploded region
2937       deselectAll();
2938       select(startMeasure, SelectType::RANGE, srcStaff);
2939       select(endMeasure, SelectType::RANGE, lastStaff - 1);
2940       }
2941 
2942 //---------------------------------------------------------
2943 //   cmdImplode
2944 ///   implodes contents of selected staves into top staff
2945 ///   for single staff, merge voices
2946 //---------------------------------------------------------
2947 
cmdImplode()2948 void Score::cmdImplode()
2949       {
2950       if (!selection().isRange())
2951             return;
2952 
2953       int dstStaff   = selection().staffStart();
2954       int endStaff   = selection().staffEnd();
2955       int dstTrack   = dstStaff * VOICES;
2956       int startTrack = dstStaff * VOICES;
2957       int endTrack   = endStaff * VOICES;
2958       Segment* startSegment = selection().startSegment();
2959       Segment* endSegment = selection().endSegment();
2960       Measure* startMeasure = startSegment->measure();
2961       Measure* endMeasure = endSegment ? endSegment->measure() : lastMeasure();
2962       Fraction startTick       = startSegment->tick();
2963       Fraction endTick         = endSegment ? endSegment->tick() : lastMeasure()->endTick();
2964       Q_ASSERT(startMeasure && endMeasure);
2965 
2966       // if single staff selected, combine voices
2967       // otherwise combine staves
2968       if (dstStaff == endStaff - 1) {
2969 
2970             // loop through segments adding notes to chord on top staff
2971             for (Segment* s = startSegment; s && s != endSegment; s = s->next1()) {
2972                   if (!s->isChordRestType())
2973                         continue;
2974                   Element* dst = s->element(dstTrack);
2975                   if (dst && dst->isChord()) {
2976                         Chord* dstChord = toChord(dst);
2977                         // see if we are tying in to this chord
2978                         Chord* tied = 0;
2979                         for (Note* n : dstChord->notes()) {
2980                               if (n->tieBack()) {
2981                                     tied = n->tieBack()->startNote()->chord();
2982                                     break;
2983                                     }
2984                               }
2985                         // loop through each subsequent staff (or track within staff)
2986                         // looking for notes to add
2987                         for (int srcTrack = startTrack + 1; srcTrack < endTrack; srcTrack++) {
2988                               Element* src = s->element(srcTrack);
2989                               if (src && src->isChord()) {
2990                                     Chord* srcChord = toChord(src);
2991                                     // when combining voices, skip if not same duration
2992                                     if (srcChord->ticks() != dstChord->ticks())
2993                                           continue;
2994                                     // add notes
2995                                     for (Note* n : srcChord->notes()) {
2996                                           NoteVal nv(n->pitch());
2997                                           nv.tpc1 = n->tpc1();
2998                                           // skip duplicates
2999                                           if (dstChord->findNote(nv.pitch))
3000                                                 continue;
3001                                           Note* nn = addNote(dstChord, nv);
3002                                           // add tie to this note if original chord was tied
3003                                           if (tied) {
3004                                                 // find note to tie to
3005                                                 for (Note *tn : tied->notes()) {
3006                                                       if (nn->pitch() == tn->pitch() && nn->tpc() == tn->tpc() && !tn->tieFor()) {
3007                                                             // found note to tie
3008                                                             Tie* tie = new Tie(this);
3009                                                             tie->setStartNote(tn);
3010                                                             tie->setEndNote(nn);
3011                                                             tie->setTick(tie->startNote()->tick());
3012                                                             tie->setTick2(tie->endNote()->tick());
3013                                                             tie->setTrack(tn->track());
3014                                                             undoAddElement(tie);
3015                                                             }
3016                                                       }
3017                                                 }
3018                                           }
3019                                     }
3020                               // delete chordrest from source track if possible
3021                               if (src && src->voice())
3022                                     undoRemoveElement(src);
3023                               }
3024                         }
3025                   // TODO - use first voice that actually has a note and implode remaining voices on it?
3026                   // see https://musescore.org/en/node/174111
3027                   else if (dst) {
3028                         // destination track has something, but it isn't a chord
3029                         // remove rests from other voices if in "voice mode"
3030                         for (int i = 1; i < VOICES; ++i) {
3031                               Element* e = s->element(dstTrack + i);
3032                               if (e && e->isRest())
3033                                     undoRemoveElement(e);
3034                               }
3035                         }
3036                   }
3037             // delete orphaned spanners (TODO: figure out solution to reconnect orphaned spanners to their cloned notes)
3038             checkSpanner(startTick, endTick);
3039             }
3040       else {
3041             int tracks[VOICES];
3042             for (int i = 0; i < VOICES; i++)
3043                   tracks[i] = -1;
3044             int full = 0;
3045 
3046             // identify tracks to combine, storing the source track numbers in tracks[]
3047             // first four non-empty tracks to win
3048             for (int track = startTrack; track < endTrack && full < VOICES; ++track) {
3049                   Measure* m = startMeasure;
3050                   do {
3051                         if (m->hasVoice(track) && !m->isOnlyRests(track)) {
3052                               tracks[full++] = track;
3053                               break;
3054                               }
3055                         } while ((m != endMeasure) && (m = m->nextMeasure()));
3056                   }
3057 
3058             // clone source tracks into destination
3059             for (int i = dstTrack; i < dstTrack + VOICES; i++) {
3060                   int strack = tracks[i % VOICES];
3061                   if (strack != -1 && strack != i) {
3062                         undo( new CloneVoice(startSegment, endTick, startSegment, strack, i, i, false));
3063                         }
3064                   }
3065             }
3066 
3067       // select destination staff only
3068       deselectAll();
3069       select(startMeasure, SelectType::RANGE, dstStaff);
3070       select(endMeasure, SelectType::RANGE, dstStaff);
3071       }
3072 
3073 //---------------------------------------------------------
3074 //   cmdSlashFill
3075 ///   fills selected region with slashes
3076 //---------------------------------------------------------
3077 
cmdSlashFill()3078 void Score::cmdSlashFill()
3079       {
3080       int startStaff = selection().staffStart();
3081       int endStaff = selection().staffEnd();
3082       Segment* startSegment = selection().startSegment();
3083       if (!startSegment) // empty score?
3084             return;
3085 
3086       Segment* endSegment = selection().endSegment();
3087 
3088       // operate on measures underlying mmrests
3089       if (startSegment && startSegment->measure() && startSegment->measure()->isMMRest())
3090             startSegment = startSegment->measure()->mmRestFirst()->first();
3091       if (endSegment && endSegment->measure() && endSegment->measure()->isMMRest())
3092             endSegment = endSegment->measure()->mmRestLast()->last();
3093 
3094       Fraction endTick = endSegment ? endSegment->tick() : lastSegment()->tick() + Fraction::fromTicks(1);
3095       Chord* firstSlash = 0;
3096       Chord* lastSlash = 0;
3097 
3098       // loop through staves in selection
3099       for (int staffIdx = startStaff; staffIdx < endStaff; ++staffIdx) {
3100             int track = staffIdx * VOICES;
3101             int voice = -1;
3102             // loop through segments adding slashes on each beat
3103             for (Segment* s = startSegment; s && s->tick() < endTick; s = s->next1()) {
3104                   if (s->segmentType() != SegmentType::ChordRest)
3105                         continue;
3106                   // determine beat type based on time signature
3107                   int d = s->measure()->timesig().denominator();
3108                   int n = (d > 4 && s->measure()->timesig().numerator() % 3 == 0) ? 3 : 1;
3109                   Fraction f(n, d);
3110                   // skip over any leading segments before next (first) beat
3111                   if (s->rtick().ticks() % f.ticks())
3112                         continue;
3113                   // determine voice to use - first available voice for this measure / staff
3114                   if (voice == -1 || s->rtick().isZero()) {
3115                         bool needGap[VOICES];
3116                         for (voice = 0; voice < VOICES; ++voice) {
3117                               needGap[voice] = false;
3118                               ChordRest* cr = toChordRest(s->element(track + voice));
3119                               // no chordrest == treat as ordinary rest for purpose of determining availbility of voice
3120                               // but also, we will need to make a gap for this voice if we do end up choosing it
3121                               if (!cr)
3122                                     needGap[voice] = true;
3123                               // chord == keep looking for an available voice
3124                               else if (cr->type() == ElementType::CHORD)
3125                                     continue;
3126                               // full measure rest == OK to use voice
3127                               else if (cr->durationType() == TDuration::DurationType::V_MEASURE)
3128                                     break;
3129                               // no chordrest or ordinary rest == OK to use voice
3130                               // if there are nothing but rests for duration of measure / selection
3131                               bool ok = true;
3132                               for (Segment* ns = s->next(SegmentType::ChordRest); ns && ns != endSegment; ns = ns->next(SegmentType::ChordRest)) {
3133                                     ChordRest* ncr = toChordRest(ns->element(track + voice));
3134                                     if (ncr && ncr->type() == ElementType::CHORD) {
3135                                           ok = false;
3136                                           break;
3137                                           }
3138                                     }
3139                               if (ok)
3140                                     break;
3141                               }
3142                         // no available voices, just use voice 0
3143                         if (voice == VOICES)
3144                               voice = 0;
3145                         // no cr was found in segment for this voice, so make gap
3146                         if (needGap[voice])
3147                               makeGapVoice(s, track + voice, f, s->tick());
3148                         }
3149                   // construct note
3150                   int line = 0;
3151                   bool error = false;
3152                   NoteVal nv;
3153                   if (staff(staffIdx)->staffType(s->tick())->group() == StaffGroup::TAB)
3154                         line = staff(staffIdx)->lines(s->tick()) / 2;
3155                   else
3156                         line = staff(staffIdx)->middleLine(s->tick());     // staff(staffIdx)->lines() - 1;
3157                   if (staff(staffIdx)->staffType(s->tick())->group() == StaffGroup::PERCUSSION) {
3158                         nv.pitch = 0;
3159                         nv.headGroup = NoteHead::Group::HEAD_SLASH;
3160                         }
3161                   else {
3162                         Position p;
3163                         p.segment = s;
3164                         p.staffIdx = staffIdx;
3165                         p.line = line;
3166                         p.fret = FRET_NONE;
3167                         _is.setRest(false);     // needed for tab
3168                         nv = noteValForPosition(p, AccidentalType::NONE, error);
3169                         }
3170                   if (error)
3171                         continue;
3172                   // insert & turn into slash
3173                   s = setNoteRest(s, track + voice, nv, f);
3174                   Chord* c = toChord(s->element(track + voice));
3175                   if (c->links()) {
3176                         for (ScoreElement* e : *c->links()) {
3177                               Chord* lc = toChord(e);
3178                               lc->setSlash(true, true);
3179                               }
3180                         }
3181                   else
3182                         c->setSlash(true, true);
3183                   lastSlash = c;
3184                   if (!firstSlash)
3185                         firstSlash = c;
3186                   }
3187             }
3188 
3189       // re-select the slashes
3190       deselectAll();
3191       if (firstSlash && lastSlash) {
3192             select(firstSlash, SelectType::RANGE);
3193             select(lastSlash, SelectType::RANGE);
3194             }
3195       }
3196 
3197 //---------------------------------------------------------
3198 //   cmdSlashRhythm
3199 ///   converts rhythms in selected region to slashes
3200 //---------------------------------------------------------
3201 
cmdSlashRhythm()3202 void Score::cmdSlashRhythm()
3203       {
3204       QList<Chord*> chords;
3205       // loop through all notes in selection
3206       foreach (Element* e, selection().elements()) {
3207             if (e->voice() >= 2 && e->isRest()) {
3208                   Rest* r = toRest(e);
3209                   if (r->links()) {
3210                         for (ScoreElement* se : *r->links()) {
3211                               Rest* lr = toRest(se);
3212                               lr->setAccent(!lr->accent());
3213                               }
3214                         }
3215                   else
3216                         r->setAccent(!r->accent());
3217                   continue;
3218                   }
3219             else if (e->isNote()) {
3220                   Note* n = toNote(e);
3221                   if (n->noteType() != NoteType::NORMAL)
3222                         continue;
3223                   Chord* c = n->chord();
3224                   // check for duplicates (chords with multiple notes)
3225                   if (chords.contains(c))
3226                         continue;
3227                   chords.append(c);
3228                   // toggle slash setting
3229                   if (c->links()) {
3230                         for (ScoreElement* se : *c->links()) {
3231                               Chord* lc = toChord(se);
3232                               lc->setSlash(!lc->slash(), false);
3233                               }
3234                         }
3235                   else
3236                         c->setSlash(!c->slash(), false);
3237                   }
3238             }
3239       }
3240 
3241 //---------------------------------------------------------
3242 //   cmdRealizeChordSymbols
3243 ///   Realize selected chord symbols into notes on the staff.
3244 ///
3245 ///   If a voicing and duration type are specified, the
3246 ///   harmony voicing settings will be overridden by the
3247 ///   passed parameters. Otherwise, the settings set on the
3248 ///   harmony object will be used.
3249 //---------------------------------------------------------
3250 
cmdRealizeChordSymbols(bool literal,Voicing voicing,HDuration durationType)3251 void Score::cmdRealizeChordSymbols(bool literal, Voicing voicing, HDuration durationType)
3252       {
3253       const QList<Element*> elist = selection().elements();
3254       for (Element* e : elist) {
3255             if (!e->isHarmony())
3256                   continue;
3257             Harmony* h = toHarmony(e);
3258             if (!h->isRealizable())
3259                   continue;
3260             RealizedHarmony r = h->getRealizedHarmony();
3261             Segment* seg = h->parent()->isSegment() ? toSegment(h->parent()) : toSegment(h->parent()->parent());
3262             Fraction tick = seg->tick();
3263             Fraction duration = r.getActualDuration(tick.ticks(), durationType);
3264             bool concertPitch = styleB(Sid::concertPitch);
3265 
3266             Chord* chord = new Chord(this); //chord template
3267             chord->setTrack(h->track()); //set track so notes have a track to sit on
3268 
3269             //create chord from notes
3270             RealizedHarmony::PitchMap notes;
3271             if (voicing == Voicing::INVALID || durationType == HDuration::INVALID)
3272                   notes = r.notes(); //no override, just use notes from realize harmony
3273             else {
3274                   //generate notes list based on overridden settings
3275                   int offset = 0;
3276                   Interval interval = h->staff()->part()->instrument(h->tick())->transpose();
3277                   if (!concertPitch)
3278                         offset = interval.chromatic;
3279                   notes = r.generateNotes(h->rootTpc(), h->baseTpc(),
3280                         literal, voicing, offset);
3281                   }
3282             RealizedHarmony::PitchMapIterator i(notes); //add notes to chord
3283             while (i.hasNext()) {
3284                   i.next();
3285                   Note* note = new Note(this);
3286                   NoteVal nval;
3287                   nval.pitch = i.key();
3288                   if (concertPitch)
3289                         nval.tpc1 = i.value();
3290                   else
3291                         nval.tpc2 = i.value();
3292                   chord->add(note); //add note first to set track and such
3293                   note->setNval(nval, tick);
3294                   }
3295 
3296             setChord(seg, h->track(), chord, duration); //add chord using template
3297             delete chord;
3298             }
3299       }
3300 
3301 //---------------------------------------------------------
3302 //   setChord
3303 //    return segment of last created chord
3304 //---------------------------------------------------------
setChord(Segment * segment,int track,Chord * chordTemplate,Fraction dur,Direction stemDirection)3305 Segment* Score::setChord(Segment* segment, int track, Chord* chordTemplate, Fraction dur, Direction stemDirection)
3306       {
3307       Q_ASSERT(segment->segmentType() == SegmentType::ChordRest);
3308 
3309       Fraction tick = segment->tick();
3310       Chord* nr     = 0; //current added chord used so we can select the last added chord and so we can apply ties
3311       std::vector<Tie*> tie(chordTemplate->notes().size()); //keep pointer to a tie for each note in the chord in case we need to tie notes
3312       ChordRest* cr = toChordRest(segment->element(track)); //chord rest under the segment for the specified track
3313 
3314       bool addTie = false;
3315 
3316       Measure* measure = 0;
3317       //keep creating chords and tieing them until we created the full duration asked for (dur)
3318       for (;;) {
3319             if (track % VOICES)
3320                   expandVoice(segment, track);
3321 
3322             Tuplet* t = cr ? cr->tuplet() : 0;
3323             Fraction tDur = segment->ticks();
3324             Segment* seg = segment->next();
3325 
3326             //we need to get a correct subduration so that makeGap can function properly
3327             //since makeGap() takes "normal" duration rather than actual length
3328             while (seg) {
3329                   if (seg->segmentType() == SegmentType::ChordRest) {
3330                         //design choice made to keep multiple notes across a tuplet as tied single notes rather than combining them
3331                         //since it's arguably more readable, but the other code is still here (commented)
3332                         ChordRest* testCr = toChordRest(seg->element(track));
3333 
3334                         //code here allows us to combine tuplet realization together which I have opted not to do for readability (of the music)
3335                         //if (!!t ^ (testCr && testCr->tuplet())) //stop if we started with a tuplet and reach something that's not a tuplet,
3336                         //      break;                          //or start with not a tuplet and reach a tuplet
3337 
3338                         if (testCr && testCr->tuplet()) //stop on tuplet
3339                               break;
3340                         tDur += seg->ticks();
3341                         }
3342                   if (tDur >= dur) { //do not go further than the duration asked for
3343                         tDur = dur;
3344                         break;
3345                         }
3346                   seg = seg->next(); //iterate only across measure (hence usage of next() rather than next1())
3347                   }
3348             if (t)
3349                   tDur *= t->ratio(); //scale by tuplet ratio to get "normal" length rather than actual length when dealing with tuplets
3350 
3351             // the returned gap ends at the measure boundary or at tuplet end
3352             Fraction dd = makeGap(segment, track, tDur, t);
3353 
3354             if (dd.isZero()) {
3355                   qDebug("cannot get gap at %d type: %d/%d", tick.ticks(), dur.numerator(),
3356                      dur.denominator());
3357                   break;
3358                   }
3359 
3360             measure = segment->measure();
3361             std::vector<TDuration> dl = toDurationList(dd, true);
3362             size_t n = dl.size();
3363             //add chord, tieing when necessary within measure
3364             for (size_t i = 0; i < n; ++i) {
3365                   const TDuration& d = dl[i];
3366 
3367                   //create new chord from template and add it
3368                   Chord* chord = new Chord(*chordTemplate);
3369                   nr = chord;
3370 
3371                   chord->setTrack(track);
3372                   chord->setDurationType(d);
3373                   chord->setTicks(d.fraction());
3374                   chord->setStemDirection(stemDirection);
3375                   chord->setTuplet(t);
3376                   undoAddCR(chord, measure, tick);
3377                   //if there is something to tie, complete tie backwards
3378                   //and add the tie to score
3379                   const std::vector<Note*> notes = chord->notes();
3380                   if (addTie) {
3381                         for (size_t j = 0; j < notes.size(); ++j) {
3382                               tie[j]->setEndNote(notes[j]);
3383                               notes[j]->setTieBack(tie[j]);
3384                               undoAddElement(tie[j]);
3385                               }
3386                         addTie = false;
3387                         }
3388                   //if we're not the last element in the duration list,
3389                   //set tie forward
3390                   if (i+1 < n) {
3391                         for (size_t j = 0; j < notes.size(); ++j) {
3392                               tie[j] = new Tie(this);
3393                               tie[j]->setStartNote(notes[j]);
3394                               tie[j]->setTick(tie[j]->startNote()->tick());
3395                               tie[j]->setTrack(track);
3396                               notes[j]->setTieFor(tie[j]);
3397                               addTie = true;
3398                               }
3399                         }
3400                   setPlayChord(true);
3401                   segment = chord->segment();
3402                   tick += chord->actualTicks();
3403                   }
3404 
3405             //subtract the duration already realized and move on
3406             if (t)
3407                   dur -= dd / t->ratio();
3408             else
3409                   dur -= dd;
3410             //we are done when there is no duration left to realize
3411             if (dur.isZero())
3412                   break;
3413 
3414             //go to next segment unless we are at the score (which means we will just be done there)
3415             Segment* nseg = tick2segment(tick, false, SegmentType::ChordRest);
3416             if (nseg == 0) {
3417                   qDebug("reached end of score");
3418                   break;
3419                   }
3420             segment = nseg;
3421 
3422             cr = toChordRest(segment->element(track));
3423 
3424             if (!cr) {
3425                   if (track % VOICES)
3426                         cr = addRest(segment, track, TDuration(TDuration::DurationType::V_MEASURE), 0);
3427                   else {
3428                         qDebug("no rest in voice 0");
3429                         break;
3430                         }
3431                   }
3432             //
3433             //  Note does not fit on current measure, create Tie to
3434             //  next part of note
3435             std::vector<Note*> notes = nr->notes();
3436             for (size_t i = 0; i < notes.size(); ++i) {
3437                   tie[i] = new Tie(this);
3438                   tie[i]->setStartNote(notes[i]);
3439                   tie[i]->setTick(tie[i]->startNote()->tick());
3440                   tie[i]->setTrack(notes[i]->track());
3441                   notes[i]->setTieFor(tie[i]);
3442                   }
3443             }
3444       if (!tie.empty())
3445             connectTies();
3446       if (nr)
3447             select(nr, SelectType::SINGLE, 0);
3448       return segment;
3449       }
3450 
3451 //---------------------------------------------------------
3452 //   cmdResequenceRehearsalMarks
3453 ///   resequences rehearsal marks within a range selection
3454 ///   or, if nothing is selected, the entire score
3455 //---------------------------------------------------------
3456 
cmdResequenceRehearsalMarks()3457 void Score::cmdResequenceRehearsalMarks()
3458       {
3459       bool noSelection = !selection().isRange();
3460 
3461       if (noSelection)
3462             cmdSelectAll();
3463       else if (!selection().isRange())
3464             return;
3465 
3466       RehearsalMark* last = 0;
3467       for (Segment* s = selection().startSegment(); s && s != selection().endSegment(); s = s->next1()) {
3468             for (Element* e : s->annotations()) {
3469                   if (e->type() == ElementType::REHEARSAL_MARK) {
3470                         RehearsalMark* rm = toRehearsalMark(e);
3471                         if (last) {
3472                               QString rmText = nextRehearsalMarkText(last, rm);
3473                               for (ScoreElement* le : rm->linkList())
3474                                     le->undoChangeProperty(Pid::TEXT, rmText);
3475                               }
3476                         last = rm;
3477                         }
3478                   }
3479             }
3480 
3481       if (noSelection)
3482             deselectAll();
3483       }
3484 
3485 //---------------------------------------------------------
3486 //   addRemoveBreaks
3487 //    interval lock
3488 //    0        false    remove all linebreaks
3489 //    > 0      false    add linebreak every interval measure
3490 //    d.c.     true     add linebreak at every system end
3491 //---------------------------------------------------------
3492 
addRemoveBreaks(int interval,bool lock)3493 void Score::addRemoveBreaks(int interval, bool lock)
3494       {
3495       Segment* startSegment = selection().startSegment();
3496       if (!startSegment) // empty score?
3497             return;
3498       Segment* endSegment   = selection().endSegment();
3499       Measure* startMeasure = startSegment->measure();
3500       Measure* endMeasure   = endSegment ? endSegment->measure() : lastMeasureMM();
3501       Measure* lastMeasure  = lastMeasureMM();
3502 
3503       // loop through measures in selection
3504       // count mmrests as a single measure
3505       int count = 0;
3506       for (Measure* mm = startMeasure; mm; mm = mm->nextMeasureMM()) {
3507 
3508             // even though we are counting mmrests as a single measure,
3509             // we need to find last real measure within mmrest for the actual break
3510             Measure* m = mm->isMMRest() ? mm->mmRestLast() : mm;
3511 
3512             if (lock) {
3513                   // skip last measure of score
3514                   if (mm == lastMeasure)
3515                         break;
3516                   // skip if it already has a break
3517                   if (m->lineBreak() || m->pageBreak())
3518                         continue;
3519                   // add break if last measure of system
3520                   if (mm->system() && mm->system()->lastMeasure() == mm)
3521                         m->undoSetLineBreak(true);
3522                   }
3523             else {
3524                   if (interval == 0) {
3525                         // remove line break if present
3526                         if (m->lineBreak())
3527                               m->undoSetLineBreak(false);
3528                         }
3529                   else {
3530                         if (++count == interval) {
3531                               // skip last measure of score
3532                               if (mm == lastMeasure)
3533                                     break;
3534                               // found place for break; add if not already one present
3535                               if (!(m->lineBreak() || m->pageBreak()))
3536                                     m->undoSetLineBreak(true);
3537                               // reset count
3538                               count = 0;
3539                               }
3540                         else if (m->lineBreak()) {
3541                               // remove line break if present in wrong place
3542                               m->undoSetLineBreak(false);
3543                               }
3544                         }
3545                   }
3546 
3547             if (mm == endMeasure)
3548                   break;
3549             }
3550 
3551       }
3552 
3553 //---------------------------------------------------------
3554 //   cmdRemoveEmptyTrailingMeasures
3555 //---------------------------------------------------------
3556 
cmdRemoveEmptyTrailingMeasures()3557 void Score::cmdRemoveEmptyTrailingMeasures()
3558       {
3559       auto beginMeasure = firstTrailingMeasure();
3560       if (beginMeasure)
3561             deleteMeasures(beginMeasure, lastMeasure());
3562       }
3563 
3564 //---------------------------------------------------------
3565 //   cmdPitchUp
3566 //---------------------------------------------------------
3567 
cmdPitchUp()3568 void Score::cmdPitchUp()
3569       {
3570       Element* el = selection().element();
3571       if (el && el->isLyrics())
3572             cmdMoveLyrics(toLyrics(el), Direction::UP);
3573       else if (el && (el->isArticulation() || el->isTextBase()))
3574             el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, -MScore::nudgeStep * el->spatium()), PropertyFlags::UNSTYLED);
3575       else if (el && el->isRest())
3576             cmdMoveRest(toRest(el), Direction::UP);
3577       else
3578             upDown(true, UpDownMode::CHROMATIC);
3579       }
3580 
3581 //---------------------------------------------------------
3582 //   cmdPitchDown
3583 //---------------------------------------------------------
3584 
cmdPitchDown()3585 void Score::cmdPitchDown()
3586       {
3587       Element* el = selection().element();
3588       if (el && el->isLyrics())
3589             cmdMoveLyrics(toLyrics(el), Direction::DOWN);
3590       else if (el && (el->isArticulation() || el->isTextBase()))
3591             el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, MScore::nudgeStep * el->spatium()), PropertyFlags::UNSTYLED);
3592       else if (el && el->isRest())
3593             cmdMoveRest(toRest(el), Direction::DOWN);
3594       else
3595             upDown(false, UpDownMode::CHROMATIC);
3596       }
3597 
3598 //---------------------------------------------------------
3599 //   cmdTimeDelete
3600 //---------------------------------------------------------
3601 
cmdTimeDelete()3602 void Score::cmdTimeDelete()
3603       {
3604       Element* e = selection().element();
3605       if (e && e->isBarLine() && toBarLine(e)->segment()->isEndBarLineType()) {
3606             Measure* m = toBarLine(e)->segment()->measure();
3607             cmdJoinMeasure(m, m->nextMeasure());
3608             }
3609       else {
3610             if (_is.insertMode())
3611                   globalTimeDelete();
3612             else
3613                   localTimeDelete();
3614             }
3615       }
3616 
3617 //---------------------------------------------------------
3618 //   cmdPitchUpOctave
3619 //---------------------------------------------------------
3620 
cmdPitchUpOctave()3621 void Score::cmdPitchUpOctave()
3622       {
3623       Element* el = selection().element();
3624       if (el && (el->isArticulation() || el->isTextBase()))
3625             el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, -MScore::nudgeStep10 * el->spatium()), PropertyFlags::UNSTYLED);
3626       else
3627             upDown(true, UpDownMode::OCTAVE);
3628       }
3629 
3630 //---------------------------------------------------------
3631 //   cmdPitchDownOctave
3632 //---------------------------------------------------------
3633 
cmdPitchDownOctave()3634 void Score::cmdPitchDownOctave()
3635       {
3636       Element* el = selection().element();
3637       if (el && (el->isArticulation() || el->isTextBase()))
3638             el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, MScore::nudgeStep10 * el->spatium()), PropertyFlags::UNSTYLED);
3639       else
3640             upDown(false, UpDownMode::OCTAVE);
3641       }
3642 
3643 //---------------------------------------------------------
3644 //   cmdPadNoteInclreaseTAB
3645 //---------------------------------------------------------
3646 
cmdPadNoteIncreaseTAB(const EditData & ed)3647 void Score::cmdPadNoteIncreaseTAB(const EditData& ed)
3648       {
3649       switch (_is.duration().type() ) {
3650 // cycle back from longest to shortest?
3651 //          case TDuration::V_LONG:
3652 //                padToggle(Pad::NOTE128, ed);
3653 //                break;
3654             case TDuration::DurationType::V_BREVE:
3655                   padToggle(Pad::NOTE00, ed);
3656                   break;
3657             case TDuration::DurationType::V_WHOLE:
3658                   padToggle(Pad::NOTE0, ed);
3659                   break;
3660             case TDuration::DurationType::V_HALF:
3661                   padToggle(Pad::NOTE1, ed);
3662                   break;
3663             case TDuration::DurationType::V_QUARTER:
3664                   padToggle(Pad::NOTE2, ed);
3665                   break;
3666             case TDuration::DurationType::V_EIGHTH:
3667                   padToggle(Pad::NOTE4, ed);
3668                   break;
3669             case TDuration::DurationType::V_16TH:
3670                   padToggle(Pad::NOTE8, ed);
3671                   break;
3672             case TDuration::DurationType::V_32ND:
3673                   padToggle(Pad::NOTE16, ed);
3674                   break;
3675             case TDuration::DurationType::V_64TH:
3676                   padToggle(Pad::NOTE32, ed);
3677                   break;
3678             case TDuration::DurationType::V_128TH:
3679                   padToggle(Pad::NOTE64, ed);
3680                   break;
3681             default:
3682                   break;
3683             }
3684       }
3685 
3686 //---------------------------------------------------------
3687 //   cmdPadNoteDecreaseTAB
3688 //---------------------------------------------------------
3689 
cmdPadNoteDecreaseTAB(const EditData & ed)3690 void Score::cmdPadNoteDecreaseTAB(const EditData& ed)
3691       {
3692       switch (_is.duration().type() ) {
3693             case TDuration::DurationType::V_LONG:
3694                   padToggle(Pad::NOTE0, ed);
3695                   break;
3696             case TDuration::DurationType::V_BREVE:
3697                   padToggle(Pad::NOTE1, ed);
3698                   break;
3699             case TDuration::DurationType::V_WHOLE:
3700                   padToggle(Pad::NOTE2, ed);
3701                   break;
3702             case TDuration::DurationType::V_HALF:
3703                   padToggle(Pad::NOTE4, ed);
3704                   break;
3705             case TDuration::DurationType::V_QUARTER:
3706                   padToggle(Pad::NOTE8, ed);
3707                   break;
3708             case TDuration::DurationType::V_EIGHTH:
3709                   padToggle(Pad::NOTE16, ed);
3710                   break;
3711             case TDuration::DurationType::V_16TH:
3712                   padToggle(Pad::NOTE32, ed);
3713                   break;
3714             case TDuration::DurationType::V_32ND:
3715                   padToggle(Pad::NOTE64, ed);
3716                   break;
3717             case TDuration::DurationType::V_64TH:
3718                   padToggle(Pad::NOTE128, ed);
3719                   break;
3720             case TDuration::DurationType::V_128TH:
3721                   padToggle(Pad::NOTE256, ed);
3722                   break;
3723             case TDuration::DurationType::V_256TH:
3724                   padToggle(Pad::NOTE512, ed);
3725                   break;
3726             case TDuration::DurationType::V_512TH:
3727                   padToggle(Pad::NOTE1024, ed);
3728                   break;
3729 // cycle back from shortest to longest?
3730 //          case TDuration::DurationType::V_1024TH:
3731 //                padToggle(Pad::NOTE00, ed);
3732 //                break;
3733             default:
3734                   break;
3735             }
3736       }
3737 
3738 //---------------------------------------------------------
3739 //   cmdToggleLayoutBreak
3740 //---------------------------------------------------------
3741 
cmdToggleLayoutBreak(LayoutBreak::Type type)3742 void Score::cmdToggleLayoutBreak(LayoutBreak::Type type)
3743       {
3744       // find measure(s)
3745       QList<MeasureBase*> mbl;
3746       if (selection().isRange()) {
3747             Measure* startMeasure = nullptr;
3748             Measure* endMeasure = nullptr;
3749             if (!selection().measureRange(&startMeasure, &endMeasure))
3750                   return;
3751             if (!startMeasure || !endMeasure)
3752                   return;
3753 #if 1
3754             // toggle break on the last measure of the range
3755             mbl.append(endMeasure);
3756             // if more than one measure selected,
3757             // also toggle break *before* the range (to try to fit selection on a single line)
3758             if (startMeasure != endMeasure && startMeasure->prev())
3759                   mbl.append(startMeasure->prev());
3760 #else
3761             // toggle breaks throughout the selection
3762             for (Measure* m = startMeasure; m; m = m->nextMeasure()) {
3763                   mbl.append(m);
3764                   if (m == endMeasure)
3765                         break;
3766                   }
3767 #endif
3768             }
3769       else {
3770             MeasureBase* mb = nullptr;
3771             for (Element* el : selection().elements()) {
3772                   switch (el->type()) {
3773                         case ElementType::HBOX:
3774                         case ElementType::VBOX:
3775                         case ElementType::TBOX:
3776                               mb = toMeasureBase(el);
3777                               break;
3778                         default: {
3779                               // find measure
3780                               Measure* measure = toMeasure(el->findMeasure());
3781                               // for start repeat, attach break to previous measure
3782                               if (measure && el->isBarLine()) {
3783                                     BarLine* bl = toBarLine(el);
3784                                     if (bl->barLineType() == BarLineType::START_REPEAT)
3785                                           measure = measure->prevMeasure();
3786                                     }
3787                               // if measure is mmrest, then propagate to last original measure
3788                               if (measure)
3789                                     mb = measure->isMMRest() ? measure->mmRestLast() : measure;
3790                               }
3791                         }
3792                   }
3793             if (mb)
3794                   mbl.append(mb);
3795             }
3796       // toggle the breaks
3797       for (MeasureBase* mb: mbl) {
3798             if (mb) {
3799                   bool val = false;
3800                   switch (type) {
3801                         case LayoutBreak::Type::LINE:
3802                               val = !mb->lineBreak();
3803                               mb->undoSetBreak(val, type);
3804                               // remove page break if appropriate
3805                               if (val && mb->pageBreak())
3806                                     mb->undoSetBreak(false, LayoutBreak::Type::PAGE);
3807                               break;
3808                         case LayoutBreak::Type::PAGE:
3809                               val = !mb->pageBreak();
3810                               mb->undoSetBreak(val, type);
3811                               // remove line break if appropriate
3812                               if (val && mb->lineBreak())
3813                                     mb->undoSetBreak(false, LayoutBreak::Type::LINE);
3814                               break;
3815                         case LayoutBreak::Type::SECTION:
3816                               val = !mb->sectionBreak();
3817                               mb->undoSetBreak(val, type);
3818                               break;
3819                         default:
3820                               break;
3821                         }
3822                   }
3823             }
3824       }
3825 
3826 //---------------------------------------------------------
3827 //   cmdToggleMmrest
3828 //---------------------------------------------------------
3829 
cmdToggleMmrest()3830 void Score::cmdToggleMmrest()
3831       {
3832       bool val = !styleB(Sid::createMultiMeasureRests);
3833       deselectAll();
3834       undo(new ChangeStyleVal(this, Sid::createMultiMeasureRests, val));
3835       }
3836 
3837 //---------------------------------------------------------
3838 //   cmdToggleHideEmpty
3839 //---------------------------------------------------------
3840 
cmdToggleHideEmpty()3841 void Score::cmdToggleHideEmpty()
3842       {
3843       bool val = !styleB(Sid::hideEmptyStaves);
3844       deselectAll();
3845       undo(new ChangeStyleVal(this, Sid::hideEmptyStaves, val));
3846       }
3847 
3848 //---------------------------------------------------------
3849 //   cmdSetVisible
3850 //---------------------------------------------------------
3851 
cmdSetVisible()3852 void Score::cmdSetVisible()
3853       {
3854       for (Element* e : selection().elements())
3855             undo(new ChangeProperty(e, Pid::VISIBLE, true));
3856       }
3857 
3858 //---------------------------------------------------------
3859 //   cmdUnsetVisible
3860 //---------------------------------------------------------
3861 
cmdUnsetVisible()3862 void Score::cmdUnsetVisible()
3863       {
3864       for (Element* e : selection().elements())
3865             undo(new ChangeProperty(e, Pid::VISIBLE, false));
3866       }
3867 
3868 //---------------------------------------------------------
3869 //   cmdAddPitch
3870 ///   insert note or add note to chord
3871 //    c d e f g a b entered:
3872 //---------------------------------------------------------
3873 
cmdAddPitch(const EditData & ed,int note,bool addFlag,bool insert)3874 void Score::cmdAddPitch(const EditData& ed, int note, bool addFlag, bool insert)
3875       {
3876       InputState& is = inputState();
3877       if (is.track() == -1)          // invalid state
3878             return;
3879       if (is.segment() == 0) {
3880             qDebug("cannot enter notes here (no chord rest at current position)");
3881             return;
3882             }
3883       is.setRest(false);
3884       const Drumset* ds = is.drumset();
3885       int octave = 4;
3886       if (ds) {
3887             char note1 = "CDEFGAB"[note];
3888             int pitch = -1;
3889             int voice = 0;
3890             for (int i = 0; i < 127; ++i) {
3891                   if (!ds->isValid(i))
3892                         continue;
3893                   if (ds->shortcut(i) && (ds->shortcut(i) == note1)) {
3894                         pitch = i;
3895                         voice = ds->voice(i);
3896                         break;
3897                         }
3898                   }
3899             if (pitch == -1) {
3900                   qDebug("  shortcut %c not defined in drumset", note1);
3901                   return;
3902                   }
3903             is.setDrumNote(pitch);
3904             is.setTrack((is.track() / VOICES) * VOICES + voice);
3905             octave = pitch / 12;
3906             if (is.segment()) {
3907                   Segment* seg = is.segment();
3908                   while (seg) {
3909                         if (seg->element(is.track()))
3910                               break;
3911                         seg = seg->prev(SegmentType::ChordRest);
3912                         }
3913                   if (seg)
3914                         is.setSegment(seg);
3915                   else
3916                         is.setSegment(is.segment()->measure()->first(SegmentType::ChordRest));
3917                   }
3918             }
3919       else {
3920             static const int tab[] = { 0, 2, 4, 5, 7, 9, 11 };
3921 
3922             // if adding notes, add above the upNote of the current chord
3923             Element* el = selection().element();
3924             if (addFlag && el && el->isNote()) {
3925                   Chord* chord = toNote(el)->chord();
3926                   Note* n      = chord->upNote();
3927                   int tpc = n->tpc();
3928                   octave = (n->epitch() - int(tpc2alter(tpc))) / PITCH_DELTA_OCTAVE;
3929                   if (note <= tpc2step(tpc))
3930                         octave++;
3931                   }
3932             else {
3933                   int curPitch = 60;
3934                   if (is.segment()) {
3935                         Staff* staff = Score::staff(is.track() / VOICES);
3936                         Segment* seg = is.segment()->prev1(SegmentType::ChordRest | SegmentType::Clef | SegmentType::HeaderClef);
3937                         while (seg) {
3938                               if (seg->isChordRestType()) {
3939                                     Element* p = seg->element(is.track());
3940                                     if (p && p->isChord()) {
3941                                           Note* n = toChord(p)->downNote();
3942                                           // forget any accidental and/or adjustment due to key signature
3943                                           curPitch = n->epitch() - static_cast<int>(tpc2alter(n->tpc()));
3944                                           break;
3945                                           }
3946                                     }
3947                               else if (seg->isClefType() || seg->isHeaderClefType()) {
3948                                     Element* p = seg->element( (is.track() / VOICES) * VOICES); // clef on voice 1
3949                                     if (p && p->isClef()) {
3950                                           Clef* clef = toClef(p);
3951                                           // check if it's an actual change or just a courtesy
3952                                           ClefType ctb = staff->clef(clef->tick() - Fraction::fromTicks(1));
3953                                           if (ctb != clef->clefType() || clef->tick().isZero()) {
3954                                                 curPitch = line2pitch(4, clef->clefType(), Key::C); // C 72 for treble clef
3955                                                 break;
3956                                                 }
3957                                           }
3958                                     }
3959                               seg = seg->prev1MM(SegmentType::ChordRest | SegmentType::Clef | SegmentType::HeaderClef);
3960                               }
3961                         octave = curPitch / 12;
3962                         }
3963 
3964                   int delta = octave * 12 + tab[note] - curPitch;
3965                   if (delta > 6)
3966                         --octave;
3967                   else if (delta < -6)
3968                         ++octave;
3969                   }
3970             }
3971       ed.view->startNoteEntryMode();
3972 
3973       int step = octave * 7 + note;
3974       cmdAddPitch(step,  addFlag, insert);
3975       ed.view->adjustCanvasPosition(is.cr(), false);
3976       }
3977 
cmdAddPitch(int step,bool addFlag,bool insert)3978 void Score::cmdAddPitch(int step, bool addFlag, bool insert)
3979       {
3980       insert = insert || inputState().usingNoteEntryMethod(NoteEntryMethod::TIMEWISE);
3981       Position pos;
3982       if (addFlag) {
3983             Element* el = selection().element();
3984             if (el && el->isNote()) {
3985                   Note* selectedNote = toNote(el);
3986                   Chord* chord  = selectedNote->chord();
3987                   Segment* seg  = chord->segment();
3988                   pos.segment   = seg;
3989                   pos.staffIdx  = selectedNote->track() / VOICES;
3990                   ClefType clef = staff(pos.staffIdx)->clef(seg->tick());
3991                   pos.line      = relStep(step, clef);
3992                   bool error;
3993                   NoteVal nval = noteValForPosition(pos, _is.accidentalType(), error);
3994                   if (error)
3995                         return;
3996                   bool forceAccidental = false;
3997                   if (_is.accidentalType() != AccidentalType::NONE) {
3998                         NoteVal nval2 = noteValForPosition(pos, AccidentalType::NONE, error);
3999                         forceAccidental = (nval.pitch == nval2.pitch);
4000                         }
4001                   addNote(chord, nval, forceAccidental);
4002                   _is.setAccidentalType(AccidentalType::NONE);
4003                   return;
4004                   }
4005             }
4006 
4007       pos.segment   = inputState().segment();
4008       pos.staffIdx  = inputState().track() / VOICES;
4009       ClefType clef = staff(pos.staffIdx)->clef(pos.segment->tick());
4010       pos.line      = relStep(step, clef);
4011 
4012       if (inputState().usingNoteEntryMethod(NoteEntryMethod::REPITCH))
4013             repitchNote(pos, !addFlag);
4014       else {
4015             if (insert)
4016                   insertChord(pos);
4017             else
4018                   putNote(pos, !addFlag);
4019             }
4020       _is.setAccidentalType(AccidentalType::NONE);
4021       }
4022 
4023 //---------------------------------------------------------
4024 //   cmdToggleVisible
4025 //---------------------------------------------------------
4026 
cmdToggleVisible()4027 void Score::cmdToggleVisible()
4028       {
4029       QSet<Element*> spanners;
4030       for (Element* e : selection().elements()) {
4031             if (e->isBracket())     // ignore
4032                   continue;
4033             if (e->isNoteDot() && selection().elements().contains(e->parent()))
4034                   // already handled in ScoreElement::undoChangeProperty(); don't toggle twice
4035                   continue;
4036             bool spannerSegment = e->isSpannerSegment();
4037             if (!spannerSegment || !spanners.contains(toSpannerSegment(e)->spanner()))
4038                   e->undoChangeProperty(Pid::VISIBLE, !e->getProperty(Pid::VISIBLE).toBool());
4039             if (spannerSegment)
4040                   spanners.insert(toSpannerSegment(e)->spanner());
4041             }
4042       }
4043 
4044 //---------------------------------------------------------
4045 //   cmdAddFret
4046 ///   insert note with given fret on current string
4047 //---------------------------------------------------------
4048 
cmdAddFret(int fret)4049 void Score::cmdAddFret(int fret)
4050       {
4051       InputState& is = inputState();
4052       if (is.track() == -1)                     // invalid state
4053             return;
4054       if (!is.segment()) {
4055             qDebug("cannot enter notes here (no chord rest at current position)");
4056             return;
4057             }
4058       Position pos;
4059       pos.segment   = is.segment();
4060       pos.staffIdx  = is.track() / VOICES;
4061       pos.line      = staff(pos.staffIdx)->staffType(is.tick())->physStringToVisual(is.string());
4062       pos.fret      = fret;
4063       putNote(pos, false);
4064       }
4065 
4066 //---------------------------------------------------------
4067 //   cmdRelayout
4068 //---------------------------------------------------------
4069 
cmdRelayout()4070 void Score::cmdRelayout()
4071       {
4072       setLayoutAll();
4073       }
4074 
4075 //---------------------------------------------------------
4076 //   cmdToggleAutoplace
4077 //---------------------------------------------------------
4078 
cmdToggleAutoplace(bool all)4079 void Score::cmdToggleAutoplace(bool all)
4080       {
4081       if (all) {
4082             bool val = !styleB(Sid::autoplaceEnabled);
4083             undoChangeStyleVal(Sid::autoplaceEnabled, val);
4084             setLayoutAll();
4085             }
4086       else {
4087             QSet<Element*> spanners;
4088             for (Element* e : selection().elements()) {
4089                   if (e->isSpannerSegment()) {
4090                         if (Element* ee = e->propertyDelegate(Pid::AUTOPLACE))
4091                               e = ee;
4092                         // spanner segments may each have their own autoplace setting
4093                         // but if they delegate to spanner, only toggle once
4094                         if (e->isSpanner()) {
4095                               if (spanners.contains(e))
4096                                     continue;
4097                               spanners.insert(e);
4098                               }
4099                         }
4100                   PropertyFlags pf = e->propertyFlags(Pid::AUTOPLACE);
4101                   if (pf == PropertyFlags::STYLED)
4102                         pf = PropertyFlags::UNSTYLED;
4103                   e->undoChangeProperty(Pid::AUTOPLACE, !e->getProperty(Pid::AUTOPLACE).toBool(), pf);
4104                   }
4105             }
4106       }
4107 
4108 //---------------------------------------------------------
4109 //   cmd
4110 //---------------------------------------------------------
4111 
cmd(const QAction * a,EditData & ed)4112 void Score::cmd(const QAction* a, EditData& ed)
4113       {
4114       QString cmd(a ? a->data().toString() : "");
4115       if (MScore::debugMode)
4116             qDebug("<%s>", qPrintable(cmd));
4117 
4118       struct ScoreCmd {
4119             const char* name;
4120             std::function<void(Score* cs, EditData& ed)> cmd;
4121             };
4122 
4123       static const std::vector<ScoreCmd> cmdList {
4124             { "note-c",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 0, false, false);                        }},
4125             { "note-d",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 1, false, false);                        }},
4126             { "note-e",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 2, false, false);                        }},
4127             { "note-f",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 3, false, false);                        }},
4128             { "note-g",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 4, false, false);                        }},
4129             { "note-a",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 5, false, false);                        }},
4130             { "note-b",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 6, false, false);                        }},
4131             { "chord-c",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 0, true, false);                         }},
4132             { "chord-d",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 1, true, false);                         }},
4133             { "chord-e",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 2, true, false);                         }},
4134             { "chord-f",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 3, true, false);                         }},
4135             { "chord-g",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 4, true, false);                         }},
4136             { "chord-a",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 5, true, false);                         }},
4137             { "chord-b",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 6, true, false);                         }},
4138             { "insert-c",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 0, false, true);                         }},
4139             { "insert-d",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 1, false, true);                         }},
4140             { "insert-e",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 2, false, true);                         }},
4141             { "insert-f",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 3, false, true);                         }},
4142             { "insert-g",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 4, false, true);                         }},
4143             { "insert-a",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 5, false, true);                         }},
4144             { "insert-b",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 6, false, true);                         }},
4145             { "fret-0",                     [](Score* cs, EditData&){ cs->cmdAddFret(0);                                              }},
4146             { "fret-1",                     [](Score* cs, EditData&){ cs->cmdAddFret(1);                                              }},
4147             { "fret-2",                     [](Score* cs, EditData&){ cs->cmdAddFret(2);                                              }},
4148             { "fret-3",                     [](Score* cs, EditData&){ cs->cmdAddFret(3);                                              }},
4149             { "fret-4",                     [](Score* cs, EditData&){ cs->cmdAddFret(4);                                              }},
4150             { "fret-5",                     [](Score* cs, EditData&){ cs->cmdAddFret(5);                                              }},
4151             { "fret-6",                     [](Score* cs, EditData&){ cs->cmdAddFret(6);                                              }},
4152             { "fret-7",                     [](Score* cs, EditData&){ cs->cmdAddFret(7);                                              }},
4153             { "fret-8",                     [](Score* cs, EditData&){ cs->cmdAddFret(8);                                              }},
4154             { "fret-9",                     [](Score* cs, EditData&){ cs->cmdAddFret(9);                                              }},
4155             { "fret-10",                    [](Score* cs, EditData&){ cs->cmdAddFret(10);                                             }},
4156             { "fret-11",                    [](Score* cs, EditData&){ cs->cmdAddFret(11);                                             }},
4157             { "fret-12",                    [](Score* cs, EditData&){ cs->cmdAddFret(12);                                             }},
4158             { "fret-13",                    [](Score* cs, EditData&){ cs->cmdAddFret(13);                                             }},
4159             { "fret-14",                    [](Score* cs, EditData&){ cs->cmdAddFret(14);                                             }},
4160             { "toggle-visible",             [](Score* cs, EditData&){ cs->cmdToggleVisible();                                         }},
4161             { "reset-stretch",              [](Score* cs, EditData&){ cs->resetUserStretch();                                         }},
4162             { "mirror-note",                [](Score* cs, EditData&){ cs->cmdMirrorNoteHead();                                        }},
4163             { "double-duration",            [](Score* cs, EditData&){ cs->cmdDoubleDuration();                                        }},
4164             { "half-duration",              [](Score* cs, EditData&){ cs->cmdHalfDuration();                                          }},
4165             { "inc-duration-dotted",        [](Score* cs, EditData&){ cs->cmdIncDurationDotted();                                     }},
4166             { "dec-duration-dotted",        [](Score* cs, EditData&){ cs->cmdDecDurationDotted();                                     }},
4167             { "add-staccato",               [](Score* cs, EditData&){ cs->addArticulation(SymId::articStaccatoAbove);                 }},
4168             { "add-tenuto",                 [](Score* cs, EditData&){ cs->addArticulation(SymId::articTenutoAbove);                   }},
4169             { "add-marcato",                [](Score* cs, EditData&){ cs->addArticulation(SymId::articMarcatoAbove);                  }},
4170             { "add-sforzato",               [](Score* cs, EditData&){ cs->addArticulation(SymId::articAccentAbove);                   }},
4171             { "add-trill",                  [](Score* cs, EditData&){ cs->addArticulation(SymId::ornamentTrill);                      }},
4172             { "add-up-bow",                 [](Score* cs, EditData&){ cs->addArticulation(SymId::stringsUpBow);                       }},
4173             { "add-down-bow",               [](Score* cs, EditData&){ cs->addArticulation(SymId::stringsDownBow);                     }},
4174             { "add-8va",                    [](Score* cs, EditData&){ cs->cmdAddOttava(OttavaType::OTTAVA_8VA);                       }},
4175             { "add-8vb",                    [](Score* cs, EditData&){ cs->cmdAddOttava(OttavaType::OTTAVA_8VB);                       }},
4176             { "note-longa",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE00, ed);                              }},
4177             { "note-longa-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE00, ed);                              }},
4178             { "note-breve",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE0, ed);                               }},
4179             { "note-breve-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE0, ed);                               }},
4180             { "pad-note-1",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE1, ed);                               }},
4181             { "pad-note-1-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE1, ed);                               }},
4182             { "pad-note-2",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE2, ed);                               }},
4183             { "pad-note-2-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE2, ed);                               }},
4184             { "pad-note-4",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE4, ed);                               }},
4185             { "pad-note-4-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE4, ed);                               }},
4186             { "pad-note-8",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE8, ed);                               }},
4187             { "pad-note-8-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE8, ed);                               }},
4188             { "pad-note-16",                [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE16, ed);                              }},
4189             { "pad-note-16-TAB",            [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE16, ed);                              }},
4190             { "pad-note-32",                [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE32, ed);                              }},
4191             { "pad-note-32-TAB",            [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE32, ed);                              }},
4192             { "pad-note-64",                [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE64, ed);                              }},
4193             { "pad-note-64-TAB",            [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE64, ed);                              }},
4194             { "pad-note-128",               [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE128, ed);                             }},
4195             { "pad-note-128-TAB",           [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE128, ed);                             }},
4196             { "pad-note-256",               [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE256, ed);                             }},
4197             { "pad-note-256-TAB",           [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE256, ed);                             }},
4198             { "pad-note-512",               [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE512, ed);                             }},
4199             { "pad-note-512-TAB",           [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE512, ed);                             }},
4200             { "pad-note-1024",              [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE1024, ed);                            }},
4201             { "pad-note-1024-TAB",          [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE1024, ed);                            }},
4202             { "reset-style",                [](Score* cs, EditData&){ cs->cmdResetAllStyle();                                         }},
4203             { "reset-text-style-overrides", [](Score* cs, EditData&){ cs->cmdResetTextStyleOverrides();                               }},
4204             { "reset-beammode",             [](Score* cs, EditData&){ cs->cmdResetBeamMode();                                         }},
4205             { "reset-groupings",            [](Score* cs, EditData&){ cs->cmdResetNoteAndRestGroupings();                             }},
4206             { "clef-violin",                [](Score* cs, EditData&){ cs->cmdInsertClef(ClefType::G);                                 }},
4207             { "clef-bass",                  [](Score* cs, EditData&){ cs->cmdInsertClef(ClefType::F);                                 }},
4208             { "voice-x12",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(0, 1);                                     }},
4209             { "voice-x13",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(0, 2);                                     }},
4210             { "voice-x14",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(0, 3);                                     }},
4211             { "voice-x23",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(1, 2);                                     }},
4212             { "voice-x24",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(1, 3);                                     }},
4213             { "voice-x34",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(2, 3);                                     }},
4214             { "pad-rest",                   [](Score* cs, EditData& ed){ cs->padToggle(Pad::REST, ed);                                }},
4215             { "pad-dot",                    [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOT, ed);                                 }},
4216             { "pad-dotdot",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOTDOT, ed);                              }},
4217             { "pad-dot3",                   [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOT3, ed);                                }},
4218             { "pad-dot4",                   [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOT4, ed);                                }},
4219             { "beam-start",                 [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::BEGIN);                          }},
4220             { "beam-mid",                   [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::MID);                            }},
4221             { "no-beam",                    [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::NONE);                           }},
4222             { "beam32",                     [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::BEGIN32);                        }},
4223             { "beam64",                     [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::BEGIN64);                        }},
4224             { "auto-beam",                  [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::AUTO);                           }},
4225             { "sharp2",                     [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::SHARP2, ed);            }},
4226             { "sharp",                      [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::SHARP, ed);             }},
4227             { "nat",                        [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::NATURAL, ed);           }},
4228             { "flat",                       [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::FLAT, ed);              }},
4229             { "flat2",                      [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::FLAT2, ed);             }},
4230             { "sharp2-post",                [](Score* cs, EditData&){ cs->changeAccidental(AccidentalType::SHARP2);                   }},
4231             { "sharp-post",                 [](Score* cs, EditData&){ cs->changeAccidental(AccidentalType::SHARP);                    }},
4232             { "nat-post",                   [](Score* cs, EditData&){ cs->changeAccidental(AccidentalType::NATURAL);                  }},
4233             { "flat-post",                  [](Score* cs, EditData&){ cs->changeAccidental(AccidentalType::FLAT);                     }},
4234             { "flat2-post",                 [](Score* cs, EditData&){ cs->changeAccidental(AccidentalType::FLAT2);                    }},
4235             { "flip",                       [](Score* cs, EditData&){ cs->cmdFlip();                                                  }},
4236             { "stretch+",                   [](Score* cs, EditData&){ cs->cmdAddStretch(0.1);                                         }},
4237             { "stretch-",                   [](Score* cs, EditData&){ cs->cmdAddStretch(-0.1);                                        }},
4238             { "pitch-spell",                [](Score* cs, EditData&){ cs->spell();                                                    }},
4239             { "select-all",                 [](Score* cs, EditData&){ cs->cmdSelectAll();                                             }},
4240             { "select-section",             [](Score* cs, EditData&){ cs->cmdSelectSection();                                         }},
4241             { "add-brackets",               [](Score* cs, EditData&){ cs->cmdAddBracket();                                            }},
4242             { "add-parentheses",            [](Score* cs, EditData&){ cs->cmdAddParentheses();                                        }},
4243             { "add-braces",                 [](Score* cs, EditData&){ cs->cmdAddBraces();                                        }},
4244             { "acciaccatura",               [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::ACCIACCATURA, MScore::division / 2);  }},
4245             { "appoggiatura",               [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::APPOGGIATURA, MScore::division / 2);  }},
4246             { "grace4",                     [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE4, MScore::division);            }},
4247             { "grace16",                    [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE16, MScore::division / 4);       }},
4248             { "grace32",                    [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE32, MScore::division / 8);       }},
4249             { "grace8after",                [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE8_AFTER, MScore::division / 2);  }},
4250             { "grace16after",               [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE16_AFTER, MScore::division / 4); }},
4251             { "grace32after",               [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE32_AFTER, MScore::division / 8); }},
4252             { "explode",                    [](Score* cs, EditData&){ cs->cmdExplode();                                               }},
4253             { "implode",                    [](Score* cs, EditData&){ cs->cmdImplode();                                               }},
4254             { "realize-chord-symbols",      [](Score* cs, EditData&){ cs->cmdRealizeChordSymbols();                                   }},
4255             { "slash-fill",                 [](Score* cs, EditData&){ cs->cmdSlashFill();                                             }},
4256             { "slash-rhythm",               [](Score* cs, EditData&){ cs->cmdSlashRhythm();                                           }},
4257             { "resequence-rehearsal-marks", [](Score* cs, EditData&){ cs->cmdResequenceRehearsalMarks();                              }},
4258             { "del-empty-measures",         [](Score* cs, EditData&){ cs->cmdRemoveEmptyTrailingMeasures();                           }},
4259             { "add-audio",                  [](Score* cs, EditData&){ cs->addAudioTrack();                                            }},
4260             { "transpose-up",               [](Score* cs, EditData&){ cs->transposeSemitone(1);                                       }},
4261             { "transpose-down",             [](Score* cs, EditData&){ cs->transposeSemitone(-1);                                      }},
4262             { "pitch-up-diatonic-alterations",   [](Score* cs, EditData&){ cs->transposeDiatonicAlterations(TransposeDirection::UP);  }},
4263             { "pitch-down-diatonic-alterations", [](Score* cs, EditData&){ cs->transposeDiatonicAlterations(TransposeDirection::DOWN);}},
4264             { "delete",                     [](Score* cs, EditData&){ cs->cmdDeleteSelection();                                       }},
4265             { "full-measure-rest",          [](Score* cs, EditData&){ cs->cmdFullMeasureRest();                                       }},
4266             { "toggle-insert-mode",         [](Score* cs, EditData&){ cs->_is.setInsertMode(!cs->_is.insertMode());                   }},
4267             { "pitch-up",                   [](Score* cs, EditData&){ cs->cmdPitchUp();                                               }},
4268             { "pitch-down",                 [](Score* cs, EditData&){ cs->cmdPitchDown();                                             }},
4269             { "time-delete",                [](Score* cs, EditData&){ cs->cmdTimeDelete();                                            }},
4270             { "pitch-up-octave",            [](Score* cs, EditData&){ cs->cmdPitchUpOctave();                                         }},
4271             { "pitch-down-octave",          [](Score* cs, EditData&){ cs->cmdPitchDownOctave();                                       }},
4272             { "pad-note-increase",          [](Score* cs, EditData& ed){ cs->cmdPadNoteIncreaseTAB(ed);                               }},
4273             { "pad-note-decrease",          [](Score* cs, EditData& ed){ cs->cmdPadNoteDecreaseTAB(ed);                               }},
4274             { "pad-note-increase-TAB",      [](Score* cs, EditData& ed){ cs->cmdPadNoteIncreaseTAB(ed);                               }},
4275             { "pad-note-decrease-TAB",      [](Score* cs, EditData& ed){ cs->cmdPadNoteDecreaseTAB(ed);                               }},
4276             { "toggle-mmrest",              [](Score* cs, EditData&){ cs->cmdToggleMmrest();                                          }},
4277             { "toggle-hide-empty",          [](Score* cs, EditData&){ cs->cmdToggleHideEmpty();                                       }},
4278             { "set-visible",                [](Score* cs, EditData&){ cs->cmdSetVisible();                                            }},
4279             { "unset-visible",              [](Score* cs, EditData&){ cs->cmdUnsetVisible();                                          }},
4280             { "system-break",               [](Score* cs, EditData&){ cs->cmdToggleLayoutBreak(LayoutBreak::Type::LINE);              }},
4281             { "page-break",                 [](Score* cs, EditData&){ cs->cmdToggleLayoutBreak(LayoutBreak::Type::PAGE);              }},
4282             { "section-break",              [](Score* cs, EditData&){ cs->cmdToggleLayoutBreak(LayoutBreak::Type::SECTION);           }},
4283             { "relayout",                   [](Score* cs, EditData&){ cs->cmdRelayout();                                              }},
4284             { "toggle-autoplace",           [](Score* cs, EditData&){ cs->cmdToggleAutoplace(false);                                  }},
4285             { "autoplace-enabled",          [](Score* cs, EditData&){ cs->cmdToggleAutoplace(true);                                   }},
4286             };
4287 
4288       for (const auto& c : cmdList) {
4289             if (cmd == c.name) {
4290                   startCmd();
4291                   c.cmd(this, ed);
4292                   endCmd();
4293                   return;
4294                   }
4295             }
4296       qDebug("unknown cmd <%s>", qPrintable(cmd));
4297       }
4298 
4299 
4300 }
4301 
4302