MuseScore/mscore/continuouspanel.cpp
2014-06-03 13:58:05 -04:00

398 lines
15 KiB
C++

//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 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 "libmscore/score.h"
#include "libmscore/measure.h"
#include "libmscore/segment.h"
#include "libmscore/system.h"
#include "libmscore/staff.h"
#include "libmscore/page.h"
#include "libmscore/sym.h"
#include "libmscore/instrument.h"
#include "libmscore/part.h"
#include "libmscore/timesig.h"
#include "libmscore/keysig.h"
#include "libmscore/barline.h"
#include "scoreview.h"
#include "continuouspanel.h"
namespace Ms {
//---------------------------------------------------------
// ContinuousPanel
//---------------------------------------------------------
ContinuousPanel::ContinuousPanel(ScoreView* sv)
{
_sv = sv;
_visible = false;
_width = 0.0;
_oldWidth = 0.0;
_newWidth = 0.0;
_measureWidth = 0.0;
_height = 0.0;
_offsetPanel = 0.0;
_x = 0.0;
_y = 0.0;
_heightName = 0.0;
_widthClef = 0.0;
_widthKeySig = 0.0;
_widthTimeSig = 0.0;
_xPosTimeSig = 0.0;
_currentMeasure = nullptr;
_currentMeasureTick = 0;
_currentMeasureNo = 0;
_mmRestCount = 0;
_xPosMeasure = 0;
}
//---------------------------------------------------------
// paintContinousPanel
//---------------------------------------------------------
void ContinuousPanel::paint(const QRect& r, QPainter& p)
{
if (!_visible)
return;
Measure* measure = _score->tick2measure(0);
if (measure == 0)
return;
if (measure->mmRest()) {
measure = measure->mmRest();
_mmRestCount = measure->mmRestCount();
}
System* system = measure->system();
if (system == 0)
return;
Segment* s = _score->tick2segment(0);
double _spatium = _score->spatium();
_x = 0;
if (_width <= 0)
_width = s->x();
//
// Don't show panel if staff names are visible
//
if (_sv->xoffset() / _sv->mag() + _width >= 0)
return;
//
// Set panel height for whole system
//
_height = 6 * _spatium;
_y = system->staffYpage(0) + system->page()->pos().y();
double y2 = 0.0;
for (int i = 0; i < _score->nstaves(); ++i) {
SysStaff* ss = system->staff(i);
if (!ss->show() || !_score->staff(i)->show())
continue;
y2 = ss->y() + ss->bbox().height();
}
_height += y2 + 2*_spatium;
_y -= 4 * _spatium;
//
// Check elements at current panel position
//
_offsetPanel = -(_sv->xoffset()) / _sv->mag();
_rect = QRect(_offsetPanel + _width, _y, 1, _height);
//qDebug() << "width=" << _width << "x="<< x << "y="<< y << "_offsetPanel=" << _offsetPanel << "_sv->xoffset()" << _sv->xoffset() << "_sv->mag()" << _sv->mag() <<"_spatium" << _spatium << "s->canvasPos().x()" << s->canvasPos().x() << "s->x()" << s->x();
Page* page = _score->pages().front();
QList<Element*> elementsCurrent = page->items(_rect);
if (elementsCurrent.empty())
return;
qStableSort(elementsCurrent.begin(), elementsCurrent.end(), elementLessThan);
foreach(const Element* e, elementsCurrent) {
e->itemDiscovered = 0;
if (!e->visible()) {
if (_score->printing() || !_score->showInvisible())
continue;
}
if (e->type() == Element::ElementType::MEASURE) {
_currentMeasure = static_cast<const Measure*>(e);
_currentTimeSig = _currentMeasure->timesig();
_currentMeasureTick = _currentMeasure->tick();
_currentMeasureNo = _currentMeasure->no();
// Find number of multi measure rests to display in the panel
if (_currentMeasure->isMMRest())
_mmRestCount = _currentMeasure->mmRestCount();
else if (_currentMeasure->mmRest())
_mmRestCount = _currentMeasure->mmRest()->mmRestCount();
else
_mmRestCount = 0;
_xPosMeasure = e->canvasX();
_measureWidth = e->width();
break;
}
}
findElementWidths(elementsCurrent);
draw(p, elementsCurrent);
}
//---------------------------------------------------------
// findElementWidths
// determines the max width for each element types
//---------------------------------------------------------
void ContinuousPanel::findElementWidths(const QList<Element*>& el) {
//
// The first pass serves to get the maximum width for each elements
//
_heightName = 0;
_widthClef = 0;
_widthKeySig = 0;
_widthTimeSig = 0;
_xPosTimeSig = 0;
foreach(const Element* e, el) {
e->itemDiscovered = 0;
if (!e->visible()) {
if (_score->printing() || !_score->showInvisible())
continue;
}
if (e->type() == Element::ElementType::STAFF_LINES) {
Staff* currentStaff = _score->staff(e->staffIdx());
//
// Find maximum height for the staff name
//
QList<StaffName>& staffNamesShort = currentStaff->part()->instr()->shortNames();
QString staffNameShort = staffNamesShort.isEmpty() ? "" : staffNamesShort[0].name;
Text* newName = new Text(_score);
newName->setText(staffNameShort);
newName->setTrack(e->track());
newName->sameLayout();
//
// Find maximum width for the current Clef
//
Clef* newClef = new Clef(_score);
ClefType currentClef = currentStaff->clef(_currentMeasureTick);
newClef->setClefType(currentClef);
newClef->layout();
//
// Find maximum width for the current KeySignature
//
KeySig* newKs = new KeySig(_score);
KeySigEvent currentKeySigEvent = currentStaff->key(_currentMeasureTick);
newKs->setKeySigEvent(currentKeySigEvent);
newKs->layout();
//
// Find maximum width for the current TimeSignature
//
TimeSig* newTs = new TimeSig(_score);
// Try to get local time signature, if not, get the current measure one
TimeSig* currentTimeSig = currentStaff->timeSig(_currentMeasureTick);
if (currentTimeSig)
newTs->setFrom(currentTimeSig);
else
newTs->setSig(_currentTimeSig.numerator(), _currentTimeSig.denominator(), TimeSigType::NORMAL);
newTs->layout();
if ((newName->height() > _heightName) && (newName->text() != ""))
_heightName = newName->height();
if (newClef->width() > _widthClef)
_widthClef = newClef->width();
if (newKs->width() > _widthKeySig)
_widthKeySig = newKs->width();
if (newTs->width() > _widthTimeSig)
_widthTimeSig = newTs->width();
delete newClef;
delete newName;
delete newKs;
delete newTs;
}
}
_newWidth = _heightName * 1.5 + _widthClef + _widthKeySig + _widthTimeSig + 5;
_xPosMeasure -= _offsetPanel;
//qDebug() << "xPosBarLine = " << _xPosMeasure << "_width ="<<_width<< " offsetpanel ="<<_offsetPanel << "newWidth ="<<_newWidth << "oldWidth ="<<_oldWidth << "_measureWidth ="<<_measureWidth;
if (_newWidth > 0) {
if (_newWidth == _width) {
_oldWidth = _width;
_width = _newWidth;
}
else if (((_xPosMeasure <= _newWidth) && (_xPosMeasure >= _oldWidth)) ||
((_xPosMeasure >= _newWidth) && (_xPosMeasure <= _oldWidth)))
_width = _xPosMeasure;
else if (((_xPosMeasure+_measureWidth <= _newWidth) && (_xPosMeasure+_measureWidth >= _oldWidth)) ||
((_xPosMeasure+_measureWidth >= _newWidth) && (_xPosMeasure+_measureWidth <= _oldWidth)))
_width = _xPosMeasure+_measureWidth;
else {
_oldWidth = _width;
_width = _newWidth;
}
}
_rect = QRect(0, _y, _width, _height);
}
//---------------------------------------------------------
// draw
//---------------------------------------------------------
void ContinuousPanel::draw(QPainter& painter, const QList<Element*>& el) {
painter.save();
//
// Draw colored rectangle
//
painter.setClipping(false);
QPointF pos(_offsetPanel, 0);
painter.translate(pos);
QColor c(MScore::selectColor[0]);
QPen pen(c);
pen.setWidthF(0.0);
pen.setStyle( Qt::NoPen );
painter.setPen(pen);
painter.setOpacity(0.80);
painter.setBrush(QColor(205, 210, 235, 255));
painter.drawRect(_rect);
painter.setClipRect(_rect);
painter.setClipping(true);
//
// Draw measure text number
//
painter.setOpacity(1);
painter.setBrush(QColor(0, 0, 0, 255));
Text* newElement = new Text(_score);
newElement->setTextStyleType(TextStyleType::DEFAULT);
newElement->setTrack(0);
newElement->setParent(0);
pos = QPointF (0, _y + newElement->height());
newElement->sameLayout();
newElement->draw(&painter);
QString text = _mmRestCount ? QString("#%1-%2").arg(_currentMeasureNo+1).arg(_currentMeasureNo+_mmRestCount) : QString("#%1").arg(_currentMeasureNo+1);
painter.drawText(QPointF(0, _y + newElement->height()), text);
pos += QPointF (_offsetPanel, -_y);
painter.translate(-pos);
delete newElement;
//
// This second pass draws the elements spaced evently using the width of the largest element
//
foreach(const Element* e, el) {
e->itemDiscovered = 0;
if (!e->visible()) {
if (_score->printing() || !_score->showInvisible())
continue;
}
if (e->type() == Element::ElementType::STAFF_LINES) {
Staff* currentStaff = _score->staff(e->staffIdx());
//
// Draw staff lines
//
QPointF pos;
pos = QPointF (_offsetPanel, 0);
pos += QPointF (_heightName * 1.5, e->pagePos().y());
painter.translate(pos);
e->draw(&painter);
painter.translate(-pos);
//
// Draw the current staff name
//
QList<StaffName>& staffNamesShort = currentStaff->part()->instr()->shortNames();
QString staffNameShort = staffNamesShort.isEmpty() ? "" : staffNamesShort[0].name;
Text* newName = new Text(_score);
newName->setText(staffNameShort);
newName->setTrack(e->track());
newName->sameLayout();
pos = QPointF (_offsetPanel, e->pagePos().y());
painter.translate(pos);
pos = QPointF (_heightName, e->height() / 2 + newName->width() / 2); // Because we rotate the canvas, height and width are swaped
painter.translate(pos);
painter.rotate(-90);
newName->draw(&painter);
painter.rotate(90);
painter.translate(-pos);
pos = QPointF (_heightName * 1.5, 0);
painter.translate(pos);
delete newName;
//
// Draw barline
//
BarLine* newBarLine = new BarLine(_score);
newBarLine->setBarLineType(BarLineType::NORMAL);
newBarLine->layout();
newBarLine->draw(&painter);
delete newBarLine;
//
// Draw the current Clef
//
Clef* newClef = new Clef(_score);
ClefType currentClef = currentStaff->clef(_currentMeasureTick);
newClef->setClefType(currentClef);
newClef->layout();
newClef->draw(&painter);
pos = QPointF(_widthClef,0);
painter.translate(pos);
delete newClef;
//
// Draw the current KeySignature
//
if (currentStaff->genKeySig()) {
KeySig* newKs = new KeySig(_score);
KeySigEvent currentKeySigEvent = currentStaff->key(_currentMeasureTick);
newKs->setKeySigEvent(currentKeySigEvent);
newKs->setParent(_score->tick2segment(_currentMeasureTick));
newKs->setTrack(e->track());
newKs->layout();
newKs->draw(&painter);
delete newKs;
}
pos = QPointF(_widthKeySig + _xPosTimeSig, 0);
painter.translate(pos);
//
// Draw the current TimeSignature
//
TimeSig* newTs = new TimeSig(_score);
// Try to get local time signature, if not, get the current measure one
TimeSig* currentTimeSig = currentStaff->timeSig(_currentMeasureTick);
if (currentTimeSig)
newTs->setFrom(currentTimeSig);
else
newTs->setSig(_currentTimeSig.numerator(), _currentTimeSig.denominator(), TimeSigType::NORMAL);
newTs->layout();
newTs->draw(&painter);
pos = QPointF(_offsetPanel + _heightName * 1.5 + _widthClef + _widthKeySig + _xPosTimeSig, e->pagePos().y());
painter.translate(-pos);
delete newTs;
}
}
painter.restore();
}
}