code: //=============================================================================
  //  MuseScore
  //  Music Composition & Notation
  //
  //  Copyright (C) 2002-2013 Werner Schweer
  //
  //  This program is free software; you can redistribute it and/or modify
  //  it under the terms of the GNU General Public License version 2
  //  as published by the Free Software Foundation and appearing in
  //  the file LICENCE.GPL
  //=============================================================================
  
  /**
   \file
   Handling of several GUI commands.
  */
  
  #include <assert.h>
  
  #include "types.h"
  #include "musescoreCore.h"
  #include "score.h"
  #include "utils.h"
  #include "key.h"
  #include "clef.h"
  #include "navigate.h"
  #include "slur.h"
  #include "tie.h"
  #include "note.h"
  #include "rest.h"
  #include "chord.h"
  #include "text.h"
  #include "sig.h"
  #include "staff.h"
  #include "part.h"
  #include "style.h"
  #include "page.h"
  #include "barline.h"
  #include "tuplet.h"
  #include "xml.h"
  #include "ottava.h"
  #include "trill.h"
  #include "pedal.h"
  #include "hairpin.h"
  #include "textline.h"
  #include "keysig.h"
  #include "volta.h"
  #include "dynamic.h"
  #include "box.h"
  #include "harmony.h"
  #include "system.h"
  #include "stafftext.h"
  #include "articulation.h"
  #include "layoutbreak.h"
  #include "drumset.h"
  #include "beam.h"
  #include "lyrics.h"
  #include "pitchspelling.h"
  #include "measure.h"
  #include "tempo.h"
  #include "undo.h"
  #include "timesig.h"
  #include "repeat.h"
  #include "tempotext.h"
  #include "noteevent.h"
  #include "breath.h"
  #include "stringdata.h"
  #include "stafftype.h"
  #include "segment.h"
  #include "chordlist.h"
  #include "mscore.h"
  #include "accidental.h"
  #include "sequencer.h"
  #include "tremolo.h"
  #include "rehearsalmark.h"
  #include "sym.h"
  
  namespace Ms {
  
  //---------------------------------------------------------
  //   reset
  //---------------------------------------------------------
  
  void CmdState::reset()
        {
        layoutFlags         = LayoutFlag::NO_FLAGS;
        _updateMode         = UpdateMode::DoNothing;
        _startTick          = Fraction(-1,1);
        _endTick            = Fraction(-1,1);
  
        _startStaff = -1;
        _endStaff = -1;
        _el = nullptr;
        _oneElement = true;
        _mb = nullptr;
        _oneMeasureBase = true;
        _locked = false;
        }
  
  //---------------------------------------------------------
  //   setTick
  //---------------------------------------------------------
  
  void CmdState::setTick(const Fraction& t)
        {
        if (_locked)
              return;
  
        if (_startTick == Fraction(-1,1) || t < _startTick)
              _startTick = t;
        if (_endTick == Fraction(-1,1) || t > _endTick)
              _endTick = t;
        setUpdateMode(UpdateMode::Layout);
        }
  
  //---------------------------------------------------------
  //   setStaff
  //---------------------------------------------------------
  
  void CmdState::setStaff(int st)
        {
        Q_ASSERT(st > -2);
        if (_locked || st == -1)
              return;
  
        if (_startStaff == -1 || st < _startStaff)
              _startStaff = st;
        if (_endStaff == -1 || st > _endStaff)
              _endStaff = st;
        }
  
  //---------------------------------------------------------
  //   setMeasureBase
  //---------------------------------------------------------
  
  void CmdState::setMeasureBase(const MeasureBase* mb)
        {
        if (!mb || _mb == mb || _locked)
              return;
  
        _oneMeasureBase = !_mb;
        _mb = mb;
        }
  
  //---------------------------------------------------------
  //   setElement
  //---------------------------------------------------------
  
  void CmdState::setElement(const Element* e)
        {
        if (!e || _el == e || _locked)
              return;
  
        _oneElement = !_el;
        _el = e;
  
        if (_oneMeasureBase)
              setMeasureBase(e->findMeasureBase());
        }
  
  //---------------------------------------------------------
  //   unsetElement
  //---------------------------------------------------------
  
  void CmdState::unsetElement(const Element* e)
        {
        if (_el == e)
              _el = nullptr;
        if (_mb == e)
              _mb = nullptr;
        }
  
  //---------------------------------------------------------
  //   element
  //---------------------------------------------------------
  
  const Element* CmdState::element() const
        {
        if (_oneElement)
              return _el;
        if (_oneMeasureBase)
              return _mb;
        return nullptr;
        }
  
  //---------------------------------------------------------
  //   setUpdateMode
  //---------------------------------------------------------
  
  void CmdState::_setUpdateMode(UpdateMode m)
        {
        _updateMode = m;
        }
  
  void CmdState::setUpdateMode(UpdateMode m)
        {
        if (int(m) > int(_updateMode))
              _setUpdateMode(m);
        }
  
  //---------------------------------------------------------
  //   startCmd
  ///   Start a GUI command by clearing the redraw area
  ///   and starting a user-visible undo.
  //---------------------------------------------------------
  
  void Score::startCmd()
        {
        if (MScore::debugMode)
              qDebug("===startCmd()");
  
        cmdState().reset();
  
        // Start collecting low-level undo operations for a
        // user-visible undo action.
        if (undoStack()->active()) {
              qDebug("Score::startCmd(): cmd already active");
              return;
              }
        undoStack()->beginMacro(this);
        }
  
  //---------------------------------------------------------
  //   undoRedo
  //---------------------------------------------------------
  
  void Score::undoRedo(bool undo, EditData* ed)
        {
        if (readOnly())
              return;
        cmdState().reset();
        if (undo)
              undoStack()->undo(ed);
        else
              undoStack()->redo(ed);
        update(false);
        masterScore()->setPlaylistDirty();  // TODO: flag all individual operations
        updateSelection();
        }
  
  //---------------------------------------------------------
  //   endCmd
  ///   End a GUI command by (if \a undo) ending a user-visble undo
  ///   and (always) updating the redraw area.
  //---------------------------------------------------------
  
  void Score::endCmd(bool rollback)
        {
        if (!undoStack()->active()) {
              qDebug("Score::endCmd(): no cmd active");
              update();
              return;
              }
        if (readOnly() || MScore::_error != MS_NO_ERROR)
              rollback = true;
  
        if (rollback)
              undoStack()->current()->unwind();
  
        update(false);
  
        if (MScore::debugMode)
              qDebug("===endCmd() %d", undoStack()->current()->childCount());
        const bool noUndo = undoStack()->current()->empty();       // nothing to undo?
        undoStack()->endMacro(noUndo);
  
        if (dirty()) {
              masterScore()->setPlaylistDirty();  // TODO: flag individual operations
              masterScore()->setAutosaveDirty(true);
              }
        MuseScoreCore::mscoreCore->endCmd();
        cmdState().reset();
        }
  
  #ifndef NDEBUG
  //---------------------------------------------------------
  //   CmdState::dump
  //---------------------------------------------------------
  
  void CmdState::dump()
        {
        qDebug("CmdState: mode %d %d-%d", int(_updateMode), _startTick.ticks(), _endTick.ticks());
        // bool _excerptsChanged     { false };
        // bool _instrumentsChanged  { false };
  
        }
  #endif
  
  //---------------------------------------------------------
  //   update
  //    layout & update
  //---------------------------------------------------------
  
  void Score::update(bool resetCmdState)
        {
        bool updateAll = false;
        for (MasterScore* ms : *movements()) {
              CmdState& cs = ms->cmdState();
              ms->deletePostponed();
              if (cs.layoutRange()) {
                    for (Score* s : ms->scoreList())
                          s->doLayoutRange(cs.startTick(), cs.endTick());
                    updateAll = true;
                    }
              }
  
        for (MasterScore* ms : *movements()) {
              CmdState& cs = ms->cmdState();
              if (updateAll || cs.updateAll()) {
                    for (Score* s : scoreList()) {
                          for (MuseScoreView* v : s->viewer) {
                                v->updateAll();
                                }
                          }
                    }
              else if (cs.updateRange()) {
                    // updateRange updates only current score
                    qreal d = spatium() * .5;
                    _updateState.refresh.adjust(-d, -d, 2 * d, 2 * d);
                    for (MuseScoreView* v : viewer)
                          v->dataChanged(_updateState.refresh);
                    _updateState.refresh = QRectF();
                    }
              const InputState& is = inputState();
              if (is.noteEntryMode() && is.segment()) {
                    setPlayPos(is.segment()->tick());
                    }
              if (playlistDirty()) {
                    for (Score* s : scoreList())
                          emit s->playlistChanged();
                    masterScore()->setPlaylistClean();
                    }
              if (resetCmdState)
                    cs.reset();
              }
        if (_selection.isRange())
              _selection.updateSelectedElements();
        }
  
  //---------------------------------------------------------
  //   deletePostponed
  //---------------------------------------------------------
  
  void Score::deletePostponed()
        {
        for (ScoreElement* e : _updateState._deleteList) {
              if (e->isSystem()) {
                    System* s = toSystem(e);
                    for (SpannerSegment* ss : s->spannerSegments()) {
                          if (ss->system() == s)
                                ss->setSystem(0);
                          }
                    }
              }
        qDeleteAll(_updateState._deleteList);
        _updateState._deleteList.clear();
        }
  
  //---------------------------------------------------------
  //   cmdAddSpanner
  //   drop VOLTA, OTTAVA, TRILL, PEDAL, DYNAMIC
  //        HAIRPIN, LET_RING, VIBRATO and TEXTLINE
  //---------------------------------------------------------
  
  void Score::cmdAddSpanner(Spanner* spanner, const QPointF& pos, bool firstStaffOnly)
        {
        int staffIdx;
        Segment* segment;
        MeasureBase* mb = pos2measure(pos, &staffIdx, 0, &segment, 0);
        if (firstStaffOnly)
              staffIdx = 0;
        // ignore if we do not have a measure
        if (mb == 0 || mb->type() != ElementType::MEASURE) {
              qDebug("cmdAddSpanner: cannot put object here");
              delete spanner;
              return;
              }
  
        // all spanners live in voice 0 (except slurs/ties)
        int track = staffIdx == -1 ? -1 : staffIdx * VOICES;
  
        spanner->setTrack(track);
        spanner->setTrack2(track);
  
        if (spanner->anchor() == Spanner::Anchor::SEGMENT) {
              spanner->setTick(segment->tick());
              Fraction lastTick = lastMeasure()->tick() + lastMeasure()->ticks();
              Fraction tick2 = qMin(segment->measure()->tick() + segment->measure()->ticks(), lastTick);
              spanner->setTick2(tick2);
              }
        else {      // Anchor::MEASURE, Anchor::CHORD, Anchor::NOTE
              Measure* m = toMeasure(mb);
              QRectF b(m->canvasBoundingRect());
  
              if (pos.x() >= (b.x() + b.width() * .5) && m != lastMeasureMM() && m->nextMeasure()->system() == m->system())
                    m = m->nextMeasure();
              spanner->setTick(m->tick());
              spanner->setTick2(m->endTick());
              }
        spanner->eraseSpannerSegments();
  
        undoAddElement(spanner);
        select(spanner, SelectType::SINGLE, 0);
        }
  
  //---------------------------------------------------------
  //   cmdAddSpanner
  //    used when applying a spanner to a selection
  //---------------------------------------------------------
  
  void Score::cmdAddSpanner(Spanner* spanner, int staffIdx, Segment* startSegment, Segment* endSegment)
        {
        int track = staffIdx * VOICES;
        spanner->setTrack(track);
        spanner->setTrack2(track);
        for (auto ss : spanner->spannerSegments())
              ss->setTrack(track);
        spanner->setTick(startSegment->tick());
        Fraction tick2;
        if (!endSegment)
              tick2 = lastSegment()->tick();
        else if (endSegment == startSegment)
              tick2 = startSegment->measure()->last()->tick();
        else
              tick2 = endSegment->tick();
        spanner->setTick2(tick2);
  #if 0 // TODO
        TextLine* tl = toTextLine(spanner);
        if (tl) {
              StyledPropertyListIdx st;
              Text* t;
              // begin
              t = tl->beginTextElement();
              if (t) {
                    st = t->textStyleType();
                    if (st >= StyledPropertyListIdx::DEFAULT)
                          t->textStyle().restyle(MScore::baseStyle().textStyle(st), textStyle(st));
                    }
              // continue
              t = tl->continueTextElement();
              if (t) {
                    st = t->textStyleType();
                    if (st >= StyledPropertyListIdx::DEFAULT)
                          t->textStyle().restyle(MScore::baseStyle().textStyle(st), textStyle(st));
                    }
              // end
              t = tl->endTextElement();
              if (t) {
                    st = t->textStyleType();
                    if (st >= StyledPropertyListIdx::DEFAULT)
                          t->textStyle().restyle(MScore::baseStyle().textStyle(st), textStyle(st));
                    }
              }
  #endif
        undoAddElement(spanner);
        }
  
  //---------------------------------------------------------
  //   expandVoice
  //    fills gaps in voice with rests,
  //    from previous cr (or beginning of measure) to next cr (or end of measure)
  //---------------------------------------------------------
  
  void Score::expandVoice(Segment* s, int track)
        {
        if (!s) {
              qDebug("expand voice: no segment");
              return;
              }
        if (s->element(track))
              return;
  
        // find previous segment with cr in this track
        Segment* ps;
        for (ps = s; ps; ps = ps->prev(SegmentType::ChordRest)) {
              if (ps->element(track))
                    break;
              }
        if (ps) {
              ChordRest* cr = toChordRest(ps->element(track));
              Fraction tick = cr->tick() + cr->actualTicks();
              if (tick > s->tick()) {
                    // previous cr extends past current segment
                    qDebug("expandVoice: cannot insert element here");
                    return;
                    }
              if (cr->isChord()) {
                    // previous cr ends on or before current segment
                    // for chords, move ps to just after cr ends
                    // so we can fill any gap that might exist
                    // but don't move ps if previous cr is a rest
                    // this will be combined with any new rests needed to fill up to s->tick() below
                    ps = ps->measure()->undoGetSegment(SegmentType::ChordRest, tick);
                    }
              }
        //
        // fill up to s->tick() with rests
        //
        Measure* m = s->measure();
        Fraction stick  = ps ?  ps->tick() : m->tick();
        Fraction ticks  = s->tick() - stick;
        if (ticks.isNotZero())
              setRest(stick, track, ticks, false, 0);
  
        //
        // fill from s->tick() until next chord/rest in measure
        //
        Segment* ns;
        for (ns = s->next(SegmentType::ChordRest); ns; ns = ns->next(SegmentType::ChordRest)) {
              if (ns->element(track))
                    break;
              }
        ticks  = ns ? (ns->tick() - s->tick()) : (m->ticks() - s->rtick());
        if (ticks == m->ticks())
              addRest(s, track, TDuration(TDuration::DurationType::V_MEASURE), 0);
        else
              setRest(s->tick(), track, ticks, false, 0);
        }
  
  void Score::expandVoice()
        {
        Segment* s = _is.segment();
        int track  = _is.track();
        expandVoice(s, track);
        }
  
  //---------------------------------------------------------
  //   cmdAddInterval
  //---------------------------------------------------------
  
  void Score::cmdAddInterval(int val, const std::vector<Note*>& nl)
        {
        startCmd();
        for (Note* on : nl) {
              Note* note = new Note(this);
              Chord* chord = on->chord();
              note->setParent(chord);
              note->setTrack(chord->track());
              int valTmp = val < 0 ? val+1 : val-1;
  
              int npitch;
              int ntpc1;
              int ntpc2;
              bool accidental = _is.noteEntryMode() && _is.accidentalType() != AccidentalType::NONE;
              bool forceAccidental = false;
              if (abs(valTmp) != 7 || accidental) {
                    int line      = on->line() - valTmp;
                    Fraction tick      = chord->tick();
                    Staff* estaff = staff(on->staffIdx() + chord->staffMove());
                    ClefType clef = estaff->clef(tick);
                    Key key       = estaff->key(tick);
                    int ntpc;
                    if (accidental) {
                          AccidentalVal acci = Accidental::subtype2value(_is.accidentalType());
                          int step = absStep(line, clef);
                          int octave = step / 7;
                          npitch = step2pitch(step) + octave * 12 + int(acci);
                          forceAccidental = (npitch == line2pitch(line, clef, key));
                          ntpc = step2tpc(step % 7, acci);
                          }
                    else {
                          npitch = line2pitch(line, clef, key);
                          ntpc = pitch2tpc(npitch, key, Prefer::NEAREST);
                          }
  
                    Interval v = on->part()->instrument(tick)->transpose();
                    if (v.isZero())
                          ntpc1 = ntpc2 = ntpc;
                    else {
                          if (styleB(Sid::concertPitch)) {
                                v.flip();
                                ntpc1 = ntpc;
                                ntpc2 = Ms::transposeTpc(ntpc, v, true);
                                }
                          else {
                                npitch += v.chromatic;
                                ntpc2 = ntpc;
                                ntpc1 = Ms::transposeTpc(ntpc, v, true);
                                }
                          }
                    }
              else { //special case for octave
                    Interval interval(7, 12);
                    if (val < 0)
                          interval.flip();
                    transposeInterval(on->pitch(), on->tpc(), &npitch, &ntpc1, interval, false);
                    ntpc1 = on->tpc1();
                    ntpc2 = on->tpc2();
                    }
              if (npitch < 0 || npitch > 127) {
                    delete note;
                    endCmd();
                    return;
                    }
              note->setPitch(npitch, ntpc1, ntpc2);
  
              undoAddElement(note);
              if (forceAccidental) {
                    Accidental* a = new Accidental(this);
                    a->setAccidentalType(_is.accidentalType());
                    a->setRole(AccidentalRole::USER);
                    a->setParent(note);
                    undoAddElement(a);
                    }
              setPlayNote(true);
  
              select(note, SelectType::SINGLE, 0);
              }
        if (_is.noteEntryMode())
              _is.setAccidentalType(AccidentalType::NONE);
        _is.moveToNextInputPos();
        endCmd();
        }
  
  //---------------------------------------------------------
  //   setGraceNote
  ///   Create a grace note in front of a normal note.
  ///   \arg ch is the chord of the normal note
  ///   \arg pitch is the pitch of the grace note
  ///   \arg is the grace note type
  ///   \len is the visual duration of the grace note (1/16 or 1/32)
  //---------------------------------------------------------
  
  Note* Score::setGraceNote(Chord* ch, int pitch, NoteType type, int len)
        {
        Note* note = new Note(this);
        Chord* chord = new Chord(this);
  
        // allow grace notes to be added to other grace notes
        // by really adding to parent chord
        if (ch->noteType() != NoteType::NORMAL)
              ch = toChord(ch->parent());
  
        chord->setTrack(ch->track());
        chord->setParent(ch);
        chord->add(note);
  
        note->setPitch(pitch);
        // find corresponding note within chord and use its tpc information
        for (Note* n : ch->notes()) {
              if (n->pitch() == pitch) {
                    note->setTpc1(n->tpc1());
                    note->setTpc2(n->tpc2());
                    break;
                    }
              }
        // note with same pitch not found, derive tpc from pitch / key
        if (!tpcIsValid(note->tpc1()) || !tpcIsValid(note->tpc2()))
              note->setTpcFromPitch();
  
        TDuration d;
        d.setVal(len);
        chord->setDurationType(d);
        chord->setTicks(d.fraction());
        chord->setNoteType(type);
        chord->setMag(ch->staff()->mag(chord->tick()) * styleD(Sid::graceNoteMag));
  
        undoAddElement(chord);
        select(note, SelectType::SINGLE, 0);
        return note;
        }
  
  //---------------------------------------------------------
  //   createCRSequence
  //    Create a rest or chord of len f.
  //    If f is not a basic len, create several rests or
  //    tied chords.
  //
  //    f     total len of ChordRest
  //    cr    prototype CR
  //    tick  start position in measure
  //---------------------------------------------------------
  
  void Score::createCRSequence(const Fraction& f, ChordRest* cr, const Fraction& t)
        {
        Fraction tick(t);
        Measure* measure = cr->measure();
        ChordRest* ocr = 0;
        for (TDuration d : toDurationList(f, true)) {
              ChordRest* ncr = toChordRest(cr->clone());
              ncr->setDurationType(d);
              ncr->setTicks(d.fraction());
              undoAddCR(ncr, measure, measure->tick() + tick);
              if (cr->isChord() && ocr) {
                    Chord* nc = toChord(ncr);
                    Chord* oc = toChord(ocr);
                    for (unsigned int i = 0; i < oc->notes().size(); ++i) {
                          Note* on = oc->notes()[i];
                          Note* nn = nc->notes()[i];
                          Tie* tie = new Tie(this);
                          tie->setStartNote(on);
                          tie->setEndNote(nn);
                          tie->setTrack(cr->track());
                          on->setTieFor(tie);
                          nn->setTieBack(tie);
                          undoAddElement(tie);
                          }
                    }
  
              tick += ncr->actualTicks();
              ocr = ncr;
              }
        }
  
  //---------------------------------------------------------
  //   setNoteRest
  //    pitch == -1  -> set rest
  //    return segment of last created note/rest
  //---------------------------------------------------------
  
  Segment* Score::setNoteRest(Segment* segment, int track, NoteVal nval, Fraction sd, Direction stemDirection, bool forceAccidental, bool rhythmic)
        {
        Q_ASSERT(segment->segmentType() == SegmentType::ChordRest);
  
        bool isRest   = nval.pitch == -1;
        Fraction tick = segment->tick();
        Element* nr   = 0;
        Tie* tie      = 0;
        ChordRest* cr = toChordRest(segment->element(track));
  
        Measure* measure = 0;
        for (;;) {
              if (track % VOICES)
                    expandVoice(segment, track);
  
              // the returned gap ends at the measure boundary or at tuplet end
              Fraction dd = makeGap(segment, track, sd, cr ? cr->tuplet() : 0);
  
              if (dd.isZero()) {
                    qDebug("cannot get gap at %d type: %d/%d", tick.ticks(), sd.numerator(),
                       sd.denominator());
                    break;
                    }
  
              measure = segment->measure();
              std::vector<TDuration> dl;
              if (rhythmic)
                    dl = toRhythmicDurationList(dd, isRest, segment->rtick(), sigmap()->timesig(tick).nominal(), measure, 1);
              else
                    dl = toDurationList(dd, true);
              size_t n = dl.size();
              for (size_t i = 0; i < n; ++i) {
                    const TDuration& d = dl[i];
                    ChordRest* ncr;
                    Note* note = 0;
                    Tie* addTie = 0;
                    if (isRest) {
                          nr = ncr = new Rest(this);
                          nr->setTrack(track);
                          ncr->setDurationType(d);
                          ncr->setTicks(d == TDuration::DurationType::V_MEASURE ? measure->ticks() : d.fraction());
                          }
                    else {
                          nr = note = new Note(this);
  
                          if (tie) {
                                tie->setEndNote(note);
                                note->setTieBack(tie);
                                addTie = tie;
                                }
                          Chord* chord = new Chord(this);
                          chord->setTrack(track);
                          chord->setDurationType(d);
                          chord->setTicks(d.fraction());
                          chord->setStemDirection(stemDirection);
                          chord->add(note);
                          note->setNval(nval, tick);
                          if (forceAccidental) {
                                int tpc = styleB(Sid::concertPitch) ? nval.tpc1 : nval.tpc2;
                                AccidentalVal alter = tpc2alter(tpc);
                                AccidentalType at = Accidental::value2subtype(alter);
                                Accidental* a = new Accidental(this);
                                a->setAccidentalType(at);
                                a->setRole(AccidentalRole::USER);
                                note->add(a);
                                }
                          ncr = chord;
                          if (i+1 < n) {
                                tie = new Tie(this);
                                tie->setStartNote(note);
                                tie->setTrack(track);
                                note->setTieFor(tie);
                                }
                          }
                    ncr->setTuplet(cr ? cr->tuplet() : 0);
                    undoAddCR(ncr, measure, tick);
                    if (addTie)
                          undoAddElement(addTie);
                    setPlayNote(true);
                    segment = ncr->segment();
                    tick += ncr->actualTicks();
                    }
  
              sd -= dd;
              if (sd.isZero())
                    break;
  
              Segment* nseg = tick2segment(tick, false, SegmentType::ChordRest);
              if (nseg == 0) {
                    qDebug("reached end of score");
                    break;
                    }
              segment = nseg;
  
              cr = toChordRest(segment->element(track));
  
              if (cr == 0) {
                    if (track % VOICES)
                          cr = addRest(segment, track, TDuration(TDuration::DurationType::V_MEASURE), 0);
                    else {
                          qDebug("no rest in voice 0");
                          break;
                          }
                    }
              //
              //  Note does not fit on current measure, create Tie to
              //  next part of note
              if (!isRest) {
                    tie = new Tie(this);
                    tie->setStartNote((Note*)nr);
                    tie->setTrack(nr->track());
                    ((Note*)nr)->setTieFor(tie);
                    }
              }
        if (tie)
              connectTies();
        if (nr) {
              if (_is.slur() && nr->type() == ElementType::NOTE) {
                    // If the start element was the same as the end element when the slur was created,
                    // the end grip of the front slur segment was given an x-offset of 3.0 * spatium().
                    // Now that the slur is about to be given a new end element, this should be reset.
                    if (_is.slur()->endElement() == _is.slur()->startElement())
                          _is.slur()->frontSegment()->reset();
                    //
                    // extend slur
                    //
                    Chord* chord = toNote(nr)->chord();
                    _is.slur()->undoChangeProperty(Pid::SPANNER_TICKS, chord->tick() - _is.slur()->tick());
                    for (ScoreElement* se : _is.slur()->linkList()) {
                          Slur* slur = toSlur(se);
                          for (ScoreElement* ee : chord->linkList()) {
                                Element* e = static_cast<Element*>(ee);
                                if (e->score() == slur->score() && e->track() == slur->track2()) {
                                      slur->score()->undo(new ChangeSpannerElements(slur, slur->startElement(), e));
                                      break;
                                      }
                                }
                          }
                    }
              select(nr, SelectType::SINGLE, 0);
              }
        return segment;
        }
  
  //---------------------------------------------------------
  //   makeGap
  //    make time gap at tick by removing/shortening
  //    chord/rest
  //
  //    if keepChord, the chord at tick is not removed
  //
  //    gap does not exceed measure or scope of tuplet
  //
  //    return size of actual gap
  //---------------------------------------------------------
  
  Fraction Score::makeGap(Segment* segment, int track, const Fraction& _sd, Tuplet* tuplet, bool keepChord)
        {
        Q_ASSERT(_sd.numerator());
  
        Measure* measure = segment->measure();
        Fraction accumulated;
        Fraction sd = _sd;
  
        //
        // remember first segment which should
        // not be deleted (it may contain other elements we want to preserve)
        //
        Segment* firstSegment = segment;
        const Fraction firstSegmentEnd = firstSegment->tick() + firstSegment->ticks();
        Fraction nextTick = segment->tick();
  
        for (Segment* seg = firstSegment; seg; seg = seg->next(SegmentType::ChordRest)) {
              //
              // voices != 0 may have gaps:
              //
              ChordRest* cr = toChordRest(seg->element(track));
              if (!cr) {
                    if (seg->tick() < nextTick)
                          continue;
                    Segment* seg1 = seg->next(SegmentType::ChordRest);
                    Fraction tick2     = seg1 ? seg1->tick() : seg->measure()->tick() + seg->measure()->ticks();
                    segment       = seg;
                    Fraction td(tick2 - seg->tick());
                    if (td > sd)
                          td = sd;
                    accumulated += td;
                    sd -= td;
                    if (sd.isZero())
                          break;
                    nextTick = tick2;
                    continue;
                    }
              if (seg->tick() > nextTick) {
                    // there was a gap
                    Fraction td(seg->tick() - nextTick);
                    if (td > sd)
                          td = sd;
                    accumulated += td;
                    sd -= td;
                    if (sd.isZero())
                          break;
                    }
              //
              // limit to tuplet level
              //
              if (tuplet) {
                    bool tupletEnd = true;
                    Tuplet* t = cr->tuplet();
                    while (t) {
                          if (cr->tuplet() == tuplet) {
                                tupletEnd = false;
                                break;
                                }
                          t = t->tuplet();
                          }
                    if (tupletEnd)
                          break;
                    }
              Fraction td(cr->ticks());
  
              // remove tremolo between 2 notes, if present
              if (cr->isChord()) {
                    Chord* c = toChord(cr);
                    if (c->tremolo()) {
                          Tremolo* tremolo = c->tremolo();
                          if (tremolo->twoNotes())
                                undoRemoveElement(tremolo);
                          }
                    }
              Tuplet* ltuplet = cr->tuplet();
              if (ltuplet != tuplet) {
                    //
                    // Current location points to the start of a (nested)tuplet.
                    // We have to remove the complete tuplet.
  
                    // get top level tuplet
                    while (ltuplet->tuplet())
                          ltuplet = ltuplet->tuplet();
  
                    // get last segment of tuplet, drilling down to leaf nodes as necessary
                    Tuplet* t = ltuplet;
                    while (t->elements().back()->isTuplet())
                          t = toTuplet(t->elements().back());
                    seg = toChordRest(t->elements().back())->segment();
  
                    // now delete the full tuplet
                    td = ltuplet->ticks();
                    cmdDeleteTuplet(ltuplet, false);
                    tuplet = 0;
                    }
              else {
                    if (seg != firstSegment || !keepChord)
                          undoRemoveElement(cr);
                    // even if there was a tuplet, we didn't remove it
                    ltuplet = 0;
                    }
              Fraction timeStretch = cr->staff()->timeStretch(cr->tick());
              nextTick += actualTicks(td, tuplet, timeStretch);
              if (sd < td) {
                    //
                    // we removed too much
                    //
                    accumulated = _sd;
                    Fraction rd = td - sd;
  
                    std::vector<TDuration> dList = toDurationList(rd, false);
                    if (dList.empty())
                          break;
  
                    Fraction tick = cr->tick() + actualTicks(sd, tuplet, timeStretch);
  
                    if ((tuplet == 0) && (((measure->tick() - tick).ticks() % dList[0].ticks().ticks()) == 0)) {
                          for (TDuration d : dList) {
                                if (ltuplet) {
                                      // take care not to recreate tuplet we just deleted
                                      Rest* r = setRest(tick, track, d.fraction(), false, 0, false);
                                      tick += r->actualTicks();
                                      }
                                else {
                                      tick += addClone(cr, tick, d)->actualTicks();
                                      }
                                }
                          }
                    else {
                          for (size_t i = dList.size(); i > 0; --i) { // loop needs to be in this reverse order
                                if (ltuplet) {
                                      // take care not to recreate tuplet we just deleted
                                      Rest* r = setRest(tick, track, dList[i-1].fraction(), false, 0, false);
                                      tick += r->actualTicks();
                                      }
                                else {
                                      tick += addClone(cr, tick, dList[i-1])->actualTicks();
                                      }
                                }
                          }
                    break;
                    }
              accumulated += td;
              sd          -= td;
              if (sd.isZero())
                    break;
              }
  //      Fraction ticks = measure->tick() + measure->ticks() - segment->tick();
  //      Fraction td = Fraction::fromTicks(ticks);
  // NEEDS REVIEW !!
  // once the statement below is removed, these two lines do nothing
  //      if (td > sd)
  //            td = sd;
  // ???  accumulated should already contain the total value of the created gap: line 749, 811 or 838
  //      this line creates a qreal-sized gap if the needed gap crosses a measure boundary
  //      by adding again the duration already added in line 838
  //      accumulated += td;
  
        const Fraction t1 = firstSegmentEnd;
        const Fraction t2 = firstSegment->tick() + accumulated;
        if (t1 < t2) {
              Segment* s1 = tick2rightSegment(t1);
              Segment* s2 = tick2rightSegment(t2);
              typedef SelectionFilterType Sel;
              // chord symbols can exist without chord/rest so they should not be removed
              constexpr Sel filter = static_cast<Sel>(int(Sel::ALL) & ~int(Sel::CHORD_SYMBOL));
              deleteAnnotationsFromRange(s1, s2, track, track + 1, filter);
              deleteSpannersFromRange(t1, t2, track, track + 1, filter);
              }
  
        return accumulated;
        }
  
  //---------------------------------------------------------
  //   makeGap1
  //    make time gap for each voice
  //    starting at tick+voiceOffset[voice] by removing/shortening
  //    chord/rest
  //    - cr is top level (not part of a tuplet)
  //    - do not stop at measure end
  //---------------------------------------------------------
  
  bool Score::makeGap1(const Fraction& baseTick, int staffIdx, const Fraction& len, int voiceOffset[VOICES])
        {
        Segment* seg = tick2segment(baseTick, true, SegmentType::ChordRest);
        if (!seg) {
              qDebug("no segment to paste at tick %d", baseTick.ticks());
              return false;
              }
        int strack = staffIdx * VOICES;
        for (int track = strack; track < strack + VOICES; track++) {
              if (voiceOffset[track-strack] == -1)
                    continue;
              Fraction tick = baseTick + Fraction::fromTicks(voiceOffset[track-strack]);
              Measure* m   = tick2measure(tick);
              if ((track % VOICES) && !m->hasVoices(staffIdx))
                    continue;
  
              Fraction newLen = len - Fraction::fromTicks(voiceOffset[track-strack]);
              Q_ASSERT(newLen.numerator() != 0);
  
              if (newLen > Fraction(0,1)) {
                    const Fraction endTick = tick + newLen;
                    deleteAnnotationsFromRange(tick2rightSegment(tick), tick2rightSegment(endTick), track, track + 1, selectionFilter());
                    deleteSpannersFromRange(tick, endTick, track, track + 1, selectionFilter());
                    }
  
              seg = m->undoGetSegment(SegmentType::ChordRest, tick);
              bool result = makeGapVoice(seg, track, newLen, tick);
              if (track == strack && !result) // makeGap failed for first voice
                    return false;
              }
        return true;
        }
  
  bool Score::makeGapVoice(Segment* seg, int track, Fraction len, const Fraction& tick)
        {
        ChordRest* cr = 0;
        cr = toChordRest(seg->element(track));
        if (!cr) {
              // check if we are in the middle of a chord/rest
              Segment* seg1 = seg->prev(SegmentType::ChordRest);
              for (;;) {
                    if (seg1 == 0) {
                          if (!(track % VOICES))
                                qDebug("no segment before tick %d", tick.ticks());
                          // this happens only for voices other than voice 1
                          expandVoice(seg, track);
                          return makeGapVoice(seg,track,len,tick);
                          }
                    if (seg1->element(track))
                          break;
                    seg1 = seg1->prev(SegmentType::ChordRest);
                    }
              ChordRest* cr1 = toChordRest(seg1->element(track));
              Fraction srcF = cr1->ticks();
              Fraction dstF = tick - cr1->tick();
              std::vector<TDuration> dList = toDurationList(dstF, true);
              size_t n = dList.size();
              undoChangeChordRestLen(cr1, TDuration(dList[0]));
              if (n > 1) {
                    Fraction crtick = cr1->tick() + cr1->actualTicks();
                    Measure* measure = tick2measure(crtick);
                    if (cr1->type() == ElementType::CHORD) {
                          // split Chord
                          Chord* c = toChord(cr1);
                          for (size_t i = 1; i < n; ++i) {
                                TDuration d = dList[i];
                                Chord* c2 = addChord(crtick, d, c, true, c->tuplet());
                                c = c2;
                                seg1 = c->segment();
                                crtick += c->actualTicks();
                                }
                          }
                    else {
                          // split Rest
                          Rest* r       = toRest(cr1);
                          for (size_t i = 1; i < n; ++i) {
                                TDuration d = dList[i];
                                Rest* r2      = toRest(r->clone());
                                r2->setTicks(d.fraction());
                                r2->setDurationType(d);
                                undoAddCR(r2, measure, crtick);
                                seg1 = r2->segment();
                                crtick += r2->actualTicks();
                                }
                          }
                    }
              setRest(tick, track, srcF - dstF, true, 0);
              for (;;) {
                    seg1 = seg1->next1(SegmentType::ChordRest);
                    if (seg1 == 0) {
                          qDebug("no segment");
                          return false;
                          }
                    if (seg1->element(track)) {
                          cr = toChordRest(seg1->element(track));
                          break;
                          }
                    }
              }
  
        for (;;) {
              if (!cr) {
                    qDebug("cannot make gap");
                    return false;
                    }
              Fraction l = makeGap(cr->segment(), cr->track(), len, 0);
              if (l.isZero()) {
                    qDebug("returns zero gap");
                    return false;
                    }
              len -= l;
              if (len.isZero())
                    break;
              // go to next cr
              Measure* m = cr->measure()->nextMeasure();
              if (m == 0) {
                    qDebug("EOS reached");
                    insertMeasure(ElementType::MEASURE, 0, false);
                    m = cr->measure()->nextMeasure();
                    if (m == 0) {
                          qDebug("===EOS reached");
                          return true;
                          }
                    }
              // first segment in measure was removed, have to recreate it
              Segment* s = m->undoGetSegment(SegmentType::ChordRest, m->tick());
              int t  = cr->track();
              cr = toChordRest(s->element(t));
              if (cr == 0) {
                    addRest(s, t, TDuration(TDuration::DurationType::V_MEASURE), 0);
                    cr = toChordRest(s->element(t));
                    }
              }
        return true;
        }
  
  //---------------------------------------------------------
  //   splitGapToMeasureBoundaries
  //    cr  - start of gap
  //    gap - gap len
  //---------------------------------------------------------
  
  QList<Fraction> Score::splitGapToMeasureBoundaries(ChordRest* cr, Fraction gap)
        {
        QList<Fraction> flist;
  
        Tuplet* tuplet = cr->tuplet();
        if (tuplet) {
              Fraction rest = tuplet->elementsDuration();
              for (DurationElement* de : tuplet->elements()) {
                    if (de == cr)
                          break;
                    rest -= de->ticks();
                    }
              if (rest < gap)
                    qDebug("does not fit in tuplet");
              else
                    flist.append(gap);
              return flist;
              }
  
        Segment* s = cr->segment();
        while (gap > Fraction(0,1)) {
              Measure* m    = s->measure();
              Fraction timeStretch = cr->staff()->timeStretch(s->tick());
              Fraction rest = (m->ticks() - s->rtick()) * timeStretch;
              if (rest >= gap) {
                    flist.append(gap);
                    return flist;
                    }
              flist.append(rest);
              gap -= rest;
              m = m->nextMeasure();
              if (m == 0)
                    return flist;
              s = m->first(SegmentType::ChordRest);
              }
        return flist;
        }
  
  //---------------------------------------------------------
  //   changeCRlen
  //---------------------------------------------------------
  
  void Score::changeCRlen(ChordRest* cr, const TDuration& d)
        {
        Fraction dstF;
        if (d.type() == TDuration::DurationType::V_MEASURE)
              dstF = cr->measure()->stretchedLen(cr->staff());
        else
              dstF = d.fraction();
        changeCRlen(cr, dstF);
        }
  
  void Score::changeCRlen(ChordRest* cr, const Fraction& dstF, bool fillWithRest)
        {
        if (cr->isRepeatMeasure()) {
              // it is not clear what should this
              // operation mean for measure repeats.
              return;
              }
        Fraction srcF(cr->ticks());
        if (srcF == dstF) {
              if (cr->isFullMeasureRest())
                    undoChangeChordRestLen(cr, dstF);
              return;
              }
  
        //keep selected element if any
        Element* selElement = selection().isSingle() ? getSelectedElement() : 0;
  
        int track      = cr->track();
        Tuplet* tuplet = cr->tuplet();
  
        if (srcF > dstF) {
              //
              // make shorter and fill with rest
              //
              deselectAll();
              if (cr->isChord()) {
                    //
                    // remove ties and tremolo between 2 notes
                    //
                    Chord* c = toChord(cr);
                    if (c->tremolo()) {
                          Tremolo* tremolo = c->tremolo();
                          if (tremolo->twoNotes())
                                undoRemoveElement(tremolo);
                          }
                    foreach (Note* n, c->notes()) {
                          if (n->tieFor())
                                undoRemoveElement(n->tieFor());
                          }
                    }
              Fraction timeStretch = cr->staff()->timeStretch(cr->tick());
              std::vector<TDuration> dList = toDurationList(dstF, true);
              undoChangeChordRestLen(cr, dList[0]);
              Fraction tick2 = cr->tick();
              for (unsigned i = 1; i < dList.size(); ++i) {
                    tick2 += actualTicks(dList[i-1].ticks(), tuplet, timeStretch);
                    TDuration d = dList[i];
                    setRest(tick2, track, d.fraction(), (d.dots() > 0), tuplet);
                    }
              if (fillWithRest)
                    setRest(cr->tick() + cr->actualTicks(), track, srcF - dstF, false, tuplet);
  
              if (selElement)
                    select(selElement, SelectType::SINGLE, 0);
              return;
              }
  
        //
        // make longer
        //
        // split required len into Measures
        QList<Fraction> flist = splitGapToMeasureBoundaries(cr, dstF);
        if (flist.empty())
              return;
  
        deselectAll();
  
        Fraction tick  = cr->tick();
        Fraction f     = dstF;
        ChordRest* cr1 = cr;
        Chord* oc      = 0;
  
        bool first = true;
        for (Fraction f2 : flist) {
              f  -= f2;
              makeGap(cr1->segment(), cr1->track(), f2, tuplet, first);
  
              if (cr->isRest()) {
                    Fraction timeStretch = cr1->staff()->timeStretch(cr1->tick());
                    Rest* r = toRest(cr);
                    if (first) {
                          std::vector<TDuration> dList = toDurationList(f2, true);
                          undoChangeChordRestLen(cr, dList[0]);
                          Fraction tick2 = cr->tick();
                          for (unsigned i = 1; i < dList.size(); ++i) {
                                tick2 += actualTicks(dList[i-1].ticks(), tuplet, timeStretch);
                                TDuration d = dList[i];
                                setRest(tick2, track, d.fraction(), (d.dots() > 0), tuplet);
                                }
                          }
                    else {
                          r = setRest(tick, track, f2, false, tuplet);
                          }
                    if (first) {
                          select(r, SelectType::SINGLE, 0);
                          first = false;
                          }
                    tick += actualTicks(f2, tuplet, timeStretch);
                    }
              else {
                    std::vector<TDuration> dList = toDurationList(f2, true);
                    Measure* measure             = tick2measure(tick);
                    Fraction etick                    = measure->tick();
  
                    if (((tick - etick).ticks() % dList[0].ticks().ticks()) == 0) {
                          for (TDuration du : dList) {
                                bool genTie;
                                Chord* cc;
                                if (oc) {
                                      genTie = true;
                                      cc = oc;
                                      oc = addChord(tick, du, cc, genTie, tuplet);
                                      }
                                else {
                                      genTie = false;
                                      cc = toChord(cr);
                                      undoChangeChordRestLen(cr, du);
                                      oc = cc;
                                      }
                                if (oc && first) {
                                      if (!selElement)
                                            select(oc, SelectType::SINGLE, 0);
                                      else
                                            select(selElement, SelectType::SINGLE, 0);
                                      first = false;
                                      }
                                if (oc)
                                      tick += oc->actualTicks();
                                }
                          }
                    else {
                          for (size_t i = dList.size(); i > 0; --i) { // loop probably needs to be in this reverse order
                                bool genTie;
                                Chord* cc;
                                if (oc) {
                                      genTie = true;
                                      cc = oc;
                                      oc = addChord(tick, dList[i-1], cc, genTie, tuplet);
                                      }
                                else {
                                      genTie = false;
                                      cc = toChord(cr);
                                      undoChangeChordRestLen(cr, dList[i-1]);
                                      oc = cc;
                                      }
                                if (first) {
                                      // select(oc, SelectType::SINGLE, 0);
                                      if (selElement)
                                            select(selElement, SelectType::SINGLE, 0);
                                      first = false;
                                      }
                                tick += oc->actualTicks();
                                }
                          }
                    }
              Measure* m  = cr1->measure();
              Measure* m1 = m->nextMeasure();
              if (m1 == 0)
                    break;
              Segment* s = m1->first(SegmentType::ChordRest);
              expandVoice(s, track);
              cr1 = toChordRest(s->element(track));
              }
        connectTies();
        }
  
  //---------------------------------------------------------
  //   upDownChromatic
  //---------------------------------------------------------
  
  static void upDownChromatic(bool up, int pitch, Note* n, Key key, int tpc1, int tpc2, int& newPitch, int& newTpc1, int& newTpc2)
        {
        if (up && pitch < 127) {
              newPitch = pitch + 1;
              if (n->concertPitch()) {
                    if (tpc1 > Tpc::TPC_A + int(key))
                          newTpc1 = tpc1 - 5;   // up semitone diatonic
                    else
                          newTpc1 = tpc1 + 7;   // up semitone chromatic
                    newTpc2 = n->transposeTpc(newTpc1);
                    }
              else {
                    if (tpc2 > Tpc::TPC_A + int(key))
                          newTpc2 = tpc2 - 5;   // up semitone diatonic
                    else
                          newTpc2 = tpc2 + 7;   // up semitone chromatic
                    newTpc1 = n->transposeTpc(newTpc2);
                    }
              }
        else if (!up && pitch > 0) {
              newPitch = pitch - 1;
              if (n->concertPitch()) {
                    if (tpc1 > Tpc::TPC_C + int(key))
                          newTpc1 = tpc1 - 7;   // down semitone chromatic
                    else
                          newTpc1 = tpc1 + 5;   // down semitone diatonic
                    newTpc2 = n->transposeTpc(newTpc1);
                    }
              else {
                    if (tpc2 > Tpc::TPC_C + int(key))
                          newTpc2 = tpc2 - 7;   // down semitone chromatic
                    else
                          newTpc2 = tpc2 + 5;   // down semitone diatonic
                    newTpc1 = n->transposeTpc(newTpc2);
                    }
              }
        }
  
  //---------------------------------------------------------
  //   setTpc
  //---------------------------------------------------------
  
  static void setTpc(Note* oNote, int tpc, int& newTpc1, int& newTpc2)
        {
        if (oNote->concertPitch()) {
              newTpc1 = tpc;
              newTpc2 = oNote->transposeTpc(tpc);
              }
        else {
              newTpc2 = tpc;
              newTpc1 = oNote->transposeTpc(tpc);
              }
        }
  
  //---------------------------------------------------------
  //   upDown
  ///   Increment/decrement pitch of note by one or by an octave.
  //---------------------------------------------------------
  
  void Score::upDown(bool up, UpDownMode mode)
        {
        QList<Note*> el = selection().uniqueNotes();
  
        for (Note* oNote : el) {
              Fraction tick     = oNote->chord()->tick();
              Staff* staff = oNote->staff();
              Part* part   = staff->part();
              Key key      = staff->key(tick);
              int tpc1     = oNote->tpc1();
              int tpc2     = oNote->tpc2();
              int pitch    = oNote->pitch();
              int newTpc1  = tpc1;      // default to unchanged
              int newTpc2  = tpc2;      // default to unchanged
              int newPitch = pitch;     // default to unchanged
              int string   = oNote->string();
              int fret     = oNote->fret();
  
              switch (staff->staffType(oNote->chord()->tick())->group()) {
                    case StaffGroup::PERCUSSION:
                          {
                          const Drumset* ds = part->instrument()->drumset();
                          if (ds) {
                                newPitch = up ? ds->nextPitch(pitch) : ds->prevPitch(pitch);
                                newTpc1 = pitch2tpc(newPitch, Key::C, Prefer::NEAREST);
                                newTpc2 = newTpc1;
                                }
                          }
                          break;
                    case StaffGroup::TAB:
                          {
                          const StringData* stringData = part->instrument()->stringData();
                          switch (mode) {
                                case UpDownMode::OCTAVE:          // move same note to next string, if possible
                                      {
                                      const StaffType* stt = staff->staffType(tick);
                                      string = stt->physStringToVisual(string);
                                      string += (up ? -1 : 1);
                                      if (string < 0 || string >= stringData->strings())
                                            return;           // no next string to move to
                                      string = stt->visualStringToPhys(string);
                                      fret = stringData->fret(pitch, string, staff, tick);
                                      if (fret == -1)          // can't have that note on that string
                                            return;
                                      // newPitch and newTpc remain unchanged
                                      }
                                      break;
  
                                case UpDownMode::DIATONIC:        // increase / decrease the pitch,
                                                              // letting the algorithm to choose fret & string
                                      upDownChromatic(up, pitch, oNote, key, tpc1, tpc2, newPitch, newTpc1, newTpc2);
                                      break;
  
                                case UpDownMode::CHROMATIC:       // increase / decrease the fret
                                      {                       // without changing the string
                                      // compute new fret
                                      if (!stringData->frets()) {
                                            qDebug("upDown tab chromatic: no frets?");
                                            return;
                                            }
                                      fret += (up ? 1 : -1);
                                      if (fret < 0 || fret > stringData->frets()) {
                                            qDebug("upDown tab in-string: out of fret range");
                                            return;
                                            }
                                      // update pitch and tpc's and check it matches stringData
                                      upDownChromatic(up, pitch, oNote, key, tpc1, tpc2, newPitch, newTpc1, newTpc2);
                                      if (newPitch != stringData->getPitch(string, fret, staff, tick) ) {
                                            // oh-oh: something went very wrong!
                                            qDebug("upDown tab in-string: pitch mismatch");
                                            return;
                                      }
                                      // store the fretting change before undoChangePitch() chooses
                                      // a fretting of its own liking!
                                      oNote->undoChangeProperty(Pid::FRET, fret);
                                      }
                                      break;
                                }
                          }
                          break;
                    case StaffGroup::STANDARD:
                          switch (mode) {
                                case UpDownMode::OCTAVE:
                                      if (up) {
                                            if (pitch < 116)
                                                  newPitch = pitch + 12;
                                            }
                                      else {
                                            if (pitch > 11)
                                                  newPitch = pitch - 12;
                                            }
                                      // newTpc remains unchanged
                                      break;
  
                                case UpDownMode::CHROMATIC:
                                      upDownChromatic(up, pitch, oNote, key, tpc1, tpc2, newPitch, newTpc1, newTpc2);
                                      break;
  
                                case UpDownMode::DIATONIC:
                                      {
                                      int tpc = oNote->tpc();
                                      if (up) {
                                            if (tpc > Tpc::TPC_A + int(key)) {
                                                  if (pitch < 127) {
                                                        newPitch = pitch + 1;
                                                        setTpc(oNote, tpc - 5, newTpc1, newTpc2);
                                                        }
                                                  }
                                            else {
                                                  if (pitch < 126) {
                                                        newPitch = pitch + 2;
                                                        setTpc(oNote, tpc + 2, newTpc1, newTpc2);
                                                        }
                                                  }
                                            }
                                      else {
                                            if (tpc > Tpc::TPC_C + int(key)) {
                                                  if (pitch > 1) {
                                                        newPitch = pitch - 2;
                                                        setTpc(oNote, tpc - 2, newTpc1, newTpc2);
                                                        }
                                                  }
                                            else {
                                                  if (pitch > 0) {
                                                        newPitch = pitch - 1;
                                                        setTpc(oNote, tpc + 5, newTpc1, newTpc2);
                                                        }
                                                  }
                                            }
                                      }
                                      break;
                                }
                          break;
                    }
  
              if ((oNote->pitch() != newPitch) || (oNote->tpc1() != newTpc1) || oNote->tpc2() != newTpc2) {
                    // remove accidental if present to make sure
                    // user added accidentals are removed here
                    // unless it's an octave change
                    // in this case courtesy accidentals are preserved
                    // because they're now harder to be re-entered due to the revised note-input workflow
                    if (mode != UpDownMode::OCTAVE) {
                          auto l = oNote->linkList();
                          for (ScoreElement* e : l) {
                                Note* ln = toNote(e);
                                if (ln->accidental())
                                      undo(new RemoveElement(ln->accidental()));
                                }
                          }
                    undoChangePitch(oNote, newPitch, newTpc1, newTpc2);
                    }
  
              // store fret change only if undoChangePitch has not been called,
              // as undoChangePitch() already manages fret changes, if necessary
              else if (staff->staffType(tick)->group() == StaffGroup::TAB) {
                    bool refret = false;
                    if (oNote->string() != string) {
                          oNote->undoChangeProperty(Pid::STRING, string);
                          refret = true;
                          }
                    if (oNote->fret() != fret) {
                          oNote->undoChangeProperty(Pid::FRET, fret);
                          refret = true;
                          }
                    if (refret) {
                          const StringData* stringData = part->instrument()->stringData();
                          stringData->fretChords(oNote->chord());
                          }
                    }
  
              // play new note with velocity 80 for 0.3 sec:
              setPlayNote(true);
              }
        setSelectionChanged(true);
        }
  
  //---------------------------------------------------------
  //   upDownDelta
  ///   Add the delta to the pitch of note.
  //---------------------------------------------------------
  
  void Score::upDownDelta(int pitchDelta)
        {
        while (pitchDelta > 0) {
              upDown(true, UpDownMode::CHROMATIC);
              pitchDelta--;
              }
  
        while (pitchDelta < 0) {
              upDown(false, UpDownMode::CHROMATIC);
              pitchDelta++;
              }
        }
  
  //---------------------------------------------------------
  //   addArticulation
  ///   Add attribute \a attr to all selected notes/rests.
  ///
  ///   Called from padToggle() to add note prefix/accent.
  //---------------------------------------------------------
  
  void Score::addArticulation(SymId attr)
        {
        QSet<Chord*> set;
        for (Element* el : selection().elements()) {
              if (el->isNote() || el->isChord()) {
                    Chord* cr = 0;
                    // apply articulation on a given chord only once
                    if (el->isNote()) {
                          cr = toNote(el)->chord();
                          if (set.contains(cr))
                                continue;
                          }
                    Articulation* na = new Articulation(this);
                    na->setSymId(attr);
                    if (!addArticulation(el, na))
                          delete na;
                    if (cr)
                          set.insert(cr);
                    }
              }
        }
  
  //---------------------------------------------------------
  //   toggleAccidental
  //---------------------------------------------------------
  
  void Score::toggleAccidental(AccidentalType at, const EditData& ed)
        {
        if (_is.accidentalType() == at)
              at = AccidentalType::NONE;
        if (noteEntryMode()) {
              _is.setAccidentalType(at);
              _is.setRest(false);
              }
        else {
              if (selection().isNone()) {
                    ed.view->startNoteEntryMode();
                    _is.setAccidentalType(at);
                    _is.setDuration(TDuration::DurationType::V_QUARTER);
                    _is.setRest(false);
                    }
              else
                    changeAccidental(at);
              }
        }
  //---------------------------------------------------------
  //   changeAccidental
  ///   Change accidental to subtype \a idx for all selected
  ///   notes.
  //---------------------------------------------------------
  
  void Score::changeAccidental(AccidentalType idx)
        {
        foreach(Note* note, selection().noteList())
              changeAccidental(note, idx);
        }
  
  //---------------------------------------------------------
  //   changeAccidental2
  //---------------------------------------------------------
  
  static void changeAccidental2(Note* n, int pitch, int tpc)
        {
        Score* score  = n->score();
        Chord* chord  = n->chord();
        Staff* st     = chord->staff();
        int fret      = n->fret();
        int string    = n->string();
  
        if (st->isTabStaff(chord->tick())) {
              if (pitch != n->pitch()) {
                    //
                    // as pitch has changed, calculate new
                    // string & fret
                    //
                    const StringData* stringData = n->part()->instrument()->stringData();
                    if (stringData)
                          stringData->convertPitch(pitch, st, chord->tick(), &string, &fret);
                    }
              }
        int tpc1;
        int tpc2 = n->transposeTpc(tpc);
        if (score->styleB(Sid::concertPitch))
              tpc1 = tpc;
        else {
              tpc1 = tpc2;
              tpc2 = tpc;
              }
  
        if (!st->isTabStaff(chord->tick())) {
              //
              // handle ties
              //
              if (n->tieBack()) {
                    if (pitch != n->pitch()) {
                          score->undoRemoveElement(n->tieBack());
                          if (n->tieFor())
                                score->undoRemoveElement(n->tieFor());
                          }
                    }
              else {
                    Note* nn = n;
                    while (nn->tieFor()) {
                          nn = nn->tieFor()->endNote();
                          score->undo(new ChangePitch(nn, pitch, tpc1, tpc2));
                          }
                    }
              }
        score->undoChangePitch(n, pitch, tpc1, tpc2);
        }
  
  //---------------------------------------------------------
  //   changeAccidental
  ///   Change accidental to subtype \accidental for
  ///   note \a note.
  //---------------------------------------------------------
  
  void Score::changeAccidental(Note* note, AccidentalType accidental)
        {
        Chord* chord = note->chord();
        if (!chord)
              return;
        Segment* segment = chord->segment();
        if (!segment)
              return;
        Measure* measure = segment->measure();
        if (!measure)
              return;
        Fraction tick = segment->tick();
        Staff* estaff = staff(chord->staffIdx() + chord->staffMove());
        if (!estaff)
              return;
        ClefType clef = estaff->clef(tick);
        int step      = ClefInfo::pitchOffset(clef) - note->line();
        while (step < 0)
              step += 7;
        step %= 7;
        //
        // accidental change may result in pitch change
        //
        AccidentalVal acc2 = measure->findAccidental(note);
        AccidentalVal acc = (accidental == AccidentalType::NONE) ? acc2 : Accidental::subtype2value(accidental);
  
        int pitch = line2pitch(note->line(), clef, Key::C) + int(acc);
        if (!note->concertPitch())
              pitch += note->transposition();
  
        int tpc = step2tpc(step, acc);
  
        bool forceRemove = false;
        bool forceAdd = false;
  
        // delete accidental
        // both for this note and for any linked notes
        if (accidental == AccidentalType::NONE)
              forceRemove = true;
  
        // precautionary or microtonal accidental
        // either way, we display it unconditionally
        // both for this note and for any linked notes
        else if (acc == acc2 || (pitch == note->pitch() && !Accidental::isMicrotonal(note->accidentalType())) || Accidental::isMicrotonal(accidental))
              forceAdd = true;
  
        for (ScoreElement* se : note->linkList()) {
              Note* ln = toNote(se);
              if (ln->concertPitch() != note->concertPitch())
                    continue;
              Score* lns    = ln->score();
              Accidental* a = ln->accidental();
              if (forceRemove) {
                    if (a)
                          lns->undoRemoveElement(a);
                    if (ln->tieBack())
                          continue;
                    }
              else if (forceAdd) {
                    if (a)
                          undoRemoveElement(a);
                    Accidental* a1 = new Accidental(lns);
                    a1->setParent(ln);
                    a1->setAccidentalType(accidental);
                    a1->setRole(AccidentalRole::USER);
                    lns->undoAddElement(a1);
                    }
              else if (a && Accidental::isMicrotonal(a->accidentalType())) {
                    lns->undoRemoveElement(a);
                    }
              changeAccidental2(ln, pitch, tpc);
              }
        setPlayNote(true);
        setSelectionChanged(true);
        }
  
  //---------------------------------------------------------
  //   addArticulation
  //---------------------------------------------------------
  
  bool Score::addArticulation(Element* el, Articulation* a)
        {
        Chord* c;
        if (el->isNote())
              c = toNote(el)->chord();
        else if (el->isChord())
              c = toChord(el);
        else
              return false;
        Articulation* oa = c->hasArticulation(a);
        if (oa) {
              undoRemoveElement(oa);
              return false;
              }
        a->setParent(c);
        a->setTrack(c->track()); // make sure it propagates between score and parts
        undoAddElement(a);
        return true;
        }
  
  //---------------------------------------------------------
  //   resetUserStretch
  //---------------------------------------------------------
  
  void Score::resetUserStretch()
        {
        Measure* m1;
        Measure* m2;
        // retrieve span of selection
        Segment* s1 = _selection.startSegment();
        Segment* s2 = _selection.endSegment();
        // if either segment is not returned by the selection
        // (for instance, no selection) fall back to first/last measure
        if (!s1)
              m1 = firstMeasureMM();
        else
              m1 = s1->measure();
        if (!s2)
              m2 = lastMeasureMM();
        else
              m2 = s2->measure();
        if (!m1 || !m2)               // should not happen!
              return;
  
        for (Measure* m = m1; m; m = m->nextMeasureMM()) {
              m->undoChangeProperty(Pid::USER_STRETCH, 1.0);
              if (m == m2)
                    break;
              }
        }
  
  //---------------------------------------------------------
  //   moveUp
  //---------------------------------------------------------
  
  void Score::moveUp(ChordRest* cr)
        {
        Staff* staff  = cr->staff();
        Part* part    = staff->part();
        int rstaff    = staff->rstaff();
        int staffMove = cr->staffMove();
  
        if ((staffMove == -1) || (rstaff + staffMove <= 0))
              return;
  
        QList<Staff*>* staves = part->staves();
        // we know that staffMove+rstaff-1 index exists due to the previous condition.
        if (staff->staffType(cr->tick())->group() != StaffGroup::STANDARD ||
            staves->at(rstaff+staffMove-1)->staffType(cr->tick())->group() != StaffGroup::STANDARD) {
              qDebug("User attempted to move a note from/to a staff which does not use standard notation - ignoring.");
              }
        else  {
              // move the chord up a staff
              undo(new ChangeChordStaffMove(cr, staffMove - 1));
              }
        }
  
  //---------------------------------------------------------
  //   moveDown
  //---------------------------------------------------------
  
  void Score::moveDown(ChordRest* cr)
        {
        Staff* staff  = cr->staff();
        Part* part    = staff->part();
        int rstaff    = staff->rstaff();
        int staffMove = cr->staffMove();
        // calculate the number of staves available so that we know whether there is another staff to move down to
        int rstaves   = part->nstaves();
  
        if ((staffMove == 1) || (rstaff + staffMove >= rstaves - 1)) {
              qDebug("moveDown staffMove==%d  rstaff %d rstaves %d", staffMove, rstaff, rstaves);
              return;
              }
  
        QList<Staff*>* staves = part->staves();
        // we know that staffMove+rstaff+1 index exists due to the previous condition.
        if (staff->staffType(cr->tick())->group() != StaffGroup::STANDARD ||
            staves->at(staffMove+rstaff+1)->staffType(cr->tick())->group() != StaffGroup::STANDARD) {
              qDebug("User attempted to move a note from/to a staff which does not use standard notation - ignoring.");
              }
        else  {
              // move the chord down a staff
              undo(new ChangeChordStaffMove(cr, staffMove + 1));
              }
        }
  
  //---------------------------------------------------------
  //   cmdAddStretch
  //---------------------------------------------------------
  
  void Score::cmdAddStretch(qreal val)
        {
        if (!selection().isRange())
              return;
        Fraction startTick = selection().tickStart();
        Fraction endTick   = selection().tickEnd();
        for (Measure* m = firstMeasureMM(); m; m = m->nextMeasureMM()) {
              if (m->tick() < startTick)
                    continue;
              if (m->tick() >= endTick)
                    break;
              qreal stretch = m->userStretch();
              stretch += val;
              if (stretch < 0)
                    stretch = 0;
              m->undoChangeProperty(Pid::USER_STRETCH, stretch);
              }
        }
  
  //---------------------------------------------------------
  //   cmdResetBeamMode
  //---------------------------------------------------------
  
  void Score::cmdResetBeamMode()
        {
        bool noSelection = selection().isNone();
        if (noSelection)
              cmdSelectAll();
        else if (!selection().isRange()) {
              qDebug("no system or staff selected");
              return;
              }
  
        Fraction endTick = selection().tickEnd();
  
        for (Segment* seg = selection().firstChordRestSegment(); seg && seg->tick() < endTick; seg = seg->next1(SegmentType::ChordRest)) {
              for (int track = selection().staffStart() * VOICES; track < selection().staffEnd() * VOICES; ++track) {
                    ChordRest* cr = toChordRest(seg->element(track));
                    if (cr == 0)
                          continue;
                    if (cr->type() == ElementType::CHORD) {
                          if (cr->beamMode() != Beam::Mode::AUTO)
                                cr->undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::AUTO));
                          }
                    else if (cr->type() == ElementType::REST) {
                          if (cr->beamMode() != Beam::Mode::NONE)
                                cr->undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::NONE));
                          }
                    }
              }
        if (noSelection)
              deselectAll();
        }
  
  //---------------------------------------------------------
  //   cmdResetStyle
  //---------------------------------------------------------
  
  void Score::cmdResetStyle()
        {
        style().reset(this);
        }
  
  //---------------------------------------------------------
  //   cmdResetNoteAndRestGroupings
  //---------------------------------------------------------
  
  void Score::cmdResetNoteAndRestGroupings()
        {
        bool noSelection = selection().isNone();
        if (noSelection)
              cmdSelectAll();
        else if (!selection().isRange()) {
              qDebug("no system or staff selected");
              return;
              }
  
        // save selection values because selection changes during grouping
        Fraction sTick = selection().tickStart();
        Fraction eTick = selection().tickEnd();
        int sStaff = selection().staffStart();
        int eStaff = selection().staffEnd();
  
        startCmd();
        for (int staff = sStaff; staff < eStaff; staff++) {
              int sTrack = staff * VOICES;
              int eTrack = sTrack + VOICES;
              for (int track = sTrack; track < eTrack; track++) {
                    if (selectionFilter().canSelectVoice(track))
                          regroupNotesAndRests(sTick, eTick, track);
                    }
              }
        endCmd();
        if (noSelection)
              deselectAll();
        }
  
  //---------------------------------------------------------
  //   resetElementShapePosition
  //    For use with Score::scanElements.
  //    Reset positions and autoplacement for the given
  //    element.
  //---------------------------------------------------------
  
  static void resetElementPosition(void*, Element* e)
        {
        if (e->generated())
              return;
        e->undoResetProperty(Pid::AUTOPLACE);
        e->undoResetProperty(Pid::OFFSET);
        e->setOffsetChanged(false);
        if (e->isSpanner())
              e->undoResetProperty(Pid::OFFSET2);
        }
  
  //---------------------------------------------------------
  //   cmdResetAllPositions
  //---------------------------------------------------------
  
  void Score::cmdResetAllPositions()
        {
        startCmd();
        scanElements(nullptr, resetElementPosition);
        endCmd();
        }
  
  //---------------------------------------------------------
  //   processMidiInput
  //---------------------------------------------------------
  
  bool Score::processMidiInput()
        {
        if (midiInputQueue()->empty())
              return false;
  
        if (MScore::debugMode)
            qDebug("processMidiInput");
  
        NoteEntryMethod entryMethod = _is.noteEntryMethod();
        bool cmdActive = false;
        while (!midiInputQueue()->empty()) {
              MidiInputEvent ev = midiInputQueue()->dequeue();
              for (auto itr = activeMidiPitches()->begin(); itr != activeMidiPitches()->end();) {
                    if ((*itr).pitch == ev.pitch)
                          itr = activeMidiPitches()->erase(itr);
                    else
                          ++itr;
                    }
              if (MScore::debugMode)
                    qDebug("<-- !noteentry dequeue %i", ev.pitch);
              if (!noteEntryMode()
                          || entryMethod == NoteEntryMethod::REALTIME_AUTO
                          || entryMethod == NoteEntryMethod::REALTIME_MANUAL) {
                    int staffIdx = selection().staffStart();
                    Part* p;
                    if (staffIdx < 0 || staffIdx >= nstaves())
                          p = staff(0)->part();
                    else
                          p = staff(staffIdx)->part();
                    if (p) {
                          if (!styleB(Sid::concertPitch)) {
                                ev.pitch += p->instrument(selection().tickStart())->transpose().chromatic;
                                }
                          MScore::seq->startNote(
                                            p->instrument()->channel(0)->channel(),
                                            ev.pitch,
                                            ev.velocity,
                                            0.0);
                          }
                    }
              if (noteEntryMode()) {
                    if (ev.velocity == 0) {
                          // delete note in realtime mode
                          //Chord* chord = toChord(_is.cr());
                          //std::vector<Note*> notes = chord->notes();
                          if (entryMethod == NoteEntryMethod::REALTIME_AUTO || entryMethod == NoteEntryMethod::REALTIME_MANUAL) {
                                if (_is.cr()->isChord()) {
                                      Note* n = toChord(_is.cr())->findNote(ev.pitch);
                                      if (n) {
                                            qDebug("Pitches match! Note %i, Pitch %i", n->pitch(), ev.pitch);
                                            if (!cmdActive) {
                                                  startCmd();
                                                  cmdActive = true;
                                                  }
                                            deleteItem(n->tieBack());
                                            deleteItem(n);
                                            }
                                      }
                                }
                          continue;
                          }
                    if (!cmdActive) {
                          startCmd();
                          cmdActive = true;
                          }
                    if (activeMidiPitches()->empty())
                          ev.chord = false;
                    else
                          ev.chord = true;
  
                    // holding shift while inputting midi will add the new pitch to the prior existing chord
                    if (qApp->keyboardModifiers() & Qt::ShiftModifier) {
                          Element* cr = _is.lastSegment()->element(_is.track());
                          if (cr && cr->isChord())
                                ev.chord = true;
                          }
  
                    // TODO: add shadow note instead of real note in realtime modes
                    // (note becomes real when realtime-advance triggered).
                    addMidiPitch(ev.pitch, ev.chord);
                    activeMidiPitches()->push_back(ev);
                    }
              }
        if (cmdActive) {
              endCmd();
              //after relayout
              Element* e = inputState().cr();
              if (e) {
                    for(MuseScoreView* v : viewer)
                          v->adjustCanvasPosition(e, false);
                    }
              return true;
              }
        return false;
        }
  
  //---------------------------------------------------------
  //   move
  //    move current selection
  //---------------------------------------------------------
  
  Element* Score::move(const QString& cmd)
        {
        ChordRest* cr;
        if (noteEntryMode()) {
              // if selection exists and is grace note, use it
              // otherwise use chord/rest at input position
              // also use it if we are moving to next chord
              // to catch up with the cursor and not move the selection by 2 positions
              cr = selection().cr();
              if (cr && (cr->isGrace() || cmd == "next-chord" || cmd == "prev-chord"))
                    ;
              else
                    cr = inputState().cr();
              }
        else if (selection().activeCR())
              cr = selection().activeCR();
        else
              cr = selection().lastChordRest();
  
        // no chord/rest found? look for another type of element
        if (cr == 0) {
              if (selection().elements().empty())
                    return 0;
              // retrieve last element of section list
              Element* el = selection().elements().last();
              Element* trg = 0;
  
              // get parent of element and process accordingly:
              // trg is the element to select on "next-chord" cmd
              // cr is the ChordRest to move from on other cmd's
              int track = el->track();            // keep note of element track
              el = el->parent();
              // element with no parent (eg, a newly-added line) - no way to find context
              if (!el)
                    return 0;
              switch (el->type()) {
                    case ElementType::NOTE:           // a note is a valid target
                          trg = el;
                          cr  = toNote(el)->chord();
                          break;
                    case ElementType::CHORD:          // a chord or a rest are valid targets
                    case ElementType::REST:
                          trg = el;
                          cr  = toChordRest(trg);
                          break;
                    case ElementType::SEGMENT: {      // from segment go to top chordrest in segment
                          Segment* seg  = toSegment(el);
                          // if segment is not chord/rest or grace, move to next chord/rest or grace segment
                          if (!seg->isChordRest()) {
                                seg = seg->next1(SegmentType::ChordRest);
                                if (seg == 0)     // if none found, return failure
                                      return 0;
                                }
                          // segment for sure contains chords/rests,
                          int size = int(seg->elist().size());
                          // if segment has a chord/rest in original element track, use it
                          if (track > -1 && track < size && seg->element(track)) {
                                trg  = seg->element(track);
                                cr = toChordRest(trg);
                                break;
                                }
                          // if not, get topmost chord/rest
                          for (int i = 0; i < size; i++)
                                if (seg->element(i)) {
                                      trg  = seg->element(i);
                                      cr = toChordRest(trg);
                                      break;
                                      }
                          break;
                          }
                    default:                      // on anything else, return failure
                          return 0;
                    }
  
              // if something found and command is forward, the element found is the destination
              if (trg && cmd == "next-chord") {
                    // if chord, go to topmost note
                    if (trg->type() == ElementType::CHORD)
                          trg = toChord(trg)->upNote();
                    setPlayNote(true);
                    select(trg, SelectType::SINGLE, 0);
                    return trg;
                    }
              // if no chordrest found, do nothing
              if (cr == 0)
                    return 0;
              // if some chordrest found, continue with default processing
              }
  
        Element* el = 0;
        Segment* ois = noteEntryMode() ? _is.segment() : nullptr;
        Measure* oim = ois ? ois->measure() : nullptr;
  
        if (cmd == "next-chord") {
              // note input cursor
              if (noteEntryMode())
                    _is.moveToNextInputPos();
  
              // selection "cursor"
              // find next chordrest, which might be a grace note
              // this may override note input cursor
              el = nextChordRest(cr);
              while (el && el->isRest() && toRest(el)->isGap())
                    el = nextChordRest(toChordRest(el));
              if (el && noteEntryMode()) {
                    // do not use if not in original or new measure (don't skip measures)
                    Measure* m = toChordRest(el)->measure();
                    Segment* nis = _is.segment();
                    Measure* nim = nis ? nis->measure() : nullptr;
                    if (m != oim && m != nim)
                          el = cr;
                    // do not use if new input segment is current cr
                    // this means input cursor just caught up to current selection
                    else if (cr && nis == cr->segment())
                          el = cr;
                    }
              else if (!el)
                    el = cr;
              }
        else if (cmd == "prev-chord") {
              // note input cursor
              if (noteEntryMode() && _is.segment()) {
                    Measure* m = _is.segment()->measure();
                    Segment* s = _is.segment()->prev1(SegmentType::ChordRest);
                    int track = _is.track();
                    for (; s; s = s->prev1(SegmentType::ChordRest)) {
                          if (s->element(track) || (s->measure() != m && s->rtick().isZero())) {
                                if (s->element(track)) {
                                      if (s->element(track)->isRest() && toRest(s->element(track))->isGap())
                                            continue;
                                      }
                                break;
                                }
                          }
                    _is.moveInputPos(s);
                    }
  
              // selection "cursor"
              // find previous chordrest, which might be a grace note
              // this may override note input cursor
              el = prevChordRest(cr);
              while (el && el->isRest() && toRest(el)->isGap())
                    el = prevChordRest(toChordRest(el));
              if (el && noteEntryMode()) {
                    // do not use if not in original or new measure (don't skip measures)
                    Measure* m = toChordRest(el)->measure();
                    Segment* nis = _is.segment();
                    Measure* nim = nis ? nis->measure() : nullptr;
                    if (m != oim && m != nim)
                          el = cr;
                    // do not use if new input segment is current cr
                    // this means input cursor just caught up to current selection
                    else if (cr && nis == cr->segment())
                          el = cr;
                    }
              else if (!el)
                    el = cr;
  
              }
        else if (cmd == "next-measure") {
              el = nextMeasure(cr);
              if (noteEntryMode())
                    _is.moveInputPos(el);
              }
        else if (cmd == "prev-measure") {
              el = prevMeasure(cr);
              if (noteEntryMode())
                    _is.moveInputPos(el);
              }
        else if (cmd == "next-track") {
              el = nextTrack(cr);
              if (noteEntryMode())
                    _is.moveInputPos(el);
              }
        else if (cmd == "prev-track") {
              el = prevTrack(cr);
              if (noteEntryMode())
                    _is.moveInputPos(el);
              }
  
        if (el) {
              if (el->type() == ElementType::CHORD)
                    el = toChord(el)->upNote();       // originally downNote
              setPlayNote(true);
              if (noteEntryMode()) {
                    // if cursor moved into a gap, selection cannot follow
                    // only select & play el if it was not already selected (does not normally happen)
                    if (_is.cr() || !el->selected())
                          select(el, SelectType::SINGLE, 0);
                    else
                          setPlayNote(false);
                    for (MuseScoreView* view : viewer)
                          view->moveCursor();
                    }
              else {
                    select(el, SelectType::SINGLE, 0);
                    }
              }
        return el;
        }
  
  //---------------------------------------------------------
  //   selectMove
  //---------------------------------------------------------
  
  Element* Score::selectMove(const QString& cmd)
        {
        ChordRest* cr;
        if (selection().activeCR())
              cr = selection().activeCR();
        else
              cr = selection().lastChordRest();
        if (cr == 0 && noteEntryMode())
              cr = inputState().cr();
        if (cr == 0)
              return 0;
  
        ChordRest* el = 0;
        if (cmd == "select-next-chord")
              el = nextChordRest(cr, true);
        else if (cmd == "select-prev-chord")
              el = prevChordRest(cr, true);
        else if (cmd == "select-next-measure")
              el = nextMeasure(cr, true, true);
        else if (cmd == "select-prev-measure")
              el = prevMeasure(cr, true);
        else if (cmd == "select-begin-line") {
              Measure* measure = cr->segment()->measure()->system()->firstMeasure();
              if (!measure)
                    return 0;
              el = measure->first()->nextChordRest(cr->track());
              }
        else if (cmd == "select-end-line") {
              Measure* measure = cr->segment()->measure()->system()->lastMeasure();
              if (!measure)
                    return 0;
              el = measure->last()->nextChordRest(cr->track(), true);
              }
        else if (cmd == "select-begin-score") {
              Measure* measure = firstMeasureMM();
              if (!measure)
                    return 0;
              el = measure->first()->nextChordRest(cr->track());
              }
        else if (cmd == "select-end-score") {
              Measure* measure = lastMeasureMM();
              if (!measure)
                    return 0;
              el = measure->last()->nextChordRest(cr->track(), true);
              }
        else if (cmd == "select-staff-above")
              el = upStaff(cr);
        else if (cmd == "select-staff-below")
              el = downStaff(cr);
        if (el)
              select(el, SelectType::RANGE, el->staffIdx());
        return el;
        }
  
  //---------------------------------------------------------
  //   cmdMirrorNoteHead
  //---------------------------------------------------------
  
  void Score::cmdMirrorNoteHead()
        {
        const QList<Element*>& el = selection().elements();
        for (Element* e : el) {
              if (e->isNote()) {
                    Note* note = toNote(e);
                    if (note->staff() && note->staff()->isTabStaff(note->chord()->tick()))
                          e->undoChangeProperty(Pid::GHOST, !note->ghost());
                    else {
                          MScore::DirectionH d = note->userMirror();
                          if (d == MScore::DirectionH::AUTO)
                                d = note->chord()->up() ? MScore::DirectionH::RIGHT : MScore::DirectionH::LEFT;
                          else
                                d = d == MScore::DirectionH::LEFT ? MScore::DirectionH::RIGHT : MScore::DirectionH::LEFT;
                          undoChangeUserMirror(note, d);
                          }
                    }
              else if (e->isHairpinSegment()) {
                    Hairpin* h = toHairpinSegment(e)->hairpin();
                    HairpinType st = h->hairpinType();
                    switch (st)  {
                          case HairpinType::CRESC_HAIRPIN:
                                st = HairpinType::DECRESC_HAIRPIN;
                                break;
                          case HairpinType::DECRESC_HAIRPIN:
                                st = HairpinType::CRESC_HAIRPIN;
                                break;
                          case HairpinType::CRESC_LINE:
                                st = HairpinType::DECRESC_LINE;
                                break;
                          case HairpinType::DECRESC_LINE:
                                st = HairpinType::CRESC_LINE;
                                break;
                          case HairpinType::INVALID:
                                break;
                          }
                    h->undoChangeProperty(Pid::HAIRPIN_TYPE, int(st));
                    }
              }
        }
  
  //---------------------------------------------------------
  //   cmdIncDecDuration
  //     When stepDotted is false and nSteps is 1 or -1, will halve or double the duration
  //     When stepDotted is true, will step by nearest dotted or undotted note
  //---------------------------------------------------------
  
  void Score::cmdIncDecDuration(int nSteps, bool stepDotted)
        {
        Element* el = selection().element();
        if (el == 0)
              return;
        if (el->isNote())
              el = el->parent();
        if (!el->isChordRest())
              return;
  
        ChordRest* cr = toChordRest(el);
  
        // if measure rest is selected as input, then the correct initialDuration will be the
        // duration of the measure's time signature, else is just the input state's duration
        TDuration initialDuration = (cr->durationType() == TDuration::DurationType::V_MEASURE) ? TDuration(cr->measure()->timesig()) : _is.duration();
        TDuration d = initialDuration.shiftRetainDots(nSteps, stepDotted);
        if (!d.isValid())
              return;
        if (cr->isChord() && (toChord(cr)->noteType() != NoteType::NORMAL)) {
              //
              // handle appoggiatura and acciaccatura
              //
              undoChangeChordRestLen(cr, d);
              }
        else
              changeCRlen(cr, d);
        _is.setDuration(d);
        nextInputPos(cr, false);
        }
  
  //---------------------------------------------------------
  //   cmdAddBracket
  //---------------------------------------------------------
  
  void Score::cmdAddBracket()
        {
        for (Element* el : selection().elements()) {
              if (el->type() == ElementType::ACCIDENTAL) {
                    Accidental* acc = toAccidental(el);
                    acc->undoChangeProperty(Pid::ACCIDENTAL_BRACKET, int(AccidentalBracket::BRACKET));
                    }
              }
        }
  
  //---------------------------------------------------------
  //   cmdAddParentheses
  //---------------------------------------------------------
  
  void Score::cmdAddParentheses()
        {
        for (Element* el : selection().elements()) {
              if (el->type() == ElementType::NOTE) {
                    Note* n = toNote(el);
                    n->addParentheses();
                    }
              else if (el->type() == ElementType::ACCIDENTAL) {
                    Accidental* acc = toAccidental(el);
                    acc->undoChangeProperty(Pid::ACCIDENTAL_BRACKET, int(AccidentalBracket::PARENTHESIS));
                    }
              else if (el->type() == ElementType::HARMONY) {
                    Harmony* h = toHarmony(el);
                    h->setLeftParen(true);
                    h->setRightParen(true);
                    h->render();
                    }
              else if (el->type() == ElementType::TIMESIG) {
                    TimeSig* ts = toTimeSig(el);
                    ts->setLargeParentheses(true);
                    }
              }
        }
  
  
  //---------------------------------------------------------
  //   cmdMoveRest
  //---------------------------------------------------------
  
  void Score::cmdMoveRest(Rest* rest, Direction dir)
        {
        QPointF pos(rest->offset());
        if (dir == Direction::UP)
              pos.ry() -= spatium();
        else if (dir == Direction::DOWN)
              pos.ry() += spatium();
        rest->undoChangeProperty(Pid::OFFSET, pos);
        }
  
  //---------------------------------------------------------
  //   cmdMoveLyrics
  //---------------------------------------------------------
  
  void Score::cmdMoveLyrics(Lyrics* lyrics, Direction dir)
        {
        int verse = lyrics->no() + (dir == Direction::UP ? -1 : 1);
        if (verse < 0)
              return;
        lyrics->undoChangeProperty(Pid::VERSE, verse);
        }
  
  //---------------------------------------------------------
  //   cmdInsertClef
  //---------------------------------------------------------
  
  void Score::cmdInsertClef(ClefType type)
        {
        if (!noteEntryMode())
              return;
        undoChangeClef(staff(inputTrack()/VOICES), inputState().cr(), type);
        }
  
  //---------------------------------------------------------
  //   cmdInsertClef
  //    insert clef before cr
  //---------------------------------------------------------
  
  void Score::cmdInsertClef(Clef* clef, ChordRest* cr)
        {
        undoChangeClef(cr->staff(), cr, clef->clefType());
        delete clef;
        }
  
  //---------------------------------------------------------
  //   cmdAddGrace
  ///   adds grace note of specified type to selected notes
  //---------------------------------------------------------
  
  void Score::cmdAddGrace (NoteType graceType, int duration)
        {
        const QList<Element*> copyOfElements = selection().elements();
        for (Element* e : copyOfElements) {
              if (e->type() == ElementType::NOTE) {
                    Note* n = toNote(e);
                    setGraceNote(n->chord(), n->pitch(), graceType, duration);
                    }
              }
        }
  
  //---------------------------------------------------------
  //   cmdExplode
  ///   explodes contents of top selected staff into subsequent staves
  //---------------------------------------------------------
  
  void Score::cmdExplode()
        {
        if (!selection().isRange())
              return;
  
        int srcStaff  = selection().staffStart();
        int lastStaff = selection().staffEnd();
        int srcTrack  = srcStaff * VOICES;
  
        // reset selection to top staff only
        // force complete measures
        Segment* startSegment = selection().startSegment();
        Segment* endSegment = selection().endSegment();
        Measure* startMeasure = startSegment->measure();
        Measure* endMeasure = endSegment ? endSegment->measure() : lastMeasure();
  
        Fraction lTick = endMeasure->endTick();
        bool voice = false;
  
        for (Measure* m = startMeasure; m && m->tick() != lTick; m = m->nextMeasure()) {
              if (m->hasVoices(srcStaff)) {
                    voice = true;
                    break;
                    }
              }
        if (! voice) {
              // force complete measures
              deselectAll();
              select(startMeasure, SelectType::RANGE, srcStaff);
              select(endMeasure, SelectType::RANGE, srcStaff);
              startSegment = selection().startSegment();
              endSegment = selection().endSegment();
              if (srcStaff == lastStaff - 1) {
                    // only one staff was selected up front - determine number of staves
                    // loop through all chords looking for maximum number of notes
                    int n = 0;
                    for (Segment* s = startSegment; s && s != endSegment; s = s->next1()) {
                          Element* e = s->element(srcTrack);
                          if (e && e->type() == ElementType::CHORD) {
                                Chord* c = toChord(e);
                                n = qMax(n, int(c->notes().size()));
                                }
                          }
                    lastStaff = qMin(nstaves(), srcStaff + n);
                    }
  
              const QByteArray mimeData(selection().mimeData());
              // copy to all destination staves
              Segment* firstCRSegment = startMeasure->tick2segment(startMeasure->tick());
              for (int i = 1; srcStaff + i < lastStaff; ++i) {
                    int track = (srcStaff + i) * VOICES;
                    ChordRest* cr = toChordRest(firstCRSegment->element(track));
                    if (cr) {
                          XmlReader e(mimeData);
                          e.setPasteMode(true);
                          pasteStaff(e, cr->segment(), cr->staffIdx());
                          }
                    }
  
              // loop through each staff removing all but one note from each chord
              for (int i = 0; srcStaff + i < lastStaff; ++i) {
                    int track = (srcStaff + i) * VOICES;
                    for (Segment* s = startSegment; s && s != endSegment; s = s->next1()) {
                          Element* e = s->element(track);
                          if (e && e->type() == ElementType::CHORD) {
                                Chord* c = toChord(e);
                                std::vector<Note*> notes = c->notes();
                                int nnotes = int(notes.size());
                                // keep note "i" from top, which is backwards from nnotes - 1
                                // reuse notes if there are more instruments than notes
                                int stavesPerNote = qMax((lastStaff - srcStaff) / nnotes, 1);
                                int keepIndex = qMax(nnotes - 1 - (i / stavesPerNote), 0);
                                Note* keepNote = c->notes()[keepIndex];
                                foreach (Note* n, notes) {
                                      if (n != keepNote)
                                            undoRemoveElement(n);
                                      }
                                }
                          }
                    }
              }
        else {
              int sTracks[VOICES];
              int dTracks[VOICES];
              if (srcStaff == lastStaff - 1)
                    lastStaff = qMin(nstaves(), srcStaff + VOICES);
  
              for (int i = 0; i < VOICES; i++) {
                    sTracks[i] = -1;
                    dTracks[i] = -1;
                    }
              int full = 0;
  
              for (Segment* seg = startSegment; seg && seg->tick() < lTick; seg = seg->next1()) {
                    for (int i = srcTrack; i < srcTrack + VOICES && full != VOICES; i++) {
                          bool t = true;
                          for (int j = 0; j < VOICES; j++) {
                                if (i == sTracks[j]) {
                                      t = false;
                                      break;
                                      }
                                }
  
                          if (!seg->measure()->hasVoice(i) || seg->measure()->isOnlyRests(i) || !t)
                                continue;
                          sTracks[full] = i;
  
                          for(int j = srcTrack + full * VOICES; j < lastStaff * VOICES; j++) {
                                if (i == j) {
                                      dTracks[full] = j;
                                      break;
                                      }
                                for(Measure* m = seg->measure(); m && m->tick() < lTick; m = m->nextMeasure()) {
                                      if (!m->hasVoice(j) || (m->hasVoice(j) && m->isOnlyRests(j)))
                                            dTracks[full] = j;
                                      else {
                                            dTracks[full] = -1;
                                            break;
                                            }
                                      }
                                if (dTracks[full] != -1)
                                      break;
                                }
                          full++;
                          }
                    }
  
              for (int i = srcTrack, j = 0; i < lastStaff * VOICES && j < VOICES ; i += VOICES, j++) {
                    int strack = sTracks[j % VOICES];
                    int dtrack = dTracks[j % VOICES];
                    if (strack != -1 && strack != dtrack && dtrack != -1)
                          undo(new CloneVoice(startSegment, lTick, startSegment, strack, dtrack, -1, false));
                    }
              }
  
        // select exploded region
        deselectAll();
        select(startMeasure, SelectType::RANGE, srcStaff);
        select(endMeasure, SelectType::RANGE, lastStaff - 1);
        }
  
  //---------------------------------------------------------
  //   cmdImplode
  ///   implodes contents of selected staves into top staff
  ///   for single staff, merge voices
  //---------------------------------------------------------
  
  void Score::cmdImplode()
        {
        if (!selection().isRange())
              return;
  
        int dstStaff   = selection().staffStart();
        int endStaff   = selection().staffEnd();
        int dstTrack   = dstStaff * VOICES;
        int startTrack = dstStaff * VOICES;
        int endTrack   = endStaff * VOICES;
        Segment* startSegment = selection().startSegment();
        Segment* endSegment = selection().endSegment();
        Measure* startMeasure = startSegment->measure();
        Measure* endMeasure = endSegment ? endSegment->measure() : lastMeasure();
        Fraction startTick       = startSegment->tick();
        Fraction endTick         = endSegment ? endSegment->tick() : lastMeasure()->endTick();
        Q_ASSERT(startMeasure && endMeasure);
  
        // if single staff selected, combine voices
        // otherwise combine staves
        if (dstStaff == endStaff - 1) {
  
              // loop through segments adding notes to chord on top staff
              for (Segment* s = startSegment; s && s != endSegment; s = s->next1()) {
                    if (!s->isChordRestType())
                          continue;
                    Element* dst = s->element(dstTrack);
                    if (dst && dst->isChord()) {
                          Chord* dstChord = toChord(dst);
                          // see if we are tying in to this chord
                          Chord* tied = 0;
                          for (Note* n : dstChord->notes()) {
                                if (n->tieBack()) {
                                      tied = n->tieBack()->startNote()->chord();
                                      break;
                                      }
                                }
                          // loop through each subsequent staff (or track within staff)
                          // looking for notes to add
                          for (int srcTrack = startTrack + 1; srcTrack < endTrack; srcTrack++) {
                                Element* src = s->element(srcTrack);
                                if (src && src->isChord()) {
                                      Chord* srcChord = toChord(src);
                                      // when combining voices, skip if not same duration
                                      if (srcChord->ticks() != dstChord->ticks())
                                            continue;
                                      // add notes
                                      for (Note* n : srcChord->notes()) {
                                            NoteVal nv(n->pitch());
                                            nv.tpc1 = n->tpc1();
                                            // skip duplicates
                                            if (dstChord->findNote(nv.pitch))
                                                  continue;
                                            Note* nn = addNote(dstChord, nv);
                                            // add tie to this note if original chord was tied
                                            if (tied) {
                                                  // find note to tie to
                                                  for (Note *tn : tied->notes()) {
                                                        if (nn->pitch() == tn->pitch() && nn->tpc() == tn->tpc() && !tn->tieFor()) {
                                                              // found note to tie
                                                              Tie* tie = new Tie(this);
                                                              tie->setStartNote(tn);
                                                              tie->setEndNote(nn);
                                                              tie->setTrack(tn->track());
                                                              undoAddElement(tie);
                                                              }
                                                        }
                                                  }
                                            }
                                      }
                                // delete chordrest from source track if possible
                                if (src && src->voice())
                                      undoRemoveElement(src);
                                }
                          }
                    // TODO - use first voice that actually has a note and implode remaining voices on it?
                    // see https://musescore.org/en/node/174111
                    else if (dst) {
                          // destination track has something, but it isn't a chord
                          // remove rests from other voices if in "voice mode"
                          for (int i = 1; i < VOICES; ++i) {
                                Element* e = s->element(dstTrack + i);
                                if (e && e->isRest())
                                      undoRemoveElement(e);
                                }
                          }
                    }
              // delete orphaned spanners (TODO: figure out solution to reconnect orphaned spanners to their cloned notes)
              checkSpanner(startTick, endTick);
              }
        else {
              int tracks[VOICES];
              for (int i = 0; i < VOICES; i++)
                    tracks[i] = -1;
              int full = 0;
  
              // identify tracks to combine, storing the source track numbers in tracks[]
              // first four non-empty tracks to win
              for (int track = startTrack; track < endTrack && full < VOICES; ++track) {
                    Measure* m = startMeasure;
                    do {
                          if (m->hasVoice(track) && !m->isOnlyRests(track)) {
                                tracks[full++] = track;
                                break;
                                }
                          } while ((m != endMeasure) && (m = m->nextMeasure()));
                    }
  
              // clone source tracks into destination
              for (int i = dstTrack; i < dstTrack + VOICES; i++) {
                    int strack = tracks[i % VOICES];
                    if (strack != -1 && strack != i) {
                          undo( new CloneVoice(startSegment, endTick, startSegment, strack, i, i, false));
                          }
                    }
              }
  
        // select destination staff only
        deselectAll();
        select(startMeasure, SelectType::RANGE, dstStaff);
        select(endMeasure, SelectType::RANGE, dstStaff);
        }
  
  //---------------------------------------------------------
  //   cmdSlashFill
  ///   fills selected region with slashes
  //---------------------------------------------------------
  
  void Score::cmdSlashFill()
        {
        int startStaff = selection().staffStart();
        int endStaff = selection().staffEnd();
        Segment* startSegment = selection().startSegment();
        if (!startSegment) // empty score?
              return;
  
        Segment* endSegment = selection().endSegment();
  
        // operate on measures underlying mmrests
        if (startSegment && startSegment->measure() && startSegment->measure()->isMMRest())
              startSegment = startSegment->measure()->mmRestFirst()->first();
        if (endSegment && endSegment->measure() && endSegment->measure()->isMMRest())
              endSegment = endSegment->measure()->mmRestLast()->last();
  
        Fraction endTick = endSegment ? endSegment->tick() : lastSegment()->tick() + Fraction::fromTicks(1);
        Chord* firstSlash = 0;
        Chord* lastSlash = 0;
  
        // loop through staves in selection
        for (int staffIdx = startStaff; staffIdx < endStaff; ++staffIdx) {
              int track = staffIdx * VOICES;
              int voice = -1;
              // loop through segments adding slashes on each beat
              for (Segment* s = startSegment; s && s->tick() < endTick; s = s->next1()) {
                    if (s->segmentType() != SegmentType::ChordRest)
                          continue;
                    // determine beat type based on time signature
                    int d = s->measure()->timesig().denominator();
                    int n = (d > 4 && s->measure()->timesig().numerator() % 3 == 0) ? 3 : 1;
                    Fraction f(n, d);
                    // skip over any leading segments before next (first) beat
                    if (s->rtick().ticks() % f.ticks())
                          continue;
                    // determine voice to use - first available voice for this measure / staff
                    if (voice == -1 || s->rtick().isZero()) {
                          bool needGap[VOICES];
                          for (voice = 0; voice < VOICES; ++voice) {
                                needGap[voice] = false;
                                ChordRest* cr = toChordRest(s->element(track + voice));
                                // no chordrest == treat as ordinary rest for purpose of determining availbility of voice
                                // but also, we will need to make a gap for this voice if we do end up choosing it
                                if (!cr)
                                      needGap[voice] = true;
                                // chord == keep looking for an available voice
                                else if (cr->type() == ElementType::CHORD)
                                      continue;
                                // full measure rest == OK to use voice
                                else if (cr->durationType() == TDuration::DurationType::V_MEASURE)
                                      break;
                                // no chordrest or ordinary rest == OK to use voice
                                // if there are nothing but rests for duration of measure / selection
                                bool ok = true;
                                for (Segment* ns = s->next(SegmentType::ChordRest); ns && ns != endSegment; ns = ns->next(SegmentType::ChordRest)) {
                                      ChordRest* ncr = toChordRest(ns->element(track + voice));
                                      if (ncr && ncr->type() == ElementType::CHORD) {
                                            ok = false;
                                            break;
                                            }
                                      }
                                if (ok)
                                      break;
                                }
                          // no available voices, just use voice 0
                          if (voice == VOICES)
                                voice = 0;
                          // no cr was found in segment for this voice, so make gap
                          if (needGap[voice])
                                makeGapVoice(s, track + voice, f, s->tick());
                          }
                    // construct note
                    int line = 0;
                    bool error = false;
                    NoteVal nv;
                    if (staff(staffIdx)->staffType(s->tick())->group() == StaffGroup::TAB)
                          line = staff(staffIdx)->lines(s->tick()) / 2;
                    else
                          line = staff(staffIdx)->middleLine(s->tick());     // staff(staffIdx)->lines() - 1;
                    if (staff(staffIdx)->staffType(s->tick())->group() == StaffGroup::PERCUSSION) {
                          nv.pitch = 0;
                          nv.headGroup = NoteHead::Group::HEAD_SLASH;
                          }
                    else {
                          Position p;
                          p.segment = s;
                          p.staffIdx = staffIdx;
                          p.line = line;
                          p.fret = FRET_NONE;
                          _is.setRest(false);     // needed for tab
                          nv = noteValForPosition(p, AccidentalType::NONE, error);
                          }
                    if (error)
                          continue;
                    // insert & turn into slash
                    s = setNoteRest(s, track + voice, nv, f);
                    Chord* c = toChord(s->element(track + voice));
                    if (c->links()) {
                          for (ScoreElement* e : *c->links()) {
                                Chord* lc = toChord(e);
                                lc->setSlash(true, true);
                                }
                          }
                    else
                          c->setSlash(true, true);
                    lastSlash = c;
                    if (!firstSlash)
                          firstSlash = c;
                    }
              }
  
        // re-select the slashes
        deselectAll();
        if (firstSlash && lastSlash) {
              select(firstSlash, SelectType::RANGE);
              select(lastSlash, SelectType::RANGE);
              }
        }
  
  //---------------------------------------------------------
  //   cmdSlashRhythm
  ///   converts rhythms in selected region to slashes
  //---------------------------------------------------------
  
  void Score::cmdSlashRhythm()
        {
        QList<Chord*> chords;
        // loop through all notes in selection
        foreach (Element* e, selection().elements()) {
              if (e->voice() >= 2 && e->isRest()) {
                    Rest* r = toRest(e);
                    if (r->links()) {
                          for (ScoreElement* se : *r->links()) {
                                Rest* lr = toRest(se);
                                lr->setAccent(!lr->accent());
                                }
                          }
                    else
                          r->setAccent(!r->accent());
                    continue;
                    }
              else if (e->isNote()) {
                    Note* n = toNote(e);
                    if (n->noteType() != NoteType::NORMAL)
                          continue;
                    Chord* c = n->chord();
                    // check for duplicates (chords with multiple notes)
                    if (chords.contains(c))
                          continue;
                    chords.append(c);
                    // toggle slash setting
                    if (c->links()) {
                          for (ScoreElement* se : *c->links()) {
                                Chord* lc = toChord(se);
                                lc->setSlash(!lc->slash(), false);
                                }
                          }
                    else
                          c->setSlash(!c->slash(), false);
                    }
              }
        }
  
  //---------------------------------------------------------
  //   cmdRealizeChordSymbols
  ///   Realize selected chord symbols into notes on the staff.
  ///
  ///   If a voicing and duration type are specified, the
  ///   harmony voicing settings will be overridden by the
  ///   passed parameters. Otherwise, the settings set on the
  ///   harmony object will be used.
  //---------------------------------------------------------
  
  void Score::cmdRealizeChordSymbols(bool literal, Voicing voicing, HDuration durationType)
        {
        const QList<Element*> elist = selection().elements();
        for (Element* e : elist) {
              if (!e->isHarmony())
                    continue;
              Harmony* h = toHarmony(e);
              if (!h->isRealizable())
                    continue;
              RealizedHarmony r = h->getRealizedHarmony();
              Segment* seg = toSegment(h->parent());
              Fraction duration = r.getActualDuration(durationType);
              Fraction tick = seg->tick();
              bool concertPitch = styleB(Sid::concertPitch);
  
              Chord* chord = new Chord(this); //chord template
              chord->setTrack(h->track()); //set track so notes have a track to sit on
  
              //create chord from notes
              RealizedHarmony::PitchMap notes;
              if (voicing == Voicing::INVALID || durationType == HDuration::INVALID)
                    notes = r.notes(); //no override, just use notes from realize harmony
              else {
                    //generate notes list based on overridden settings
                    int offset = 0;
                    Interval interval = h->staff()->part()->instrument(h->tick())->transpose();
                    if (!concertPitch)
                          offset = interval.chromatic;
                    notes = r.generateNotes(h->rootTpc(), h->baseTpc(),
                          literal, voicing, offset);
                    }
              RealizedHarmony::PitchMapIterator i(notes); //add notes to chord
              while (i.hasNext()) {
                    i.next();
                    Note* note = new Note(this);
                    NoteVal nval;
                    nval.pitch = i.key();
                    if (concertPitch)
                          nval.tpc1 = i.value();
                    else
                          nval.tpc2 = i.value();
                    chord->add(note); //add note first to set track and such
                    note->setNval(nval, tick);
                    }
  
              setChord(seg, h->track(), chord, duration); //add chord using template
              delete chord;
              }
        }
  
  //---------------------------------------------------------
  //   setChord
  //    return segment of last created chord
  //---------------------------------------------------------
  Segment* Score::setChord(Segment* segment, int track, Chord* chordTemplate, Fraction dur, Direction stemDirection)
        {
        Q_ASSERT(segment->segmentType() == SegmentType::ChordRest);
  
        Fraction tick = segment->tick();
        Chord* nr     = 0; //current added chord used so we can select the last added chord and so we can apply ties
        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
        ChordRest* cr = toChordRest(segment->element(track)); //chord rest under the segment for the specified track
  
        bool addTie = false;
  
        Measure* measure = 0;
        //keep creating chords and tieing them until we created the full duration asked for (dur)
        for (;;) {
              if (track % VOICES)
                    expandVoice(segment, track);
  
              Tuplet* t = cr ? cr->tuplet() : 0;
              Fraction tDur = segment->ticks();
              Segment* seg = segment->next();
  
              //we need to get a correct subduration so that makeGap can function properly
              //since makeGap() takes "normal" duration rather than actual length
              while (seg) {
                    if (seg->segmentType() == SegmentType::ChordRest) {
                          //design choice made to keep multiple notes across a tuplet as tied single notes rather than combining them
                          //since it's arguably more readable, but the other code is still here (commented)
                          ChordRest* testCr = toChordRest(seg->element(track));
  
                          //code here allows us to combine tuplet realization together which I have opted not to do for readability (of the music)
                          //if (!!t ^ (testCr && testCr->tuplet())) //stop if we started with a tuplet and reach something that's not a tuplet,
                          //      break;                          //or start with not a tuplet and reach a tuplet
  
                          if (testCr && testCr->tuplet()) //stop on tuplet
                                break;
                          tDur += seg->ticks();
                          }
                    if (tDur >= dur) { //do not go further than the duration asked for
                          tDur = dur;
                          break;
                          }
                    seg = seg->next(); //iterate only across measure (hence usage of next() rather than next1())
                    }
              if (t)
                    tDur *= t->ratio(); //scale by tuplet ratio to get "normal" length rather than actual length when dealing with tuplets
  
              // the returned gap ends at the measure boundary or at tuplet end
              Fraction dd = makeGap(segment, track, tDur, t);
  
              if (dd.isZero()) {
                    qDebug("cannot get gap at %d type: %d/%d", tick.ticks(), dur.numerator(),
                       dur.denominator());
                    break;
                    }
  
              measure = segment->measure();
              std::vector<TDuration> dl = toDurationList(dd, true);
              size_t n = dl.size();
              //add chord, tieing when necessary within measure
              for (size_t i = 0; i < n; ++i) {
                    const TDuration& d = dl[i];
  
                    //create new chord from template and add it
                    Chord* chord = new Chord(*chordTemplate);
                    nr = chord;
  
                    chord->setTrack(track);
                    chord->setDurationType(d);
                    chord->setTicks(d.fraction());
                    chord->setStemDirection(stemDirection);
                    chord->setTuplet(t);
                    undoAddCR(chord, measure, tick);
                    //if there is something to tie, complete tie backwards
                    //and add the tie to score
                    const std::vector<Note*> notes = chord->notes();
                    if (addTie) {
                          for (size_t i = 0; i < notes.size(); ++i) {
                                tie[i]->setEndNote(notes[i]);
                                notes[i]->setTieBack(tie[i]);
                                undoAddElement(tie[i]);
                                }
                          addTie = false;
                          }
                    //if we're not the last element in the duration list,
                    //set tie forward
                    if (i+1 < n) {
                          for (size_t i = 0; i < notes.size(); ++i) {
                                tie[i] = new Tie(this);
                                tie[i]->setStartNote(notes[i]);
                                tie[i]->setTrack(track);
                                notes[i]->setTieFor(tie[i]);
                                addTie = true;
                                }
                          }
                    setPlayChord(true);
                    segment = chord->segment();
                    tick += chord->actualTicks();
                    }
  
              //subtract the duration already realized and move on
              if (t)
                    dur -= dd / t->ratio();
              else
                    dur -= dd;
              //we are done when there is no duration left to realize
              if (dur.isZero())
                    break;
  
              //go to next segment unless we are at the score (which means we will just be done there)
              Segment* nseg = tick2segment(tick, false, SegmentType::ChordRest);
              if (nseg == 0) {
                    qDebug("reached end of score");
                    break;
                    }
              segment = nseg;
  
              cr = toChordRest(segment->element(track));
  
              if (cr == 0) {
                    if (track % VOICES)
                          cr = addRest(segment, track, TDuration(TDuration::DurationType::V_MEASURE), 0);
                    else {
                          qDebug("no rest in voice 0");
                          break;
                          }
                    }
              //
              //  Note does not fit on current measure, create Tie to
              //  next part of note
              std::vector<Note*> notes = nr->notes();
              for (size_t i = 0; i < notes.size(); ++i) {
                    tie[i] = new Tie(this);
                    tie[i]->setStartNote(notes[i]);
                    tie[i]->setTrack(notes[i]->track());
                    notes[i]->setTieFor(tie[i]);
                    }
              }
        if (!tie.empty())
              connectTies();
        if (nr)
              select(nr, SelectType::SINGLE, 0);
        return segment;
        }
  
  //---------------------------------------------------------
  //   cmdResequenceRehearsalMarks
  ///   resequences rehearsal marks within a range selection
  ///   or, if nothing is selected, the entire score
  //---------------------------------------------------------
  
  void Score::cmdResequenceRehearsalMarks()
        {
        bool noSelection = !selection().isRange();
  
        if (noSelection)
              cmdSelectAll();
        else if (!selection().isRange())
              return;
  
        RehearsalMark* last = 0;
        for (Segment* s = selection().startSegment(); s && s != selection().endSegment(); s = s->next1()) {
              for (Element* e : s->annotations()) {
                    if (e->type() == ElementType::REHEARSAL_MARK) {
                          RehearsalMark* rm = toRehearsalMark(e);
                          if (last) {
                                QString rmText = nextRehearsalMarkText(last, rm);
                                for (ScoreElement* le : rm->linkList())
                                      le->undoChangeProperty(Pid::TEXT, rmText);
                                }
                          last = rm;
                          }
                    }
              }
  
        if (noSelection)
              deselectAll();
        }
  
  //---------------------------------------------------------
  //   addRemoveBreaks
  //    interval lock
  //    0        false    remove all linebreaks
  //    > 0      false    add linebreak every interval measure
  //    d.c.     true     add linebreak at every system end
  //---------------------------------------------------------
  
  void Score::addRemoveBreaks(int interval, bool lock)
        {
        Segment* startSegment = selection().startSegment();
        if (!startSegment) // empty score?
              return;
        Segment* endSegment   = selection().endSegment();
        Measure* startMeasure = startSegment->measure();
        Measure* endMeasure   = endSegment ? endSegment->measure() : lastMeasureMM();
        Measure* lastMeasure  = lastMeasureMM();
  
        // loop through measures in selection
        // count mmrests as a single measure
        int count = 0;
        for (Measure* mm = startMeasure; mm; mm = mm->nextMeasureMM()) {
  
              // even though we are counting mmrests as a single measure,
              // we need to find last real measure within mmrest for the actual break
              Measure* m = mm->isMMRest() ? mm->mmRestLast() : mm;
  
              if (lock) {
                    // skip last measure of score
                    if (mm == lastMeasure)
                          break;
                    // skip if it already has a break
                    if (m->lineBreak() || m->pageBreak())
                          continue;
                    // add break if last measure of system
                    if (mm->system() && mm->system()->lastMeasure() == mm)
                          m->undoSetLineBreak(true);
                    }
              else {
                    if (interval == 0) {
                          // remove line break if present
                          if (m->lineBreak())
                                m->undoSetLineBreak(false);
                          }
                    else {
                          if (++count == interval) {
                                // skip last measure of score
                                if (mm == lastMeasure)
                                      break;
                                // found place for break; add if not already one present
                                if (!(m->lineBreak() || m->pageBreak()))
                                      m->undoSetLineBreak(true);
                                // reset count
                                count = 0;
                                }
                          else if (m->lineBreak()) {
                                // remove line break if present in wrong place
                                m->undoSetLineBreak(false);
                                }
                          }
                    }
  
              if (mm == endMeasure)
                    break;
              }
  
        }
  
  //---------------------------------------------------------
  //   cmdRemoveEmptyTrailingMeasures
  //---------------------------------------------------------
  
  void Score::cmdRemoveEmptyTrailingMeasures()
        {
        MasterScore* score = masterScore();
        Measure* firstMeasure;
        Measure* lastMeasure = score->lastMeasure();
        if (!lastMeasure || !lastMeasure->isFullMeasureRest())
              return;
        firstMeasure = lastMeasure;
        for (firstMeasure = lastMeasure;;) {
              Measure* m = firstMeasure->prevMeasure();
              if (!m || !m->isFullMeasureRest())
                    break;
              firstMeasure = m;
              }
        deleteMeasures(firstMeasure, lastMeasure);
        }
  
  //---------------------------------------------------------
  //   cmdPitchUp
  //---------------------------------------------------------
  
  void Score::cmdPitchUp()
        {
        Element* el = selection().element();
        if (el && el->isLyrics())
              cmdMoveLyrics(toLyrics(el), Direction::UP);
        else if (el && (el->isArticulation() || el->isTextBase()))
              el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, -MScore::nudgeStep * el->spatium()), PropertyFlags::UNSTYLED);
        else if (el && el->isRest())
              cmdMoveRest(toRest(el), Direction::UP);
        else
              upDown(true, UpDownMode::CHROMATIC);
        }
  
  //---------------------------------------------------------
  //   cmdPitchDown
  //---------------------------------------------------------
  
  void Score::cmdPitchDown()
        {
        Element* el = selection().element();
        if (el && el->isLyrics())
              cmdMoveLyrics(toLyrics(el), Direction::DOWN);
        else if (el && (el->isArticulation() || el->isTextBase()))
              el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, MScore::nudgeStep * el->spatium()), PropertyFlags::UNSTYLED);
        else if (el && el->isRest())
              cmdMoveRest(toRest(el), Direction::DOWN);
        else
              upDown(false, UpDownMode::CHROMATIC);
        }
  
  //---------------------------------------------------------
  //   cmdTimeDelete
  //---------------------------------------------------------
  
  void Score::cmdTimeDelete()
        {
        Element* e = selection().element();
        if (e && e->isBarLine() && toBarLine(e)->segment()->isEndBarLineType()) {
              Measure* m = toBarLine(e)->segment()->measure();
              cmdJoinMeasure(m, m->nextMeasure());
              }
        else {
              if (_is.insertMode())
                    globalTimeDelete();
              else
                    localTimeDelete();
              }
        }
  
  //---------------------------------------------------------
  //   cmdPitchUpOctave
  //---------------------------------------------------------
  
  void Score::cmdPitchUpOctave()
        {
        Element* el = selection().element();
        if (el && (el->isArticulation() || el->isTextBase()))
              el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, -MScore::nudgeStep10 * el->spatium()), PropertyFlags::UNSTYLED);
        else
              upDown(true, UpDownMode::OCTAVE);
        }
  
  //---------------------------------------------------------
  //   cmdPitchDownOctave
  //---------------------------------------------------------
  
  void Score::cmdPitchDownOctave()
        {
        Element* el = selection().element();
        if (el && (el->isArticulation() || el->isTextBase()))
              el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, MScore::nudgeStep10 * el->spatium()), PropertyFlags::UNSTYLED);
        else
              upDown(false, UpDownMode::OCTAVE);
        }
  
  //---------------------------------------------------------
  //   cmdPadNoteInclreaseTAB
  //---------------------------------------------------------
  
  void Score::cmdPadNoteIncreaseTAB(const EditData& ed)
        {
        switch (_is.duration().type() ) {
  // cycle back from longest to shortest?
  //          case TDuration::V_LONG:
  //                padToggle(Pad::NOTE128, ed);
  //                break;
              case TDuration::DurationType::V_BREVE:
                    padToggle(Pad::NOTE00, ed);
                    break;
              case TDuration::DurationType::V_WHOLE:
                    padToggle(Pad::NOTE0, ed);
                    break;
              case TDuration::DurationType::V_HALF:
                    padToggle(Pad::NOTE1, ed);
                    break;
              case TDuration::DurationType::V_QUARTER:
                    padToggle(Pad::NOTE2, ed);
                    break;
              case TDuration::DurationType::V_EIGHTH:
                    padToggle(Pad::NOTE4, ed);
                    break;
              case TDuration::DurationType::V_16TH:
                    padToggle(Pad::NOTE8, ed);
                    break;
              case TDuration::DurationType::V_32ND:
                    padToggle(Pad::NOTE16, ed);
                    break;
              case TDuration::DurationType::V_64TH:
                    padToggle(Pad::NOTE32, ed);
                    break;
              case TDuration::DurationType::V_128TH:
                    padToggle(Pad::NOTE64, ed);
                    break;
              default:
                    break;
              }
        }
  
  //---------------------------------------------------------
  //   cmdPadNoteDecreaseTAB
  //---------------------------------------------------------
  
  void Score::cmdPadNoteDecreaseTAB(const EditData& ed)
        {
        switch (_is.duration().type() ) {
              case TDuration::DurationType::V_LONG:
                    padToggle(Pad::NOTE0, ed);
                    break;
              case TDuration::DurationType::V_BREVE:
                    padToggle(Pad::NOTE1, ed);
                    break;
              case TDuration::DurationType::V_WHOLE:
                    padToggle(Pad::NOTE2, ed);
                    break;
              case TDuration::DurationType::V_HALF:
                    padToggle(Pad::NOTE4, ed);
                    break;
              case TDuration::DurationType::V_QUARTER:
                    padToggle(Pad::NOTE8, ed);
                    break;
              case TDuration::DurationType::V_EIGHTH:
                    padToggle(Pad::NOTE16, ed);
                    break;
              case TDuration::DurationType::V_16TH:
                    padToggle(Pad::NOTE32, ed);
                    break;
              case TDuration::DurationType::V_32ND:
                    padToggle(Pad::NOTE64, ed);
                    break;
              case TDuration::DurationType::V_64TH:
                    padToggle(Pad::NOTE128, ed);
                    break;
  // cycle back from shortest to longest?
  //          case TDuration::DurationType::V_128TH:
  //                padToggle(Pad::NOTE00, ed);
  //                break;
              default:
                    break;
              }
        }
  
  //---------------------------------------------------------
  //   cmdToggleLayoutBreak
  //---------------------------------------------------------
  
  void Score::cmdToggleLayoutBreak(LayoutBreak::Type type)
        {
        // find measure(s)
        QList<MeasureBase*> mbl;
        if (selection().isRange()) {
              Measure* startMeasure = nullptr;
              Measure* endMeasure = nullptr;
              if (!selection().measureRange(&startMeasure, &endMeasure))
                    return;
              if (!startMeasure || !endMeasure)
                    return;
  #if 1
              // toggle break on the last measure of the range
              mbl.append(endMeasure);
              // if more than one measure selected,
              // also toggle break *before* the range (to try to fit selection on a single line)
              if (startMeasure != endMeasure && startMeasure->prev())
                    mbl.append(startMeasure->prev());
  #else
              // toggle breaks throughout the selection
              for (Measure* m = startMeasure; m; m = m->nextMeasure()) {
                    mbl.append(m);
                    if (m == endMeasure)
                          break;
                    }
  #endif
              }
        else {
              MeasureBase* mb = nullptr;
              for (Element* el : selection().elements()) {
                    switch (el->type()) {
                          case ElementType::HBOX:
                          case ElementType::VBOX:
                          case ElementType::TBOX:
                                mb = toMeasureBase(el);
                                break;
                          default: {
                                // find measure
                                Measure* measure = toMeasure(el->findMeasure());
                                // for start repeat, attach break to previous measure
                                if (measure && el->isBarLine()) {
                                      BarLine* bl = toBarLine(el);
                                      if (bl->barLineType() == BarLineType::START_REPEAT)
                                            measure = measure->prevMeasure();
                                      }
                                // if measure is mmrest, then propagate to last original measure
                                if (measure)
                                      mb = measure->isMMRest() ? measure->mmRestLast() : measure;
                                }
                          }
                    }
              if (mb)
                    mbl.append(mb);
              }
        // toggle the breaks
        for (MeasureBase* mb: mbl) {
              if (mb) {
                    bool val = false;
                    switch (type) {
                          case LayoutBreak::Type::LINE:
                                val = !mb->lineBreak();
                                mb->undoSetBreak(val, type);
                                // remove page break if appropriate
                                if (val && mb->pageBreak())
                                      mb->undoSetBreak(false, LayoutBreak::Type::PAGE);
                                break;
                          case LayoutBreak::Type::PAGE:
                                val = !mb->pageBreak();
                                mb->undoSetBreak(val, type);
                                // remove line break if appropriate
                                if (val && mb->lineBreak())
                                      mb->undoSetBreak(false, LayoutBreak::Type::LINE);
                                break;
                          case LayoutBreak::Type::SECTION:
                                val = !mb->sectionBreak();
                                mb->undoSetBreak(val, type);
                                break;
                          default:
                                break;
                          }
                    }
              }
        }
  
  //---------------------------------------------------------
  //   cmdToggleMmrest
  //---------------------------------------------------------
  
  void Score::cmdToggleMmrest()
        {
        bool val = !styleB(Sid::createMultiMeasureRests);
        deselectAll();
        undo(new ChangeStyleVal(this, Sid::createMultiMeasureRests, val));
        }
  
  //---------------------------------------------------------
  //   cmdToggleHideEmpty
  //---------------------------------------------------------
  
  void Score::cmdToggleHideEmpty()
        {
        bool val = !styleB(Sid::hideEmptyStaves);
        deselectAll();
        undo(new ChangeStyleVal(this, Sid::hideEmptyStaves, val));
        }
  
  //---------------------------------------------------------
  //   cmdSetVisible
  //---------------------------------------------------------
  
  void Score::cmdSetVisible()
        {
        for (Element* e : selection().elements())
              undo(new ChangeProperty(e, Pid::VISIBLE, true));
        }
  
  //---------------------------------------------------------
  //   cmdUnsetVisible
  //---------------------------------------------------------
  
  void Score::cmdUnsetVisible()
        {
        for (Element* e : selection().elements())
              undo(new ChangeProperty(e, Pid::VISIBLE, false));
        }
  
  //---------------------------------------------------------
  //   cmdAddPitch
  ///   insert note or add note to chord
  //    c d e f g a b entered:
  //---------------------------------------------------------
  
  void Score::cmdAddPitch(const EditData& ed, int note, bool addFlag, bool insert)
        {
        InputState& is = inputState();
        if (is.track() == -1)          // invalid state
              return;
        if (is.segment() == 0) {
              qDebug("cannot enter notes here (no chord rest at current position)");
              return;
              }
        is.setRest(false);
        const Drumset* ds = is.drumset();
        int octave = 4;
        if (ds) {
              char note1 = "CDEFGAB"[note];
              int pitch = -1;
              int voice = 0;
              for (int i = 0; i < 127; ++i) {
                    if (!ds->isValid(i))
                          continue;
                    if (ds->shortcut(i) && (ds->shortcut(i) == note1)) {
                          pitch = i;
                          voice = ds->voice(i);
                          break;
                          }
                    }
              if (pitch == -1) {
                    qDebug("  shortcut %c not defined in drumset", note1);
                    return;
                    }
              is.setDrumNote(pitch);
              is.setTrack((is.track() / VOICES) * VOICES + voice);
              octave = pitch / 12;
              if (is.segment()) {
                    Segment* seg = is.segment();
                    while (seg) {
                          if (seg->element(is.track()))
                                break;
                          seg = seg->prev(SegmentType::ChordRest);
                          }
                    if (seg)
                          is.setSegment(seg);
                    else
                          is.setSegment(is.segment()->measure()->first(SegmentType::ChordRest));
                    }
              }
        else {
              static const int tab[] = { 0, 2, 4, 5, 7, 9, 11 };
  
              // if adding notes, add above the upNote of the current chord
              Element* el = selection().element();
              if (addFlag && el && el->isNote()) {
                    Chord* chord = toNote(el)->chord();
                    Note* n      = chord->upNote();
                    octave = n->epitch() / 12;
                    int tpc = n->tpc();
                    if (tpc == Tpc::TPC_C_BB || tpc == Tpc::TPC_C_B)
                          ++octave;
                    else if (tpc == Tpc::TPC_B_S || tpc == Tpc::TPC_B_SS)
                          --octave;
                    if (note <= tpc2step(tpc))
                          octave++;
                    }
              else {
                    int curPitch = 60;
                    if (is.segment()) {
                          Staff* staff = Score::staff(is.track() / VOICES);
                          Segment* seg = is.segment()->prev1(SegmentType::ChordRest | SegmentType::Clef | SegmentType::HeaderClef);
                          while (seg) {
                                if (seg->isChordRestType()) {
                                      Element* p = seg->element(is.track());
                                      if (p && p->isChord()) {
                                            curPitch = toChord(p)->downNote()->epitch();
                                            break;
                                            }
                                      }
                                else if (seg->isClefType() || seg->isHeaderClefType()) {
                                      Element* p = seg->element( (is.track() / VOICES) * VOICES); // clef on voice 1
                                      if (p && p->isClef()) {
                                            Clef* clef = toClef(p);
                                            // check if it's an actual change or just a courtesy
                                            ClefType ctb = staff->clef(clef->tick() - Fraction::fromTicks(1));
                                            if (ctb != clef->clefType() || clef->tick().isZero()) {
                                                  curPitch = line2pitch(4, clef->clefType(), Key::C); // C 72 for treble clef
                                                  break;
                                                  }
                                            }
                                      }
                                seg = seg->prev1MM(SegmentType::ChordRest | SegmentType::Clef | SegmentType::HeaderClef);
                                }
                          octave = curPitch / 12;
                          }
  
                    int delta = octave * 12 + tab[note] - curPitch;
                    if (delta > 6)
                          --octave;
                    else if (delta < -6)
                          ++octave;
                    }
              }
        ed.view->startNoteEntryMode();
  
        int step = octave * 7 + note;
        cmdAddPitch(step,  addFlag, insert);
        ed.view->adjustCanvasPosition(is.cr(), false);
        }
  
  void Score::cmdAddPitch(int step, bool addFlag, bool insert)
        {
        insert = insert || inputState().usingNoteEntryMethod(NoteEntryMethod::TIMEWISE);
        Position pos;
        if (addFlag) {
              Element* el = selection().element();
              if (el && el->isNote()) {
                    Note* selectedNote = toNote(el);
                    Chord* chord  = selectedNote->chord();
                    Segment* seg  = chord->segment();
                    pos.segment   = seg;
                    pos.staffIdx  = selectedNote->track() / VOICES;
                    ClefType clef = staff(pos.staffIdx)->clef(seg->tick());
                    pos.line      = relStep(step, clef);
                    bool error;
                    NoteVal nval = noteValForPosition(pos, _is.accidentalType(), error);
                    if (error)
                          return;
                    bool forceAccidental = false;
                    if (_is.accidentalType() != AccidentalType::NONE) {
                          NoteVal nval2 = noteValForPosition(pos, AccidentalType::NONE, error);
                          forceAccidental = (nval.pitch == nval2.pitch);
                          }
                    addNote(chord, nval, forceAccidental);
                    _is.setAccidentalType(AccidentalType::NONE);
                    return;
                    }
              }
  
        pos.segment   = inputState().segment();
        pos.staffIdx  = inputState().track() / VOICES;
        ClefType clef = staff(pos.staffIdx)->clef(pos.segment->tick());
        pos.line      = relStep(step, clef);
  
        if (inputState().usingNoteEntryMethod(NoteEntryMethod::REPITCH))
              repitchNote(pos, !addFlag);
        else {
              if (insert)
                    insertChord(pos);
              else
                    putNote(pos, !addFlag);
              }
        _is.setAccidentalType(AccidentalType::NONE);
        }
  
  //---------------------------------------------------------
  //   cmdToggleVisible
  //---------------------------------------------------------
  
  void Score::cmdToggleVisible()
        {
        QSet<Element*> spanners;
        for (Element* e : selection().elements()) {
              if (e->isBracket())     // ignore
                    continue;
              if (e->isNoteDot() && selection().elements().contains(e->parent()))
                    // already handled in ScoreElement::undoChangeProperty(); don't toggle twice
                    continue;
              bool spannerSegment = e->isSpannerSegment();
              if (!spannerSegment || !spanners.contains(toSpannerSegment(e)->spanner()))
                    e->undoChangeProperty(Pid::VISIBLE, !e->getProperty(Pid::VISIBLE).toBool());
              if (spannerSegment)
                    spanners.insert(toSpannerSegment(e)->spanner());
              }
        }
  
  //---------------------------------------------------------
  //   cmdAddFret
  ///   insert note with given fret on current string
  //---------------------------------------------------------
  
  void Score::cmdAddFret(int fret)
        {
        InputState& is = inputState();
        if (is.track() == -1)                     // invalid state
              return;
        if (!is.segment()) {
              qDebug("cannot enter notes here (no chord rest at current position)");
              return;
              }
        Position pos;
        pos.segment   = is.segment();
        pos.staffIdx  = is.track() / VOICES;
        pos.line      = staff(pos.staffIdx)->staffType(is.tick())->physStringToVisual(is.string());
        pos.fret      = fret;
        putNote(pos, false);
        }
  
  //---------------------------------------------------------
  //   cmdRelayout
  //---------------------------------------------------------
  
  void Score::cmdRelayout()
        {
        setLayoutAll();
        }
  
  //---------------------------------------------------------
  //   cmdToggleAutoplace
  //---------------------------------------------------------
  
  void Score::cmdToggleAutoplace(bool all)
        {
        if (all) {
              bool val = !styleB(Sid::autoplaceEnabled);
              undoChangeStyleVal(Sid::autoplaceEnabled, val);
              setLayoutAll();
              }
        else {
              QSet<Element*> spanners;
              for (Element* e : selection().elements()) {
                    if (e->isSpannerSegment()) {
                          if (Element* ee = e->propertyDelegate(Pid::AUTOPLACE))
                                e = ee;
                          // spanner segments may each have their own autoplace setting
                          // but if they delegate to spanner, only toggle once
                          if (e->isSpanner()) {
                                if (spanners.contains(e))
                                      continue;
                                spanners.insert(e);
                                }
                          }
                    PropertyFlags pf = e->propertyFlags(Pid::AUTOPLACE);
                    if (pf == PropertyFlags::STYLED)
                          pf = PropertyFlags::UNSTYLED;
                    e->undoChangeProperty(Pid::AUTOPLACE, !e->getProperty(Pid::AUTOPLACE).toBool(), pf);
                    }
              }
        }
  
  //---------------------------------------------------------
  //   cmd
  //---------------------------------------------------------
  
  void Score::cmd(const QAction* a, EditData& ed)
        {
        QString cmd(a ? a->data().toString() : "");
        if (MScore::debugMode)
              qDebug("<%s>", qPrintable(cmd));
  
        struct ScoreCmd {
              const char* name;
              std::function<void(Score* cs, EditData& ed)> cmd;
              };
        static const std::vector<ScoreCmd> cmdList {
              { "note-c",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 0, false, false);                        }},
              { "note-d",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 1, false, false);                        }},
              { "note-e",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 2, false, false);                        }},
              { "note-f",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 3, false, false);                        }},
              { "note-g",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 4, false, false);                        }},
              { "note-a",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 5, false, false);                        }},
              { "note-b",                     [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 6, false, false);                        }},
              { "chord-c",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 0, true, false);                         }},
              { "chord-d",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 1, true, false);                         }},
              { "chord-e",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 2, true, false);                         }},
              { "chord-f",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 3, true, false);                         }},
              { "chord-g",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 4, true, false);                         }},
              { "chord-a",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 5, true, false);                         }},
              { "chord-b",                    [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 6, true, false);                         }},
              { "insert-c",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 0, false, true);                         }},
              { "insert-d",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 1, false, true);                         }},
              { "insert-e",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 2, false, true);                         }},
              { "insert-f",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 3, false, true);                         }},
              { "insert-g",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 4, false, true);                         }},
              { "insert-a",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 5, false, true);                         }},
              { "insert-b",                   [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 6, false, true);                         }},
              { "fret-0",                     [](Score* cs, EditData&){ cs->cmdAddFret(0);                                              }},
              { "fret-1",                     [](Score* cs, EditData&){ cs->cmdAddFret(1);                                              }},
              { "fret-2",                     [](Score* cs, EditData&){ cs->cmdAddFret(2);                                              }},
              { "fret-3",                     [](Score* cs, EditData&){ cs->cmdAddFret(3);                                              }},
              { "fret-4",                     [](Score* cs, EditData&){ cs->cmdAddFret(4);                                              }},
              { "fret-5",                     [](Score* cs, EditData&){ cs->cmdAddFret(5);                                              }},
              { "fret-6",                     [](Score* cs, EditData&){ cs->cmdAddFret(6);                                              }},
              { "fret-7",                     [](Score* cs, EditData&){ cs->cmdAddFret(7);                                              }},
              { "fret-8",                     [](Score* cs, EditData&){ cs->cmdAddFret(8);                                              }},
              { "fret-9",                     [](Score* cs, EditData&){ cs->cmdAddFret(9);                                              }},
              { "fret-10",                    [](Score* cs, EditData&){ cs->cmdAddFret(10);                                             }},
              { "fret-11",                    [](Score* cs, EditData&){ cs->cmdAddFret(11);                                             }},
              { "fret-12",                    [](Score* cs, EditData&){ cs->cmdAddFret(12);                                             }},
              { "fret-13",                    [](Score* cs, EditData&){ cs->cmdAddFret(13);                                             }},
              { "fret-14",                    [](Score* cs, EditData&){ cs->cmdAddFret(14);                                             }},
              { "toggle-visible",             [](Score* cs, EditData&){ cs->cmdToggleVisible();                                         }},
              { "reset-stretch",              [](Score* cs, EditData&){ cs->resetUserStretch();                                         }},
              { "mirror-note",                [](Score* cs, EditData&){ cs->cmdMirrorNoteHead();                                        }},
              { "double-duration",            [](Score* cs, EditData&){ cs->cmdDoubleDuration();                                        }},
              { "half-duration",              [](Score* cs, EditData&){ cs->cmdHalfDuration();                                          }},
              { "inc-duration-dotted",        [](Score* cs, EditData&){ cs->cmdIncDurationDotted();                                     }},
              { "dec-duration-dotted",        [](Score* cs, EditData&){ cs->cmdDecDurationDotted();                                     }},
              { "add-staccato",               [](Score* cs, EditData&){ cs->addArticulation(SymId::articStaccatoAbove);                 }},
              { "add-tenuto",                 [](Score* cs, EditData&){ cs->addArticulation(SymId::articTenutoAbove);                   }},
              { "add-marcato",                [](Score* cs, EditData&){ cs->addArticulation(SymId::articMarcatoAbove);                  }},
              { "add-sforzato",               [](Score* cs, EditData&){ cs->addArticulation(SymId::articAccentAbove);                   }},
              { "add-trill",                  [](Score* cs, EditData&){ cs->addArticulation(SymId::ornamentTrill);                      }},
              { "add-up-bow",                 [](Score* cs, EditData&){ cs->addArticulation(SymId::stringsUpBow);                       }},
              { "add-down-bow",               [](Score* cs, EditData&){ cs->addArticulation(SymId::stringsDownBow);                     }},
              { "add-8va",                    [](Score* cs, EditData&){ cs->cmdAddOttava(OttavaType::OTTAVA_8VA);                       }},
              { "add-8vb",                    [](Score* cs, EditData&){ cs->cmdAddOttava(OttavaType::OTTAVA_8VB);                       }},
              { "note-longa",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE00, ed);                              }},
              { "note-longa-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE00, ed);                              }},
              { "note-breve",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE0, ed);                               }},
              { "note-breve-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE0, ed);                               }},
              { "pad-note-1",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE1, ed);                               }},
              { "pad-note-1-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE1, ed);                               }},
              { "pad-note-2",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE2, ed);                               }},
              { "pad-note-2-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE2, ed);                               }},
              { "pad-note-4",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE4, ed);                               }},
              { "pad-note-4-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE4, ed);                               }},
              { "pad-note-8",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE8, ed);                               }},
              { "pad-note-8-TAB",             [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE8, ed);                               }},
              { "pad-note-16",                [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE16, ed);                              }},
              { "pad-note-16-TAB",            [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE16, ed);                              }},
              { "pad-note-32",                [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE32, ed);                              }},
              { "pad-note-32-TAB",            [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE32, ed);                              }},
              { "pad-note-64",                [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE64, ed);                              }},
              { "pad-note-64-TAB",            [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE64, ed);                              }},
              { "pad-note-128",               [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE128, ed);                             }},
              { "pad-note-128-TAB",           [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE128, ed);                             }},
              { "reset-style",                [](Score* cs, EditData&){ cs->cmdResetStyle();                                            }},
              { "reset-beammode",             [](Score* cs, EditData&){ cs->cmdResetBeamMode();                                         }},
              { "reset-groupings",            [](Score* cs, EditData&){ cs->cmdResetNoteAndRestGroupings();                             }},
              { "clef-violin",                [](Score* cs, EditData&){ cs->cmdInsertClef(ClefType::G);                                 }},
              { "clef-bass",                  [](Score* cs, EditData&){ cs->cmdInsertClef(ClefType::F);                                 }},
              { "voice-x12",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(0, 1);                                     }},
              { "voice-x13",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(0, 2);                                     }},
              { "voice-x14",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(0, 3);                                     }},
              { "voice-x23",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(1, 2);                                     }},
              { "voice-x24",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(1, 3);                                     }},
              { "voice-x34",                  [](Score* cs, EditData&){ cs->cmdExchangeVoice(2, 3);                                     }},
              { "pad-rest",                   [](Score* cs, EditData& ed){ cs->padToggle(Pad::REST, ed);                                }},
              { "pad-dot",                    [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOT, ed);                                 }},
              { "pad-dotdot",                 [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOTDOT, ed);                              }},
              { "pad-dot3",                   [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOT3, ed);                                }},
              { "pad-dot4",                   [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOT4, ed);                                }},
              { "beam-start",                 [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::BEGIN);                          }},
              { "beam-mid",                   [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::MID);                            }},
              { "no-beam",                    [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::NONE);                           }},
              { "beam32",                     [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::BEGIN32);                        }},
              { "beam64",                     [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::BEGIN64);                        }},
              { "auto-beam",                  [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::AUTO);                           }},
              { "sharp2",                     [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::SHARP2, ed);            }},
              { "sharp",                      [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::SHARP, ed);             }},
              { "nat",                        [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::NATURAL, ed);           }},
              { "flat",                       [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::FLAT, ed);              }},
              { "flat2",                      [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::FLAT2, ed);             }},
              { "flip",                       [](Score* cs, EditData&){ cs->cmdFlip();                                                  }},
              { "stretch+",                   [](Score* cs, EditData&){ cs->cmdAddStretch(0.1);                                         }},
              { "stretch-",                   [](Score* cs, EditData&){ cs->cmdAddStretch(-0.1);                                        }},
              { "pitch-spell",                [](Score* cs, EditData&){ cs->spell();                                                    }},
              { "select-all",                 [](Score* cs, EditData&){ cs->cmdSelectAll();                                             }},
              { "select-section",             [](Score* cs, EditData&){ cs->cmdSelectSection();                                         }},
              { "add-brackets",               [](Score* cs, EditData&){ cs->cmdAddBracket();                                            }},
              { "add-parentheses",            [](Score* cs, EditData&){ cs->cmdAddParentheses();                                        }},
              { "acciaccatura",               [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::ACCIACCATURA, MScore::division / 2);  }},
              { "appoggiatura",               [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::APPOGGIATURA, MScore::division / 2);  }},
              { "grace4",                     [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE4, MScore::division);            }},
              { "grace16",                    [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE16, MScore::division / 4);       }},
              { "grace32",                    [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE32, MScore::division / 8);       }},
              { "grace8after",                [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE8_AFTER, MScore::division / 2);  }},
              { "grace16after",               [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE16_AFTER, MScore::division / 4); }},
              { "grace32after",               [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE32_AFTER, MScore::division / 8); }},
              { "explode",                    [](Score* cs, EditData&){ cs->cmdExplode();                                               }},
              { "implode",                    [](Score* cs, EditData&){ cs->cmdImplode();                                               }},
              { "slash-fill",                 [](Score* cs, EditData&){ cs->cmdSlashFill();                                             }},
              { "slash-rhythm",               [](Score* cs, EditData&){ cs->cmdSlashRhythm();                                           }},
              { "resequence-rehearsal-marks", [](Score* cs, EditData&){ cs->cmdResequenceRehearsalMarks();                              }},
              { "del-empty-measures",         [](Score* cs, EditData&){ cs->cmdRemoveEmptyTrailingMeasures();                           }},
              { "add-audio",                  [](Score* cs, EditData&){ cs->addAudioTrack();                                            }},
              { "transpose-up",               [](Score* cs, EditData&){ cs->transposeSemitone(1);                                       }},
              { "transpose-down",             [](Score* cs, EditData&){ cs->transposeSemitone(-1);                                      }},
              { "delete",                     [](Score* cs, EditData&){ cs->cmdDeleteSelection();                                       }},
              { "full-measure-rest",          [](Score* cs, EditData&){ cs->cmdFullMeasureRest();                                       }},
              { "toggle-insert-mode",         [](Score* cs, EditData&){ cs->_is.setInsertMode(!cs->_is.insertMode());                       }},
              { "pitch-up",                   [](Score* cs, EditData&){ cs->cmdPitchUp();                                               }},
              { "pitch-down",                 [](Score* cs, EditData&){ cs->cmdPitchDown();                                             }},
              { "time-delete",                [](Score* cs, EditData&){ cs->cmdTimeDelete();                                            }},
              { "pitch-up-octave",            [](Score* cs, EditData&){ cs->cmdPitchUpOctave();                                         }},
              { "pitch-down-octave",          [](Score* cs, EditData&){ cs->cmdPitchDownOctave();                                       }},
              { "pad-note-increase",          [](Score* cs, EditData& ed){ cs->cmdPadNoteIncreaseTAB(ed);                               }},
              { "pad-note-decrease",          [](Score* cs, EditData& ed){ cs->cmdPadNoteDecreaseTAB(ed);                               }},
              { "pad-note-increase-TAB",      [](Score* cs, EditData& ed){ cs->cmdPadNoteIncreaseTAB(ed);                               }},
              { "pad-note-decrease-TAB",      [](Score* cs, EditData& ed){ cs->cmdPadNoteDecreaseTAB(ed);                               }},
              { "toggle-mmrest",              [](Score* cs, EditData&){ cs->cmdToggleMmrest();                                          }},
              { "toggle-hide-empty",          [](Score* cs, EditData&){ cs->cmdToggleHideEmpty();                                       }},
              { "set-visible",                [](Score* cs, EditData&){ cs->cmdSetVisible();                                            }},
              { "unset-visible",              [](Score* cs, EditData&){ cs->cmdUnsetVisible();                                          }},
              { "system-break",               [](Score* cs, EditData&){ cs->cmdToggleLayoutBreak(LayoutBreak::Type::LINE);              }},
              { "page-break",                 [](Score* cs, EditData&){ cs->cmdToggleLayoutBreak(LayoutBreak::Type::PAGE);              }},
              { "section-break",              [](Score* cs, EditData&){ cs->cmdToggleLayoutBreak(LayoutBreak::Type::SECTION);           }},
              { "relayout",                   [](Score* cs, EditData&){ cs->cmdRelayout();                                              }},
              { "toggle-autoplace",           [](Score* cs, EditData&){ cs->cmdToggleAutoplace(false);                                  }},
              { "autoplace-enabled",          [](Score* cs, EditData&){ cs->cmdToggleAutoplace(true);                                   }},
              };
  
        for (const auto& c : cmdList) {
              if (cmd == c.name) {
                    startCmd();
                    c.cmd(this, ed);
                    endCmd();
                    return;
                    }
              }
        qDebug("unknown cmd <%s>", qPrintable(cmd));
        }
  
  
  }
  
  