diff --git a/src/appshell/view/notationpagemodel.cpp b/src/appshell/view/notationpagemodel.cpp index 51a34f8e0b67d..30e5075a72386 100644 --- a/src/appshell/view/notationpagemodel.cpp +++ b/src/appshell/view/notationpagemodel.cpp @@ -61,11 +61,11 @@ void NotationPageModel::init() }); extensionsProvider()->manifestListChanged().onNotify(this, [this]() { - updateExtensionsToolBarVisibility(); + scheduleUpdateExtensionsToolBarVisibility(); }); extensionsProvider()->manifestChanged().onReceive(this, [this](const muse::extensions::Manifest&) { - updateExtensionsToolBarVisibility(); + scheduleUpdateExtensionsToolBarVisibility(); }); brailleConfiguration()->braillePanelEnabledChanged().onNotify(this, [this]() { @@ -74,17 +74,17 @@ void NotationPageModel::init() onNotationChanged(); - updateDrumsetPanelVisibility(); - updatePercussionPanelVisibility(); - updateExtensionsToolBarVisibility(); + scheduleUpdateDrumsetPanelVisibility(); + scheduleUpdatePercussionPanelVisibility(); + scheduleUpdateExtensionsToolBarVisibility(); notationConfiguration()->useNewPercussionPanelChanged().onNotify(this, [this]() { - updateDrumsetPanelVisibility(); - updatePercussionPanelVisibility(); + scheduleUpdateDrumsetPanelVisibility(); + scheduleUpdatePercussionPanelVisibility(); }); notationConfiguration()->percussionPanelAutoShowModeChanged().onNotify(this, [this]() { - updatePercussionPanelVisibility(); + scheduleUpdatePercussionPanelVisibility(); }); } @@ -177,14 +177,14 @@ void NotationPageModel::onNotationChanged() INotationNoteInputPtr noteInput = notation->interaction()->noteInput(); noteInput->stateChanged().onNotify(this, [this]() { - updateDrumsetPanelVisibility(); - updatePercussionPanelVisibility(); + scheduleUpdateDrumsetPanelVisibility(); + scheduleUpdatePercussionPanelVisibility(); }); INotationInteractionPtr notationInteraction = notation->interaction(); notationInteraction->selectionChanged().onNotify(this, [this]() { - updateDrumsetPanelVisibility(); - updatePercussionPanelVisibility(); + scheduleUpdateDrumsetPanelVisibility(); + scheduleUpdatePercussionPanelVisibility(); }); } @@ -205,7 +205,22 @@ void NotationPageModel::toggleDock(const QString& name) dispatcher()->dispatch("dock-toggle", ActionData::make_arg1(name)); } -void NotationPageModel::updateDrumsetPanelVisibility() +void NotationPageModel::scheduleUpdateDrumsetPanelVisibility() +{ + if (m_updateDrumsetPanelVisibilityScheduled) { + return; + } + + m_updateDrumsetPanelVisibilityScheduled = true; + + //! NOTE: ensure we don't update it multiple times in succession + muse::async::Async::call(this, [this]() { + doUpdateDrumsetPanelVisibility(); + m_updateDrumsetPanelVisibilityScheduled = false; + }); +} + +void NotationPageModel::doUpdateDrumsetPanelVisibility() { TRACEFUNC; @@ -219,10 +234,7 @@ void NotationPageModel::updateDrumsetPanelVisibility() return; } - //! NOTE: ensure we don't dispatch it multiple times in succession - muse::async::Async::call(this, [=]() { - dispatcher()->dispatch("dock-set-open", ActionData::make_arg2(DRUMSET_PANEL_NAME, open)); - }); + dispatcher()->dispatch("dock-set-open", ActionData::make_arg2(DRUMSET_PANEL_NAME, open)); }; // This should never be open when the new percussion panel is in use... @@ -243,7 +255,22 @@ void NotationPageModel::updateDrumsetPanelVisibility() setDrumsetPanelOpen(shouldOpen); } -void NotationPageModel::updatePercussionPanelVisibility() +void NotationPageModel::scheduleUpdatePercussionPanelVisibility() +{ + if (m_updatePercussionPanelVisibilityScheduled) { + return; + } + + m_updatePercussionPanelVisibilityScheduled = true; + + //! NOTE: ensure we don't update it multiple times in succession + muse::async::Async::call(this, [this]() { + doUpdatePercussionPanelVisibility(); + m_updatePercussionPanelVisibilityScheduled = false; + }); +} + +void NotationPageModel::doUpdatePercussionPanelVisibility() { TRACEFUNC; @@ -259,10 +286,7 @@ void NotationPageModel::updatePercussionPanelVisibility() return; } - //! NOTE: ensure we don't dispatch it multiple times in succession - muse::async::Async::call(this, [=]() { - dispatcher()->dispatch("dock-set-open", ActionData::make_arg2(PERCUSSION_PANEL_NAME, open)); - }); + dispatcher()->dispatch("dock-set-open", ActionData::make_arg2(PERCUSSION_PANEL_NAME, open)); }; // This should never be open when the old drumset panel is in use... @@ -328,21 +352,35 @@ void NotationPageModel::updatePercussionPanelVisibility() setPercussionPanelOpen(true); } -void NotationPageModel::updateExtensionsToolBarVisibility() +void NotationPageModel::scheduleUpdateExtensionsToolBarVisibility() +{ + if (m_updateExtensionsToolBarVisibilityScheduled) { + return; + } + + m_updateExtensionsToolBarVisibilityScheduled = true; + + //! NOTE: ensure we don't update it multiple times in succession + muse::async::Async::call(this, [this]() { + doUpdateExtensionsToolBarVisibility(); + m_updateExtensionsToolBarVisibilityScheduled = false; + }); +} + +void NotationPageModel::doUpdateExtensionsToolBarVisibility() { const muse::dock::IDockWindow* window = dockWindowProvider()->window(); if (!window) { return; } - auto setExtensionsToolBarOpen = [this](bool open) { - //! NOTE: ensure we don't dispatch it multiple times in succession - muse::async::Async::call(this, [=]() { - dispatcher()->dispatch("dock-set-open", ActionData::make_arg2(EXTENSIONS_TOOLBAR_NAME, open)); - }); - }; + auto setExtensionsToolBarOpen = [this, window](bool open) { + if (open == window->isDockOpen(EXTENSIONS_TOOLBAR_NAME)) { + return; + } - bool noItems = true; + dispatcher()->dispatch("dock-set-open", ActionData::make_arg2(EXTENSIONS_TOOLBAR_NAME, open)); + }; muse::extensions::ManifestList enabledExtensions = extensionsProvider()->manifestList(muse::extensions::Filter::Enabled); for (const muse::extensions::Manifest& m : enabledExtensions) { @@ -351,9 +389,10 @@ void NotationPageModel::updateExtensionsToolBarVisibility() continue; } - noItems = false; + setExtensionsToolBarOpen(true); + return; } } - setExtensionsToolBarOpen(!noItems); + setExtensionsToolBarOpen(false); } diff --git a/src/appshell/view/notationpagemodel.h b/src/appshell/view/notationpagemodel.h index 6b3274941123a..99f462d829916 100644 --- a/src/appshell/view/notationpagemodel.h +++ b/src/appshell/view/notationpagemodel.h @@ -19,8 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef MU_APPSHELL_NOTATIONPAGEMODEL_H -#define MU_APPSHELL_NOTATIONPAGEMODEL_H +#pragma once #include @@ -89,10 +88,17 @@ class NotationPageModel : public QObject, public muse::Injectable, public muse:: void toggleDock(const QString& name); - void updateDrumsetPanelVisibility(); - void updatePercussionPanelVisibility(); - void updateExtensionsToolBarVisibility(); + void scheduleUpdateDrumsetPanelVisibility(); + void doUpdateDrumsetPanelVisibility(); + + void scheduleUpdatePercussionPanelVisibility(); + void doUpdatePercussionPanelVisibility(); + + void scheduleUpdateExtensionsToolBarVisibility(); + void doUpdateExtensionsToolBarVisibility(); + + bool m_updateDrumsetPanelVisibilityScheduled = false; + bool m_updatePercussionPanelVisibilityScheduled = false; + bool m_updateExtensionsToolBarVisibilityScheduled = false; }; } - -#endif // MU_APPSHELL_NOTATIONPAGEMODEL_H diff --git a/src/engraving/dom/textedit.cpp b/src/engraving/dom/textedit.cpp index aad6d82ee8484..410692da8d9e2 100644 --- a/src/engraving/dom/textedit.cpp +++ b/src/engraving/dom/textedit.cpp @@ -198,6 +198,7 @@ void TextBase::endEdit(EditData& ed) undo->reopen(); if (newlyAdded) { score()->endCmd(true); // rollback the "add element" command + ted->deleteText = true; } else { score()->undoRemoveElement(this); commitText(); diff --git a/src/notation/internal/notationactioncontroller.cpp b/src/notation/internal/notationactioncontroller.cpp index a1920aacf82d7..97d8feec95ab0 100644 --- a/src/notation/internal/notationactioncontroller.cpp +++ b/src/notation/internal/notationactioncontroller.cpp @@ -2035,8 +2035,15 @@ void NotationActionController::navigateToTextElement(MoveDirection direction, bo currentNotationInteraction()->navigateToLyrics(direction, moveOnly); } else if (element->isHarmony()) { const Harmony* chordSymbol = editedChordSymbol(); + + // otherwise, chord symbol will be deleted when navigating away from it + const bool canPlay = chordSymbol && !chordSymbol->plainText().empty(); + currentNotationInteraction()->navigateToNearHarmony(direction, nearNoteOrRest); - playbackController()->playElements({ chordSymbol }); + + if (canPlay) { + playbackController()->playElements({ chordSymbol }); + } } else if (element->isFiguredBass()) { currentNotationInteraction()->navigateToNearFiguredBass(direction); } else { @@ -2053,8 +2060,15 @@ void NotationActionController::navigateToTextElementByFraction(const Fraction& f if (element->isHarmony()) { const Harmony* chordSymbol = editedChordSymbol(); + + // otherwise, chord symbol will be deleted when navigating away from it + const bool canPlay = chordSymbol && !chordSymbol->plainText().empty(); + currentNotationInteraction()->navigateToHarmony(fraction); - playbackController()->playElements({ chordSymbol }); + + if (canPlay) { + playbackController()->playElements({ chordSymbol }); + } } else if (element->isFiguredBass()) { currentNotationInteraction()->navigateToFiguredBass(fraction); } @@ -2069,8 +2083,15 @@ void NotationActionController::navigateToTextElementInNearMeasure(MoveDirection if (element->isHarmony()) { const Harmony* chordSymbol = editedChordSymbol(); + + // otherwise, chord symbol will be deleted when navigating away from it + const bool canPlay = chordSymbol && !chordSymbol->plainText().empty(); + currentNotationInteraction()->navigateToHarmonyInNearMeasure(direction); - playbackController()->playElements({ chordSymbol }); + + if (canPlay) { + playbackController()->playElements({ chordSymbol }); + } } else if (element->isFiguredBass()) { currentNotationInteraction()->navigateToFiguredBassInNearMeasure(direction); } diff --git a/src/notation/internal/notationinteraction.cpp b/src/notation/internal/notationinteraction.cpp index 974f029679566..c5487f172507d 100644 --- a/src/notation/internal/notationinteraction.cpp +++ b/src/notation/internal/notationinteraction.cpp @@ -7052,6 +7052,8 @@ void NotationInteraction::navigateToHarmonyInNearMeasure(MoveDirection direction track_idx_t track = harmony->track(); + doEndEditElement(); + mu::engraving::Harmony* nextHarmony = findHarmonyInSegment(segment, track, harmony->textStyleType()); if (!nextHarmony) { nextHarmony = createHarmony(segment, track, harmony->harmonyType()); @@ -7097,6 +7099,8 @@ void NotationInteraction::navigateToHarmony(const Fraction& ticks) segment = segment->next1(mu::engraving::SegmentType::ChordRest); } + doEndEditElement(); + startEdit(TranslatableString("undoableAction", "Navigate to chord symbol")); if (!segment || segment->tick() > newTick) { // no ChordRest segment at this tick @@ -7148,6 +7152,8 @@ void NotationInteraction::navigateToNearFiguredBass(MoveDirection direction) return; } + doEndEditElement(); + bool bNew = false; // add a (new) FB element, using chord duration as default duration mu::engraving::FiguredBass* fbNew = mu::engraving::FiguredBass::addFiguredBassToSegment(nextSegm, track, Fraction(0, 1), &bNew); @@ -7192,6 +7198,8 @@ void NotationInteraction::navigateToFiguredBassInNearMeasure(MoveDirection direc return; } + doEndEditElement(); + bool bNew = false; // add a (new) FB element, using chord duration as default duration mu::engraving::FiguredBass* fbNew = mu::engraving::FiguredBass::addFiguredBassToSegment(nextSegm, fb->track(), Fraction(0, 1), &bNew); @@ -7228,8 +7236,6 @@ void NotationInteraction::navigateToFiguredBass(const Fraction& ticks) } } - doEndEditElement(); - // look for a segment at this tick; if none, create one mu::engraving::Segment* nextSegm = segm; while (nextSegm && nextSegm->tick() < nextSegTick) { @@ -7244,6 +7250,8 @@ void NotationInteraction::navigateToFiguredBass(const Fraction& ticks) } } + doEndEditElement(); + startEdit(TranslatableString("undoableAction", "Navigate to figured bass")); bool bNew = false; @@ -7445,6 +7453,8 @@ void NotationInteraction::navigateToNearText(MoveDirection direction) } } + doEndEditElement(); + if (textEl) { // edit existing text TextBase* text = dynamic_cast(textEl);