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