From 46c28ab32418880a6fd876ce247adef1dd009af1 Mon Sep 17 00:00:00 2001 From: ajuncosa Date: Mon, 8 Jun 2026 18:27:24 +0200 Subject: [PATCH 1/5] Clean up small tie/slur fragments after masking --- src/engraving/rendering/score/masklayout.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/engraving/rendering/score/masklayout.cpp b/src/engraving/rendering/score/masklayout.cpp index 18c9b8a950915..35c1cfc15de00 100644 --- a/src/engraving/rendering/score/masklayout.cpp +++ b/src/engraving/rendering/score/masklayout.cpp @@ -430,13 +430,17 @@ void MaskLayout::computeSlurTieMasks(SlurTieSegment* slurTieSegment) slurTieShape.translate(-slurTiePos); // Use the mask's bbox to break the slur/tie only once, regardless of the mask elements in between: - RectF maskBbox = mask.bbox(); + Shape maskBbox = mask.bbox(); // Avoid the slur/tie line being partially masked (i.e. it should always be either fully "cut", // or not masked at all, so we extend the mask vertically to encompass the slur/tie's full height): maskBbox.adjust(0.0, slurTieShape.top() - mask.top(), 0.0, slurTieShape.bottom() - mask.bottom()); maskBbox.pad(maskPadding); + // If tiny tie/slur bits are left, just remove them: + const double minFragmentLength = 0.5 * spatium; + cleanupMask(slurTieShape, maskBbox, minFragmentLength); + slurTieSegment->mutldata()->setMask(maskBbox); } From 77131018c5c52fa31d93ef82ac5ce8931c2f3aac Mon Sep 17 00:00:00 2001 From: ajuncosa Date: Tue, 9 Jun 2026 19:56:39 +0200 Subject: [PATCH 2/5] Fix slurTie mask property read from XML --- src/engraving/rw/read500/tread.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engraving/rw/read500/tread.cpp b/src/engraving/rw/read500/tread.cpp index 53ea334f12555..f32b6c6b66522 100644 --- a/src/engraving/rw/read500/tread.cpp +++ b/src/engraving/rw/read500/tread.cpp @@ -3794,6 +3794,7 @@ bool TRead::readProperties(SlurTie* s, XmlReader& e, ReadContext& ctx) const AsciiStringView tag(e.name()); if (TRead::readProperty(s, tag, e, ctx, Pid::SLUR_DIRECTION)) { + } else if (TRead::readProperty(s, tag, e, ctx, Pid::MASK_SLURTIE)) { } else if (tag == "lineType") { s->setStyleType(static_cast(e.readInt())); } else if (tag == "SlurSegment" || tag == "TieSegment" || tag == "LaissezVibSegment" || tag == "PartialTieSegment" From ad19e12beed0f141b07b36153741d01a665e8cfc Mon Sep 17 00:00:00 2001 From: ajuncosa Date: Fri, 26 Jun 2026 14:24:55 +0200 Subject: [PATCH 3/5] Fix SlurAndTieSettings translation context from inspector to propertiespanel --- .../PropertiesPanel/notation/lines/SlurAndTieSettings.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/propertiespanel/qml/MuseScore/PropertiesPanel/notation/lines/SlurAndTieSettings.qml b/src/propertiespanel/qml/MuseScore/PropertiesPanel/notation/lines/SlurAndTieSettings.qml index 10504960ca7b6..05860f2a4e1a2 100644 --- a/src/propertiespanel/qml/MuseScore/PropertiesPanel/notation/lines/SlurAndTieSettings.qml +++ b/src/propertiespanel/qml/MuseScore/PropertiesPanel/notation/lines/SlurAndTieSettings.qml @@ -102,7 +102,7 @@ Column { FlatRadioButtonGroupPropertyView { id: maskSection - titleText: qsTrc("inspector", "Mask over clefs, key and time signatures") + titleText: qsTrc("propertiespanel", "Mask over clefs, key and time signatures") propertyItem: root.model ? root.model.maskSlurTie : null navigationPanel: root.navigationPanel @@ -110,9 +110,9 @@ Column { navigationRowStart: tiePlacementSection.navigationRowEnd + 1 model: [ - { text: qsTrc("inspector", "Auto"), value: CommonTypes.AUTO_ON_OFF_AUTO }, - { text: qsTrc("inspector", "On"), value: CommonTypes.AUTO_ON_OFF_ON }, - { text: qsTrc("inspector", "Off"), value: CommonTypes.AUTO_ON_OFF_OFF } + { text: qsTrc("propertiespanel", "Auto"), value: CommonTypes.AUTO_ON_OFF_AUTO }, + { text: qsTrc("propertiespanel", "On"), value: CommonTypes.AUTO_ON_OFF_ON }, + { text: qsTrc("propertiespanel", "Off"), value: CommonTypes.AUTO_ON_OFF_OFF } ] } From 2a9e3dd91fc97afb51c16036ee7f6dd8daec4e91 Mon Sep 17 00:00:00 2001 From: ajuncosa Date: Thu, 2 Jul 2026 15:58:01 +0200 Subject: [PATCH 4/5] Revert "Clean up small tie/slur fragments after masking" This reverts commit 3b90eb174a196b01d81976ea57a3e716cec52ec3. --- src/engraving/rendering/score/masklayout.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/engraving/rendering/score/masklayout.cpp b/src/engraving/rendering/score/masklayout.cpp index 35c1cfc15de00..18c9b8a950915 100644 --- a/src/engraving/rendering/score/masklayout.cpp +++ b/src/engraving/rendering/score/masklayout.cpp @@ -430,17 +430,13 @@ void MaskLayout::computeSlurTieMasks(SlurTieSegment* slurTieSegment) slurTieShape.translate(-slurTiePos); // Use the mask's bbox to break the slur/tie only once, regardless of the mask elements in between: - Shape maskBbox = mask.bbox(); + RectF maskBbox = mask.bbox(); // Avoid the slur/tie line being partially masked (i.e. it should always be either fully "cut", // or not masked at all, so we extend the mask vertically to encompass the slur/tie's full height): maskBbox.adjust(0.0, slurTieShape.top() - mask.top(), 0.0, slurTieShape.bottom() - mask.bottom()); maskBbox.pad(maskPadding); - // If tiny tie/slur bits are left, just remove them: - const double minFragmentLength = 0.5 * spatium; - cleanupMask(slurTieShape, maskBbox, minFragmentLength); - slurTieSegment->mutldata()->setMask(maskBbox); } From d0b6f5cfb58d4248554f4c504dd5f520f607f3d0 Mon Sep 17 00:00:00 2001 From: ajuncosa Date: Wed, 8 Jul 2026 11:51:24 +0200 Subject: [PATCH 5/5] Shorten slurs and ties when they would otherwise cross over an end-of-system clef --- .../rendering/score/slurtielayout.cpp | 25 +++++++++++++++++-- src/engraving/rendering/score/slurtielayout.h | 2 ++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/engraving/rendering/score/slurtielayout.cpp b/src/engraving/rendering/score/slurtielayout.cpp index 9235549a565c3..18f85896b7809 100644 --- a/src/engraving/rendering/score/slurtielayout.cpp +++ b/src/engraving/rendering/score/slurtielayout.cpp @@ -25,6 +25,7 @@ #include "dom/slur.h" #include "dom/chord.h" +#include "dom/clef.h" #include "dom/score.h" #include "dom/system.h" #include "dom/staff.h" @@ -268,7 +269,7 @@ SpannerSegment* SlurTieLayout::layoutSystem(Slur* item, System* system, LayoutCo } } - double endingX = outgoingPartialSlur ? measure->endingXForOpenEndedLines() : system->endingXForOpenEndedLines(); + double endingX = endingXForOpenEndedSlurTie(outgoingPartialSlur ? measure : system->lastMeasure(), item->startCR()->vStaffIdx()); p2 = PointF(endingX, y); // adjust for ties at the end of the system @@ -353,6 +354,26 @@ void SlurTieLayout::adjustSlurFloatingEndPointAngles(SlurSegment* slurSeg, Point } } +double SlurTieLayout::endingXForOpenEndedSlurTie(const Measure* measure, staff_idx_t staffIdx) +{ + double endingX = measure->endingXForOpenEndedLines(); + + const Segment* clefSeg = measure->findSegmentR(SegmentType::ClefTypes, measure->ticks()); + if (!clefSeg || !clefSeg->enabled()) { + return endingX; + } + + const Clef* clef = toClef(clefSeg->element(staff2track(staffIdx))); + if (!clef || !clef->addToSkyline()) { + return endingX; + } + + const double margin = clef->style().styleAbsolute(Sid::lineEndToBarlineDistance); + const double clefLeftX = measure->x() + clefSeg->x() + clef->ldata()->shape().translated(clef->pos()).left(); + + return std::min(endingX, clefLeftX - margin); +} + //--------------------------------------------------------- // slurPos // calculate position of start- and endpoint of slur @@ -1562,7 +1583,7 @@ TieSegment* SlurTieLayout::layoutTieFor(Tie* item, System* system) int segmentCount = sPos.system1 == sPos.system2 ? 1 : 2; if (segmentCount == 2) { - sPos.p2 = PointF(system->endingXForOpenEndedLines(), sPos.p1.y()); + sPos.p2 = PointF(endingXForOpenEndedSlurTie(system->lastMeasure(), item->startNote()->vStaffIdx()), sPos.p1.y()); } else { sPos.p2 = computeDefaultStartOrEndPoint(item, Grip::END); } diff --git a/src/engraving/rendering/score/slurtielayout.h b/src/engraving/rendering/score/slurtielayout.h index fd7b4caeda9d7..7448dbd688e88 100644 --- a/src/engraving/rendering/score/slurtielayout.h +++ b/src/engraving/rendering/score/slurtielayout.h @@ -95,6 +95,8 @@ class SlurTieLayout static bool isOverBeams(Slur* slur); static double computeShoulderHeight(SlurSegment* slurSeg, double slurLengthInSp, PointF shoulderOffset); + static double endingXForOpenEndedSlurTie(const Measure* measure, staff_idx_t staffIdx); + static bool tieSegmentShouldBeSkipped(const Tie* item); static void computeStartAndEndSystem(Tie* item, SlurTiePos& slurTiePos); static PointF computeDefaultStartOrEndPoint(const Tie* tie, Grip startOrEnd);