|
39 | 39 | #include "../dom/barline.h" |
40 | 40 | #include "../dom/box.h" |
41 | 41 | #include "../dom/chord.h" |
| 42 | +#include "../dom/chordrest.h" |
42 | 43 | #include "../dom/clef.h" |
43 | 44 | #include "../dom/drumset.h" |
| 45 | +#include "../dom/durationtype.h" |
44 | 46 | #include "../dom/dynamic.h" |
45 | 47 | #include "../dom/factory.h" |
46 | 48 | #include "../dom/glissando.h" |
@@ -3303,45 +3305,71 @@ void Score::cmdMirrorNoteHead() |
3303 | 3305 |
|
3304 | 3306 | void Score::cmdIncDecDuration(int nSteps, bool stepDotted) |
3305 | 3307 | { |
3306 | | - EngravingItem* el = selection().element(); |
3307 | | - if (el == 0) { |
3308 | | - return; |
3309 | | - } |
3310 | | - if (el->isNote()) { |
3311 | | - el = el->parentItem(); |
3312 | | - } |
3313 | | - if (!el->isChordRest()) { |
3314 | | - return; |
3315 | | - } |
3316 | | - |
3317 | | - ChordRest* cr = toChordRest(el); |
| 3308 | + if (m_selection.isRange()) { |
| 3309 | + if (!m_selection.canCopy()) { |
| 3310 | + return; |
| 3311 | + } |
| 3312 | + ChordRest* firstCR = m_selection.firstChordRest(); |
| 3313 | + if (firstCR->isGrace()) { |
| 3314 | + firstCR = toChordRest(firstCR->parent()); |
| 3315 | + } |
| 3316 | + TDuration initialDuration = firstCR->ticks(); |
| 3317 | + TDuration d = initialDuration.shiftRetainDots(nSteps, stepDotted); |
| 3318 | + if (!d.isValid()) { |
| 3319 | + return; |
| 3320 | + } |
| 3321 | + Fraction scale = d.ticks() / initialDuration.ticks(); |
| 3322 | + for (ChordRest* cr : getSelectedChordRests()) { |
| 3323 | + Fraction newTicks = cr->ticks() * scale; |
| 3324 | + if (newTicks < Fraction(1, 1024) |
| 3325 | + || (stepDotted && cr->durationType().dots() != firstCR->durationType().dots() |
| 3326 | + && !cr->isGrace())) { |
| 3327 | + return; |
| 3328 | + } |
| 3329 | + } |
| 3330 | + const muse::ByteArray mimeData(m_selection.mimeData()); |
| 3331 | + XmlReader e(mimeData); |
| 3332 | + deleteRange(m_selection.startSegment(), m_selection.endSegment(), staff2track(m_selection.staffStart()), |
| 3333 | + staff2track(m_selection.staffEnd()), selectionFilter(), m_selection.rangeContainsMultiNoteChords()); |
| 3334 | + pasteStaff(e, m_selection.startSegment(), m_selection.staffStart(), scale); |
| 3335 | + } else if (m_selection.isList()) { |
| 3336 | + const std::set<ChordRest*> crs = getSelectedChordRests(); |
| 3337 | + for (ChordRest* cr : crs) { |
| 3338 | + // if measure rest is selected as input, then the correct initialDuration will be the |
| 3339 | + // duration of the measure's time signature, else is just the ChordRest's duration |
| 3340 | + TDuration initialDuration = cr->durationType(); |
| 3341 | + if (initialDuration == DurationType::V_MEASURE) { |
| 3342 | + initialDuration = TDuration(cr->measure()->timesig(), true); |
| 3343 | + |
| 3344 | + if (initialDuration.fraction() < cr->measure()->timesig() && nSteps > 0) { |
| 3345 | + // Duration already shortened by truncation; shorten one step less |
| 3346 | + --nSteps; |
| 3347 | + } |
| 3348 | + } |
3318 | 3349 |
|
3319 | | - // if measure rest is selected as input, then the correct initialDuration will be the |
3320 | | - // duration of the measure's time signature, else is just the ChordRest's duration |
3321 | | - TDuration initialDuration = cr->durationType(); |
3322 | | - if (initialDuration == DurationType::V_MEASURE) { |
3323 | | - initialDuration = TDuration(cr->measure()->timesig(), true); |
| 3350 | + TDuration newDuration { stepDotted ? initialDuration.shiftRetainDots(nSteps, stepDotted) : initialDuration.shift(nSteps) }; |
| 3351 | + if (!newDuration.isValid()) { |
| 3352 | + continue; |
| 3353 | + } |
3324 | 3354 |
|
3325 | | - if (initialDuration.fraction() < cr->measure()->timesig() && nSteps > 0) { |
3326 | | - // Duration already shortened by truncation; shorten one step less |
3327 | | - --nSteps; |
| 3355 | + if (cr->isGrace()) { |
| 3356 | + undoChangeChordRestLen(cr, newDuration); |
| 3357 | + } else { |
| 3358 | + changeCRlen(cr, newDuration); |
| 3359 | + } |
| 3360 | + } |
| 3361 | + // 2nd loop needed to reselect what was selected before 1st loop |
| 3362 | + // as `changeCRlen()` changes the selection to `SelectType::SINGLE` |
| 3363 | + for (ChordRest* cr : crs) { |
| 3364 | + EngravingItem* e = cr; |
| 3365 | + if (cr->isChord()) { |
| 3366 | + e = toChord(cr)->upNote(); |
| 3367 | + } |
| 3368 | + if (canReselectItem(e)) { |
| 3369 | + select(e, SelectType::ADD); |
| 3370 | + } |
3328 | 3371 | } |
3329 | 3372 | } |
3330 | | - |
3331 | | - TDuration d = (nSteps != 0) ? initialDuration.shiftRetainDots(nSteps, stepDotted) : initialDuration; |
3332 | | - if (!d.isValid()) { |
3333 | | - return; |
3334 | | - } |
3335 | | - if (cr->isChord() && (toChord(cr)->noteType() != NoteType::NORMAL)) { |
3336 | | - // |
3337 | | - // handle appoggiatura and acciaccatura |
3338 | | - // |
3339 | | - undoChangeChordRestLen(cr, d); |
3340 | | - } else { |
3341 | | - changeCRlen(cr, d); |
3342 | | - } |
3343 | | - m_is.setDuration(d); |
3344 | | - nextInputPos(cr, false); |
3345 | 3373 | } |
3346 | 3374 |
|
3347 | 3375 | //--------------------------------------------------------- |
|
0 commit comments