//========================================================= // MusE // Linux Music Editor // $Id: mtscale.cpp,v 1.8.2.7 2009/05/03 04:14:01 terminator356 Exp $ // (C) Copyright 1999 Werner Schweer (ws@seh.de) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; version 2 of // the License, or (at your option) any later version. // // 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //========================================================= #include #include #include #include "mtscale.h" #include "song.h" #include "app.h" #include "icons.h" #include "gconfig.h" namespace MusEGui { //--------------------------------------------------------- // MTScale // Midi Time Scale //--------------------------------------------------------- MTScale::MTScale(int* r, QWidget* parent, int xs, bool _mode) : View(parent, xs, 1) { waveMode = _mode; setToolTip(tr("bar scale")); barLocator = false; raster = r; if (waveMode) { pos[0] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->cpos()); pos[1] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->lpos()); pos[2] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->rpos()); } else { pos[0] = MusEGlobal::song->cpos(); pos[1] = MusEGlobal::song->lpos(); pos[2] = MusEGlobal::song->rpos(); } pos[3] = INT_MAX; // do not show button = Qt::NoButton; setMouseTracking(true); connect(MusEGlobal::song, SIGNAL(posChanged(int, unsigned, bool)), SLOT(setPos(int, unsigned, bool))); connect(MusEGlobal::song, SIGNAL(songChanged(MusECore::SongChangedFlags_t)), SLOT(songChanged(MusECore::SongChangedFlags_t))); connect(MusEGlobal::song, SIGNAL(markerChanged(int)), SLOT(redraw())); connect(MusEGlobal::muse, SIGNAL(configChanged()), SLOT(configChanged())); setFixedHeight(28); setBg(MusEGlobal::config.rulerBg); //setBg(QColor(0xe0, 0xe0, 0xe0)); } void MTScale::configChanged() { setBg(MusEGlobal::config.rulerBg); } //--------------------------------------------------------- // songChanged //--------------------------------------------------------- void MTScale::songChanged(MusECore::SongChangedFlags_t type) { if (type & (SC_SIG|SC_TEMPO)) { if ((type & SC_TEMPO) && waveMode) { pos[0] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->cpos()); pos[1] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->lpos()); pos[2] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->rpos()); } redraw(); } } //--------------------------------------------------------- // setPos //--------------------------------------------------------- void MTScale::setPos(int idx, unsigned val, bool) { if (val == INT_MAX) { if (idx == 3) { pos[3] = INT_MAX; redraw(QRect(0, 0, width(), height())); } return; } if (waveMode) val = MusEGlobal::tempomap.tick2frame(val); if (val == pos[idx]) return; //unsigned opos = mapx(pos[idx] == INT_MAX ? val : pos[idx]); int opos = mapx(pos[idx] == INT_MAX ? val : pos[idx]); pos[idx] = val; if (!isVisible()) return; int tval = mapx(val); int x = -9; int w = 18; if (tval < 0) { // tval<0 occurs whenever the window is scrolled left, so I switched to signed int (ml) //printf("MTScale::setPos - idx:%d val:%d tval:%d opos:%d w:%d h:%d\n", idx, val, tval, opos, width(), height()); redraw(QRect(0,0,width(),height())); return; } //if (opos > (unsigned int) tval) { //prevent compiler warning: comparison signed/unsigned if (opos > tval) { w += opos - tval; x += tval; } else { w += tval - opos; x += opos; } //printf("MTScale::setPos idx:%d val:%d tval:%d opos:%d x:%d w:%d h:%d\n", idx, val, tval, opos, x, w, height()); redraw(QRect(x, 0, w, height())); } //--------------------------------------------------------- // viewMousePressEvent //--------------------------------------------------------- void MTScale::viewMousePressEvent(QMouseEvent* event) { button = event->button(); viewMouseMoveEvent(event); } //--------------------------------------------------------- // viewMouseReleaseEvent //--------------------------------------------------------- void MTScale::viewMouseReleaseEvent(QMouseEvent*) { button = Qt::NoButton; } //--------------------------------------------------------- // viewMouseMoveEvent //--------------------------------------------------------- void MTScale::viewMouseMoveEvent(QMouseEvent* event) { if (event->modifiers() & Qt::ShiftModifier ) setCursor(QCursor(Qt::PointingHandCursor)); else setCursor(QCursor(Qt::ArrowCursor)); int x = event->x(); if (waveMode) x = MusEGlobal::tempomap.frame2tick(x); x = AL::sigmap.raster(x, *raster); if (x < 0) x = 0; //printf("MTScale::viewMouseMoveEvent\n"); emit timeChanged(x); int i; switch (button) { case Qt::LeftButton: i = 0; break; case Qt::MidButton: i = 1; break; case Qt::RightButton: if ((MusEGlobal::config.rangeMarkerWithoutMMB) && (event->modifiers() & Qt::ControlModifier)) i = 1; else i = 2; break; default: return; // if no button is pressed the function returns here } MusECore::Pos p(x, true); if(i== 0 && (event->modifiers() & Qt::ShiftModifier )) { // If shift +LMB we add a marker MusECore::Marker *alreadyExists = MusEGlobal::song->getMarkerAt(x); if (!alreadyExists) { MusEGlobal::song->addMarker(QString(""), x, false); // Removed p3.3.43 // Song::addMarker() already emits a 'markerChanged'. //emit addMarker(x); } } else if (i== 2 && (event->modifiers() & Qt::ShiftModifier )) { // If shift +RMB we remove a marker MusECore::Marker *toRemove = MusEGlobal::song->getMarkerAt(x); if (toRemove) MusEGlobal::song->removeMarker(toRemove); else printf("No marker to remove\n"); } else MusEGlobal::song->setPos(i, p); // all other cases: relocating one of the locators } //--------------------------------------------------------- // leaveEvent //--------------------------------------------------------- void MTScale::leaveEvent(QEvent*) { emit timeChanged(INT_MAX); } //--------------------------------------------------------- // draw //--------------------------------------------------------- void MTScale::pdraw(QPainter& p, const QRect& r) { int x = r.x(); int w = r.width(); // Added by Tim. p3.3.6 //printf("MTScale::pdraw x:%d w:%d\n", x, w); x -= 20; w += 40; // wg. Text //--------------------------------------------------- // draw Marker //--------------------------------------------------- int y = 12; p.setPen(MusEGlobal::config.rulerFg); p.setFont(MusEGlobal::config.fonts[5]); p.drawLine(r.x(), y+1, r.x() + r.width(), y+1); QRect tr(r); tr.setHeight(12); MusECore::MarkerList* marker = MusEGlobal::song->marker(); for (MusECore::iMarker m = marker->begin(); m != marker->end(); ++m) { int xp; if(waveMode) xp = mapx(m->second.frame()); else xp = mapx(m->second.tick()); if (xp > x+w) break; int xe = r.x() + r.width(); MusECore::iMarker mm = m; ++mm; if (mm != marker->end()) { if(waveMode) xe = mapx(MusEGlobal::tempomap.tick2frame(mm->first)); else xe = mapx(mm->first); } QRect tr(xp, 0, xe-xp, 13); //if (m->second.current()) // p.fillRect(tr, white); QRect wr = r.intersect(tr); //if (r.intersects(tr)) if(!wr.isEmpty()) { if (m->second.current()) { p.fillRect(tr, Qt::white); } int x2; //MusECore::iMarker mm = m; //++mm; if (mm != marker->end()) { if(waveMode) x2 = mapx(MusEGlobal::tempomap.tick2frame(mm->first)); else x2 = mapx(mm->first); } else x2 = xp+200; //printf("MTScale::pdraw marker %s xp:%d y:%d h:%d r.x:%d r.w:%d\n", m->second.name().toLatin1(), xp, height(), y, r.x(), r.width()); // Must be reasonable about very low negative x values! With long songs > 15min // and with high horizontal magnification, 'ghost' drawings appeared, // apparently the result of truncation later (xp = -65006 caused ghosting // at bar 245 with magnification at max.), even with correct clipping region // applied to painter in View::paint(). Tim. Apr 5 2009 // Quote: "Warning: Note that QPainter does not attempt to work around // coordinate limitations in the underlying window system. Some platforms may // behave incorrectly with coordinates as small as +/-4000." if(xp >= -32) p.drawPixmap(xp, 0, *flagIconS); if(xp >= -1023) { QRect r = QRect(xp+10, 0, x2-xp, 12); p.setPen(MusEGlobal::config.rulerFg); p.drawText(r, Qt::AlignLeft|Qt::AlignVCenter, m->second.name()); } if(xp >= 0) { p.setPen(Qt::green); p.drawLine(xp, y, xp, height()); } } } //--------------------------------------------------- // draw location marker //--------------------------------------------------- int h = height()-12; if (barLocator) { p.setPen(Qt::red); int xp = mapx(pos[0]); if (xp >= x && xp < x+w) p.drawLine(xp, y, xp, h); p.setPen(Qt::blue); xp = mapx(pos[1]); if (xp >= x && xp < x+w) p.drawLine(xp, y, xp, h); xp = mapx(pos[2]); if (xp >= x && xp < x+w) p.drawLine(xp, y, xp, h); } else { for (int i = 0; i < 3; ++i) { int xp = mapx(pos[i]); if (xp >= x && xp < x+w) { QPixmap* pm = markIcon[i]; p.drawPixmap(xp - pm->width()/2, y-1, *pm); } } } p.setPen(MusEGlobal::config.rulerFg); if (pos[3] != INT_MAX) { int xp = mapx(pos[3]); if (xp >= x && xp < x+w) p.drawLine(xp, 0, xp, height()); } unsigned ctick; int bar1, bar2, beat; unsigned tick; if (waveMode) { ctick = MusEGlobal::tempomap.frame2tick(mapxDev(x)); AL::sigmap.tickValues(ctick, &bar1, &beat, &tick); AL::sigmap.tickValues(MusEGlobal::tempomap.frame2tick(mapxDev(x+w)), &bar2, &beat, &tick); } else { ctick = mapxDev(x); AL::sigmap.tickValues(ctick, &bar1, &beat, &tick); AL::sigmap.tickValues(mapxDev(x+w), &bar2, &beat, &tick); } //printf("bar %d %d-%d=%d\n", bar, ntick, stick, ntick-stick); int stick = AL::sigmap.bar2tick(bar1, 0, 0); int ntick; for (int bar = bar1; bar <= bar2; bar++, stick = ntick) { ntick = AL::sigmap.bar2tick(bar+1, 0, 0); int tpix, a, b=0; if (waveMode) { a = MusEGlobal::tempomap.tick2frame(ntick); b = MusEGlobal::tempomap.tick2frame(stick); tpix = rmapx(a - b); } else { tpix = rmapx(ntick - stick); } if (tpix < 64) { // don�t show beats if measure is this small int n = 1; if (tpix < 32) n = 2; if (tpix <= 16) n = 4; if (tpix < 8) n = 8; if (tpix <= 4) n = 16; if (tpix <= 2) n = 32; if (bar % n) continue; p.setFont(MusEGlobal::config.fonts[3]); int x = mapx(waveMode ? b : stick); QString s; s.setNum(bar + 1); p.drawLine(x, y+1, x, y+1+h); // QRect r = QRect(x+2, y, 0, h); QRect r = QRect(x+2, y, 1000, h); p.drawText(r, Qt::AlignLeft|Qt::AlignVCenter|Qt::TextDontClip, s); } else { int z, n; AL::sigmap.timesig(stick, z, n); for (int beat = 0; beat < z; beat++) { int xx = AL::sigmap.bar2tick(bar, beat, 0); if (waveMode) xx = MusEGlobal::tempomap.tick2frame(xx); int xp = mapx(xx); QString s; QRect r(xp+2, y, 1000, h); int y1; int num; if (beat == 0) { num = bar + 1; y1 = y + 1; p.setFont(MusEGlobal::config.fonts[3]); } else { num = beat + 1; y1 = y + 7; p.setFont(MusEGlobal::config.fonts[4]); r.setY(y+3); } s.setNum(num); p.drawLine(xp, y1, xp, y+1+h); p.drawText(r, Qt::AlignLeft|Qt::AlignVCenter|Qt::TextDontClip, s); } } } } } // namespace MusEGui