2857 lines
117 KiB
C++
2857 lines
117 KiB
C++
//=============================================================================
|
|
// MuseScore
|
|
// Music Composition & Notation
|
|
//
|
|
// Copyright (C) 2002-2013 Werner Schweer
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2
|
|
// as published by the Free Software Foundation and appearing in
|
|
// the file LICENCE.GPL
|
|
//=============================================================================
|
|
|
|
#include "timeline.h"
|
|
#include "navigator.h"
|
|
#include "musescore.h"
|
|
#include "libmscore/score.h"
|
|
#include "libmscore/page.h"
|
|
#include "preferences.h"
|
|
#include "libmscore/mscore.h"
|
|
#include "libmscore/system.h"
|
|
#include "libmscore/measurebase.h"
|
|
#include "libmscore/measure.h"
|
|
#include "libmscore/chord.h"
|
|
#include "libmscore/staff.h"
|
|
#include "libmscore/rest.h"
|
|
#include "libmscore/part.h"
|
|
#include "libmscore/tempo.h"
|
|
#include "libmscore/keysig.h"
|
|
#include "libmscore/timesig.h"
|
|
#include "libmscore/key.h"
|
|
#include "libmscore/tempotext.h"
|
|
#include "libmscore/text.h"
|
|
#include "libmscore/rehearsalmark.h"
|
|
#include "libmscore/barline.h"
|
|
#include "libmscore/jump.h"
|
|
#include "libmscore/marker.h"
|
|
#include "texttools.h"
|
|
#include "mixer.h"
|
|
#include "tourhandler.h"
|
|
|
|
namespace Ms {
|
|
|
|
//---------------------------------------------------------
|
|
// showTimeline
|
|
//---------------------------------------------------------
|
|
|
|
void MuseScore::showTimeline(bool visible)
|
|
{
|
|
QSplitter* split = static_cast<QSplitter*>(_timeline->widget());
|
|
Timeline* time = static_cast<Timeline*>(split->widget(1));
|
|
|
|
QAction* act = getAction("toggle-timeline");
|
|
if (!time) {
|
|
time = new Timeline(_timeline);
|
|
time->setScore(0);
|
|
time->setScoreView(cv);
|
|
}
|
|
connect(_timeline, SIGNAL(visibilityChanged(bool)), act, SLOT(setChecked(bool)));
|
|
connect(_timeline, SIGNAL(closed(bool)), act, SLOT(setChecked(bool)));
|
|
reDisplayDockWidget(_timeline, visible);
|
|
|
|
getAction("toggle-timeline")->setChecked(visible);
|
|
if (visible)
|
|
TourHandler::startTour("timeline-tour");
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// TDockWidget
|
|
//---------------------------------------------------------
|
|
|
|
TDockWidget::TDockWidget(QWidget* w)
|
|
: QDockWidget(w)
|
|
{
|
|
setFocusPolicy(Qt::NoFocus);
|
|
_grid = new QSplitter();
|
|
setWidget(_grid);
|
|
_grid->setHandleWidth(0);
|
|
setAllowedAreas(Qt::DockWidgetAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea));
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
|
|
setWindowTitle(tr("Timeline"));
|
|
setObjectName("Timeline");
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// closeEvent
|
|
//---------------------------------------------------------
|
|
|
|
void TDockWidget::closeEvent(QCloseEvent* event)
|
|
{
|
|
emit closed(false);
|
|
QWidget::closeEvent(event);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// TRowLabels
|
|
//---------------------------------------------------------
|
|
|
|
TRowLabels::TRowLabels(TDockWidget* dock_widget, Timeline* time, QGraphicsView* w)
|
|
: QGraphicsView(w)
|
|
{
|
|
setFocusPolicy(Qt::NoFocus);
|
|
scrollArea = dock_widget;
|
|
parent = time;
|
|
setScene(new QGraphicsScene);
|
|
scene()->setBackgroundBrush(Qt::lightGray);
|
|
setSceneRect(0, 0, 50, time->height());
|
|
|
|
setMinimumWidth(0);
|
|
|
|
QSplitter* split = scrollArea->grid();
|
|
QList<int> sizes;
|
|
//TODO: Replace 70 with hard coded value
|
|
sizes << 70 << 10000;
|
|
split->setSizes(sizes);
|
|
|
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
setContentsMargins(0, 0, 0, 0);
|
|
setAlignment(Qt::Alignment((Qt::AlignLeft | Qt::AlignTop)));
|
|
|
|
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), time->verticalScrollBar(), SLOT(setValue(int)));
|
|
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(restrict_scroll(int)));
|
|
connect(this, SIGNAL(moved(QPointF)), time, SLOT(mouseOver(QPointF)));
|
|
|
|
static const char* ud_arrow[] = {
|
|
"10 18 2 1",
|
|
"# c #000000",
|
|
". c #d3d3d3",
|
|
"..........",
|
|
"..........",
|
|
"....##....",
|
|
"...####...",
|
|
"..##..##..",
|
|
"..#....#..",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..#....#..",
|
|
"..##..##..",
|
|
"...####...",
|
|
"....##....",
|
|
"..........",
|
|
".........."
|
|
};
|
|
|
|
static const char* u_arrow[] = {
|
|
"10 18 2 1",
|
|
"# c #000000",
|
|
". c #d3d3d3",
|
|
"..........",
|
|
"..........",
|
|
"....##....",
|
|
"...####...",
|
|
"..##..##..",
|
|
"..#....#..",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
".........."
|
|
};
|
|
|
|
static const char* d_arrow[] = {
|
|
"10 18 2 1",
|
|
"# c #000000",
|
|
". c #d3d3d3",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..#....#..",
|
|
"..##..##..",
|
|
"...####...",
|
|
"....##....",
|
|
"..........",
|
|
".........."
|
|
};
|
|
|
|
static const char* cu_arrow[] = {
|
|
"9 18 2 1",
|
|
"# c #000000",
|
|
". c #d3d3d3",
|
|
".........",
|
|
".........",
|
|
".........",
|
|
".........",
|
|
"....#....",
|
|
"...###...",
|
|
"..#.#.#..",
|
|
".#..#..#.",
|
|
"....#....",
|
|
"....#....",
|
|
"....#....",
|
|
"....#....",
|
|
".........",
|
|
".........",
|
|
".........",
|
|
".........",
|
|
".........",
|
|
"........."
|
|
};
|
|
|
|
static const char* cd_arrow[] = {
|
|
"9 18 2 1",
|
|
"# c #000000",
|
|
". c #d3d3d3",
|
|
".........",
|
|
".........",
|
|
".........",
|
|
".........",
|
|
".........",
|
|
"....#....",
|
|
"....#....",
|
|
"....#....",
|
|
"....#....",
|
|
"....#....",
|
|
".#..#..#.",
|
|
"..#.#.#..",
|
|
"...###...",
|
|
"....#....",
|
|
".........",
|
|
".........",
|
|
".........",
|
|
"........."
|
|
};
|
|
|
|
static const char* open_eye[] = {
|
|
"11 18 2 1",
|
|
"# c #000000",
|
|
". c #d3d3d3",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"...####....",
|
|
".##....##..",
|
|
".#......#..",
|
|
"#........#.",
|
|
"#...##...#.",
|
|
"#...##...#.",
|
|
"#........#.",
|
|
".#......#..",
|
|
".##....##..",
|
|
"...####....",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"..........."
|
|
};
|
|
|
|
static const char* closed_eye[] = {
|
|
"11 18 2 1",
|
|
"# c #000000",
|
|
". c #d3d3d3",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"..######...",
|
|
"##..##..##.",
|
|
"##..##..##.",
|
|
"..######...",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"...........",
|
|
"..........."
|
|
};
|
|
|
|
|
|
mouseover_map[MouseOverValue::COLLAPSE_DOWN_ARROW] = new QPixmap(cd_arrow);
|
|
mouseover_map[MouseOverValue::COLLAPSE_UP_ARROW] = new QPixmap(cu_arrow);
|
|
mouseover_map[MouseOverValue::MOVE_DOWN_ARROW] = new QPixmap(d_arrow);
|
|
mouseover_map[MouseOverValue::MOVE_UP_DOWN_ARROW] = new QPixmap(ud_arrow);
|
|
mouseover_map[MouseOverValue::MOVE_UP_ARROW] = new QPixmap(u_arrow);
|
|
mouseover_map[MouseOverValue::OPEN_EYE] = new QPixmap(open_eye);
|
|
mouseover_map[MouseOverValue::CLOSED_EYE] = new QPixmap(closed_eye);
|
|
|
|
std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned int> tmp(nullptr, MouseOverValue::NONE, -1);
|
|
old_item_info = tmp;
|
|
|
|
connect(this, SIGNAL(requestContextMenu(QContextMenuEvent*)), parent, SLOT(contextMenuEvent(QContextMenuEvent*)));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// restrict_scroll
|
|
//---------------------------------------------------------
|
|
|
|
void TRowLabels::restrict_scroll(int value)
|
|
{
|
|
if (value > parent->verticalScrollBar()->maximum())
|
|
verticalScrollBar()->setValue(parent->verticalScrollBar()->maximum());
|
|
for (std::vector<std::pair<QGraphicsItem*, int>>::iterator it = meta_labels.begin();
|
|
it != meta_labels.end(); ++it) {
|
|
std::pair<QGraphicsItem*, int> pair_graphic_int = *it;
|
|
|
|
QGraphicsItem* graphics_item = pair_graphic_int.first;
|
|
|
|
QGraphicsRectItem* graphics_rect_item = qgraphicsitem_cast<QGraphicsRectItem*>(graphics_item);
|
|
QGraphicsLineItem* graphics_line_item = qgraphicsitem_cast<QGraphicsLineItem*>(graphics_item);
|
|
QGraphicsPixmapItem* graphics_pixmap_item = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphics_item);
|
|
int y = pair_graphic_int.second * 20;
|
|
int scrollbar_value = verticalScrollBar()->value();
|
|
|
|
if (graphics_rect_item) {
|
|
QRectF rectf = graphics_rect_item->rect();
|
|
rectf.setY(qreal(scrollbar_value + y));
|
|
rectf.setHeight(20);
|
|
graphics_rect_item->setRect(rectf);
|
|
}
|
|
else if (graphics_line_item) {
|
|
QLineF linef = graphics_line_item->line();
|
|
linef.setLine(linef.x1(), y + scrollbar_value + 1, linef.x2(), y + scrollbar_value + 1);
|
|
graphics_line_item->setLine(linef);
|
|
}
|
|
else if (graphics_pixmap_item)
|
|
graphics_pixmap_item->setY(qreal(scrollbar_value + y + 1));
|
|
else
|
|
graphics_item->setY(qreal(scrollbar_value + y));
|
|
}
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateLabels
|
|
//---------------------------------------------------------
|
|
|
|
void TRowLabels::updateLabels(std::vector<std::pair<QString, bool>> labels, int height)
|
|
{
|
|
|
|
scene()->clear();
|
|
meta_labels.clear();
|
|
if (labels.empty())
|
|
return;
|
|
|
|
unsigned int num_metas = parent->nmetas();
|
|
int max_width = -1;
|
|
int measure_width = 0;
|
|
for (unsigned int row = 0; row < labels.size(); row++) {
|
|
//Draw instrument name rectangle
|
|
int ypos = (row < num_metas)? row * height + verticalScrollBar()->value() : row * height + 3;
|
|
QGraphicsRectItem* graphics_rect_item = new QGraphicsRectItem(0, ypos, width(), height);
|
|
QGraphicsTextItem* graphics_text_item = new QGraphicsTextItem(labels[row].first);
|
|
|
|
if (row == num_metas - 1)
|
|
measure_width = graphics_text_item->boundingRect().width();
|
|
max_width = max(max_width, int(graphics_text_item->boundingRect().width()));
|
|
|
|
QFontMetrics f(QApplication::font());
|
|
QString part_name = f.elidedText(labels[row].first, Qt::ElideRight, width());
|
|
graphics_text_item->setPlainText(part_name);
|
|
graphics_text_item->setX(0);
|
|
graphics_text_item->setY(ypos);
|
|
if (labels[row].second)
|
|
graphics_text_item->setDefaultTextColor(QColor(Qt::black));
|
|
else
|
|
graphics_text_item->setDefaultTextColor(QColor(150, 150, 150));
|
|
graphics_rect_item->setPen(QPen(QColor(150, 150, 150)));
|
|
graphics_rect_item->setBrush(QBrush(QColor(211, 211, 211)));
|
|
graphics_text_item->setZValue(-1);
|
|
graphics_rect_item->setZValue(-1);
|
|
|
|
graphics_rect_item->setData(0, QVariant::fromValue<bool>(false));
|
|
graphics_text_item->setData(0, QVariant::fromValue<bool>(false));
|
|
|
|
MouseOverValue mouse_over_arrow = MouseOverValue::NONE;
|
|
if (num_metas - 1 == row && (num_metas > 2 || parent->collapsed())) {
|
|
//Measures meta
|
|
if (parent->collapsed())
|
|
mouse_over_arrow = MouseOverValue::COLLAPSE_DOWN_ARROW;
|
|
else
|
|
mouse_over_arrow = MouseOverValue::COLLAPSE_UP_ARROW;
|
|
}
|
|
else if (row < num_metas - 1) {
|
|
if (row != 0 && row + 1 <= num_metas - 2)
|
|
mouse_over_arrow = MouseOverValue::MOVE_UP_DOWN_ARROW;
|
|
else if (row == 0 && row + 1 < num_metas - 1)
|
|
mouse_over_arrow = MouseOverValue::MOVE_DOWN_ARROW;
|
|
else if (row == num_metas - 2 && row != 0)
|
|
mouse_over_arrow = MouseOverValue::MOVE_UP_ARROW;
|
|
}
|
|
else if (num_metas <= row) {
|
|
if (parent->numToStaff(row - num_metas) &&
|
|
parent->numToStaff(row - num_metas)->show())
|
|
mouse_over_arrow = MouseOverValue::OPEN_EYE;
|
|
else
|
|
mouse_over_arrow = MouseOverValue::CLOSED_EYE;
|
|
}
|
|
graphics_text_item->setData(1, QVariant::fromValue<MouseOverValue>(mouse_over_arrow));
|
|
graphics_rect_item->setData(1, QVariant::fromValue<MouseOverValue>(mouse_over_arrow));
|
|
|
|
graphics_text_item->setData(2, QVariant::fromValue<unsigned int>(row));
|
|
graphics_rect_item->setData(2, QVariant::fromValue<unsigned int>(row));
|
|
|
|
scene()->addItem(graphics_rect_item);
|
|
scene()->addItem(graphics_text_item);
|
|
if (row < num_metas) {
|
|
std::pair<QGraphicsItem*, int> p1(graphics_rect_item, row);
|
|
std::pair<QGraphicsItem*, int> p2(graphics_text_item, row);
|
|
meta_labels.push_back(p1);
|
|
meta_labels.push_back(p2);
|
|
graphics_rect_item->setZValue(1);
|
|
graphics_text_item->setZValue(2);
|
|
}
|
|
}
|
|
QGraphicsLineItem* graphics_line_item = new QGraphicsLineItem(0,
|
|
height * num_metas + verticalScrollBar()->value() + 1,
|
|
max(max_width + 20, 70),
|
|
height * num_metas + verticalScrollBar()->value() + 1);
|
|
graphics_line_item->setPen(QPen(QColor(150, 150, 150), 4));
|
|
graphics_line_item->setZValue(0);
|
|
graphics_line_item->setData(0, QVariant::fromValue<bool>(false));
|
|
scene()->addItem(graphics_line_item);
|
|
|
|
std::pair<QGraphicsItem*, int> graphics_line_item_pair(graphics_line_item, num_metas);
|
|
meta_labels.push_back(graphics_line_item_pair);
|
|
|
|
setSceneRect(0, 0, max_width, parent->getHeight() + parent->horizontalScrollBar()->height());
|
|
|
|
std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned int> tmp(nullptr, MouseOverValue::NONE, -1);
|
|
old_item_info = tmp;
|
|
|
|
setMinimumWidth(measure_width + 9);
|
|
setMaximumWidth(max(max_width + 20, 70));
|
|
mouseOver(mapToScene(mapFromGlobal(QCursor::pos())));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// resizeEvent
|
|
//---------------------------------------------------------
|
|
|
|
void TRowLabels::resizeEvent(QResizeEvent*)
|
|
{
|
|
std::vector<std::pair<QString, bool>> labels = parent->getLabels();
|
|
updateLabels(labels, 20);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mousePressEvent
|
|
//---------------------------------------------------------
|
|
|
|
void TRowLabels::mousePressEvent(QMouseEvent* event)
|
|
{
|
|
if (event->button() == Qt::RightButton)
|
|
return;
|
|
|
|
QPointF scene_pt = mapToScene(event->pos());
|
|
unsigned int num_metas = parent->nmetas();
|
|
|
|
//Check if mouse position in scene is on the last meta
|
|
QPointF measure_meta_tl = QPointF(0, (num_metas - 1) * 20 + verticalScrollBar()->value());
|
|
QPointF measure_meta_br = QPointF(width(), num_metas * 20 + verticalScrollBar()->value());
|
|
if (QRectF(measure_meta_tl, measure_meta_br).contains(scene_pt) && (num_metas > 2 || parent->collapsed())) {
|
|
if (std::get<0>(old_item_info)) {
|
|
std::pair<QGraphicsItem*, int> p(std::get<0>(old_item_info), std::get<2>(old_item_info));
|
|
std::vector<std::pair<QGraphicsItem*, int>>::iterator it = std::find(meta_labels.begin(), meta_labels.end(), p);
|
|
if (it != meta_labels.end())
|
|
meta_labels.erase(it);
|
|
scene()->removeItem(std::get<0>(old_item_info));
|
|
}
|
|
std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned int> tmp(nullptr, MouseOverValue::NONE, -1);
|
|
old_item_info = tmp;
|
|
mouseOver(mapToScene(mapFromGlobal(QCursor::pos())));
|
|
|
|
parent->setCollapsed(!parent->collapsed());
|
|
parent->updateGrid();
|
|
}
|
|
else {
|
|
//Check if pixmap was selected
|
|
if (QGraphicsItem* graphics_item = scene()->itemAt(scene_pt, transform())) {
|
|
QGraphicsPixmapItem* graphics_pixmap_item = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphics_item);
|
|
if (graphics_pixmap_item) {
|
|
unsigned int row = graphics_pixmap_item->data(2).value<unsigned int>();
|
|
if (row == num_metas - 1)
|
|
return;
|
|
else if (row < num_metas - 1) {
|
|
//Find mid point between up and down arrow
|
|
qreal mid_point = graphics_pixmap_item->boundingRect().height() / 2 + graphics_pixmap_item->scenePos().y();
|
|
if (scene_pt.y() > mid_point)
|
|
emit swapMeta(row, false);
|
|
else
|
|
emit swapMeta(row, true);
|
|
}
|
|
else if (row >= num_metas)
|
|
parent->toggleShow(row - num_metas);
|
|
}
|
|
else {
|
|
dragging = true;
|
|
this->setCursor(Qt::SizeAllCursor);
|
|
old_loc = QPoint(int(scene_pt.x()), int(scene_pt.y()));
|
|
}
|
|
|
|
}
|
|
else {
|
|
dragging = true;
|
|
this->setCursor(Qt::SizeAllCursor);
|
|
old_loc = QPoint(int(scene_pt.x()), int(scene_pt.y()));
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mouseMoveEvent
|
|
//---------------------------------------------------------
|
|
|
|
void TRowLabels::mouseMoveEvent(QMouseEvent* event)
|
|
{
|
|
QPointF scene_pt = mapToScene(event->pos());
|
|
if (dragging) {
|
|
this->setCursor(Qt::SizeAllCursor);
|
|
int y_offset = int(old_loc.y()) - int(scene_pt.y());
|
|
verticalScrollBar()->setValue(verticalScrollBar()->value() + y_offset);
|
|
}
|
|
else
|
|
mouseOver(scene_pt);
|
|
emit moved(QPointF(-1, -1));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mouseReleaseEvent
|
|
//---------------------------------------------------------
|
|
|
|
void TRowLabels::mouseReleaseEvent(QMouseEvent* event)
|
|
{
|
|
if (QGraphicsItem* graphics_item = scene()->itemAt(mapToScene(event->pos()), transform())) {
|
|
QGraphicsPixmapItem* graphics_pixmap_item = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphics_item);
|
|
if (graphics_pixmap_item)
|
|
this->setCursor(Qt::PointingHandCursor);
|
|
else
|
|
this->setCursor(Qt::ArrowCursor);
|
|
}
|
|
else
|
|
this->setCursor(Qt::ArrowCursor);
|
|
dragging = false;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// leaveEvent
|
|
//---------------------------------------------------------
|
|
|
|
void TRowLabels::leaveEvent(QEvent*)
|
|
{
|
|
if (!rect().contains(mapFromGlobal(QCursor::pos())))
|
|
mouseOver(mapToScene(mapFromGlobal(QCursor::pos())));
|
|
}
|
|
//---------------------------------------------------------
|
|
// contextMenuEvent
|
|
//---------------------------------------------------------
|
|
|
|
void TRowLabels::contextMenuEvent(QContextMenuEvent* event)
|
|
{
|
|
emit requestContextMenu(event);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mouseOver
|
|
//---------------------------------------------------------
|
|
|
|
void TRowLabels::mouseOver(QPointF scene_pt)
|
|
{
|
|
//Handle drawing of arrows
|
|
if (QGraphicsItem* graphics_item = scene()->itemAt(scene_pt, transform())) {
|
|
QGraphicsPixmapItem* graphics_pixmap_item = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphics_item);
|
|
if (graphics_pixmap_item) {
|
|
this->setCursor(Qt::PointingHandCursor);
|
|
return;
|
|
}
|
|
|
|
MouseOverValue mouse_over_arrow = graphics_item->data(1).value<MouseOverValue>();
|
|
if (mouse_over_arrow != MouseOverValue::NONE) {
|
|
QPixmap* pixmap_arrow = mouseover_map[mouse_over_arrow];
|
|
QGraphicsPixmapItem* graphics_pixmap_item_arrow = new QGraphicsPixmapItem(*pixmap_arrow);
|
|
unsigned int row = graphics_item->data(2).value<unsigned int>();
|
|
|
|
QString tooltip;
|
|
switch (mouse_over_arrow) {
|
|
case MouseOverValue::COLLAPSE_DOWN_ARROW:
|
|
tooltip = tr("Expand meta rows");
|
|
break;
|
|
case MouseOverValue::COLLAPSE_UP_ARROW:
|
|
tooltip = tr("Collapse meta rows");
|
|
break;
|
|
case MouseOverValue::MOVE_DOWN_ARROW:
|
|
tooltip = tr("Move meta row down one");
|
|
break;
|
|
case MouseOverValue::MOVE_UP_ARROW:
|
|
tooltip = tr("Move meta row up one");
|
|
break;
|
|
case MouseOverValue::MOVE_UP_DOWN_ARROW:
|
|
tooltip = tr("Move meta row up/down one");
|
|
break;
|
|
case MouseOverValue::OPEN_EYE:
|
|
tooltip = tr("Hide instrument in score");
|
|
break;
|
|
case MouseOverValue::CLOSED_EYE:
|
|
tooltip = tr("Show instrument in score");
|
|
break;
|
|
default:
|
|
tooltip = "";
|
|
break;
|
|
}
|
|
|
|
graphics_pixmap_item_arrow->setToolTip(tooltip);
|
|
if (mouse_over_arrow == MouseOverValue::OPEN_EYE || mouse_over_arrow == MouseOverValue::CLOSED_EYE)
|
|
graphics_pixmap_item_arrow->setData(0, QVariant::fromValue<bool>(false));
|
|
else
|
|
graphics_pixmap_item_arrow->setData(0, QVariant::fromValue<bool>(true));
|
|
graphics_pixmap_item_arrow->setData(1, QVariant::fromValue<MouseOverValue>(mouse_over_arrow));
|
|
graphics_pixmap_item_arrow->setData(2, QVariant::fromValue<unsigned int>(row));
|
|
|
|
//Draw arrow at correct location
|
|
if (row < parent->nmetas()) {
|
|
graphics_pixmap_item_arrow->setPos(width() - 12, verticalScrollBar()->value() + 1 + row * 20);
|
|
graphics_pixmap_item_arrow->setZValue(3);
|
|
}
|
|
else {
|
|
graphics_pixmap_item_arrow->setPos(width() - 13, row * 20 + 5);
|
|
graphics_pixmap_item_arrow->setZValue(-1);
|
|
}
|
|
|
|
|
|
if (std::get<2>(old_item_info) == row && std::get<1>(old_item_info) == mouse_over_arrow) {
|
|
//DO NOTHING
|
|
}
|
|
else {
|
|
if (std::get<0>(old_item_info)) {
|
|
std::pair<QGraphicsItem*, int> p(std::get<0>(old_item_info), std::get<2>(old_item_info));
|
|
std::vector<std::pair<QGraphicsItem*, int>>::iterator it = std::find(meta_labels.begin(), meta_labels.end(), p);
|
|
if (it != meta_labels.end())
|
|
meta_labels.erase(it);
|
|
scene()->removeItem(std::get<0>(old_item_info));
|
|
}
|
|
std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned int> tmp(graphics_pixmap_item_arrow, mouse_over_arrow, row);
|
|
old_item_info = tmp;
|
|
if (mouse_over_arrow != MouseOverValue::OPEN_EYE && mouse_over_arrow != MouseOverValue::CLOSED_EYE) {
|
|
std::pair<QGraphicsItem*, int> p(graphics_pixmap_item_arrow, row);
|
|
meta_labels.push_back(p);
|
|
}
|
|
scene()->addItem(graphics_pixmap_item_arrow);
|
|
}
|
|
|
|
}
|
|
else {
|
|
if (std::get<0>(old_item_info))
|
|
scene()->removeItem(std::get<0>(old_item_info));
|
|
std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned int> tmp(nullptr, MouseOverValue::NONE, -1);
|
|
old_item_info = tmp;
|
|
}
|
|
}
|
|
else {
|
|
if (std::get<0>(old_item_info)) {
|
|
std::pair<QGraphicsItem*, int> p(std::get<0>(old_item_info), std::get<2>(old_item_info));
|
|
std::vector<std::pair<QGraphicsItem*, int>>::iterator it = std::find(meta_labels.begin(), meta_labels.end(), p);
|
|
if (it != meta_labels.end())
|
|
meta_labels.erase(it);
|
|
scene()->removeItem(std::get<0>(old_item_info));
|
|
}
|
|
std::tuple<QGraphicsPixmapItem*, MouseOverValue, unsigned int> tmp(nullptr, MouseOverValue::NONE, -1);
|
|
old_item_info = tmp;
|
|
}
|
|
if (QGraphicsItem* graphics_item = scene()->itemAt(scene_pt, transform())) {
|
|
QGraphicsPixmapItem* graphics_pixmap_item = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphics_item);
|
|
if (graphics_pixmap_item)
|
|
this->setCursor(Qt::PointingHandCursor);
|
|
else
|
|
this->setCursor(Qt::ArrowCursor);
|
|
}
|
|
else
|
|
this->setCursor(Qt::ArrowCursor);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// cursorIsOn
|
|
//---------------------------------------------------------
|
|
|
|
QString TRowLabels::cursorIsOn()
|
|
{
|
|
QPointF scene_pos = mapToScene(mapFromGlobal(QCursor::pos()));
|
|
QGraphicsItem* graphics_item = scene()->itemAt(scene_pos, transform());
|
|
if (graphics_item) {
|
|
auto it = meta_labels.begin();
|
|
for (;it != meta_labels.end(); ++it) {
|
|
if ((*it).first == graphics_item)
|
|
break;
|
|
}
|
|
if (it != meta_labels.end())
|
|
return "meta";
|
|
else
|
|
return "instrument";
|
|
}
|
|
else
|
|
return "";
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// Timeline
|
|
//---------------------------------------------------------
|
|
|
|
Timeline::Timeline(TDockWidget* dock_widget, QWidget* parent)
|
|
: QGraphicsView(parent)
|
|
{
|
|
setFocusPolicy(Qt::NoFocus);
|
|
setAlignment(Qt::Alignment((Qt::AlignLeft | Qt::AlignTop)));
|
|
setAttribute(Qt::WA_NoBackground);
|
|
|
|
scrollArea = dock_widget;
|
|
QSplitter* split = static_cast<QSplitter*>(scrollArea->widget());
|
|
|
|
row_names = new TRowLabels(dock_widget, this);
|
|
split->addWidget(row_names);
|
|
split->addWidget(this);
|
|
split->setChildrenCollapsible(false);
|
|
split->setStretchFactor(0, 0);
|
|
split->setStretchFactor(1, 0);
|
|
|
|
setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
|
|
|
setScene(new QGraphicsScene);
|
|
setSceneRect(0, 0, 100, 100);
|
|
scene()->setBackgroundBrush(Qt::lightGray);
|
|
|
|
connect(verticalScrollBar(),SIGNAL(valueChanged(int)),row_names->verticalScrollBar(),SLOT(setValue(int)));
|
|
connect(verticalScrollBar(),SIGNAL(valueChanged(int)),this,SLOT(handle_scroll(int)));
|
|
connect(row_names, SIGNAL(swapMeta(uint,bool)), this, SLOT(swapMeta(uint,bool)));
|
|
connect(this, SIGNAL(moved(QPointF)), row_names, SLOT(mouseOver(QPointF)));
|
|
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> t1(tr("Tempo"), &Ms::Timeline::tempo_meta, true);
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> t2(tr("Time Signature"), &Ms::Timeline::time_meta, true);
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> t3(tr("Rehearsal Mark"), &Ms::Timeline::rehearsal_meta, true);
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> t4(tr("Key Signature"), &Ms::Timeline::key_meta, true);
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> t5(tr("Barlines"), &Ms::Timeline::barline_meta, true);
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> t6(tr("Jumps and Markers"), &Ms::Timeline::jump_marker_meta, true);
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> t7(tr("Measures"), &Ms::Timeline::measure_meta, true);
|
|
metas.push_back(t1);
|
|
metas.push_back(t2);
|
|
metas.push_back(t3);
|
|
metas.push_back(t4);
|
|
metas.push_back(t5);
|
|
metas.push_back(t6);
|
|
metas.push_back(t7);
|
|
|
|
std::tuple<QGraphicsItem*, int, QColor> ohi(nullptr, -1, QColor());
|
|
old_hover_info = ohi;
|
|
std::tuple<int, qreal, Element*, Element*, bool> ri(0, 0, nullptr, nullptr, false);
|
|
repeat_info = ri;
|
|
|
|
static const char* left_repeat[] = {
|
|
"7 14 2 1",
|
|
"# c #000000",
|
|
". c None",
|
|
"##.#...",
|
|
"##.#...",
|
|
"##.#...",
|
|
"##.#...",
|
|
"##.#.##",
|
|
"##.#.##",
|
|
"##.#...",
|
|
"##.#...",
|
|
"##.#.##",
|
|
"##.#.##",
|
|
"##.#...",
|
|
"##.#...",
|
|
"##.#...",
|
|
"##.#..."
|
|
};
|
|
|
|
static const char* right_repeat[] = {
|
|
"7 14 2 1",
|
|
"# c #000000",
|
|
". c None",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"##.#.##",
|
|
"##.#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"##.#.##",
|
|
"##.#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##"
|
|
};
|
|
|
|
static const char* final_barline[] = {
|
|
"7 14 2 1",
|
|
"# c #000000",
|
|
". c None",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##",
|
|
"...#.##"
|
|
};
|
|
|
|
static const char* double_barline[] = {
|
|
"7 14 2 1",
|
|
"# c #000000",
|
|
". c None",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#..",
|
|
"..#.#.."
|
|
};
|
|
|
|
QPixmap* left_repeat_pixmap = new QPixmap(left_repeat);
|
|
QPixmap* right_repeat_pixmap = new QPixmap(right_repeat);
|
|
QPixmap* final_barline_pixmap = new QPixmap(final_barline);
|
|
QPixmap* double_barline_pixmap = new QPixmap(double_barline);
|
|
|
|
barlines["Start repeat"] = left_repeat_pixmap;
|
|
barlines["End repeat"] = right_repeat_pixmap;
|
|
barlines["Final barline"] = final_barline_pixmap;
|
|
barlines["Double barline"] = double_barline_pixmap;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// drawGrid
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::drawGrid(int global_rows, int global_cols)
|
|
{
|
|
scene()->clear();
|
|
meta_rows.clear();
|
|
|
|
if (global_rows == 0 || global_cols == 0) return;
|
|
int stagger = 0;
|
|
unsigned int num_metas = nmetas();
|
|
setMinimumHeight(grid_height * (num_metas + 1) + 5 + horizontalScrollBar()->height());
|
|
setMinimumWidth(grid_width * 3);
|
|
global_z_value = 1;
|
|
|
|
//Draw grid
|
|
Measure* curr_measure = _score->firstMeasure();
|
|
QList<Part*> part_list = getParts();
|
|
for (int col = 0; col < global_cols; col++) {
|
|
for (int row = 0; row < global_rows; row++) {
|
|
QGraphicsRectItem* graphics_rect_item = new QGraphicsRectItem(col * grid_width,
|
|
grid_height * (row + num_metas) + 3,
|
|
grid_width,
|
|
grid_height);
|
|
|
|
setMetaData(graphics_rect_item, row, ElementType::INVALID, curr_measure, false, 0);
|
|
|
|
QString translate_measure = tr("Measure");
|
|
QChar initial_letter = translate_measure[0];
|
|
QTextDocument doc;
|
|
QString part_name = "";
|
|
if (part_list.size() > row) {
|
|
doc.setHtml(part_list.at(row)->longName());
|
|
part_name = doc.toPlainText();
|
|
}
|
|
if (part_name.isEmpty() && part_list.size() > row)
|
|
part_name = part_list.at(row)->instrumentName();
|
|
|
|
graphics_rect_item->setToolTip(initial_letter + QString(" ") + QString::number(curr_measure->no() + 1) + QString(", ") + part_name);
|
|
graphics_rect_item->setPen(QPen(QColor(Qt::lightGray)));
|
|
graphics_rect_item->setBrush(QBrush(colorBox(graphics_rect_item)));
|
|
graphics_rect_item->setZValue(-3);
|
|
scene()->addItem(graphics_rect_item);
|
|
}
|
|
|
|
curr_measure = curr_measure->nextMeasure();
|
|
}
|
|
setSceneRect(0, 0, getWidth(), getHeight());
|
|
|
|
//Draw meta rows and separator
|
|
QGraphicsLineItem* graphics_line_item_separator = new QGraphicsLineItem(0,
|
|
grid_height * num_metas + verticalScrollBar()->value() + 1,
|
|
getWidth() - 1,
|
|
grid_height * num_metas + verticalScrollBar()->value() + 1);
|
|
graphics_line_item_separator->setPen(QPen(QColor(150, 150, 150), 4));
|
|
graphics_line_item_separator->setZValue(-2);
|
|
scene()->addItem(graphics_line_item_separator);
|
|
std::pair<QGraphicsItem*, int> pair_graphics_int_separator(graphics_line_item_separator, num_metas);
|
|
meta_rows.push_back(pair_graphics_int_separator);
|
|
|
|
for (unsigned int row = 0; row < num_metas; row++) {
|
|
QGraphicsRectItem* meta_row = new QGraphicsRectItem(0,
|
|
grid_height * row + verticalScrollBar()->value(),
|
|
getWidth(),
|
|
grid_height);
|
|
meta_row->setBrush(QBrush(QColor(211,211,211)));
|
|
meta_row->setPen(QPen(QColor(150, 150, 150)));
|
|
meta_row->setData(0, QVariant::fromValue<int>(-1));
|
|
|
|
scene()->addItem(meta_row);
|
|
|
|
std::pair<QGraphicsItem*, int> pair_graphics_int_meta(meta_row, row);
|
|
meta_rows.push_back(pair_graphics_int_meta);
|
|
}
|
|
|
|
int x_pos = 0;
|
|
|
|
//Create stagger array if collapsed_meta is false
|
|
#if (!defined (_MSCVER) && !defined (_MSC_VER))
|
|
int stagger_arr[num_metas];
|
|
for (unsigned int row = 0; row < num_metas; row++)
|
|
stagger_arr[row] = 0;
|
|
#else
|
|
// MSVC does not support VLA. Replace with std::vector. If profiling determines that the
|
|
// heap allocation is slow, an optimization might be used.
|
|
std::vector<int> stagger_arr(num_metas, 0); // Default initialized, loop not required
|
|
#endif
|
|
|
|
bool no_key = true;
|
|
std::get<4>(repeat_info) = false;
|
|
|
|
for (Measure* cm = _score->firstMeasure(); cm; cm = cm->nextMeasure()) {
|
|
for (Segment* curr_seg = cm->first(); curr_seg; curr_seg = curr_seg->next()) {
|
|
//Toggle no_key if initial key signature is found
|
|
if (curr_seg->isKeySigType() && cm == _score->firstMeasure()) {
|
|
if (no_key && curr_seg->tick().isZero())
|
|
no_key = false;
|
|
}
|
|
|
|
//If no initial key signature is found, add key signature
|
|
if (cm == _score->firstMeasure() && no_key &&
|
|
(curr_seg->isTimeSigType() || curr_seg->isChordRestType())) {
|
|
|
|
if (getMetaRow(tr("Key Signature")) != num_metas) {
|
|
if (collapsed_meta)
|
|
key_meta(0, &stagger, x_pos);
|
|
else
|
|
key_meta(0, &stagger_arr[getMetaRow(tr("Key Signature"))], x_pos);
|
|
}
|
|
no_key = false;
|
|
}
|
|
int row = 0;
|
|
for (auto it = metas.begin(); it != metas.end(); ++it) {
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> meta = *it;
|
|
if (!std::get<2>(meta))
|
|
continue;
|
|
void (Timeline::*func)(Segment*, int*, int) = std::get<1>(meta);
|
|
if (collapsed_meta)
|
|
(this->*func)(curr_seg, &stagger, x_pos);
|
|
else
|
|
(this->*func)(curr_seg, &stagger_arr[row], x_pos);
|
|
row++;
|
|
}
|
|
}
|
|
//Handle all jumps here
|
|
if (getMetaRow(tr("Jumps and Markers")) != num_metas) {
|
|
ElementList measure_elements_list = cm->el();
|
|
for (Element* element : measure_elements_list) {
|
|
std::get<3>(repeat_info) = element;
|
|
if (element->isMarker())
|
|
jump_marker_meta(0, &stagger, x_pos);
|
|
}
|
|
for (Element* element : measure_elements_list) {
|
|
if (element->isJump()) {
|
|
std::get<2>(repeat_info) = element;
|
|
if (collapsed_meta)
|
|
jump_marker_meta(0, &stagger, x_pos);
|
|
else
|
|
jump_marker_meta(0, &std::get<0>(repeat_info), x_pos);
|
|
}
|
|
}
|
|
}
|
|
stagger = 0;
|
|
std::get<0>(repeat_info) = 0;
|
|
|
|
for (unsigned int row = 0; row < num_metas; row++) {
|
|
stagger_arr[row] = 0;
|
|
}
|
|
x_pos += grid_width;
|
|
std::get<4>(repeat_info) = false;
|
|
}
|
|
drawSelection();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// tempo_meta
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::tempo_meta(Segment* seg, int* stagger, int pos)
|
|
{
|
|
//Find position of tempo_meta in metas
|
|
int row = getMetaRow(tr("Tempo"));
|
|
|
|
//Add all tempo texts in this segment
|
|
const std::vector<Element*> annotations = seg->annotations();
|
|
for (Element* element : annotations) {
|
|
if (element->isTempoText()) {
|
|
TempoText* text = toTempoText(element);
|
|
qreal x = pos + (*stagger) * spacing;
|
|
if (addMetaValue(x, pos, text->plainText(), row, ElementType::TEMPO_TEXT, element, 0, seg->measure())) {
|
|
(*stagger)++;
|
|
global_z_value++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// time_meta
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::time_meta(Segment* seg, int* stagger, int pos)
|
|
{
|
|
if (!seg->isTimeSigType())
|
|
return;
|
|
|
|
int x = pos + (*stagger) * spacing;
|
|
|
|
//Find position of time_meta in metas
|
|
int row = getMetaRow(tr("Time Signature"));
|
|
|
|
TimeSig* original_time_sig = toTimeSig(seg->element(0));
|
|
if (!original_time_sig)
|
|
return;
|
|
|
|
//Check if same across all staves
|
|
const int nrows = _score->staves().size();
|
|
bool same = true;
|
|
for (int track = 0; track < nrows; track++) {
|
|
const TimeSig* curr_time_sig = toTimeSig(seg->element(track * VOICES));
|
|
if (!curr_time_sig) {
|
|
same = false;
|
|
break;
|
|
}
|
|
if (*curr_time_sig == *original_time_sig) {
|
|
continue;
|
|
}
|
|
same = false;
|
|
break;
|
|
}
|
|
if (!same)
|
|
return;
|
|
QString text = QString::number(original_time_sig->numerator()) + QString("/") + QString::number(original_time_sig->denominator());
|
|
|
|
if (addMetaValue(x, pos, text, row, ElementType::TIMESIG, 0, seg, seg->measure())) {
|
|
(*stagger)++;
|
|
global_z_value++;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// rehearsal_meta
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::rehearsal_meta(Segment* seg, int* stagger, int pos)
|
|
{
|
|
int row = getMetaRow(tr("Rehearsal Mark"));
|
|
|
|
for (Element* element : seg->annotations()) {
|
|
int x = pos + (*stagger) * spacing;
|
|
if (element->isRehearsalMark()) {
|
|
|
|
RehearsalMark* rehersal_mark = toRehearsalMark(element);
|
|
if (!rehersal_mark)
|
|
continue;
|
|
|
|
if (addMetaValue(x, pos, rehersal_mark->plainText(), row, ElementType::REHEARSAL_MARK, element, 0, seg->measure())) {
|
|
(*stagger)++;
|
|
global_z_value++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// key_meta
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::key_meta(Segment* seg, int* stagger, int pos)
|
|
{
|
|
//If seg is null, handle initial key signature
|
|
if (seg && !seg->isKeySigType())
|
|
return;
|
|
|
|
int row = getMetaRow(tr("Key Signature"));
|
|
std::map<Key, int> key_frequencies;
|
|
QList<Staff*> staves = _score->staves();
|
|
|
|
int track = 0;
|
|
for (Staff* stave : staves) {
|
|
if (!stave->show()) {
|
|
track += VOICES;
|
|
continue;
|
|
}
|
|
|
|
//Ignore unpitched staves
|
|
if ((seg && !stave->isPitchedStaff(seg->tick())) || (!seg && !stave->isPitchedStaff(Fraction(0,1)))) {
|
|
track += VOICES;
|
|
continue;
|
|
}
|
|
|
|
//Add corrected key signature to map
|
|
//Atonal -> Key::INVALID
|
|
//Custom -> Key::NUM_OF
|
|
const KeySig* curr_key_sig = nullptr;
|
|
if (seg)
|
|
curr_key_sig = toKeySig(seg->element(track));
|
|
|
|
Key global_key;
|
|
if (seg)
|
|
global_key = stave->key(seg->tick());
|
|
else
|
|
global_key = stave->key(Fraction(0,1));
|
|
if (curr_key_sig) {
|
|
if (curr_key_sig->generated())
|
|
return;
|
|
global_key = curr_key_sig->key();
|
|
}
|
|
|
|
if (curr_key_sig && curr_key_sig->isAtonal())
|
|
global_key = Key::INVALID;
|
|
else if (curr_key_sig && curr_key_sig->isCustom())
|
|
global_key = Key::NUM_OF;
|
|
else {
|
|
const Interval curr_interval = stave->part()->instrument()->transpose();
|
|
global_key = transposeKey(global_key, curr_interval);
|
|
}
|
|
|
|
std::map<Key, int>::iterator it = key_frequencies.find(global_key);
|
|
if (it != key_frequencies.end())
|
|
key_frequencies[global_key]++;
|
|
else
|
|
key_frequencies[global_key] = 1;
|
|
|
|
track += VOICES;
|
|
}
|
|
|
|
//Change key into QString
|
|
Key new_key = Key::C;
|
|
int max_key_freq = 0;
|
|
for (std::map<Key, int>::iterator iter = key_frequencies.begin(); iter != key_frequencies.end(); ++iter) {
|
|
if (iter->second > max_key_freq) {
|
|
new_key = iter->first;
|
|
max_key_freq = iter->second;
|
|
}
|
|
}
|
|
QString key_text;
|
|
QString tooltip;
|
|
if (new_key == Key::INVALID) {
|
|
key_text = "X";
|
|
tooltip = qApp->translate("MuseScore", keyNames[15]);
|
|
}
|
|
else if (new_key == Key::NUM_OF) {
|
|
key_text = "?";
|
|
tooltip = tr("Custom Key Signature");
|
|
}
|
|
else if (int(new_key) == 0) {
|
|
key_text = "\u266E";
|
|
tooltip = qApp->translate("MuseScore", keyNames[14]);
|
|
}
|
|
else if (int(new_key) < 0) {
|
|
key_text = QString::number(abs(int(new_key))) + "\u266D";
|
|
tooltip = qApp->translate("MuseScore", keyNames[(7 + int(new_key)) * 2 + 1]);
|
|
}
|
|
else {
|
|
key_text = QString::number(abs(int(new_key))) + "\u266F";
|
|
tooltip = qApp->translate("MuseScore", keyNames[(int(new_key) - 1) * 2]);
|
|
}
|
|
|
|
int x = pos + (*stagger) * spacing;
|
|
Measure* measure = (seg)? seg->measure() : 0;
|
|
if (addMetaValue(x, pos, key_text, row, ElementType::KEYSIG, 0, seg, measure, tooltip)) {
|
|
(*stagger)++;
|
|
global_z_value++;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// repeat_meta
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::barline_meta(Segment* seg, int* stagger, int pos)
|
|
{
|
|
if (!seg->isBeginBarLineType() && !seg->isEndBarLineType() && !seg->isBarLine() && !seg->isStartRepeatBarLineType())
|
|
return;
|
|
|
|
//Find position of repeat_meta in metas
|
|
int row = getMetaRow(tr("Barlines"));
|
|
|
|
QString repeat_text = "";
|
|
BarLine* barline = toBarLine(seg->element(0));
|
|
|
|
if (barline) {
|
|
switch (barline->barLineType()) {
|
|
case BarLineType::START_REPEAT:
|
|
repeat_text = QString("Start repeat");
|
|
break;
|
|
case BarLineType::END_REPEAT:
|
|
repeat_text = QString("End repeat");
|
|
break;
|
|
case BarLineType::END_START_REPEAT:
|
|
// actually an end repeat followed by a start repeat, so nothing needs to be done here
|
|
break;
|
|
case BarLineType::DOUBLE:
|
|
repeat_text = QString("Double barline");
|
|
break;
|
|
case BarLineType::END:
|
|
repeat_text = QString("Final barline");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
is_barline = true;
|
|
}
|
|
else
|
|
return;
|
|
|
|
Measure* measure = seg->measure();
|
|
ElementType element_type = ElementType::BAR_LINE;
|
|
Element* element = nullptr;
|
|
|
|
if (repeat_text == "") {
|
|
is_barline = false;
|
|
return;
|
|
}
|
|
|
|
int x = pos + (*stagger) * spacing;
|
|
if (addMetaValue(x, pos, repeat_text, row, element_type, element, seg, measure)) {
|
|
(*stagger)++;
|
|
global_z_value++;
|
|
}
|
|
is_barline = false;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// jump_marker_meta
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::jump_marker_meta(Segment* seg, int* stagger, int pos)
|
|
{
|
|
if (seg)
|
|
return;
|
|
|
|
//Find position of repeat_meta in metas
|
|
int row = getMetaRow(tr("Jumps and Markers"));
|
|
|
|
QString text = "";
|
|
Element* element = nullptr;
|
|
if (std::get<2>(repeat_info))
|
|
element = std::get<2>(repeat_info);
|
|
else if (std::get<3>(repeat_info))
|
|
element = std::get<3>(repeat_info);
|
|
|
|
Measure* measure;
|
|
ElementType element_type;
|
|
if (std::get<2>(repeat_info)) {
|
|
Jump* jump = toJump(std::get<2>(repeat_info));
|
|
text = jump->plainText();
|
|
measure = jump->measure();
|
|
element_type = ElementType::JUMP;
|
|
}
|
|
else {
|
|
Marker* marker = toMarker(std::get<3>(repeat_info));
|
|
QList<TextFragment> tf_list = marker->fragmentList();
|
|
for (TextFragment tf: tf_list)
|
|
text.push_back(tf.text);
|
|
measure = marker->measure();
|
|
if (marker->markerType() == Marker::Type::FINE || marker->markerType() == Marker::Type::TOCODA) {
|
|
element_type = ElementType::MARKER;
|
|
std::get<2>(repeat_info) = std::get<3>(repeat_info);
|
|
std::get<3>(repeat_info) = nullptr;
|
|
}
|
|
else
|
|
element_type = ElementType::MARKER;
|
|
}
|
|
|
|
if (text == "") {
|
|
std::get<2>(repeat_info) = nullptr;
|
|
std::get<3>(repeat_info) = nullptr;
|
|
return;
|
|
}
|
|
|
|
int x = pos + (*stagger) * spacing;
|
|
if (addMetaValue(x, pos, text, row, element_type, element, seg, measure)) {
|
|
(*stagger)++;
|
|
global_z_value++;
|
|
}
|
|
std::get<2>(repeat_info) = nullptr;
|
|
std::get<3>(repeat_info) = nullptr;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// measure_meta
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::measure_meta(Segment* , int* , int pos)
|
|
{
|
|
//Increment decided by zoom level
|
|
int increment_value = 1;
|
|
int halfway = (max_zoom + min_zoom) / 2;
|
|
if (grid_width <= max_zoom && grid_width > halfway)
|
|
increment_value = 1;
|
|
else if (grid_width <= halfway && grid_width > min_zoom)
|
|
increment_value = 5;
|
|
else
|
|
increment_value = 10;
|
|
|
|
int curr_measure_number = pos / grid_width;
|
|
if (curr_measure_number == global_measure_number)
|
|
return;
|
|
|
|
global_measure_number = curr_measure_number;
|
|
//Check if 1 or 5*n
|
|
if (curr_measure_number + 1 != 1 && (curr_measure_number + 1) % increment_value != 0)
|
|
return;
|
|
|
|
//Find position of measure_meta in metas
|
|
int row = getMetaRow(tr("Measures"));
|
|
|
|
//Adjust number
|
|
Measure* curr_measure;
|
|
for (curr_measure = _score->firstMeasure(); curr_measure_number != 0; curr_measure_number--, curr_measure = curr_measure->nextMeasure()) {
|
|
|
|
}
|
|
|
|
//Add measure number
|
|
QString measure_number = (curr_measure->irregular())? "( )" : QString::number(curr_measure->no() + 1);
|
|
QGraphicsTextItem* graphics_text_item = new QGraphicsTextItem(measure_number);
|
|
graphics_text_item->setDefaultTextColor(QColor(0, 0, 0));
|
|
graphics_text_item->setX(pos);
|
|
graphics_text_item->setY(grid_height * row + verticalScrollBar()->value());
|
|
|
|
QFont f = graphics_text_item->font();
|
|
f.setPointSizeF(7.0);
|
|
graphics_text_item->setFont(f);
|
|
|
|
//Center text
|
|
qreal remaining_width = grid_width - graphics_text_item->boundingRect().width();
|
|
qreal remaining_height = grid_height - graphics_text_item->boundingRect().height();
|
|
graphics_text_item->setX(graphics_text_item->x() + remaining_width / 2);
|
|
graphics_text_item->setY(graphics_text_item->y() + remaining_height / 2);
|
|
|
|
int end_of_text = graphics_text_item->x() + graphics_text_item->boundingRect().width();
|
|
int end_of_grid = getWidth();
|
|
if (end_of_text <= end_of_grid) {
|
|
scene()->addItem(graphics_text_item);
|
|
|
|
std::pair<QGraphicsItem*, int> pair_measure_text(graphics_text_item, row);
|
|
meta_rows.push_back(pair_measure_text);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getMetaRow
|
|
//---------------------------------------------------------
|
|
|
|
unsigned int Timeline::getMetaRow(QString target_text)
|
|
{
|
|
if (collapsed_meta) {
|
|
if (target_text == tr("Measures"))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
int row = 0;
|
|
for (auto it = metas.begin(); it != metas.end(); ++it) {
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> meta = *it;
|
|
QString meta_text = std::get<0>(meta);
|
|
bool visible = std::get<2>(meta);
|
|
if (meta_text == target_text && visible)
|
|
break;
|
|
else if (!visible)
|
|
continue;
|
|
row++;
|
|
}
|
|
return row;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// addMetaValue
|
|
//---------------------------------------------------------
|
|
|
|
bool Timeline::addMetaValue(int x, int pos, QString meta_text, int row, ElementType element_type, Element* element, Segment* seg, Measure* measure, QString tooltip)
|
|
{
|
|
QGraphicsTextItem* graphics_text_item = new QGraphicsTextItem(meta_text);
|
|
qreal text_width = graphics_text_item->boundingRect().width();
|
|
|
|
QGraphicsPixmapItem* graphics_pixmap_item = nullptr;
|
|
if (is_barline)
|
|
graphics_pixmap_item = new QGraphicsPixmapItem(*barlines[meta_text]);
|
|
|
|
if (graphics_pixmap_item) {
|
|
text_width = 10;
|
|
if (text_width > grid_width) {
|
|
text_width = grid_width;
|
|
if (meta_text == QString("End repeat") && std::get<4>(repeat_info))
|
|
text_width /= 2;
|
|
}
|
|
}
|
|
|
|
if (text_width + x > getWidth())
|
|
text_width = getWidth() - x;
|
|
|
|
//Adjust x for end repeats
|
|
if ((meta_text == QString("End repeat") || meta_text == QString("Final barline") || meta_text == QString("Double barline") || std::get<2>(repeat_info)) && !collapsed_meta) {
|
|
if (std::get<0>(repeat_info) > 0)
|
|
x = pos + grid_width - std::get<1>(repeat_info) + std::get<0>(repeat_info) * spacing;
|
|
else {
|
|
x = pos + grid_width - text_width;
|
|
std::get<1>(repeat_info) = text_width;
|
|
}
|
|
//Check if extending past left side
|
|
if (x < 0) {
|
|
text_width = text_width + x;
|
|
x = 0;
|
|
}
|
|
}
|
|
|
|
//Return if past width
|
|
if (x >= getWidth())
|
|
return false;
|
|
|
|
QGraphicsItem* item_to_add;
|
|
if (graphics_pixmap_item) {
|
|
//Exact values required for repeat pixmap to work visually
|
|
if (text_width != 10)
|
|
graphics_pixmap_item = new QGraphicsPixmapItem();
|
|
if (meta_text == QString("Start repeat"))
|
|
std::get<4>(repeat_info) = true;
|
|
graphics_pixmap_item->setX(x + 2);
|
|
graphics_pixmap_item->setY(grid_height * row + verticalScrollBar()->value() + 3);
|
|
item_to_add = graphics_pixmap_item;
|
|
}
|
|
else if (meta_text == "\uE047" || meta_text == "\uE048") {
|
|
graphics_text_item->setX(x);
|
|
graphics_text_item->setY(grid_height * row + verticalScrollBar()->value() - 2);
|
|
item_to_add = graphics_text_item;
|
|
}
|
|
else if (row == 0 ) {
|
|
graphics_text_item->setX(x);
|
|
graphics_text_item->setY(grid_height * row + verticalScrollBar()->value() - 6);
|
|
item_to_add = graphics_text_item;
|
|
}
|
|
else {
|
|
graphics_text_item->setX(x);
|
|
graphics_text_item->setY(grid_height * row + verticalScrollBar()->value() - 1);
|
|
item_to_add = graphics_text_item;
|
|
}
|
|
|
|
QFontMetrics f(QApplication::font());
|
|
QString part_name = f.elidedText(graphics_text_item->toPlainText(),
|
|
Qt::ElideRight,
|
|
text_width);
|
|
|
|
//Set tool tip if elided
|
|
if (tooltip != "")
|
|
graphics_text_item->setToolTip(tooltip);
|
|
else if (part_name != meta_text)
|
|
graphics_text_item->setToolTip(graphics_text_item->toPlainText());
|
|
graphics_text_item->setPlainText(part_name);
|
|
|
|
//Make text fit within rectangle
|
|
while (graphics_text_item->boundingRect().width() > text_width &&
|
|
graphics_text_item->toPlainText() != "") {
|
|
QString text = graphics_text_item->toPlainText();
|
|
text.chop(1);
|
|
graphics_text_item->setPlainText(text);
|
|
}
|
|
|
|
QGraphicsRectItem* graphics_rect_item = new QGraphicsRectItem(x,
|
|
grid_height * row + verticalScrollBar()->value(),
|
|
text_width,
|
|
grid_height);
|
|
if (tooltip != "")
|
|
graphics_rect_item->setToolTip(tooltip);
|
|
else if (part_name != meta_text)
|
|
graphics_rect_item->setToolTip(meta_text);
|
|
else if (graphics_pixmap_item)
|
|
graphics_rect_item->setToolTip(tr(meta_text.toLatin1().constData()));
|
|
|
|
setMetaData(graphics_rect_item, -1, element_type, measure, true, element, item_to_add, seg);
|
|
setMetaData(item_to_add, -1, element_type, measure, true, element, graphics_rect_item, seg);
|
|
|
|
graphics_rect_item->setZValue(global_z_value);
|
|
item_to_add->setZValue(global_z_value);
|
|
|
|
graphics_rect_item->setPen(QPen(Qt::black));
|
|
graphics_rect_item->setBrush(QBrush(Qt::gray));
|
|
|
|
scene()->addItem(graphics_rect_item);
|
|
scene()->addItem(item_to_add);
|
|
|
|
std::pair<QGraphicsItem*, int> pair_time_rect(graphics_rect_item, row);
|
|
std::pair<QGraphicsItem*, int> pair_time_text(item_to_add, row);
|
|
meta_rows.push_back(pair_time_rect);
|
|
meta_rows.push_back(pair_time_text);
|
|
|
|
if (meta_text == QString("End repeat"))
|
|
std::get<0>(repeat_info)++;
|
|
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setMetaData
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::setMetaData(QGraphicsItem* gi, int staff, ElementType et, Measure* m, bool full_measure, Element* e, QGraphicsItem* pair_item, Segment* seg)
|
|
{
|
|
//full_measure true for meta values
|
|
//pr is null for grid items, set for meta values
|
|
//seg is set if key meta
|
|
gi->setData(0, QVariant::fromValue<int>(staff));
|
|
gi->setData(1, QVariant::fromValue<ElementType>(et));
|
|
gi->setData(2, QVariant::fromValue<void*>(m));
|
|
gi->setData(3, QVariant::fromValue<bool>(full_measure));
|
|
gi->setData(4, QVariant::fromValue<void*>(e));
|
|
gi->setData(5, QVariant::fromValue<void*>(pair_item));
|
|
gi->setData(6, QVariant::fromValue<void*>(seg));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getWidth
|
|
//---------------------------------------------------------
|
|
|
|
int Timeline::getWidth()
|
|
{
|
|
if (_score)
|
|
return int(_score->nmeasures() * grid_width);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getHeight
|
|
//---------------------------------------------------------
|
|
|
|
int Timeline::getHeight()
|
|
{
|
|
if (_score)
|
|
return int((nstaves() + nmetas()) * grid_height + 3);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// correctStave
|
|
//---------------------------------------------------------
|
|
|
|
int Timeline::correctStave(int stave)
|
|
{
|
|
//Find correct stave (skipping hidden staves)
|
|
QList<Staff*> list = _score->staves();
|
|
int count = 0;
|
|
while (stave >= count) {
|
|
if (count >= list.size()) {
|
|
count = list.size() - 1;
|
|
return count;
|
|
}
|
|
if (!list.at(count)->show())
|
|
stave++;
|
|
count++;
|
|
}
|
|
return stave;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
// correctPart
|
|
//---------------------------------------------------------
|
|
|
|
int Timeline::correctPart(int stave)
|
|
{
|
|
//Find correct stave (skipping hidden staves)
|
|
QList<Staff*> list = _score->staves();
|
|
int count = correctStave(stave);
|
|
return getParts().indexOf(list.at(count)->part());
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getParts
|
|
//---------------------------------------------------------
|
|
|
|
QList<Part*> Timeline::getParts()
|
|
{
|
|
QList<Part*> realPartList = _score->parts();
|
|
QList<Part*> partList;
|
|
for (Part* p : realPartList) {
|
|
for (int i = 0; i < p->nstaves(); i++) {
|
|
partList.append(p);
|
|
}
|
|
}
|
|
|
|
return partList;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// changeSelection
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::changeSelection(SelState)
|
|
{
|
|
scene()->blockSignals(true);
|
|
scene()->clearSelection();
|
|
|
|
QRectF selection_rect = selection_path.boundingRect();
|
|
if (selection_rect == QRectF())
|
|
return;
|
|
|
|
int nmeta = nmetas();
|
|
|
|
//Get borders of the current viewport
|
|
int left_border = horizontalScrollBar()->value();
|
|
int right_border = horizontalScrollBar()->value() + viewport()->width();
|
|
int top_border = verticalScrollBar()->value() + nmeta * grid_height;
|
|
int bottom_border = verticalScrollBar()->value() + viewport()->height();
|
|
|
|
bool selection_extends_up = false, selection_extends_left = false;
|
|
bool selection_extends_right = false, selection_extends_down = false;
|
|
|
|
//Figure out which directions the selection extends
|
|
if (selection_rect.top() < top_border)
|
|
selection_extends_up = true;
|
|
if (selection_rect.left() < left_border - 1)
|
|
selection_extends_left = true;
|
|
if (selection_rect.right() > right_border)
|
|
selection_extends_right = true;
|
|
if (selection_rect.bottom() > bottom_border)
|
|
selection_extends_down = true;
|
|
|
|
if (selection_extends_down
|
|
&& old_selection_rect.bottom() != selection_rect.bottom()
|
|
&& !meta_value) {
|
|
int new_scrollbar_value = int(verticalScrollBar()->value() + selection_rect.bottom() - bottom_border);
|
|
verticalScrollBar()->setValue(new_scrollbar_value);
|
|
}
|
|
else if (selection_extends_up
|
|
&& !selection_extends_down
|
|
&& old_selection_rect.bottom() != selection_rect.bottom()
|
|
&& !meta_value
|
|
&& old_selection_rect.contains(selection_rect)) {
|
|
int new_scrollbar_value = int(verticalScrollBar()->value() + selection_rect.bottom() - bottom_border);
|
|
verticalScrollBar()->setValue(new_scrollbar_value);
|
|
}
|
|
|
|
if (selection_extends_right
|
|
&& old_selection_rect.right() != selection_rect.right()) {
|
|
int new_scrollbar_value = int(horizontalScrollBar()->value() + selection_rect.right() - right_border);
|
|
horizontalScrollBar()->setValue(new_scrollbar_value);
|
|
}
|
|
if (selection_extends_up
|
|
&& old_selection_rect.top() != selection_rect.top()
|
|
&& !meta_value) {
|
|
int new_scrollbar_value = int(selection_rect.top()) - nmeta * grid_height;
|
|
verticalScrollBar()->setValue(new_scrollbar_value);
|
|
}
|
|
if (selection_extends_left
|
|
&& old_selection_rect.left() != selection_rect.left()) {
|
|
int new_scrollbar_value = int(selection_rect.left());
|
|
horizontalScrollBar()->setValue(new_scrollbar_value);
|
|
}
|
|
|
|
if (selection_extends_left
|
|
&& !selection_extends_right
|
|
&& old_selection_rect.right() != selection_rect.right()
|
|
&& old_selection_rect.contains(selection_rect)) {
|
|
int new_scrollbar_value = int(horizontalScrollBar()->value() + selection_rect.right() - right_border);
|
|
horizontalScrollBar()->setValue(new_scrollbar_value);
|
|
}
|
|
if (selection_extends_right
|
|
&& !selection_extends_left
|
|
&& old_selection_rect.left() != selection_rect.left()
|
|
&& old_selection_rect.contains(selection_rect)) {
|
|
int new_scrollbar_value = int(selection_rect.left());
|
|
horizontalScrollBar()->setValue(new_scrollbar_value);
|
|
}
|
|
|
|
if (selection_extends_down
|
|
&& !selection_extends_up
|
|
&& old_selection_rect.top() != selection_rect.top()
|
|
&& !meta_value
|
|
&& old_selection_rect.contains(selection_rect)) {
|
|
int new_scrollbar_value = int(selection_rect.top()) - nmeta * grid_height;
|
|
verticalScrollBar()->setValue(new_scrollbar_value);
|
|
}
|
|
|
|
old_selection_rect = selection_rect;
|
|
|
|
meta_value = false;
|
|
scene()->blockSignals(false);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// drawSelection
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::drawSelection()
|
|
{
|
|
selection_path = QPainterPath();
|
|
selection_path.setFillRule(Qt::WindingFill);
|
|
|
|
std::set<std::tuple<Measure*, int, ElementType>> meta_labels_set;
|
|
|
|
const Selection& selection = _score->selection();
|
|
const QList<Element*>& el = selection.elements();
|
|
for (Element* element : el) {
|
|
if (element->tick() == Fraction(-1,1))
|
|
continue;
|
|
else {
|
|
switch (element->type()) {
|
|
case ElementType::INSTRUMENT_NAME:
|
|
case ElementType::VBOX:
|
|
case ElementType::HBOX:
|
|
case ElementType::TEXT:
|
|
case ElementType::TIE_SEGMENT:
|
|
case ElementType::SLUR_SEGMENT:
|
|
case ElementType::TIE:
|
|
case ElementType::SLUR:
|
|
continue;
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
int staffIdx;
|
|
Fraction tick = element->tick();
|
|
Measure* measure = _score->tick2measure(tick);
|
|
staffIdx = element->staffIdx();
|
|
if (numToStaff(staffIdx) && !numToStaff(staffIdx)->show())
|
|
continue;
|
|
|
|
if ((element->isTempoText() ||
|
|
element->isKeySig() ||
|
|
element->isTimeSig() ||
|
|
element->isRehearsalMark() ||
|
|
element->isJump() ||
|
|
element->isMarker()) &&
|
|
!element->generated())
|
|
staffIdx = -1;
|
|
|
|
if (element->isBarLine()) {
|
|
staffIdx = -1;
|
|
BarLine* barline = toBarLine(element);
|
|
if (barline &&
|
|
(barline->barLineType() == BarLineType::END_REPEAT || barline->barLineType() == BarLineType::DOUBLE || barline->barLineType() == BarLineType::END) &&
|
|
measure != _score->lastMeasure()) {
|
|
if (measure->prevMeasure())
|
|
measure = measure->prevMeasure();
|
|
}
|
|
}
|
|
|
|
//element->type() for meta rows, invalid for everything else
|
|
ElementType element_type = (staffIdx == -1)? element->type() : ElementType::INVALID;
|
|
|
|
//If has a multi measure rest, find the count and add each measure to it
|
|
// ws: If style flag Sid::createMultiMeasureRests is not set, then
|
|
// measure->mmRest() is not valid
|
|
|
|
// if (measure->mmRest() ) {
|
|
if (measure->mmRest() && measure->score()->styleB(Sid::createMultiMeasureRests)) {
|
|
int mmrest_count = measure->mmRest()->mmRestCount();
|
|
Measure* tmp_measure = measure;
|
|
for (int mmrest_measure = 0; mmrest_measure < mmrest_count; mmrest_measure++) {
|
|
std::tuple<Measure*, int, ElementType> tmp(tmp_measure, staffIdx, element_type);
|
|
meta_labels_set.insert(tmp);
|
|
tmp_measure = tmp_measure->nextMeasure();
|
|
}
|
|
}
|
|
else {
|
|
std::tuple<Measure*, int, ElementType> tmp(measure, staffIdx, element_type);
|
|
meta_labels_set.insert(tmp);
|
|
}
|
|
}
|
|
|
|
QList<QGraphicsItem*> graphics_item_list = scene()->items();
|
|
for (QGraphicsItem* graphics_item : graphics_item_list) {
|
|
|
|
int stave = graphics_item->data(0).value<int>();
|
|
ElementType element_type = graphics_item->data(1).value<ElementType>();
|
|
Measure* measure = static_cast<Measure*>(graphics_item->data(2).value<void*>());
|
|
|
|
std::tuple<Measure*, int, ElementType> target_tuple(measure, stave, element_type);
|
|
std::set<std::tuple<Measure*, int, ElementType>>::iterator it;
|
|
it = meta_labels_set.find(target_tuple);
|
|
|
|
if (stave == -1 && it != meta_labels_set.end()) {
|
|
//Make sure the element is correct
|
|
QList<Element*> element_list = _score->selection().elements();
|
|
Element* target_element = static_cast<Element*>(graphics_item->data(4).value<void*>());
|
|
Segment* seg = static_cast<Segment*>(graphics_item->data(6).value<void*>());
|
|
|
|
if (target_element) {
|
|
for (Element* element : element_list) {
|
|
if (element == target_element) {
|
|
QGraphicsRectItem* graphics_rect_item = qgraphicsitem_cast<QGraphicsRectItem*>(graphics_item);
|
|
if (graphics_rect_item)
|
|
graphics_rect_item->setBrush(QBrush(QColor(173,216,230)));
|
|
}
|
|
}
|
|
}
|
|
else if (seg) {
|
|
for (Element* element : element_list) {
|
|
QGraphicsRectItem* graphics_rect_item = qgraphicsitem_cast<QGraphicsRectItem*>(graphics_item);
|
|
if (graphics_rect_item) {
|
|
for (int track = 0; track < _score->nstaves() * VOICES; track++) {
|
|
if (element == seg->element(track))
|
|
graphics_rect_item->setBrush(QBrush(QColor(173,216,230)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
QGraphicsRectItem* graphics_rect_item = qgraphicsitem_cast<QGraphicsRectItem*>(graphics_item);
|
|
if (graphics_rect_item)
|
|
graphics_rect_item->setBrush(QBrush(QColor(173,216,230)));
|
|
}
|
|
}
|
|
//Change color from gray to only blue
|
|
else if (it != meta_labels_set.end()) {
|
|
QGraphicsRectItem* graphics_rect_item = qgraphicsitem_cast<QGraphicsRectItem*>(graphics_item);
|
|
graphics_rect_item->setBrush(QBrush(QColor(graphics_rect_item->brush().color().red(),
|
|
graphics_rect_item->brush().color().green(),
|
|
255)));
|
|
selection_path.addRect(graphics_rect_item->rect());
|
|
}
|
|
}
|
|
|
|
QGraphicsPathItem* graphics_path_item = new QGraphicsPathItem(selection_path.simplified());
|
|
if (selection.isRange())
|
|
graphics_path_item->setPen(QPen(QColor(0, 0, 255), 3));
|
|
else
|
|
graphics_path_item->setPen(QPen(QColor(0, 0, 0), 1));
|
|
|
|
graphics_path_item->setBrush(Qt::NoBrush);
|
|
graphics_path_item->setZValue(-1);
|
|
scene()->addItem(graphics_path_item);
|
|
|
|
if (std::get<0>(old_hover_info)) {
|
|
std::get<0>(old_hover_info) = nullptr;
|
|
std::get<1>(old_hover_info) = -1;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mousePressEvent
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::mousePressEvent(QMouseEvent* event)
|
|
{
|
|
if (!_score)
|
|
return;
|
|
|
|
if (event->button() == Qt::RightButton)
|
|
return;
|
|
|
|
//Set as clicked
|
|
mouse_pressed = true;
|
|
scene()->clearSelection();
|
|
|
|
QPointF scene_pt = mapToScene(event->pos());
|
|
//Set as old location
|
|
old_loc = QPoint(int(scene_pt.x()), int(scene_pt.y()));
|
|
QList<QGraphicsItem*> graphics_item_list = scene()->items(scene_pt);
|
|
//Find highest z value for rect
|
|
int max_z_value = -4;
|
|
QGraphicsItem* curr_graphics_item = nullptr;
|
|
for (QGraphicsItem* graphics_item: graphics_item_list) {
|
|
QGraphicsRectItem* graphics_rect_item = qgraphicsitem_cast<QGraphicsRectItem*>(graphics_item);
|
|
if (graphics_rect_item && graphics_item->zValue() > max_z_value) {
|
|
curr_graphics_item = graphics_item;
|
|
max_z_value = graphics_item->zValue();
|
|
}
|
|
}
|
|
if (curr_graphics_item) {
|
|
int stave = curr_graphics_item->data(0).value<int>();
|
|
Measure* curr_measure = static_cast<Measure*>(curr_graphics_item->data(2).value<void*>());
|
|
if (numToStaff(stave) && !numToStaff(stave)->show())
|
|
return;
|
|
|
|
if (!curr_measure) {
|
|
int nmeta = nmetas();
|
|
int bottom_of_meta = nmeta * grid_height + verticalScrollBar()->value();
|
|
|
|
//Handle measure box clicks
|
|
if (scene_pt.y() > (nmeta - 1) * grid_height + verticalScrollBar()->value() &&
|
|
scene_pt.y() < bottom_of_meta) {
|
|
|
|
QRectF tmp(scene_pt.x(), 0, 3, nmeta * grid_height + nstaves() * grid_height);
|
|
QList<QGraphicsItem*> gl = scene()->items(tmp);
|
|
Measure* measure = nullptr;
|
|
|
|
for (QGraphicsItem* graphics_item : gl) {
|
|
measure = static_cast<Measure*>(graphics_item->data(2).value<void*>());
|
|
//-3 z value is the grid square values
|
|
if (graphics_item->zValue() == -3 && measure)
|
|
break;
|
|
}
|
|
if (measure)
|
|
_cv->adjustCanvasPosition(measure, false);
|
|
}
|
|
if (scene_pt.y() < bottom_of_meta)
|
|
return;
|
|
|
|
QList<QGraphicsItem*> gl = items(event->pos());
|
|
for (QGraphicsItem* graphics_item : gl) {
|
|
curr_measure = static_cast<Measure*>(graphics_item->data(2).value<void*>());
|
|
stave = graphics_item->data(0).value<int>();
|
|
if (curr_measure)
|
|
break;
|
|
}
|
|
if (!curr_measure) {
|
|
_score->select(0, SelectType::SINGLE, 0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool meta_value_clicked = curr_graphics_item->data(3).value<bool>();
|
|
|
|
scene()->clearSelection();
|
|
if (meta_value_clicked) {
|
|
|
|
meta_value = true;
|
|
old_selection_rect = QRect();
|
|
|
|
_cv->adjustCanvasPosition(curr_measure, false, 0);
|
|
verticalScrollBar()->setValue(0);
|
|
|
|
Segment* seg = static_cast<Segment*>(curr_graphics_item->data(6).value<void*>());
|
|
|
|
if (seg) {
|
|
_score->deselectAll();
|
|
for (int track = 0; track < _score->nstaves() * VOICES; track++) {
|
|
Element* element = seg->element(track);
|
|
if (element)
|
|
_score->select(seg->element(track), SelectType::ADD);
|
|
}
|
|
}
|
|
else {
|
|
//Also select the elements that they correspond to
|
|
ElementType element_type = curr_graphics_item->data(1).value<ElementType>();
|
|
SegmentType segment_type = SegmentType::Invalid;
|
|
if (element_type == ElementType::KEYSIG)
|
|
segment_type = SegmentType::KeySig;
|
|
else if (element_type == ElementType::TIMESIG)
|
|
segment_type = SegmentType::TimeSig;
|
|
|
|
if (segment_type != SegmentType::Invalid) {
|
|
Segment* curr_seg = curr_measure->first();
|
|
for (; curr_seg && curr_seg->segmentType() != segment_type; curr_seg = curr_seg->next()) {
|
|
}
|
|
if (curr_seg) {
|
|
_score->deselectAll();
|
|
for (int j = 0; j < _score->nstaves(); j++) {
|
|
Element* element = curr_seg->firstElement(j);
|
|
if (element)
|
|
_score->select(element, SelectType::ADD);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
_score->deselectAll();
|
|
_score->select(curr_measure, SelectType::ADD, 0);
|
|
//Select just the element for tempo_text
|
|
Element* element = static_cast<Element*>(curr_graphics_item->data(4).value<void*>());
|
|
_score->deselectAll();
|
|
_score->select(element);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
//Handle cell clicks
|
|
if (event->modifiers() == Qt::ShiftModifier) {
|
|
if (curr_measure->mmRest())
|
|
curr_measure = curr_measure->mmRest();
|
|
else if (curr_measure->mmRestCount() == -1)
|
|
curr_measure = curr_measure->prevMeasureMM();
|
|
_score->select(curr_measure, SelectType::RANGE, stave);
|
|
_score->setUpdateAll();
|
|
}
|
|
else if (event->modifiers() == Qt::ControlModifier) {
|
|
|
|
if (_score->selection().isNone()) {
|
|
if (curr_measure->mmRest())
|
|
curr_measure = curr_measure->mmRest();
|
|
else if (curr_measure->mmRestCount() == -1)
|
|
curr_measure = curr_measure->prevMeasureMM();
|
|
|
|
_score->select(curr_measure, SelectType::RANGE, 0);
|
|
_score->select(curr_measure, SelectType::RANGE, _score->nstaves()-1);
|
|
_score->setUpdateAll();
|
|
}
|
|
else
|
|
_score->deselectAll();
|
|
}
|
|
else {
|
|
if (curr_measure->mmRest())
|
|
curr_measure = curr_measure->mmRest();
|
|
else if (curr_measure->mmRestCount() == -1)
|
|
curr_measure = curr_measure->prevMeasureMM();
|
|
_score->select(curr_measure, SelectType::SINGLE, stave);
|
|
}
|
|
_cv->adjustCanvasPosition(curr_measure, false, stave);
|
|
|
|
}
|
|
mscore->endCmd();
|
|
_score->update();
|
|
}
|
|
else {
|
|
_score->deselectAll();
|
|
mscore->endCmd();
|
|
_score->update();
|
|
}
|
|
_score->setUpdateAll();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mouseMoveEvent
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::mouseMoveEvent(QMouseEvent* event)
|
|
{
|
|
QPointF new_loc = mapToScene(event->pos());
|
|
if (!mouse_pressed) {
|
|
|
|
if (cursorIsOn() == "meta") {
|
|
this->setCursor(Qt::ArrowCursor);
|
|
mouseOver(new_loc);
|
|
}
|
|
else if (cursorIsOn() == "invalid")
|
|
this->setCursor(Qt::ForbiddenCursor);
|
|
else
|
|
this->setCursor(Qt::ArrowCursor);
|
|
|
|
emit moved(QPointF(-1, -1));
|
|
return;
|
|
}
|
|
|
|
if (state == ViewState::NORMAL) {
|
|
if (event->modifiers() == Qt::ShiftModifier) {
|
|
//Slight wiggle room for selection (Same as score)
|
|
if (abs(new_loc.x() - old_loc.x()) > 2 ||
|
|
abs(new_loc.y() - old_loc.y()) > 2) {
|
|
_score->deselectAll();
|
|
updateGrid();
|
|
state = ViewState::LASSO;
|
|
selection_box = new QGraphicsRectItem();
|
|
selection_box->setRect(old_loc.x(), old_loc.y(), 0, 0);
|
|
selection_box->setPen(QPen(QColor(0, 0, 255), 2));
|
|
selection_box->setBrush(QBrush(QColor(0, 0, 255, 50)));
|
|
scene()->addItem(selection_box);
|
|
}
|
|
}
|
|
else {
|
|
state = ViewState::DRAG;
|
|
this->setCursor(Qt::SizeAllCursor);
|
|
}
|
|
}
|
|
|
|
if (state == ViewState::LASSO) {
|
|
QRect tmp = QRect((old_loc.x() < new_loc.x())? old_loc.x() : new_loc.x(),
|
|
(old_loc.y() < new_loc.y())? old_loc.y() : new_loc.y(),
|
|
abs(new_loc.x() - old_loc.x()),
|
|
abs(new_loc.y() - old_loc.y()));
|
|
selection_box->setRect(tmp);
|
|
}
|
|
else if (state == ViewState::DRAG) {
|
|
int x_offset = int(old_loc.x()) - int(new_loc.x());
|
|
int y_offset = int(old_loc.y()) - int(new_loc.y());
|
|
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + x_offset);
|
|
verticalScrollBar()->setValue(verticalScrollBar()->value() + y_offset);
|
|
}
|
|
emit moved(QPointF(-1, -1));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mouseReleaseEvent
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::mouseReleaseEvent(QMouseEvent*)
|
|
{
|
|
mouse_pressed = false;
|
|
if (state == ViewState::LASSO) {
|
|
|
|
scene()->removeItem(selection_box);
|
|
_score->deselectAll();
|
|
|
|
int width, height;
|
|
QPoint loc = mapFromScene(selection_box->rect().topLeft());
|
|
width = int(selection_box->rect().width());
|
|
height = int(selection_box->rect().height());
|
|
|
|
QList<QGraphicsItem*> graphics_item_list = items(QRect(loc.x(), loc.y(), width, height));
|
|
//Find top left and bottom right to create selection
|
|
QGraphicsItem* tl_graphics_item = nullptr;
|
|
QGraphicsItem* br_graphics_item = nullptr;
|
|
for (QGraphicsItem* graphics_item : graphics_item_list) {
|
|
Measure* curr_measure = static_cast<Measure*>(graphics_item->data(2).value<void*>());
|
|
if (!curr_measure) continue;
|
|
int stave = graphics_item->data(0).value<int>();
|
|
if (stave == -1) continue;
|
|
|
|
if (!tl_graphics_item && !br_graphics_item) {
|
|
tl_graphics_item = graphics_item;
|
|
br_graphics_item = graphics_item;
|
|
continue;
|
|
}
|
|
|
|
if (graphics_item->boundingRect().top() < tl_graphics_item->boundingRect().top())
|
|
tl_graphics_item = graphics_item;
|
|
if (graphics_item->boundingRect().left() < tl_graphics_item->boundingRect().left())
|
|
tl_graphics_item = graphics_item;
|
|
|
|
if (graphics_item->boundingRect().bottom() > br_graphics_item->boundingRect().bottom())
|
|
br_graphics_item = graphics_item;
|
|
if (graphics_item->boundingRect().right() > br_graphics_item->boundingRect().right())
|
|
br_graphics_item = graphics_item;
|
|
|
|
}
|
|
|
|
//Select single tl_graphics_item and then range br_graphics_item
|
|
if (tl_graphics_item && br_graphics_item) {
|
|
Measure* tl_measure = static_cast<Measure*>(tl_graphics_item->data(2).value<void*>());
|
|
int tl_stave = tl_graphics_item->data(0).value<int>();
|
|
Measure* br_measure = static_cast<Measure*>(br_graphics_item->data(2).value<void*>());
|
|
int br_stave = br_graphics_item->data(0).value<int>();
|
|
if (tl_measure && br_measure) {
|
|
//Focus selection of mmRests here
|
|
if (tl_measure->mmRest())
|
|
tl_measure = tl_measure->mmRest();
|
|
else if (tl_measure->mmRestCount() == -1)
|
|
tl_measure = tl_measure->prevMeasureMM();
|
|
if (br_measure->mmRest())
|
|
br_measure = br_measure->mmRest();
|
|
else if (br_measure->mmRestCount() == -1)
|
|
br_measure = br_measure->prevMeasureMM();
|
|
|
|
_score->select(tl_measure, SelectType::SINGLE, tl_stave);
|
|
_score->select(br_measure, SelectType::RANGE, br_stave);
|
|
}
|
|
_cv->adjustCanvasPosition(tl_measure, false, tl_stave);
|
|
}
|
|
|
|
_score->update();
|
|
mscore->endCmd();
|
|
}
|
|
else if (state == ViewState::DRAG) {
|
|
this->setCursor(Qt::ArrowCursor);
|
|
mscore->endCmd();
|
|
}
|
|
state = ViewState::NORMAL;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// leaveEvent
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::leaveEvent(QEvent*)
|
|
{
|
|
if (!rect().contains(mapFromGlobal(QCursor::pos()))) {
|
|
QPointF p = mapToScene(mapFromGlobal(QCursor::pos()));
|
|
mouseOver(p);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// wheelEvent
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::wheelEvent(QWheelEvent* event)
|
|
{
|
|
if (event->modifiers().testFlag(Qt::ControlModifier)) {
|
|
qreal original_cursor_pos = mapToScene(mapFromGlobal(QCursor::pos())).x();
|
|
int original_scroll_value = horizontalScrollBar()->value();
|
|
qreal ratio = original_cursor_pos / qreal(getWidth());
|
|
|
|
if (event->angleDelta().y() > 0 && grid_width < max_zoom) {
|
|
grid_width++;
|
|
updateGrid();
|
|
}
|
|
else if (event->angleDelta().y() < 0 && grid_width > min_zoom) {
|
|
grid_width--;
|
|
updateGrid();
|
|
}
|
|
|
|
//Attempt to keep mouse in original spot
|
|
qreal new_pos = qreal(getWidth()) * ratio;
|
|
int offset = new_pos - original_cursor_pos;
|
|
horizontalScrollBar()->setValue(original_scroll_value + offset);
|
|
}
|
|
else if (event->modifiers().testFlag(Qt::ShiftModifier)) {
|
|
qreal num_of_steps = qreal(event->angleDelta().y()) / 2;
|
|
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - int(num_of_steps));
|
|
}
|
|
else
|
|
QGraphicsView::wheelEvent(event);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateGrid
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::updateGrid()
|
|
{
|
|
if (!isVisible())
|
|
return;
|
|
|
|
if (_score && _score->firstMeasure()) {
|
|
drawGrid(nstaves(), _score->nmeasures());
|
|
updateView();
|
|
drawSelection();
|
|
mouseOver(mapToScene(mapFromGlobal(QCursor::pos())));
|
|
row_names->updateLabels(getLabels(), grid_height);
|
|
}
|
|
viewport()->update();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setScore
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::setScore(Score* s)
|
|
{
|
|
_score = s;
|
|
scene()->clear();
|
|
|
|
if (_score) {
|
|
connect(_score, &QObject::destroyed, this, &Timeline::objectDestroyed, Qt::UniqueConnection);
|
|
drawGrid(nstaves(), _score->nmeasures());
|
|
changeSelection(SelState::NONE);
|
|
row_names->updateLabels(getLabels(), grid_height);
|
|
}
|
|
else {
|
|
//Clear timeline if no score is present
|
|
QSplitter* sp = scrollArea->grid();
|
|
if (sp && sp->count() > 0) {
|
|
TRowLabels* t_row_labels = static_cast<TRowLabels*>(sp->widget(0));
|
|
std::vector<std::pair<QString, bool>> no_labels;
|
|
t_row_labels->updateLabels(no_labels, 0);
|
|
}
|
|
meta_rows.clear();
|
|
setSceneRect(0, 0, 0, 0);
|
|
}
|
|
|
|
viewport()->update();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setScoreView
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::setScoreView(ScoreView* v)
|
|
{
|
|
_cv = v;
|
|
if (_cv) {
|
|
connect(_cv, &ScoreView::sizeChanged, this, &Timeline::updateView, Qt::UniqueConnection);
|
|
connect(_cv, &ScoreView::viewRectChanged, this, &Timeline::updateView, Qt::UniqueConnection);
|
|
connect(_cv, &QObject::destroyed, this, &Timeline::objectDestroyed, Qt::UniqueConnection);
|
|
updateView();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// objectDestroyed
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::objectDestroyed(QObject* obj)
|
|
{
|
|
if (_cv == obj)
|
|
setScoreView(nullptr);
|
|
else if (_score == obj)
|
|
setScore(nullptr);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateView
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::updateView()
|
|
{
|
|
if (!isVisible())
|
|
return;
|
|
|
|
if (_cv && _score) {
|
|
QRectF canvas = QRectF(_cv->matrix().inverted().mapRect(_cv->geometry()));
|
|
|
|
std::set<std::pair<Measure*, int>> visible_items_set;
|
|
|
|
//Find visible measures of score
|
|
for (Measure* curr_measure = _score->firstMeasure(); curr_measure; curr_measure = curr_measure->nextMeasure()) {
|
|
System* system = curr_measure->system();
|
|
|
|
if (curr_measure->mmRest() && _score->styleB(Sid::createMultiMeasureRests)) {
|
|
//Handle mmRests
|
|
Measure* mmrest_measure = curr_measure->mmRest();
|
|
system = mmrest_measure->system();
|
|
if (!system)
|
|
continue;
|
|
|
|
//Add all measures within mmRest to visible_items_set if mmRest_visible
|
|
for (; curr_measure != mmrest_measure->mmRestLast(); curr_measure = curr_measure->nextMeasure()) {
|
|
for (int staff = 0; staff < _score->staves().length(); staff++) {
|
|
if (!_score->staff(staff)->show())
|
|
continue;
|
|
QRectF stave_rect = QRectF(system->canvasBoundingRect().left(),
|
|
system->staffCanvasYpage(staff),
|
|
system->width(),
|
|
system->staff(staff)->bbox().height());
|
|
QRectF show_rect = mmrest_measure->canvasBoundingRect().intersected(stave_rect);
|
|
|
|
if (canvas.intersects(show_rect)) {
|
|
std::pair<Measure*, int> p(curr_measure, staff);
|
|
visible_items_set.insert(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Handle last measure in mmRest
|
|
for (int staff = 0; staff < _score->staves().length(); staff++) {
|
|
if (!_score->staff(staff)->show())
|
|
continue;
|
|
QRectF stave_rect = QRectF(system->canvasBoundingRect().left(),
|
|
system->staffCanvasYpage(staff),
|
|
system->width(),
|
|
system->staff(staff)->bbox().height());
|
|
QRectF show_rect = mmrest_measure->canvasBoundingRect().intersected(stave_rect);
|
|
|
|
if (canvas.intersects(show_rect)) {
|
|
std::pair<Measure*, int> p(curr_measure, staff);
|
|
visible_items_set.insert(p);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!system)
|
|
continue;
|
|
|
|
for (int staff = 0; staff < _score->staves().length(); staff++) {
|
|
if (!_score->staff(staff)->show())
|
|
continue;
|
|
QRectF stave_rect = QRectF(system->canvasBoundingRect().left(),
|
|
system->staffCanvasYpage(staff),
|
|
system->width(),
|
|
system->staff(staff)->bbox().height());
|
|
QRectF show_rect = curr_measure->canvasBoundingRect().intersected(stave_rect);
|
|
|
|
if (canvas.intersects(show_rect)) {
|
|
std::pair<Measure*, int> p(curr_measure, staff);
|
|
visible_items_set.insert(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Find respective visible elements in timeline
|
|
QPainterPath visible_painter_path = QPainterPath();
|
|
visible_painter_path.setFillRule(Qt::WindingFill);
|
|
for (QGraphicsItem* graphics_item : scene()->items()) {
|
|
int stave = graphics_item->data(0).value<int>();
|
|
Measure* measure = static_cast<Measure*>(graphics_item->data(2).value<void*>());
|
|
if (numToStaff(stave) && !numToStaff(stave)->show())
|
|
continue;
|
|
|
|
std::pair<Measure*, int> tmp(measure, stave);
|
|
std::set<std::pair<Measure*, int>>::iterator it;
|
|
it = visible_items_set.find(tmp);
|
|
if (it != visible_items_set.end())
|
|
visible_painter_path.addRect(graphics_item->boundingRect());
|
|
}
|
|
|
|
QPainterPath non_visible_painter_path = QPainterPath();
|
|
non_visible_painter_path.setFillRule(Qt::WindingFill);
|
|
|
|
QRectF timeline_rect = QRectF(0, 0, getWidth(), getHeight());
|
|
non_visible_painter_path.addRect(timeline_rect);
|
|
|
|
non_visible_painter_path = non_visible_painter_path.subtracted(visible_painter_path);
|
|
|
|
QGraphicsPathItem* non_visible_path_item = new QGraphicsPathItem(non_visible_painter_path.simplified());
|
|
|
|
QPen non_visible_pen = QPen(QColor(100, 150, 250));
|
|
QBrush non_visible_brush = QBrush(QColor(192, 192, 192, 180));
|
|
non_visible_path_item->setPen(QPen(non_visible_brush.color()));
|
|
non_visible_path_item->setBrush(non_visible_brush);
|
|
non_visible_path_item->setZValue(-3);
|
|
|
|
QGraphicsPathItem* visible = new QGraphicsPathItem(visible_painter_path.simplified());
|
|
visible->setPen(non_visible_pen);
|
|
visible->setBrush(Qt::NoBrush);
|
|
visible->setZValue(-2);
|
|
|
|
//Find old path, remove it
|
|
for (QGraphicsItem* graphics_item : scene()->items()) {
|
|
if (graphics_item->type() == QGraphicsPathItem().type()) {
|
|
QGraphicsPathItem* old_path_item = static_cast<QGraphicsPathItem*>(graphics_item);
|
|
QBrush old_brush = old_path_item->brush();
|
|
QPen old_pen = old_path_item->pen();
|
|
if (old_brush == non_visible_brush || old_pen == non_visible_pen)
|
|
scene()->removeItem(old_path_item);
|
|
}
|
|
}
|
|
|
|
scene()->addItem(non_visible_path_item);
|
|
scene()->addItem(visible);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// nstaves
|
|
//---------------------------------------------------------
|
|
|
|
int Timeline::nstaves()
|
|
{
|
|
return _score->staves().size();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// colorBox
|
|
//---------------------------------------------------------
|
|
|
|
QColor Timeline::colorBox(QGraphicsRectItem* item)
|
|
{
|
|
Measure* measure = static_cast<Measure*>(item->data(2).value<void*>());
|
|
int stave = item->data(0).value<int>();
|
|
for (Segment* seg = measure->first(); seg; seg = seg->next()) {
|
|
if (!seg->isChordRestType())
|
|
continue;
|
|
for (int track = stave * VOICES; track < stave * VOICES + VOICES; track++) {
|
|
ChordRest* chord_rest = seg->cr(track);
|
|
if (chord_rest) {
|
|
ElementType crt = chord_rest->type();
|
|
if (crt == ElementType::CHORD || crt == ElementType::REPEAT_MEASURE)
|
|
return QColor(Qt::gray);
|
|
}
|
|
}
|
|
}
|
|
return QColor(224,224,224);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getLabels
|
|
//---------------------------------------------------------
|
|
|
|
std::vector<std::pair<QString, bool>> Timeline::getLabels()
|
|
{
|
|
if (!_score) {
|
|
std::vector<std::pair<QString, bool>> no_labels;
|
|
return no_labels;
|
|
}
|
|
QList<Part*> part_list = getParts();
|
|
//transfer them into a vector of qstrings and then add the meta row names
|
|
std::vector<std::pair<QString, bool>> row_labels;
|
|
if (collapsed_meta) {
|
|
std::pair<QString, bool> first("", true);
|
|
std::pair<QString, bool> second(tr("Measures"), true);
|
|
row_labels.push_back(first);
|
|
row_labels.push_back(second);
|
|
}
|
|
else {
|
|
for (auto it = metas.begin(); it != metas.end(); ++it) {
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> meta = *it;
|
|
if (!std::get<2>(meta))
|
|
continue;
|
|
std::pair<QString, bool> meta_label(std::get<0>(meta), true);
|
|
row_labels.push_back(meta_label);
|
|
}
|
|
}
|
|
|
|
for (int stave = 0; stave < part_list.size(); stave++) {
|
|
QTextDocument doc;
|
|
QString part_name = "";
|
|
doc.setHtml(part_list.at(stave)->longName());
|
|
part_name = doc.toPlainText();
|
|
if (part_name.isEmpty())
|
|
part_name = part_list.at(stave)->instrumentName();
|
|
|
|
std::pair<QString, bool> instrument_label(part_name, part_list.at(stave)->show());
|
|
row_labels.push_back(instrument_label);
|
|
}
|
|
return row_labels;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// handle_scroll
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::handle_scroll(int value)
|
|
{
|
|
if (!_score)
|
|
return;
|
|
for (std::vector<std::pair<QGraphicsItem*, int>>::iterator it = meta_rows.begin();
|
|
it != meta_rows.end(); ++it) {
|
|
std::pair<QGraphicsItem*, int> pair_graphics_int = *it;
|
|
|
|
QGraphicsItem* graphics_item = pair_graphics_int.first;
|
|
QGraphicsRectItem* graphics_rect_item = qgraphicsitem_cast<QGraphicsRectItem*>(graphics_item);
|
|
QGraphicsLineItem* graphics_line_item = qgraphicsitem_cast<QGraphicsLineItem*>(graphics_item);
|
|
QGraphicsPixmapItem* graphics_pixmap_item = qgraphicsitem_cast<QGraphicsPixmapItem*>(graphics_item);
|
|
|
|
int row_y = pair_graphics_int.second * grid_height;
|
|
int scrollbar_value = value;
|
|
|
|
if (graphics_rect_item) {
|
|
QRectF rectf = graphics_rect_item->rect();
|
|
rectf.setY(qreal(scrollbar_value + row_y));
|
|
rectf.setHeight(grid_height);
|
|
graphics_rect_item->setRect(rectf);
|
|
}
|
|
else if (graphics_line_item) {
|
|
QLineF linef = graphics_line_item->line();
|
|
linef.setLine(linef.x1(), row_y + scrollbar_value + 1, linef.x2(), row_y + scrollbar_value + 1);
|
|
graphics_line_item->setLine(linef);
|
|
}
|
|
else if (graphics_pixmap_item)
|
|
graphics_pixmap_item->setY(qreal(scrollbar_value + row_y + 3));
|
|
else
|
|
graphics_item->setY(qreal(scrollbar_value + row_y));
|
|
}
|
|
viewport()->update();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mouseOver
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::mouseOver(QPointF pos)
|
|
{
|
|
//Choose item with the largest original Z value...
|
|
QList<QGraphicsItem*> graphics_list = scene()->items(pos);
|
|
QGraphicsItem* hovered_graphics_item = 0;
|
|
int max_z_value = -1;
|
|
for (QGraphicsItem* curr_graphics_item: graphics_list) {
|
|
if (qgraphicsitem_cast<QGraphicsTextItem*>(curr_graphics_item))
|
|
continue;
|
|
if (curr_graphics_item->zValue() >= max_z_value && curr_graphics_item->zValue() < global_z_value) {
|
|
hovered_graphics_item = curr_graphics_item;
|
|
max_z_value = hovered_graphics_item->zValue();
|
|
}
|
|
else if (curr_graphics_item->zValue() > global_z_value && std::get<1>(old_hover_info) >= max_z_value){
|
|
hovered_graphics_item = curr_graphics_item;
|
|
max_z_value = std::get<1>(old_hover_info);
|
|
}
|
|
}
|
|
|
|
if (!hovered_graphics_item) {
|
|
if (std::get<0>(old_hover_info)) {
|
|
std::get<0>(old_hover_info)->setZValue(std::get<1>(old_hover_info));
|
|
static_cast<QGraphicsItem*>(std::get<0>(old_hover_info)->data(5).value<void*>())->setZValue(std::get<1>(old_hover_info));
|
|
QGraphicsRectItem* graphics_rect_item1 = qgraphicsitem_cast<QGraphicsRectItem*>(std::get<0>(old_hover_info));
|
|
QGraphicsRectItem* graphics_rect_item2 = qgraphicsitem_cast<QGraphicsRectItem*>(static_cast<QGraphicsItem*>(std::get<0>(old_hover_info)->data(5).value<void*>()));
|
|
if (graphics_rect_item1)
|
|
graphics_rect_item1->setBrush(QBrush(std::get<2>(old_hover_info)));
|
|
if (graphics_rect_item2)
|
|
graphics_rect_item2->setBrush(QBrush(std::get<2>(old_hover_info)));
|
|
std::get<0>(old_hover_info) = nullptr;
|
|
std::get<1>(old_hover_info) = -1;
|
|
}
|
|
return;
|
|
}
|
|
QGraphicsItem* pair_item = static_cast<QGraphicsItem*>(hovered_graphics_item->data(5).value<void*>());
|
|
if (!pair_item) {
|
|
if (std::get<0>(old_hover_info)) {
|
|
std::get<0>(old_hover_info)->setZValue(std::get<1>(old_hover_info));
|
|
static_cast<QGraphicsItem*>(std::get<0>(old_hover_info)->data(5).value<void*>())->setZValue(std::get<1>(old_hover_info));
|
|
QGraphicsRectItem* graphics_rect_item1 = qgraphicsitem_cast<QGraphicsRectItem*>(std::get<0>(old_hover_info));
|
|
QGraphicsRectItem* graphics_rect_item2 = qgraphicsitem_cast<QGraphicsRectItem*>(static_cast<QGraphicsItem*>(std::get<0>(old_hover_info)->data(5).value<void*>()));
|
|
if (graphics_rect_item1)
|
|
graphics_rect_item1->setBrush(QBrush(std::get<2>(old_hover_info)));
|
|
if (graphics_rect_item2)
|
|
graphics_rect_item2->setBrush(QBrush(std::get<2>(old_hover_info)));
|
|
std::get<0>(old_hover_info) = nullptr;
|
|
std::get<1>(old_hover_info) = -1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (std::get<0>(old_hover_info) == hovered_graphics_item)
|
|
return;
|
|
|
|
if (std::get<0>(old_hover_info)) {
|
|
std::get<0>(old_hover_info)->setZValue(std::get<1>(old_hover_info));
|
|
static_cast<QGraphicsItem*>(std::get<0>(old_hover_info)->data(5).value<void*>())->setZValue(std::get<1>(old_hover_info));
|
|
QGraphicsRectItem* graphics_rect_item1 = qgraphicsitem_cast<QGraphicsRectItem*>(std::get<0>(old_hover_info));
|
|
QGraphicsRectItem* graphics_rect_item2 = qgraphicsitem_cast<QGraphicsRectItem*>(static_cast<QGraphicsItem*>(std::get<0>(old_hover_info)->data(5).value<void*>()));
|
|
if (graphics_rect_item1)
|
|
graphics_rect_item1->setBrush(QBrush(std::get<2>(old_hover_info)));
|
|
if (graphics_rect_item2)
|
|
graphics_rect_item2->setBrush(QBrush(std::get<2>(old_hover_info)));
|
|
|
|
std::get<0>(old_hover_info) = nullptr;
|
|
std::get<1>(old_hover_info) = -1;
|
|
}
|
|
|
|
std::get<1>(old_hover_info) = hovered_graphics_item->zValue();
|
|
std::get<0>(old_hover_info) = hovered_graphics_item;
|
|
|
|
//Give items the top z value
|
|
hovered_graphics_item->setZValue(global_z_value + 1);
|
|
pair_item->setZValue(global_z_value + 1);
|
|
|
|
QGraphicsRectItem* graphics_rect_item1 = qgraphicsitem_cast<QGraphicsRectItem*>(hovered_graphics_item);
|
|
QGraphicsRectItem* graphics_rect_item2 = qgraphicsitem_cast<QGraphicsRectItem*>(pair_item);
|
|
if (graphics_rect_item1) {
|
|
std::get<2>(old_hover_info) = graphics_rect_item1->brush().color();
|
|
if (std::get<2>(old_hover_info) != QColor(173,216,230))
|
|
graphics_rect_item1->setBrush(QBrush(Qt::lightGray));
|
|
}
|
|
if (graphics_rect_item2) {
|
|
std::get<2>(old_hover_info) = graphics_rect_item2->brush().color();
|
|
if (std::get<2>(old_hover_info) != QColor(173,216,230))
|
|
graphics_rect_item2->setBrush(QBrush(Qt::lightGray));
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// swapMeta
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::swapMeta(unsigned int row, bool switch_up)
|
|
{
|
|
//Attempt to switch row up or down, skipping non visible rows
|
|
if (switch_up && row != 0) {
|
|
//traverse backwards until visible one is found
|
|
auto swap = metas.begin() + correctMetaRow(row) - 1;
|
|
while (!std::get<2>(*swap))
|
|
swap--;
|
|
iter_swap(metas.begin() + correctMetaRow(row), swap);
|
|
}
|
|
else if (!switch_up && row != nmetas() - 2) {
|
|
//traverse forwards until visible one is found
|
|
auto swap = metas.begin() + correctMetaRow(row) + 1;
|
|
while (!std::get<2>(*swap))
|
|
swap++;
|
|
iter_swap(metas.begin() + correctMetaRow(row), swap);
|
|
}
|
|
|
|
updateGrid();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// numToStaff
|
|
//---------------------------------------------------------
|
|
|
|
Staff* Timeline::numToStaff(int staff)
|
|
{
|
|
if (!_score)
|
|
return 0;
|
|
QList<Staff*> staves = _score->staves();
|
|
if (staves.size() > staff && staff >= 0)
|
|
return staves.at(staff);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// toggleShow
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::toggleShow(int staff)
|
|
{
|
|
if (!_score)
|
|
return;
|
|
QList<Part*> parts = getParts();
|
|
if (parts.size() > staff && staff >= 0) {
|
|
parts.at(staff)->setShow(!parts.at(staff)->show());
|
|
parts.at(staff)->undoChangeProperty(Pid::VISIBLE, parts.at(staff)->show());
|
|
_score->masterScore()->setLayoutAll();
|
|
_score->masterScore()->update();
|
|
mscore->endCmd();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// showContextMenu
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::contextMenuEvent(QContextMenuEvent*)
|
|
{
|
|
QMenu* context_menu = new QMenu(tr("Context menu"), this);
|
|
if (row_names->cursorIsOn() == "instrument") {
|
|
QAction* edit_instruments = new QAction(tr("Edit Instruments"), this);
|
|
connect(edit_instruments, SIGNAL(triggered()), this, SLOT(requestInstrumentDialog()));
|
|
context_menu->addAction(edit_instruments);
|
|
context_menu->exec(QCursor::pos());
|
|
}
|
|
else if (row_names->cursorIsOn() == "meta" || cursorIsOn() == "meta") {
|
|
for (auto it = metas.begin(); it != metas.end(); ++it) {
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> meta = *it;
|
|
QString row_name = std::get<0>(meta);
|
|
if (row_name != tr("Measures")) {
|
|
QAction* action = new QAction(row_name, this);
|
|
action->setCheckable(true);
|
|
action->setChecked(std::get<2>(meta));
|
|
connect(action, SIGNAL(triggered()), this, SLOT(toggleMetaRow()));
|
|
context_menu->addAction(action);
|
|
}
|
|
}
|
|
context_menu->addSeparator();
|
|
QAction* hide_all = new QAction(tr("Hide all"), this);
|
|
connect(hide_all, SIGNAL(triggered()), this, SLOT(toggleMetaRow()));
|
|
context_menu->addAction(hide_all);
|
|
QAction* show_all = new QAction(tr("Show all"), this);
|
|
connect(show_all, SIGNAL(triggered()), this, SLOT(toggleMetaRow()));
|
|
context_menu->addAction(show_all);
|
|
context_menu->exec(QCursor::pos());
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// toggleMetaRow
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::toggleMetaRow()
|
|
{
|
|
QAction* action = qobject_cast<QAction*>(QObject::sender());
|
|
if (action) {
|
|
QString target_text = action->text();
|
|
|
|
if (target_text == tr("Hide all")) {
|
|
for (auto it = metas.begin(); it != metas.end(); ++it) {
|
|
QString meta_text = std::get<0>(*it);
|
|
if (meta_text != tr("Measures"))
|
|
std::get<2>(*it) = false;
|
|
}
|
|
updateGrid();
|
|
return;
|
|
}
|
|
else if (target_text == tr("Show all")) {
|
|
for (auto it = metas.begin(); it != metas.end(); ++it)
|
|
std::get<2>(*it) = true;
|
|
updateGrid();
|
|
return;
|
|
}
|
|
|
|
bool checked = action->isChecked();
|
|
//Find target text in metas and toggle visibility to the checked status of action
|
|
for (auto it = metas.begin(); it != metas.end(); ++it) {
|
|
QString meta_text = std::get<0>(*it);
|
|
if (meta_text == target_text) {
|
|
std::get<2>(*it) = checked;
|
|
updateGrid();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// nmetas
|
|
//---------------------------------------------------------
|
|
|
|
unsigned int Timeline::nmetas()
|
|
{
|
|
unsigned int total = 0;
|
|
if (collapsed_meta)
|
|
return 2;
|
|
for (auto it = metas.begin(); it != metas.end(); ++it) {
|
|
std::tuple<QString, void (Timeline::*)(Segment*, int*, int), bool> meta = *it;
|
|
if (std::get<2>(meta))
|
|
total++;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// correctMetaRow
|
|
//---------------------------------------------------------
|
|
|
|
unsigned int Timeline::correctMetaRow(unsigned int row)
|
|
{
|
|
unsigned int count = 0;
|
|
auto it = metas.begin();
|
|
while (row >= count) {
|
|
if (!std::get<2>(*it))
|
|
row++;
|
|
count++;
|
|
++it;
|
|
}
|
|
return row;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// correctMetaRow
|
|
//---------------------------------------------------------
|
|
|
|
QString Timeline::cursorIsOn()
|
|
{
|
|
QPointF scene_pos = mapToScene(mapFromGlobal(QCursor::pos()));
|
|
QGraphicsItem* graphics_item = scene()->itemAt(scene_pos, transform());
|
|
if (graphics_item) {
|
|
auto it = meta_rows.begin();
|
|
for (;it != meta_rows.end(); ++it) {
|
|
if ((*it).first == graphics_item)
|
|
break;
|
|
}
|
|
if (it != meta_rows.end())
|
|
return "meta";
|
|
else {
|
|
QList<QGraphicsItem*> graphics_item_list = scene()->items(scene_pos);
|
|
for (QGraphicsItem* curr_graphics_item : graphics_item_list) {
|
|
Measure* curr_measure = static_cast<Measure*>(curr_graphics_item->data(2).value<void*>());
|
|
int stave = curr_graphics_item->data(0).value<int>();
|
|
if (curr_measure && !numToStaff(stave)->show())
|
|
return "invalid";
|
|
}
|
|
return "instrument";
|
|
}
|
|
}
|
|
else
|
|
return "";
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// requestInstrumentDialog
|
|
//---------------------------------------------------------
|
|
|
|
void Timeline::requestInstrumentDialog()
|
|
{
|
|
QAction* act = getAction("instruments");
|
|
mscore->cmd(act);
|
|
if (mscore->getMixer())
|
|
mscore->getMixer()->setScore(_score);
|
|
}
|
|
|
|
}
|