From df08eae6ba4440cb807627da4c03194561bebfb9 Mon Sep 17 00:00:00 2001
From: David Faure <faure@kde.org>
Date: Wed, 25 Mar 2026 23:42:00 +0100
Subject: [PATCH] Fix tuplet bracket lost when beaming across a tuplet boundary

When beaming an 8th note with a triplet of 16ths (Ctrl+B), the
tuplet bracket ("3") disappeared because applyTuplingLine() spanned
the bracket over the entire mixed group, including the non-tupled
8th note which lacks tuplet properties.

Narrow the bracket endpoints in applyTuplingLine() to only span
events that are actually GROUP_TYPE_TUPLED, so the bracket correctly
covers just the triplet notes.
---
 src/gui/editors/notation/NotationGroup.cpp | 29 ++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/src/gui/editors/notation/NotationGroup.cpp b/src/gui/editors/notation/NotationGroup.cpp
index 63c17059a..0c05b874c 100644
--- a/src/gui/editors/notation/NotationGroup.cpp
+++ b/src/gui/editors/notation/NotationGroup.cpp
@@ -858,6 +858,35 @@ NotationGroup::applyTuplingLine(NotationStaff &staff)
         initialElement(getInitialElement()),
         finalElement(getFinalElement());
 
+    // In a mixed group (beamed + tupled notes sharing a group ID),
+    // narrow the bracket to only span the tupled events.
+    for (NELIterator it = initialElement; ; ++it) {
+        std::string t;
+        if ((*it)->event()->get<String>(
+                BaseProperties::BEAMED_GROUP_TYPE, t) &&
+            t == BaseProperties::GROUP_TYPE_TUPLED) {
+            initialElement = it;
+            if (static_cast<NotationElement*>(*it)->isNote())
+                initialNote = it;
+            break;
+        }
+        if (it == finalElement)
+            return;  // no tupled event found
+    }
+    for (NELIterator it = finalElement; ; --it) {
+        std::string t;
+        if ((*it)->event()->get<String>(
+                BaseProperties::BEAMED_GROUP_TYPE, t) &&
+            t == BaseProperties::GROUP_TYPE_TUPLED) {
+            finalElement = it;
+            if (static_cast<NotationElement*>(*it)->isNote())
+                finalNote = it;
+            break;
+        }
+        if (it == initialElement)
+            break;
+    }
+
     NELIterator initialNoteOrRest(initialElement);
     NotationElement* initialNoteOrRestEl = static_cast<NotationElement*>(*initialNoteOrRest);
 
-- 
2.53.0

