From 60d9b722813d28d355aa8a30fccb9e9edf2a90e9 Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Tue, 10 Dec 2024 23:37:01 +0000 Subject: [PATCH 01/10] Percussion panel - escape to finish editing --- .../percussionpanel/percussionpanelmodel.cpp | 16 ++++++++++++++++ .../view/percussionpanel/percussionpanelmodel.h | 2 ++ 2 files changed, 18 insertions(+) diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.cpp b/src/notation/view/percussionpanel/percussionpanelmodel.cpp index f2741aaa57eb1..712ba4dce1bf6 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelmodel.cpp @@ -40,6 +40,7 @@ PercussionPanelModel::PercussionPanelModel(QObject* parent) : QObject(parent) { m_padListModel = new PercussionPanelPadListModel(this); + qApp->installEventFilter(this); } bool PercussionPanelModel::enabled() const @@ -265,6 +266,21 @@ void PercussionPanelModel::setUpConnections() }); } +bool PercussionPanelModel::eventFilter(QObject* watched, QEvent* event) +{ + // Finish editing on escape... + if (m_currentPanelMode != PanelMode::Mode::EDIT_LAYOUT || event->type() != QEvent::Type::ShortcutOverride) { + return QObject::eventFilter(watched, event); + } + QKeyEvent* keyEvent = dynamic_cast(event); + if (!keyEvent || keyEvent->key() != Qt::Key_Escape) { + return QObject::eventFilter(watched, event); + } + finishEditing(); + event->setAccepted(true); + return true; +} + void PercussionPanelModel::writePitch(int pitch) { INotationUndoStackPtr undoStack = notation()->undoStack(); diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.h b/src/notation/view/percussionpanel/percussionpanelmodel.h index ddc0d243083ed..3439fafc070fa 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.h +++ b/src/notation/view/percussionpanel/percussionpanelmodel.h @@ -102,6 +102,8 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus private: void setUpConnections(); + bool eventFilter(QObject* watched, QEvent* event) override; + void writePitch(int pitch); void playPitch(int pitch); From ea82362c0e31aed4d6744ea6d0e9cbf6c08b94e0 Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Wed, 11 Dec 2024 21:39:28 +0000 Subject: [PATCH 02/10] Percussion panel - various navigation fixes --- .../NotationScene/PercussionPanel.qml | 32 +++++++++++++++---- .../percussionpanel/percussionpanelmodel.cpp | 2 ++ .../percussionpanelpadlistmodel.cpp | 14 ++++++++ .../percussionpanelpadlistmodel.h | 3 ++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml b/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml index 3c78352cbd5b6..24f473ab18c4e 100644 --- a/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml +++ b/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml @@ -195,6 +195,18 @@ Item { // This variable ensures we stay within a given pad when tabbing back-and-forth between // "main" and "footer" controls property var currentPadNavigationIndex: [0, 0] + function onNavigationEvent(event) { + var navigationRow = gridPrv.currentPadNavigationIndex[0] + var navigationColumn = gridPrv.currentPadNavigationIndex[1] + + if (navigationRow >= padGrid.numRows || navigationColumn >= padGrid.numColumns) { + gridPrv.currentPadNavigationIndex = [0, 0] + } + + if (event.type === NavigationEvent.AboutActive) { + event.setData("controlIndex", gridPrv.currentPadNavigationIndex) + } + } } Layout.alignment: Qt.AlignTop @@ -217,9 +229,7 @@ Item { order: toolbar.navigationOrderEnd + 1 onNavigationEvent: function(event) { - if (event.type === NavigationEvent.AboutActive) { - event.setData("controlIndex", gridPrv.currentPadNavigationIndex) - } + gridPrv.onNavigationEvent(event) } } @@ -233,9 +243,7 @@ Item { enabled: percModel.currentPanelMode !== PanelMode.EDIT_LAYOUT onNavigationEvent: function(event) { - if (event.type === NavigationEvent.AboutActive) { - event.setData("controlIndex", gridPrv.currentPadNavigationIndex) - } + gridPrv.onNavigationEvent(event) } } @@ -275,6 +283,7 @@ Item { padGrid.swapOriginPad = pad padGrid.isKeyboardSwapActive = isKeyboardSwap padGrid.model.startPadSwap(index) + pad.padNavigation.requestActive() } onEndPadSwapRequested: { @@ -295,6 +304,17 @@ Item { } gridPrv.currentPadNavigationIndex = [pad.navigationRow, pad.navigationColumn] } + + Connections { + target: padGrid.model + + function onPadFocusRequested(padIndex) { + if (index !== padIndex) { + return + } + pad.padNavigation.requestActive() + } + } } states: [ diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.cpp b/src/notation/view/percussionpanel/percussionpanelmodel.cpp index 712ba4dce1bf6..91d5b5bb32b4d 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelmodel.cpp @@ -204,6 +204,7 @@ void PercussionPanelModel::finishEditing(bool discardChanges) if (inst->drumset() && updatedDrumset && *inst->drumset() == *updatedDrumset) { setCurrentPanelMode(m_panelModeToRestore); + m_padListModel->focusLastActivePad(); return; } @@ -214,6 +215,7 @@ void PercussionPanelModel::finishEditing(bool discardChanges) undoStack->commitChanges(); setCurrentPanelMode(m_panelModeToRestore); + m_padListModel->focusLastActivePad(); } void PercussionPanelModel::customizeKit() diff --git a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp index 62c6cf3fb9950..9f86924b68164 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp @@ -75,6 +75,9 @@ void PercussionPanelPadListModel::addEmptyRow() } emit layoutChanged(); emit numPadsChanged(); + + const int indexToFocus = numPads() - NUM_COLUMNS; + emit padFocusRequested(indexToFocus); } void PercussionPanelPadListModel::deleteRow(int row) @@ -119,6 +122,7 @@ void PercussionPanelPadListModel::endPadSwap(int endIndex) emit layoutChanged(); } m_padSwapStartIndex = -1; + emit padFocusRequested(endIndex); } void PercussionPanelPadListModel::setDrumset(const engraving::Drumset* drumset) @@ -182,6 +186,16 @@ mu::engraving::Drumset PercussionPanelPadListModel::constructDefaultLayout(const return defaultLayout; } +void PercussionPanelPadListModel::focusLastActivePad() +{ + for (int i = m_padModels.size() - 1; i >= 0; --i) { + if (m_padModels.at(i)) { + emit padFocusRequested(i); + return; + } + } +} + void PercussionPanelPadListModel::load() { beginResetModel(); diff --git a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h index ded78c397c204..b3e4b2e306824 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h +++ b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h @@ -71,12 +71,15 @@ class PercussionPanelPadListModel : public QAbstractListModel, public muse::asyn mu::engraving::Drumset constructDefaultLayout(const engraving::Drumset* templateDrumset) const; + void focusLastActivePad(); + muse::async::Notification hasActivePadsChanged() const { return m_hasActivePadsChanged; } muse::async::Channel padTriggered() const { return m_triggeredChannel; } signals: void numPadsChanged(); void rowIsEmptyChanged(int row, bool empty); + void padFocusRequested(int padIndex); //! NOTE: This won't work if it is called immediately before a layoutChange private: static constexpr int NUM_COLUMNS = 8; From 36cc850adc4cf2c59e8bb64ab47a429a01ae2a1c Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Wed, 11 Dec 2024 08:47:33 +0000 Subject: [PATCH 03/10] Percussion panel - copy change (Instrument names to Pad names) --- .../NotationScene/internal/PercussionPanelPad.qml | 4 ++-- .../internal/PercussionPanelPadContent.qml | 12 ++++++------ .../view/percussionpanel/percussionpanelmodel.cpp | 12 ++++++------ .../percussionpanel/percussionpanelpadlistmodel.cpp | 2 +- .../view/percussionpanel/percussionpanelpadmodel.cpp | 8 ++++---- .../view/percussionpanel/percussionpanelpadmodel.h | 10 +++++----- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPad.qml b/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPad.qml index fd1671b603119..d0d9e6c7dae26 100644 --- a/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPad.qml +++ b/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPad.qml @@ -88,7 +88,7 @@ DropArea { enabled: Boolean(root.padModel) || root.panelMode === PanelMode.EDIT_LAYOUT accessible.role: MUAccessible.Button - accessible.name: Boolean(root.padModel) ? root.padModel.instrumentName : qsTrc("notation", "Empty pad") + accessible.name: Boolean(root.padModel) ? root.padModel.padName : qsTrc("notation", "Empty pad") accessible.description: prv.accessibleDescription @@ -115,7 +115,7 @@ DropArea { enabled: Boolean(root.padModel) accessible.role: MUAccessible.Button - accessible.name: Boolean(root.padModel) ? root.padModel.instrumentName + " " + qsTrc("notation", "footer") : "" + accessible.name: Boolean(root.padModel) ? root.padModel.padName + " " + qsTrc("notation", "footer") : "" accessible.description: prv.accessibleDescription diff --git a/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPadContent.qml b/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPadContent.qml index 66f21e893df3b..cc5cf174b1dec 100644 --- a/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPadContent.qml +++ b/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPadContent.qml @@ -66,7 +66,7 @@ Column { } if (mouseArea.containsMouse && root.useNotationPreview) { - ui.tooltip.show(root, root.padModel.instrumentName) + ui.tooltip.show(root, root.padModel.padName) } else { ui.tooltip.hide(root) } @@ -74,7 +74,7 @@ Column { } Rectangle { - id: instrumentNameBackground + id: padNameBackground visible: !root.useNotationPreview anchors.fill: parent @@ -83,7 +83,7 @@ Column { } StyledTextLabel { - id: instrumentNameLabel + id: padNameLabel visible: !root.useNotationPreview @@ -94,7 +94,7 @@ Column { maximumLineCount: 4 font: ui.theme.bodyBoldFont - text: Boolean(root.padModel) ? root.padModel.instrumentName : "" + text: Boolean(root.padModel) ? root.padModel.padName : "" } PaintedEngravingItem { @@ -115,7 +115,7 @@ Column { name: "MOUSE_HOVERED" when: mouseArea.containsMouse && !mouseArea.pressed && !root.padSwapActive PropertyChanges { - target: instrumentNameBackground + target: padNameBackground color: Utils.colorWithAlpha(ui.theme.accentColor, ui.theme.buttonOpacityHover) } PropertyChanges { @@ -127,7 +127,7 @@ Column { name: "MOUSE_HIT" when: mouseArea.pressed || root.padSwapActive PropertyChanges { - target: instrumentNameBackground + target: padNameBackground color: Utils.colorWithAlpha(ui.theme.accentColor, ui.theme.buttonOpacityHit) } PropertyChanges { diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.cpp b/src/notation/view/percussionpanel/percussionpanelmodel.cpp index 91d5b5bb32b4d..5604bce2c44df 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelmodel.cpp @@ -27,7 +27,7 @@ #include "engraving/dom/factory.h" #include "engraving/dom/undo.h" -static const QString INSTRUMENT_NAMES_CODE("percussion-instrument-names"); +static const QString PAD_NAMES_CODE("percussion-pad-names"); static const QString NOTATION_PREVIEW_CODE("percussion-notation-preview"); static const QString EDIT_LAYOUT_CODE("percussion-edit-layout"); static const QString RESET_LAYOUT_CODE("percussion-reset-layout"); @@ -108,9 +108,9 @@ void PercussionPanelModel::init() QList PercussionPanelModel::layoutMenuItems() const { - const TranslatableString instrumentNamesTitle("notation", "Instrument names"); + const TranslatableString padNamesTitle("notation", "Pad names"); // Using IconCode for this instead of "checked" because we want the tick to display on the left - const int instrumentNamesIcon = static_cast(m_useNotationPreview ? IconCode::Code::NONE : IconCode::Code::TICK_RIGHT_ANGLE); + const int padNamesIcon = static_cast(m_useNotationPreview ? IconCode::Code::NONE : IconCode::Code::TICK_RIGHT_ANGLE); const TranslatableString notationPreviewTitle("notation", "Notation preview"); // Using IconCode for this instead of "checked" because we want the tick to display on the left @@ -125,8 +125,8 @@ QList PercussionPanelModel::layoutMenuItems() const const int resetLayoutIcon = static_cast(IconCode::Code::UNDO); QList menuItems = { - { { "id", INSTRUMENT_NAMES_CODE }, - { "title", instrumentNamesTitle.qTranslated() }, { "icon", instrumentNamesIcon }, { "enabled", true } }, + { { "id", PAD_NAMES_CODE }, + { "title", padNamesTitle.qTranslated() }, { "icon", padNamesIcon }, { "enabled", true } }, { { "id", NOTATION_PREVIEW_CODE }, { "title", notationPreviewTitle.qTranslated() }, { "icon", notationPreviewIcon }, { "enabled", true } }, @@ -145,7 +145,7 @@ QList PercussionPanelModel::layoutMenuItems() const void PercussionPanelModel::handleMenuItem(const QString& itemId) { - if (itemId == INSTRUMENT_NAMES_CODE) { + if (itemId == PAD_NAMES_CODE) { setUseNotationPreview(false); } else if (itemId == NOTATION_PREVIEW_CODE) { setUseNotationPreview(true); diff --git a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp index 9f86924b68164..f3fc57789e013 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp @@ -271,7 +271,7 @@ PercussionPanelPadModel* PercussionPanelPadListModel::createPadModelForPitch(int } PercussionPanelPadModel* model = new PercussionPanelPadModel(this); - model->setInstrumentName(m_drumset->name(pitch)); + model->setPadName(m_drumset->name(pitch)); const QString shortcut = m_drumset->shortcut(pitch) ? QChar(m_drumset->shortcut(pitch)) : QString("-"); model->setKeyboardShortcut(shortcut); diff --git a/src/notation/view/percussionpanel/percussionpanelpadmodel.cpp b/src/notation/view/percussionpanel/percussionpanelpadmodel.cpp index 64a62a1218982..7a3ea0e4601c7 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelpadmodel.cpp @@ -29,14 +29,14 @@ PercussionPanelPadModel::PercussionPanelPadModel(QObject* parent) { } -void PercussionPanelPadModel::setInstrumentName(const QString& instrumentName) +void PercussionPanelPadModel::setPadName(const QString& padName) { - if (m_instrumentName == instrumentName) { + if (m_padName == padName) { return; } - m_instrumentName = instrumentName; - emit instrumentNameChanged(); + m_padName = padName; + emit padNameChanged(); } void PercussionPanelPadModel::setKeyboardShortcut(const QString& keyboardShortcut) diff --git a/src/notation/view/percussionpanel/percussionpanelpadmodel.h b/src/notation/view/percussionpanel/percussionpanelpadmodel.h index f7be14c2124fd..1a6c0d7c44026 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadmodel.h +++ b/src/notation/view/percussionpanel/percussionpanelpadmodel.h @@ -36,7 +36,7 @@ class PercussionPanelPadModel : public QObject, public muse::async::Asyncable { Q_OBJECT - Q_PROPERTY(QString instrumentName READ instrumentName NOTIFY instrumentNameChanged) + Q_PROPERTY(QString padName READ padName NOTIFY padNameChanged) Q_PROPERTY(QString keyboardShortcut READ keyboardShortcut NOTIFY keyboardShortcutChanged) Q_PROPERTY(QString midiNote READ midiNote NOTIFY midiNoteChanged) @@ -46,8 +46,8 @@ class PercussionPanelPadModel : public QObject, public muse::async::Asyncable public: explicit PercussionPanelPadModel(QObject* parent = nullptr); - QString instrumentName() const { return m_instrumentName; } - void setInstrumentName(const QString& instrumentName); + QString padName() const { return m_padName; } + void setPadName(const QString& padName); QString keyboardShortcut() const { return m_keyboardShortcut; } void setKeyboardShortcut(const QString& keyboardShortcut); @@ -66,7 +66,7 @@ class PercussionPanelPadModel : public QObject, public muse::async::Asyncable muse::async::Notification padTriggered() const { return m_triggeredNotification; } signals: - void instrumentNameChanged(); + void padNameChanged(); void keyboardShortcutChanged(); void midiNoteChanged(); @@ -74,7 +74,7 @@ class PercussionPanelPadModel : public QObject, public muse::async::Asyncable void notationPreviewItemChanged(); private: - QString m_instrumentName; + QString m_padName; QString m_keyboardShortcut; int m_pitch = -1; From ab11c42780d46bed20500f79b6a255c090861d3a Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Tue, 17 Dec 2024 09:11:16 +0000 Subject: [PATCH 04/10] Don't always move focus to notation when entering note input --- src/context/internal/uicontextresolver.cpp | 2 +- src/notation/inotationnoteinput.h | 4 ++-- src/notation/internal/notationnoteinput.cpp | 10 +++++----- src/notation/internal/notationnoteinput.h | 8 ++++---- src/notation/view/abstractnotationpaintview.cpp | 17 +++++++++++------ 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/context/internal/uicontextresolver.cpp b/src/context/internal/uicontextresolver.cpp index 45be1775f7187..121e90efd4653 100644 --- a/src/context/internal/uicontextresolver.cpp +++ b/src/context/internal/uicontextresolver.cpp @@ -67,7 +67,7 @@ void UiContextResolver::init() notifyAboutContextChanged(); }); - notation->interaction()->noteInput()->noteInputStarted().onNotify(this, [this]() { + notation->interaction()->noteInput()->noteInputStarted().onReceive(this, [this](bool) { notifyAboutContextChanged(); }); diff --git a/src/notation/inotationnoteinput.h b/src/notation/inotationnoteinput.h index a9dd94b0c5ef2..3256bf1bcbf59 100644 --- a/src/notation/inotationnoteinput.h +++ b/src/notation/inotationnoteinput.h @@ -37,14 +37,14 @@ class INotationNoteInput virtual NoteInputState state() const = 0; - virtual void startNoteInput() = 0; + virtual void startNoteInput(bool focusNotation = true) = 0; virtual void endNoteInput(bool resetState = false) = 0; virtual void toggleNoteInputMethod(NoteInputMethod method) = 0; virtual void addNote(NoteName noteName, NoteAddingMode addingMode) = 0; virtual void padNote(const Pad& pad) = 0; virtual muse::Ret putNote(const muse::PointF& pos, bool replace, bool insert) = 0; virtual void removeNote(const muse::PointF& pos) = 0; - virtual muse::async::Notification noteInputStarted() const = 0; + virtual muse::async::Channel noteInputStarted() const = 0; virtual muse::async::Notification noteInputEnded() const = 0; virtual void addTuplet(const TupletOptions& options) = 0; diff --git a/src/notation/internal/notationnoteinput.cpp b/src/notation/internal/notationnoteinput.cpp index 9eb800603d5c4..576edd900525d 100644 --- a/src/notation/internal/notationnoteinput.cpp +++ b/src/notation/internal/notationnoteinput.cpp @@ -89,7 +89,7 @@ NoteInputState NotationNoteInput::state() const } //! NOTE Copied from `void ScoreView::startNoteEntry()` -void NotationNoteInput::startNoteInput() +void NotationNoteInput::startNoteInput(bool focusNotation) { TRACEFUNC; @@ -143,7 +143,7 @@ void NotationNoteInput::startNoteInput() break; } - notifyAboutNoteInputStarted(); + notifyAboutNoteInputStarted(focusNotation); notifyAboutStateChanged(); m_interaction->showItem(el); @@ -399,7 +399,7 @@ void NotationNoteInput::removeNote(const PointF& pos) MScoreErrorsController(iocContext()).checkAndShowMScoreError(); } -Notification NotationNoteInput::noteInputStarted() const +Channel NotationNoteInput::noteInputStarted() const { return m_noteInputStarted; } @@ -675,9 +675,9 @@ void NotationNoteInput::notifyNoteAddedChanged() m_noteAdded.notify(); } -void NotationNoteInput::notifyAboutNoteInputStarted() +void NotationNoteInput::notifyAboutNoteInputStarted(bool focusNotation) { - m_noteInputStarted.notify(); + m_noteInputStarted.send(focusNotation); } void NotationNoteInput::notifyAboutNoteInputEnded() diff --git a/src/notation/internal/notationnoteinput.h b/src/notation/internal/notationnoteinput.h index a8f3487fd8e75..075870b8a6108 100644 --- a/src/notation/internal/notationnoteinput.h +++ b/src/notation/internal/notationnoteinput.h @@ -51,14 +51,14 @@ class NotationNoteInput : public INotationNoteInput, public muse::Injectable, pu NoteInputState state() const override; - void startNoteInput() override; + void startNoteInput(bool focusNotation = true) override; void endNoteInput(bool resetState = false) override; void toggleNoteInputMethod(NoteInputMethod method) override; void addNote(NoteName noteName, NoteAddingMode addingMode) override; void padNote(const Pad& pad) override; muse::Ret putNote(const muse::PointF& pos, bool replace, bool insert) override; void removeNote(const muse::PointF& pos) override; - muse::async::Notification noteInputStarted() const override; + muse::async::Channel noteInputStarted() const override; muse::async::Notification noteInputEnded() const override; void addTuplet(const TupletOptions& options) override; @@ -95,7 +95,7 @@ class NotationNoteInput : public INotationNoteInput, public muse::Injectable, pu void updateInputState(); void notifyAboutStateChanged(); void notifyNoteAddedChanged(); - void notifyAboutNoteInputStarted(); + void notifyAboutNoteInputStarted(bool focusNotation = true); void notifyAboutNoteInputEnded(); std::set articulationIds() const; @@ -106,7 +106,7 @@ class NotationNoteInput : public INotationNoteInput, public muse::Injectable, pu muse::async::Notification m_stateChanged; muse::async::Notification m_noteAdded; - muse::async::Notification m_noteInputStarted; + muse::async::Channel m_noteInputStarted; muse::async::Notification m_noteInputEnded; ScoreCallbacks* m_scoreCallbacks = nullptr; diff --git a/src/notation/view/abstractnotationpaintview.cpp b/src/notation/view/abstractnotationpaintview.cpp index edd8c22f98ea3..a3f85d03e9a0a 100644 --- a/src/notation/view/abstractnotationpaintview.cpp +++ b/src/notation/view/abstractnotationpaintview.cpp @@ -248,10 +248,20 @@ void AbstractNotationPaintView::onLoadNotation(INotationPtr) }); onNoteInputStateChanged(); + if (isNoteEnterMode()) { + emit activeFocusRequested(); + } + interaction->noteInput()->stateChanged().onNotify(this, [this]() { onNoteInputStateChanged(); }); + interaction->noteInput()->noteInputStarted().onReceive(this, [this](bool focusNotation) { + if (focusNotation) { + emit activeFocusRequested(); + } + }); + interaction->selectionChanged().onNotify(this, [this]() { scheduleRedraw(); }); @@ -457,12 +467,7 @@ void AbstractNotationPaintView::onNoteInputStateChanged() { TRACEFUNC; - bool noteEnterMode = isNoteEnterMode(); - setAcceptHoverEvents(noteEnterMode); - - if (noteEnterMode) { - emit activeFocusRequested(); - } + setAcceptHoverEvents(isNoteEnterMode()); if (INotationInteractionPtr interaction = notationInteraction()) { interaction->hideShadowNote(); From 3dd2de230d985ed1041148df75cf995fd3e229b1 Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Tue, 17 Dec 2024 09:15:39 +0000 Subject: [PATCH 05/10] Percussion panel - keep focus in panel when starting note entry --- src/notation/view/percussionpanel/percussionpanelmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.cpp b/src/notation/view/percussionpanel/percussionpanelmodel.cpp index 5604bce2c44df..c0eac43865da3 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelmodel.cpp @@ -292,7 +292,7 @@ void PercussionPanelModel::writePitch(int pitch) undoStack->prepareChanges(muse::TranslatableString("undoableAction", "Enter percussion note")); - interaction()->noteInput()->startNoteInput(); + interaction()->noteInput()->startNoteInput(/*focusNotation*/ false); score()->addMidiPitch(pitch, false, /*transpose*/ false); undoStack->commitChanges(); From 749759866ecd412f304bc2d6ed52b7dfd84c3c21 Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Tue, 17 Dec 2024 15:05:13 +0000 Subject: [PATCH 06/10] Percussion panel - implement sound title label --- .../NotationScene/PercussionPanel.qml | 34 ++++++++- .../percussionpanel/percussionpanelmodel.cpp | 69 +++++++++++++++++++ .../percussionpanel/percussionpanelmodel.h | 14 ++++ src/project/internal/projectaudiosettings.cpp | 15 +++- src/project/internal/projectaudiosettings.h | 2 + src/project/iprojectaudiosettings.h | 1 + 6 files changed, 133 insertions(+), 2 deletions(-) diff --git a/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml b/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml index 24f473ab18c4e..381e6c6a8dd48 100644 --- a/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml +++ b/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml @@ -86,10 +86,42 @@ Item { panelWidth: root.width } + StyledIconLabel { + id: soundTitleIcon + + anchors.verticalCenter: soundTitleLabel.verticalCenter + anchors.right: soundTitleLabel.left + + anchors.rightMargin: 6 + + visible: percModel.enabled && !percModel.soundTitle.isEmpty + + color: ui.theme.fontPrimaryColor + + iconCode: IconCode.AUDIO + } + + StyledTextLabel { + id: soundTitleLabel + + anchors { + top: toolbar.bottom + right: parent.right + + topMargin: 8 + bottomMargin: 8 + rightMargin: 16 + } + + visible: percModel.enabled && !percModel.soundTitle.isEmpty + + text: percModel.soundTitle + } + StyledFlickable { id: flickable - anchors.top: toolbar.bottom + anchors.top: soundTitleLabel.bottom anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.cpp b/src/notation/view/percussionpanel/percussionpanelmodel.cpp index c0eac43865da3..7cbe0c446b353 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelmodel.cpp @@ -26,6 +26,9 @@ #include "engraving/dom/factory.h" #include "engraving/dom/undo.h" +#include "engraving/dom/utils.h" + +#include "audio/audioutils.h" static const QString PAD_NAMES_CODE("percussion-pad-names"); static const QString NOTATION_PREVIEW_CODE("percussion-notation-preview"); @@ -57,6 +60,20 @@ void PercussionPanelModel::setEnabled(bool enabled) emit enabledChanged(); } +QString PercussionPanelModel::soundTitle() const +{ + return m_soundTitle; +} + +void PercussionPanelModel::setSoundTitle(const QString& soundTitle) +{ + if (m_soundTitle == soundTitle) { + return; + } + m_soundTitle = soundTitle; + emit soundTitleChanged(); +} + PanelMode::Mode PercussionPanelModel::currentPanelMode() const { return m_currentPanelMode; @@ -235,6 +252,7 @@ void PercussionPanelModel::setUpConnections() } m_padListModel->setDrumset(drumset); + updateSoundTitle(currentTrackId()); }; if (!notation()) { @@ -266,6 +284,36 @@ void PercussionPanelModel::setUpConnections() case PanelMode::Mode::SOUND_PREVIEW: playPitch(pitch); } }); + + if (!audioSettings()) { + return; + } + + audioSettings()->trackInputParamsChanged().onReceive(this, [this](InstrumentTrackId trackId) { + if (trackId != currentTrackId()) { + return; + } + updateSoundTitle(trackId); + }); +} + +void PercussionPanelModel::updateSoundTitle(const InstrumentTrackId& trackId) +{ + if (!trackId.isValid()) { + setSoundTitle(QString()); + return; + } + + const audio::AudioInputParams& params = audioSettings()->trackInputParams(trackId); + + const QString name = muse::audio::audioSourceName(params).toQString(); + const QString category = muse::audio::audioSourceCategoryName(params).toQString(); + if (name.isEmpty() || category.isEmpty()) { + setSoundTitle(QString()); + return; + } + + setSoundTitle(category + ": " + name); } bool PercussionPanelModel::eventFilter(QObject* watched, QEvent* event) @@ -366,6 +414,27 @@ void PercussionPanelModel::resetLayout() undoStack->commitChanges(); } +InstrumentTrackId PercussionPanelModel::currentTrackId() const +{ + if (!interaction()) { + return InstrumentTrackId(); + } + + const NoteInputState inputState = interaction()->noteInput()->state(); + const Staff* staff = inputState.staff; + + if (!staff || !staff->part() || !inputState.segment) { + return InstrumentTrackId(); + } + + return { staff->part()->id(), staff->part()->instrumentId(inputState.segment->tick()) }; +} + +const project::IProjectAudioSettingsPtr PercussionPanelModel::audioSettings() const +{ + return globalContext()->currentProject() ? globalContext()->currentProject()->audioSettings() : nullptr; +} + const INotationPtr PercussionPanelModel::notation() const { return globalContext()->currentNotation(); diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.h b/src/notation/view/percussionpanel/percussionpanelmodel.h index 3439fafc070fa..0eec3c27d9cc3 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.h +++ b/src/notation/view/percussionpanel/percussionpanelmodel.h @@ -59,6 +59,8 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged) + Q_PROPERTY(QString soundTitle READ soundTitle NOTIFY soundTitleChanged) + Q_PROPERTY(PanelMode::Mode currentPanelMode READ currentPanelMode WRITE setCurrentPanelMode NOTIFY currentPanelModeChanged) Q_PROPERTY(bool useNotationPreview READ useNotationPreview WRITE setUseNotationPreview NOTIFY useNotationPreviewChanged) @@ -72,6 +74,9 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus bool enabled() const; void setEnabled(bool enabled); + QString soundTitle() const; + void setSoundTitle(const QString& soundTitle); + PanelMode::Mode currentPanelMode() const; void setCurrentPanelMode(const PanelMode::Mode& panelMode); @@ -94,6 +99,8 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus signals: void enabledChanged(); + void soundTitleChanged(); + void currentPanelModeChanged(const PanelMode::Mode& panelMode); void useNotationPreviewChanged(bool useNotationPreview); @@ -102,6 +109,8 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus private: void setUpConnections(); + void updateSoundTitle(const InstrumentTrackId& trackId); + bool eventFilter(QObject* watched, QEvent* event) override; void writePitch(int pitch); @@ -109,6 +118,9 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus void resetLayout(); + mu::engraving::InstrumentTrackId currentTrackId() const; + + const project::IProjectAudioSettingsPtr audioSettings() const; const mu::notation::INotationPtr notation() const; const mu::notation::INotationInteractionPtr interaction() const; @@ -116,6 +128,8 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus bool m_enabled = false; + QString m_soundTitle; + PanelMode::Mode m_currentPanelMode = PanelMode::Mode::WRITE; PanelMode::Mode m_panelModeToRestore = PanelMode::Mode::WRITE; bool m_useNotationPreview = false; diff --git a/src/project/internal/projectaudiosettings.cpp b/src/project/internal/projectaudiosettings.cpp index c993cee87f94e..0574648e3d0ab 100644 --- a/src/project/internal/projectaudiosettings.cpp +++ b/src/project/internal/projectaudiosettings.cpp @@ -110,6 +110,7 @@ void ProjectAudioSettings::setTrackInputParams(const InstrumentTrackId& partId, } m_trackInputParamsMap.insert_or_assign(partId, params); + m_trackInputParamsChanged.send(partId); m_settingsChanged.notify(); } @@ -119,10 +120,21 @@ void ProjectAudioSettings::clearTrackInputParams() return; } - m_trackInputParamsMap.clear(); + auto it = m_trackInputParamsMap.begin(); + while (it != m_trackInputParamsMap.end()) { + InstrumentTrackId id = it->first; + it = m_trackInputParamsMap.erase(it); + m_trackInputParamsChanged.send(id); + } + m_settingsChanged.notify(); } +muse::async::Channel ProjectAudioSettings::trackInputParamsChanged() const +{ + return m_trackInputParamsChanged; +} + bool ProjectAudioSettings::trackHasExistingOutputParams(const InstrumentTrackId& partId) const { return muse::contains(m_trackOutputParamsMap, partId); @@ -192,6 +204,7 @@ void ProjectAudioSettings::removeTrackParams(const InstrumentTrackId& partId) auto inSearch = m_trackInputParamsMap.find(partId); if (inSearch != m_trackInputParamsMap.end()) { m_trackInputParamsMap.erase(inSearch); + m_trackInputParamsChanged.send(partId); m_settingsChanged.notify(); } diff --git a/src/project/internal/projectaudiosettings.h b/src/project/internal/projectaudiosettings.h index b9c4e61a51f12..1e9816e0624d7 100644 --- a/src/project/internal/projectaudiosettings.h +++ b/src/project/internal/projectaudiosettings.h @@ -48,6 +48,7 @@ class ProjectAudioSettings : public IProjectAudioSettings const muse::audio::AudioInputParams& trackInputParams(const engraving::InstrumentTrackId& partId) const override; void setTrackInputParams(const engraving::InstrumentTrackId& partId, const muse::audio::AudioInputParams& params) override; void clearTrackInputParams() override; + muse::async::Channel trackInputParamsChanged() const override; bool trackHasExistingOutputParams(const engraving::InstrumentTrackId& partId) const override; const muse::audio::AudioOutputParams& trackOutputParams(const engraving::InstrumentTrackId& partId) const override; @@ -115,6 +116,7 @@ class ProjectAudioSettings : public IProjectAudioSettings std::unordered_map m_trackOutputParamsMap; muse::async::Notification m_settingsChanged; + muse::async::Channel m_trackInputParamsChanged; mu::playback::SoundProfileName m_activeSoundProfileName; }; diff --git a/src/project/iprojectaudiosettings.h b/src/project/iprojectaudiosettings.h index f2e96c2785789..830b384ef7af6 100644 --- a/src/project/iprojectaudiosettings.h +++ b/src/project/iprojectaudiosettings.h @@ -49,6 +49,7 @@ class IProjectAudioSettings virtual const muse::audio::AudioInputParams& trackInputParams(const engraving::InstrumentTrackId& trackId) const = 0; virtual void setTrackInputParams(const engraving::InstrumentTrackId& trackId, const muse::audio::AudioInputParams& params) = 0; virtual void clearTrackInputParams() = 0; + virtual muse::async::Channel trackInputParamsChanged() const = 0; virtual bool trackHasExistingOutputParams(const engraving::InstrumentTrackId& trackId) const = 0; virtual const muse::audio::AudioOutputParams& trackOutputParams(const engraving::InstrumentTrackId& trackId) const = 0; From 71e9a3045fb1c6e53029023bfa9868d9867b7944 Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Tue, 17 Dec 2024 15:22:23 +0000 Subject: [PATCH 07/10] Percussion panel - implement pad swap options dialog --- src/notation/notationmodule.cpp | 1 + src/notation/notationscene.qrc | 1 + .../PercussionPanelPadSwapDialog.qml | 236 ++++++++++++++++++ .../qml/MuseScore/NotationScene/qmldir | 1 + .../percussionpanel/percussionpanelmodel.cpp | 9 +- .../percussionpanelpadlistmodel.cpp | 61 ++++- .../percussionpanelpadlistmodel.h | 12 +- .../Project/AlsoShareAudioComDialog.qml | 4 +- 8 files changed, 316 insertions(+), 9 deletions(-) create mode 100644 src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml diff --git a/src/notation/notationmodule.cpp b/src/notation/notationmodule.cpp index 8986d0b96cb66..90b9b10de9bd1 100644 --- a/src/notation/notationmodule.cpp +++ b/src/notation/notationmodule.cpp @@ -153,6 +153,7 @@ void NotationModule::resolveImports() ir->registerQmlUri(Uri("musescore://notation/parts"), "MuseScore/NotationScene/PartsDialog.qml"); ir->registerQmlUri(Uri("musescore://notation/selectmeasurescount"), "MuseScore/NotationScene/SelectMeasuresCountDialog.qml"); ir->registerQmlUri(Uri("musescore://notation/editgridsize"), "MuseScore/NotationScene/EditGridSizeDialog.qml"); + ir->registerQmlUri(Uri("musescore://notation/percussionpanelpadswap"), "MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml"); } } diff --git a/src/notation/notationscene.qrc b/src/notation/notationscene.qrc index 4b6f5e9730be1..04bdfd0db1be0 100644 --- a/src/notation/notationscene.qrc +++ b/src/notation/notationscene.qrc @@ -65,5 +65,6 @@ qml/MuseScore/NotationScene/internal/EditStyle/StyleControlRowWithReset.qml qml/MuseScore/NotationScene/internal/EditStyle/TextFieldWithReset.qml qml/MuseScore/NotationScene/internal/EditStyle/IconAndTextButtonSelector.qml + qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml diff --git a/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml b/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml new file mode 100644 index 0000000000000..828a68f87208f --- /dev/null +++ b/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml @@ -0,0 +1,236 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import QtQuick 2.15 + +import Muse.Ui 1.0 +import Muse.UiComponents 1.0 + +StyledDialogView { + id: root + + contentWidth: 500 + contentHeight: contentRow.implicitHeight + contentColumn.spacing + buttonBox.implicitHeight + + margins: 16 + + //! NOTE: Actually making this empty will display "MuseScore Studio" + title: " " + + function done(data = {}) { + let value = Object.assign(data) + + root.ret = { + errcode: 0, + value: value + } + + root.hide() + } + + onNavigationActivateRequested: { + var btn = buttonBox.firstFocusBtn + if (btn) { + btn.navigation.requestActive() + } + } + + onAccessibilityActivateRequested: { + accessibleInfo.readInfo() + } + + QtObject { + id: prv + property bool moveMidiNotesAndShortcuts: true + } + + AccessibleItem { + id: accessibleInfo + + accessibleParent: radioButtons.accessible + visualItem: titleLabel + role: MUAccessible.StaticText + name: titleLabel.text + + function readInfo() { + accessibleInfo.ignored = false + accessibleInfo.focused = true + } + + function resetFocus() { + accessibleInfo.ignored = true + accessibleInfo.focused = false + } + } + + NavigationPanel { + id: contentNavigationPanel + + name: "contentNavigationPanel" + section: root.navigationSection + order: 0 + } + + Row { + id: contentRow + + width: parent.width + spacing: 28 + + StyledIconLabel { + id: icon + + font.pixelSize: 48 + iconCode: IconCode.QUESTION + } + + Column { + id: contentColumn + + width: contentRow.width - contentRow.spacing - icon.width + spacing: 16 + + StyledTextLabel { + id: titleLabel + + width: parent.width + + font: ui.theme.largeBodyBoldFont + horizontalAlignment: Text.AlignLeft + wrapMode: Text.Wrap + + text: qsTrc("notation", "Do you also want to move the MIDI notes and keyboard shortcuts that trigger these sounds?") + } + + RadioButtonGroup { + id: radioButtons + + width: parent.width + spacing: contentColumn.spacing + + orientation: ListView.Vertical + + model: [ + { text: qsTrc("notation", "Move MIDI notes and keyboard shortcuts with their sounds"), value: true }, + { text: qsTrc("notation", "Leave MIDI notes and keyboard shortcuts fixed to original pad positions"), value: false } + ] + + delegate: Row { + width: parent.width + spacing: 6 + + RoundedRadioButton { + id: radioButton + + anchors.verticalCenter: parent.verticalCenter + + navigation.name: modelData.text + navigation.panel: contentNavigationPanel + navigation.row: model.index + + checked: modelData.value === prv.moveMidiNotesAndShortcuts + + onToggled: { + // TODO: Live update the pads when this value is changed... + prv.moveMidiNotesAndShortcuts = modelData.value + } + } + + //! NOTE: Can't use radioButton.text because it won't wrap + StyledTextLabel { + width: parent.width - parent.spacing - radioButton.width + + anchors.verticalCenter: parent.verticalCenter + + horizontalAlignment: Text.AlignLeft + wrapMode: Text.Wrap + text: modelData.text + + MouseArea { + id: mouseArea + + anchors.fill: parent + + onClicked: { + // TODO: Live update the pads when this value is changed... + prv.moveMidiNotesAndShortcuts = modelData.value + } + } + } + } + } + + CheckBox { + id: rememberMyChoice + + width: parent.width + + navigation.panel: contentNavigationPanel + navigation.row: radioButtons.model.length + navigation.accessible.name: rememberMyChoice.text + + text: qsTrc("global", "Remember my choice") + checked: false + onClicked: { + rememberMyChoice.checked = !rememberMyChoice.checked + } + } + + + StyledTextLabel { + id: preferenceInfo + + width: parent.width + + horizontalAlignment: Text.AlignLeft + wrapMode: Text.Wrap + + text: qsTrc("global", "This setting can be changed at any time in Preferences") + } + } + } + + ButtonBox { + id: buttonBox + + anchors { + top: contentRow.bottom + topMargin: contentColumn.spacing + right: parent.right + } + + navigationPanel.section: root.navigationSection + navigationPanel.order: contentNavigationPanel.order + 1 + + buttons: [ ButtonBoxModel.Cancel, ButtonBoxModel.Done ] + + isAccessibilityDisabledWhenInit: true + + onStandardButtonClicked: function(buttonId) { + if (buttonId === ButtonBoxModel.Cancel) { + root.reject() + return + } + + root.done({ moveMidiNotesAndShortcuts: prv.moveMidiNotesAndShortcuts, rememberMyChoice: rememberMyChoice.checked }) + } + } +} diff --git a/src/notation/qml/MuseScore/NotationScene/qmldir b/src/notation/qml/MuseScore/NotationScene/qmldir index 287b099fc4a2e..92a378548318f 100644 --- a/src/notation/qml/MuseScore/NotationScene/qmldir +++ b/src/notation/qml/MuseScore/NotationScene/qmldir @@ -13,3 +13,4 @@ SelectionFilterPanel 1.0 SelectionFilterPanel.qml UndoHistoryPanel 1.0 UndoHistoryPanel.qml PianoKeyboardPanel 1.0 PianoKeyboardPanel.qml PercussionPanel 1.0 PercussionPanel.qml +PercussionPanelPadSwapDialog 1.0 PercussionPanelPadSwapDialog.qml diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.cpp b/src/notation/view/percussionpanel/percussionpanelmodel.cpp index 7cbe0c446b353..e80e712985642 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelmodel.cpp @@ -210,11 +210,17 @@ void PercussionPanelModel::finishEditing(bool discardChanges) if (!model) { continue; } + const int row = i / m_padListModel->numColumns(); const int column = i % m_padListModel->numColumns(); + engraving::DrumInstrument& drum = updatedDrumset->drum(model->pitch()); + drum.panelRow = row; drum.panelColumn = column; + + const QString& shortcut = model->keyboardShortcut(); + drum.shortcut = shortcut.isEmpty() ? '\0' : shortcut.toLatin1().at(0); } // Return if nothing changed after edit... @@ -319,7 +325,8 @@ void PercussionPanelModel::updateSoundTitle(const InstrumentTrackId& trackId) bool PercussionPanelModel::eventFilter(QObject* watched, QEvent* event) { // Finish editing on escape... - if (m_currentPanelMode != PanelMode::Mode::EDIT_LAYOUT || event->type() != QEvent::Type::ShortcutOverride) { + if (m_currentPanelMode != PanelMode::Mode::EDIT_LAYOUT || event->type() != QEvent::Type::ShortcutOverride + || m_padListModel->swapInProgress()) { return QObject::eventFilter(watched, event); } QKeyEvent* keyEvent = dynamic_cast(event); diff --git a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp index f3fc57789e013..55d536c871e42 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp @@ -116,13 +116,31 @@ void PercussionPanelPadListModel::startPadSwap(int startIndex) void PercussionPanelPadListModel::endPadSwap(int endIndex) { - if (indexIsValid(m_padSwapStartIndex) && indexIsValid(endIndex)) { - movePad(m_padSwapStartIndex, endIndex); - } else { + const auto endSwap = [this, endIndex]() { + m_padSwapStartIndex = -1; + emit padFocusRequested(endIndex); + }; + + if (m_padSwapStartIndex == endIndex || !indexIsValid(m_padSwapStartIndex) || !indexIsValid(endIndex)) { + // Put everything back where it was... emit layoutChanged(); + endSwap(); + return; } - m_padSwapStartIndex = -1; - emit padFocusRequested(endIndex); + + movePad(m_padSwapStartIndex, endIndex); + + if (!m_padModels.at(m_padSwapStartIndex) || !m_padModels.at(endIndex)) { + // Swapping with an empty pad - no extra options... + endSwap(); + return; + } + + // Give Qt a chance to process pending UI updates before opening the options dialog... + QMetaObject::invokeMethod(this, [this, endSwap, endIndex]() { + applyPadSwapOptions(m_padSwapStartIndex, endIndex); + endSwap(); + }, Qt::QueuedConnection); } void PercussionPanelPadListModel::setDrumset(const engraving::Drumset* drumset) @@ -319,6 +337,39 @@ int PercussionPanelPadListModel::createModelIndexForPitch(int pitch) const return modelIndex; } +void PercussionPanelPadListModel::applyPadSwapOptions(int fromIndex, int toIndex) +{ + muse::UriQuery query("musescore://notation/percussionpanelpadswap?sync=true&modal=true"); + muse::RetVal rv = interactive()->open(query); + + if (rv.val.isNull()) { + // Move was cancelled - revert the swap... + movePad(fromIndex, toIndex); + return; + } + + const QVariantMap vals = rv.val.toQVariant().toMap(); + const bool moveMidiNotesAndShortcuts = vals["moveMidiNotesAndShortcuts"].toBool(); + // const bool rememberMyChoice = vals["rememberMyChoice"].toBool(); + + if (moveMidiNotesAndShortcuts) { + // MIDI notes and shortcuts were moved with the pad itself, so we can return... + return; + } + + PercussionPanelPadModel* fromModel = m_padModels.at(fromIndex); + PercussionPanelPadModel* toModel = m_padModels.at(toIndex); + + const int tempPitch = fromModel->pitch(); + const QString tempShortcut = fromModel->keyboardShortcut(); + + fromModel->setPitch(toModel->pitch()); + fromModel->setKeyboardShortcut(toModel->keyboardShortcut()); + + toModel->setPitch(tempPitch); + toModel->setKeyboardShortcut(tempShortcut); +} + void PercussionPanelPadListModel::movePad(int fromIndex, int toIndex) { const int fromRow = fromIndex / NUM_COLUMNS; diff --git a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h index b3e4b2e306824..1d561706a671d 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h +++ b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h @@ -24,16 +24,23 @@ #include +#include "modularity/ioc.h" #include "async/asyncable.h" #include "async/channel.h" +#include "iinteractive.h" +#include "inotationconfiguration.h" + #include "engraving/dom/drumset.h" #include "percussionpanelpadmodel.h" namespace mu::notation { -class PercussionPanelPadListModel : public QAbstractListModel, public muse::async::Asyncable +class PercussionPanelPadListModel : public QAbstractListModel, public muse::Injectable, public muse::async::Asyncable { + muse::Inject interactive = { this }; + muse::Inject configuration = { this }; + Q_OBJECT Q_PROPERTY(int numColumns READ numColumns CONSTANT) @@ -58,6 +65,7 @@ class PercussionPanelPadListModel : public QAbstractListModel, public muse::asyn Q_INVOKABLE void startPadSwap(int startIndex); Q_INVOKABLE void endPadSwap(int endIndex); + bool swapInProgress() const { return indexIsValid(m_padSwapStartIndex); } bool hasActivePads() const { return m_drumset; } @@ -97,6 +105,8 @@ class PercussionPanelPadListModel : public QAbstractListModel, public muse::asyn void movePad(int fromIndex, int toIndex); + void applyPadSwapOptions(int fromIndex, int toIndex); + int numEmptySlotsAtRow(int row) const; engraving::Drumset* m_drumset = nullptr; //! NOTE: Pointer may be invalid, see PercussionPanelModel::setUpConnections diff --git a/src/project/qml/MuseScore/Project/AlsoShareAudioComDialog.qml b/src/project/qml/MuseScore/Project/AlsoShareAudioComDialog.qml index fd334b62a4391..7ef9e615593fc 100644 --- a/src/project/qml/MuseScore/Project/AlsoShareAudioComDialog.qml +++ b/src/project/qml/MuseScore/Project/AlsoShareAudioComDialog.qml @@ -142,7 +142,7 @@ StyledDialogView { Layout.fillWidth: true horizontalAlignment: Text.AlignLeft - text: qsTrc("project/cloud", "You can change this setting in Preferences at any time.") + text: qsTrc("global", "You can change this setting in Preferences at any time.") font: ui.theme.bodyFont } @@ -162,7 +162,7 @@ StyledDialogView { navigation.row: 1 navigation.accessible.name: text + "; " + preferenceInfo.text - text: qsTrc("project/cloud", "Remember my choice") + text: qsTrc("global", "Remember my choice") checked: root.rememberChoice From 393cb6d6d901a9ca8ef4005cda8fb15a94f54d30 Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Tue, 17 Dec 2024 15:24:38 +0000 Subject: [PATCH 08/10] Added percussion preferences page --- src/appshell/appshell.qrc | 1 + .../Preferences/PercussionPreferencesPage.qml | 161 ++++++++++++++++++ .../view/preferences/preferencesmodel.cpp | 3 + src/framework/ui/view/iconcodes.h | 2 + 4 files changed, 167 insertions(+) create mode 100644 src/appshell/qml/Preferences/PercussionPreferencesPage.qml diff --git a/src/appshell/appshell.qrc b/src/appshell/appshell.qrc index ee73ff2aee5f9..cd28a075cc68b 100644 --- a/src/appshell/appshell.qrc +++ b/src/appshell/appshell.qrc @@ -102,5 +102,6 @@ qml/Preferences/internal/MixerSection.qml qml/DevTools/Extensions/ExtensionsListView.qml qml/platform/PlatformMenuBar.qml + qml/Preferences/PercussionPreferencesPage.qml diff --git a/src/appshell/qml/Preferences/PercussionPreferencesPage.qml b/src/appshell/qml/Preferences/PercussionPreferencesPage.qml new file mode 100644 index 0000000000000..40a6cc9d77333 --- /dev/null +++ b/src/appshell/qml/Preferences/PercussionPreferencesPage.qml @@ -0,0 +1,161 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.15 + +import Muse.Ui 1.0 +import Muse.UiComponents 1.0 +import MuseScore.Preferences 1.0 + +import "internal" + +PreferencesPage { + id: root + + BaseSection { + id: percussionPanelPreferences + + title: qsTrc("appshell/preferences", "Percussion") + + navigation.section: root.navigationSection + + CheckBox { + id: unpitchedSelectedCheckbox + width: parent.width + + text: qsTrc("appshell/preferences", "Open the percussion panel when an unpitched staff is selected") + + navigation.name: "UnpitchedSelectedCheckbox" + navigation.panel: percussionPanelPreferences.navigation + navigation.row: 0 + + onClicked: { + // TODO: configuration - toggle autoShowPercussionPanel + } + } + + StyledTextLabel { + id: padSwapInfo + + width: parent.width + + horizontalAlignment: Text.AlignLeft + wrapMode: Text.Wrap + text: qsTrc("notation", "When swapping the positions of two drum pads:") + } + + RadioButtonGroup { + id: radioButtons + + property int navigationRowStart: unpitchedSelectedCheckbox.navigation.row + 1 + property int navigationRowEnd: radioButtons.navigationRowStart + model.length + + width: parent.width + spacing: percussionPanelPreferences.spacing + + orientation: ListView.Vertical + + model: [ + { text: qsTrc("notation", "Move MIDI notes and keyboard shortcuts with their sounds"), value: true }, + { text: qsTrc("notation", "Leave MIDI notes and keyboard shortcuts fixed to original pad positions"), value: false } + ] + + delegate: Row { + width: parent.width + spacing: 6 + + RoundedRadioButton { + id: radioButton + + anchors.verticalCenter: parent.verticalCenter + + navigation.name: modelData.text + navigation.panel: percussionPanelPreferences.navigation + navigation.row: radioButtons.navigationRowStart + model.index + + // TODO: checked: modelData.value === pad swap preference + + onToggled: { + // TODO: configuration - change pad swap preference + } + } + + //! NOTE: Can't use radioButton.text because it won't wrap + StyledTextLabel { + width: parent.width - parent.spacing - radioButton.width + + anchors.verticalCenter: parent.verticalCenter + + horizontalAlignment: Text.AlignLeft + wrapMode: Text.Wrap + text: modelData.text + + MouseArea { + id: mouseArea + + anchors.fill: parent + + onClicked: { + // TODO: configuration - change pad swap preference + } + } + } + } + } + + CheckBox { + id: alwaysAsk + + width: parent.width + + text: qsTrc("global", "Always ask") + + navigation.name: "AlwaysAskCheckBox" + navigation.panel: percussionPanelPreferences.navigation + navigation.row: radioButtons.navigationRowEnd + + onClicked: { + // TODO: configuration - toggle "show pad swap dialog" + } + } + } + + FlatButton { + id: useNewPercussionPanel + + anchors { + top: percussionPanelPreferences.bottom + topMargin: percussionPanelPreferences.spacing + left: parent.left + } + + text: qsTrc("notation", "Switch to old percussion panel") // TODO: "old/new" depending on current configuration... + + navigation.name: "SwitchPercussionPanels" + navigation.panel: percussionPanelPreferences.navigation + navigation.row: alwaysAsk.navigation.row + 1 + + onClicked: { + // TODO: configuration - toggle use of new percussion panel + } + } +} diff --git a/src/appshell/view/preferences/preferencesmodel.cpp b/src/appshell/view/preferences/preferencesmodel.cpp index 48f6415741d77..41ce6e5ccd065 100644 --- a/src/appshell/view/preferences/preferencesmodel.cpp +++ b/src/appshell/view/preferences/preferencesmodel.cpp @@ -178,6 +178,9 @@ void PreferencesModel::load(const QString& currentPageId) makeItem("midi-device-mapping", QT_TRANSLATE_NOOP("appshell/preferences", "MIDI mappings"), IconCode::Code::MIDI_INPUT, "Preferences/MidiDeviceMappingPreferencesPage.qml"), + makeItem("percussion", QT_TRANSLATE_NOOP("appshell/preferences", "Percussion"), IconCode::Code::PERCUSSION, + "Preferences/PercussionPreferencesPage.qml"), + makeItem("import", QT_TRANSLATE_NOOP("appshell/preferences", "Import"), IconCode::Code::IMPORT, "Preferences/ImportPreferencesPage.qml"), diff --git a/src/framework/ui/view/iconcodes.h b/src/framework/ui/view/iconcodes.h index 1001ad1df04bd..36a8272cabd13 100644 --- a/src/framework/ui/view/iconcodes.h +++ b/src/framework/ui/view/iconcodes.h @@ -460,6 +460,8 @@ class IconCode LV_CHORD_OUTSIDE = 0xF47F, LV_CHORD_INSIDE = 0xF480, + PERCUSSION = 0xF479, + SYSTEM_LOCK_START = 0xF481, SYSTEM_LOCK_END = 0xF482, From 7c43a4821d8427418da43640898e14a683f1f745 Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Wed, 18 Dec 2024 10:22:02 +0000 Subject: [PATCH 09/10] Implement percussion preferences --- src/appshell/CMakeLists.txt | 2 + src/appshell/appshellmodule.cpp | 2 + .../Preferences/PercussionPreferencesPage.qml | 53 ++++++----- src/appshell/view/notationpagemodel.cpp | 7 +- src/appshell/view/notationpagemodel.h | 2 +- .../percussionpreferencesmodel.cpp | 87 +++++++++++++++++++ .../preferences/percussionpreferencesmodel.h | 71 +++++++++++++++ src/notation/inotationconfiguration.h | 11 ++- .../internal/notationconfiguration.cpp | 61 ++++++++++++- src/notation/internal/notationconfiguration.h | 15 ++++ .../PercussionPanelPadSwapDialog.qml | 15 ++-- .../tests/mocks/notationconfigurationmock.h | 10 +++ .../percussionpanelpadlistmodel.cpp | 51 ++++++++--- .../percussionpanelpadlistmodel.h | 3 +- .../notation/notationconfigurationstub.cpp | 44 +++++++++- .../notation/notationconfigurationstub.h | 10 +++ 16 files changed, 395 insertions(+), 49 deletions(-) create mode 100644 src/appshell/view/preferences/percussionpreferencesmodel.cpp create mode 100644 src/appshell/view/preferences/percussionpreferencesmodel.h diff --git a/src/appshell/CMakeLists.txt b/src/appshell/CMakeLists.txt index 36ed619c6a91c..812b5b740c8c6 100644 --- a/src/appshell/CMakeLists.txt +++ b/src/appshell/CMakeLists.txt @@ -86,6 +86,8 @@ set(MODULE_SRC ${CMAKE_CURRENT_LIST_DIR}/view/preferences/importpreferencesmodel.h ${CMAKE_CURRENT_LIST_DIR}/view/preferences/audiomidipreferencesmodel.cpp ${CMAKE_CURRENT_LIST_DIR}/view/preferences/audiomidipreferencesmodel.h + ${CMAKE_CURRENT_LIST_DIR}/view/preferences/percussionpreferencesmodel.cpp + ${CMAKE_CURRENT_LIST_DIR}/view/preferences/percussionpreferencesmodel.h ${CMAKE_CURRENT_LIST_DIR}/view/preferences/commonaudioapiconfigurationmodel.cpp ${CMAKE_CURRENT_LIST_DIR}/view/preferences/commonaudioapiconfigurationmodel.h ${CMAKE_CURRENT_LIST_DIR}/view/preferences/braillepreferencesmodel.cpp diff --git a/src/appshell/appshellmodule.cpp b/src/appshell/appshellmodule.cpp index 054d6d94c395f..0100dd25538f9 100644 --- a/src/appshell/appshellmodule.cpp +++ b/src/appshell/appshellmodule.cpp @@ -56,6 +56,7 @@ #include "view/preferences/scorepreferencesmodel.h" #include "view/preferences/importpreferencesmodel.h" #include "view/preferences/audiomidipreferencesmodel.h" +#include "view/preferences/percussionpreferencesmodel.h" #include "view/preferences/commonaudioapiconfigurationmodel.h" #include "view/preferences/braillepreferencesmodel.h" #include "view/framelesswindow/framelesswindowmodel.h" @@ -150,6 +151,7 @@ void AppShellModule::registerUiTypes() qmlRegisterType("MuseScore.Preferences", 1, 0, "ScorePreferencesModel"); qmlRegisterType("MuseScore.Preferences", 1, 0, "ImportPreferencesModel"); qmlRegisterType("MuseScore.Preferences", 1, 0, "AudioMidiPreferencesModel"); + qmlRegisterType("MuseScore.Preferences", 1, 0, "PercussionPreferencesModel"); qmlRegisterType("MuseScore.Preferences", 1, 0, "CommonAudioApiConfigurationModel"); qmlRegisterType("MuseScore.Preferences", 1, 0, "BraillePreferencesModel"); diff --git a/src/appshell/qml/Preferences/PercussionPreferencesPage.qml b/src/appshell/qml/Preferences/PercussionPreferencesPage.qml index 40a6cc9d77333..d9ab1ee135f3a 100644 --- a/src/appshell/qml/Preferences/PercussionPreferencesPage.qml +++ b/src/appshell/qml/Preferences/PercussionPreferencesPage.qml @@ -31,6 +31,14 @@ import "internal" PreferencesPage { id: root + PercussionPreferencesModel { + id: percussionPreferencesModel + } + + Component.onCompleted: { + percussionPreferencesModel.init() + } + BaseSection { id: percussionPanelPreferences @@ -40,6 +48,8 @@ PreferencesPage { CheckBox { id: unpitchedSelectedCheckbox + + visible: percussionPreferencesModel.useNewPercussionPanel width: parent.width text: qsTrc("appshell/preferences", "Open the percussion panel when an unpitched staff is selected") @@ -48,14 +58,17 @@ PreferencesPage { navigation.panel: percussionPanelPreferences.navigation navigation.row: 0 + checked: percussionPreferencesModel.autoShowPercussionPanel + onClicked: { - // TODO: configuration - toggle autoShowPercussionPanel + percussionPreferencesModel.autoShowPercussionPanel = !unpitchedSelectedCheckbox.checked } } StyledTextLabel { id: padSwapInfo + visible: percussionPreferencesModel.useNewPercussionPanel width: parent.width horizontalAlignment: Text.AlignLeft @@ -69,6 +82,8 @@ PreferencesPage { property int navigationRowStart: unpitchedSelectedCheckbox.navigation.row + 1 property int navigationRowEnd: radioButtons.navigationRowStart + model.length + visible: percussionPreferencesModel.useNewPercussionPanel + width: parent.width spacing: percussionPanelPreferences.spacing @@ -92,10 +107,10 @@ PreferencesPage { navigation.panel: percussionPanelPreferences.navigation navigation.row: radioButtons.navigationRowStart + model.index - // TODO: checked: modelData.value === pad swap preference + checked: modelData.value === percussionPreferencesModel.percussionPanelMoveMidiNotesAndShortcuts onToggled: { - // TODO: configuration - change pad swap preference + percussionPreferencesModel.percussionPanelMoveMidiNotesAndShortcuts = modelData.value } } @@ -115,7 +130,7 @@ PreferencesPage { anchors.fill: parent onClicked: { - // TODO: configuration - change pad swap preference + percussionPreferencesModel.percussionPanelMoveMidiNotesAndShortcuts = modelData.value } } } @@ -125,6 +140,7 @@ PreferencesPage { CheckBox { id: alwaysAsk + visible: percussionPreferencesModel.useNewPercussionPanel width: parent.width text: qsTrc("global", "Always ask") @@ -133,29 +149,26 @@ PreferencesPage { navigation.panel: percussionPanelPreferences.navigation navigation.row: radioButtons.navigationRowEnd + checked: percussionPreferencesModel.showPercussionPanelPadSwapDialog + onClicked: { - // TODO: configuration - toggle "show pad swap dialog" + percussionPreferencesModel.showPercussionPanelPadSwapDialog = !alwaysAsk.checked } } - } - - FlatButton { - id: useNewPercussionPanel - anchors { - top: percussionPanelPreferences.bottom - topMargin: percussionPanelPreferences.spacing - left: parent.left - } + FlatButton { + id: useNewPercussionPanel - text: qsTrc("notation", "Switch to old percussion panel") // TODO: "old/new" depending on current configuration... + text: percussionPreferencesModel.useNewPercussionPanel ? qsTrc("notation", "Switch to old percussion panel") + : qsTrc("notation", "Switch to new percussion panel") - navigation.name: "SwitchPercussionPanels" - navigation.panel: percussionPanelPreferences.navigation - navigation.row: alwaysAsk.navigation.row + 1 + navigation.name: "SwitchPercussionPanels" + navigation.panel: percussionPanelPreferences.navigation + navigation.row: alwaysAsk.navigation.row + 1 - onClicked: { - // TODO: configuration - toggle use of new percussion panel + onClicked: { + percussionPreferencesModel.useNewPercussionPanel = !percussionPreferencesModel.useNewPercussionPanel + } } } } diff --git a/src/appshell/view/notationpagemodel.cpp b/src/appshell/view/notationpagemodel.cpp index e2dc8c2f733d2..5a225dde906a0 100644 --- a/src/appshell/view/notationpagemodel.cpp +++ b/src/appshell/view/notationpagemodel.cpp @@ -66,6 +66,11 @@ void NotationPageModel::init() updateDrumsetPanelVisibility(); updatePercussionPanelVisibility(); + + notationConfiguration()->useNewPercussionPanelChanged().onNotify(this, [this]() { + updateDrumsetPanelVisibility(); + updatePercussionPanelVisibility(); + }); } QString NotationPageModel::notationToolBarName() const @@ -150,7 +155,6 @@ void NotationPageModel::onNotationChanged() return; } - // TODO: Delete when the new percussion panel is finished if (!notationConfiguration()->useNewPercussionPanel()) { INotationNoteInputPtr noteInput = notation->interaction()->noteInput(); noteInput->stateChanged().onNotify(this, [this]() { @@ -235,7 +239,6 @@ void NotationPageModel::updatePercussionPanelVisibility() }; // This should never be open when the old drumset panel is in use... - // TODO: Delete when the new percussion panel is finished if (!notationConfiguration()->useNewPercussionPanel()) { setPercussionPanelOpen(false); return; diff --git a/src/appshell/view/notationpagemodel.h b/src/appshell/view/notationpagemodel.h index 7f4b99c0f585d..38921d9473f8a 100644 --- a/src/appshell/view/notationpagemodel.h +++ b/src/appshell/view/notationpagemodel.h @@ -85,7 +85,7 @@ class NotationPageModel : public QObject, public muse::Injectable, public muse:: void toggleDock(const QString& name); - void updateDrumsetPanelVisibility(); // TODO: Delete when the new percussion panel is finished + void updateDrumsetPanelVisibility(); void updatePercussionPanelVisibility(); }; } diff --git a/src/appshell/view/preferences/percussionpreferencesmodel.cpp b/src/appshell/view/preferences/percussionpreferencesmodel.cpp new file mode 100644 index 0000000000000..84897ee9505e6 --- /dev/null +++ b/src/appshell/view/preferences/percussionpreferencesmodel.cpp @@ -0,0 +1,87 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "percussionpreferencesmodel.h" + +PercussionPreferencesModel::PercussionPreferencesModel(QObject* parent) + : QObject(parent), muse::Injectable(muse::iocCtxForQmlObject(this)) +{ +} + +void PercussionPreferencesModel::init() +{ + configuration()->useNewPercussionPanelChanged().onNotify(this, [this]() { + emit useNewPercussionPanelChanged(); + }); + + configuration()->autoShowPercussionPanelChanged().onNotify(this, [this]() { + emit autoShowPercussionPanelChanged(); + }); + + configuration()->showPercussionPanelPadSwapDialogChanged().onNotify(this, [this]() { + emit showPercussionPanelPadSwapDialogChanged(); + }); + + configuration()->percussionPanelMoveMidiNotesAndShortcutsChanged().onNotify(this, [this]() { + emit percussionPanelMoveMidiNotesAndShortcutsChanged(); + }); +} + +bool PercussionPreferencesModel::useNewPercussionPanel() const +{ + return configuration()->useNewPercussionPanel(); +} + +void PercussionPreferencesModel::setUseNewPercussionPanel(bool use) +{ + configuration()->setUseNewPercussionPanel(use); +} + +bool PercussionPreferencesModel::autoShowPercussionPanel() const +{ + return configuration()->autoShowPercussionPanel(); +} + +void PercussionPreferencesModel::setAutoShowPercussionPanel(bool autoShow) +{ + configuration()->setAutoShowPercussionPanel(autoShow); +} + +bool PercussionPreferencesModel::showPercussionPanelPadSwapDialog() const +{ + return configuration()->showPercussionPanelPadSwapDialog(); +} + +void PercussionPreferencesModel::setShowPercussionPanelPadSwapDialog(bool show) +{ + configuration()->setShowPercussionPanelPadSwapDialog(show); +} + +bool PercussionPreferencesModel::percussionPanelMoveMidiNotesAndShortcuts() const +{ + return configuration()->percussionPanelMoveMidiNotesAndShortcuts(); +} + +void PercussionPreferencesModel::setPercussionPanelMoveMidiNotesAndShortcuts(bool move) +{ + configuration()->setPercussionPanelMoveMidiNotesAndShortcuts(move); +} diff --git a/src/appshell/view/preferences/percussionpreferencesmodel.h b/src/appshell/view/preferences/percussionpreferencesmodel.h new file mode 100644 index 0000000000000..cbe9dec900180 --- /dev/null +++ b/src/appshell/view/preferences/percussionpreferencesmodel.h @@ -0,0 +1,71 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include "modularity/ioc.h" +#include "notation/inotationconfiguration.h" + +#include "async/asyncable.h" + +class PercussionPreferencesModel : public QObject, public muse::Injectable, public muse::async::Asyncable +{ + Q_OBJECT + + Q_PROPERTY(bool useNewPercussionPanel READ useNewPercussionPanel WRITE setUseNewPercussionPanel NOTIFY useNewPercussionPanelChanged) + + Q_PROPERTY(bool autoShowPercussionPanel READ autoShowPercussionPanel + WRITE setAutoShowPercussionPanel NOTIFY autoShowPercussionPanelChanged) + + Q_PROPERTY(bool showPercussionPanelPadSwapDialog READ showPercussionPanelPadSwapDialog + WRITE setShowPercussionPanelPadSwapDialog NOTIFY showPercussionPanelPadSwapDialogChanged) + + Q_PROPERTY(bool percussionPanelMoveMidiNotesAndShortcuts READ percussionPanelMoveMidiNotesAndShortcuts + WRITE setPercussionPanelMoveMidiNotesAndShortcuts NOTIFY percussionPanelMoveMidiNotesAndShortcutsChanged) + + muse::Inject configuration = { this }; + +public: + explicit PercussionPreferencesModel(QObject* parent = nullptr); + + Q_INVOKABLE void init(); + + bool useNewPercussionPanel() const; + void setUseNewPercussionPanel(bool use); + + bool autoShowPercussionPanel() const; + void setAutoShowPercussionPanel(bool autoShow); + + bool showPercussionPanelPadSwapDialog() const; + void setShowPercussionPanelPadSwapDialog(bool show); + + bool percussionPanelMoveMidiNotesAndShortcuts() const; + void setPercussionPanelMoveMidiNotesAndShortcuts(bool move); + +signals: + void useNewPercussionPanelChanged(); + void autoShowPercussionPanelChanged(); + void showPercussionPanelPadSwapDialogChanged(); + void percussionPanelMoveMidiNotesAndShortcutsChanged(); +}; diff --git a/src/notation/inotationconfiguration.h b/src/notation/inotationconfiguration.h index c673e1227b148..6c7744271e39d 100644 --- a/src/notation/inotationconfiguration.h +++ b/src/notation/inotationconfiguration.h @@ -193,12 +193,21 @@ class INotationConfiguration : MODULE_EXPORT_INTERFACE virtual muse::ValCh midiUseWrittenPitch() const = 0; virtual void setMidiUseWrittenPitch(bool useWrittenPitch) = 0; - // TODO: Delete when the new percussion panel is finished virtual bool useNewPercussionPanel() const = 0; virtual void setUseNewPercussionPanel(bool use) = 0; + virtual muse::async::Notification useNewPercussionPanelChanged() const = 0; virtual bool autoShowPercussionPanel() const = 0; virtual void setAutoShowPercussionPanel(bool autoShow) = 0; + virtual muse::async::Notification autoShowPercussionPanelChanged() const = 0; + + virtual bool showPercussionPanelPadSwapDialog() const = 0; + virtual void setShowPercussionPanelPadSwapDialog(bool show) = 0; + virtual muse::async::Notification showPercussionPanelPadSwapDialogChanged() const = 0; + + virtual bool percussionPanelMoveMidiNotesAndShortcuts() const = 0; + virtual void setPercussionPanelMoveMidiNotesAndShortcuts(bool move) = 0; + virtual muse::async::Notification percussionPanelMoveMidiNotesAndShortcutsChanged() const = 0; virtual muse::io::path_t styleFileImportPath() const = 0; virtual void setStyleFileImportPath(const muse::io::path_t& path) = 0; diff --git a/src/notation/internal/notationconfiguration.cpp b/src/notation/internal/notationconfiguration.cpp index 20eec06261d09..64cce14817e69 100644 --- a/src/notation/internal/notationconfiguration.cpp +++ b/src/notation/internal/notationconfiguration.cpp @@ -93,6 +93,8 @@ static const Settings::Key PIANO_KEYBOARD_NUMBER_OF_KEYS(module_name, "pianoKey static const Settings::Key USE_NEW_PERCUSSION_PANEL_KEY(module_name, "ui/useNewPercussionPanel"); static const Settings::Key AUTO_SHOW_PERCUSSION_PANEL_KEY(module_name, "ui/autoShowPercussionPanel"); +static const Settings::Key SHOW_PERCUSSION_PANEL_SWAP_DIALOG(module_name, "ui/showPercussionPanelPadSwapDialog"); +static const Settings::Key PERCUSSION_PANEL_MOVE_MIDI_NOTES_AND_SHORTCUTS(module_name, "ui/percussionPanelMoveMidiNotesAndShortcuts"); static const Settings::Key STYLE_FILE_IMPORT_PATH_KEY(module_name, "import/style/styleFile"); @@ -225,8 +227,25 @@ void NotationConfiguration::init() m_midiInputUseWrittenPitch.set(val.toBool()); }); - settings()->setDefaultValue(USE_NEW_PERCUSSION_PANEL_KEY, Val(false)); + settings()->setDefaultValue(USE_NEW_PERCUSSION_PANEL_KEY, Val(false)); // TODO: true when new percussion panel is ready + settings()->valueChanged(USE_NEW_PERCUSSION_PANEL_KEY).onReceive(this, [this](const Val&) { + m_useNewPercussionPanelChanged.notify(); + }); + settings()->setDefaultValue(AUTO_SHOW_PERCUSSION_PANEL_KEY, Val(true)); + settings()->valueChanged(AUTO_SHOW_PERCUSSION_PANEL_KEY).onReceive(this, [this](const Val&) { + m_autoShowPercussionPanelChanged.notify(); + }); + + settings()->setDefaultValue(SHOW_PERCUSSION_PANEL_SWAP_DIALOG, Val(true)); + settings()->valueChanged(SHOW_PERCUSSION_PANEL_SWAP_DIALOG).onReceive(this, [this](const Val&) { + m_showPercussionPanelPadSwapDialogChanged.notify(); + }); + + settings()->setDefaultValue(PERCUSSION_PANEL_MOVE_MIDI_NOTES_AND_SHORTCUTS, Val(true)); + settings()->valueChanged(PERCUSSION_PANEL_MOVE_MIDI_NOTES_AND_SHORTCUTS).onReceive(this, [this](const Val&) { + m_percussionPanelMoveMidiNotesAndShortcutsChanged.notify(); + }); engravingConfiguration()->scoreInversionChanged().onNotify(this, [this]() { m_foregroundChanged.notify(); @@ -888,6 +907,11 @@ void NotationConfiguration::setUseNewPercussionPanel(bool use) settings()->setSharedValue(USE_NEW_PERCUSSION_PANEL_KEY, Val(use)); } +Notification NotationConfiguration::useNewPercussionPanelChanged() const +{ + return m_useNewPercussionPanelChanged; +} + bool NotationConfiguration::autoShowPercussionPanel() const { return settings()->value(AUTO_SHOW_PERCUSSION_PANEL_KEY).toBool(); @@ -898,6 +922,41 @@ void NotationConfiguration::setAutoShowPercussionPanel(bool autoShow) settings()->setSharedValue(AUTO_SHOW_PERCUSSION_PANEL_KEY, Val(autoShow)); } +Notification NotationConfiguration::autoShowPercussionPanelChanged() const +{ + return m_autoShowPercussionPanelChanged; +} + +bool NotationConfiguration::showPercussionPanelPadSwapDialog() const +{ + return settings()->value(SHOW_PERCUSSION_PANEL_SWAP_DIALOG).toBool(); +} + +void NotationConfiguration::setShowPercussionPanelPadSwapDialog(bool show) +{ + settings()->setSharedValue(SHOW_PERCUSSION_PANEL_SWAP_DIALOG, Val(show)); +} + +Notification NotationConfiguration::showPercussionPanelPadSwapDialogChanged() const +{ + return m_showPercussionPanelPadSwapDialogChanged; +} + +bool NotationConfiguration::percussionPanelMoveMidiNotesAndShortcuts() const +{ + return settings()->value(PERCUSSION_PANEL_MOVE_MIDI_NOTES_AND_SHORTCUTS).toBool(); +} + +void NotationConfiguration::setPercussionPanelMoveMidiNotesAndShortcuts(bool move) +{ + settings()->setSharedValue(PERCUSSION_PANEL_MOVE_MIDI_NOTES_AND_SHORTCUTS, Val(move)); +} + +Notification NotationConfiguration::percussionPanelMoveMidiNotesAndShortcutsChanged() const +{ + return m_percussionPanelMoveMidiNotesAndShortcutsChanged; +} + void NotationConfiguration::setPianoKeyboardNumberOfKeys(int number) { settings()->setSharedValue(PIANO_KEYBOARD_NUMBER_OF_KEYS, Val(number)); diff --git a/src/notation/internal/notationconfiguration.h b/src/notation/internal/notationconfiguration.h index eeb740be773ec..a24da7e3a5687 100644 --- a/src/notation/internal/notationconfiguration.h +++ b/src/notation/internal/notationconfiguration.h @@ -200,9 +200,19 @@ class NotationConfiguration : public INotationConfiguration, public muse::async: bool useNewPercussionPanel() const override; void setUseNewPercussionPanel(bool use) override; + muse::async::Notification useNewPercussionPanelChanged() const override; bool autoShowPercussionPanel() const override; void setAutoShowPercussionPanel(bool autoShow) override; + muse::async::Notification autoShowPercussionPanelChanged() const override; + + bool showPercussionPanelPadSwapDialog() const override; + void setShowPercussionPanelPadSwapDialog(bool show); + muse::async::Notification showPercussionPanelPadSwapDialogChanged() const override; + + bool percussionPanelMoveMidiNotesAndShortcuts() const override; + void setPercussionPanelMoveMidiNotesAndShortcuts(bool move); + muse::async::Notification percussionPanelMoveMidiNotesAndShortcutsChanged() const override; muse::io::path_t styleFileImportPath() const override; void setStyleFileImportPath(const muse::io::path_t& path) override; @@ -224,6 +234,7 @@ class NotationConfiguration : public INotationConfiguration, public muse::async: muse::async::Notification m_backgroundChanged; muse::async::Notification m_foregroundChanged; + muse::async::Channel m_canvasOrientationChanged; muse::async::Channel m_userStylesPathChanged; muse::async::Notification m_scoreOrderListPathsChanged; @@ -233,6 +244,10 @@ class NotationConfiguration : public INotationConfiguration, public muse::async: muse::ValCh m_pianoKeyboardNumberOfKeys; muse::ValCh m_midiInputUseWrittenPitch; muse::async::Channel m_anchorColorChanged; + muse::async::Notification m_useNewPercussionPanelChanged; + muse::async::Notification m_autoShowPercussionPanelChanged; + muse::async::Notification m_showPercussionPanelPadSwapDialogChanged; + muse::async::Notification m_percussionPanelMoveMidiNotesAndShortcutsChanged; int m_styleDialogLastPageIndex = 0; int m_styleDialogLastSubPageIndex = 0; diff --git a/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml b/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml index 828a68f87208f..ee0f1e755f732 100644 --- a/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml +++ b/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml @@ -27,6 +27,8 @@ import Muse.UiComponents 1.0 StyledDialogView { id: root + property bool moveMidiNotesAndShortcuts: true + contentWidth: 500 contentHeight: contentRow.implicitHeight + contentColumn.spacing + buttonBox.implicitHeight @@ -57,11 +59,6 @@ StyledDialogView { accessibleInfo.readInfo() } - QtObject { - id: prv - property bool moveMidiNotesAndShortcuts: true - } - AccessibleItem { id: accessibleInfo @@ -146,11 +143,11 @@ StyledDialogView { navigation.panel: contentNavigationPanel navigation.row: model.index - checked: modelData.value === prv.moveMidiNotesAndShortcuts + checked: modelData.value === root.moveMidiNotesAndShortcuts onToggled: { // TODO: Live update the pads when this value is changed... - prv.moveMidiNotesAndShortcuts = modelData.value + root.moveMidiNotesAndShortcuts = modelData.value } } @@ -171,7 +168,7 @@ StyledDialogView { onClicked: { // TODO: Live update the pads when this value is changed... - prv.moveMidiNotesAndShortcuts = modelData.value + root.moveMidiNotesAndShortcuts = modelData.value } } } @@ -230,7 +227,7 @@ StyledDialogView { return } - root.done({ moveMidiNotesAndShortcuts: prv.moveMidiNotesAndShortcuts, rememberMyChoice: rememberMyChoice.checked }) + root.done({ moveMidiNotesAndShortcuts: root.moveMidiNotesAndShortcuts, rememberMyChoice: rememberMyChoice.checked }) } } } diff --git a/src/notation/tests/mocks/notationconfigurationmock.h b/src/notation/tests/mocks/notationconfigurationmock.h index af8b990a985f8..a0c553e54d283 100644 --- a/src/notation/tests/mocks/notationconfigurationmock.h +++ b/src/notation/tests/mocks/notationconfigurationmock.h @@ -185,9 +185,19 @@ class NotationConfigurationMock : public INotationConfiguration MOCK_METHOD(bool, useNewPercussionPanel, (), (const, override)); MOCK_METHOD(void, setUseNewPercussionPanel, (bool), (override)); + MOCK_METHOD(muse::async::Notification, useNewPercussionPanelChanged, (), (const, override)); MOCK_METHOD(bool, autoShowPercussionPanel, (), (const, override)); MOCK_METHOD(void, setAutoShowPercussionPanel, (bool), (override)); + MOCK_METHOD(muse::async::Notification, autoShowPercussionPanelChanged, (), (const, override)); + + MOCK_METHOD(bool, showPercussionPanelPadSwapDialog, (), (const, override)); + MOCK_METHOD(void, setShowPercussionPanelPadSwapDialog, (bool), (override)); + MOCK_METHOD(muse::async::Notification, showPercussionPanelPadSwapDialogChanged, (), (const, override)); + + MOCK_METHOD(bool, percussionPanelMoveMidiNotesAndShortcuts, (), (const, override)); + MOCK_METHOD(void, setPercussionPanelMoveMidiNotesAndShortcuts, (bool), (override)); + MOCK_METHOD(muse::async::Notification, percussionPanelMoveMidiNotesAndShortcutsChanged, (), (const, override)); MOCK_METHOD(muse::io::path_t, styleFileImportPath, (), (const, override)); MOCK_METHOD(void, setStyleFileImportPath, (const muse::io::path_t&), (override)); diff --git a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp index 55d536c871e42..39625d0d7b8f5 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp @@ -138,7 +138,28 @@ void PercussionPanelPadListModel::endPadSwap(int endIndex) // Give Qt a chance to process pending UI updates before opening the options dialog... QMetaObject::invokeMethod(this, [this, endSwap, endIndex]() { - applyPadSwapOptions(m_padSwapStartIndex, endIndex); + bool moveMidiNotesAndShortcuts = configuration()->percussionPanelMoveMidiNotesAndShortcuts(); + + if (configuration()->showPercussionPanelPadSwapDialog()) { + const muse::RetVal rv = openPadSwapDialog(); + if (!rv.ret) { + // Cancelled, revert the swap... + movePad(m_padSwapStartIndex, endIndex); + endSwap(); + return; + } + + const QVariantMap vals = rv.val.toQVariant().toMap(); + moveMidiNotesAndShortcuts = vals["moveMidiNotesAndShortcuts"].toBool(); + } + + if (moveMidiNotesAndShortcuts) { + // MIDI notes and shortcuts were moved with the pad itself, so we can return... + endSwap(); + return; + } + + swapMidiNotesAndShortcuts(m_padSwapStartIndex, endIndex); endSwap(); }, Qt::QueuedConnection); } @@ -337,26 +358,30 @@ int PercussionPanelPadListModel::createModelIndexForPitch(int pitch) const return modelIndex; } -void PercussionPanelPadListModel::applyPadSwapOptions(int fromIndex, int toIndex) +muse::RetVal PercussionPanelPadListModel::openPadSwapDialog() { + const bool moveMidiNotesAndShortcuts = configuration()->percussionPanelMoveMidiNotesAndShortcuts(); + muse::UriQuery query("musescore://notation/percussionpanelpadswap?sync=true&modal=true"); + query.addParam("moveMidiNotesAndShortcuts", muse::Val(moveMidiNotesAndShortcuts)); muse::RetVal rv = interactive()->open(query); - if (rv.val.isNull()) { - // Move was cancelled - revert the swap... - movePad(fromIndex, toIndex); - return; - } - const QVariantMap vals = rv.val.toQVariant().toMap(); - const bool moveMidiNotesAndShortcuts = vals["moveMidiNotesAndShortcuts"].toBool(); - // const bool rememberMyChoice = vals["rememberMyChoice"].toBool(); + if (!rv.ret) { + return rv; + } - if (moveMidiNotesAndShortcuts) { - // MIDI notes and shortcuts were moved with the pad itself, so we can return... - return; + const bool rememberMyChoice = vals["rememberMyChoice"].toBool(); + if (rememberMyChoice) { + configuration()->setPercussionPanelMoveMidiNotesAndShortcuts(moveMidiNotesAndShortcuts); } + configuration()->setShowPercussionPanelPadSwapDialog(!rememberMyChoice); + return rv; +} + +void PercussionPanelPadListModel::swapMidiNotesAndShortcuts(int fromIndex, int toIndex) +{ PercussionPanelPadModel* fromModel = m_padModels.at(fromIndex); PercussionPanelPadModel* toModel = m_padModels.at(toIndex); diff --git a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h index 1d561706a671d..ee8d5610534ff 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h +++ b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h @@ -105,7 +105,8 @@ class PercussionPanelPadListModel : public QAbstractListModel, public muse::Inje void movePad(int fromIndex, int toIndex); - void applyPadSwapOptions(int fromIndex, int toIndex); + muse::RetVal openPadSwapDialog(); + void swapMidiNotesAndShortcuts(int fromIndex, int toIndex); int numEmptySlotsAtRow(int row) const; diff --git a/src/stubs/notation/notationconfigurationstub.cpp b/src/stubs/notation/notationconfigurationstub.cpp index e4a4c28b8319b..e4f6197c617bc 100644 --- a/src/stubs/notation/notationconfigurationstub.cpp +++ b/src/stubs/notation/notationconfigurationstub.cpp @@ -477,13 +477,19 @@ void NotationConfigurationStub::setMidiUseWrittenPitch(bool) bool NotationConfigurationStub::useNewPercussionPanel() const { - return false + return false; } void NotationConfigurationStub::setUseNewPercussionPanel(bool) { } +muse::async::Notification NotationConfigurationStub::useNewPercussionPanelChanged() const +{ + static muse::async::Notification n; + return n; +} + bool NotationConfigurationStub::autoShowPercussionPanel() const { return true; @@ -493,6 +499,42 @@ void NotationConfigurationStub::setAutoShowPercussionPanel(bool) { } +muse::async::Notification NotationConfigurationStub::autoShowPercussionPanelChanged() const +{ + static muse::async::Notification n; + return n; +} + +bool NotationConfigurationStub::showPercussionPanelPadSwapDialog() const +{ + return true; +} + +void NotationConfigurationStub::setShowPercussionPanelPadSwapDialog(bool) +{ +} + +muse::async::Notification NotationConfigurationStub::showPercussionPanelPadSwapDialogChanged() const +{ + static muse::async::Notification n; + return n; +} + +bool NotationConfigurationStub::percussionPanelMoveMidiNotesAndShortcuts() const +{ + return true; +} + +void NotationConfigurationStub::setPercussionPanelMoveMidiNotesAndShortcuts(bool) +{ +} + +muse::async::Notification NotationConfigurationStub::percussionPanelMoveMidiNotesAndShortcutsChanged() const +{ + static muse::async::Notification n; + return n; +} + muse::io::path_t NotationConfigurationStub::styleFileImportPath() const { return muse::io::path_t(); diff --git a/src/stubs/notation/notationconfigurationstub.h b/src/stubs/notation/notationconfigurationstub.h index 0ebedae9e6572..f02f0bf5018ab 100644 --- a/src/stubs/notation/notationconfigurationstub.h +++ b/src/stubs/notation/notationconfigurationstub.h @@ -176,9 +176,19 @@ class NotationConfigurationStub : public INotationConfiguration bool useNewPercussionPanel() const override; void setUseNewPercussionPanel(bool use) override; + muse::async::Notification useNewPercussionPanelChanged() const override; bool autoShowPercussionPanel() const override; void setAutoShowPercussionPanel(bool autoShow) override; + muse::async::Notification autoShowPercussionPanelChanged() const override; + + bool showPercussionPanelPadSwapDialog() const override; + void setShowPercussionPanelPadSwapDialog(bool show); + muse::async::Notification showPercussionPanelPadSwapDialogChanged() const override; + + bool percussionPanelMoveMidiNotesAndShortcuts() const override; + void setPercussionPanelMoveMidiNotesAndShortcuts(bool move); + muse::async::Notification percussionPanelMoveMidiNotesAndShortcutsChanged() const override; muse::io::path_t styleFileImportPath() const override; void setStyleFileImportPath(const muse::io::path_t& path) override; From a7283615ea1a5260a8ab94d077489f4f6e46bb66 Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Tue, 17 Dec 2024 15:38:28 +0000 Subject: [PATCH 10/10] Added notation/percussion translation context --- .../qml/Preferences/PercussionPreferencesPage.qml | 10 +++++----- .../qml/MuseScore/NotationScene/PercussionPanel.qml | 4 ++-- .../NotationScene/PercussionPanelPadSwapDialog.qml | 6 +++--- .../NotationScene/internal/PercussionPanelPad.qml | 8 ++++---- .../NotationScene/internal/PercussionPanelToolBar.qml | 10 +++++----- .../view/percussionpanel/percussionpanelmodel.cpp | 10 +++++----- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/appshell/qml/Preferences/PercussionPreferencesPage.qml b/src/appshell/qml/Preferences/PercussionPreferencesPage.qml index d9ab1ee135f3a..34a219e713d12 100644 --- a/src/appshell/qml/Preferences/PercussionPreferencesPage.qml +++ b/src/appshell/qml/Preferences/PercussionPreferencesPage.qml @@ -73,7 +73,7 @@ PreferencesPage { horizontalAlignment: Text.AlignLeft wrapMode: Text.Wrap - text: qsTrc("notation", "When swapping the positions of two drum pads:") + text: qsTrc("notation/percussion", "When swapping the positions of two drum pads:") } RadioButtonGroup { @@ -90,8 +90,8 @@ PreferencesPage { orientation: ListView.Vertical model: [ - { text: qsTrc("notation", "Move MIDI notes and keyboard shortcuts with their sounds"), value: true }, - { text: qsTrc("notation", "Leave MIDI notes and keyboard shortcuts fixed to original pad positions"), value: false } + { text: qsTrc("notation/percussion", "Move MIDI notes and keyboard shortcuts with their sounds"), value: true }, + { text: qsTrc("notation/percussion", "Leave MIDI notes and keyboard shortcuts fixed to original pad positions"), value: false } ] delegate: Row { @@ -159,8 +159,8 @@ PreferencesPage { FlatButton { id: useNewPercussionPanel - text: percussionPreferencesModel.useNewPercussionPanel ? qsTrc("notation", "Switch to old percussion panel") - : qsTrc("notation", "Switch to new percussion panel") + text: percussionPreferencesModel.useNewPercussionPanel ? qsTrc("notation/percussion", "Switch to old percussion panel") + : qsTrc("notation/percussion", "Switch to new percussion panel") navigation.name: "SwitchPercussionPanels" navigation.panel: percussionPanelPreferences.navigation diff --git a/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml b/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml index 381e6c6a8dd48..446243502b166 100644 --- a/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml +++ b/src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml @@ -411,7 +411,7 @@ Item { enabled: !padGrid.isKeyboardSwapActive icon: IconCode.PLUS - text: qsTrc("notation", "Add row") + text: qsTrc("notation/percussion", "Add row") orientation: Qt.Horizontal navigation.panel: addRowButtonPanel @@ -433,7 +433,7 @@ Item { anchors.topMargin: (padGrid.cellHeight / 2) - (panelDisabledLabel.height / 2) font: ui.theme.bodyFont - text: qsTrc("notation", "Select an unpitched percussion staff to see available sounds") + text: qsTrc("notation/percussion", "Select an unpitched percussion staff to see available sounds") } } diff --git a/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml b/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml index ee0f1e755f732..359c02c866d4b 100644 --- a/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml +++ b/src/notation/qml/MuseScore/NotationScene/PercussionPanelPadSwapDialog.qml @@ -114,7 +114,7 @@ StyledDialogView { horizontalAlignment: Text.AlignLeft wrapMode: Text.Wrap - text: qsTrc("notation", "Do you also want to move the MIDI notes and keyboard shortcuts that trigger these sounds?") + text: qsTrc("notation/percussion", "Do you also want to move the MIDI notes and keyboard shortcuts that trigger these sounds?") } RadioButtonGroup { @@ -126,8 +126,8 @@ StyledDialogView { orientation: ListView.Vertical model: [ - { text: qsTrc("notation", "Move MIDI notes and keyboard shortcuts with their sounds"), value: true }, - { text: qsTrc("notation", "Leave MIDI notes and keyboard shortcuts fixed to original pad positions"), value: false } + { text: qsTrc("notation/percussion", "Move MIDI notes and keyboard shortcuts with their sounds"), value: true }, + { text: qsTrc("notation/percussion", "Leave MIDI notes and keyboard shortcuts fixed to original pad positions"), value: false } ] delegate: Row { diff --git a/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPad.qml b/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPad.qml index d0d9e6c7dae26..f988adc02d9ea 100644 --- a/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPad.qml +++ b/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelPad.qml @@ -67,10 +67,10 @@ DropArea { readonly property real footerHeight: 24 readonly property string accessibleDescription: { //: %1 will be the row number of a percussion panel pad - let line1 = qsTrc("notation", "Row: %1").arg(root.navigationRow + 1) + let line1 = qsTrc("notation/percussion", "Row: %1").arg(root.navigationRow + 1) //: %1 will be the column number of a percussion panel pad - let line2 = qsTrc("notation", "Column: %1").arg(root.navigationColumn + 1) + let line2 = qsTrc("notation/percussion", "Column: %1").arg(root.navigationColumn + 1) return line1 + ", " + line2 } @@ -88,7 +88,7 @@ DropArea { enabled: Boolean(root.padModel) || root.panelMode === PanelMode.EDIT_LAYOUT accessible.role: MUAccessible.Button - accessible.name: Boolean(root.padModel) ? root.padModel.padName : qsTrc("notation", "Empty pad") + accessible.name: Boolean(root.padModel) ? root.padModel.padName : qsTrc("notation/percussion", "Empty pad") accessible.description: prv.accessibleDescription @@ -115,7 +115,7 @@ DropArea { enabled: Boolean(root.padModel) accessible.role: MUAccessible.Button - accessible.name: Boolean(root.padModel) ? root.padModel.padName + " " + qsTrc("notation", "footer") : "" + accessible.name: Boolean(root.padModel) ? root.padModel.padName + " " + qsTrc("notation/percussion", "footer") : "" accessible.description: prv.accessibleDescription diff --git a/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelToolBar.qml b/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelToolBar.qml index d31a25f436e87..10c6108544603 100644 --- a/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelToolBar.qml +++ b/src/notation/qml/MuseScore/NotationScene/internal/PercussionPanelToolBar.qml @@ -70,7 +70,7 @@ Item { enabled: root.model.enabled icon: IconCode.EDIT - text: qsTrc("notation", "Write") + text: qsTrc("notation/percussion", "Write") orientation: Qt.Horizontal accentButton: root.model.currentPanelMode === PanelMode.WRITE backgroundRadius: 0 @@ -137,7 +137,7 @@ Item { enabled: root.model.enabled icon: IconCode.PLAY - text: qsTrc("notation", "Preview") + text: qsTrc("notation/percussion", "Preview") orientation: Qt.Horizontal accentButton: root.model.currentPanelMode === PanelMode.SOUND_PREVIEW backgroundRadius: 0 @@ -198,7 +198,7 @@ Item { enabled: root.model.enabled visible: root.model.currentPanelMode === PanelMode.EDIT_LAYOUT - text: qsTrc("notation", "Finish editing") + text: qsTrc("notation/percussion", "Finish editing") orientation: Qt.Horizontal accentButton: true @@ -230,7 +230,7 @@ Item { enabled: root.model.enabled icon: IconCode.SPLIT_VIEW_HORIZONTAL - text: qsTrc("notation", "Layout") + text: qsTrc("notation/percussion", "Layout") orientation: Qt.Horizontal navigation.panel: rightSideNavPanel @@ -251,7 +251,7 @@ Item { FlatButton { enabled: root.model.enabled && root.model.currentPanelMode !== PanelMode.EDIT_LAYOUT - text: qsTrc("notation", "Customize kit") + text: qsTrc("notation/percussion", "Customize kit") orientation: Qt.Horizontal navigation.panel: rightSideNavPanel diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.cpp b/src/notation/view/percussionpanel/percussionpanelmodel.cpp index e80e712985642..7ca2978a90e56 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelmodel.cpp @@ -125,20 +125,20 @@ void PercussionPanelModel::init() QList PercussionPanelModel::layoutMenuItems() const { - const TranslatableString padNamesTitle("notation", "Pad names"); + const TranslatableString padNamesTitle("notation/percussion", "Pad names"); // Using IconCode for this instead of "checked" because we want the tick to display on the left const int padNamesIcon = static_cast(m_useNotationPreview ? IconCode::Code::NONE : IconCode::Code::TICK_RIGHT_ANGLE); - const TranslatableString notationPreviewTitle("notation", "Notation preview"); + const TranslatableString notationPreviewTitle("notation/percussion", "Notation preview"); // Using IconCode for this instead of "checked" because we want the tick to display on the left const int notationPreviewIcon = static_cast(m_useNotationPreview ? IconCode::Code::TICK_RIGHT_ANGLE : IconCode::Code::NONE); const TranslatableString editLayoutTitle = m_currentPanelMode == PanelMode::Mode::EDIT_LAYOUT - ? TranslatableString("notation", "Finish editing") - : TranslatableString("notation", "Edit layout"); + ? TranslatableString("notation/percussion", "Finish editing") + : TranslatableString("notation/percussion", "Edit layout"); const int editLayoutIcon = static_cast(IconCode::Code::CONFIGURE); - const TranslatableString resetLayoutTitle("notation", "Reset layout"); + const TranslatableString resetLayoutTitle("notation/percussion", "Reset layout"); const int resetLayoutIcon = static_cast(IconCode::Code::UNDO); QList menuItems = {