From 563cd5d76d7a683d3210d63e29ba6c8ad139d2e0 Mon Sep 17 00:00:00 2001 From: Marc Sabatella Date: Sat, 19 Oct 2019 08:36:08 -0600 Subject: [PATCH] fix #273256, fix #273266: special characters dialog fixes A number of small issues prevent the special characters dialog from working properly, especially for chord symbols. Drag and drop only works with some symbols because FSYMBOL was missing in the switch statements in dragdrop.cpp. Text elements can handle drop of FSYMBOL (which is why double-click works), but they weren't getting to chance during drag&drop. Fix was just adding those case statements. For Harmony objects, we also needed to add the handlers in acceptDrop() and drop() (the latter just passing through to TextBase). However, accidentals require special handling in Harmony::endEdit() in order to parse. Code was added recently to do this, but it didn't actually work (I suspect it did when written, but things changed between then and when it was merged). I rearranged the code in in Harmony::endEdit() a bit - and added comments to explain. Basically, setHarmony() needs to be called *after* the back-substitution (replacing flat with "b", sharp with "#"), but the back-substitution needs to happen after TextBase::endEdit() finalizes the text (actually, if it were possible to substitute before, that would be better, but do to the way the undo records are munged in TextBase::endEdit(), it seemed to dangerous to even try). Bottom line: I do the TextBase::endEdit(), then the back-substitution, then the setHarmony(). I needed to be sure to trigger a layout, which required a startCmd/endCmd pair (since TextBase::endEdit() already called endCmd). --- libmscore/harmony.cpp | 80 +++++++++++++++++++++++++++++++++---------- mscore/dragdrop.cpp | 2 ++ 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/libmscore/harmony.cpp b/libmscore/harmony.cpp index 9acce6e54a76e..cc5297e706561 100644 --- a/libmscore/harmony.cpp +++ b/libmscore/harmony.cpp @@ -634,17 +634,17 @@ const ChordDescription* Harmony::parseHarmony(const QString& ss, int* root, int* bool useLiteral = false; if (ss.endsWith(' ')) useLiteral = true; - QString s = ss.simplified(); if (_harmonyType == HarmonyType::ROMAN) { - _userName = s; - _textName = s; + _userName = ss; + _textName = ss; *root = Tpc::TPC_INVALID; *base = Tpc::TPC_INVALID; return 0; } // pre-process for parentheses + QString s = ss.simplified(); if ((_leftParen = s.startsWith('('))) s.remove(0,1); if ((_rightParen = (s.endsWith(')') && s.count('(') < s.count(')')))) @@ -789,22 +789,50 @@ bool Harmony::edit(EditData& ed) void Harmony::endEdit(EditData& ed) { - // render to layout as chord symbol - setHarmony(plainText()); - // disable spell check - showSpell = false; + // complete editing: generate xml text, set Pid::TEXT, perform initial layout + // if text has changed, this also triggers setHarmony() which renders chord symbol + // but any rendering or layout performed here is tenative, + // we may still need to substitute special characters, + // and that cannot be until after editing is completed + TextBase::endEdit(ed); + + // get plain text + QString s = plainText(); + + // if user explicitly added symbols to the text, + // convert them back to their respective replacement texts + if (harmonyType() != HarmonyType::ROMAN) { + s.replace("\u1d12b", "bb"); // double-flat + s.replace("\u266d", "b"); // flat + s.replace("\ue260", "b"); // flat + // do not replace natural sign + // (right now adding the symbol explicitly is the only way to force a natural sign to appear at all) + //s.replace("\u266e", "n"); // natural, if one day we support that too + //s.replace("\ue261", "n"); // natural, if one day we support that too + s.replace("\u266f", "#"); // sharp + s.replace("\ue262", "#"); // sharp + s.replace("\u1d12a", "x"); // double-sharp + s.replace("\u0394", "^"); // Δ + s.replace("\u00d0", "o"); // ° + s.replace("\u00f8", "0"); // ø + s.replace("\u00d8", "0"); // Ø + } + else { + s.replace("\ue260", "\u266d"); // flat + s.replace("\ue261", "\u266e"); // natural + s.replace("\ue262", "\u266f"); // sharp + } - _userName.replace("\u1d12b", "bb"); // double-flat - _userName.replace("\u266d", "b"); // flat - //_userName.replace("\u266e", "n"); // natural, if one day we support that too - _userName.replace("\u266f", "#"); // sharp - _userName.replace("\u1d12a", "x"); // double-sharp - _userName.replace("\u0394", "t"); // Δ - _userName.replace("\u00d0", "o"); // ° - _userName.replace("\u00f8", "0"); // ø - _userName.replace("\u00d8", "0"); // Ø + // render and layout chord symbol + // (needs to be done here if text hasn't changed, or redone if replacemens were performed above) + score()->startCmd(); + setHarmony(s); + layout1(); + triggerLayout(); + score()->endCmd(); - TextBase::endEdit(ed); // layout happens here + // disable spell check + showSpell = false; if (links()) { for (ScoreElement* e : *links()) { @@ -1731,7 +1759,18 @@ QString Harmony::screenReaderInfo() const bool Harmony::acceptDrop(EditData& data) const { - return data.dropElement->isFretDiagram(); + Element* e = data.dropElement; + if (e->isFretDiagram()) { + return true; + } + else if (e->isSymbol() || e->isFSymbol()) { + // symbols can be added in edit mode + if (data.getData(this)) + return true; + else + return false; + } + return false; } //--------------------------------------------------------- @@ -1747,6 +1786,11 @@ Element* Harmony::drop(EditData& data) fd->setTrack(track()); score()->undoAddElement(fd); } + else if (e->isSymbol() || e->isFSymbol()) { + TextBase::drop(data); + layout1(); + e = 0; // cannot select + } else { qWarning("Harmony: cannot drop <%s>\n", e->name()); delete e; diff --git a/mscore/dragdrop.cpp b/mscore/dragdrop.cpp index 6ea655f1860dd..069f97540b653 100644 --- a/mscore/dragdrop.cpp +++ b/mscore/dragdrop.cpp @@ -371,6 +371,7 @@ void ScoreView::dragMoveEvent(QDragMoveEvent* event) break; case ElementType::IMAGE: case ElementType::SYMBOL: + case ElementType::FSYMBOL: case ElementType::DYNAMIC: case ElementType::KEYSIG: case ElementType::CLEF: @@ -465,6 +466,7 @@ void ScoreView::dropEvent(QDropEvent* event) } break; case ElementType::SYMBOL: + case ElementType::FSYMBOL: case ElementType::IMAGE: applyUserOffset = true; // fall-thru