MuseScore/mscore/ruler.cpp
2014-06-17 14:35:16 +02:00

385 lines
11 KiB
C++

//=============================================================================
// MusE Score
// Linux Music Score Editor
// $Id:$
//
// Copyright (C) 2009 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#include "ruler.h"
#include "libmscore/score.h"
namespace Ms {
#if 0 // yet(?) unused
static const int MAP_OFFSET = 480;
#endif
QPixmap* Ruler::markIcon[3];
static const char* rmark_xpm[]={
"18 18 2 1",
"# c #0000ff",
". c None",
"..................",
"..................",
"..................",
"..................",
"..................",
"..................",
"..................",
"........##########",
"........#########.",
"........########..",
"........#######...",
"........######....",
"........#####.....",
"........####......",
"........###.......",
"........##........",
"........##........",
"........##........"};
static const char* lmark_xpm[]={
"18 18 2 1",
"# c #0000ff",
". c None",
"..................",
"..................",
"..................",
"..................",
"..................",
"..................",
"..................",
"##########........",
".#########........",
"..########........",
"...#######........",
"....######........",
".....#####........",
"......####........",
".......###........",
"........##........",
"........##........",
"........##........"};
static const char* cmark_xpm[]={
"18 18 2 1",
"# c #ff0000",
". c None",
"..................",
"..................",
"..................",
"..................",
"..................",
"..................",
"..................",
"##################",
".################.",
"..##############..",
"...############...",
"....##########....",
".....########.....",
"......######......",
".......####.......",
"........##........",
"........##........",
"........##........"};
//---------------------------------------------------------
// Ruler
//---------------------------------------------------------
Ruler::Ruler(QWidget* parent)
: QWidget(parent)
{
if (markIcon[0] == 0) {
markIcon[0] = new QPixmap(cmark_xpm);
markIcon[1] = new QPixmap(lmark_xpm);
markIcon[2] = new QPixmap(rmark_xpm);
}
setMouseTracking(true);
magStep = 0;
_xpos = 0;
_xmag = 0.1;
_timeType = TType::TICKS;
_font2.setPixelSize(14);
_font2.setBold(true);
_font1.setPixelSize(10);
}
//---------------------------------------------------------
// setScore
//---------------------------------------------------------
void Ruler::setScore(Score* s, Pos* lc)
{
_score = s;
_locator = lc;
if (_score)
_cursor.setContext(_score->tempomap(), _score->sigmap());
setEnabled(_score != 0);
}
//---------------------------------------------------------
// setXmag
//---------------------------------------------------------
void Ruler::setMag(double x, double /*y*/)
{
if (_xmag != x) {
_xmag = x;
int tpix = (480 * 4) * _xmag;
magStep = 0;
if (tpix < 64)
magStep = 1;
if (tpix < 32)
magStep = 2;
if (tpix <= 16)
magStep = 3;
if (tpix < 8)
magStep = 4;
if (tpix <= 4)
magStep = 5;
if (tpix <= 2)
magStep = 6;
update();
}
}
//---------------------------------------------------------
// setXpos
//---------------------------------------------------------
void Ruler::setXpos(int val)
{
_xpos = val;
update();
}
//---------------------------------------------------------
// pix2pos
//---------------------------------------------------------
Pos Ruler::pix2pos(int x) const
{
int val = lrint((x + 5 + _xpos)/_xmag - 480);
if (val < 0)
val = 0;
return Pos(_score->tempomap(), _score->sigmap(), val, _timeType);
}
//---------------------------------------------------------
// pos2pix
//---------------------------------------------------------
int Ruler::pos2pix(const Pos& p) const
{
// return lrint((p.time(_timeType) + 480) * _xmag) - _xpos - 5;
return lrint((p.time(_timeType) + 480) * _xmag) - _xpos - 1;
}
//---------------------------------------------------------
// paintEvent
//---------------------------------------------------------
void Ruler::paintEvent(QPaintEvent* e)
{
QPainter p(this);
const QRect& r = e->rect();
static const int mag[7] = {
1, 1, 2, 5, 10, 20, 50
};
int x = r.x();
int w = r.width();
int y = rulerHeight - 16;
int h = 16; // 14;
int y1 = r.y();
int rh = r.height();
if (y1 < rulerHeight) {
rh -= rulerHeight - y1;
y1 = rulerHeight;
}
int y2 = y1 + rh;
if (x < (-_xpos))
x = -_xpos;
if (!_score)
return;
Pos pos1 = pix2pos(x);
Pos pos2 = pix2pos(x+w);
//---------------------------------------------------
// draw raster
//---------------------------------------------------
int bar1, bar2, beat, tick;
pos1.mbt(&bar1, &beat, &tick);
pos2.mbt(&bar2, &beat, &tick);
int n = mag[magStep];
bar1 = (bar1 / n) * n; // round down
if (bar1 && n >= 2)
bar1 -= 1;
bar2 = ((bar2 + n - 1) / n) * n; // round up
for (int bar = bar1; bar <= bar2;) {
Pos stick(_score->tempomap(), _score->sigmap(), bar, 0, 0);
if (magStep) {
p.setFont(_font2);
int x = pos2pix(stick);
QString s;
s.setNum(bar + 1);
p.setPen(Qt::black);
p.drawLine(x, y, x, y + h);
QRect r = QRect(x+2, y, 1000, h);
p.drawText(r, Qt::AlignLeft | Qt::AlignVCenter, s);
p.setPen(Qt::lightGray);
if (x > 0)
p.drawLine(x, y1, x, y2);
}
else {
SigEvent sig = stick.timesig();
int z = sig.timesig().numerator();
for (int beat = 0; beat < z; beat++) {
Pos xx(_score->tempomap(), _score->sigmap(), bar, beat, 0);
int xp = pos2pix(xx);
if (xp < 0)
continue;
QString s;
QRect r(xp+2, y + 1, 1000, h);
int y3;
int num;
if (beat == 0) {
num = bar + 1;
y3 = y + 2;
p.setFont(_font2);
}
else {
num = beat + 1;
y3 = y + 8;
p.setFont(_font1);
r.moveTop(r.top() + 1);
}
s.setNum(num);
p.setPen(Qt::black);
p.drawLine(xp, y3, xp, y+h);
p.drawText(r, Qt::AlignLeft | Qt::AlignVCenter, s);
p.setPen(beat == 0 ? Qt::lightGray : Qt::gray);
if (xp > 0)
p.drawLine(xp, y1, xp, y2);
}
}
if (bar == 0 && n >= 2)
bar += (n-1);
else
bar += n;
}
//
// draw mouse cursor marker
//
p.setPen(Qt::black);
if (_cursor.valid()) {
int xp = pos2pix(_cursor);
if (xp >= x && xp < x+w)
p.drawLine(xp, 0, xp, rulerHeight);
}
static const QColor lcColors[3] = { Qt::red, Qt::blue, Qt::blue };
for (int i = 0; i < 3; ++i) {
if (!_locator[i].valid())
continue;
p.setPen(lcColors[i]);
int xp = pos2pix(_locator[i]);
QPixmap* pm = markIcon[i];
// int pw = (pm->width() + 1) / 2;
int pw = pm->width() / 2;
int x1 = x - pw;
int x2 = x + w + pw;
if (xp >= x1 && xp < x2)
p.drawPixmap(xp - pw, y-2, *pm);
}
}
//---------------------------------------------------------
// mousePressEvent
//---------------------------------------------------------
void Ruler::mousePressEvent(QMouseEvent* e)
{
moveLocator(e);
}
//---------------------------------------------------------
// mouseMoveEvent
//---------------------------------------------------------
void Ruler::mouseMoveEvent(QMouseEvent* e)
{
moveLocator(e);
}
//---------------------------------------------------------
// moveLocator
//---------------------------------------------------------
void Ruler::moveLocator(QMouseEvent* e)
{
Pos pos(pix2pos(e->pos().x()));
if (e->buttons() & Qt::LeftButton)
emit locatorMoved(0, pos);
else if (e->buttons() & Qt::MidButton)
emit locatorMoved(1, pos);
else if (e->buttons() & Qt::RightButton)
emit locatorMoved(2, pos);
}
//---------------------------------------------------------
// leaveEvent
//---------------------------------------------------------
void Ruler::leaveEvent(QEvent*)
{
_cursor.setInvalid();
emit posChanged(_cursor);
update();
}
//---------------------------------------------------------
// setPos
//---------------------------------------------------------
void Ruler::setPos(const Pos& pos)
{
if (_cursor != pos) {
int x1 = pos2pix(_cursor);
int x2 = pos2pix(pos);
if (x1 > x2) {
int tmp = x2;
x2 = x1;
x1 = tmp;
}
update(QRect(x1-1, 0, x2-x1+2, height()));
_cursor = pos;
}
}
}