From 280d1b92c58eac26f59373a5d2eeb411446af591 Mon Sep 17 00:00:00 2001 From: pyonpyoco <60975353+pyonpyoco@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:30:14 +0900 Subject: [PATCH 1/5] Add T/t and P/p fingerings for fretboard diagrams --- src/engraving/dom/fret.cpp | 36 +++++++++++++++++++ src/engraving/dom/fret.h | 14 ++++++++ src/engraving/rendering/score/tlayout.cpp | 2 +- .../fretdiagrams/FretDiagramSettings.qml | 26 +++++++++----- .../fretdiagrams/fretdiagramsettingsmodel.cpp | 31 ++++++++++++++-- .../fretdiagrams/fretdiagramsettingsmodel.h | 4 ++- .../fretdiagrams/internal/fretcanvas.cpp | 3 +- 7 files changed, 102 insertions(+), 14 deletions(-) diff --git a/src/engraving/dom/fret.cpp b/src/engraving/dom/fret.cpp index c00b6d185d68f..ee2d379ac6a14 100644 --- a/src/engraving/dom/fret.cpp +++ b/src/engraving/dom/fret.cpp @@ -1320,6 +1320,42 @@ String FretDiagram::screenReaderInfo() const return res; } +int FretDiagram::fingeringFromChar(Char c) +{ + switch(c.unicode()){ + case '1': return int(FretDiagram::FingeringValue::ONE); + case '2': return int(FretDiagram::FingeringValue::TWO); + case '3': return int(FretDiagram::FingeringValue::THREE); + case '4': return int(FretDiagram::FingeringValue::FOUR); + case '5': return int(FretDiagram::FingeringValue::FIVE); + + case 'T': + case 't': + return int(FretDiagram::FingeringValue::THUMB); + + case 'P': + case 'p': + return int(FretDiagram::FingeringValue::PULGAR); + + default: + return int(FretDiagram::FingeringValue::NONE); + } +} + +String FretDiagram::fingeringToString(int v) +{ + if(v >= 1 && v <= 5) + return String::number(v); + + if(v == int(FretDiagram::FingeringValue::THUMB)) + return String("T"); + + if(v == int(FretDiagram::FingeringValue::PULGAR)) + return String("P"); + + return String(); +} + void FretDiagram::setFingering(std::vector v) { m_fingering = std::move(v); diff --git a/src/engraving/dom/fret.h b/src/engraving/dom/fret.h index d8a12b6674f90..f637be11a73bb 100644 --- a/src/engraving/dom/fret.h +++ b/src/engraving/dom/fret.h @@ -221,6 +221,20 @@ class FretDiagram final : public EngravingItem String accessibleInfo() const override; String screenReaderInfo() const override; + enum class FingeringValue : int { + NONE = 0, + ONE, + TWO, + THREE, + FOUR, + FIVE, + THUMB = 6, //T + PULGAR = 7 //P + }; + + static int fingeringFromChar(Char c); + static String fingeringToString(int v); + bool showFingering() const { return m_showFingering; } void setShowFingering(bool v) { m_showFingering = v; } const std::vector& fingering() const { return m_fingering; } diff --git a/src/engraving/rendering/score/tlayout.cpp b/src/engraving/rendering/score/tlayout.cpp index dfb9efa3eb8bd..13cf60c54e9ed 100644 --- a/src/engraving/rendering/score/tlayout.cpp +++ b/src/engraving/rendering/score/tlayout.cpp @@ -2469,7 +2469,7 @@ void TLayout::layoutFretDiagram(const FretDiagram* item, FretDiagram::LayoutData if (finger == 0) { continue; } - String fingerS = String::number(finger); + String fingerS = FretDiagram::fingeringToString(finger); double width = fontMetrics.width(fingerS); double digitHeight = fontMetrics.tightBoundingRect(fingerS).height(); double xOff = -0.5 * width; diff --git a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/FretDiagramSettings.qml b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/FretDiagramSettings.qml index 08bfac08159f0..eaa203602eac8 100644 --- a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/FretDiagramSettings.qml +++ b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/FretDiagramSettings.qml @@ -123,7 +123,7 @@ Item { required property int index property int string: repeater.count - index - 1 - property string finger: root.model ? root.model.fingerings[string] : 0 + property string finger: root.model ? root.model.displayFingerings[string] : 0 Layout.preferredWidth: 40 spacing: 8 @@ -150,16 +150,27 @@ Item { textHorizontalAlignment: Qt.AlignHCenter indeterminateText: '-' + isIndeterminate: { - const fingerInt = parseInt(repeaterItem.finger) - return isNaN(fingerInt) || fingerInt < 1 || fingerInt > 5 + const f = repeaterItem.finger + + if(!f || f.length === 0) + return true + + if(f === "T" || f === "P") + return false + + const v = parseInt(f) + return isNaN(v) || v < 1 || v > 5 + } currentText: isIndeterminate ? '' : repeaterItem.finger - validator: IntInputValidator { - top: 5 - bottom: 0 + validator: RegularExpressionValidator { regularExpression: /^[1-5TtPp]?$/ } + + onTextEdited: { + text = text.toUpperCase() } navigation.name: `Finger ${repeaterItem.string + 1} text input` @@ -167,8 +178,7 @@ Item { navigation.row: repeater.navigationRowStart + repeaterItem.index navigation.accessible.name: qsTrc("inspector", "Finger for string %1").arg(repeaterItem.string + 1) - onTextEditingFinished: function (newTextValue) { - var newFinger = parseInt(newTextValue) + onTextEditingFinished: function (newFinger) { if (root.model) { root.model.setFingering(repeaterItem.string, newFinger) } diff --git a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.cpp b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.cpp index 5bf4db8b67555..baf5fc4048d62 100644 --- a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.cpp +++ b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.cpp @@ -191,14 +191,39 @@ QStringList FretDiagramSettingsModel::fingerings() const return fingerings.split(','); } -void FretDiagramSettingsModel::setFingering(int string, int finger) +QStringList FretDiagramSettingsModel::displayFingerings() const { - finger = std::clamp(finger, 0, 5); + QStringList domList = fingerings(); + QStringList result; + + for (const QString& t : domList) { + bool ok = false; + int v = t.toInt(&ok); + if (!ok) { + v = int(mu::engraving::FretDiagram::FingeringValue::NONE); + } + + mu::engraving::String s = mu::engraving::FretDiagram::fingeringToString(v); + result << s.toQString(); + } + + return result; +} + +void FretDiagramSettingsModel::setFingering(int string, const QString& fingerText) +{ + + int fingerValue = int(mu::engraving::FretDiagram::FingeringValue::NONE); + + if(!fingerText.isEmpty()){ + mu::engraving::Char ch(fingerText[0].unicode()); + fingerValue = mu::engraving::FretDiagram::fingeringFromChar(ch); + } QStringList curFingerings = fingerings(); assert(string < curFingerings.size()); - QString newFinger = QString::number(finger); + QString newFinger = QString::number(fingerValue); curFingerings[string] = newFinger; QString newFingerings = curFingerings.join(","); diff --git a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.h b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.h index c863761f7aafb..05ec36d4f77ec 100644 --- a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.h +++ b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.h @@ -57,6 +57,7 @@ class FretDiagramSettingsModel : public AbstractInspectorModel Q_PROPERTY(QVariant fretDiagram READ fretDiagram NOTIFY fretDiagramChanged) Q_PROPERTY(mu::inspector::PropertyItem * showFingerings READ showFingerings CONSTANT) Q_PROPERTY(QStringList fingerings READ fingerings NOTIFY fingeringsChanged) + Q_PROPERTY(QStringList displayFingerings READ displayFingerings NOTIFY fretDiagramChanged) public: explicit FretDiagramSettingsModel(QObject* parent, const muse::modularity::ContextPtr& iocCtx, IElementRepositoryService* repository); @@ -76,8 +77,9 @@ class FretDiagramSettingsModel : public AbstractInspectorModel PropertyItem* verticalAlign() const; PropertyItem* showFingerings() const; QStringList fingerings() const; + QStringList displayFingerings() const; - Q_INVOKABLE void setFingering(int string, int finger); + Q_INVOKABLE void setFingering(int string, const QString& fingerText); Q_INVOKABLE void resetFingerings(); QVariant fretDiagram() const; diff --git a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/internal/fretcanvas.cpp b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/internal/fretcanvas.cpp index 29d7b57457d2c..1b6f938a868e4 100644 --- a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/internal/fretcanvas.cpp +++ b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/internal/fretcanvas.cpp @@ -204,7 +204,8 @@ void FretCanvas::draw(QPainter* painter) if (finger == 0) { continue; } - QString fingerS = QString::number(finger); + String fs = mu::engraving::FretDiagram::fingeringToString(finger); + QString fingerS = fs.toQString(); double width = fontMetrics.width(fingerS); double xOff = -0.5 * width; double fingerX = (m_diagram->strings() - i - 1) * stringDist + xOff; From dc7b9cb069cccc0ea92af60c66da6ba45700660a Mon Sep 17 00:00:00 2001 From: pyonpyoco <60975353+pyonpyoco@users.noreply.github.com> Date: Fri, 12 Dec 2025 22:10:43 +0900 Subject: [PATCH 2/5] Apply Uncrustify formatting --- src/engraving/dom/fret.cpp | 41 ++++++++++--------- src/engraving/dom/fret.h | 2 +- .../fretdiagrams/fretdiagramsettingsmodel.cpp | 3 +- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/engraving/dom/fret.cpp b/src/engraving/dom/fret.cpp index ee2d379ac6a14..65a26baa52f7b 100644 --- a/src/engraving/dom/fret.cpp +++ b/src/engraving/dom/fret.cpp @@ -1322,37 +1322,40 @@ String FretDiagram::screenReaderInfo() const int FretDiagram::fingeringFromChar(Char c) { - switch(c.unicode()){ - case '1': return int(FretDiagram::FingeringValue::ONE); - case '2': return int(FretDiagram::FingeringValue::TWO); - case '3': return int(FretDiagram::FingeringValue::THREE); - case '4': return int(FretDiagram::FingeringValue::FOUR); - case '5': return int(FretDiagram::FingeringValue::FIVE); + switch (c.unicode()) { + case '1': return int(FretDiagram::FingeringValue::ONE); + case '2': return int(FretDiagram::FingeringValue::TWO); + case '3': return int(FretDiagram::FingeringValue::THREE); + case '4': return int(FretDiagram::FingeringValue::FOUR); + case '5': return int(FretDiagram::FingeringValue::FIVE); - case 'T': - case 't': - return int(FretDiagram::FingeringValue::THUMB); + case 'T': + case 't': + return int(FretDiagram::FingeringValue::THUMB); - case 'P': - case 'p': - return int(FretDiagram::FingeringValue::PULGAR); + case 'P': + case 'p': + return int(FretDiagram::FingeringValue::PULGAR); - default: - return int(FretDiagram::FingeringValue::NONE); + default: + return int(FretDiagram::FingeringValue::NONE); } } String FretDiagram::fingeringToString(int v) { - if(v >= 1 && v <= 5) + if (v >= 1 && v <= 5) { return String::number(v); - - if(v == int(FretDiagram::FingeringValue::THUMB)) + } + + if (v == int(FretDiagram::FingeringValue::THUMB)) { return String("T"); + } - if(v == int(FretDiagram::FingeringValue::PULGAR)) + if (v == int(FretDiagram::FingeringValue::PULGAR)) { return String("P"); - + } + return String(); } diff --git a/src/engraving/dom/fret.h b/src/engraving/dom/fret.h index f637be11a73bb..14ee0163515db 100644 --- a/src/engraving/dom/fret.h +++ b/src/engraving/dom/fret.h @@ -234,7 +234,7 @@ class FretDiagram final : public EngravingItem static int fingeringFromChar(Char c); static String fingeringToString(int v); - + bool showFingering() const { return m_showFingering; } void setShowFingering(bool v) { m_showFingering = v; } const std::vector& fingering() const { return m_fingering; } diff --git a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.cpp b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.cpp index baf5fc4048d62..b1436f793944b 100644 --- a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.cpp +++ b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.cpp @@ -212,10 +212,9 @@ QStringList FretDiagramSettingsModel::displayFingerings() const void FretDiagramSettingsModel::setFingering(int string, const QString& fingerText) { - int fingerValue = int(mu::engraving::FretDiagram::FingeringValue::NONE); - if(!fingerText.isEmpty()){ + if (!fingerText.isEmpty()) { mu::engraving::Char ch(fingerText[0].unicode()); fingerValue = mu::engraving::FretDiagram::fingeringFromChar(ch); } From faa637d069a35ceb6c88127a5e0e5a24b6872549 Mon Sep 17 00:00:00 2001 From: pyonpyoco <60975353+pyonpyoco@users.noreply.github.com> Date: Fri, 12 Dec 2025 22:13:40 +0900 Subject: [PATCH 3/5] Use UTF-16 string literals for thumb/pulgar fingering --- src/engraving/dom/fret.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engraving/dom/fret.cpp b/src/engraving/dom/fret.cpp index 65a26baa52f7b..9bc97441b1e96 100644 --- a/src/engraving/dom/fret.cpp +++ b/src/engraving/dom/fret.cpp @@ -1349,11 +1349,11 @@ String FretDiagram::fingeringToString(int v) } if (v == int(FretDiagram::FingeringValue::THUMB)) { - return String("T"); + return String(u"T"); } if (v == int(FretDiagram::FingeringValue::PULGAR)) { - return String("P"); + return String(u"P"); } return String(); From 75c969569245f1ddebdcbc81fb10370e928a05be Mon Sep 17 00:00:00 2001 From: pyonpyoco <60975353+pyonpyoco@users.noreply.github.com> Date: Wed, 25 Mar 2026 23:28:07 +0900 Subject: [PATCH 4/5] Omit T/P fretboard fingerings from legacy fretFingering output --- src/engraving/rw/read460/tread.cpp | 18 +++++++++++++++++- src/engraving/rw/write/twrite.cpp | 16 ++++++++++++++-- .../fretdiagrams/fretdiagramsettingsmodel.h | 2 +- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/engraving/rw/read460/tread.cpp b/src/engraving/rw/read460/tread.cpp index addd77a273c31..15e71bda90f1b 100644 --- a/src/engraving/rw/read460/tread.cpp +++ b/src/engraving/rw/read460/tread.cpp @@ -805,6 +805,11 @@ void TRead::read(Expression* expr, XmlReader& xml, ReadContext& ctx) void TRead::read(FretDiagram* d, XmlReader& e, ReadContext& ctx) { + std::vector legacyFingering; + std::vector fullFingering; + bool hasLegacyFingering = false; + bool hasFullFingering = false; + while (e.readNextStartElement()) { const AsciiStringView tag(e.name()); @@ -862,12 +867,23 @@ void TRead::read(FretDiagram* d, XmlReader& e, ReadContext& ctx) d->add(h); } } else if (readProperty(d, tag, e, ctx, Pid::FRET_SHOW_FINGERINGS)) { - } else if (readProperty(d, tag, e, ctx, Pid::FRET_FINGERING)) { + } else if (tag == "fretFingeringEx"){ + fullFingering = TConv::fromXml(e.readText(), std::vector()); + hasFullFingering = true; + } else if (tag == "fretFingering") { + legacyFingering = TConv::fromXml(e.readText(), std::vector()); + hasLegacyFingering = true; } else if (TRead::readProperty(d, tag, e, ctx, Pid::EXCLUDE_VERTICAL_ALIGN)) { } else if (!readItemProperties(d, e, ctx)) { e.unknown(); } } + + if(hasFullFingering) { + d->setFingering(fullFingering); + } else if (hasLegacyFingering) { + d->setFingering(legacyFingering); + } } void TRead::read(TremoloBar* b, XmlReader& e, ReadContext& ctx) diff --git a/src/engraving/rw/write/twrite.cpp b/src/engraving/rw/write/twrite.cpp index 0f94f266d02fc..1e0c08b88698b 100644 --- a/src/engraving/rw/write/twrite.cpp +++ b/src/engraving/rw/write/twrite.cpp @@ -1442,7 +1442,7 @@ void TWrite::write(const FretDiagram* item, XmlWriter& xml, WriteContext& ctx) } xml.startElement(item); - static const std::array pids { { + static const std::array pids { { Pid::MIN_DISTANCE, Pid::FRET_OFFSET, Pid::FRET_FRETS, @@ -1451,7 +1451,6 @@ void TWrite::write(const FretDiagram* item, XmlWriter& xml, WriteContext& ctx) Pid::MAG, Pid::ORIENTATION, Pid::FRET_SHOW_FINGERINGS, - Pid::FRET_FINGERING, Pid::EXCLUDE_VERTICAL_ALIGN } }; @@ -1459,6 +1458,19 @@ void TWrite::write(const FretDiagram* item, XmlWriter& xml, WriteContext& ctx) for (Pid p : pids) { writeProperty(item, xml, p); } + + const std::vector& fullFingering = item->fingering(); + std::vector legacyFingering = fullFingering; + + for (int& v: legacyFingering){ + if(v == 6 || v == 7){ + v = 0; + } + } + + xml.tag("fretFingering", TConv::toXml(legacyFingering)); + xml.tag("fretFingeringEx", TConv::toXml(fullFingering)); + writeItemProperties(item, xml, ctx); if (item->harmony()) { diff --git a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.h b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.h index 05ec36d4f77ec..f98780f989caf 100644 --- a/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.h +++ b/src/inspector/qml/MuseScore/Inspector/notation/fretdiagrams/fretdiagramsettingsmodel.h @@ -57,7 +57,7 @@ class FretDiagramSettingsModel : public AbstractInspectorModel Q_PROPERTY(QVariant fretDiagram READ fretDiagram NOTIFY fretDiagramChanged) Q_PROPERTY(mu::inspector::PropertyItem * showFingerings READ showFingerings CONSTANT) Q_PROPERTY(QStringList fingerings READ fingerings NOTIFY fingeringsChanged) - Q_PROPERTY(QStringList displayFingerings READ displayFingerings NOTIFY fretDiagramChanged) + Q_PROPERTY(QStringList displayFingerings READ displayFingerings NOTIFY fingeringsChanged) public: explicit FretDiagramSettingsModel(QObject* parent, const muse::modularity::ContextPtr& iocCtx, IElementRepositoryService* repository); From 2ea98f91c04b5d5a7134040ae2a0121021e27006 Mon Sep 17 00:00:00 2001 From: pyonpyoco <60975353+pyonpyoco@users.noreply.github.com> Date: Wed, 25 Mar 2026 23:35:50 +0900 Subject: [PATCH 5/5] Apply Uncrustify formatting --- src/engraving/rw/read460/tread.cpp | 4 ++-- src/engraving/rw/write/twrite.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engraving/rw/read460/tread.cpp b/src/engraving/rw/read460/tread.cpp index 15e71bda90f1b..83da13e1ef740 100644 --- a/src/engraving/rw/read460/tread.cpp +++ b/src/engraving/rw/read460/tread.cpp @@ -867,7 +867,7 @@ void TRead::read(FretDiagram* d, XmlReader& e, ReadContext& ctx) d->add(h); } } else if (readProperty(d, tag, e, ctx, Pid::FRET_SHOW_FINGERINGS)) { - } else if (tag == "fretFingeringEx"){ + } else if (tag == "fretFingeringEx") { fullFingering = TConv::fromXml(e.readText(), std::vector()); hasFullFingering = true; } else if (tag == "fretFingering") { @@ -879,7 +879,7 @@ void TRead::read(FretDiagram* d, XmlReader& e, ReadContext& ctx) } } - if(hasFullFingering) { + if (hasFullFingering) { d->setFingering(fullFingering); } else if (hasLegacyFingering) { d->setFingering(legacyFingering); diff --git a/src/engraving/rw/write/twrite.cpp b/src/engraving/rw/write/twrite.cpp index 1e0c08b88698b..06483b7076649 100644 --- a/src/engraving/rw/write/twrite.cpp +++ b/src/engraving/rw/write/twrite.cpp @@ -1462,8 +1462,8 @@ void TWrite::write(const FretDiagram* item, XmlWriter& xml, WriteContext& ctx) const std::vector& fullFingering = item->fingering(); std::vector legacyFingering = fullFingering; - for (int& v: legacyFingering){ - if(v == 6 || v == 7){ + for (int& v: legacyFingering) { + if (v == 6 || v == 7) { v = 0; } }