MuseScore/libmscore/bend.cpp

280 lines
9.1 KiB
C++
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
// $Id:$
//
// Copyright (C) 2010-2011 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 "bend.h"
#include "score.h"
#include "undo.h"
#include "staff.h"
#include "chord.h"
#include "note.h"
//---------------------------------------------------------
// label
//---------------------------------------------------------
static const char* label[] = {
"", "1/4", "1/2", "3/4", "full",
"1 1/4", "1 1/2", "1 3/4", "2",
"2 1/4", "2 1/2", "2 3/4", "3"
};
//---------------------------------------------------------
// Bend
//---------------------------------------------------------
Bend::Bend(Score* s)
: Element(s)
{
setFlags(ELEMENT_MOVABLE | ELEMENT_SELECTABLE);
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void Bend::layout()
{
qreal _spatium = spatium();
if (staff() && !staff()->isTabStaff()) {
2012-05-26 14:26:10 +02:00
setbbox(QRectF());
if (!parent()) {
noteWidth = -_spatium*2;
notePos = QPointF(0.0, _spatium*3);
}
}
_lw = _spatium * 0.15;
Note* note = static_cast<Note*>(parent());
if (note == 0) {
noteWidth = 0.0;
notePos = QPointF();
}
else {
notePos = note->pos();
noteWidth = note->width();
}
QRectF bb;
const TextStyle* st = &score()->textStyle(TEXT_STYLE_BENCH);
QFont f = st->fontPx(_spatium);
QFontMetricsF fm(f);
int n = _points.size();
qreal x = noteWidth;
qreal y = -_spatium * .8;
qreal x2, y2;
qreal aw = _spatium * .5;
QPolygonF arrowUp;
arrowUp << QPointF(0, 0) << QPointF(aw*.5, aw) << QPointF(-aw*.5, aw);
QPolygonF arrowDown;
arrowDown << QPointF(0, 0) << QPointF(aw*.5, -aw) << QPointF(-aw*.5, -aw);
for (int pt = 0; pt < n; ++pt) {
if (pt == (n-1))
break;
int pitch = _points[pt].pitch;
if (pt == 0 && pitch) {
y2 = -notePos.y() -_spatium * 2;
x2 = x;
bb |= QRectF(x, y, x2-x, y2-y);
bb |= arrowUp.translated(x2, y2 + _spatium * .2).boundingRect();
int idx = (pitch + 12)/25;
const char* l = label[idx];
bb |= fm.boundingRect(QRectF(x2, y2, 0, 0),
Qt::AlignHCenter | Qt::AlignBottom | Qt::TextDontClip, QString(l));
y = y2;
}
if (pitch == _points[pt+1].pitch) {
if (pt == (n-2))
break;
x2 = x + _spatium;
y2 = y;
bb |= QRectF(x, y, x2-x, y2-y);
}
else if (pitch < _points[pt+1].pitch) {
// up
x2 = x + _spatium*.5;
y2 = -notePos.y() -_spatium * 2;
qreal dx = x2 - x;
qreal dy = y2 - y;
QPainterPath path;
path.moveTo(x, y);
path.cubicTo(x+dx/2, y, x2, y+dy/4, x2, y2);
bb |= path.boundingRect();
bb |= arrowUp.translated(x2, y2 + _spatium * .2).boundingRect();
int idx = (_points[pt+1].pitch + 12)/25;
const char* l = label[idx];
QRectF r;
bb |= fm.boundingRect(QRectF(x2, y2, 0, 0),
Qt::AlignHCenter | Qt::AlignBottom | Qt::TextDontClip, QString(l));
}
else {
// down
x2 = x + _spatium*.5;
y2 = y + _spatium * 3;
qreal dx = x2 - x;
qreal dy = y2 - y;
QPainterPath path;
path.moveTo(x, y);
path.cubicTo(x+dx/2, y, x2, y+dy/4, x2, y2);
bb |= path.boundingRect();
bb |= arrowDown.translated(x2, y2 - _spatium * .2).boundingRect();
}
x = x2;
y = y2;
}
bb.adjust(-_lw, -_lw, _lw, _lw);
setbbox(bb);
setPos(0.0, 0.0);
adjustReadPos();
}
//---------------------------------------------------------
// draw
//---------------------------------------------------------
void Bend::draw(QPainter* painter) const
{
if (staff() && !staff()->isTabStaff())
2012-05-26 14:26:10 +02:00
return;
QPen pen(curColor(), _lw, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter->setPen(pen);
painter->setBrush(QBrush(Qt::black));
qreal _spatium = spatium();
const TextStyle* st = &score()->textStyle(TEXT_STYLE_BENCH);
QFont f = st->fontPx(_spatium);
painter->setFont(f);
int n = _points.size();
qreal x = noteWidth;
qreal y = -_spatium * .8;
qreal x2, y2;
qreal aw = _spatium * .5;
QPolygonF arrowUp;
arrowUp << QPointF(0, 0) << QPointF(aw*.5, aw) << QPointF(-aw*.5, aw);
QPolygonF arrowDown;
arrowDown << QPointF(0, 0) << QPointF(aw*.5, -aw) << QPointF(-aw*.5, -aw);
for (int pt = 0; pt < n; ++pt) {
if (pt == (n-1))
break;
int pitch = _points[pt].pitch;
if (pt == 0 && pitch) {
y2 = -notePos.y() -_spatium * 2;
x2 = x;
painter->drawLine(QLineF(x, y, x2, y2));
painter->setBrush(QBrush(Qt::black));
painter->drawPolygon(arrowUp.translated(x2, y2 + _spatium * .2));
int idx = (pitch + 12)/25;
const char* l = label[idx];
painter->drawText(QRectF(x2, y2, .0, .0), Qt::AlignVCenter|Qt::TextDontClip, QString(l));
y = y2;
}
if (pitch == _points[pt+1].pitch) {
if (pt == (n-2))
break;
x2 = x + _spatium;
y2 = y;
painter->drawLine(QLineF(x, y, x2, y2));
}
else if (pitch < _points[pt+1].pitch) {
// up
x2 = x + _spatium*.5;
y2 = -notePos.y() -_spatium * 2;
qreal dx = x2 - x;
qreal dy = y2 - y;
QPainterPath path;
path.moveTo(x, y);
path.cubicTo(x+dx/2, y, x2, y+dy/4, x2, y2);
painter->setBrush(Qt::NoBrush);
painter->drawPath(path);
painter->setBrush(QBrush(Qt::black));
painter->drawPolygon(arrowUp.translated(x2, y2 + _spatium * .2));
int idx = (_points[pt+1].pitch + 12)/25;
const char* l = label[idx];
qreal ty = y2; // - _spatium;
painter->drawText(QRectF(x2, ty, .0, .0),
Qt::AlignHCenter | Qt::AlignBottom | Qt::TextDontClip, QString(l));
}
else {
// down
x2 = x + _spatium*.5;
y2 = y + _spatium * 3;
qreal dx = x2 - x;
qreal dy = y2 - y;
QPainterPath path;
path.moveTo(x, y);
path.cubicTo(x+dx/2, y, x2, y+dy/4, x2, y2);
painter->setBrush(Qt::NoBrush);
painter->drawPath(path);
painter->setBrush(QBrush(Qt::black));
painter->drawPolygon(arrowDown.translated(x2, y2 - _spatium * .2));
}
x = x2;
y = y2;
}
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void Bend::write(Xml& xml) const
{
xml.stag("Bend");
foreach(const PitchValue& v, _points) {
xml.tagE(QString("point time=\"%1\" pitch=\"%2\" vibrato=\"%3\"")
.arg(v.time).arg(v.pitch).arg(v.vibrato));
}
xml.etag();
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void Bend::read(const QDomElement& de)
{
for (QDomElement e = de.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
const QString& tag(e.tagName());
if (tag == "point") {
PitchValue pv;
pv.time = e.attribute("time").toInt();
pv.pitch = e.attribute("pitch").toInt();
pv.vibrato = e.attribute("vibrato").toInt();
_points.append(pv);
}
else
domError(e);
}
}