LCOV - code coverage report
Current view: top level - src/appshell/qml/MuseScore/AppShell - notationpagemodel.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 180 0
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #include "notationpagemodel.h"
      24              : 
      25              : #include "async/async.h"
      26              : #include "log.h"
      27              : 
      28              : #include "engraving/dom/part.h"
      29              : #include "engraving/dom/score.h"
      30              : #include "engraving/dom/staff.h"
      31              : 
      32              : #include "notation/inotation.h"
      33              : #include "notation/inotationelements.h" // IWYU pragma: keep
      34              : #include "notation/inotationinteraction.h"
      35              : #include "notation/inotationnoteinput.h"
      36              : #include "notation/inotationselection.h"
      37              : 
      38              : #include "dockwindow/idockwindow.h"
      39              : #include "dockwindow_v2/dockcommands.h"
      40              : 
      41              : using namespace muse;
      42              : using namespace mu::appshell;
      43              : using namespace mu::notation;
      44              : using namespace mu::engraving;
      45              : 
      46            0 : NotationPageModel::NotationPageModel(QObject* parent)
      47            0 :     : QObject(parent), muse::Contextable(muse::iocCtxForQmlObject(this))
      48              : {
      49            0 : }
      50              : 
      51            0 : bool NotationPageModel::isNavigatorVisible() const
      52              : {
      53            0 :     return appShellState()->isNotationNavigatorVisible();
      54              : }
      55              : 
      56            0 : bool NotationPageModel::isBraillePanelVisible() const
      57              : {
      58            0 :     return brailleConfiguration()->braillePanelEnabled();
      59              : }
      60              : 
      61            0 : void NotationPageModel::init()
      62              : {
      63            0 :     TRACEFUNC;
      64              : 
      65            0 :     if (m_inited) {
      66            0 :         return;
      67              :     }
      68              : 
      69            0 :     commandsController()->dockToggleRequested().onReceive(this, [this](const DockName& dockName) {
      70            0 :         toggleDock(dockName);
      71            0 :     });
      72              : 
      73            0 :     projectSession()->currentNotationChanged().onNotify(this, [this]() {
      74            0 :         onNotationChanged();
      75            0 :         scheduleUpdatePercussionPanelVisibility();
      76            0 :     });
      77              : 
      78            0 :     extensionsProvider()->manifestListChanged().onNotify(this, [this]() {
      79            0 :         scheduleUpdateExtensionsToolBarVisibility();
      80            0 :     });
      81              : 
      82            0 :     extensionsProvider()->enabledChanged().onReceive(this, [this](const muse::Uri&) {
      83            0 :         scheduleUpdateExtensionsToolBarVisibility();
      84            0 :     });
      85              : 
      86            0 :     brailleConfiguration()->braillePanelEnabledChanged().onNotify(this, [this]() {
      87            0 :         emit isBraillePanelVisibleChanged();
      88            0 :     });
      89              : 
      90            0 :     onNotationChanged();
      91              : 
      92            0 :     scheduleUpdatePercussionPanelVisibility();
      93            0 :     scheduleUpdateExtensionsToolBarVisibility();
      94              : 
      95            0 :     notationSceneConfiguration()->percussionPanelAutoShowModeChanged().onNotify(this, [this]() {
      96            0 :         scheduleUpdatePercussionPanelVisibility();
      97            0 :     });
      98              : 
      99            0 :     m_inited = true;
     100            0 : }
     101              : 
     102            0 : QString NotationPageModel::notationToolBarName() const
     103              : {
     104            0 :     return NOTATION_TOOLBAR_NAME;
     105              : }
     106              : 
     107            0 : QString NotationPageModel::playbackToolBarName() const
     108              : {
     109            0 :     return PLAYBACK_TOOLBAR_NAME;
     110              : }
     111              : 
     112            0 : QString NotationPageModel::undoRedoToolBarName() const
     113              : {
     114            0 :     return UNDO_REDO_TOOLBAR_NAME;
     115              : }
     116              : 
     117            0 : QString NotationPageModel::noteInputBarName() const
     118              : {
     119            0 :     return NOTE_INPUT_BAR_NAME;
     120              : }
     121              : 
     122            0 : QString NotationPageModel::extensionsToolBarName() const
     123              : {
     124            0 :     return EXTENSIONS_TOOLBAR_NAME;
     125              : }
     126              : 
     127            0 : QString NotationPageModel::palettesPanelName() const
     128              : {
     129            0 :     return PALETTES_PANEL_NAME;
     130              : }
     131              : 
     132            0 : QString NotationPageModel::layoutPanelName() const
     133              : {
     134            0 :     return LAYOUT_PANEL_NAME;
     135              : }
     136              : 
     137            0 : QString NotationPageModel::propertiesPanelName() const
     138              : {
     139            0 :     return PROPERTIES_PANEL_NAME;
     140              : }
     141              : 
     142            0 : QString NotationPageModel::selectionFiltersPanelName() const
     143              : {
     144            0 :     return SELECTION_FILTERS_PANEL_NAME;
     145              : }
     146              : 
     147            0 : QString NotationPageModel::undoHistoryPanelName() const
     148              : {
     149            0 :     return UNDO_HISTORY_PANEL_NAME;
     150              : }
     151              : 
     152            0 : QString NotationPageModel::mixerPanelName() const
     153              : {
     154            0 :     return MIXER_PANEL_NAME;
     155              : }
     156              : 
     157            0 : QString NotationPageModel::pianoKeyboardPanelName() const
     158              : {
     159            0 :     return PIANO_KEYBOARD_PANEL_NAME;
     160              : }
     161              : 
     162            0 : QString NotationPageModel::timelinePanelName() const
     163              : {
     164            0 :     return TIMELINE_PANEL_NAME;
     165              : }
     166              : 
     167            0 : QString NotationPageModel::percussionPanelName() const
     168              : {
     169            0 :     return PERCUSSION_PANEL_NAME;
     170              : }
     171              : 
     172            0 : QString NotationPageModel::statusBarName() const
     173              : {
     174            0 :     return NOTATION_STATUSBAR_NAME;
     175              : }
     176              : 
     177            0 : void NotationPageModel::onNotationChanged()
     178              : {
     179            0 :     INotationPtr notation = projectSession()->currentNotation();
     180            0 :     if (!notation) {
     181            0 :         return;
     182              :     }
     183              : 
     184            0 :     INotationNoteInputPtr noteInput = notation->interaction()->noteInput();
     185            0 :     noteInput->stateChanged().onNotify(this, [this]() {
     186            0 :         scheduleUpdatePercussionPanelVisibility();
     187            0 :     }, Asyncable::Mode::SetReplace /* FIXME */);
     188              : 
     189            0 :     INotationInteractionPtr notationInteraction = notation->interaction();
     190            0 :     notationInteraction->selectionChanged().onNotify(this, [this]() {
     191            0 :         scheduleUpdatePercussionPanelVisibility();
     192            0 :     }, Asyncable::Mode::SetReplace /* FIXME */);
     193            0 : }
     194              : 
     195            0 : void NotationPageModel::toggleDock(const QString& name)
     196              : {
     197            0 :     if (name == NOTATION_NAVIGATOR_PANEL_NAME) {
     198            0 :         appShellState()->setIsNotationNavigatorVisible(!isNavigatorVisible());
     199            0 :         emit isNavigatorVisibleChanged();
     200            0 :         return;
     201              :     }
     202              : 
     203            0 :     if (name == NOTATION_BRAILLE_PANEL_NAME) {
     204            0 :         brailleConfiguration()->setBraillePanelEnabled(!isBraillePanelVisible());
     205            0 :         emit isBraillePanelVisibleChanged();
     206            0 :         return;
     207              :     }
     208              : 
     209            0 :     commandDispatcher()->dispatch(dock::DOCK_TOGGLE_COMMAND, { { "dock_name", muse::Val(name) } });
     210            0 : }
     211              : 
     212            0 : void NotationPageModel::scheduleUpdatePercussionPanelVisibility()
     213              : {
     214            0 :     if (m_updatePercussionPanelVisibilityScheduled) {
     215            0 :         return;
     216              :     }
     217              : 
     218            0 :     m_updatePercussionPanelVisibilityScheduled = true;
     219              : 
     220              :     //! NOTE: ensure we don't update it multiple times in succession
     221            0 :     muse::async::Async::call(this, [this]() {
     222            0 :         doUpdatePercussionPanelVisibility();
     223            0 :         m_updatePercussionPanelVisibilityScheduled = false;
     224            0 :     });
     225              : }
     226              : 
     227            0 : void NotationPageModel::doUpdatePercussionPanelVisibility()
     228              : {
     229            0 :     TRACEFUNC;
     230              : 
     231              :     //! NOTE: If the user is entering percussion notes with the piano keyboard, we can assume that they
     232              :     //! don't want the percussion panel to auto-show...
     233            0 :     const muse::dock::IDockWindow* window = dockWindowProvider()->window();
     234            0 :     if (!window || window->isDockOpen(PIANO_KEYBOARD_PANEL_NAME)) {
     235            0 :         return;
     236              :     }
     237              : 
     238            0 :     auto setPercussionPanelOpen = [this, window](bool open) {
     239            0 :         if (open == window->isDockOpen(PERCUSSION_PANEL_NAME)) {
     240            0 :             return;
     241              :         }
     242              : 
     243            0 :         commandDispatcher()->dispatch(dock::DOCK_SET_OPEN_COMMAND,
     244            0 :                                       { { "dock_name", muse::Val(PERCUSSION_PANEL_NAME) }, { "open", muse::Val(open) } });
     245            0 :     };
     246              : 
     247            0 :     const PercussionPanelAutoShowMode autoShowMode = notationSceneConfiguration()->percussionPanelAutoShowMode();
     248            0 :     const INotationPtr notation = projectSession()->currentNotation();
     249            0 :     if (!notation || !notation->elements() || autoShowMode == PercussionPanelAutoShowMode::NEVER) {
     250            0 :         return;
     251              :     }
     252              : 
     253            0 :     const INotationNoteInputPtr noteInput = notation->interaction()->noteInput();
     254            0 :     const bool autoClose = notationSceneConfiguration()->autoClosePercussionPanel();
     255            0 :     if (noteInput && !noteInput->isNoteInputMode() && autoShowMode == PercussionPanelAutoShowMode::UNPITCHED_STAFF_NOTE_INPUT) {
     256            0 :         if (autoClose) {
     257            0 :             setPercussionPanelOpen(false);
     258              :         }
     259            0 :         return;
     260              :     }
     261              : 
     262            0 :     const Score* score = notation->elements()->msScore();
     263            0 :     if (score) {
     264            0 :         const InputState& inputState = score->inputState();
     265            0 :         const Staff* staff = inputState.staff();
     266            0 :         if (inputState.noteEntryMode() && staff && staff->isDrumStaff(inputState.tick())) {
     267            0 :             setPercussionPanelOpen(true);
     268            0 :             return;
     269              :         }
     270              :     }
     271              : 
     272            0 :     const INotationSelectionPtr selection = notation->interaction()->selection();
     273            0 :     if (!score || !selection || selection->isNone()) {
     274            0 :         if (autoClose) {
     275            0 :             setPercussionPanelOpen(false);
     276              :         }
     277            0 :         return;
     278              :     }
     279              : 
     280            0 :     if (selection->isRange()) {
     281            0 :         const INotationSelectionRangePtr rangeSelection = selection->range();
     282            0 :         if (!rangeSelection) {
     283            0 :             if (autoClose) {
     284            0 :                 setPercussionPanelOpen(false);
     285              :             }
     286            0 :             return;
     287              :         }
     288            0 :         for (const Part* p : rangeSelection->selectedParts()) {
     289            0 :             if (p->hasDrumStaff()) {
     290            0 :                 continue;
     291              :             }
     292            0 :             if (autoClose) {
     293            0 :                 setPercussionPanelOpen(false);
     294              :             }
     295            0 :             return;
     296            0 :         }
     297            0 :     } else {
     298            0 :         for (const EngravingItem* e : selection->elements()) {
     299            0 :             const Staff* staff = e->staff();
     300            0 :             if (staff && staff->isDrumStaff(e->tick())) {
     301            0 :                 continue;
     302              :             }
     303            0 :             if (autoClose) {
     304            0 :                 setPercussionPanelOpen(false);
     305              :             }
     306            0 :             return;
     307              :         }
     308              :     }
     309              : 
     310            0 :     setPercussionPanelOpen(true);
     311            0 : }
     312              : 
     313            0 : void NotationPageModel::scheduleUpdateExtensionsToolBarVisibility()
     314              : {
     315            0 :     if (m_updateExtensionsToolBarVisibilityScheduled) {
     316            0 :         return;
     317              :     }
     318              : 
     319            0 :     m_updateExtensionsToolBarVisibilityScheduled = true;
     320              : 
     321              :     //! NOTE: ensure we don't update it multiple times in succession
     322            0 :     muse::async::Async::call(this, [this]() {
     323            0 :         doUpdateExtensionsToolBarVisibility();
     324            0 :         m_updateExtensionsToolBarVisibilityScheduled = false;
     325            0 :     });
     326              : }
     327              : 
     328            0 : void NotationPageModel::doUpdateExtensionsToolBarVisibility()
     329              : {
     330            0 :     const muse::dock::IDockWindow* window = dockWindowProvider()->window();
     331            0 :     if (!window) {
     332            0 :         return;
     333              :     }
     334              : 
     335            0 :     auto setExtensionsToolBarOpen = [this, window](bool open) {
     336            0 :         if (open == window->isDockOpen(EXTENSIONS_TOOLBAR_NAME)) {
     337            0 :             return;
     338              :         }
     339              : 
     340            0 :         commandDispatcher()->dispatch(dock::DOCK_SET_OPEN_COMMAND,
     341            0 :                                       { { "dock_name", muse::Val(EXTENSIONS_TOOLBAR_NAME) }, { "open", muse::Val(open) } });
     342            0 :     };
     343              : 
     344            0 :     muse::extensions::ManifestList enabledExtensions = extensionsProvider()->manifestList(muse::extensions::Filter::Enabled);
     345            0 :     for (const muse::extensions::Manifest& m : enabledExtensions) {
     346            0 :         for (const muse::extensions::Action& a : m.actions) {
     347            0 :             if (!a.showOnToolbar) {
     348            0 :                 continue;
     349              :             }
     350              : 
     351            0 :             setExtensionsToolBarOpen(true);
     352            0 :             return;
     353              :         }
     354              :     }
     355              : 
     356            0 :     setExtensionsToolBarOpen(false);
     357            0 : }
        

Generated by: LCOV version 2.0-1