LCOV - code coverage report
Current view: top level - src/palette/widgets - keyedit.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 254 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 <QDir>
      24              : #include <QAction>
      25              : #include <QMouseEvent>
      26              : #include <QDragEnterEvent>
      27              : #include <QMimeData>
      28              : #include <QVBoxLayout>
      29              : 
      30              : #include "keyedit.h"
      31              : 
      32              : #include "modularity/ioc.h"
      33              : #include "translation.h"
      34              : 
      35              : #include "engraving/dom/accidental.h"
      36              : #include "engraving/dom/clef.h"
      37              : #include "engraving/dom/dummyparent.h"
      38              : #include "engraving/dom/factory.h"
      39              : #include "engraving/dom/keysig.h"
      40              : #include "engraving/dom/masterscore.h"
      41              : #include "engraving/dom/mscore.h"
      42              : #include "engraving/rendering/iscorerenderer.h"
      43              : #include "engraving/rw/rwregister.h"
      44              : #include "engraving/style/defaultstyle.h"
      45              : #include "engraving/types/symnames.h"
      46              : 
      47              : #include "keycanvas.h"
      48              : #include "palettewidget.h"
      49              : #include "internal/palettecreator.h"
      50              : 
      51              : #include "log.h"
      52              : 
      53              : using namespace mu;
      54              : using namespace muse::draw;
      55              : using namespace mu::engraving;
      56              : using namespace mu::palette;
      57              : 
      58              : //---------------------------------------------------------
      59              : //   KeyCanvas
      60              : //---------------------------------------------------------
      61              : 
      62            0 : KeyCanvas::KeyCanvas(QWidget* parent)
      63            0 :     : QFrame(parent), muse::Contextable(muse::iocCtxForQWidget(this))
      64              : {
      65            0 :     setAcceptDrops(true);
      66            0 :     qreal mag = configuration()->paletteSpatium() * configuration()->paletteScaling()
      67            0 :                 / paletteScoreProvider()->paletteScore()->style().spatium();
      68            0 :     _matrix = QTransform(mag, 0.0, 0.0, mag, 0.0, 0.0);
      69            0 :     imatrix = _matrix.inverted();
      70            0 :     dragElement = 0;
      71            0 :     setFocusPolicy(Qt::StrongFocus);
      72            0 :     QAction* a = new QAction("delete", this);
      73            0 :     a->setShortcut(Qt::Key_Delete);
      74            0 :     addAction(a);
      75            0 :     clef = Factory::createClef(paletteScoreProvider()->paletteScore()->dummy());
      76            0 :     clef->setClefType(ClefType::G);
      77            0 :     connect(a, &QAction::triggered, this, &KeyCanvas::deleteElement);
      78            0 : }
      79              : 
      80              : //---------------------------------------------------------
      81              : //   delete
      82              : //---------------------------------------------------------
      83              : 
      84            0 : void KeyCanvas::deleteElement()
      85              : {
      86            0 :     foreach (Accidental* a, accidentals) {
      87            0 :         if (a->selected()) {
      88            0 :             accidentals.removeOne(a);
      89            0 :             delete a;
      90            0 :             update();
      91            0 :             break;
      92              :         }
      93            0 :     }
      94            0 : }
      95              : 
      96              : //---------------------------------------------------------
      97              : //   clear
      98              : //---------------------------------------------------------
      99              : 
     100            0 : void KeyCanvas::clear()
     101              : {
     102            0 :     foreach (Accidental* a, accidentals) {
     103            0 :         delete a;
     104            0 :     }
     105            0 :     accidentals.clear();
     106            0 :     update();
     107            0 : }
     108              : 
     109              : //---------------------------------------------------------
     110              : //   paintEvent
     111              : //---------------------------------------------------------
     112              : 
     113            0 : void KeyCanvas::paintEvent(QPaintEvent*)
     114              : {
     115            0 :     muse::draw::Painter painter(this, "keycanvas");
     116            0 :     painter.setAntialiasing(true);
     117            0 :     qreal wh = double(height());
     118            0 :     qreal ww = double(width());
     119            0 :     double y = wh * .5 - 2 * configuration()->paletteSpatium() * extraMag;
     120              : 
     121            0 :     const double paletteScoreSpatium = paletteScoreProvider()->paletteScore()->style().spatium();
     122            0 :     qreal mag  = configuration()->paletteSpatium() * extraMag / paletteScoreSpatium;
     123            0 :     _matrix    = QTransform(mag, 0.0, 0.0, mag, 0.0, y);
     124            0 :     imatrix    = _matrix.inverted();
     125              : 
     126            0 :     qreal x = 3;
     127            0 :     qreal w = ww - 6;
     128              : 
     129            0 :     painter.setWorldTransform(Transform::fromQTransform(_matrix));
     130              : 
     131            0 :     QRectF r = imatrix.mapRect(QRectF(x, y, w, wh));
     132              : 
     133            0 :     RectF background = RectF::fromQRectF(imatrix.mapRect(QRectF(0, 0, ww, wh)));
     134            0 :     painter.fillRect(background, notationConfiguration()->foregroundColor());
     135              : 
     136            0 :     rendering::PaintOptions opt;
     137            0 :     opt.invertColors = notationConfiguration()->shouldInvertScore();
     138              : 
     139            0 :     muse::draw::Pen pen(engravingConfiguration()->displayedDefaultColor(opt.invertColors));
     140            0 :     pen.setWidthF(engraving::DefaultStyle::defaultStyle().styleS(
     141            0 :                       Sid::staffLineWidth).val() * paletteScoreSpatium);
     142            0 :     painter.setPen(pen);
     143              : 
     144            0 :     for (int i = 0; i < 5; ++i) {
     145            0 :         qreal yy = r.y() + i * paletteScoreSpatium;
     146            0 :         painter.drawLine(LineF(r.x(), yy, r.x() + r.width(), yy));
     147              :     }
     148              : 
     149            0 :     const auto paletteRenderer = paletteScoreProvider()->paletteScore()->renderer();
     150            0 :     if (dragElement) {
     151            0 :         painter.save();
     152            0 :         painter.translate(dragElement->pagePos());
     153            0 :         paletteRenderer->drawItem(dragElement, &painter, opt);
     154            0 :         painter.restore();
     155              :     }
     156            0 :     foreach (Accidental* a, accidentals) {
     157            0 :         painter.save();
     158            0 :         painter.translate(a->pagePos());
     159            0 :         paletteRenderer->drawItem(a, &painter, opt);
     160            0 :         painter.restore();
     161            0 :     }
     162            0 :     clef->setPos(0.0, 0.0);
     163              : 
     164            0 :     engravingRender()->layoutItem(clef);
     165              : 
     166            0 :     painter.translate(clef->pagePos());
     167            0 :     paletteRenderer->drawItem(clef, &painter, opt);
     168            0 : }
     169              : 
     170              : //---------------------------------------------------------
     171              : //   mousePressEvent
     172              : //---------------------------------------------------------
     173              : 
     174            0 : void KeyCanvas::mousePressEvent(QMouseEvent* event)
     175              : {
     176            0 :     startMove = imatrix.map(QPointF(event->pos() - base));
     177            0 :     moveElement = 0;
     178            0 :     foreach (Accidental* a, accidentals) {
     179            0 :         QRectF r = a->pageBoundingRect().toQRectF();
     180            0 :         if (r.contains(startMove)) {
     181            0 :             a->setSelected(true);
     182            0 :             moveElement = a;
     183              :         } else {
     184            0 :             a->setSelected(false);
     185              :         }
     186            0 :     }
     187            0 :     update();
     188            0 : }
     189              : 
     190              : //---------------------------------------------------------
     191              : //   mouseMoveEvent
     192              : //---------------------------------------------------------
     193              : 
     194            0 : void KeyCanvas::mouseMoveEvent(QMouseEvent* event)
     195              : {
     196            0 :     if (moveElement == 0) {
     197            0 :         return;
     198              :     }
     199            0 :     QPointF p = imatrix.map(QPointF(event->pos()));
     200            0 :     QPointF delta = p - startMove;
     201            0 :     moveElement->move(PointF::fromQPointF(delta));
     202            0 :     startMove = p;
     203            0 :     update();
     204              : }
     205              : 
     206              : //---------------------------------------------------------
     207              : //   mouseReleaseEvent
     208              : //---------------------------------------------------------
     209              : 
     210            0 : void KeyCanvas::mouseReleaseEvent(QMouseEvent*)
     211              : {
     212            0 :     if (moveElement == 0) {
     213            0 :         return;
     214              :     }
     215            0 :     snap(moveElement);
     216            0 :     update();
     217              : }
     218              : 
     219              : //---------------------------------------------------------
     220              : //   dragEnterEvent
     221              : //---------------------------------------------------------
     222              : 
     223            0 : void KeyCanvas::dragEnterEvent(QDragEnterEvent* event)
     224              : {
     225            0 :     const QMimeData* dta = event->mimeData();
     226            0 :     if (dta->hasFormat(mimeSymbolFormat)) {
     227            0 :         QByteArray a = dta->data(mimeSymbolFormat);
     228            0 :         XmlReader e(a);
     229              : 
     230            0 :         PointF dragOffset;
     231            0 :         Fraction duration;
     232            0 :         ElementType type = EngravingItem::readType(e, &dragOffset, &duration);
     233            0 :         if (type != ElementType::ACCIDENTAL) {
     234            0 :             return;
     235              :         }
     236              : 
     237            0 :         event->acceptProposedAction();
     238            0 :         dragElement = static_cast<Accidental*>(Factory::createItem(type, paletteScoreProvider()->paletteScore()->dummy()));
     239              : 
     240            0 :         rw::RWRegister::reader()->readItem(dragElement, e);
     241            0 :         engravingRender()->layoutItem(dragElement);
     242            0 :     } else {
     243            0 :         if (MScore::debugMode) {
     244            0 :             LOGD("KeyCanvas::dragEnterEvent: formats:");
     245            0 :             foreach (const QString& s, event->mimeData()->formats()) {
     246            0 :                 LOGD("   %s", qPrintable(s));
     247            0 :             }
     248              :         }
     249              :     }
     250              : }
     251              : 
     252              : //---------------------------------------------------------
     253              : //   dragMoveEvent
     254              : //---------------------------------------------------------
     255              : 
     256            0 : void KeyCanvas::dragMoveEvent(QDragMoveEvent* event)
     257              : {
     258            0 :     if (dragElement) {
     259            0 :         event->acceptProposedAction();
     260            0 :         PointF pos = PointF::fromQPointF(imatrix.map(event->position()));
     261            0 :         dragElement->setPos(pos);
     262            0 :         update();
     263              :     }
     264            0 : }
     265              : 
     266              : //---------------------------------------------------------
     267              : //   dropEvent
     268              : //---------------------------------------------------------
     269              : 
     270            0 : void KeyCanvas::dropEvent(QDropEvent*)
     271              : {
     272            0 :     for (Accidental* a : accidentals) {
     273            0 :         a->setSelected(false);
     274              :     }
     275            0 :     dragElement->setSelected(true);
     276            0 :     accidentals.append(dragElement);
     277            0 :     snap(dragElement);
     278            0 :     dragElement = 0;
     279            0 :     update();
     280            0 : }
     281              : 
     282              : //---------------------------------------------------------
     283              : //   snap
     284              : //---------------------------------------------------------
     285              : 
     286            0 : void KeyCanvas::snap(Accidental* a)
     287              : {
     288            0 :     double _spatium = paletteScoreProvider()->paletteScore()->style().spatium();
     289            0 :     double spatium2 = _spatium * .5;
     290            0 :     double y = a->ldata()->pos().y();
     291            0 :     double x = KEYEDIT_ACC_ZERO_POINT * _spatium;
     292            0 :     int line = round(y / spatium2);
     293            0 :     y = line * spatium2;
     294            0 :     a->mutldata()->setPosY(y);
     295              :     // take default xposition unless Control is pressed
     296            0 :     int i = accidentals.indexOf(a);
     297            0 :     if (i > 0) {
     298            0 :         qreal accidentalGap = DefaultStyle::baseStyle().styleS(Sid::keysigAccidentalDistance).val() * _spatium;
     299            0 :         Accidental* prev = accidentals[i - 1];
     300            0 :         double prevX = prev->ldata()->pos().x();
     301            0 :         qreal prevWidth = prev->symWidth(prev->symId());
     302            0 :         x = prevX + prevWidth + accidentalGap;
     303              :     }
     304            0 :     if (!QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) {
     305            0 :         a->mutldata()->setPosX(x);
     306              :     }
     307            0 : }
     308              : 
     309              : //---------------------------------------------------------
     310              : //   KeyEditor
     311              : //---------------------------------------------------------
     312              : 
     313            0 : KeyEditor::KeyEditor(QWidget* parent)
     314            0 :     : QWidget(parent), muse::Contextable(muse::iocCtxForQWidget(this))
     315              : {
     316            0 :     setupUi(this);
     317              : 
     318            0 :     QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Expanding);
     319              : 
     320              :     // create key signature palette
     321              : 
     322            0 :     QLayout* layout = new QVBoxLayout();
     323            0 :     layout->setContentsMargins(0, 0, 0, 0);
     324            0 :     keySigframe->setLayout(layout);
     325              : 
     326            0 :     m_keySigPaletteWidget = new PaletteWidget(this, true /*setIocContext*/);
     327            0 :     m_keySigPaletteWidget->setPalette(PaletteCreator(iocContext()).newKeySigPalette());
     328            0 :     m_keySigPaletteWidget->setReadOnly(false);
     329              : 
     330            0 :     m_keySigArea = new PaletteScrollArea(m_keySigPaletteWidget);
     331            0 :     m_keySigArea->setSizePolicy(policy);
     332            0 :     m_keySigArea->setRestrictHeight(false);
     333            0 :     m_keySigArea->setFocusProxy(m_keySigPaletteWidget);
     334            0 :     m_keySigArea->setFocusPolicy(Qt::TabFocus);
     335              : 
     336            0 :     layout->addWidget(m_keySigArea);
     337              : 
     338              :     // create accidental palette
     339              : 
     340            0 :     layout = new QVBoxLayout();
     341            0 :     layout->setContentsMargins(0, 0, 0, 0);
     342            0 :     accidentalsFrame->setLayout(layout);
     343              : 
     344            0 :     m_accidentalsPaletteWidget = new PaletteWidget(this, true /*setIocContext*/);
     345            0 :     m_accidentalsPaletteWidget->setPalette(PaletteCreator(iocContext()).newAccidentalsPalette());
     346            0 :     qreal adj = m_accidentalsPaletteWidget->mag();
     347            0 :     m_accidentalsPaletteWidget->setGridSize(m_accidentalsPaletteWidget->gridWidth() / adj, m_accidentalsPaletteWidget->gridHeight() / adj);
     348            0 :     m_accidentalsPaletteWidget->setMag(1.0);
     349              : 
     350            0 :     PaletteScrollArea* accidentalsPaletteArea = new PaletteScrollArea(m_accidentalsPaletteWidget);
     351            0 :     accidentalsPaletteArea->setSizePolicy(policy);
     352            0 :     accidentalsPaletteArea->setRestrictHeight(false);
     353            0 :     accidentalsPaletteArea->setFocusProxy(m_accidentalsPaletteWidget);
     354            0 :     accidentalsPaletteArea->setFocusPolicy(Qt::TabFocus);
     355              : 
     356            0 :     layout->addWidget(accidentalsPaletteArea);
     357              : 
     358            0 :     connect(addButton, &QPushButton::clicked, this, &KeyEditor::addClicked);
     359            0 :     connect(clearButton, &QPushButton::clicked, this, &KeyEditor::clearClicked);
     360            0 :     connect(m_keySigPaletteWidget, &PaletteWidget::changed, this, &KeyEditor::setDirty);
     361              : 
     362              :     //
     363              :     // set all "builtin" key signatures to read only
     364              :     //
     365            0 :     int n = m_keySigPaletteWidget->actualCellCount();
     366            0 :     for (int i = 0; i < n; ++i) {
     367            0 :         m_keySigPaletteWidget->setCellReadOnly(i, true);
     368              :     }
     369              : 
     370            0 :     if (!configuration()->useFactorySettings()) {
     371            0 :         m_keySigPaletteWidget->readFromFile(configuration()->keySignaturesDirPath().toQString());
     372              :     }
     373              : 
     374              :     //! NOTE: It is necessary for the correct start of navigation in the dialog
     375            0 :     setFocus();
     376            0 : }
     377              : 
     378              : //---------------------------------------------------------
     379              : //   addClicked
     380              : //---------------------------------------------------------
     381              : 
     382            0 : void KeyEditor::addClicked()
     383              : {
     384            0 :     const QList<Accidental*> al = canvas->getAccidentals();
     385            0 :     double spatium = paletteScoreProvider()->paletteScore()->style().spatium();
     386            0 :     double xoff = KEYEDIT_ACC_ZERO_POINT * spatium;
     387              : 
     388            0 :     KeySigEvent e;
     389            0 :     e.setCustom(true);
     390            0 :     Spatium accidentalGap = DefaultStyle::baseStyle().styleS(Sid::keysigAccidentalDistance);
     391            0 :     for (int i = 0; i < al.size(); ++i) {
     392            0 :         Accidental* a = al[i];
     393            0 :         CustDef c;
     394            0 :         c.sym = a->symId();
     395            0 :         PointF pos = a->ldata()->pos();
     396            0 :         c.xAlt = Spatium::fromAbsolute(pos.x() - xoff, spatium);
     397            0 :         if (i > 0) {
     398            0 :             Accidental* prev = al[i - 1];
     399            0 :             PointF prevPos = prev->ldata()->pos();
     400            0 :             qreal prevWidth = prev->symWidth(prev->symId());
     401            0 :             c.xAlt -= Spatium::fromAbsolute(prevPos.x() - xoff + prevWidth, spatium) + accidentalGap;
     402              :         }
     403            0 :         int line = static_cast<int>(round((pos.y() / spatium) * 2));
     404            0 :         bool flat = std::string(SymNames::nameForSymId(c.sym).ascii()).find("Flat") != std::string::npos;
     405            0 :         c.degree = (3 - line) % 7;
     406            0 :         c.degree += (c.degree < 0) ? 7 : 0;
     407            0 :         line += flat ? -1 : 1; // top accidentals in treble clef are gis (#), or es (b)
     408            0 :         c.octAlt = static_cast<int>((line - (line >= 0 ? 0 : 6)) / 7);
     409            0 :         e.customKeyDefs().push_back(c);
     410              :     }
     411            0 :     auto ks = Factory::makeKeySig(paletteScoreProvider()->paletteScore()->dummy());
     412            0 :     ks->setKeySigEvent(e);
     413            0 :     m_keySigPaletteWidget->appendElement(ks, "custom");
     414            0 :     m_dirty = true;
     415              : 
     416            0 :     paletteProvider()->addCustomItemRequested().send(ks);
     417            0 : }
     418              : 
     419              : //---------------------------------------------------------
     420              : //   clearClicked
     421              : //---------------------------------------------------------
     422              : 
     423            0 : void KeyEditor::clearClicked()
     424              : {
     425            0 :     canvas->clear();
     426            0 : }
     427              : 
     428              : //---------------------------------------------------------
     429              : //   showKeyPalette
     430              : //---------------------------------------------------------
     431              : 
     432            0 : void KeyEditor::setShowKeyPalette(bool showKeyPalette)
     433              : {
     434            0 :     m_keySigArea->setVisible(showKeyPalette);
     435            0 : }
     436              : 
     437              : //---------------------------------------------------------
     438              : //   save
     439              : //---------------------------------------------------------
     440              : 
     441            0 : void KeyEditor::save()
     442              : {
     443            0 :     QDir dir;
     444            0 :     dir.mkpath(configuration()->keySignaturesDirPath().toQString());
     445            0 :     m_keySigPaletteWidget->writeToFile(configuration()->keySignaturesDirPath().toQString());
     446            0 : }
     447              : 
     448            0 : bool KeyEditor::showKeyPalette() const
     449              : {
     450            0 :     return m_keySigArea->isVisible();
     451              : }
     452              : 
     453            0 : KeyEditorDialog::KeyEditorDialog(QWidget* parent)
     454            0 :     : muse::ui::WidgetDialog(parent)
     455              : {
     456            0 :     setWindowTitle(muse::qtrc("palette", "Key signatures"));
     457            0 :     setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
     458            0 : }
     459              : 
     460            0 : void KeyEditorDialog::classBegin()
     461              : {
     462            0 :     m_keyEditor = new KeyEditor(this);
     463            0 :     QVBoxLayout* layout = new QVBoxLayout(this);
     464            0 :     layout->setContentsMargins(0, 0, 0, 0);
     465            0 :     layout->setSizeConstraint(QLayout::SetFixedSize);
     466            0 :     layout->addWidget(m_keyEditor);
     467            0 : }
     468              : 
     469            0 : bool KeyEditorDialog::showKeyPalette() const
     470              : {
     471            0 :     return m_keyEditor->showKeyPalette();
     472              : }
     473              : 
     474            0 : void KeyEditorDialog::setShowKeyPalette(bool showKeyPalette)
     475              : {
     476            0 :     m_keyEditor->setShowKeyPalette(showKeyPalette);
     477            0 : }
        

Generated by: LCOV version 2.0-1