From 165d966e48ffc89c4f3b216c8eab92f41501a92c Mon Sep 17 00:00:00 2001 From: Howard-C Date: Tue, 28 Jul 2020 13:13:28 +0800 Subject: [PATCH 1/7] fix #301834: crash when changing local time signature to another one with same duration This is because it doesn't check whether the time signature is local or not, so it always goes to every staff and trys to find a time signature segment, causing `nullptr`. --- libmscore/edit.cpp | 73 +++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/libmscore/edit.cpp b/libmscore/edit.cpp index c113392381e5c..3ecc765660368 100644 --- a/libmscore/edit.cpp +++ b/libmscore/edit.cpp @@ -812,37 +812,58 @@ void Score::cmdAddTimeSig(Measure* fm, int staffIdx, TimeSig* ts, bool local) return; } + auto getStaffIdxRange = [this, local, staffIdx](const Score* score) -> std::pair { + int startStaffIdx, endStaffIdx; + if (local) { + if (score == this) { + startStaffIdx = staffIdx; + endStaffIdx = startStaffIdx + 1; + } + else { + // TODO: get index for this score + qDebug("cmdAddTimeSig: unable to write local time signature change to linked score"); + startStaffIdx = 0; + endStaffIdx = 0; + } + } + else { + startStaffIdx = 0; + endStaffIdx = score->nstaves(); + } + return std::make_pair(startStaffIdx, endStaffIdx); + }; + if (ots && ots->sig() == ns && ots->stretch() == ts->stretch()) { // // the measure duration does not change, // so its ok to just update the time signatures // TimeSig* nts = staff(staffIdx)->nextTimeSig(tick + Fraction::fromTicks(1)); - const Fraction lmTick = nts ? nts->segment()->tick() : Fraction(-1,1); + const Fraction lmTick = nts ? nts->segment()->tick() : Fraction(-1, 1); for (Score* score : scoreList()) { Measure* mf = score->tick2measure(tick); - Measure* lm = (lmTick != Fraction(-1,1)) ? score->tick2measure(lmTick) : nullptr; + Measure* lm = (lmTick != Fraction(-1, 1)) ? score->tick2measure(lmTick) : nullptr; for (Measure* m = mf; m != lm; m = m->nextMeasure()) { bool changeActual = m->ticks() == m->timesig(); m->undoChangeProperty(Pid::TIMESIG_NOMINAL, QVariant::fromValue(ns)); if (changeActual) { - m->undoChangeProperty(Pid::TIMESIG_ACTUAL, QVariant::fromValue(ns)); + m->undoChangeProperty(Pid::TIMESIG_ACTUAL, QVariant::fromValue(ns)); + } + std::pair staffIdxRange = getStaffIdxRange(score); + for (int si = staffIdxRange.first; si < staffIdxRange.second; ++si) { + TimeSig* nsig = toTimeSig(seg->element(si * VOICES)); + nsig->undoChangeProperty(Pid::SHOW_COURTESY, ts->showCourtesySig()); + nsig->undoChangeProperty(Pid::TIMESIG, QVariant::fromValue(ts->sig())); + nsig->undoChangeProperty(Pid::TIMESIG_TYPE, int(ts->timeSigType())); + nsig->undoChangeProperty(Pid::NUMERATOR_STRING, ts->numeratorString()); + nsig->undoChangeProperty(Pid::DENOMINATOR_STRING, ts->denominatorString()); + nsig->undoChangeProperty(Pid::TIMESIG_STRETCH, QVariant::fromValue(ts->stretch())); + nsig->undoChangeProperty(Pid::GROUPS, QVariant::fromValue(ts->groups())); + nsig->setSelected(false); + nsig->setDropTarget(0); } } } - int n = nstaves(); - for (int si = 0; si < n; ++si) { - TimeSig* nsig = toTimeSig(seg->element(si * VOICES)); - nsig->undoChangeProperty(Pid::SHOW_COURTESY, ts->showCourtesySig()); - nsig->undoChangeProperty(Pid::TIMESIG, QVariant::fromValue(ts->sig())); - nsig->undoChangeProperty(Pid::TIMESIG_TYPE, int(ts->timeSigType())); - nsig->undoChangeProperty(Pid::NUMERATOR_STRING, ts->numeratorString()); - nsig->undoChangeProperty(Pid::DENOMINATOR_STRING, ts->denominatorString()); - nsig->undoChangeProperty(Pid::TIMESIG_STRETCH, QVariant::fromValue(ts->stretch())); - nsig->undoChangeProperty(Pid::GROUPS, QVariant::fromValue(ts->groups())); - nsig->setSelected(false); - nsig->setDropTarget(0); - } } else { Score* mScore = masterScore(); Measure* mf = mScore->tick2measure(tick); @@ -885,23 +906,9 @@ void Score::cmdAddTimeSig(Measure* fm, int staffIdx, TimeSig* ts, bool local) std::map masterTimeSigs; for (Score* score : scoreList()) { Measure* nfm = score->tick2measure(tick); - seg = nfm->undoGetSegment(SegmentType::TimeSig, nfm->tick()); - int startStaffIdx, endStaffIdx; - if (local) { - if (score == this) { - startStaffIdx = staffIdx; - endStaffIdx = startStaffIdx + 1; - } else { - // TODO: get index for this score - qDebug("cmdAddTimeSig: unable to write local time signature change to linked score"); - startStaffIdx = 0; - endStaffIdx = 0; - } - } else { - startStaffIdx = 0; - endStaffIdx = score->nstaves(); - } - for (int si = startStaffIdx; si < endStaffIdx; ++si) { + seg = nfm->undoGetSegment(SegmentType::TimeSig, nfm->tick()); + std::pair staffIdxRange = getStaffIdxRange(score); + for (int si = staffIdxRange.first; si < staffIdxRange.second; ++si) { TimeSig* nsig = toTimeSig(seg->element(si * VOICES)); if (nsig == 0) { nsig = new TimeSig(*ts); From 4124599f24247874642b6cf2e7a28cab6e8a6e37 Mon Sep 17 00:00:00 2001 From: Howard-C Date: Tue, 28 Jul 2020 13:50:41 +0800 Subject: [PATCH 2/7] fix #285135: "line thickness" parameter of ambitus is not working properly `Pid::LINE_WIDTH` cannot be used, since it's a `qreal` value, but the value used to store the line thickness of an ambitus is a `Spatium` value, so we have to use another `Pid` which is `Spatium` type, a new one `Pid::LINE_WIDTH_SPATIUM`. --- libmscore/ambitus.cpp | 12 ++++++------ libmscore/property.cpp | 2 ++ libmscore/property.h | 1 + .../notation/ambituses/ambitussettingsmodel.cpp | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libmscore/ambitus.cpp b/libmscore/ambitus.cpp index 9310074ca65e0..2959f59fcc337 100644 --- a/libmscore/ambitus.cpp +++ b/libmscore/ambitus.cpp @@ -203,8 +203,8 @@ void Ambitus::write(XmlWriter& xml) const xml.tag(Pid::HEAD_GROUP, int(_noteHeadGroup), int(NOTEHEADGROUP_DEFAULT)); xml.tag(Pid::HEAD_TYPE, int(_noteHeadType), int(NOTEHEADTYPE_DEFAULT)); xml.tag(Pid::MIRROR_HEAD,int(_dir), int(DIR_DEFAULT)); - xml.tag("hasLine", _hasLine, true); - xml.tag(Pid::LINE_WIDTH, _lineWidth, LINEWIDTH_DEFAULT); + xml.tag("hasLine", _hasLine, true); + xml.tag(Pid::LINE_WIDTH_SPATIUM, _lineWidth, LINEWIDTH_DEFAULT); xml.tag("topPitch", _topPitch); xml.tag("topTpc", _topTpc); xml.tag("bottomPitch",_bottomPitch); @@ -252,7 +252,7 @@ bool Ambitus::readProperties(XmlReader& e) } else if (tag == "hasLine") { setHasLine(e.readInt()); } else if (tag == "lineWidth") { - readProperty(e, Pid::LINE_WIDTH); + readProperty(e, Pid::LINE_WIDTH_SPATIUM); } else if (tag == "topPitch") { _topPitch = e.readInt(); } else if (tag == "bottomPitch") { @@ -673,7 +673,7 @@ QVariant Ambitus::getProperty(Pid propertyId) const return int(direction()); case Pid::GHOST: // recycled property = _hasLine return hasLine(); - case Pid::LINE_WIDTH: + case Pid::LINE_WIDTH_SPATIUM: return lineWidth(); case Pid::TPC1: return topTpc(); @@ -711,7 +711,7 @@ bool Ambitus::setProperty(Pid propertyId, const QVariant& v) case Pid::GHOST: // recycled property = _hasLine setHasLine(v.toBool()); break; - case Pid::LINE_WIDTH: + case Pid::LINE_WIDTH_SPATIUM: setLineWidth(v.value()); break; case Pid::TPC1: @@ -754,7 +754,7 @@ QVariant Ambitus::propertyDefault(Pid id) const return int(DIR_DEFAULT); case Pid::GHOST: return HASLINE_DEFAULT; - case Pid::LINE_WIDTH: + case Pid::LINE_WIDTH_SPATIUM: return Spatium(LINEWIDTH_DEFAULT); case Pid::TPC1: return estimateRanges().topTpc; diff --git a/libmscore/property.cpp b/libmscore/property.cpp index 60151e7fa1612..7f381449137bc 100644 --- a/libmscore/property.cpp +++ b/libmscore/property.cpp @@ -303,6 +303,8 @@ static constexpr PropertyMetaData propertyList[] = { DUMMY_QT_TRANSLATE_NOOP("propertyName", "line style") }, { Pid::LINE_WIDTH, false, "lineWidth", P_TYPE::SP_REAL, DUMMY_QT_TRANSLATE_NOOP("propertyName", "line width") }, + { Pid::LINE_WIDTH_SPATIUM, false, "lineWidth", P_TYPE::SPATIUM, + DUMMY_QT_TRANSLATE_NOOP("propertyName", "line width (spatium)") }, { Pid::LASSO_POS, false, 0, P_TYPE::POINT_MM, DUMMY_QT_TRANSLATE_NOOP("propertyName", "lasso position") }, { Pid::LASSO_SIZE, false, 0, P_TYPE::SIZE_MM, diff --git a/libmscore/property.h b/libmscore/property.h index 7f95861ed579e..92c72d9b74783 100644 --- a/libmscore/property.h +++ b/libmscore/property.h @@ -196,6 +196,7 @@ enum class Pid { GROUPS, LINE_STYLE, LINE_WIDTH, + LINE_WIDTH_SPATIUM, LASSO_POS, LASSO_SIZE, TIME_STRETCH, diff --git a/mu4/scenes/inspector/models/notation/ambituses/ambitussettingsmodel.cpp b/mu4/scenes/inspector/models/notation/ambituses/ambitussettingsmodel.cpp index 641e4b5a1924a..4b18936028205 100644 --- a/mu4/scenes/inspector/models/notation/ambituses/ambitussettingsmodel.cpp +++ b/mu4/scenes/inspector/models/notation/ambituses/ambitussettingsmodel.cpp @@ -35,7 +35,7 @@ void AmbitusSettingsModel::createProperties() }); m_direction = buildPropertyItem(Ms::Pid::MIRROR_HEAD); - m_lineThickness = buildPropertyItem(Ms::Pid::LINE_WIDTH); + m_lineThickness = buildPropertyItem(Ms::Pid::LINE_WIDTH_SPATIUM); } void AmbitusSettingsModel::requestElements() From a6285f7a1548db0ecd639576bfe09e77315fe6ef Mon Sep 17 00:00:00 2001 From: Howard-C Date: Tue, 28 Jul 2020 13:57:45 +0800 Subject: [PATCH 3/7] fix #305941: changing octaves for ambiti doesn't work correctly --- libmscore/ambitus.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmscore/ambitus.cpp b/libmscore/ambitus.cpp index 2959f59fcc337..752f4da12e6e5 100644 --- a/libmscore/ambitus.cpp +++ b/libmscore/ambitus.cpp @@ -727,10 +727,10 @@ bool Ambitus::setProperty(Pid propertyId, const QVariant& v) setBottomPitch(v.toInt()); break; case Pid::FBPARENTHESIS3: // recycled property = octave of _topPitch - setTopPitch(topPitch() % 12 + v.toInt() * 12); + setTopPitch(topPitch() % 12 + (v.toInt() + 1) * 12); break; case Pid::FBPARENTHESIS4: // recycled property = octave of _bottomPitch - setBottomPitch(bottomPitch() % 12 + v.toInt() * 12); + setBottomPitch(bottomPitch() % 12 + (v.toInt() + 1) * 12); break; default: return Element::setProperty(propertyId, v); From ce9a7f2d78b3fda8c332605af9fa09d044e10bae Mon Sep 17 00:00:00 2001 From: Howard-C Date: Tue, 28 Jul 2020 14:03:51 +0800 Subject: [PATCH 4/7] fix #307047: a problem with stem layout with tremolo --- libmscore/chord.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libmscore/chord.cpp b/libmscore/chord.cpp index 96a1a730eb620..22c2c4e0dd393 100644 --- a/libmscore/chord.cpp +++ b/libmscore/chord.cpp @@ -1522,11 +1522,15 @@ qreal Chord::minAbsStemLength() const if (!_tremolo->twoNotes()) { _tremolo->layout(); // guarantee right "height value" - qreal height; + // distance between tremolo stroke(s) and chord + // choose the furthest/nearest note to calculate for unbeamed/beamed chords + // this is due to special layout mechanisms regarding beamed chords + // may be changed if beam layout code is improved/rewritten + qreal height = 0.0; if (up()) { - height = upPos() - _tremolo->pos().y(); + height = (beam() ? upPos() : downPos()) - _tremolo->pos().y(); } else { - height = _tremolo->pos().y() + _tremolo->height() - downPos(); + height = _tremolo->pos().y() + _tremolo->height() - (beam() ? downPos() : upPos()); } const bool hasHook = beamLvl && !beam(); if (hasHook) { From 785253c09c3133f0cc953d9cb19235bf5274502c Mon Sep 17 00:00:00 2001 From: Howard-C Date: Tue, 28 Jul 2020 15:26:43 +0800 Subject: [PATCH 5/7] fix #294768: tremolos don't have cue size This is because the `mag()` factor isn't taken into consideration. Along with multiplying `mag()` in some places, I also created a new member function `minHeight()` for `Tremolo` class to calculate the effective height of tremolo strokes, that is, the height the strokes spread across a given vertical line, without multiplying `spatium()`, to resolve an issue of stem length (a bit longer than intended when direction is down and has single-note tremolo on it) which is not obvious in normal size but obvious in cue size. Several places are already using this effective height, so a separate function for calculating it is really convenient to use. --- libmscore/chord.cpp | 10 +-- libmscore/tremolo.cpp | 146 ++++++++++++++++++++++-------------------- libmscore/tremolo.h | 2 + 3 files changed, 85 insertions(+), 73 deletions(-) diff --git a/libmscore/chord.cpp b/libmscore/chord.cpp index 22c2c4e0dd393..3f809892d3790 100644 --- a/libmscore/chord.cpp +++ b/libmscore/chord.cpp @@ -1513,8 +1513,8 @@ qreal Chord::minAbsStemLength() const return 0.0; } - const qreal sw = score()->styleS(Sid::tremoloStrokeWidth).val(); - const qreal td = score()->styleS(Sid::tremoloDistance).val(); + const qreal sw = score()->styleS(Sid::tremoloStrokeWidth).val() * mag(); + const qreal td = score()->styleS(Sid::tremoloDistance).val() * mag(); int beamLvl = beams(); const qreal beamDist = beam() ? beam()->beamDist() : (sw * spatium()); @@ -1530,20 +1530,20 @@ qreal Chord::minAbsStemLength() const if (up()) { height = (beam() ? upPos() : downPos()) - _tremolo->pos().y(); } else { - height = _tremolo->pos().y() + _tremolo->height() - (beam() ? downPos() : upPos()); + height = _tremolo->pos().y() + _tremolo->minHeight() * spatium() - (beam() ? downPos() : upPos()); } const bool hasHook = beamLvl && !beam(); if (hasHook) { beamLvl += (up() ? 4 : 2); // reserve more space for stem with both hook and tremolo } - const qreal additionalHeight = beamLvl ? 0 : sw* spatium(); + const qreal additionalHeight = beamLvl ? 0 : sw * spatium(); return height + beamLvl * beamDist + additionalHeight; } // two-note tremolo else { if (_tremolo->chord1()->up() == _tremolo->chord2()->up()) { - const qreal tremoloMinHeight = ((_tremolo->lines() - 1) * td + sw) * spatium(); + const qreal tremoloMinHeight = _tremolo->minHeight() * spatium(); return tremoloMinHeight + beamLvl * beamDist + 2 * td * spatium(); } return 0.0; diff --git a/libmscore/tremolo.cpp b/libmscore/tremolo.cpp index a6fcd728ee811..e11912646acc5 100644 --- a/libmscore/tremolo.cpp +++ b/libmscore/tremolo.cpp @@ -72,6 +72,17 @@ qreal Tremolo::mag() const return parent() ? parent()->mag() : 1.0; } +//--------------------------------------------------------- +// minHeight +//--------------------------------------------------------- + +qreal Tremolo::minHeight() const +{ + const qreal sw = score()->styleS(Sid::tremoloStrokeWidth).val() * mag(); + const qreal td = score()->styleS(Sid::tremoloDistance).val() * mag(); + return (lines() - 1) * td + sw; +} + //--------------------------------------------------------- // draw //--------------------------------------------------------- @@ -86,15 +97,16 @@ void Tremolo::draw(QPainter* painter) const painter->setPen(Qt::NoPen); painter->drawPath(path); } - if ((parent() == 0) && !twoNotes()) { + // for palette + if (!parent() && !twoNotes()) { qreal x = 0.0; // bbox().width() * .25; QPen pen(curColor(), point(score()->styleS(Sid::stemWidth))); painter->setPen(pen); - const qreal _spatium = spatium(); + const qreal sp = spatium(); if (_tremoloType == TremoloType::BUZZ_ROLL) { - painter->drawLine(QLineF(x, -_spatium, x, bbox().bottom() + _spatium)); + painter->drawLine(QLineF(x, -sp, x, bbox().bottom() + sp)); } else { - painter->drawLine(QLineF(x, -_spatium * .5, x, path.boundingRect().height() + _spatium)); + painter->drawLine(QLineF(x, -sp * .5, x, path.boundingRect().height() + sp)); } } } @@ -179,7 +191,7 @@ QPainterPath Tremolo::basePath() const return QPainterPath(); } - const qreal _spatium = spatium(); + const qreal _spatium = spatium() * mag(); qreal w2 = _spatium * score()->styleS(Sid::tremoloWidth).val() * .5; qreal lw = _spatium * score()->styleS(Sid::tremoloStrokeWidth).val(); @@ -228,7 +240,7 @@ void Tremolo::computeShape() // layoutOneNoteTremolo //--------------------------------------------------------- -void Tremolo::layoutOneNoteTremolo(qreal x, qreal y, qreal _spatium) +void Tremolo::layoutOneNoteTremolo(qreal x, qreal y, qreal spatium) { Q_ASSERT(!twoNotes()); @@ -236,22 +248,19 @@ void Tremolo::layoutOneNoteTremolo(qreal x, qreal y, qreal _spatium) int line = up ? chord()->upLine() : chord()->downLine(); if (!placeMidStem()) { - const qreal td = score()->styleS(Sid::tremoloDistance).val(); - const qreal sw = score()->styleS(Sid::tremoloStrokeWidth).val(); - qreal t = 0.0; // nearest distance between note and tremolo stroke should be no less than 3.0 if (chord()->hook() || chord()->beam()) { - t = up ? -3.0 - (2.0 * (lines() - 1)) * td - 2.0 * sw : 3.0; + t = up ? -3.0 - 2.0 * minHeight() : 3.0; } else { if (!up && !(line & 1)) { // stem is down; even line - t = qMax(6.0 - (2.0 * (lines() - 1)) * td - 2.0 * sw, 3.0); + t = qMax(6.0 - 2.0 * minHeight(), 3.0); } else if (!up && (line & 1)) { // stem is down; odd line - t = qMax(5.0 - (2.0 * (lines() - 1)) * td - 2.0 * sw, 3.0); + t = qMax(5.0 - 2.0 * minHeight(), 3.0); } else if (up && !(line & 1)) { // stem is up; even line - t = qMin(-3.0 - (2.0 * (lines() - 1)) * td - 2.0 * sw, -6.0); + t = qMin(-3.0 - 2.0 * minHeight(), -6.0); } else { /*if ( up && (line & 1))*/ // stem is up; odd line - t = qMin(-3.0 - (2.0 * (lines() - 1)) * td - 2.0 * sw, -5.0); + t = qMin(-3.0 - 2.0 * minHeight(), -5.0); } } @@ -262,16 +271,16 @@ void Tremolo::layoutOneNoteTremolo(qreal x, qreal y, qreal _spatium) } // prevent stroke from going out of staff at the bottom while stem direction is up else { - yLine = qMin(yLine, (staff()->lines(tick()) - 1) * 2 - (2.0 * (lines() - 1)) * td - 2.0 * sw); + yLine = qMin(yLine, (staff()->lines(tick()) - 1) * 2 - 2.0 * minHeight()); } - y = yLine * .5 * _spatium; + y = yLine * .5 * spatium; } else { const Note* n = up ? chord()->downNote() : chord()->upNote(); const qreal noteBorder = n->y() + (up ? n->bbox().top() : n->bbox().bottom()); const Stem* stem = chord()->stem(); - const qreal stemLen = stem ? stem->height() : (3 * _spatium); + const qreal stemLen = stem ? stem->height() : (3 * spatium); const qreal stemY = stem ? (stem->y() + (up ? stem->bbox().bottom() : stem->bbox().top())) : noteBorder; const qreal stemNoteOverlap = std::max(0.0, (up ? 1.0 : -1.0) * (stemY - noteBorder)); @@ -303,7 +312,7 @@ void Tremolo::layoutOneNoteTremolo(qreal x, qreal y, qreal _spatium) y += (up ? 1 : -1) * stemBeamOverlap / 2; } else if (chord()->hook()) { - const qreal hookLvlHeight = 0.5 * _spatium; // TODO: avoid hardcoding this (how?) + const qreal hookLvlHeight = 0.5 * spatium; // TODO: avoid hardcoding this (how?) y += (up ? 1 : -1) * (chord()->beams() + 0.5) * hookLvlHeight; } } @@ -311,57 +320,13 @@ void Tremolo::layoutOneNoteTremolo(qreal x, qreal y, qreal _spatium) setPos(x, y); } -//--------------------------------------------------------- -// layout -//--------------------------------------------------------- - -void Tremolo::layout() -{ - const qreal _spatium = spatium(); - - path = basePath(); - - _chord1 = toChord(parent()); - if (!_chord1) { - // palette - if (_tremoloType != TremoloType::BUZZ_ROLL) { - const QRectF box = path.boundingRect(); - addbbox(QRectF(box.x(), box.bottom(), box.width(), _spatium)); - } - return; - } - - Note* anchor1 = _chord1->upNote(); - Stem* stem = _chord1->stem(); - qreal x, y, h; - if (stem) { - x = stem->pos().x(); - y = stem->pos().y(); - h = stem->stemLen(); - } else { - // center tremolo above note - x = anchor1->x() + anchor1->headWidth() * .5; - y = anchor1->y(); - h = 2.0 * _spatium + bbox().height(); - if (anchor1->line() > 4) { - h *= -1; - } - } - - if (twoNotes()) { - layoutTwoNotesTremolo(x, y, h, _spatium); - } else { - layoutOneNoteTremolo(x, y, _spatium); - } -} - extern std::pair extendedStemLenWithTwoNoteTremolo(Tremolo*, qreal, qreal); //--------------------------------------------------------- // layoutTwoNotesTremolo //--------------------------------------------------------- -void Tremolo::layoutTwoNotesTremolo(qreal x, qreal y, qreal h, qreal _spatium) +void Tremolo::layoutTwoNotesTremolo(qreal x, qreal y, qreal h, qreal spatium) { bool defaultStyle = (strokeStyle() == TremoloStrokeStyle::DEFAULT); @@ -414,7 +379,7 @@ void Tremolo::layoutTwoNotesTremolo(qreal x, qreal y, qreal h, qreal _spatium) y2 = _chord2->stemPos().y() - firstChordStaffY + extendedLen.second; } - qreal lw = _spatium * score()->styleS(Sid::tremoloStrokeWidth).val(); + qreal lw = spatium * score()->styleS(Sid::tremoloStrokeWidth).val(); if (_chord1->beams() == 0 && _chord2->beams() == 0) { // improve the case when one stem is up and another is down if (defaultStyle && _chord1->up() != _chord2->up() && !crossStaffBeamBetween()) { @@ -468,12 +433,12 @@ void Tremolo::layoutTwoNotesTremolo(qreal x, qreal y, qreal h, qreal _spatium) QTransform xScaleTransform; // TODO const qreal H_MULTIPLIER = score()->styleS(Sid::tremoloBeamLengthMultiplier).val(); const qreal H_MULTIPLIER = defaultStyle ? 0.62 : 1; - // TODO const qreal MAX_H_LENGTH = _spatium * score()->styleS(Sid::tremoloBeamLengthMultiplier).val(); - const qreal MAX_H_LENGTH = _spatium * 12.0; + // TODO const qreal MAX_H_LENGTH = spatium * score()->styleS(Sid::tremoloBeamLengthMultiplier).val(); + const qreal MAX_H_LENGTH = spatium * 12.0; qreal defaultLength = qMin(H_MULTIPLIER * (x2 - x1), MAX_H_LENGTH); qreal xScaleFactor = defaultStyle ? defaultLength : H_MULTIPLIER * (x2 - x1); - const qreal w2 = _spatium * score()->styleS(Sid::tremoloWidth).val() * .5; + const qreal w2 = spatium * score()->styleS(Sid::tremoloWidth).val() * .5; xScaleFactor /= (2.0 * w2); xScaleTransform.scale(xScaleFactor, 1.0); @@ -514,7 +479,7 @@ void Tremolo::layoutTwoNotesTremolo(qreal x, qreal y, qreal h, qreal _spatium) // 2. The chords are on different staves and the tremolo is between them. // The layout should be improved by extending both stems, so changes are not needed here. if (_chord1->up() != _chord2->up() && defaultStyle && !crossStaffBeamBetween()) { - dy = qMin(qMax(dy, -1.0 * _spatium / defaultLength * dx), 1.0 * _spatium / defaultLength * dx); + dy = qMin(qMax(dy, -1.0 * spatium / defaultLength * dx), 1.0 * spatium / defaultLength * dx); } qreal ds = dy / dx; shearTransform.shear(0.0, ds); @@ -524,6 +489,51 @@ void Tremolo::layoutTwoNotesTremolo(qreal x, qreal y, qreal h, qreal _spatium) setPos(x, y + beamYOffset); } +//--------------------------------------------------------- +// layout +//--------------------------------------------------------- + +void Tremolo::layout() +{ + const qreal _spatium = spatium(); + + path = basePath(); + + _chord1 = toChord(parent()); + if (!_chord1) { + // palette + if (_tremoloType != TremoloType::BUZZ_ROLL) { + const QRectF box = path.boundingRect(); + addbbox(QRectF(box.x(), box.bottom(), box.width(), _spatium)); + } + return; + } + + Note* anchor1 = _chord1->upNote(); + Stem* stem = _chord1->stem(); + qreal x, y, h; + if (stem) { + x = stem->pos().x(); + y = stem->pos().y(); + h = stem->stemLen(); + } else { + // center tremolo above note + x = anchor1->x() + anchor1->headWidth() * .5; + y = anchor1->y(); + h = 2.0 * _spatium + bbox().height(); + if (anchor1->line() > 4) { + h *= -1; + } + } + + if (twoNotes()) { + layoutTwoNotesTremolo(x, y, h, _spatium); + } else { + layoutOneNoteTremolo(x, y, _spatium); + } +} + + //--------------------------------------------------------- // crossStaffBeamBetween // Return true if tremolo is two-note cross-staff and beams between staves diff --git a/libmscore/tremolo.h b/libmscore/tremolo.h index d77e77740bdc8..e63bafd2a6f7c 100644 --- a/libmscore/tremolo.h +++ b/libmscore/tremolo.h @@ -75,6 +75,8 @@ class Tremolo final : public Element void setTremoloType(TremoloType t); TremoloType tremoloType() const { return _tremoloType; } + qreal minHeight() const; + qreal mag() const override; void draw(QPainter*) const override; void layout() override; From 01e8a76ccdd09c4db5950f0b5f7024f6bc618151 Mon Sep 17 00:00:00 2001 From: Howard-C Date: Tue, 28 Jul 2020 15:28:49 +0800 Subject: [PATCH 6/7] Slightly alter the positions of one-note tremolo strokes to make them look better --- libmscore/tremolo.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libmscore/tremolo.cpp b/libmscore/tremolo.cpp index e11912646acc5..f9ff45b22f145 100644 --- a/libmscore/tremolo.cpp +++ b/libmscore/tremolo.cpp @@ -253,14 +253,16 @@ void Tremolo::layoutOneNoteTremolo(qreal x, qreal y, qreal spatium) if (chord()->hook() || chord()->beam()) { t = up ? -3.0 - 2.0 * minHeight() : 3.0; } else { + const qreal offset = 2.0 * score()->styleS(Sid::tremoloStrokeWidth).val(); + if (!up && !(line & 1)) { // stem is down; even line - t = qMax(6.0 - 2.0 * minHeight(), 3.0); + t = qMax(4.0 + offset - 2.0 * minHeight(), 3.0); } else if (!up && (line & 1)) { // stem is down; odd line - t = qMax(5.0 - 2.0 * minHeight(), 3.0); + t = qMax(5.0 - 2.0 * minHeight(), 3.0); } else if (up && !(line & 1)) { // stem is up; even line - t = qMin(-3.0 - 2.0 * minHeight(), -6.0); + t = qMin(-3.0 - 2.0 * minHeight(), -4.0 - offset); } else { /*if ( up && (line & 1))*/ // stem is up; odd line - t = qMin(-3.0 - 2.0 * minHeight(), -5.0); + t = qMin(-3.0 - 2.0 * minHeight(), -5.0); } } From 04f0db72aacc80f57f0c9c3cc02e9075096da686 Mon Sep 17 00:00:00 2001 From: Howard-C Date: Tue, 28 Jul 2020 15:42:07 +0800 Subject: [PATCH 7/7] Adjust code style --- libmscore/chord.cpp | 2 +- libmscore/edit.cpp | 39 +++++++++++++++++++-------------------- libmscore/score.cpp | 17 +++++++++-------- libmscore/tremolo.cpp | 7 +++---- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/libmscore/chord.cpp b/libmscore/chord.cpp index 3f809892d3790..5a68e0718cc10 100644 --- a/libmscore/chord.cpp +++ b/libmscore/chord.cpp @@ -1536,7 +1536,7 @@ qreal Chord::minAbsStemLength() const if (hasHook) { beamLvl += (up() ? 4 : 2); // reserve more space for stem with both hook and tremolo } - const qreal additionalHeight = beamLvl ? 0 : sw * spatium(); + const qreal additionalHeight = beamLvl ? 0 : (sw * spatium()); return height + beamLvl * beamDist + additionalHeight; } diff --git a/libmscore/edit.cpp b/libmscore/edit.cpp index 3ecc765660368..bfef8a71912bd 100644 --- a/libmscore/edit.cpp +++ b/libmscore/edit.cpp @@ -812,26 +812,25 @@ void Score::cmdAddTimeSig(Measure* fm, int staffIdx, TimeSig* ts, bool local) return; } - auto getStaffIdxRange = [this, local, staffIdx](const Score* score) -> std::pair { - int startStaffIdx, endStaffIdx; - if (local) { - if (score == this) { - startStaffIdx = staffIdx; - endStaffIdx = startStaffIdx + 1; - } - else { - // TODO: get index for this score - qDebug("cmdAddTimeSig: unable to write local time signature change to linked score"); - startStaffIdx = 0; - endStaffIdx = 0; - } - } - else { - startStaffIdx = 0; - endStaffIdx = score->nstaves(); - } - return std::make_pair(startStaffIdx, endStaffIdx); - }; + auto getStaffIdxRange + = [this, local, staffIdx](const Score* score) -> std::pair { + int startStaffIdx, endStaffIdx; + if (local) { + if (score == this) { + startStaffIdx = staffIdx; + endStaffIdx = startStaffIdx + 1; + } else { + // TODO: get index for this score + qDebug("cmdAddTimeSig: unable to write local time signature change to linked score"); + startStaffIdx = 0; + endStaffIdx = 0; + } + } else { + startStaffIdx = 0; + endStaffIdx = score->nstaves(); + } + return std::make_pair(startStaffIdx, endStaffIdx); + }; if (ots && ots->sig() == ns && ots->stretch() == ts->stretch()) { // diff --git a/libmscore/score.cpp b/libmscore/score.cpp index e4356b4b0d67d..a28d860619d14 100644 --- a/libmscore/score.cpp +++ b/libmscore/score.cpp @@ -4329,14 +4329,15 @@ int Score::duration() //--------------------------------------------------------- int Score::durationWithoutRepeats() - { - masterScore()->setExpandRepeats(false); - const RepeatList& rl = repeatList(); - if (rl.empty()) - return 0; - const RepeatSegment* rs = rl.last(); - return lrint(utick2utime(rs->utick + rs->len())); - } +{ + masterScore()->setExpandRepeats(false); + const RepeatList& rl = repeatList(); + if (rl.empty()) { + return 0; + } + const RepeatSegment* rs = rl.last(); + return lrint(utick2utime(rs->utick + rs->len())); +} //--------------------------------------------------------- // createRehearsalMarkText diff --git a/libmscore/tremolo.cpp b/libmscore/tremolo.cpp index f9ff45b22f145..0c37313c2d88c 100644 --- a/libmscore/tremolo.cpp +++ b/libmscore/tremolo.cpp @@ -258,11 +258,11 @@ void Tremolo::layoutOneNoteTremolo(qreal x, qreal y, qreal spatium) if (!up && !(line & 1)) { // stem is down; even line t = qMax(4.0 + offset - 2.0 * minHeight(), 3.0); } else if (!up && (line & 1)) { // stem is down; odd line - t = qMax(5.0 - 2.0 * minHeight(), 3.0); + t = qMax(5.0 - 2.0 * minHeight(), 3.0); } else if (up && !(line & 1)) { // stem is up; even line - t = qMin(-3.0 - 2.0 * minHeight(), -4.0 - offset); + t = qMin(-3.0 - 2.0 * minHeight(), -4.0 - offset); } else { /*if ( up && (line & 1))*/ // stem is up; odd line - t = qMin(-3.0 - 2.0 * minHeight(), -5.0); + t = qMin(-3.0 - 2.0 * minHeight(), -5.0); } } @@ -535,7 +535,6 @@ void Tremolo::layout() } } - //--------------------------------------------------------- // crossStaffBeamBetween // Return true if tremolo is two-note cross-staff and beams between staves