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