LCOV - code coverage report
Current view: top level - src/notationscene/widgets - timeline.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 1740 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 "timeline.h"
      24              : 
      25              : #include <QApplication>
      26              : #include <QGraphicsTextItem>
      27              : #include <QMenu>
      28              : #include <QMouseEvent>
      29              : #include <QScrollBar>
      30              : #include <QTextDocument>
      31              : 
      32              : #include "translation.h"
      33              : 
      34              : #include "engraving/dom/barline.h"
      35              : #include "engraving/dom/jump.h"
      36              : #include "engraving/dom/key.h"
      37              : #include "engraving/dom/keysig.h"
      38              : #include "engraving/dom/marker.h"
      39              : #include "engraving/dom/measure.h"
      40              : #include "engraving/dom/measurebase.h"
      41              : #include "engraving/dom/mscore.h"
      42              : #include "engraving/dom/page.h"
      43              : #include "engraving/dom/part.h"
      44              : #include "engraving/dom/rehearsalmark.h"
      45              : #include "engraving/dom/score.h"
      46              : #include "engraving/dom/staff.h"
      47              : #include "engraving/dom/system.h"
      48              : #include "engraving/dom/tempotext.h"
      49              : #include "engraving/dom/timesig.h"
      50              : #include "engraving/types/typesconv.h"
      51              : 
      52              : #include "notation/inotationelements.h" // IWYU pragma: keep
      53              : #include "notation/inotationinteraction.h"
      54              : #include "notation/inotationselection.h"
      55              : #include "notation/inotationundostack.h" // IWYU pragma: keep
      56              : 
      57              : #include "instrumentsscene/instrumentscommands.h"
      58              : 
      59              : #include "log.h"
      60              : 
      61              : using namespace mu::notation;
      62              : using namespace mu::engraving;
      63              : using namespace mu::instrumentsscene;
      64              : 
      65              : using namespace Qt::StringLiterals;
      66              : 
      67              : //---------------------------------------------------------
      68              : //   TRowLabels
      69              : //---------------------------------------------------------
      70              : 
      71            0 : TRowLabels::TRowLabels(QSplitter* splitter, Timeline* time)
      72            0 :     : QGraphicsView(splitter)
      73              : {
      74            0 :     TRACEFUNC;
      75              : 
      76            0 :     setFocusPolicy(Qt::NoFocus);
      77            0 :     setObjectName("TRowLabels");
      78              : 
      79            0 :     _splitter = splitter;
      80            0 :     _timeline = time;
      81            0 :     setScene(new QGraphicsScene);
      82            0 :     scene()->setBackgroundBrush(time->activeTheme().backgroundColor);
      83            0 :     setSceneRect(0, 0, 50, time->height());
      84              : 
      85            0 :     setMinimumWidth(0);
      86              : 
      87            0 :     QSplitter* split = _splitter;
      88            0 :     QList<int> sizes;
      89              :     // TODO: Replace 70 with hard coded value
      90            0 :     sizes << 70 << 10000;
      91            0 :     split->setSizes(sizes);
      92              : 
      93            0 :     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
      94            0 :     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
      95            0 :     setContentsMargins(0, 0, 0, 0);
      96            0 :     setAlignment(Qt::Alignment((Qt::AlignLeft | Qt::AlignTop)));
      97              : 
      98            0 :     connect(verticalScrollBar(), &QScrollBar::valueChanged, time->verticalScrollBar(), &QScrollBar::setValue);
      99            0 :     connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &TRowLabels::restrictScroll);
     100            0 :     connect(this, &TRowLabels::moved, time, &Timeline::mouseOver);
     101              : 
     102              :     static const char* udArrow[] = {
     103              :         "10 18 2 1",
     104              :         "# c #000000",
     105              :         ". c #d3d3d3",
     106              :         "..........",
     107              :         "..........",
     108              :         "....##....",
     109              :         "...####...",
     110              :         "..##..##..",
     111              :         "..#....#..",
     112              :         "..........",
     113              :         "..........",
     114              :         "..........",
     115              :         "..........",
     116              :         "..........",
     117              :         "..........",
     118              :         "..#....#..",
     119              :         "..##..##..",
     120              :         "...####...",
     121              :         "....##....",
     122              :         "..........",
     123              :         ".........."
     124              :     };
     125              : 
     126              :     static const char* uArrow[] = {
     127              :         "10 18 2 1",
     128              :         "# c #000000",
     129              :         ". c #d3d3d3",
     130              :         "..........",
     131              :         "..........",
     132              :         "....##....",
     133              :         "...####...",
     134              :         "..##..##..",
     135              :         "..#....#..",
     136              :         "..........",
     137              :         "..........",
     138              :         "..........",
     139              :         "..........",
     140              :         "..........",
     141              :         "..........",
     142              :         "..........",
     143              :         "..........",
     144              :         "..........",
     145              :         "..........",
     146              :         "..........",
     147              :         ".........."
     148              :     };
     149              : 
     150              :     static const char* dArrow[] = {
     151              :         "10 18 2 1",
     152              :         "# c #000000",
     153              :         ". c #d3d3d3",
     154              :         "..........",
     155              :         "..........",
     156              :         "..........",
     157              :         "..........",
     158              :         "..........",
     159              :         "..........",
     160              :         "..........",
     161              :         "..........",
     162              :         "..........",
     163              :         "..........",
     164              :         "..........",
     165              :         "..........",
     166              :         "..#....#..",
     167              :         "..##..##..",
     168              :         "...####...",
     169              :         "....##....",
     170              :         "..........",
     171              :         ".........."
     172              :     };
     173              : 
     174              :     static const char* cuArrow[] = {
     175              :         "9 18 2 1",
     176              :         "# c #000000",
     177              :         ". c #d3d3d3",
     178              :         ".........",
     179              :         ".........",
     180              :         ".........",
     181              :         ".........",
     182              :         "....#....",
     183              :         "...###...",
     184              :         "..#.#.#..",
     185              :         ".#..#..#.",
     186              :         "....#....",
     187              :         "....#....",
     188              :         "....#....",
     189              :         "....#....",
     190              :         ".........",
     191              :         ".........",
     192              :         ".........",
     193              :         ".........",
     194              :         ".........",
     195              :         "........."
     196              :     };
     197              : 
     198              :     static const char* cdArrow[] = {
     199              :         "9 18 2 1",
     200              :         "# c #000000",
     201              :         ". c #d3d3d3",
     202              :         ".........",
     203              :         ".........",
     204              :         ".........",
     205              :         ".........",
     206              :         ".........",
     207              :         "....#....",
     208              :         "....#....",
     209              :         "....#....",
     210              :         "....#....",
     211              :         "....#....",
     212              :         ".#..#..#.",
     213              :         "..#.#.#..",
     214              :         "...###...",
     215              :         "....#....",
     216              :         ".........",
     217              :         ".........",
     218              :         ".........",
     219              :         "........."
     220              :     };
     221              : 
     222              :     static const char* openEye[] = {
     223              :         "11 18 2 1",
     224              :         "# c #000000",
     225              :         ". c #d3d3d3",
     226              :         "...........",
     227              :         "...........",
     228              :         "...........",
     229              :         "...........",
     230              :         "...####....",
     231              :         ".##....##..",
     232              :         ".#......#..",
     233              :         "#........#.",
     234              :         "#...##...#.",
     235              :         "#...##...#.",
     236              :         "#........#.",
     237              :         ".#......#..",
     238              :         ".##....##..",
     239              :         "...####....",
     240              :         "...........",
     241              :         "...........",
     242              :         "...........",
     243              :         "..........."
     244              :     };
     245              : 
     246              :     static const char* closedEye[] = {
     247              :         "11 18 2 1",
     248              :         "# c #000000",
     249              :         ". c #d3d3d3",
     250              :         "...........",
     251              :         "...........",
     252              :         "...........",
     253              :         "...........",
     254              :         "...........",
     255              :         "...........",
     256              :         "...........",
     257              :         "..######...",
     258              :         "##..##..##.",
     259              :         "##..##..##.",
     260              :         "..######...",
     261              :         "...........",
     262              :         "...........",
     263              :         "...........",
     264              :         "...........",
     265              :         "...........",
     266              :         "...........",
     267              :         "..........."
     268              :     };
     269              : 
     270            0 :     _mouseoverMap[MouseOverValue::COLLAPSE_DOWN_ARROW] = new QPixmap(cdArrow);
     271            0 :     _mouseoverMap[MouseOverValue::COLLAPSE_UP_ARROW] = new QPixmap(cuArrow);
     272            0 :     _mouseoverMap[MouseOverValue::MOVE_DOWN_ARROW] = new QPixmap(dArrow);
     273            0 :     _mouseoverMap[MouseOverValue::MOVE_UP_DOWN_ARROW] = new QPixmap(udArrow);
     274            0 :     _mouseoverMap[MouseOverValue::MOVE_UP_ARROW] = new QPixmap(uArrow);
     275            0 :     _mouseoverMap[MouseOverValue::OPEN_EYE] = new QPixmap(openEye);
     276            0 :     _mouseoverMap[MouseOverValue::CLOSED_EYE] = new QPixmap(closedEye);
     277              : 
     278            0 :     std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned> tmp(nullptr, MouseOverValue::NONE, -1);
     279            0 :     _oldItemInfo = tmp;
     280              : 
     281            0 :     connect(this, &TRowLabels::requestContextMenu, _timeline, &Timeline::contextMenuEvent);
     282            0 : }
     283              : 
     284            0 : bool TRowLabels::handleEvent(QEvent* e)
     285              : {
     286            0 :     return QWidget::event(e);
     287              : }
     288              : 
     289              : //---------------------------------------------------------
     290              : //   TRowLabels::restrictScroll
     291              : //---------------------------------------------------------
     292              : 
     293            0 : void TRowLabels::restrictScroll(int value)
     294              : {
     295            0 :     TRACEFUNC;
     296              : 
     297            0 :     if (value > _timeline->verticalScrollBar()->maximum()) {
     298            0 :         verticalScrollBar()->setValue(_timeline->verticalScrollBar()->maximum());
     299              :     }
     300            0 :     for (std::vector<std::pair<QGraphicsItem*, int> >::iterator it = _metaLabels.begin();
     301            0 :          it != _metaLabels.end(); ++it) {
     302            0 :         std::pair<QGraphicsItem*, int> pairGraphicInt = *it;
     303              : 
     304            0 :         QGraphicsItem* graphicsItem = pairGraphicInt.first;
     305              : 
     306            0 :         QGraphicsRectItem* graphicsRectItem = qgraphicsitem_cast<QGraphicsRectItem*>(graphicsItem);
     307            0 :         QGraphicsLineItem* graphicsLineItem = qgraphicsitem_cast<QGraphicsLineItem*>(graphicsItem);
     308            0 :         QGraphicsPixmapItem* graphicsPixmapItem = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphicsItem);
     309            0 :         int y = pairGraphicInt.second * 20;
     310            0 :         int scrollbarValue = verticalScrollBar()->value();
     311              : 
     312            0 :         if (graphicsRectItem) {
     313            0 :             QRectF rectf = graphicsRectItem->rect();
     314            0 :             rectf.setY(qreal(scrollbarValue + y));
     315            0 :             rectf.setHeight(20);
     316            0 :             graphicsRectItem->setRect(rectf);
     317            0 :         } else if (graphicsLineItem) {
     318            0 :             QLineF linef = graphicsLineItem->line();
     319            0 :             linef.setLine(linef.x1(), y + scrollbarValue + 1, linef.x2(), y + scrollbarValue + 1);
     320            0 :             graphicsLineItem->setLine(linef);
     321            0 :         } else if (graphicsPixmapItem) {
     322            0 :             graphicsPixmapItem->setY(qreal(scrollbarValue + y + 1));
     323              :         } else {
     324            0 :             graphicsItem->setY(qreal(scrollbarValue + y));
     325              :         }
     326              :     }
     327            0 :     viewport()->update();
     328            0 : }
     329              : 
     330              : //---------------------------------------------------------
     331              : //   TRowLabels::updateLabels
     332              : //---------------------------------------------------------
     333              : 
     334            0 : void TRowLabels::updateLabels(std::vector<std::pair<QString, bool> > labels, int height)
     335              : {
     336            0 :     TRACEFUNC;
     337              : 
     338            0 :     scene()->clear();
     339            0 :     _metaLabels.clear();
     340            0 :     if (labels.empty()) {
     341            0 :         return;
     342              :     }
     343              : 
     344            0 :     unsigned numMetas = _timeline->nmetas();
     345            0 :     int maxWidth = -1;
     346            0 :     int measureWidth = 0;
     347            0 :     for (unsigned row = 0; row < labels.size(); row++) {
     348              :         // Draw instrument name rectangle
     349            0 :         int ypos = (row < numMetas) ? row * height + verticalScrollBar()->value() : row * height + 3;
     350            0 :         QGraphicsRectItem* graphicsRectItem = new QGraphicsRectItem(0, ypos, width(), height);
     351            0 :         QGraphicsTextItem* graphicsTextItem = new QGraphicsTextItem(labels[row].first);
     352              : 
     353            0 :         if (row == numMetas - 1) {
     354            0 :             measureWidth = graphicsTextItem->boundingRect().width();
     355              :         }
     356            0 :         maxWidth = std::max(maxWidth, int(graphicsTextItem->boundingRect().width()));
     357              : 
     358            0 :         QFontMetrics f(QApplication::font());
     359            0 :         QString partName = f.elidedText(labels[row].first, Qt::ElideRight, width());
     360            0 :         graphicsTextItem->setPlainText(partName);
     361            0 :         graphicsTextItem->setX(0);
     362            0 :         graphicsTextItem->setY(ypos);
     363            0 :         if (labels[row].second) {
     364            0 :             graphicsTextItem->setDefaultTextColor(_timeline->activeTheme().labelsColor1);
     365              :         } else {
     366            0 :             graphicsTextItem->setDefaultTextColor(_timeline->activeTheme().labelsColor2);
     367              :         }
     368            0 :         graphicsRectItem->setPen(QPen(_timeline->activeTheme().labelsColor2));
     369            0 :         graphicsRectItem->setBrush(QBrush(_timeline->activeTheme().labelsColor3));
     370            0 :         graphicsTextItem->setZValue(-1);
     371            0 :         graphicsRectItem->setZValue(-1);
     372              : 
     373            0 :         graphicsRectItem->setData(0, QVariant::fromValue<bool>(false));
     374            0 :         graphicsTextItem->setData(0, QVariant::fromValue<bool>(false));
     375              : 
     376            0 :         MouseOverValue mouseOverArrow = MouseOverValue::NONE;
     377            0 :         if (numMetas - 1 == row && (numMetas > 2 || _timeline->collapsed())) {
     378              :             // Measures meta
     379            0 :             if (_timeline->collapsed()) {
     380            0 :                 mouseOverArrow = MouseOverValue::COLLAPSE_DOWN_ARROW;
     381              :             } else {
     382            0 :                 mouseOverArrow = MouseOverValue::COLLAPSE_UP_ARROW;
     383              :             }
     384            0 :         } else if (row < numMetas - 1) {
     385            0 :             if (row != 0 && row + 1 <= numMetas - 2) {
     386            0 :                 mouseOverArrow = MouseOverValue::MOVE_UP_DOWN_ARROW;
     387            0 :             } else if (row == 0 && row + 1 < numMetas - 1) {
     388            0 :                 mouseOverArrow = MouseOverValue::MOVE_DOWN_ARROW;
     389            0 :             } else if (row == numMetas - 2 && row != 0) {
     390            0 :                 mouseOverArrow = MouseOverValue::MOVE_UP_ARROW;
     391              :             }
     392            0 :         } else if (numMetas <= row) {
     393            0 :             if (_timeline->numToStaff(row - numMetas)
     394            0 :                 && _timeline->numToStaff(row - numMetas)->show()) {
     395            0 :                 mouseOverArrow = MouseOverValue::OPEN_EYE;
     396              :             } else {
     397            0 :                 mouseOverArrow = MouseOverValue::CLOSED_EYE;
     398              :             }
     399              :         }
     400            0 :         graphicsTextItem->setData(1, QVariant::fromValue<MouseOverValue>(mouseOverArrow));
     401            0 :         graphicsRectItem->setData(1, QVariant::fromValue<MouseOverValue>(mouseOverArrow));
     402              : 
     403            0 :         graphicsTextItem->setData(2, QVariant::fromValue<unsigned>(row));
     404            0 :         graphicsRectItem->setData(2, QVariant::fromValue<unsigned>(row));
     405              : 
     406            0 :         scene()->addItem(graphicsRectItem);
     407            0 :         scene()->addItem(graphicsTextItem);
     408            0 :         if (row < numMetas) {
     409            0 :             std::pair<QGraphicsItem*, int> p1 = std::make_pair(graphicsRectItem, row);
     410            0 :             std::pair<QGraphicsItem*, int> p2 = std::make_pair(graphicsTextItem, row);
     411            0 :             _metaLabels.push_back(p1);
     412            0 :             _metaLabels.push_back(p2);
     413            0 :             graphicsRectItem->setZValue(1);
     414            0 :             graphicsTextItem->setZValue(2);
     415              :         }
     416            0 :     }
     417              :     QGraphicsLineItem* graphicsLineItem = new QGraphicsLineItem(0,
     418            0 :                                                                 height * numMetas + verticalScrollBar()->value() + 1,
     419            0 :                                                                 std::max(maxWidth + 20, 70),
     420            0 :                                                                 height * numMetas + verticalScrollBar()->value() + 1);
     421            0 :     graphicsLineItem->setPen(QPen(QColor(150, 150, 150), 4));
     422            0 :     graphicsLineItem->setZValue(0);
     423            0 :     graphicsLineItem->setData(0, QVariant::fromValue<bool>(false));
     424            0 :     scene()->addItem(graphicsLineItem);
     425              : 
     426            0 :     std::pair<QGraphicsItem*, int> graphicsLineItemPair = std::make_pair(graphicsLineItem, numMetas);
     427            0 :     _metaLabels.push_back(graphicsLineItemPair);
     428              : 
     429            0 :     setSceneRect(0, 0, maxWidth, _timeline->getHeight() + _timeline->horizontalScrollBar()->height());
     430              : 
     431            0 :     std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned> tmp(nullptr, MouseOverValue::NONE, -1);
     432            0 :     _oldItemInfo = tmp;
     433              : 
     434            0 :     setMinimumWidth(measureWidth + 9);
     435            0 :     setMaximumWidth(std::max(maxWidth + 20, 70));
     436            0 :     mouseOver(mapToScene(mapFromGlobal(QCursor::pos())));
     437            0 : }
     438              : 
     439              : //---------------------------------------------------------
     440              : //   TRowLabels::resizeEvent
     441              : //---------------------------------------------------------
     442              : 
     443            0 : void TRowLabels::resizeEvent(QResizeEvent*)
     444              : {
     445            0 :     std::vector<std::pair<QString, bool> > labels = _timeline->getLabels();
     446            0 :     updateLabels(labels, 20);
     447            0 : }
     448              : 
     449              : //---------------------------------------------------------
     450              : //   TRowLabels::mousePressEvent
     451              : //---------------------------------------------------------
     452              : 
     453            0 : void TRowLabels::mousePressEvent(QMouseEvent* event)
     454              : {
     455            0 :     if (event->button() == Qt::RightButton) {
     456            0 :         return;
     457              :     }
     458              : 
     459            0 :     TRACEFUNC;
     460              : 
     461            0 :     QPointF scenePt = mapToScene(event->pos());
     462            0 :     unsigned numMetas = _timeline->nmetas();
     463              : 
     464              :     // Check if mouse position in scene is on the last meta
     465            0 :     QPointF measureMetaTl = QPointF(0, (numMetas - 1) * 20 + verticalScrollBar()->value());
     466            0 :     QPointF measureMetaBr = QPointF(width(), numMetas * 20 + verticalScrollBar()->value());
     467            0 :     if (QRectF(measureMetaTl, measureMetaBr).contains(scenePt) && (numMetas > 2 || _timeline->collapsed())) {
     468            0 :         if (std::get<0>(_oldItemInfo)) {
     469            0 :             std::pair<QGraphicsItem*, int> p = std::make_pair(std::get<0>(_oldItemInfo), std::get<2>(_oldItemInfo));
     470            0 :             std::vector<std::pair<QGraphicsItem*, int> >::iterator it = std::find(_metaLabels.begin(), _metaLabels.end(), p);
     471            0 :             if (it != _metaLabels.end()) {
     472            0 :                 _metaLabels.erase(it);
     473              :             }
     474            0 :             scene()->removeItem(std::get<0>(_oldItemInfo));
     475              :         }
     476            0 :         std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned> tmp(nullptr, MouseOverValue::NONE, -1);
     477            0 :         _oldItemInfo = tmp;
     478            0 :         mouseOver(mapToScene(mapFromGlobal(QCursor::pos())));
     479              : 
     480            0 :         _timeline->setCollapsed(!_timeline->collapsed());
     481            0 :         _timeline->updateGridView();
     482              :     } else {
     483              :         // Check if pixmap was selected
     484            0 :         if (QGraphicsItem* graphicsItem = scene()->itemAt(scenePt, transform())) {
     485            0 :             QGraphicsPixmapItem* graphicsPixmapItem = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphicsItem);
     486            0 :             if (graphicsPixmapItem) {
     487            0 :                 unsigned row = graphicsPixmapItem->data(2).value<unsigned>();
     488            0 :                 if (row == numMetas - 1) {
     489            0 :                     return;
     490            0 :                 } else if (row < numMetas - 1) {
     491              :                     // Find mid point between up and down arrow
     492            0 :                     qreal midPoint = graphicsPixmapItem->boundingRect().height() / 2 + graphicsPixmapItem->scenePos().y();
     493            0 :                     if (scenePt.y() > midPoint) {
     494            0 :                         emit swapMeta(row, false);
     495              :                     } else {
     496            0 :                         emit swapMeta(row, true);
     497              :                     }
     498            0 :                 } else if (row >= numMetas) {
     499            0 :                     _timeline->toggleShow(row - numMetas);
     500              :                 }
     501              :             } else {
     502            0 :                 _dragging = true;
     503            0 :                 setCursor(Qt::SizeAllCursor);
     504            0 :                 _oldLoc = QPoint(int(scenePt.x()), int(scenePt.y()));
     505              :             }
     506              :         } else {
     507            0 :             _dragging = true;
     508            0 :             setCursor(Qt::SizeAllCursor);
     509            0 :             _oldLoc = QPoint(int(scenePt.x()), int(scenePt.y()));
     510              :         }
     511              :     }
     512            0 : }
     513              : 
     514              : //---------------------------------------------------------
     515              : //   TRowLabels::mouseMoveEvent
     516              : //---------------------------------------------------------
     517              : 
     518            0 : void TRowLabels::mouseMoveEvent(QMouseEvent* event)
     519              : {
     520            0 :     QPointF scenePt = mapToScene(event->pos());
     521            0 :     if (_dragging) {
     522            0 :         setCursor(Qt::SizeAllCursor);
     523            0 :         int yOffset = int(_oldLoc.y()) - int(scenePt.y());
     524            0 :         verticalScrollBar()->setValue(verticalScrollBar()->value() + yOffset);
     525              :     } else {
     526            0 :         mouseOver(scenePt);
     527              :     }
     528            0 :     emit moved(QPointF(-1, -1));
     529            0 : }
     530              : 
     531              : //---------------------------------------------------------
     532              : //   TRowLabels::mouseReleaseEvent
     533              : //---------------------------------------------------------
     534              : 
     535            0 : void TRowLabels::mouseReleaseEvent(QMouseEvent* event)
     536              : {
     537            0 :     if (QGraphicsItem* graphicsItem = scene()->itemAt(mapToScene(event->pos()), transform())) {
     538            0 :         QGraphicsPixmapItem* graphicsPixmapItem = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphicsItem);
     539            0 :         if (graphicsPixmapItem) {
     540            0 :             setCursor(Qt::PointingHandCursor);
     541              :         } else {
     542            0 :             setCursor(Qt::ArrowCursor);
     543              :         }
     544              :     } else {
     545            0 :         setCursor(Qt::ArrowCursor);
     546              :     }
     547            0 :     _dragging = false;
     548            0 : }
     549              : 
     550              : //---------------------------------------------------------
     551              : //   TRowLabels::leaveEvent
     552              : //---------------------------------------------------------
     553              : 
     554            0 : void TRowLabels::leaveEvent(QEvent*)
     555              : {
     556            0 :     if (!rect().contains(mapFromGlobal(QCursor::pos()))) {
     557            0 :         mouseOver(mapToScene(mapFromGlobal(QCursor::pos())));
     558              :     }
     559            0 : }
     560              : 
     561              : //---------------------------------------------------------
     562              : //   TRowLabels::contextMenuEvent
     563              : //---------------------------------------------------------
     564              : 
     565            0 : void TRowLabels::contextMenuEvent(QContextMenuEvent* event)
     566              : {
     567            0 :     emit requestContextMenu(event);
     568            0 : }
     569              : 
     570              : //---------------------------------------------------------
     571              : //   TRowLabels::mouseOver
     572              : //---------------------------------------------------------
     573              : 
     574            0 : void TRowLabels::mouseOver(QPointF scenePt)
     575              : {
     576            0 :     TRACEFUNC;
     577              : 
     578              :     // Handle drawing of arrows
     579            0 :     if (QGraphicsItem* graphicsItem = scene()->itemAt(scenePt, transform())) {
     580            0 :         QGraphicsPixmapItem* graphicsPixmapItem = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphicsItem);
     581            0 :         if (graphicsPixmapItem) {
     582            0 :             setCursor(Qt::PointingHandCursor);
     583            0 :             return;
     584              :         }
     585              : 
     586            0 :         MouseOverValue mouseOverArrow = graphicsItem->data(1).value<MouseOverValue>();
     587            0 :         if (mouseOverArrow != MouseOverValue::NONE) {
     588            0 :             QPixmap* pixmapArrow = _mouseoverMap[mouseOverArrow];
     589            0 :             QGraphicsPixmapItem* graphicsPixmapItemArrow = new QGraphicsPixmapItem(*pixmapArrow);
     590            0 :             unsigned row = graphicsItem->data(2).value<unsigned>();
     591              : 
     592            0 :             QString tooltip;
     593            0 :             switch (mouseOverArrow) {
     594            0 :             case MouseOverValue::COLLAPSE_DOWN_ARROW:
     595            0 :                 tooltip = muse::qtrc("notation/timeline", "Expand meta rows");
     596            0 :                 break;
     597            0 :             case MouseOverValue::COLLAPSE_UP_ARROW:
     598            0 :                 tooltip = muse::qtrc("notation/timeline", "Collapse meta rows");
     599            0 :                 break;
     600            0 :             case MouseOverValue::MOVE_DOWN_ARROW:
     601            0 :                 tooltip = muse::qtrc("notation/timeline", "Move meta row down one");
     602            0 :                 break;
     603            0 :             case MouseOverValue::MOVE_UP_ARROW:
     604            0 :                 tooltip = muse::qtrc("notation/timeline", "Move meta row up one");
     605            0 :                 break;
     606            0 :             case MouseOverValue::MOVE_UP_DOWN_ARROW:
     607            0 :                 tooltip = muse::qtrc("notation/timeline", "Move meta row up/down one");
     608            0 :                 break;
     609            0 :             case MouseOverValue::OPEN_EYE:
     610            0 :                 tooltip = muse::qtrc("notation/timeline", "Hide instrument in score");
     611            0 :                 break;
     612            0 :             case MouseOverValue::CLOSED_EYE:
     613            0 :                 tooltip = muse::qtrc("notation/timeline", "Show instrument in score");
     614            0 :                 break;
     615            0 :             default:
     616            0 :                 tooltip = "";
     617            0 :                 break;
     618              :             }
     619              : 
     620            0 :             graphicsPixmapItemArrow->setToolTip(tooltip);
     621            0 :             if (mouseOverArrow == MouseOverValue::OPEN_EYE || mouseOverArrow == MouseOverValue::CLOSED_EYE) {
     622            0 :                 graphicsPixmapItemArrow->setData(0, QVariant::fromValue<bool>(false));
     623              :             } else {
     624            0 :                 graphicsPixmapItemArrow->setData(0, QVariant::fromValue<bool>(true));
     625              :             }
     626            0 :             graphicsPixmapItemArrow->setData(1, QVariant::fromValue<MouseOverValue>(mouseOverArrow));
     627            0 :             graphicsPixmapItemArrow->setData(2, QVariant::fromValue<unsigned>(row));
     628              : 
     629              :             // Draw arrow at correct location
     630            0 :             if (row < _timeline->nmetas()) {
     631            0 :                 graphicsPixmapItemArrow->setPos(width() - 12, verticalScrollBar()->value() + 1 + row * 20);
     632            0 :                 graphicsPixmapItemArrow->setZValue(3);
     633              :             } else {
     634            0 :                 graphicsPixmapItemArrow->setPos(width() - 13, row * 20 + 5);
     635            0 :                 graphicsPixmapItemArrow->setZValue(-1);
     636              :             }
     637              : 
     638            0 :             if (std::get<2>(_oldItemInfo) == row && std::get<1>(_oldItemInfo) == mouseOverArrow) {
     639              :                 // DO NOTHING
     640              :             } else {
     641            0 :                 if (std::get<0>(_oldItemInfo)) {
     642            0 :                     std::pair<QGraphicsItem*, int> p = std::make_pair(std::get<0>(_oldItemInfo), std::get<2>(_oldItemInfo));
     643            0 :                     std::vector<std::pair<QGraphicsItem*, int> >::iterator it = std::find(_metaLabels.begin(), _metaLabels.end(), p);
     644            0 :                     if (it != _metaLabels.end()) {
     645            0 :                         _metaLabels.erase(it);
     646              :                     }
     647            0 :                     scene()->removeItem(std::get<0>(_oldItemInfo));
     648              :                 }
     649            0 :                 std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned> tmp(graphicsPixmapItemArrow, mouseOverArrow, row);
     650            0 :                 _oldItemInfo = tmp;
     651            0 :                 if (mouseOverArrow != MouseOverValue::OPEN_EYE && mouseOverArrow != MouseOverValue::CLOSED_EYE) {
     652            0 :                     std::pair<QGraphicsItem*, int> p = std::make_pair(graphicsPixmapItemArrow, row);
     653            0 :                     _metaLabels.push_back(p);
     654              :                 }
     655            0 :                 scene()->addItem(graphicsPixmapItemArrow);
     656              :             }
     657            0 :         } else {
     658            0 :             if (std::get<0>(_oldItemInfo)) {
     659            0 :                 scene()->removeItem(std::get<0>(_oldItemInfo));
     660              :             }
     661            0 :             std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned> tmp(nullptr, MouseOverValue::NONE, -1);
     662            0 :             _oldItemInfo = tmp;
     663              :         }
     664              :     } else {
     665            0 :         if (std::get<0>(_oldItemInfo)) {
     666            0 :             std::pair<QGraphicsItem*, int> p = std::make_pair(std::get<0>(_oldItemInfo), std::get<2>(_oldItemInfo));
     667            0 :             std::vector<std::pair<QGraphicsItem*, int> >::iterator it = std::find(_metaLabels.begin(), _metaLabels.end(), p);
     668            0 :             if (it != _metaLabels.end()) {
     669            0 :                 _metaLabels.erase(it);
     670              :             }
     671            0 :             scene()->removeItem(std::get<0>(_oldItemInfo));
     672              :         }
     673            0 :         std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned> tmp(nullptr, MouseOverValue::NONE, -1);
     674            0 :         _oldItemInfo = tmp;
     675              :     }
     676            0 :     if (QGraphicsItem* graphicsItem = scene()->itemAt(scenePt, transform())) {
     677            0 :         QGraphicsPixmapItem* graphicsPixmapItem = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphicsItem);
     678            0 :         if (graphicsPixmapItem) {
     679            0 :             setCursor(Qt::PointingHandCursor);
     680              :         } else {
     681            0 :             setCursor(Qt::ArrowCursor);
     682              :         }
     683              :     } else {
     684            0 :         setCursor(Qt::ArrowCursor);
     685              :     }
     686            0 : }
     687              : 
     688              : //---------------------------------------------------------
     689              : //   TRiwLabels::cursorIsOn
     690              : //---------------------------------------------------------
     691              : 
     692            0 : QString TRowLabels::cursorIsOn()
     693              : {
     694            0 :     QPointF scenePos = mapToScene(mapFromGlobal(QCursor::pos()));
     695            0 :     QGraphicsItem* graphicsItem = scene()->itemAt(scenePos, transform());
     696            0 :     if (graphicsItem) {
     697            0 :         auto it = _metaLabels.begin();
     698            0 :         for (; it != _metaLabels.end(); ++it) {
     699            0 :             if ((*it).first == graphicsItem) {
     700            0 :                 break;
     701              :             }
     702              :         }
     703            0 :         if (it != _metaLabels.end()) {
     704            0 :             return "meta";
     705              :         } else {
     706            0 :             return "instrument";
     707              :         }
     708              :     } else {
     709            0 :         return "";
     710              :     }
     711              : }
     712              : 
     713              : //---------------------------------------------------------
     714              : //   Timeline
     715              : //---------------------------------------------------------
     716              : 
     717            0 : Timeline::Timeline(QSplitter* splitter, const muse::modularity::ContextPtr& iocCtx)
     718            0 :     : QGraphicsView(splitter), muse::Contextable(iocCtx)
     719              : {
     720            0 :     TRACEFUNC;
     721              : 
     722            0 :     setFocusPolicy(Qt::NoFocus);
     723            0 :     setAlignment(Qt::Alignment((Qt::AlignLeft | Qt::AlignTop)));
     724            0 :     setAttribute(Qt::WA_OpaquePaintEvent);
     725            0 :     setObjectName("Timeline");
     726              : 
     727              :     // theming
     728            0 :     _lightTheme.backgroundColor      = QColor(Qt::lightGray);
     729            0 :     _lightTheme.labelsColor1         = QColor(Qt::black);
     730            0 :     _lightTheme.labelsColor2         = QColor(150, 150, 150);
     731            0 :     _lightTheme.labelsColor3         = QColor(211, 211, 211);
     732            0 :     _lightTheme.gridColor1           = QColor(150, 150, 150);
     733            0 :     _lightTheme.gridColor2           = QColor(211, 211, 211);
     734            0 :     _lightTheme.measureMetaColor     = QColor(0, 0, 0);
     735            0 :     _lightTheme.selectionColor       = QColor(173, 216, 230);
     736            0 :     _lightTheme.nonVisiblePenColor   = QColor(100, 150, 250);
     737            0 :     _lightTheme.nonVisibleBrushColor = QColor(192, 192, 192, 180);
     738            0 :     _lightTheme.colorBoxColor        = QColor(Qt::gray);
     739            0 :     _lightTheme.metaValuePenColor    = QColor(Qt::black);
     740            0 :     _lightTheme.metaValueBrushColor  = QColor(Qt::gray);
     741              : 
     742            0 :     _darkTheme.backgroundColor       = QColor(35, 35, 35);
     743            0 :     _darkTheme.labelsColor1          = QColor(225, 225, 225);
     744            0 :     _darkTheme.labelsColor2          = QColor(55, 55, 55);
     745            0 :     _darkTheme.labelsColor3          = QColor(70, 70, 70);
     746            0 :     _darkTheme.gridColor1            = QColor(50, 50, 50);
     747            0 :     _darkTheme.gridColor2            = QColor(75, 75, 75);
     748            0 :     _darkTheme.measureMetaColor      = QColor(200, 200, 200);
     749            0 :     _darkTheme.selectionColor        = QColor(55, 70, 75);
     750            0 :     _darkTheme.nonVisiblePenColor    = QColor(40, 60, 80);
     751            0 :     _darkTheme.nonVisibleBrushColor  = QColor(55, 55, 55, 180);
     752            0 :     _darkTheme.colorBoxColor         = QColor(Qt::gray);
     753            0 :     _darkTheme.metaValuePenColor     = QColor(Qt::lightGray);
     754            0 :     _darkTheme.metaValueBrushColor   = QColor(Qt::darkGray);
     755              : 
     756            0 :     _splitter = splitter;
     757            0 :     _rowNames = new TRowLabels(splitter, this);
     758            0 :     _splitter->addWidget(_rowNames);
     759            0 :     _splitter->addWidget(this);
     760            0 :     _splitter->setChildrenCollapsible(false);
     761            0 :     _splitter->setStretchFactor(0, 0);
     762            0 :     _splitter->setStretchFactor(1, 0);
     763              : 
     764            0 :     setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
     765              : 
     766            0 :     setScene(new QGraphicsScene);
     767            0 :     setSceneRect(0, 0, 100, 100);
     768            0 :     scene()->setBackgroundBrush(QBrush(activeTheme().backgroundColor));
     769              : 
     770            0 :     connect(verticalScrollBar(), &QScrollBar::valueChanged, _rowNames->verticalScrollBar(), &QScrollBar::setValue);
     771            0 :     connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &Timeline::handleScroll);
     772            0 :     connect(_rowNames, &TRowLabels::swapMeta, this, &Timeline::swapMeta);
     773            0 :     connect(this, &Timeline::moved, _rowNames, &TRowLabels::mouseOver);
     774              : 
     775            0 :     _metas.push_back({ muse::qtrc("notation/timeline", "Tempo"), &Timeline::tempoMeta, true });
     776            0 :     _metas.push_back({ muse::qtrc("notation/timeline", "Time signature"), &Timeline::timeMeta, true });
     777            0 :     _metas.push_back({ muse::qtrc("notation/timeline", "Rehearsal mark"), &Timeline::rehearsalMeta, true });
     778            0 :     _metas.push_back({ muse::qtrc("notation/timeline", "Key signature"), &Timeline::keyMeta, true });
     779            0 :     _metas.push_back({ muse::qtrc("notation/timeline", "Barlines"), &Timeline::barlineMeta, true });
     780            0 :     _metas.push_back({ muse::qtrc("notation/timeline", "Jumps and markers"), &Timeline::jumpMarkerMeta, true });
     781            0 :     _metas.push_back({ muse::qtrc("notation/timeline", "Measures"), &Timeline::measureMeta, true });
     782              : 
     783            0 :     std::tuple<QGraphicsItem*, int, QColor> ohi(nullptr, -1, QColor());
     784            0 :     _oldHoverInfo = ohi;
     785            0 :     std::tuple<int, qreal, EngravingItem*, EngravingItem*, bool> ri(0, 0, nullptr, nullptr, false);
     786            0 :     _repeatInfo = ri;
     787              : 
     788              :     static const char* startRepeat[] = {
     789              :         "7 14 2 1",
     790              :         "# c #000000",
     791              :         ". c None",
     792              :         "##.#...",
     793              :         "##.#...",
     794              :         "##.#...",
     795              :         "##.#...",
     796              :         "##.#.##",
     797              :         "##.#.##",
     798              :         "##.#...",
     799              :         "##.#...",
     800              :         "##.#.##",
     801              :         "##.#.##",
     802              :         "##.#...",
     803              :         "##.#...",
     804              :         "##.#...",
     805              :         "##.#..."
     806              :     };
     807              : 
     808              :     static const char* endRepeat[] = {
     809              :         "7 14 2 1",
     810              :         "# c #000000",
     811              :         ". c None",
     812              :         "...#.##",
     813              :         "...#.##",
     814              :         "...#.##",
     815              :         "...#.##",
     816              :         "##.#.##",
     817              :         "##.#.##",
     818              :         "...#.##",
     819              :         "...#.##",
     820              :         "##.#.##",
     821              :         "##.#.##",
     822              :         "...#.##",
     823              :         "...#.##",
     824              :         "...#.##",
     825              :         "...#.##"
     826              :     };
     827              : 
     828              :     static const char* endBarline[] = {
     829              :         "7 14 2 1",
     830              :         "# c #000000",
     831              :         ". c None",
     832              :         "...#.##",
     833              :         "...#.##",
     834              :         "...#.##",
     835              :         "...#.##",
     836              :         "...#.##",
     837              :         "...#.##",
     838              :         "...#.##",
     839              :         "...#.##",
     840              :         "...#.##",
     841              :         "...#.##",
     842              :         "...#.##",
     843              :         "...#.##",
     844              :         "...#.##",
     845              :         "...#.##"
     846              :     };
     847              : 
     848              :     static const char* doubleBarline[] = {
     849              :         "7 14 2 1",
     850              :         "# c #000000",
     851              :         ". c None",
     852              :         "..#.#..",
     853              :         "..#.#..",
     854              :         "..#.#..",
     855              :         "..#.#..",
     856              :         "..#.#..",
     857              :         "..#.#..",
     858              :         "..#.#..",
     859              :         "..#.#..",
     860              :         "..#.#..",
     861              :         "..#.#..",
     862              :         "..#.#..",
     863              :         "..#.#..",
     864              :         "..#.#..",
     865              :         "..#.#.."
     866              :     };
     867              : 
     868              :     static const char* reverseEndBarline[] = {
     869              :         "7 14 2 1",
     870              :         "# c #000000",
     871              :         ". c None",
     872              :         "##.#...",
     873              :         "##.#...",
     874              :         "##.#...",
     875              :         "##.#...",
     876              :         "##.#...",
     877              :         "##.#...",
     878              :         "##.#...",
     879              :         "##.#...",
     880              :         "##.#...",
     881              :         "##.#...",
     882              :         "##.#...",
     883              :         "##.#...",
     884              :         "##.#...",
     885              :         "##.#..."
     886              :     };
     887              : 
     888              :     static const char* heavyBarline[] = {
     889              :         "6 14 2 1",
     890              :         "# c #000000",
     891              :         ". c None",
     892              :         "..##..",
     893              :         "..##..",
     894              :         "..##..",
     895              :         "..##..",
     896              :         "..##..",
     897              :         "..##..",
     898              :         "..##..",
     899              :         "..##..",
     900              :         "..##..",
     901              :         "..##..",
     902              :         "..##..",
     903              :         "..##..",
     904              :         "..##..",
     905              :         "..##.."
     906              :     };
     907              : 
     908              :     static const char* doubleHeavyBarline[] = {
     909              :         "7 14 2 1",
     910              :         "# c #000000",
     911              :         ". c None",
     912              :         ".##.##.",
     913              :         ".##.##.",
     914              :         ".##.##.",
     915              :         ".##.##.",
     916              :         ".##.##.",
     917              :         ".##.##.",
     918              :         ".##.##.",
     919              :         ".##.##.",
     920              :         ".##.##.",
     921              :         ".##.##.",
     922              :         ".##.##.",
     923              :         ".##.##.",
     924              :         ".##.##.",
     925              :         ".##.##."
     926              :     };
     927              : 
     928            0 :     QPixmap* startRepeatPixmap = new QPixmap(startRepeat);
     929            0 :     QPixmap* endRepeatPixmap = new QPixmap(endRepeat);
     930            0 :     QPixmap* endBarlinePixmap = new QPixmap(endBarline);
     931            0 :     QPixmap* doubleBarlinePixmap = new QPixmap(doubleBarline);
     932            0 :     QPixmap* reverseEndBarlinePixmap = new QPixmap(reverseEndBarline);
     933            0 :     QPixmap* heavyBarlinePixmap = new QPixmap(heavyBarline);
     934            0 :     QPixmap* doubleHeavyBarlinePixmap = new QPixmap(doubleHeavyBarline);
     935              : 
     936            0 :     _barlines[BarLineType::START_REPEAT] = startRepeatPixmap;
     937            0 :     _barlines[BarLineType::END_REPEAT] = endRepeatPixmap;
     938            0 :     _barlines[BarLineType::END] = endBarlinePixmap;
     939            0 :     _barlines[BarLineType::DOUBLE] = doubleBarlinePixmap;
     940            0 :     _barlines[BarLineType::REVERSE_END] = reverseEndBarlinePixmap;
     941            0 :     _barlines[BarLineType::HEAVY] = heavyBarlinePixmap;
     942            0 :     _barlines[BarLineType::DOUBLE_HEAVY] = doubleHeavyBarlinePixmap;
     943              : 
     944            0 :     uiConfiguration()->currentThemeChanged().onNotify(this, [this]() {
     945            0 :         updateTimelineTheme();
     946            0 :     });
     947            0 : }
     948              : 
     949            0 : bool Timeline::handleEvent(QEvent* e)
     950              : {
     951            0 :     return QWidget::event(e);
     952              : }
     953              : 
     954              : //---------------------------------------------------------
     955              : //   Timeline::drawGrid
     956              : //---------------------------------------------------------
     957              : 
     958            0 : void Timeline::drawGrid(int globalRows, int globalCols, int startMeasure, int endMeasure)
     959              : {
     960            0 :     TRACEFUNC;
     961              : 
     962            0 :     if (endMeasure < 0) {
     963            0 :         endMeasure = globalCols;
     964              :     }
     965            0 :     if (startMeasure < 0) {
     966            0 :         endMeasure = startMeasure;
     967              :     }
     968              : 
     969            0 :     const bool rebuildAll = (
     970            0 :         gridRows != globalRows || gridCols != globalCols
     971            0 :         || (startMeasure == 0 && 2 * (endMeasure - startMeasure) > globalCols)  // rebuild all if more than half of score has changed
     972              :         );
     973            0 :     const bool rebuildPartial = !rebuildAll && (startMeasure >= 0);
     974              : 
     975            0 :     const unsigned numMetas = nmetas();
     976              : 
     977            0 :     if (rebuildAll) {
     978            0 :         clearScene();
     979            0 :         startMeasure = 0;
     980            0 :         endMeasure = globalCols;
     981              :     } else {
     982            0 :         if (rebuildPartial) {
     983              :             const QRectF replacedRect
     984            0 :                 = getMeasureRect(startMeasure, 0, numMetas) | getMeasureRect(endMeasure - 1, globalRows - 1, numMetas);
     985            0 :             const QList<QGraphicsItem*> replacedItems = scene()->items(replacedRect, Qt::ContainsItemShape);
     986            0 :             for (QGraphicsItem* item : replacedItems) {
     987            0 :                 if (item->data(keyItemType).value<ItemType>() != ItemType::TYPE_MEASURE) {
     988            0 :                     continue;
     989              :                 }
     990            0 :                 scene()->removeItem(item);
     991            0 :                 delete item;
     992              :             }
     993            0 :         }
     994              : 
     995              :         // Meta rows are still rebuilt from scratch, remove old meta rows manually
     996            0 :         const QList<QGraphicsItem*> items = scene()->items();
     997            0 :         for (QGraphicsItem* item : items) {
     998            0 :             if (item->data(keyItemType).value<ItemType>() != ItemType::TYPE_META) {
     999            0 :                 continue;
    1000              :             }
    1001            0 :             scene()->removeItem(item);
    1002            0 :             delete item;
    1003              :         }
    1004            0 :     }
    1005              : 
    1006            0 :     _metaRows.clear();
    1007              : 
    1008            0 :     if (globalRows == 0 || globalCols == 0) {
    1009            0 :         return;
    1010              :     }
    1011              : 
    1012            0 :     int stagger = 0;
    1013            0 :     setMinimumHeight(_gridHeight * (numMetas + 1) + 5 + horizontalScrollBar()->height());
    1014            0 :     setMinimumWidth(_gridWidth * 3);
    1015            0 :     _globalZValue = 1;
    1016              : 
    1017              :     // Draw grid
    1018            0 :     Measure* currMeasure = score()->firstMeasure();
    1019            0 :     for (int i = 0; i < startMeasure; ++i) {
    1020            0 :         currMeasure = currMeasure->nextMeasure();
    1021              :     }
    1022              : 
    1023            0 :     QList<Part*> partList = getParts();
    1024              : 
    1025            0 :     for (int col = startMeasure; col < endMeasure; col++) {
    1026            0 :         for (int row = 0; row < globalRows; row++) {
    1027            0 :             QGraphicsRectItem* graphicsRectItem = new QGraphicsRectItem(getMeasureRect(col, row, numMetas));
    1028            0 :             graphicsRectItem->setData(keyItemType, QVariant::fromValue(ItemType::TYPE_MEASURE));
    1029              : 
    1030            0 :             setMetaData(graphicsRectItem, row, ElementType::INVALID, currMeasure, false, 0);
    1031              : 
    1032            0 :             QString translateMeasure = muse::qtrc("notation/timeline", "Measure");
    1033            0 :             QChar initialLetter = translateMeasure[0];
    1034            0 :             QTextDocument doc;
    1035            0 :             QString partName = "";
    1036            0 :             if (partList.size() > row) {
    1037            0 :                 doc.setHtml(partList.at(row)->longName());
    1038            0 :                 partName = doc.toPlainText();
    1039            0 :                 if (partName.isEmpty()) {         // No Long instrument name? Fall back to Part name
    1040            0 :                     doc.setHtml(partList.at(row)->partName());
    1041            0 :                     partName = doc.toPlainText();
    1042              :                 }
    1043            0 :                 if (partName.isEmpty()) {       // No Part name? Fall back to Instrument name
    1044            0 :                     partName = partList.at(row)->instrumentName();
    1045              :                 }
    1046              :             }
    1047              : 
    1048            0 :             graphicsRectItem->setToolTip(initialLetter + u" "_s + QString::number(currMeasure->measureNumber() + 1) + u", "_s + partName);
    1049            0 :             graphicsRectItem->setPen(QPen(activeTheme().backgroundColor));
    1050            0 :             graphicsRectItem->setBrush(QBrush(colorBox(graphicsRectItem)));
    1051            0 :             graphicsRectItem->setZValue(-3);
    1052            0 :             scene()->addItem(graphicsRectItem);
    1053            0 :         }
    1054              : 
    1055            0 :         currMeasure = currMeasure->nextMeasure();
    1056              :     }
    1057            0 :     setSceneRect(0, 0, getWidth(), getHeight());
    1058              : 
    1059              :     // Draw meta rows and separator
    1060              :     QGraphicsLineItem* graphicsLineItemSeparator = new QGraphicsLineItem(0,
    1061            0 :                                                                          _gridHeight * numMetas + verticalScrollBar()->value() + 1,
    1062            0 :                                                                          getWidth() - 1,
    1063            0 :                                                                          _gridHeight * numMetas + verticalScrollBar()->value() + 1);
    1064            0 :     graphicsLineItemSeparator->setData(keyItemType, QVariant::fromValue(ItemType::TYPE_META));
    1065            0 :     graphicsLineItemSeparator->setPen(QPen(activeTheme().gridColor1, 4));
    1066            0 :     graphicsLineItemSeparator->setZValue(-2);
    1067            0 :     scene()->addItem(graphicsLineItemSeparator);
    1068            0 :     std::pair<QGraphicsItem*, int> pairGraphicsIntSeparator(graphicsLineItemSeparator, numMetas);
    1069            0 :     _metaRows.push_back(pairGraphicsIntSeparator);
    1070              : 
    1071            0 :     for (unsigned row = 0; row < numMetas; row++) {
    1072              :         QGraphicsRectItem* metaRow = new QGraphicsRectItem(0,
    1073            0 :                                                            _gridHeight * row + verticalScrollBar()->value(),
    1074            0 :                                                            getWidth(),
    1075            0 :                                                            _gridHeight);
    1076            0 :         metaRow->setData(keyItemType, QVariant::fromValue(ItemType::TYPE_META));
    1077            0 :         metaRow->setBrush(QBrush(activeTheme().gridColor2));
    1078            0 :         metaRow->setPen(QPen(activeTheme().gridColor1));
    1079            0 :         metaRow->setData(0, QVariant::fromValue<int>(-1));
    1080              : 
    1081            0 :         scene()->addItem(metaRow);
    1082              : 
    1083            0 :         std::pair<QGraphicsItem*, int> pairGraphicsIntMeta(metaRow, row);
    1084            0 :         _metaRows.push_back(pairGraphicsIntMeta);
    1085              :     }
    1086              : 
    1087            0 :     int xPos = 0;
    1088              : 
    1089              :     // Create stagger array if _collapsedMeta is false
    1090            0 :     std::vector<int> staggerArr(numMetas, 0);    // Default initialized, loop not required
    1091              : 
    1092            0 :     bool noKey = true;
    1093            0 :     std::get<4>(_repeatInfo) = false;
    1094              : 
    1095            0 :     for (Measure* cm = score()->firstMeasure(); cm; cm = cm->nextMeasure()) {
    1096            0 :         for (Segment* currSeg = cm->first(); currSeg; currSeg = currSeg->next()) {
    1097              :             // Toggle noKey if initial key signature is found
    1098            0 :             if (currSeg->isKeySigType() && cm == score()->firstMeasure()) {
    1099            0 :                 if (noKey && currSeg->tick().isZero()) {
    1100            0 :                     noKey = false;
    1101              :                 }
    1102              :             }
    1103              : 
    1104              :             // If no initial key signature is found, add key signature
    1105            0 :             if (cm == score()->firstMeasure() && noKey
    1106            0 :                 && (currSeg->isTimeSigType() || currSeg->isChordRestType())) {
    1107            0 :                 if (getMetaRow(muse::qtrc("notation/timeline", "Key signature")) != numMetas) {
    1108            0 :                     if (_collapsedMeta) {
    1109            0 :                         keyMeta(0, &stagger, xPos);
    1110              :                     } else {
    1111            0 :                         keyMeta(0, &staggerArr[getMetaRow(muse::qtrc("notation/timeline", "Key signature"))], xPos);
    1112              :                     }
    1113              :                 }
    1114            0 :                 noKey = false;
    1115              :             }
    1116            0 :             int row = 0;
    1117            0 :             for (auto it = _metas.begin(); it != _metas.end(); ++it) {
    1118            0 :                 std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> meta = *it;
    1119            0 :                 if (!std::get<2>(meta)) {
    1120            0 :                     continue;
    1121              :                 }
    1122            0 :                 void (Timeline::* func)(Segment*, int*, int) = std::get<1>(meta);
    1123            0 :                 if (_collapsedMeta) {
    1124            0 :                     (this->*func)(currSeg, &stagger, xPos);
    1125              :                 } else {
    1126            0 :                     (this->*func)(currSeg, &staggerArr[row], xPos);
    1127              :                 }
    1128            0 :                 row++;
    1129            0 :             }
    1130              :         }
    1131              :         // Handle all jumps here
    1132            0 :         if (getMetaRow(muse::qtrc("notation/timeline", "Jumps and markers")) != numMetas) {
    1133            0 :             ElementList measureElementsList = cm->el();
    1134            0 :             for (EngravingItem* element : measureElementsList) {
    1135            0 :                 std::get<3>(_repeatInfo) = element;
    1136            0 :                 if (element->isMarker()) {
    1137            0 :                     jumpMarkerMeta(0, &stagger, xPos);
    1138              :                 }
    1139              :             }
    1140            0 :             for (EngravingItem* element : measureElementsList) {
    1141            0 :                 if (element->isJump()) {
    1142            0 :                     std::get<2>(_repeatInfo) = element;
    1143            0 :                     if (_collapsedMeta) {
    1144            0 :                         jumpMarkerMeta(0, &stagger, xPos);
    1145              :                     } else {
    1146            0 :                         jumpMarkerMeta(0, &std::get<0>(_repeatInfo), xPos);
    1147              :                     }
    1148              :                 }
    1149              :             }
    1150            0 :         }
    1151            0 :         stagger = 0;
    1152            0 :         std::get<0>(_repeatInfo) = 0;
    1153              : 
    1154            0 :         for (unsigned row = 0; row < numMetas; row++) {
    1155            0 :             staggerArr[row] = 0;
    1156              :         }
    1157            0 :         xPos += _gridWidth;
    1158            0 :         std::get<4>(_repeatInfo) = false;
    1159              :     }
    1160              : 
    1161            0 :     gridRows = globalRows;
    1162            0 :     gridCols = globalCols;
    1163            0 : }
    1164              : 
    1165              : //---------------------------------------------------------
    1166              : //   Timeline::tempoMeta
    1167              : //---------------------------------------------------------
    1168              : 
    1169            0 : void Timeline::tempoMeta(Segment* seg, int* stagger, int pos)
    1170              : {
    1171              :     // Find position of tempoMeta in metas
    1172            0 :     int row = getMetaRow(muse::qtrc("notation/timeline", "Tempo"));
    1173              : 
    1174              :     // Add all tempo texts in this segment
    1175            0 :     const std::vector<EngravingItem*> annotations = seg->annotations();
    1176            0 :     for (EngravingItem* element : annotations) {
    1177            0 :         if (element->isTempoText()) {
    1178            0 :             TempoText* text = toTempoText(element);
    1179            0 :             qreal x = pos + (*stagger) * _spacing;
    1180            0 :             if (addMetaValue(x, pos, text->plainText(), row, ElementType::TEMPO_TEXT, element, 0, seg->measure())) {
    1181            0 :                 (*stagger)++;
    1182            0 :                 _globalZValue++;
    1183              :             }
    1184              :         }
    1185              :     }
    1186            0 : }
    1187              : 
    1188              : //---------------------------------------------------------
    1189              : //   Timeline::timeMeta
    1190              : //---------------------------------------------------------
    1191              : 
    1192            0 : void Timeline::timeMeta(Segment* seg, int* stagger, int pos)
    1193              : {
    1194            0 :     if (!seg->isTimeSigType()) {
    1195            0 :         return;
    1196              :     }
    1197              : 
    1198            0 :     TRACEFUNC;
    1199              : 
    1200            0 :     int x = pos + (*stagger) * _spacing;
    1201              : 
    1202              :     // Find position of timeMeta in metas
    1203            0 :     int row = getMetaRow(muse::qtrc("notation/timeline", "Time signature"));
    1204              : 
    1205            0 :     TimeSig* originalTimeSig = toTimeSig(seg->element(0));
    1206            0 :     if (!originalTimeSig) {
    1207            0 :         return;
    1208              :     }
    1209              : 
    1210              :     // Check if same across all staves
    1211            0 :     const size_t nrows = score()->staves().size();
    1212            0 :     bool same = true;
    1213            0 :     for (size_t track = 0; track < nrows; track++) {
    1214            0 :         const TimeSig* currTimeSig = toTimeSig(seg->element(track * VOICES));
    1215            0 :         if (!currTimeSig) {
    1216            0 :             same = false;
    1217            0 :             break;
    1218              :         }
    1219            0 :         if (*currTimeSig == *originalTimeSig) {
    1220            0 :             continue;
    1221              :         }
    1222            0 :         same = false;
    1223            0 :         break;
    1224              :     }
    1225            0 :     if (!same) {
    1226            0 :         return;
    1227              :     }
    1228            0 :     QString text = QString::number(originalTimeSig->numerator()) + QString("/") + QString::number(originalTimeSig->denominator());
    1229              : 
    1230            0 :     if (addMetaValue(x, pos, text, row, ElementType::TIMESIG, 0, seg, seg->measure())) {
    1231            0 :         (*stagger)++;
    1232            0 :         _globalZValue++;
    1233              :     }
    1234            0 : }
    1235              : 
    1236              : //---------------------------------------------------------
    1237              : //   Timeline::rehearsalMeta
    1238              : //---------------------------------------------------------
    1239              : 
    1240            0 : void Timeline::rehearsalMeta(Segment* seg, int* stagger, int pos)
    1241              : {
    1242            0 :     int row = getMetaRow(muse::qtrc("notation/timeline", "Rehearsal mark"));
    1243              : 
    1244            0 :     for (EngravingItem* element : seg->annotations()) {
    1245            0 :         int x = pos + (*stagger) * _spacing;
    1246            0 :         if (element->isRehearsalMark()) {
    1247            0 :             RehearsalMark* rehearsal_mark = toRehearsalMark(element);
    1248            0 :             if (!rehearsal_mark) {
    1249            0 :                 continue;
    1250              :             }
    1251              : 
    1252            0 :             if (addMetaValue(x, pos, rehearsal_mark->plainText(), row, ElementType::REHEARSAL_MARK, element, 0, seg->measure())) {
    1253            0 :                 (*stagger)++;
    1254            0 :                 _globalZValue++;
    1255              :             }
    1256              :         }
    1257              :     }
    1258            0 : }
    1259              : 
    1260              : //---------------------------------------------------------
    1261              : //   Timeline::keyMeta
    1262              : //---------------------------------------------------------
    1263              : 
    1264            0 : void Timeline::keyMeta(Segment* seg, int* stagger, int pos)
    1265              : {
    1266              :     // If seg is nullptr, handle initial key signature
    1267            0 :     if (seg && !seg->isKeySigType()) {
    1268            0 :         return;
    1269              :     }
    1270              : 
    1271            0 :     TRACEFUNC;
    1272              : 
    1273            0 :     int row = getMetaRow(muse::qtrc("notation/timeline", "Key signature"));
    1274            0 :     std::map<Key, int> keyFrequencies;
    1275            0 :     const std::vector<Staff*>& staves = score()->staves();
    1276              : 
    1277            0 :     int track = 0;
    1278            0 :     for (Staff* stave : staves) {
    1279            0 :         if (!stave->show()) {
    1280            0 :             track += VOICES;
    1281            0 :             continue;
    1282              :         }
    1283              : 
    1284              :         // Ignore unpitched staves
    1285            0 :         if ((seg && !stave->isPitchedStaff(seg->tick())) || (!seg && !stave->isPitchedStaff(Fraction(0, 1)))) {
    1286            0 :             track += VOICES;
    1287            0 :             continue;
    1288              :         }
    1289              : 
    1290              :         // Add corrected key signature to map
    1291              :         // Atonal -> Key::INVALID
    1292              :         // Custom -> Key::NUM_OF
    1293            0 :         const KeySig* currKeySig = nullptr;
    1294            0 :         if (seg) {
    1295            0 :             currKeySig = toKeySig(seg->element(track));
    1296              :         }
    1297              : 
    1298              :         Key globalKey;
    1299            0 :         if (seg) {
    1300            0 :             globalKey = stave->concertKey(seg->tick());
    1301              :         } else {
    1302            0 :             globalKey = stave->concertKey(Fraction(0, 1));
    1303              :         }
    1304            0 :         if (currKeySig) {
    1305            0 :             if (currKeySig->generated()) {
    1306            0 :                 return;
    1307              :             }
    1308            0 :             globalKey = currKeySig->concertKey();
    1309              :         }
    1310              : 
    1311            0 :         if (currKeySig && currKeySig->isAtonal()) {
    1312            0 :             globalKey = Key::INVALID;
    1313            0 :         } else if (currKeySig && currKeySig->isCustom()) {
    1314            0 :             globalKey = Key::NUM_OF;
    1315              :         }
    1316              : 
    1317            0 :         std::map<Key, int>::iterator it = keyFrequencies.find(globalKey);
    1318            0 :         if (it != keyFrequencies.end()) {
    1319            0 :             keyFrequencies[globalKey]++;
    1320              :         } else {
    1321            0 :             keyFrequencies[globalKey] = 1;
    1322              :         }
    1323              : 
    1324            0 :         track += VOICES;
    1325              :     }
    1326              : 
    1327              :     // Change key into QString
    1328            0 :     Key newKey = Key::C;
    1329            0 :     int maxKeyFreq = 0;
    1330            0 :     for (std::map<Key, int>::iterator iter = keyFrequencies.begin(); iter != keyFrequencies.end(); ++iter) {
    1331            0 :         if (iter->second > maxKeyFreq) {
    1332            0 :             newKey = iter->first;
    1333            0 :             maxKeyFreq = iter->second;
    1334              :         }
    1335              :     }
    1336            0 :     QString keyText;
    1337            0 :     QString tooltip;
    1338            0 :     if (newKey == Key::INVALID) {
    1339            0 :         keyText = "X";
    1340            0 :         tooltip = TConv::translatedUserName(Key::INVALID, true);
    1341            0 :     } else if (newKey == Key::NUM_OF) {
    1342            0 :         keyText = "?";
    1343            0 :         tooltip = muse::qtrc("notation/timeline", "Custom key signature");
    1344            0 :     } else if (int(newKey) == 0) {
    1345            0 :         keyText = "\u266E";
    1346            0 :         tooltip = TConv::translatedUserName(Key::C);
    1347            0 :     } else if (int(newKey) < 0) {
    1348            0 :         keyText = QString::number(std::abs(int(newKey))) + "\u266D";
    1349            0 :         tooltip = TConv::translatedUserName(newKey);
    1350              :     } else {
    1351            0 :         keyText = QString::number(std::abs(int(newKey))) + "\u266F";
    1352            0 :         tooltip = TConv::translatedUserName(newKey);
    1353              :     }
    1354              : 
    1355            0 :     int x = pos + (*stagger) * _spacing;
    1356            0 :     Measure* measure = seg ? seg->measure() : 0;
    1357            0 :     if (addMetaValue(x, pos, keyText, row, ElementType::KEYSIG, 0, seg, measure, tooltip)) {
    1358            0 :         (*stagger)++;
    1359            0 :         _globalZValue++;
    1360              :     }
    1361            0 : }
    1362              : 
    1363              : //---------------------------------------------------------
    1364              : //   Timeline::barLineMeta
    1365              : //---------------------------------------------------------
    1366              : 
    1367            0 : void Timeline::barlineMeta(Segment* seg, int* stagger, int pos)
    1368              : {
    1369            0 :     if (!seg->isBeginBarLineType() && !seg->isEndBarLineType() && !seg->isBarLine() && !seg->isStartRepeatBarLineType()) {
    1370            0 :         return;
    1371              :     }
    1372              : 
    1373            0 :     TRACEFUNC;
    1374              : 
    1375              :     // Find position of repeat_meta in metas
    1376            0 :     int row = getMetaRow(muse::qtrc("notation/timeline", "Barlines"));
    1377              : 
    1378            0 :     QString repeatText = "";
    1379            0 :     BarLine* barline = toBarLine(seg->element(0));
    1380              : 
    1381            0 :     if (barline) {
    1382            0 :         switch (barline->barLineType()) {
    1383            0 :         case BarLineType::START_REPEAT:
    1384              :         case BarLineType::END_REPEAT:
    1385              :         case BarLineType::END:
    1386              :         case BarLineType::DOUBLE:
    1387              :         case BarLineType::REVERSE_END:
    1388              :         case BarLineType::HEAVY:
    1389              :         case BarLineType::DOUBLE_HEAVY:
    1390            0 :             repeatText = BarLine::translatedUserTypeName(barline->barLineType());
    1391            0 :             break;
    1392            0 :         case BarLineType::END_START_REPEAT:
    1393              :         // actually an end repeat followed by a start repeat, so nothing needs to be done here
    1394              :         default:
    1395            0 :             break;
    1396              :         }
    1397            0 :         _isBarline = true;
    1398              :     } else {
    1399            0 :         return;
    1400              :     }
    1401              : 
    1402            0 :     Measure* measure = seg->measure();
    1403            0 :     ElementType elementType = ElementType::BAR_LINE;
    1404            0 :     EngravingItem* element = nullptr;
    1405              : 
    1406            0 :     if (repeatText == "") {
    1407            0 :         _isBarline = false;
    1408            0 :         return;
    1409              :     }
    1410              : 
    1411            0 :     int x = pos + (*stagger) * _spacing;
    1412            0 :     if (addMetaValue(x, pos, repeatText, row, elementType, element, seg, measure)) {
    1413            0 :         (*stagger)++;
    1414            0 :         _globalZValue++;
    1415              :     }
    1416            0 :     _isBarline = false;
    1417            0 : }
    1418              : 
    1419              : //---------------------------------------------------------
    1420              : //   Timeline::jumpMarkerMeta
    1421              : //---------------------------------------------------------
    1422              : 
    1423            0 : void Timeline::jumpMarkerMeta(Segment* seg, int* stagger, int pos)
    1424              : {
    1425            0 :     if (seg) {
    1426            0 :         return;
    1427              :     }
    1428              : 
    1429            0 :     TRACEFUNC;
    1430              : 
    1431              :     // Find position of repeat_meta in metas
    1432            0 :     int row = getMetaRow(muse::qtrc("notation/timeline", "Jumps and markers"));
    1433              : 
    1434            0 :     QString text = "";
    1435            0 :     EngravingItem* element = nullptr;
    1436            0 :     if (std::get<2>(_repeatInfo)) {
    1437            0 :         element = std::get<2>(_repeatInfo);
    1438            0 :     } else if (std::get<3>(_repeatInfo)) {
    1439            0 :         element = std::get<3>(_repeatInfo);
    1440              :     }
    1441              : 
    1442              :     Measure* measure;
    1443              :     ElementType elementType;
    1444            0 :     if (std::get<2>(_repeatInfo)) {
    1445            0 :         Jump* jump = toJump(std::get<2>(_repeatInfo));
    1446            0 :         text = jump->plainText();
    1447            0 :         measure = jump->measure();
    1448            0 :         elementType = ElementType::JUMP;
    1449              :     } else {
    1450            0 :         Marker* marker = toMarker(std::get<3>(_repeatInfo));
    1451            0 :         std::list<TextFragment> tf_list = marker->fragmentList();
    1452            0 :         for (TextFragment tf : tf_list) {
    1453            0 :             text.push_back(tf.text);
    1454            0 :         }
    1455            0 :         measure = marker->measure();
    1456            0 :         if (marker->markerType() == MarkerType::FINE
    1457            0 :             || marker->markerType() == MarkerType::TOCODA
    1458            0 :             || marker->markerType() == MarkerType::TOCODASYM
    1459            0 :             || marker->markerType() == MarkerType::DA_CODA
    1460            0 :             || marker->markerType() == MarkerType::DA_DBLCODA
    1461              :             ) {
    1462            0 :             elementType = ElementType::MARKER;
    1463            0 :             std::get<2>(_repeatInfo) = std::get<3>(_repeatInfo);
    1464            0 :             std::get<3>(_repeatInfo) = nullptr;
    1465              :         } else {
    1466            0 :             elementType = ElementType::MARKER;
    1467              :         }
    1468            0 :     }
    1469              : 
    1470            0 :     if (text == "") {
    1471            0 :         std::get<2>(_repeatInfo) = nullptr;
    1472            0 :         std::get<3>(_repeatInfo) = nullptr;
    1473            0 :         return;
    1474              :     }
    1475              : 
    1476            0 :     int x = pos + (*stagger) * _spacing;
    1477            0 :     if (addMetaValue(x, pos, text, row, elementType, element, seg, measure)) {
    1478            0 :         (*stagger)++;
    1479            0 :         _globalZValue++;
    1480              :     }
    1481            0 :     std::get<2>(_repeatInfo) = nullptr;
    1482            0 :     std::get<3>(_repeatInfo) = nullptr;
    1483            0 : }
    1484              : 
    1485              : //---------------------------------------------------------
    1486              : //   Timeline::measureMeta
    1487              : //---------------------------------------------------------
    1488              : 
    1489            0 : void Timeline::measureMeta(Segment*, int*, int pos)
    1490              : {
    1491            0 :     TRACEFUNC;
    1492              : 
    1493              :     // Increment decided by zoom level
    1494            0 :     int incrementValue = 1;
    1495            0 :     int halfway = (_maxZoom + _minZoom) / 2;
    1496            0 :     if (_gridWidth <= _maxZoom && _gridWidth > halfway) {
    1497            0 :         incrementValue = 1;
    1498            0 :     } else if (_gridWidth <= halfway && _gridWidth > _minZoom) {
    1499            0 :         incrementValue = 5;
    1500              :     } else {
    1501            0 :         incrementValue = 10;
    1502              :     }
    1503              : 
    1504            0 :     int currMeasureNumber = pos / _gridWidth;
    1505            0 :     if (currMeasureNumber == _globalMeasureNumber) {
    1506            0 :         return;
    1507              :     }
    1508              : 
    1509            0 :     _globalMeasureNumber = currMeasureNumber;
    1510              :     // Check if 1 or 5*n
    1511            0 :     if (currMeasureNumber + 1 != 1 && (currMeasureNumber + 1) % incrementValue != 0) {
    1512            0 :         return;
    1513              :     }
    1514              : 
    1515              :     // Find position of measureMeta in metas
    1516            0 :     int row = getMetaRow(muse::qtrc("notation/timeline", "Measures"));
    1517              : 
    1518              :     // Adjust number
    1519              :     Measure* currMeasure;
    1520            0 :     for (currMeasure = score()->firstMeasure(); currMeasureNumber != 0; currMeasureNumber--, currMeasure = currMeasure->nextMeasure()) {
    1521              :     }
    1522              : 
    1523              :     // Add measure number
    1524            0 :     QString measureNumber = (currMeasure->excludeFromNumbering()) ? u"( )"_s : QString::number(currMeasure->measureNumber() + 1);
    1525            0 :     QGraphicsTextItem* graphicsTextItem = new QGraphicsTextItem(measureNumber);
    1526            0 :     graphicsTextItem->setData(keyItemType, QVariant::fromValue(ItemType::TYPE_META));
    1527            0 :     graphicsTextItem->setDefaultTextColor(activeTheme().measureMetaColor);
    1528            0 :     graphicsTextItem->setX(pos);
    1529            0 :     graphicsTextItem->setY(_gridHeight * row + verticalScrollBar()->value());
    1530              : 
    1531            0 :     QFont f = graphicsTextItem->font();
    1532            0 :     f.setPointSizeF(7.0);
    1533            0 :     graphicsTextItem->setFont(f);
    1534              : 
    1535              :     // Center text
    1536            0 :     qreal remainingWidth  = _gridWidth - graphicsTextItem->boundingRect().width();
    1537            0 :     qreal remainingHeight = _gridHeight - graphicsTextItem->boundingRect().height();
    1538            0 :     graphicsTextItem->setX(graphicsTextItem->x() + remainingWidth / 2);
    1539            0 :     graphicsTextItem->setY(graphicsTextItem->y() + remainingHeight / 2);
    1540              : 
    1541            0 :     int endOfText = graphicsTextItem->x() + graphicsTextItem->boundingRect().width();
    1542            0 :     int endOfGrid = getWidth();
    1543            0 :     if (endOfText <= endOfGrid) {
    1544            0 :         scene()->addItem(graphicsTextItem);
    1545              : 
    1546            0 :         std::pair<QGraphicsItem*, int> pairMeasureText = std::make_pair(graphicsTextItem, row);
    1547            0 :         _metaRows.push_back(pairMeasureText);
    1548              :     }
    1549            0 : }
    1550              : 
    1551              : //---------------------------------------------------------
    1552              : //   Timeline::getMetaRow
    1553              : //---------------------------------------------------------
    1554              : 
    1555            0 : unsigned Timeline::getMetaRow(QString targetText)
    1556              : {
    1557            0 :     if (_collapsedMeta) {
    1558            0 :         if (targetText == muse::qtrc("notation/timeline", "Measures")) {
    1559            0 :             return 1;
    1560              :         } else {
    1561            0 :             return 0;
    1562              :         }
    1563              :     }
    1564            0 :     int row = 0;
    1565            0 :     for (auto it = _metas.begin(); it != _metas.end(); ++it) {
    1566            0 :         std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> meta = *it;
    1567            0 :         QString metaText = std::get<0>(meta);
    1568            0 :         bool visible = std::get<2>(meta);
    1569            0 :         if (metaText == targetText && visible) {
    1570            0 :             break;
    1571            0 :         } else if (!visible) {
    1572            0 :             continue;
    1573              :         }
    1574            0 :         row++;
    1575            0 :     }
    1576            0 :     return row;
    1577              : }
    1578              : 
    1579              : //---------------------------------------------------------
    1580              : //   Timeline::addMetaValue
    1581              : //---------------------------------------------------------
    1582              : 
    1583            0 : bool Timeline::addMetaValue(int x, int pos, QString metaText, int row, ElementType elementType, EngravingItem* element, Segment* seg,
    1584              :                             Measure* measure, QString tooltip)
    1585              : {
    1586            0 :     TRACEFUNC;
    1587              : 
    1588            0 :     QGraphicsTextItem* graphicsTextItem = new QGraphicsTextItem(metaText);
    1589            0 :     qreal textWidth = graphicsTextItem->boundingRect().width();
    1590              : 
    1591            0 :     QGraphicsPixmapItem* graphicsPixmapItem = nullptr;
    1592              : 
    1593              :     std::map<QString, BarLineType> barLineTypes = {
    1594            0 :         { BarLine::translatedUserTypeName(BarLineType::START_REPEAT), BarLineType::START_REPEAT },
    1595            0 :         { BarLine::translatedUserTypeName(BarLineType::END_REPEAT), BarLineType::END_REPEAT },
    1596            0 :         { BarLine::translatedUserTypeName(BarLineType::END), BarLineType::END },
    1597            0 :         { BarLine::translatedUserTypeName(BarLineType::DOUBLE), BarLineType::DOUBLE },
    1598            0 :         { BarLine::translatedUserTypeName(BarLineType::REVERSE_END), BarLineType::REVERSE_END },
    1599            0 :         { BarLine::translatedUserTypeName(BarLineType::HEAVY), BarLineType::HEAVY },
    1600            0 :         { BarLine::translatedUserTypeName(BarLineType::DOUBLE_HEAVY), BarLineType::DOUBLE_HEAVY },
    1601            0 :     };
    1602              : 
    1603            0 :     BarLineType barLineType = barLineTypes[metaText];
    1604              : 
    1605            0 :     if (_isBarline) {
    1606            0 :         graphicsPixmapItem = new QGraphicsPixmapItem(*_barlines[barLineType]);
    1607              :     }
    1608              : 
    1609            0 :     if (graphicsPixmapItem) {
    1610            0 :         textWidth = 10;
    1611            0 :         if (textWidth > _gridWidth) {
    1612            0 :             textWidth = _gridWidth;
    1613            0 :             if (barLineType == BarLineType::END_REPEAT && std::get<4>(_repeatInfo)) {
    1614            0 :                 textWidth /= 2;
    1615              :             }
    1616              :         }
    1617              :     }
    1618              : 
    1619            0 :     if (textWidth + x > getWidth()) {
    1620            0 :         textWidth = getWidth() - x;
    1621              :     }
    1622              : 
    1623              :     // Adjust x for end repeats
    1624            0 :     if ((barLineType == BarLineType::END_REPEAT
    1625            0 :          || barLineType == BarLineType::END
    1626            0 :          || barLineType == BarLineType::DOUBLE
    1627            0 :          || barLineType == BarLineType::REVERSE_END
    1628            0 :          || barLineType == BarLineType::HEAVY
    1629            0 :          || barLineType == BarLineType::DOUBLE_HEAVY
    1630            0 :          || std::get<2>(_repeatInfo))
    1631            0 :         && !_collapsedMeta) {
    1632            0 :         if (std::get<0>(_repeatInfo) > 0) {
    1633            0 :             x = pos + _gridWidth - std::get<1>(_repeatInfo) + std::get<0>(_repeatInfo) * _spacing;
    1634              :         } else {
    1635            0 :             x = pos + _gridWidth - textWidth;
    1636            0 :             std::get<1>(_repeatInfo) = textWidth;
    1637              :         }
    1638              :         // Check if extending past left side
    1639            0 :         if (x < 0) {
    1640            0 :             textWidth = textWidth + x;
    1641            0 :             x = 0;
    1642              :         }
    1643              :     }
    1644              : 
    1645              :     // Return if past width
    1646            0 :     if (x >= getWidth()) {
    1647            0 :         return false;
    1648              :     }
    1649              : 
    1650              :     QGraphicsItem* itemToAdd;
    1651            0 :     if (graphicsPixmapItem) {
    1652              :         // Exact values required for repeat pixmap to work visually
    1653            0 :         if (textWidth != 10) {
    1654            0 :             graphicsPixmapItem = new QGraphicsPixmapItem();
    1655              :         }
    1656            0 :         if (barLineType == BarLineType::START_REPEAT) {
    1657            0 :             std::get<4>(_repeatInfo) = true;
    1658              :         }
    1659            0 :         graphicsPixmapItem->setX(x + 2);
    1660            0 :         graphicsPixmapItem->setY(_gridHeight * row + verticalScrollBar()->value() + 3);
    1661            0 :         itemToAdd = graphicsPixmapItem;
    1662            0 :     } else if (metaText == "\uE047" || metaText == "\uE048") {
    1663            0 :         graphicsTextItem->setX(x);
    1664            0 :         graphicsTextItem->setY(_gridHeight * row + verticalScrollBar()->value() - 2);
    1665            0 :         itemToAdd = graphicsTextItem;
    1666            0 :     } else if (row == 0) {
    1667            0 :         graphicsTextItem->setX(x);
    1668            0 :         graphicsTextItem->setY(_gridHeight * row + verticalScrollBar()->value() - 6);
    1669            0 :         itemToAdd = graphicsTextItem;
    1670              :     } else {
    1671            0 :         graphicsTextItem->setX(x);
    1672            0 :         graphicsTextItem->setY(_gridHeight * row + verticalScrollBar()->value() - 1);
    1673            0 :         itemToAdd = graphicsTextItem;
    1674              :     }
    1675              : 
    1676            0 :     QFontMetrics f(QApplication::font());
    1677            0 :     QString partName = f.elidedText(graphicsTextItem->toPlainText(),
    1678              :                                     Qt::ElideRight,
    1679            0 :                                     textWidth);
    1680              : 
    1681              :     // Set tool tip if elided
    1682            0 :     if (tooltip != "") {
    1683            0 :         graphicsTextItem->setToolTip(tooltip);
    1684            0 :     } else if (partName != metaText) {
    1685            0 :         graphicsTextItem->setToolTip(graphicsTextItem->toPlainText());
    1686              :     }
    1687            0 :     graphicsTextItem->setPlainText(partName);
    1688              : 
    1689              :     // Make text fit within rectangle
    1690            0 :     while (graphicsTextItem->boundingRect().width() > textWidth
    1691            0 :            && graphicsTextItem->toPlainText() != "") {
    1692            0 :         QString text = graphicsTextItem->toPlainText();
    1693            0 :         text.chop(1);
    1694            0 :         graphicsTextItem->setPlainText(text);
    1695            0 :     }
    1696              : 
    1697              :     QGraphicsRectItem* graphicsRectItem = new QGraphicsRectItem(x,
    1698            0 :                                                                 _gridHeight * row + verticalScrollBar()->value(),
    1699              :                                                                 textWidth,
    1700            0 :                                                                 _gridHeight);
    1701            0 :     if (tooltip != "") {
    1702            0 :         graphicsRectItem->setToolTip(tooltip);
    1703            0 :     } else if (partName != metaText || graphicsPixmapItem) {
    1704            0 :         graphicsRectItem->setToolTip(metaText);
    1705              :     }
    1706              : 
    1707            0 :     setMetaData(graphicsRectItem, -1, elementType, measure, true, element, itemToAdd, seg);
    1708            0 :     setMetaData(itemToAdd, -1, elementType, measure, true, element, graphicsRectItem, seg);
    1709              : 
    1710            0 :     graphicsRectItem->setData(keyItemType, QVariant::fromValue(ItemType::TYPE_META));
    1711            0 :     itemToAdd->setData(keyItemType, QVariant::fromValue(ItemType::TYPE_META));
    1712              : 
    1713            0 :     graphicsRectItem->setZValue(_globalZValue);
    1714            0 :     itemToAdd->setZValue(_globalZValue);
    1715              : 
    1716            0 :     graphicsRectItem->setPen(QPen(activeTheme().metaValuePenColor));
    1717            0 :     graphicsRectItem->setBrush(QBrush(activeTheme().metaValueBrushColor));
    1718              : 
    1719            0 :     scene()->addItem(graphicsRectItem);
    1720            0 :     scene()->addItem(itemToAdd);
    1721              : 
    1722            0 :     std::pair<QGraphicsItem*, int> pairTimeRect = std::make_pair(graphicsRectItem, row);
    1723            0 :     std::pair<QGraphicsItem*, int> pairTimeText = std::make_pair(itemToAdd, row);
    1724            0 :     _metaRows.push_back(pairTimeRect);
    1725            0 :     _metaRows.push_back(pairTimeText);
    1726              : 
    1727            0 :     if (barLineType == BarLineType::END_REPEAT) {
    1728            0 :         std::get<0>(_repeatInfo)++;
    1729              :     }
    1730              : 
    1731            0 :     return true;
    1732            0 : }
    1733              : 
    1734              : //---------------------------------------------------------
    1735              : //   Timeline::setMetaData
    1736              : //---------------------------------------------------------
    1737              : 
    1738            0 : void Timeline::setMetaData(QGraphicsItem* gi, int staff, ElementType et, Measure* m, bool full_measure, EngravingItem* e,
    1739              :                            QGraphicsItem* pairItem,
    1740              :                            Segment* seg)
    1741              : {
    1742              :     // full_measure true for meta values
    1743              :     // pr is null for grid items, set for meta values
    1744              :     // seg is set if key meta
    1745            0 :     gi->setData(0, QVariant::fromValue<int>(staff));
    1746            0 :     gi->setData(1, QVariant::fromValue<ElementType>(et));
    1747            0 :     gi->setData(2, QVariant::fromValue<void*>(m));
    1748            0 :     gi->setData(3, QVariant::fromValue<bool>(full_measure));
    1749            0 :     gi->setData(4, QVariant::fromValue<void*>(e));
    1750            0 :     gi->setData(5, QVariant::fromValue<void*>(pairItem));
    1751            0 :     gi->setData(6, QVariant::fromValue<void*>(seg));
    1752            0 : }
    1753              : 
    1754              : //---------------------------------------------------------
    1755              : //   Timeline::getWidth
    1756              : //---------------------------------------------------------
    1757              : 
    1758            0 : int Timeline::getWidth() const
    1759              : {
    1760            0 :     if (score()) {
    1761            0 :         return static_cast<int>(score()->nmeasures()) * _gridWidth;
    1762              :     } else {
    1763            0 :         return 0;
    1764              :     }
    1765              : }
    1766              : 
    1767              : //---------------------------------------------------------
    1768              : //   Timeline::getHeight
    1769              : //---------------------------------------------------------
    1770              : 
    1771            0 : int Timeline::getHeight() const
    1772              : {
    1773            0 :     if (score()) {
    1774            0 :         return (nstaves() + static_cast<int>(nmetas())) * _gridHeight + 3;
    1775              :     } else {
    1776            0 :         return 0;
    1777              :     }
    1778              : }
    1779              : 
    1780              : //---------------------------------------------------------
    1781              : //   Timeline::correctStave
    1782              : //---------------------------------------------------------
    1783              : 
    1784            0 : staff_idx_t Timeline::correctStave(staff_idx_t stave)
    1785              : {
    1786              :     // Find correct stave (skipping hidden staves)
    1787            0 :     const std::vector<Staff*>& list = score()->staves();
    1788            0 :     size_t count = 0;
    1789            0 :     while (stave >= count) {
    1790            0 :         if (count >= list.size()) {
    1791            0 :             count = list.size() - 1;
    1792            0 :             return count;
    1793              :         }
    1794            0 :         if (!list.at(count)->show()) {
    1795            0 :             stave++;
    1796              :         }
    1797            0 :         count++;
    1798              :     }
    1799            0 :     return stave;
    1800              : }
    1801              : 
    1802              : //---------------------------------------------------------
    1803              : //   Timeline::correctPart
    1804              : //---------------------------------------------------------
    1805              : 
    1806            0 : int Timeline::correctPart(staff_idx_t stave)
    1807              : {
    1808              :     // Find correct stave (skipping hidden staves)
    1809            0 :     const std::vector<Staff*>& list = score()->staves();
    1810            0 :     staff_idx_t count = correctStave(stave);
    1811            0 :     return getParts().indexOf(list.at(count)->part());
    1812              : }
    1813              : 
    1814              : //---------------------------------------------------------
    1815              : //   Timeline::getParts
    1816              : //---------------------------------------------------------
    1817              : 
    1818            0 : QList<Part*> Timeline::getParts()
    1819              : {
    1820            0 :     const std::vector<Part*>& realPartList = score()->parts();
    1821            0 :     QList<Part*> partList;
    1822            0 :     for (Part* p : realPartList) {
    1823            0 :         for (size_t i = 0; i < p->nstaves(); i++) {
    1824            0 :             partList.append(p);
    1825              :         }
    1826              :     }
    1827              : 
    1828            0 :     return partList;
    1829            0 : }
    1830              : 
    1831              : //---------------------------------------------------------
    1832              : //   clearScene
    1833              : //---------------------------------------------------------
    1834              : 
    1835            0 : void Timeline::clearScene()
    1836              : {
    1837            0 :     scene()->clear();
    1838              : 
    1839              :     // clear pointers to scene items, they have been deleted by clear()
    1840            0 :     nonVisiblePathItem = nullptr;
    1841            0 :     visiblePathItem = nullptr;
    1842            0 :     selectionItem = nullptr;
    1843            0 : }
    1844              : 
    1845              : //---------------------------------------------------------
    1846              : //   Timeline::changeSelection
    1847              : //---------------------------------------------------------
    1848              : 
    1849            0 : void Timeline::changeSelection(SelState)
    1850              : {
    1851            0 :     TRACEFUNC;
    1852              : 
    1853            0 :     scene()->blockSignals(true);
    1854            0 :     scene()->clearSelection();
    1855              : 
    1856            0 :     QRectF selectionRect = _selectionPath.boundingRect();
    1857            0 :     if (selectionRect == QRectF()) {
    1858            0 :         return;
    1859              :     }
    1860              : 
    1861            0 :     int nmeta = nmetas();
    1862              : 
    1863              :     // Get borders of the current viewport
    1864            0 :     int leftBorder = horizontalScrollBar()->value();
    1865            0 :     int rightBorder = horizontalScrollBar()->value() + viewport()->width();
    1866            0 :     int topBorder = verticalScrollBar()->value() + nmeta * _gridHeight;
    1867            0 :     int bottomBorder = verticalScrollBar()->value() + viewport()->height();
    1868              : 
    1869            0 :     bool selectionExtendsUp = false,    selectionExtendsLeft = false;
    1870            0 :     bool selectionExtendsRight = false, selectionExtendsDown = false;
    1871              : 
    1872              :     // Figure out which directions the selection extends
    1873            0 :     if (selectionRect.top() < topBorder) {
    1874            0 :         selectionExtendsUp = true;
    1875              :     }
    1876            0 :     if (selectionRect.left() < leftBorder - 1) {
    1877            0 :         selectionExtendsLeft = true;
    1878              :     }
    1879            0 :     if (selectionRect.right() > rightBorder) {
    1880            0 :         selectionExtendsRight = true;
    1881              :     }
    1882            0 :     if (selectionRect.bottom() > bottomBorder) {
    1883            0 :         selectionExtendsDown = true;
    1884              :     }
    1885              : 
    1886            0 :     if (selectionExtendsDown
    1887            0 :         && _oldSelectionRect.bottom() != selectionRect.bottom()
    1888            0 :         && !_metaValue) {
    1889            0 :         int newScrollbarValue = int(verticalScrollBar()->value() + selectionRect.bottom() - bottomBorder);
    1890            0 :         verticalScrollBar()->setValue(newScrollbarValue);
    1891            0 :     } else if (selectionExtendsUp
    1892            0 :                && !selectionExtendsDown
    1893            0 :                && _oldSelectionRect.bottom() != selectionRect.bottom()
    1894            0 :                && !_metaValue
    1895            0 :                && _oldSelectionRect.contains(selectionRect)) {
    1896            0 :         int newScrollbarValue = int(verticalScrollBar()->value() + selectionRect.bottom() - bottomBorder);
    1897            0 :         verticalScrollBar()->setValue(newScrollbarValue);
    1898              :     }
    1899              : 
    1900            0 :     if (selectionExtendsRight
    1901            0 :         && _oldSelectionRect.right() != selectionRect.right()) {
    1902            0 :         int newScrollbarValue = int(horizontalScrollBar()->value() + selectionRect.right() - rightBorder);
    1903            0 :         horizontalScrollBar()->setValue(newScrollbarValue);
    1904              :     }
    1905            0 :     if (selectionExtendsUp
    1906            0 :         && _oldSelectionRect.top() != selectionRect.top()
    1907            0 :         && !_metaValue) {
    1908            0 :         int newScrollbarValue = int(selectionRect.top()) - nmeta * _gridHeight;
    1909            0 :         verticalScrollBar()->setValue(newScrollbarValue);
    1910              :     }
    1911            0 :     if (selectionExtendsLeft
    1912            0 :         && _oldSelectionRect.left() != selectionRect.left()) {
    1913            0 :         int newScrollbarValue = int(selectionRect.left());
    1914            0 :         horizontalScrollBar()->setValue(newScrollbarValue);
    1915              :     }
    1916              : 
    1917            0 :     if (selectionExtendsLeft
    1918            0 :         && !selectionExtendsRight
    1919            0 :         && _oldSelectionRect.right() != selectionRect.right()
    1920            0 :         && _oldSelectionRect.contains(selectionRect)) {
    1921            0 :         int newScrollbarValue = int(horizontalScrollBar()->value() + selectionRect.right() - rightBorder);
    1922            0 :         horizontalScrollBar()->setValue(newScrollbarValue);
    1923              :     }
    1924            0 :     if (selectionExtendsRight
    1925            0 :         && !selectionExtendsLeft
    1926            0 :         && _oldSelectionRect.left() != selectionRect.left()
    1927            0 :         && _oldSelectionRect.contains(selectionRect)) {
    1928            0 :         int newScrollbarValue = int(selectionRect.left());
    1929            0 :         horizontalScrollBar()->setValue(newScrollbarValue);
    1930              :     }
    1931              : 
    1932            0 :     if (selectionExtendsDown
    1933            0 :         && !selectionExtendsUp
    1934            0 :         && _oldSelectionRect.top() != selectionRect.top()
    1935            0 :         && !_metaValue
    1936            0 :         && _oldSelectionRect.contains(selectionRect)) {
    1937            0 :         int newScrollbarValue = int(selectionRect.top()) - nmeta * _gridHeight;
    1938            0 :         verticalScrollBar()->setValue(newScrollbarValue);
    1939              :     }
    1940              : 
    1941            0 :     _oldSelectionRect = selectionRect;
    1942              : 
    1943            0 :     _metaValue = false;
    1944            0 :     scene()->blockSignals(false);
    1945            0 : }
    1946              : 
    1947              : //---------------------------------------------------------
    1948              : //   Timeline::drawSelection
    1949              : //---------------------------------------------------------
    1950              : 
    1951            0 : void Timeline::drawSelection()
    1952              : {
    1953            0 :     if (!score()) {
    1954            0 :         return;
    1955              :     }
    1956              : 
    1957            0 :     TRACEFUNC;
    1958              : 
    1959            0 :     _selectionPath = QPainterPath();
    1960            0 :     _selectionPath.setFillRule(Qt::WindingFill);
    1961              : 
    1962            0 :     std::set<std::tuple<Measure*, int, ElementType> > metaLabelsSet;
    1963              : 
    1964            0 :     INotationSelectionPtr selection = interaction()->selection();
    1965              : 
    1966            0 :     for (EngravingItem* element : selection->elements()) {
    1967            0 :         if (element->tick() == Fraction(-1, 1)) {
    1968            0 :             continue;
    1969              :         } else {
    1970            0 :             switch (element->type()) {
    1971            0 :             case ElementType::INSTRUMENT_NAME:
    1972              :             case ElementType::VBOX:
    1973              :             case ElementType::HBOX:
    1974              :             case ElementType::TEXT:
    1975              :             case ElementType::TIE_SEGMENT:
    1976              :             case ElementType::SLUR_SEGMENT:
    1977              :             case ElementType::TIE:
    1978              :             case ElementType::SLUR:
    1979              :             case ElementType::HAMMER_ON_PULL_OFF:
    1980            0 :                 continue;
    1981              :                 break;
    1982            0 :             default: break;
    1983              :             }
    1984              :         }
    1985              : 
    1986              :         int staffIdx;
    1987            0 :         Fraction tick = element->tick();
    1988            0 :         Measure* measure = score()->tick2measure(tick);
    1989            0 :         staffIdx = static_cast<int>(element->staffIdx());
    1990            0 :         if (numToStaff(staffIdx) && !numToStaff(staffIdx)->show()) {
    1991            0 :             continue;
    1992              :         }
    1993              : 
    1994            0 :         if ((element->isTempoText()
    1995            0 :              || element->isKeySig()
    1996            0 :              || element->isTimeSig()
    1997            0 :              || element->isRehearsalMark()
    1998            0 :              || element->isJump()
    1999            0 :              || element->isMarker())
    2000            0 :             && !element->generated()) {
    2001            0 :             staffIdx = -1;
    2002              :         }
    2003              : 
    2004            0 :         if (element->isBarLine()) {
    2005            0 :             staffIdx = -1;
    2006            0 :             BarLine* barline = toBarLine(element);
    2007            0 :             if (barline
    2008            0 :                 && (barline->barLineType() == BarLineType::END_REPEAT
    2009            0 :                     || barline->barLineType() == BarLineType::END
    2010            0 :                     || barline->barLineType() == BarLineType::DOUBLE
    2011            0 :                     || barline->barLineType() == BarLineType::REVERSE_END
    2012            0 :                     || barline->barLineType() == BarLineType::HEAVY
    2013            0 :                     || barline->barLineType() == BarLineType::DOUBLE_HEAVY)
    2014            0 :                 && measure != score()->lastMeasure()) {
    2015            0 :                 if (measure->prevMeasure()) {
    2016            0 :                     measure = measure->prevMeasure();
    2017              :                 }
    2018              :             }
    2019              :         }
    2020              : 
    2021              :         // element->type() for meta rows, invalid for everything else
    2022            0 :         ElementType elementType = (staffIdx == -1) ? element->type() : ElementType::INVALID;
    2023              : 
    2024              :         // If has a multi measure rest, find the count and add each measure to it
    2025              :         // ws: If style flag Sid::createMultiMeasureRests is not set, then
    2026              :         // measure->mmRest() is not valid
    2027              : 
    2028            0 :         if (measure->mmRest() && measure->score()->style().styleB(Sid::createMultiMeasureRests)) {
    2029            0 :             int mmrestCount = measure->mmRest()->mmRestCount();
    2030            0 :             Measure* tmpMeasure = measure;
    2031            0 :             for (int mmrestMeasure = 0; mmrestMeasure < mmrestCount; mmrestMeasure++) {
    2032            0 :                 std::tuple<Measure*, int, ElementType> tmp(tmpMeasure, staffIdx, elementType);
    2033            0 :                 metaLabelsSet.insert(tmp);
    2034            0 :                 tmpMeasure = tmpMeasure->nextMeasure();
    2035              :             }
    2036              :         } else {
    2037            0 :             std::tuple<Measure*, int, ElementType> tmp(measure, staffIdx, elementType);
    2038            0 :             metaLabelsSet.insert(tmp);
    2039              :         }
    2040              :     }
    2041              : 
    2042            0 :     const QList<QGraphicsItem*> graphicsItemList = scene()->items();
    2043            0 :     for (QGraphicsItem* graphicsItem : graphicsItemList) {
    2044            0 :         int stave = graphicsItem->data(0).value<int>();
    2045            0 :         ElementType elementType = graphicsItem->data(1).value<ElementType>();
    2046            0 :         Measure* measure = static_cast<Measure*>(graphicsItem->data(2).value<void*>());
    2047              : 
    2048            0 :         std::tuple<Measure*, int, ElementType> targetTuple(measure, stave, elementType);
    2049            0 :         std::set<std::tuple<Measure*, int, ElementType> >::iterator it;
    2050            0 :         it = metaLabelsSet.find(targetTuple);
    2051              : 
    2052            0 :         if (stave == -1 && it != metaLabelsSet.end()) {
    2053              :             //Make sure the element is correct
    2054            0 :             const std::vector<EngravingItem*>& elementList = interaction()->selection()->elements();
    2055            0 :             EngravingItem* targetElement = static_cast<EngravingItem*>(graphicsItem->data(4).value<void*>());
    2056            0 :             Segment* seg = static_cast<Segment*>(graphicsItem->data(6).value<void*>());
    2057              : 
    2058            0 :             if (targetElement) {
    2059            0 :                 for (EngravingItem* element : elementList) {
    2060            0 :                     if (element == targetElement) {
    2061            0 :                         QGraphicsRectItem* graphicsRectItem = qgraphicsitem_cast<QGraphicsRectItem*>(graphicsItem);
    2062            0 :                         if (graphicsRectItem) {
    2063            0 :                             graphicsRectItem->setBrush(QBrush(activeTheme().selectionColor));
    2064              :                         }
    2065              :                     }
    2066              :                 }
    2067            0 :             } else if (seg) {
    2068            0 :                 for (EngravingItem* element : elementList) {
    2069            0 :                     QGraphicsRectItem* graphicsRectItem = qgraphicsitem_cast<QGraphicsRectItem*>(graphicsItem);
    2070            0 :                     if (graphicsRectItem) {
    2071            0 :                         for (size_t track = 0; track < score()->nstaves() * VOICES; track++) {
    2072            0 :                             if (element == seg->element(track)) {
    2073            0 :                                 graphicsRectItem->setBrush(QBrush(activeTheme().selectionColor));
    2074              :                             }
    2075              :                         }
    2076              :                     }
    2077              :                 }
    2078              :             } else {
    2079            0 :                 QGraphicsRectItem* graphicsRectItem = qgraphicsitem_cast<QGraphicsRectItem*>(graphicsItem);
    2080            0 :                 if (graphicsRectItem) {
    2081            0 :                     graphicsRectItem->setBrush(QBrush(activeTheme().selectionColor));
    2082              :                 }
    2083              :             }
    2084              :         }
    2085              :         // Change color from gray to only blue
    2086            0 :         else if (it != metaLabelsSet.end()) {
    2087            0 :             QGraphicsRectItem* graphicsRectItem = qgraphicsitem_cast<QGraphicsRectItem*>(graphicsItem);
    2088            0 :             graphicsRectItem->setBrush(QBrush(QColor(graphicsRectItem->brush().color().red(),
    2089            0 :                                                      graphicsRectItem->brush().color().green(),
    2090            0 :                                                      255)));
    2091            0 :             _selectionPath.addRect(graphicsRectItem->rect());
    2092              :         } else {
    2093              :             // Ensure unselected measures are not marked selected
    2094            0 :             QGraphicsRectItem* graphicsRectItem = qgraphicsitem_cast<QGraphicsRectItem*>(graphicsItem);
    2095            0 :             if (graphicsRectItem && graphicsRectItem->data(keyItemType).value<ItemType>() == ItemType::TYPE_MEASURE) {
    2096            0 :                 graphicsRectItem->setBrush(QBrush(colorBox(graphicsRectItem)));
    2097              :             }
    2098              :         }
    2099              :     }
    2100              : 
    2101            0 :     if (selectionItem) {
    2102            0 :         scene()->removeItem(selectionItem);
    2103            0 :         delete selectionItem;
    2104            0 :         selectionItem = nullptr;
    2105              :     }
    2106              : 
    2107            0 :     selectionItem = new QGraphicsPathItem(_selectionPath.simplified());
    2108            0 :     if (selection->isRange()) {
    2109            0 :         selectionItem->setPen(QPen(QColor(0, 0, 255), 3));
    2110              :     } else {
    2111            0 :         selectionItem->setPen(QPen(QColor(0, 0, 0), 1));
    2112              :     }
    2113              : 
    2114            0 :     selectionItem->setBrush(Qt::NoBrush);
    2115            0 :     selectionItem->setZValue(-1);
    2116            0 :     scene()->addItem(selectionItem);
    2117              : 
    2118            0 :     if (std::get<0>(_oldHoverInfo)) {
    2119            0 :         std::get<0>(_oldHoverInfo) = nullptr;
    2120            0 :         std::get<1>(_oldHoverInfo) = -1;
    2121              :     }
    2122            0 : }
    2123              : 
    2124              : //---------------------------------------------------------
    2125              : //   Timeline::mousePressEvent
    2126              : //---------------------------------------------------------
    2127              : 
    2128            0 : void Timeline::mousePressEvent(QMouseEvent* event)
    2129              : {
    2130            0 :     if (!score()) {
    2131            0 :         return;
    2132              :     }
    2133              : 
    2134            0 :     if (event->button() == Qt::RightButton) {
    2135            0 :         return;
    2136              :     }
    2137              : 
    2138            0 :     TRACEFUNC;
    2139              : 
    2140              :     // Set as clicked
    2141            0 :     _mousePressed = true;
    2142            0 :     scene()->clearSelection();
    2143              : 
    2144            0 :     QPointF scenePt = mapToScene(event->pos());
    2145              :     // Set as old location
    2146            0 :     _oldLoc = QPoint(int(scenePt.x()), int(scenePt.y()));
    2147            0 :     QList<QGraphicsItem*> graphicsItemList = scene()->items(scenePt);
    2148              :     // Find highest z value for rect
    2149            0 :     int maxZValue = -4;
    2150            0 :     QGraphicsItem* currGraphicsItem = nullptr;
    2151            0 :     for (QGraphicsItem* graphicsItem : graphicsItemList) {
    2152            0 :         QGraphicsRectItem* graphicsRectItem = qgraphicsitem_cast<QGraphicsRectItem*>(graphicsItem);
    2153            0 :         if (graphicsRectItem && graphicsItem->zValue() > maxZValue) {
    2154            0 :             currGraphicsItem = graphicsItem;
    2155            0 :             maxZValue = graphicsItem->zValue();
    2156              :         }
    2157              :     }
    2158            0 :     if (currGraphicsItem) {
    2159            0 :         int stave = currGraphicsItem->data(0).value<int>();
    2160            0 :         Measure* currMeasure = static_cast<Measure*>(currGraphicsItem->data(2).value<void*>());
    2161            0 :         if (numToStaff(stave) && !numToStaff(stave)->show()) {
    2162            0 :             return;
    2163              :         }
    2164              : 
    2165            0 :         if (!currMeasure) {
    2166            0 :             int nmeta = nmetas();
    2167            0 :             int bottomOfMeta = nmeta * _gridHeight + verticalScrollBar()->value();
    2168              : 
    2169              :             // Handle measure box clicks
    2170            0 :             if (scenePt.y() > (nmeta - 1) * _gridHeight + verticalScrollBar()->value()
    2171            0 :                 && scenePt.y() < bottomOfMeta) {
    2172            0 :                 QRectF tmp(scenePt.x(), 0, 3, nmeta * _gridHeight + nstaves() * _gridHeight);
    2173            0 :                 QList<QGraphicsItem*> gl = scene()->items(tmp);
    2174            0 :                 Measure* measure = nullptr;
    2175              : 
    2176            0 :                 for (QGraphicsItem* graphicsItem : gl) {
    2177            0 :                     measure = static_cast<Measure*>(graphicsItem->data(2).value<void*>());
    2178              :                     //-3 z value is the grid square values
    2179            0 :                     if (graphicsItem->zValue() == -3 && measure) {
    2180            0 :                         break;
    2181              :                     }
    2182              :                 }
    2183              : 
    2184            0 :                 if (measure) {
    2185            0 :                     interaction()->showItem(measure);
    2186              :                 }
    2187            0 :             }
    2188            0 :             if (scenePt.y() < bottomOfMeta) {
    2189            0 :                 return;
    2190              :             }
    2191              : 
    2192            0 :             QList<QGraphicsItem*> gl = items(event->pos());
    2193            0 :             for (QGraphicsItem* graphicsItem : gl) {
    2194            0 :                 currMeasure = static_cast<Measure*>(graphicsItem->data(2).value<void*>());
    2195            0 :                 stave = graphicsItem->data(0).value<int>();
    2196            0 :                 if (currMeasure) {
    2197            0 :                     break;
    2198              :                 }
    2199              :             }
    2200            0 :             if (!currMeasure) {
    2201            0 :                 interaction()->clearSelection();
    2202            0 :                 return;
    2203              :             }
    2204            0 :         }
    2205              : 
    2206            0 :         bool metaValueClicked = currGraphicsItem->data(3).value<bool>();
    2207              : 
    2208            0 :         scene()->clearSelection();
    2209            0 :         if (metaValueClicked) {
    2210            0 :             _metaValue = true;
    2211            0 :             _oldSelectionRect = QRect();
    2212              : 
    2213            0 :             interaction()->showItem(currMeasure, 0);
    2214            0 :             verticalScrollBar()->setValue(0);
    2215              : 
    2216            0 :             Segment* seg = static_cast<Segment*>(currGraphicsItem->data(6).value<void*>());
    2217              : 
    2218            0 :             if (seg) {
    2219            0 :                 std::vector<EngravingItem*> elements;
    2220              : 
    2221            0 :                 for (size_t track = 0; track < score()->nstaves() * VOICES; track++) {
    2222            0 :                     EngravingItem* element = seg->element(track);
    2223            0 :                     if (element) {
    2224            0 :                         elements.push_back(element);
    2225              :                     }
    2226              :                 }
    2227              : 
    2228            0 :                 if (elements.empty()) {
    2229            0 :                     interaction()->clearSelection();
    2230              :                 } else {
    2231            0 :                     interaction()->select(elements);
    2232              :                 }
    2233            0 :             } else {
    2234              :                 // Also select the elements that they correspond to
    2235            0 :                 ElementType elementType = currGraphicsItem->data(1).value<ElementType>();
    2236            0 :                 SegmentType segmentType = SegmentType::Invalid;
    2237            0 :                 if (elementType == ElementType::KEYSIG) {
    2238            0 :                     segmentType = SegmentType::KeySig;
    2239            0 :                 } else if (elementType == ElementType::TIMESIG) {
    2240            0 :                     segmentType = SegmentType::TimeSig;
    2241              :                 }
    2242              : 
    2243            0 :                 if (segmentType != SegmentType::Invalid) {
    2244            0 :                     Segment* currSeg = currMeasure->first();
    2245            0 :                     for (; currSeg && currSeg->segmentType() != segmentType; currSeg = currSeg->next()) {
    2246              :                     }
    2247            0 :                     if (currSeg) {
    2248            0 :                         std::vector<EngravingItem*> elements;
    2249              : 
    2250            0 :                         for (size_t j = 0; j < score()->nstaves(); j++) {
    2251            0 :                             EngravingItem* element = currSeg->firstElementForNavigation(j);
    2252            0 :                             if (element) {
    2253            0 :                                 elements.push_back(element);
    2254              :                             }
    2255              :                         }
    2256              : 
    2257            0 :                         if (elements.empty()) {
    2258            0 :                             interaction()->clearSelection();
    2259              :                         } else {
    2260            0 :                             interaction()->select(elements);
    2261              :                         }
    2262            0 :                     }
    2263              :                 } else {
    2264              :                     // Select just the element for tempo_text
    2265            0 :                     EngravingItem* element = static_cast<EngravingItem*>(currGraphicsItem->data(4).value<void*>());
    2266            0 :                     if (element) {
    2267            0 :                         interaction()->select({ element });
    2268            0 :                     } else if (currMeasure) {
    2269            0 :                         interaction()->select({ currMeasure });
    2270              :                     } else {
    2271            0 :                         interaction()->clearSelection();
    2272              :                     }
    2273              :                 }
    2274              :             }
    2275              :         } else {
    2276              :             // Handle cell clicks
    2277            0 :             if (event->modifiers() == Qt::ShiftModifier) {
    2278            0 :                 if (currMeasure->mmRest()) {
    2279            0 :                     currMeasure = currMeasure->mmRest();
    2280            0 :                 } else if (!currMeasure->isMMRest()) {
    2281            0 :                     currMeasure = currMeasure->prevMeasureMM();
    2282              :                 }
    2283              : 
    2284            0 :                 if (currMeasure) {
    2285            0 :                     interaction()->select({ currMeasure }, SelectType::RANGE, stave);
    2286              :                 }
    2287            0 :             } else if (event->modifiers() == Qt::ControlModifier) {
    2288            0 :                 if (interaction()->selection()->isNone()) {
    2289            0 :                     if (currMeasure->mmRest()) {
    2290            0 :                         currMeasure = currMeasure->mmRest();
    2291            0 :                     } else if (!currMeasure->isMMRest()) {
    2292            0 :                         currMeasure = currMeasure->prevMeasureMM();
    2293              :                     }
    2294              : 
    2295            0 :                     if (currMeasure) {
    2296            0 :                         interaction()->select({ currMeasure }, SelectType::RANGE, 0);
    2297            0 :                         interaction()->select({ currMeasure }, SelectType::RANGE, score()->nstaves() - 1);
    2298              :                     }
    2299              :                 } else {
    2300            0 :                     interaction()->clearSelection();
    2301              :                 }
    2302              :             } else {
    2303            0 :                 if (currMeasure->mmRest()) {
    2304            0 :                     currMeasure = currMeasure->mmRest();
    2305            0 :                 } else if (!currMeasure->isMMRest()) {
    2306            0 :                     currMeasure = currMeasure->prevMeasureMM();
    2307              :                 }
    2308              : 
    2309            0 :                 if (currMeasure) {
    2310            0 :                     interaction()->select({ currMeasure }, SelectType::SINGLE, stave);
    2311              :                 }
    2312              :             }
    2313              : 
    2314            0 :             if (currMeasure) {
    2315            0 :                 interaction()->showItem(currMeasure, stave);
    2316              :             }
    2317              :         }
    2318              :     } else {
    2319            0 :         interaction()->clearSelection();
    2320              :     }
    2321              : 
    2322            0 :     this->seekSelection();
    2323            0 : }
    2324              : 
    2325            0 : void Timeline::seekSelection()
    2326              : {
    2327            0 :     const INotationSelectionPtr selection = interaction()->selection();
    2328            0 :     const std::vector<EngravingItem*>& elements = selection->elements();
    2329            0 :     if (elements.empty()) {
    2330            0 :         return;
    2331              :     }
    2332              : 
    2333            0 :     EngravingItem* elementToSeek = elements.front();
    2334            0 :     for (EngravingItem* element : elements) {
    2335            0 :         if (element->tick() > elementToSeek->tick()) {
    2336            0 :             continue;
    2337              :         }
    2338            0 :         elementToSeek = element;
    2339              :     }
    2340              : 
    2341            0 :     playbackController()->seekElement(elementToSeek);
    2342            0 : }
    2343              : 
    2344              : //---------------------------------------------------------
    2345              : //   Timeline::mouseMoveEvent
    2346              : //---------------------------------------------------------
    2347              : 
    2348            0 : void Timeline::mouseMoveEvent(QMouseEvent* event)
    2349              : {
    2350            0 :     QPointF newLoc = mapToScene(event->pos());
    2351            0 :     if (!_mousePressed) {
    2352            0 :         if (cursorIsOn(event->pos()) == "meta") {
    2353            0 :             setCursor(Qt::ArrowCursor);
    2354            0 :             mouseOver(newLoc);
    2355            0 :         } else if (cursorIsOn(event->pos()) == "invalid") {
    2356            0 :             setCursor(Qt::ForbiddenCursor);
    2357              :         } else {
    2358            0 :             setCursor(Qt::ArrowCursor);
    2359              :         }
    2360              : 
    2361            0 :         emit moved(QPointF(-1, -1));
    2362            0 :         return;
    2363              :     }
    2364              : 
    2365            0 :     if (state == ViewState::NORMAL) {
    2366            0 :         if (event->modifiers() == Qt::ShiftModifier) {
    2367              :             // Slight wiggle room for selection (Same as score)
    2368            0 :             if (std::abs(newLoc.x() - _oldLoc.x()) > 2
    2369            0 :                 || std::abs(newLoc.y() - _oldLoc.y()) > 2) {
    2370            0 :                 interaction()->clearSelection();
    2371            0 :                 updateGrid();
    2372            0 :                 state = ViewState::LASSO;
    2373            0 :                 _selectionBox = new QGraphicsRectItem();
    2374            0 :                 _selectionBox->setRect(_oldLoc.x(), _oldLoc.y(), 0, 0);
    2375            0 :                 _selectionBox->setPen(QPen(QColor(0, 0, 255), 2));
    2376            0 :                 _selectionBox->setBrush(QBrush(QColor(0, 0, 255, 50)));
    2377            0 :                 scene()->addItem(_selectionBox);
    2378              :             }
    2379              :         } else {
    2380            0 :             state = ViewState::DRAG;
    2381            0 :             setCursor(Qt::SizeAllCursor);
    2382              :         }
    2383              :     }
    2384              : 
    2385            0 :     if (state == ViewState::LASSO) {
    2386            0 :         QRect tmp = QRect((_oldLoc.x() < newLoc.x()) ? _oldLoc.x() : newLoc.x(),
    2387            0 :                           (_oldLoc.y() < newLoc.y()) ? _oldLoc.y() : newLoc.y(),
    2388            0 :                           std::abs(newLoc.x() - _oldLoc.x()),
    2389            0 :                           std::abs(newLoc.y() - _oldLoc.y()));
    2390            0 :         _selectionBox->setRect(tmp);
    2391            0 :     } else if (state == ViewState::DRAG) {
    2392            0 :         int x_offset = int(_oldLoc.x()) - int(newLoc.x());
    2393            0 :         int yOffset = int(_oldLoc.y()) - int(newLoc.y());
    2394            0 :         horizontalScrollBar()->setValue(horizontalScrollBar()->value() + x_offset);
    2395            0 :         verticalScrollBar()->setValue(verticalScrollBar()->value() + yOffset);
    2396              :     }
    2397              : 
    2398            0 :     emit moved(QPointF(-1, -1));
    2399              : }
    2400              : 
    2401              : //---------------------------------------------------------
    2402              : //   Timeline::mouseReleaseEvent
    2403              : //---------------------------------------------------------
    2404              : 
    2405            0 : void Timeline::mouseReleaseEvent(QMouseEvent*)
    2406              : {
    2407            0 :     _mousePressed = false;
    2408              : 
    2409            0 :     if (state == ViewState::LASSO) {
    2410            0 :         scene()->removeItem(_selectionBox);
    2411            0 :         interaction()->clearSelection();
    2412              : 
    2413              :         int width, height;
    2414            0 :         QPoint loc = mapFromScene(_selectionBox->rect().topLeft());
    2415            0 :         width = int(_selectionBox->rect().width());
    2416            0 :         height = int(_selectionBox->rect().height());
    2417              : 
    2418            0 :         QList<QGraphicsItem*> graphicsItemList = items(QRect(loc.x(), loc.y(), width, height));
    2419              :         // Find top left and bottom right to create selection
    2420            0 :         QGraphicsItem* tlGraphicsItem = nullptr;
    2421            0 :         QGraphicsItem* brGraphicsItem = nullptr;
    2422            0 :         for (QGraphicsItem* graphicsItem : graphicsItemList) {
    2423            0 :             Measure* currMeasure = static_cast<Measure*>(graphicsItem->data(2).value<void*>());
    2424            0 :             if (!currMeasure) {
    2425            0 :                 continue;
    2426              :             }
    2427            0 :             int stave = graphicsItem->data(0).value<int>();
    2428            0 :             if (stave == -1) {
    2429            0 :                 continue;
    2430              :             }
    2431              : 
    2432            0 :             if (!tlGraphicsItem && !brGraphicsItem) {
    2433            0 :                 tlGraphicsItem = graphicsItem;
    2434            0 :                 brGraphicsItem = graphicsItem;
    2435            0 :                 continue;
    2436              :             }
    2437              : 
    2438            0 :             if (graphicsItem->boundingRect().top() < tlGraphicsItem->boundingRect().top()) {
    2439            0 :                 tlGraphicsItem = graphicsItem;
    2440              :             }
    2441            0 :             if (graphicsItem->boundingRect().left() < tlGraphicsItem->boundingRect().left()) {
    2442            0 :                 tlGraphicsItem = graphicsItem;
    2443              :             }
    2444              : 
    2445            0 :             if (graphicsItem->boundingRect().bottom() > brGraphicsItem->boundingRect().bottom()) {
    2446            0 :                 brGraphicsItem = graphicsItem;
    2447              :             }
    2448            0 :             if (graphicsItem->boundingRect().right() > brGraphicsItem->boundingRect().right()) {
    2449            0 :                 brGraphicsItem = graphicsItem;
    2450              :             }
    2451              :         }
    2452              : 
    2453              :         // Select single tlGraphicsItem and then range brGraphicsItem
    2454            0 :         if (tlGraphicsItem && brGraphicsItem) {
    2455            0 :             Measure* tlMeasure = static_cast<Measure*>(tlGraphicsItem->data(2).value<void*>());
    2456            0 :             int tlStave = tlGraphicsItem->data(0).value<int>();
    2457            0 :             Measure* brMeasure = static_cast<Measure*>(brGraphicsItem->data(2).value<void*>());
    2458            0 :             int brStave = brGraphicsItem->data(0).value<int>();
    2459            0 :             if (tlMeasure && brMeasure) {
    2460              :                 // Focus selection of mmRests here
    2461            0 :                 if (tlMeasure->mmRest()) {
    2462            0 :                     tlMeasure = tlMeasure->mmRest();
    2463            0 :                 } else if (!tlMeasure->isMMRest()) {
    2464            0 :                     tlMeasure = tlMeasure->prevMeasureMM();
    2465              :                 }
    2466            0 :                 if (brMeasure->mmRest()) {
    2467            0 :                     brMeasure = brMeasure->mmRest();
    2468            0 :                 } else if (!brMeasure->isMMRest()) {
    2469            0 :                     brMeasure = brMeasure->prevMeasureMM();
    2470              :                 }
    2471              : 
    2472            0 :                 if (tlMeasure) {
    2473            0 :                     interaction()->select({ tlMeasure }, SelectType::SINGLE, tlStave);
    2474              :                 }
    2475              : 
    2476            0 :                 if (brMeasure) {
    2477            0 :                     interaction()->select({ brMeasure }, SelectType::RANGE, brStave);
    2478              :                 }
    2479              :             }
    2480              : 
    2481            0 :             if (tlMeasure) {
    2482            0 :                 interaction()->showItem(tlMeasure, tlStave);
    2483              :             }
    2484              :         }
    2485            0 :     } else if (state == ViewState::DRAG) {
    2486            0 :         setCursor(Qt::ArrowCursor);
    2487              :     }
    2488            0 :     state = ViewState::NORMAL;
    2489            0 : }
    2490              : 
    2491              : //---------------------------------------------------------
    2492              : //   Timeline::leaveEvent
    2493              : //---------------------------------------------------------
    2494              : 
    2495            0 : void Timeline::leaveEvent(QEvent*)
    2496              : {
    2497            0 :     if (!rect().contains(mapFromGlobal(QCursor::pos()))) {
    2498            0 :         QPointF p = mapToScene(mapFromGlobal(QCursor::pos()));
    2499            0 :         mouseOver(p);
    2500              :     }
    2501            0 : }
    2502              : 
    2503              : //---------------------------------------------------------
    2504              : //   Timeline::wheelEvent
    2505              : //---------------------------------------------------------
    2506              : 
    2507            0 : void Timeline::wheelEvent(QWheelEvent* event)
    2508              : {
    2509            0 :     if (event->modifiers().testFlag(Qt::ControlModifier)) {
    2510            0 :         qreal originalCursorPos = mapToScene(mapFromGlobal(QCursor::pos())).x();
    2511            0 :         int originalScrollValue = horizontalScrollBar()->value();
    2512            0 :         qreal ratio = originalCursorPos / qreal(getWidth());
    2513              : 
    2514            0 :         if (event->angleDelta().y() > 0 && _gridWidth < _maxZoom) {
    2515            0 :             _gridWidth++;
    2516            0 :             updateGridFull();
    2517            0 :         } else if (event->angleDelta().y() < 0 && _gridWidth > _minZoom) {
    2518            0 :             _gridWidth--;
    2519            0 :             updateGridFull();
    2520              :         }
    2521              : 
    2522              :         // Attempt to keep mouse in original spot
    2523            0 :         qreal newPos = qreal(getWidth()) * ratio;
    2524            0 :         int offset = newPos - originalCursorPos;
    2525            0 :         horizontalScrollBar()->setValue(originalScrollValue + offset);
    2526            0 :     } else if (event->modifiers().testFlag(Qt::ShiftModifier)) {
    2527            0 :         qreal numOfSteps = qreal(event->angleDelta().y()) / 2;
    2528            0 :         horizontalScrollBar()->setValue(horizontalScrollBar()->value() - int(numOfSteps));
    2529              :     } else {
    2530            0 :         QGraphicsView::wheelEvent(event);
    2531              :     }
    2532            0 : }
    2533              : 
    2534              : //---------------------------------------------------------
    2535              : //   showEvent
    2536              : //---------------------------------------------------------
    2537              : 
    2538            0 : void Timeline::showEvent(QShowEvent* evt)
    2539              : {
    2540            0 :     QGraphicsView::showEvent(evt);
    2541            0 :     if (!evt->spontaneous()) {
    2542            0 :         setNotation(m_notation);
    2543              :     }
    2544            0 : }
    2545              : 
    2546              : //---------------------------------------------------------
    2547              : //   changeEvent
    2548              : //---------------------------------------------------------
    2549              : 
    2550            0 : void Timeline::changeEvent(QEvent* event)
    2551              : {
    2552            0 :     QGraphicsView::changeEvent(event);
    2553            0 :     if (event->type() == QEvent::LanguageChange) {
    2554            0 :         _metas.clear();
    2555            0 :         _metas.push_back({ muse::qtrc("notation/timeline", "Tempo"), &Timeline::tempoMeta, true });
    2556            0 :         _metas.push_back({ muse::qtrc("notation/timeline", "Time signature"), &Timeline::timeMeta, true });
    2557            0 :         _metas.push_back({ muse::qtrc("notation/timeline", "Rehearsal mark"), &Timeline::rehearsalMeta, true });
    2558            0 :         _metas.push_back({ muse::qtrc("notation/timeline", "Key signature"), &Timeline::keyMeta, true });
    2559            0 :         _metas.push_back({ muse::qtrc("notation/timeline", "Barlines"), &Timeline::barlineMeta, true });
    2560            0 :         _metas.push_back({ muse::qtrc("notation/timeline", "Jumps and markers"), &Timeline::jumpMarkerMeta, true });
    2561            0 :         _metas.push_back({ muse::qtrc("notation/timeline", "Measures"), &Timeline::measureMeta, true });
    2562              : 
    2563            0 :         updateGridFull();
    2564              :     }
    2565            0 : }
    2566              : 
    2567              : //---------------------------------------------------------
    2568              : //   Timeline::updateGrid
    2569              : //---------------------------------------------------------
    2570              : 
    2571            0 : void Timeline::updateGrid(int startMeasure, int endMeasure)
    2572              : {
    2573            0 :     TRACEFUNC;
    2574              : 
    2575            0 :     if (score() && score()->firstMeasure()) {
    2576            0 :         drawGrid(static_cast<int>(nstaves()), static_cast<int>(score()->nmeasures()), startMeasure, endMeasure);
    2577            0 :         updateView();
    2578            0 :         drawSelection();
    2579            0 :         mouseOver(mapToScene(mapFromGlobal(QCursor::pos())));
    2580            0 :         _rowNames->updateLabels(getLabels(), _gridHeight);
    2581              :     }
    2582            0 :     viewport()->update();
    2583            0 : }
    2584              : 
    2585              : //---------------------------------------------------------
    2586              : //   updateGridFromCmdState
    2587              : //---------------------------------------------------------
    2588              : 
    2589            0 : void Timeline::updateGridFromCmdState()
    2590              : {
    2591            0 :     if (!score()) {
    2592            0 :         updateGridFull();
    2593            0 :         return;
    2594              :     }
    2595              : 
    2596            0 :     const CmdState& cState = score()->cmdState();
    2597              : 
    2598            0 :     const bool layoutChanged = cState.layoutRange();
    2599              : 
    2600            0 :     if (!layoutChanged) {
    2601            0 :         updateGridView();
    2602            0 :         return;
    2603              :     }
    2604              : 
    2605            0 :     const bool layoutAll = layoutChanged && (cState.startTick() < Fraction(0, 1) || cState.endTick() < Fraction(0, 1));
    2606              : 
    2607            0 :     const Measure* startMeasure = layoutAll ? nullptr : score()->tick2measure(cState.startTick());
    2608            0 :     const int startMeasureIndex = startMeasure ? startMeasure->measureIndex() : 0;
    2609              : 
    2610            0 :     const Measure* endMeasure = layoutAll ? nullptr : score()->tick2measure(cState.endTick());
    2611            0 :     const int endMeasureIndex = endMeasure ? (endMeasure->measureIndex() + 1) : static_cast<int>(score()->nmeasures());
    2612              : 
    2613            0 :     updateGrid(startMeasureIndex, endMeasureIndex);
    2614              : }
    2615              : 
    2616              : //---------------------------------------------------------
    2617              : //   Timeline::setNotation
    2618              : //---------------------------------------------------------
    2619              : 
    2620            0 : void Timeline::setNotation(INotationPtr notation)
    2621              : {
    2622            0 :     m_notation = notation;
    2623              : 
    2624            0 :     clearScene();
    2625              : 
    2626            0 :     if (m_notation) {
    2627            0 :         drawGrid(nstaves(), static_cast<int>(score()->nmeasures()));
    2628            0 :         drawSelection();
    2629            0 :         changeSelection(SelState::NONE);
    2630            0 :         _rowNames->updateLabels(getLabels(), _gridHeight);
    2631              :     } else {
    2632              :         // Clear timeline if no score is present
    2633            0 :         if (_splitter && _splitter->count() > 0) {
    2634            0 :             TRowLabels* tRowLabels = static_cast<TRowLabels*>(_splitter->widget(0));
    2635            0 :             std::vector<std::pair<QString, bool> > noLabels;
    2636            0 :             tRowLabels->updateLabels(noLabels, 0);
    2637            0 :         }
    2638            0 :         _metaRows.clear();
    2639            0 :         setSceneRect(0, 0, 0, 0);
    2640              :     }
    2641            0 : }
    2642              : 
    2643              : //---------------------------------------------------------
    2644              : //   Timeline::updateView
    2645              : //---------------------------------------------------------
    2646              : 
    2647            0 : void Timeline::updateView()
    2648              : {
    2649            0 :     if (!score()) {
    2650            0 :         return;
    2651              :     }
    2652              : 
    2653            0 :     TRACEFUNC;
    2654              : 
    2655              :     //! FIXME
    2656            0 :     RectF canvas;        // = QRectF(_cv->matrix().inverted().mapRect(_cv->geometry()));
    2657              : 
    2658              :     // Find visible elements in timeline
    2659            0 :     QPainterPath visiblePainterPath = QPainterPath();
    2660            0 :     visiblePainterPath.setFillRule(Qt::WindingFill);
    2661              : 
    2662              :     // Find visible measures of score
    2663            0 :     int measureIndex = 0;
    2664            0 :     const int numMetas = nmetas();
    2665              : 
    2666            0 :     for (Measure* currMeasure = score()->firstMeasure(); currMeasure; currMeasure = currMeasure->nextMeasure(), ++measureIndex) {
    2667            0 :         System* system = currMeasure->system();
    2668              : 
    2669            0 :         if (currMeasure->mmRest() && score()->style().styleB(Sid::createMultiMeasureRests)) {
    2670              :             // Handle mmRests
    2671            0 :             Measure* mmrestMeasure = currMeasure->mmRest();
    2672            0 :             system = mmrestMeasure->system();
    2673            0 :             if (!system) {
    2674            0 :                 measureIndex += currMeasure->mmRestCount();
    2675            0 :                 continue;
    2676              :             }
    2677              : 
    2678              :             // Add all measures within mmRest to visibleItemsSet if mmRest_visible
    2679            0 :             for (; currMeasure != mmrestMeasure->mmRestLast(); currMeasure = currMeasure->nextMeasure(), ++measureIndex) {
    2680            0 :                 for (size_t staff = 0; staff < score()->staves().size(); staff++) {
    2681            0 :                     if (!score()->staff(staff)->show()) {
    2682            0 :                         continue;
    2683              :                     }
    2684            0 :                     RectF staveRect = RectF(system->canvasBoundingRect().left(),
    2685              :                                             system->staffCanvasYpage(staff),
    2686              :                                             system->width(),
    2687            0 :                                             system->staff(staff)->bbox().height());
    2688            0 :                     RectF showRect = mmrestMeasure->canvasBoundingRect().intersected(staveRect);
    2689              : 
    2690            0 :                     if (canvas.intersects(showRect)) {
    2691            0 :                         visiblePainterPath.addRect(getMeasureRect(measureIndex, static_cast<int>(staff), numMetas));
    2692              :                     }
    2693              :                 }
    2694              :             }
    2695              : 
    2696              :             // Handle last measure in mmRest
    2697            0 :             for (size_t staff = 0; staff < score()->staves().size(); staff++) {
    2698            0 :                 if (!score()->staff(staff)->show()) {
    2699            0 :                     continue;
    2700              :                 }
    2701            0 :                 RectF staveRect = RectF(system->canvasBoundingRect().left(),
    2702              :                                         system->staffCanvasYpage(staff),
    2703              :                                         system->width(),
    2704            0 :                                         system->staff(staff)->bbox().height());
    2705            0 :                 RectF showRect = mmrestMeasure->canvasBoundingRect().intersected(staveRect);
    2706              : 
    2707            0 :                 if (canvas.intersects(showRect)) {
    2708            0 :                     visiblePainterPath.addRect(getMeasureRect(measureIndex, static_cast<int>(staff), numMetas));
    2709              :                 }
    2710              :             }
    2711            0 :             continue;
    2712            0 :         }
    2713              : 
    2714            0 :         if (!system) {
    2715            0 :             continue;
    2716              :         }
    2717              : 
    2718            0 :         for (size_t staff = 0; staff < score()->staves().size(); staff++) {
    2719            0 :             if (!score()->staff(staff)->show()) {
    2720            0 :                 continue;
    2721              :             }
    2722            0 :             RectF staveRect = RectF(system->canvasBoundingRect().left(),
    2723              :                                     system->staffCanvasYpage(staff),
    2724              :                                     system->width(),
    2725            0 :                                     system->staff(staff)->bbox().height());
    2726            0 :             RectF showRect = currMeasure->canvasBoundingRect().intersected(staveRect);
    2727              : 
    2728            0 :             if (canvas.intersects(showRect)) {
    2729            0 :                 visiblePainterPath.addRect(getMeasureRect(measureIndex, static_cast<int>(staff), numMetas));
    2730              :             }
    2731              :         }
    2732              :     }
    2733              : 
    2734            0 :     if (nonVisiblePathItem) {
    2735            0 :         scene()->removeItem(nonVisiblePathItem);
    2736            0 :         delete nonVisiblePathItem;
    2737            0 :         nonVisiblePathItem = nullptr;
    2738              :     }
    2739            0 :     if (visiblePathItem) {
    2740            0 :         scene()->removeItem(visiblePathItem);
    2741            0 :         delete visiblePathItem;
    2742            0 :         visiblePathItem = nullptr;
    2743              :     }
    2744              : 
    2745            0 :     QPainterPath nonVisiblePainterPath = QPainterPath();
    2746            0 :     nonVisiblePainterPath.setFillRule(Qt::WindingFill);
    2747              : 
    2748            0 :     QRectF timelineRect = QRectF(0, 0, getWidth(), getHeight());
    2749            0 :     nonVisiblePainterPath.addRect(timelineRect);
    2750              : 
    2751            0 :     nonVisiblePainterPath = nonVisiblePainterPath.subtracted(visiblePainterPath);
    2752              : 
    2753            0 :     nonVisiblePathItem = new QGraphicsPathItem(nonVisiblePainterPath.simplified());
    2754              : 
    2755            0 :     QPen nonVisiblePen = QPen(activeTheme().nonVisiblePenColor);
    2756            0 :     QBrush nonVisibleBrush = QBrush(activeTheme().nonVisibleBrushColor);
    2757            0 :     nonVisiblePathItem->setPen(QPen(nonVisibleBrush.color()));
    2758            0 :     nonVisiblePathItem->setBrush(nonVisibleBrush);
    2759            0 :     nonVisiblePathItem->setZValue(-3);
    2760              : 
    2761            0 :     visiblePathItem = new QGraphicsPathItem(visiblePainterPath.simplified());
    2762            0 :     visiblePathItem->setPen(nonVisiblePen);
    2763            0 :     visiblePathItem->setBrush(Qt::NoBrush);
    2764            0 :     visiblePathItem->setZValue(-2);
    2765              : 
    2766            0 :     scene()->addItem(nonVisiblePathItem);
    2767            0 :     scene()->addItem(visiblePathItem);
    2768            0 : }
    2769              : 
    2770              : //---------------------------------------------------------
    2771              : //   Timeline::nstaves
    2772              : //---------------------------------------------------------
    2773              : 
    2774            0 : int Timeline::nstaves() const
    2775              : {
    2776            0 :     return static_cast<int>(score()->staves().size());
    2777              : }
    2778              : 
    2779              : //---------------------------------------------------------
    2780              : //   Timeline::colorBox
    2781              : //---------------------------------------------------------
    2782              : 
    2783            0 : QColor Timeline::colorBox(QGraphicsRectItem* item)
    2784              : {
    2785            0 :     Measure* measure = static_cast<Measure*>(item->data(2).value<void*>());
    2786            0 :     staff_idx_t stave = static_cast<staff_idx_t>(item->data(0).value<int>());
    2787            0 :     for (Segment* seg = measure->first(); seg; seg = seg->next()) {
    2788            0 :         if (!seg->isChordRestType()) {
    2789            0 :             continue;
    2790              :         }
    2791            0 :         for (track_idx_t track = stave * VOICES; track < stave * VOICES + VOICES; track++) {
    2792            0 :             ChordRest* chordRest = seg->cr(track);
    2793            0 :             if (chordRest) {
    2794            0 :                 ElementType crt = chordRest->type();
    2795            0 :                 if (crt == ElementType::CHORD || crt == ElementType::MEASURE_REPEAT) {
    2796            0 :                     return activeTheme().colorBoxColor;
    2797              :                 }
    2798              :             }
    2799              :         }
    2800              :     }
    2801            0 :     return QColor(224, 224, 224);
    2802              : }
    2803              : 
    2804              : //---------------------------------------------------------
    2805              : //   Timeline::getLabels
    2806              : //---------------------------------------------------------
    2807              : 
    2808            0 : std::vector<std::pair<QString, bool> > Timeline::getLabels()
    2809              : {
    2810            0 :     if (!score()) {
    2811            0 :         std::vector<std::pair<QString, bool> > noLabels;
    2812            0 :         return noLabels;
    2813            0 :     }
    2814              : 
    2815            0 :     QList<Part*> partList = getParts();
    2816              :     // Transfer them into a vector of qstrings and then add the meta row names
    2817            0 :     std::vector<std::pair<QString, bool> > rowLabels;
    2818            0 :     if (_collapsedMeta) {
    2819            0 :         std::pair<QString, bool> first = std::make_pair("", true);
    2820            0 :         std::pair<QString, bool> second = std::make_pair(muse::qtrc("notation/timeline", "Measures"), true);
    2821            0 :         rowLabels.push_back(first);
    2822            0 :         rowLabels.push_back(second);
    2823            0 :     } else {
    2824            0 :         for (auto it = _metas.begin(); it != _metas.end(); ++it) {
    2825            0 :             std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> meta = *it;
    2826            0 :             if (!std::get<2>(meta)) {
    2827            0 :                 continue;
    2828              :             }
    2829            0 :             std::pair<QString, bool> metaLabel = std::make_pair(std::get<0>(meta), true);
    2830            0 :             rowLabels.push_back(metaLabel);
    2831            0 :         }
    2832              :     }
    2833              : 
    2834            0 :     for (int stave = 0; stave < partList.size(); stave++) {
    2835            0 :         QTextDocument doc;
    2836            0 :         QString partName = "";
    2837            0 :         doc.setHtml(partList.at(stave)->longName());
    2838            0 :         partName = doc.toPlainText();
    2839            0 :         if (partName.isEmpty()) {     // No Long instrument name? Fall back to Part name
    2840            0 :             doc.setHtml(partList.at(stave)->partName());
    2841            0 :             partName = doc.toPlainText();
    2842              :         }
    2843            0 :         if (partName.isEmpty()) {   // No Part name? Fall back to Instrument name
    2844            0 :             partName = partList.at(stave)->instrumentName();
    2845              :         }
    2846              : 
    2847            0 :         std::pair<QString, bool> instrumentLabel = std::make_pair(partName, partList.at(stave)->show());
    2848            0 :         rowLabels.push_back(instrumentLabel);
    2849            0 :     }
    2850            0 :     return rowLabels;
    2851            0 : }
    2852              : 
    2853              : //---------------------------------------------------------
    2854              : //   Timeline::handleScroll
    2855              : //---------------------------------------------------------
    2856              : 
    2857            0 : void Timeline::handleScroll(int value)
    2858              : {
    2859            0 :     if (!score()) {
    2860            0 :         return;
    2861              :     }
    2862              : 
    2863            0 :     for (auto it = _metaRows.begin(); it != _metaRows.end(); ++it) {
    2864            0 :         std::pair<QGraphicsItem*, int> pairGraphicsInt = *it;
    2865              : 
    2866            0 :         QGraphicsItem* graphicsItem = pairGraphicsInt.first;
    2867            0 :         QGraphicsRectItem* graphicsRectItem = qgraphicsitem_cast<QGraphicsRectItem*>(graphicsItem);
    2868            0 :         QGraphicsLineItem* graphicsLineItem = qgraphicsitem_cast<QGraphicsLineItem*>(graphicsItem);
    2869            0 :         QGraphicsPixmapItem* graphicsPixmapItem = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphicsItem);
    2870              : 
    2871            0 :         int rowY = pairGraphicsInt.second * _gridHeight;
    2872            0 :         int scrollbarValue = value;
    2873              : 
    2874            0 :         if (graphicsRectItem) {
    2875            0 :             QRectF rectf = graphicsRectItem->rect();
    2876            0 :             rectf.setY(qreal(scrollbarValue + rowY));
    2877            0 :             rectf.setHeight(_gridHeight);
    2878            0 :             graphicsRectItem->setRect(rectf);
    2879            0 :         } else if (graphicsLineItem) {
    2880            0 :             QLineF linef = graphicsLineItem->line();
    2881            0 :             linef.setLine(linef.x1(), rowY + scrollbarValue + 1, linef.x2(), rowY + scrollbarValue + 1);
    2882            0 :             graphicsLineItem->setLine(linef);
    2883            0 :         } else if (graphicsPixmapItem) {
    2884            0 :             graphicsPixmapItem->setY(qreal(scrollbarValue + rowY + 3));
    2885              :         } else {
    2886            0 :             graphicsItem->setY(qreal(scrollbarValue + rowY));
    2887              :         }
    2888              :     }
    2889            0 :     viewport()->update();
    2890              : }
    2891              : 
    2892              : //---------------------------------------------------------
    2893              : //   Timeline::mouseOver
    2894              : //---------------------------------------------------------
    2895              : 
    2896            0 : void Timeline::mouseOver(QPointF pos)
    2897              : {
    2898            0 :     TRACEFUNC;
    2899              : 
    2900              :     // Choose item with the largest original Z value...
    2901            0 :     QList<QGraphicsItem*> graphicsList = scene()->items(pos);
    2902            0 :     QGraphicsItem* hoveredGraphicsItem = 0;
    2903            0 :     int maxZValue = -1;
    2904            0 :     for (QGraphicsItem* currGraphicsItem : graphicsList) {
    2905            0 :         if (qgraphicsitem_cast<QGraphicsTextItem*>(currGraphicsItem)) {
    2906            0 :             continue;
    2907              :         }
    2908            0 :         if (currGraphicsItem->zValue() >= maxZValue && currGraphicsItem->zValue() < _globalZValue) {
    2909            0 :             hoveredGraphicsItem = currGraphicsItem;
    2910            0 :             maxZValue = hoveredGraphicsItem->zValue();
    2911            0 :         } else if (currGraphicsItem->zValue() > _globalZValue && std::get<1>(_oldHoverInfo) >= maxZValue) {
    2912            0 :             hoveredGraphicsItem = currGraphicsItem;
    2913            0 :             maxZValue = std::get<1>(_oldHoverInfo);
    2914              :         }
    2915              :     }
    2916              : 
    2917            0 :     if (!hoveredGraphicsItem) {
    2918            0 :         if (std::get<0>(_oldHoverInfo)) {
    2919            0 :             std::get<0>(_oldHoverInfo)->setZValue(std::get<1>(_oldHoverInfo));
    2920            0 :             static_cast<QGraphicsItem*>(std::get<0>(_oldHoverInfo)->data(5).value<void*>())->setZValue(std::get<1>(_oldHoverInfo));
    2921            0 :             QGraphicsRectItem* graphicsRectItem1 = qgraphicsitem_cast<QGraphicsRectItem*>(std::get<0>(_oldHoverInfo));
    2922              :             QGraphicsRectItem* graphicsRectItem2
    2923            0 :                 = qgraphicsitem_cast<QGraphicsRectItem*>(static_cast<QGraphicsItem*>(std::get<0>(_oldHoverInfo)->data(5).value<void*>()));
    2924            0 :             if (graphicsRectItem1) {
    2925            0 :                 graphicsRectItem1->setBrush(QBrush(std::get<2>(_oldHoverInfo)));
    2926              :             }
    2927            0 :             if (graphicsRectItem2) {
    2928            0 :                 graphicsRectItem2->setBrush(QBrush(std::get<2>(_oldHoverInfo)));
    2929              :             }
    2930            0 :             std::get<0>(_oldHoverInfo) = nullptr;
    2931            0 :             std::get<1>(_oldHoverInfo) = -1;
    2932              :         }
    2933            0 :         return;
    2934              :     }
    2935            0 :     QGraphicsItem* pairItem = static_cast<QGraphicsItem*>(hoveredGraphicsItem->data(5).value<void*>());
    2936            0 :     if (!pairItem) {
    2937            0 :         if (std::get<0>(_oldHoverInfo)) {
    2938            0 :             std::get<0>(_oldHoverInfo)->setZValue(std::get<1>(_oldHoverInfo));
    2939            0 :             static_cast<QGraphicsItem*>(std::get<0>(_oldHoverInfo)->data(5).value<void*>())->setZValue(std::get<1>(_oldHoverInfo));
    2940            0 :             QGraphicsRectItem* graphicsRectItem1 = qgraphicsitem_cast<QGraphicsRectItem*>(std::get<0>(_oldHoverInfo));
    2941              :             QGraphicsRectItem* graphicsRectItem2
    2942            0 :                 = qgraphicsitem_cast<QGraphicsRectItem*>(static_cast<QGraphicsItem*>(std::get<0>(_oldHoverInfo)->data(5).value<void*>()));
    2943            0 :             if (graphicsRectItem1) {
    2944            0 :                 graphicsRectItem1->setBrush(QBrush(std::get<2>(_oldHoverInfo)));
    2945              :             }
    2946            0 :             if (graphicsRectItem2) {
    2947            0 :                 graphicsRectItem2->setBrush(QBrush(std::get<2>(_oldHoverInfo)));
    2948              :             }
    2949            0 :             std::get<0>(_oldHoverInfo) = nullptr;
    2950            0 :             std::get<1>(_oldHoverInfo) = -1;
    2951              :         }
    2952            0 :         return;
    2953              :     }
    2954              : 
    2955            0 :     if (std::get<0>(_oldHoverInfo) == hoveredGraphicsItem) {
    2956            0 :         return;
    2957              :     }
    2958              : 
    2959            0 :     if (std::get<0>(_oldHoverInfo)) {
    2960            0 :         std::get<0>(_oldHoverInfo)->setZValue(std::get<1>(_oldHoverInfo));
    2961            0 :         static_cast<QGraphicsItem*>(std::get<0>(_oldHoverInfo)->data(5).value<void*>())->setZValue(std::get<1>(_oldHoverInfo));
    2962            0 :         QGraphicsRectItem* graphicsRectItem1 = qgraphicsitem_cast<QGraphicsRectItem*>(std::get<0>(_oldHoverInfo));
    2963              :         QGraphicsRectItem* graphicsRectItem2
    2964            0 :             = qgraphicsitem_cast<QGraphicsRectItem*>(static_cast<QGraphicsItem*>(std::get<0>(_oldHoverInfo)->data(5).value<void*>()));
    2965            0 :         if (graphicsRectItem1) {
    2966            0 :             graphicsRectItem1->setBrush(QBrush(std::get<2>(_oldHoverInfo)));
    2967              :         }
    2968            0 :         if (graphicsRectItem2) {
    2969            0 :             graphicsRectItem2->setBrush(QBrush(std::get<2>(_oldHoverInfo)));
    2970              :         }
    2971              : 
    2972            0 :         std::get<0>(_oldHoverInfo) = nullptr;
    2973            0 :         std::get<1>(_oldHoverInfo) = -1;
    2974              :     }
    2975              : 
    2976            0 :     std::get<1>(_oldHoverInfo) = hoveredGraphicsItem->zValue();
    2977            0 :     std::get<0>(_oldHoverInfo) = hoveredGraphicsItem;
    2978              : 
    2979              :     // Give items the top z value
    2980            0 :     hoveredGraphicsItem->setZValue(_globalZValue + 1);
    2981            0 :     pairItem->setZValue(_globalZValue + 1);
    2982              : 
    2983            0 :     QGraphicsRectItem* graphicsRectItem1 = qgraphicsitem_cast<QGraphicsRectItem*>(hoveredGraphicsItem);
    2984            0 :     QGraphicsRectItem* graphicsRectItem2 = qgraphicsitem_cast<QGraphicsRectItem*>(pairItem);
    2985            0 :     if (graphicsRectItem1) {
    2986            0 :         std::get<2>(_oldHoverInfo) = graphicsRectItem1->brush().color();
    2987            0 :         if (std::get<2>(_oldHoverInfo) != activeTheme().selectionColor) {
    2988            0 :             graphicsRectItem1->setBrush(QBrush(activeTheme().backgroundColor));
    2989              :         }
    2990              :     }
    2991            0 :     if (graphicsRectItem2) {
    2992            0 :         std::get<2>(_oldHoverInfo) = graphicsRectItem2->brush().color();
    2993            0 :         if (std::get<2>(_oldHoverInfo) != activeTheme().selectionColor) {
    2994            0 :             graphicsRectItem2->setBrush(QBrush(activeTheme().backgroundColor));
    2995              :         }
    2996              :     }
    2997            0 : }
    2998              : 
    2999              : //---------------------------------------------------------
    3000              : //   Timeline::swapMeta
    3001              : //---------------------------------------------------------
    3002              : 
    3003            0 : void Timeline::swapMeta(unsigned row, bool switchUp)
    3004              : {
    3005              :     // Attempt to switch row up or down, skipping non visible rows
    3006            0 :     if (switchUp && row != 0) {
    3007              :         // traverse backwards until visible one is found
    3008            0 :         auto swap = _metas.begin() + correctMetaRow(row) - 1;
    3009            0 :         while (!std::get<2>(*swap)) {
    3010            0 :             swap--;
    3011              :         }
    3012            0 :         iter_swap(_metas.begin() + correctMetaRow(row), swap);
    3013            0 :     } else if (!switchUp && row != nmetas() - 2) {
    3014              :         // traverse forwards until visible one is found
    3015            0 :         auto swap = _metas.begin() + correctMetaRow(row) + 1;
    3016            0 :         while (!std::get<2>(*swap)) {
    3017            0 :             swap++;
    3018              :         }
    3019            0 :         iter_swap(_metas.begin() + correctMetaRow(row), swap);
    3020              :     }
    3021              : 
    3022            0 :     updateGrid();
    3023            0 : }
    3024              : 
    3025              : //---------------------------------------------------------
    3026              : //   Timeline::numToStaff
    3027              : //---------------------------------------------------------
    3028              : 
    3029            0 : Staff* Timeline::numToStaff(int staff)
    3030              : {
    3031            0 :     if (!score()) {
    3032            0 :         return nullptr;
    3033              :     }
    3034              : 
    3035            0 :     size_t staffIdx = static_cast<size_t>(staff);
    3036              : 
    3037            0 :     const std::vector<Staff*>& staves = score()->staves();
    3038            0 :     if (staffIdx < staves.size()) {
    3039            0 :         return staves.at(staffIdx);
    3040              :     } else {
    3041            0 :         return nullptr;
    3042              :     }
    3043              : }
    3044              : 
    3045              : //---------------------------------------------------------
    3046              : //   Timeline::toggleShow
    3047              : //---------------------------------------------------------
    3048              : 
    3049            0 : void Timeline::toggleShow(int staff)
    3050              : {
    3051            0 :     if (!score()) {
    3052            0 :         return;
    3053              :     }
    3054              : 
    3055            0 :     QList<Part*> parts = getParts();
    3056            0 :     if (staff < 0 || staff >= parts.size()) {
    3057            0 :         return;
    3058              :     }
    3059              : 
    3060            0 :     Part* part = parts.at(staff);
    3061              : 
    3062            0 :     bool newShow = !part->show();
    3063              :     TranslatableString actionName = newShow
    3064            0 :                                     ? TranslatableString("undoableAction", "Show instrument")
    3065            0 :                                     : TranslatableString("undoableAction", "Hide instrument");
    3066              : 
    3067            0 :     m_notation->undoStack()->prepareChanges(actionName);
    3068            0 :     part->undoChangeProperty(Pid::VISIBLE, newShow);
    3069            0 :     m_notation->undoStack()->commitChanges();
    3070            0 :     m_notation->notationChanged().send(muse::RectF());
    3071            0 : }
    3072              : 
    3073              : //---------------------------------------------------------
    3074              : //   Timeline::showContextMenu
    3075              : //---------------------------------------------------------
    3076              : 
    3077            0 : void Timeline::contextMenuEvent(QContextMenuEvent* event)
    3078              : {
    3079            0 :     QMenu* contextMenu = new QMenu(muse::qtrc("notation/timeline", "Context menu"), this);
    3080            0 :     if (_rowNames->cursorIsOn() == "instrument") {
    3081            0 :         QAction* edit_instruments = new QAction(muse::qtrc("notation/timeline", "Edit instruments"), this);
    3082            0 :         connect(edit_instruments, &QAction::triggered, this, &Timeline::requestInstrumentDialog);
    3083            0 :         contextMenu->addAction(edit_instruments);
    3084            0 :         contextMenu->exec(QCursor::pos());
    3085            0 :     } else if (_rowNames->cursorIsOn() == "meta" || cursorIsOn(event->pos()) == "meta") {
    3086            0 :         for (auto it = _metas.begin(); it != _metas.end(); ++it) {
    3087            0 :             std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> meta = *it;
    3088            0 :             QString row_name = std::get<0>(meta);
    3089            0 :             if (row_name != muse::qtrc("notation/timeline", "Measures")) {
    3090            0 :                 QAction* action = new QAction(row_name, this);
    3091            0 :                 action->setCheckable(true);
    3092            0 :                 action->setChecked(std::get<2>(meta));
    3093            0 :                 connect(action, &QAction::triggered, this, &Timeline::toggleMetaRow);
    3094            0 :                 contextMenu->addAction(action);
    3095              :             }
    3096            0 :         }
    3097            0 :         contextMenu->addSeparator();
    3098            0 :         QAction* hide_all = new QAction(muse::qtrc("notation/timeline", "Hide all"), this);
    3099            0 :         connect(hide_all, &QAction::triggered, this, &Timeline::toggleMetaRow);
    3100            0 :         contextMenu->addAction(hide_all);
    3101            0 :         QAction* show_all = new QAction(muse::qtrc("notation/timeline", "Show all"), this);
    3102            0 :         connect(show_all, &QAction::triggered, this, &Timeline::toggleMetaRow);
    3103            0 :         contextMenu->addAction(show_all);
    3104            0 :         contextMenu->exec(QCursor::pos());
    3105              :     }
    3106            0 : }
    3107              : 
    3108              : //---------------------------------------------------------
    3109              : //   Timeline::toggleMetaRow
    3110              : //---------------------------------------------------------
    3111              : 
    3112            0 : void Timeline::toggleMetaRow()
    3113              : {
    3114            0 :     QAction* action = qobject_cast<QAction*>(QObject::sender());
    3115            0 :     if (!action) {
    3116            0 :         return;
    3117              :     }
    3118              : 
    3119            0 :     QString targetText = action->text();
    3120              : 
    3121            0 :     if (targetText == muse::qtrc("notation/timeline", "Hide all")) {
    3122            0 :         for (auto it = _metas.begin(); it != _metas.end(); ++it) {
    3123            0 :             QString metaText = std::get<0>(*it);
    3124            0 :             if (metaText != muse::qtrc("notation/timeline", "Measures")) {
    3125            0 :                 std::get<2>(*it) = false;
    3126              :             }
    3127            0 :         }
    3128            0 :         updateGrid();
    3129            0 :         return;
    3130            0 :     } else if (targetText == muse::qtrc("notation/timeline", "Show all")) {
    3131            0 :         for (auto it = _metas.begin(); it != _metas.end(); ++it) {
    3132            0 :             std::get<2>(*it) = true;
    3133              :         }
    3134            0 :         updateGrid();
    3135            0 :         return;
    3136              :     }
    3137              : 
    3138            0 :     bool checked = action->isChecked();
    3139              :     // Find target text in metas and toggle visibility to the checked status of action
    3140            0 :     for (auto it = _metas.begin(); it != _metas.end(); ++it) {
    3141            0 :         QString metaText = std::get<0>(*it);
    3142            0 :         if (metaText == targetText) {
    3143            0 :             std::get<2>(*it) = checked;
    3144            0 :             updateGrid();
    3145            0 :             break;
    3146              :         }
    3147            0 :     }
    3148            0 : }
    3149              : 
    3150              : //---------------------------------------------------------
    3151              : //   Timeline::nmetas
    3152              : //---------------------------------------------------------
    3153              : 
    3154            0 : unsigned Timeline::nmetas() const
    3155              : {
    3156            0 :     unsigned total = 0;
    3157            0 :     if (_collapsedMeta) {
    3158            0 :         return 2;
    3159              :     }
    3160            0 :     for (auto it = _metas.begin(); it != _metas.end(); ++it) {
    3161            0 :         std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> meta = *it;
    3162            0 :         if (std::get<2>(meta)) {
    3163            0 :             total++;
    3164              :         }
    3165            0 :     }
    3166            0 :     return total;
    3167              : }
    3168              : 
    3169              : //---------------------------------------------------------
    3170              : //   Timeline::correctMetaRow
    3171              : //---------------------------------------------------------
    3172              : 
    3173            0 : unsigned Timeline::correctMetaRow(unsigned row)
    3174              : {
    3175            0 :     unsigned count = 0;
    3176            0 :     auto it = _metas.begin();
    3177            0 :     while (row >= count) {
    3178            0 :         if (!std::get<2>(*it)) {
    3179            0 :             row++;
    3180              :         }
    3181            0 :         count++;
    3182            0 :         ++it;
    3183              :     }
    3184            0 :     return row;
    3185              : }
    3186              : 
    3187              : //---------------------------------------------------------
    3188              : //   Timeline::correctMetaRow
    3189              : //---------------------------------------------------------
    3190              : 
    3191            0 : QString Timeline::cursorIsOn(const QPoint& cursorPos)
    3192              : {
    3193            0 :     QGraphicsItem* graphicsItem = scene()->itemAt(cursorPos, transform());
    3194            0 :     if (!graphicsItem) {
    3195            0 :         return "";
    3196              :     }
    3197              : 
    3198            0 :     auto it = _metaRows.begin();
    3199            0 :     for (; it != _metaRows.end(); ++it) {
    3200            0 :         if ((*it).first == graphicsItem) {
    3201            0 :             break;
    3202              :         }
    3203              :     }
    3204            0 :     if (it != _metaRows.end()) {
    3205            0 :         return "meta";
    3206              :     }
    3207            0 :     QList<QGraphicsItem*> graphicsItemList = scene()->items(cursorPos);
    3208            0 :     for (QGraphicsItem* currGraphicsItem : graphicsItemList) {
    3209            0 :         Measure* currMeasure = static_cast<Measure*>(currGraphicsItem->data(2).value<void*>());
    3210            0 :         int stave = currGraphicsItem->data(0).value<int>();
    3211            0 :         const Staff* st = numToStaff(stave);
    3212            0 :         if (currMeasure && !(st && st->show())) {
    3213            0 :             return "invalid";
    3214              :         }
    3215              :     }
    3216            0 :     return "instrument";
    3217            0 : }
    3218              : 
    3219              : //---------------------------------------------------------
    3220              : //   Timeline::activeTheme
    3221              : //---------------------------------------------------------
    3222              : 
    3223            0 : const TimelineTheme& Timeline::activeTheme() const
    3224              : {
    3225            0 :     if (uiConfiguration()->currentTheme().codeKey == muse::ui::DARK_THEME_CODE) {
    3226            0 :         return _darkTheme;
    3227              :     }
    3228              : 
    3229            0 :     return _lightTheme;
    3230              : }
    3231              : 
    3232              : //---------------------------------------------------------
    3233              : //   Timeline::updateTimelineTheme
    3234              : //---------------------------------------------------------
    3235              : 
    3236            0 : void Timeline::updateTimelineTheme()
    3237              : {
    3238            0 :     const QBrush backgroundBrush = QBrush(activeTheme().backgroundColor);
    3239            0 :     scene()->setBackgroundBrush(backgroundBrush);
    3240            0 :     _rowNames->scene()->setBackgroundBrush(backgroundBrush);
    3241            0 :     updateGrid();
    3242            0 : }
    3243              : 
    3244              : //---------------------------------------------------------
    3245              : //   Timeline::requestInstrumentDialog
    3246              : //---------------------------------------------------------
    3247              : 
    3248            0 : void Timeline::requestInstrumentDialog()
    3249              : {
    3250            0 :     commandDispatcher()->dispatch(INSTRUMENTS_SELECT_COMMAND);
    3251            0 : }
    3252              : 
    3253            0 : INotationInteractionPtr Timeline::interaction() const
    3254              : {
    3255            0 :     return m_notation ? m_notation->interaction() : nullptr;
    3256              : }
    3257              : 
    3258            0 : Score* Timeline::score() const
    3259              : {
    3260            0 :     return m_notation ? m_notation->elements()->msScore() : nullptr;
    3261              : }
    3262              : 
    3263            0 : TRowLabels* Timeline::labelsColumn() const
    3264              : {
    3265            0 :     return _rowNames;
    3266              : }
        

Generated by: LCOV version 2.0-1