LCOV - code coverage report
Current view: top level - src/notationscene/widgets - measureproperties.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 172 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 "measureproperties.h"
      24              : 
      25              : #include <QKeyEvent>
      26              : 
      27              : #include "translation.h"
      28              : 
      29              : #include "engraving/dom/masterscore.h"
      30              : #include "engraving/dom/measure.h"
      31              : #include "engraving/dom/measurerepeat.h"
      32              : #include "engraving/dom/range.h"
      33              : #include "engraving/dom/sig.h"
      34              : #include "engraving/editing/editstaff.h"
      35              : 
      36              : #include "notation/inotationelements.h" // IWYU pragma: keep
      37              : #include "notation/inotationinteraction.h"
      38              : #include "notation/inotationundostack.h"
      39              : 
      40              : #include "ui/view/widgetnavigationfix.h"
      41              : #include "ui/view/widgetstatestore.h"
      42              : #include "ui/view/widgetutils.h"
      43              : 
      44              : using namespace mu::notation;
      45              : using namespace muse::ui;
      46              : 
      47              : static const int ITEM_ACCESSIBLE_TITLE_ROLE = Qt::UserRole + 1;
      48              : 
      49            0 : MeasurePropertiesDialog::MeasurePropertiesDialog(QWidget* parent)
      50            0 :     : muse::ui::WidgetDialog(parent)
      51              : {
      52            0 :     setObjectName("MeasureProperties");
      53            0 :     setupUi(this);
      54            0 :     setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
      55              : 
      56            0 :     qApp->installEventFilter(this);
      57            0 : }
      58              : 
      59            0 : void MeasurePropertiesDialog::componentComplete()
      60              : {
      61            0 :     m_notation = context()->currentNotation();
      62            0 :     initMeasure();
      63              : 
      64            0 :     staves->verticalHeader()->hide();
      65              : 
      66            0 :     nextButton->setText(iconCodeToChar(IconCode::Code::ARROW_RIGHT));
      67            0 :     previousButton->setText(iconCodeToChar(IconCode::Code::ARROW_LEFT));
      68              : 
      69            0 :     connect(buttonBox, &QDialogButtonBox::clicked, this, &MeasurePropertiesDialog::bboxClicked);
      70            0 :     connect(nextButton, &QToolButton::clicked, this, &MeasurePropertiesDialog::gotoNextMeasure);
      71            0 :     connect(previousButton, &QToolButton::clicked, this, &MeasurePropertiesDialog::gotoPreviousMeasure);
      72              : 
      73            0 :     if (qApp->layoutDirection() == Qt::LayoutDirection::RightToLeft) {
      74            0 :         horizontalLayout_2->removeWidget(nextButton);
      75            0 :         horizontalLayout_2->insertWidget(0, nextButton);
      76              :     }
      77              : 
      78            0 :     WidgetUtils::setWidgetIcon(previousButton, IconCode::Code::ARROW_LEFT);
      79            0 :     WidgetUtils::setWidgetIcon(nextButton, IconCode::Code::ARROW_RIGHT);
      80              : 
      81              :     //! NOTE: It is necessary for the correct start of navigation in the dialog
      82            0 :     setFocus();
      83            0 : }
      84              : 
      85            0 : void MeasurePropertiesDialog::initMeasure()
      86              : {
      87            0 :     if (!m_notation) {
      88            0 :         return;
      89              :     }
      90              : 
      91            0 :     mu::engraving::Measure* measure = m_notation->interaction()->selectedMeasure();
      92              : 
      93            0 :     IF_ASSERT_FAILED(measure) {
      94            0 :         return;
      95              :     }
      96              : 
      97            0 :     setMeasure(measure);
      98              : }
      99              : 
     100              : //---------------------------------------------------------
     101              : //   getNextMeasure
     102              : //    skip multi measure rests
     103              : //---------------------------------------------------------
     104              : 
     105            0 : mu::engraving::Measure* getNextMeasure(mu::engraving::Measure* m)
     106              : {
     107            0 :     mu::engraving::Measure* mm = m->nextMeasureMM();
     108            0 :     while (mm && mm->isMMRest()) {
     109            0 :         mm = mm->nextMeasureMM();
     110              :     }
     111            0 :     return mm;
     112              : }
     113              : 
     114              : //---------------------------------------------------------
     115              : //   getPrevMeasure
     116              : //    skip multi measure rests
     117              : //---------------------------------------------------------
     118              : 
     119            0 : mu::engraving::Measure* getPrevMeasure(mu::engraving::Measure* m)
     120              : {
     121            0 :     mu::engraving::Measure* mm = m->prevMeasureMM();
     122            0 :     while (mm && mm->isMMRest()) {
     123            0 :         mm = mm->prevMeasureMM();
     124              :     }
     125            0 :     return mm;
     126              : }
     127              : 
     128              : //---------------------------------------------------------
     129              : //   gotoNextMeasure
     130              : //---------------------------------------------------------
     131              : 
     132            0 : void MeasurePropertiesDialog::gotoNextMeasure()
     133              : {
     134            0 :     apply();
     135            0 :     if (getNextMeasure(m_measure)) {
     136            0 :         setMeasure(getNextMeasure(m_measure));
     137              :     }
     138            0 :     nextButton->setEnabled(getNextMeasure(m_measure));
     139            0 :     previousButton->setEnabled(getPrevMeasure(m_measure));
     140            0 :     m_notation->notationChanged().send(muse::RectF());
     141            0 : }
     142              : 
     143              : //---------------------------------------------------------
     144              : //   gotoPreviousMeasure
     145              : //---------------------------------------------------------
     146              : 
     147            0 : void MeasurePropertiesDialog::gotoPreviousMeasure()
     148              : {
     149            0 :     apply();
     150            0 :     if (getPrevMeasure(m_measure)) {
     151            0 :         setMeasure(getPrevMeasure(m_measure));
     152              :     }
     153            0 :     nextButton->setEnabled(getNextMeasure(m_measure));
     154            0 :     previousButton->setEnabled(getPrevMeasure(m_measure));
     155            0 :     m_notation->notationChanged().send(muse::RectF());
     156            0 : }
     157              : 
     158            0 : bool MeasurePropertiesDialog::eventFilter(QObject* obj, QEvent* event)
     159              : {
     160            0 :     if (event->type() == QEvent::KeyPress) {
     161            0 :         QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event);
     162            0 :         if (keyEvent
     163            0 :             && WidgetNavigationFix::fixNavigationForTableWidget(
     164            0 :                 WidgetNavigationFix::NavigationChain { staves, actualZ, buttonBox },
     165              :                 keyEvent->key())) {
     166            0 :             return true;
     167              :         }
     168              :     }
     169              : 
     170            0 :     return QDialog::eventFilter(obj, event);
     171              : }
     172              : 
     173              : //---------------------------------------------------------
     174              : //   setMeasure
     175              : //---------------------------------------------------------
     176              : 
     177            0 : void MeasurePropertiesDialog::setMeasure(mu::engraving::Measure* measure)
     178              : {
     179            0 :     m_measure = measure;
     180            0 :     nextButton->setEnabled(m_measure->nextMeasure() != 0);
     181            0 :     previousButton->setEnabled(m_measure->prevMeasure() != 0);
     182              : 
     183            0 :     setWindowTitle(muse::qtrc("notation/measureproperties", "Properties for measure %1").arg(m_measure->measureNumber() + 1));
     184            0 :     m_notation->interaction()->clearSelection();
     185            0 :     m_notation->interaction()->select({ m_measure }, mu::engraving::SelectType::ADD, 0);
     186              : 
     187            0 :     actualZ->setValue(m_measure->ticks().numerator());
     188            0 :     int index = actualN->findText(QString::number(m_measure->ticks().denominator()));
     189            0 :     if (index == -1) {
     190            0 :         index = 2;
     191              :     }
     192            0 :     actualN->setCurrentIndex(index);
     193            0 :     nominalZ->setNum(m_measure->timesig().numerator());
     194            0 :     nominalN->setNum(m_measure->timesig().denominator());
     195              : 
     196            0 :     excludeFromNumbering->setChecked(m_measure->excludeFromNumbering());
     197            0 :     breakMultiMeasureRest->setChecked(m_measure->breakMultiMeasureRest());
     198            0 :     int n  = m_measure->repeatCount();
     199            0 :     count->setValue(n);
     200            0 :     bool enableCount = m_measure->repeatEnd();
     201            0 :     count->setEnabled(enableCount);
     202            0 :     count->setVisible(enableCount);
     203            0 :     labelCount->setVisible(enableCount);
     204            0 :     layoutStretch->setValue(m_measure->userStretch());
     205            0 :     measureNumberMode->setCurrentIndex(int(m_measure->measureNumberMode()));
     206            0 :     measureNumberOffset->setValue(m_measure->measureNumberOffset());
     207              : 
     208            0 :     mu::engraving::Score* score = m_measure->score();
     209            0 :     size_t rows = score->nstaves();
     210            0 :     staves->setRowCount(static_cast<int>(rows));
     211            0 :     staves->setColumnCount(3);
     212              : 
     213            0 :     auto itemAccessibleText = [](const QTableWidgetItem* item){
     214            0 :         return item->data(ITEM_ACCESSIBLE_TITLE_ROLE).toString() + ": "
     215            0 :                + (item->checkState() == Qt::Checked ? muse::qtrc("ui", "checked", "checkstate") : muse::qtrc("ui", "unchecked",
     216            0 :                                                                                                              "checkstate"));
     217              :     };
     218              : 
     219            0 :     for (size_t staffIdx = 0; staffIdx < rows; ++staffIdx) {
     220            0 :         QTableWidgetItem* item = new QTableWidgetItem(QString("%1").arg(staffIdx + 1));
     221            0 :         staves->setItem(static_cast<int>(staffIdx), 0, item);
     222              : 
     223            0 :         item = new QTableWidgetItem();
     224            0 :         item->setFlags(item->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
     225            0 :         item->setCheckState(m_measure->visible(staffIdx) ? Qt::Checked : Qt::Unchecked);
     226            0 :         if (rows == 1) {                  // cannot be invisible if only one row
     227            0 :             item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
     228              :         }
     229            0 :         item->setData(ITEM_ACCESSIBLE_TITLE_ROLE, muse::qtrc("notation/measureproperties", "Visible"));
     230            0 :         item->setData(Qt::AccessibleTextRole, itemAccessibleText(item));
     231            0 :         staves->setItem(static_cast<int>(staffIdx), 1, item);
     232              : 
     233            0 :         item = new QTableWidgetItem();
     234            0 :         item->setFlags(item->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
     235            0 :         item->setCheckState(m_measure->stemless(staffIdx) ? Qt::Checked : Qt::Unchecked);
     236            0 :         item->setData(ITEM_ACCESSIBLE_TITLE_ROLE, muse::qtrc("notation/measureproperties", "Stemless"));
     237            0 :         item->setData(Qt::AccessibleTextRole, itemAccessibleText(item));
     238            0 :         staves->setItem(static_cast<int>(staffIdx), 2, item);
     239              :     }
     240              : 
     241            0 :     connect(staves, &QTableWidget::itemChanged, this, [&itemAccessibleText](QTableWidgetItem* item){
     242            0 :         item->setData(Qt::AccessibleTextRole, itemAccessibleText(item));
     243            0 :     });
     244            0 : }
     245              : 
     246              : //---------------------------------------------------------
     247              : //   bboxClicked
     248              : //---------------------------------------------------------
     249              : 
     250            0 : void MeasurePropertiesDialog::bboxClicked(QAbstractButton* button)
     251              : {
     252            0 :     switch (buttonBox->buttonRole(button)) {
     253            0 :     case QDialogButtonBox::ApplyRole:
     254              :     case QDialogButtonBox::AcceptRole:
     255            0 :         apply();
     256            0 :         break;
     257            0 :     default:
     258            0 :         break;
     259              :     }
     260            0 : }
     261              : 
     262              : //---------------------------------------------------------
     263              : //   visible
     264              : //---------------------------------------------------------
     265              : 
     266            0 : bool MeasurePropertiesDialog::visible(int staffIdx)
     267              : {
     268            0 :     QTableWidgetItem* item = staves->item(staffIdx, 1);
     269            0 :     return item->checkState() == Qt::Checked;
     270              : }
     271              : 
     272              : //---------------------------------------------------------
     273              : //   stemless
     274              : //---------------------------------------------------------
     275              : 
     276            0 : bool MeasurePropertiesDialog::stemless(int staffIdx)
     277              : {
     278            0 :     QTableWidgetItem* item = staves->item(staffIdx, 2);
     279            0 :     return item->checkState() == Qt::Checked;
     280              : }
     281              : 
     282              : //---------------------------------------------------------
     283              : //   sig
     284              : //---------------------------------------------------------
     285              : 
     286            0 : mu::engraving::Fraction MeasurePropertiesDialog::len() const
     287              : {
     288            0 :     return mu::engraving::Fraction(actualZ->value(), 1 << actualN->currentIndex());
     289              : }
     290              : 
     291              : //---------------------------------------------------------
     292              : //   repeatCount
     293              : //---------------------------------------------------------
     294              : 
     295            0 : int MeasurePropertiesDialog::repeatCount() const
     296              : {
     297            0 :     return count->value();
     298              : }
     299              : 
     300              : //---------------------------------------------------------
     301              : //   apply
     302              : //---------------------------------------------------------
     303              : 
     304            0 : void MeasurePropertiesDialog::apply()
     305              : {
     306            0 :     if (!m_notation || !m_measure) {
     307            0 :         return;
     308              :     }
     309              : 
     310            0 :     mu::engraving::Score* score = m_measure->score();
     311              : 
     312            0 :     m_notation->undoStack()->prepareChanges(muse::TranslatableString("undoableAction", "Edit measure properties"));
     313            0 :     bool propertiesChanged = false;
     314            0 :     for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
     315            0 :         bool v = visible(static_cast<int>(staffIdx));
     316            0 :         bool s = stemless(static_cast<int>(staffIdx));
     317            0 :         if (m_measure->visible(staffIdx) != v || m_measure->stemless(staffIdx) != s) {
     318            0 :             score->undo(new mu::engraving::ChangeMStaffProperties(m_measure, static_cast<int>(staffIdx), v, s));
     319            0 :             propertiesChanged = true;
     320              :         }
     321              :     }
     322              : 
     323            0 :     m_measure->undoChangeProperty(mu::engraving::Pid::REPEAT_COUNT, repeatCount());
     324            0 :     m_measure->undoChangeProperty(mu::engraving::Pid::BREAK_MMR, breakMultiMeasureRest->isChecked());
     325            0 :     m_measure->undoChangeProperty(mu::engraving::Pid::USER_STRETCH, layoutStretch->value());
     326            0 :     m_measure->undoChangeProperty(mu::engraving::Pid::MEASURE_NUMBER_MODE, measureNumberMode->currentIndex());
     327            0 :     m_measure->undoChangeProperty(mu::engraving::Pid::MEASURE_NUMBER_OFFSET, measureNumberOffset->value());
     328            0 :     m_measure->undoChangeProperty(mu::engraving::Pid::EXCLUDE_FROM_NUMBERING, excludeFromNumbering->isChecked());
     329              : 
     330            0 :     if (m_measure->ticks() != len()) {
     331            0 :         mu::engraving::ScoreRange range;
     332            0 :         range.read(m_measure->first(), m_measure->last());
     333            0 :         m_measure->adjustToLen(len());
     334            0 :     }
     335              : 
     336            0 :     if (propertiesChanged) {
     337            0 :         m_measure->triggerLayout();
     338              :     }
     339            0 :     m_notation->undoStack()->commitChanges();
     340              : 
     341            0 :     m_notation->interaction()->select({ m_measure }, mu::engraving::SelectType::SINGLE, 0);
     342            0 :     m_notation->notationChanged().send(muse::RectF());
     343              : }
     344              : 
     345            0 : void MeasurePropertiesDialog::showEvent(QShowEvent* event)
     346              : {
     347            0 :     WidgetStateStore::restoreGeometry(this);
     348            0 :     QDialog::showEvent(event);
     349            0 : }
     350              : 
     351            0 : void MeasurePropertiesDialog::hideEvent(QHideEvent* event)
     352              : {
     353            0 :     WidgetStateStore::saveGeometry(this);
     354            0 :     QDialog::hideEvent(event);
     355            0 : }
        

Generated by: LCOV version 2.0-1