Logo Search packages:      
Sourcecode: rosegarden version File versions  Download package

temporuler.cpp

// -*- c-basic-offset: 4 -*-

/*
    Rosegarden-4
    A sequencer and musical notation editor.

    This program is Copyright 2000-2006
        Guillaume Laurent   <glaurent@telegraph-road.org>,
        Chris Cannam        <cannam@all-day-breakfast.com>,
        Richard Bown        <bownie@bownie.com>

    The moral right of the authors to claim authorship of this work
    has been asserted.

    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; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#include <qpainter.h>
#include <qtooltip.h>
#include <qpopupmenu.h>
#include <qpixmap.h>
#include <qiconset.h>

#include <klocale.h>
#include <kaction.h>
#include <kglobal.h>
#include <kstddirs.h>
#include <kmainwindow.h>

#include "temporuler.h"
#include "colours.h"
#include "rosestrings.h"
#include "rosedebug.h"
#include "rosegardenguidoc.h"
#include "Composition.h"
#include "RulerScale.h"
#include "SnapGrid.h"

#include "tempocolour.h"
#include "widgets.h"

using Rosegarden::RulerScale;
using Rosegarden::Composition;
using Rosegarden::timeT;
using Rosegarden::tempoT;
using Rosegarden::RealTime;
using Rosegarden::SnapGrid;

00053 TempoRuler::TempoRuler(RulerScale *rulerScale,
                   RosegardenGUIDoc *doc,
                   KXMLGUIFactory *factory,
                   double xorigin,
                   int height,
                   bool small,
                   QWidget *parent,
                   const char *name) :
    QWidget(parent, name),
    m_xorigin(xorigin),
    m_height(height),
    m_currentXOffset(0),
    m_width(-1),
    m_small(small),
    m_illuminate(-1),
    m_illuminatePoint(false),
    m_illuminateTarget(false),
    m_refreshLinesOnly(false),
    m_dragVert(false),
    m_dragTarget(false),
    m_dragHoriz(false),
    m_dragStartY(0),
    m_dragStartX(0),
    m_dragFine(false),
    m_clickX(0),
    m_dragStartTempo(-1),
    m_dragStartTarget(-1),
    m_dragOriginalTempo(-1),
    m_dragOriginalTarget(-1),
    m_composition(&doc->getComposition()),
    m_rulerScale(rulerScale),
    m_menu(0),
    m_factory(0),
    m_fontMetrics(m_boldFont)
{
//    m_font.setPointSize(m_small ? 9 : 11);
//    m_boldFont.setPointSize(m_small ? 9 : 11);

//    m_font.setPixelSize(m_height * 2 / 3);
//    m_boldFont.setPixelSize(m_height * 2 / 3);

    m_font.setPixelSize(m_height / 3);
    m_boldFont.setPixelSize(m_height * 2 / 5);
    m_boldFont.setBold(true);
    m_fontMetrics = QFontMetrics(m_boldFont);

    m_textFloat = new RosegardenTextFloat(this);
    m_textFloat->hide();

//    setBackgroundColor(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::TextRulerBackground));
    setBackgroundMode(Qt::NoBackground);

    QObject::connect
      (doc->getCommandHistory(), SIGNAL(commandExecuted()),
       this, SLOT(update()));

    m_menu = new QPopupMenu;
    
    QString pixmapDir = KGlobal::dirs()->findResource("appdata", "pixmaps/");
    QIconSet icon;

    icon = QIconSet(QPixmap(pixmapDir + "/toolbar/event-insert-tempo.png"));
    (new KAction(i18n("Insert Tempo Change"), icon, 0, this,
             SLOT(slotInsertTempoHere()), actionCollection(),
             "insert_tempo_here"))->plug(m_menu);

    (new KAction(i18n("Insert Tempo Change at Playback Position"), 0, 0, this,
             SLOT(slotInsertTempoAtPointer()), actionCollection(),
             "insert_tempo_at_pointer"))->plug(m_menu);

    m_menu->insertSeparator();

    icon = QIconSet(QPixmap(pixmapDir + "/toolbar/event-delete.png"));
    (new KAction(i18n("Delete Tempo Change"), icon, 0, this,
             SLOT(slotDeleteTempoChange()), actionCollection(),
             "delete_tempo"))->plug(m_menu);

    m_menu->insertSeparator();

    (new KAction(i18n("Ramp Tempo to Next Tempo"), 0, 0, this,
             SLOT(slotRampToNext()), actionCollection(),
             "ramp_to_next"))->plug(m_menu);

    (new KAction(i18n("Un-Ramp Tempo"), 0, 0, this,
             SLOT(slotUnramp()), actionCollection(),
             "unramp"))->plug(m_menu);

    m_menu->insertSeparator();

    icon = QIconSet(QPixmap(pixmapDir + "/toolbar/event-edit.png"));
    (new KAction(i18n("Edit Tempo..."), icon, 0, this,
             SLOT(slotEditTempo()), actionCollection(),
             "edit_tempo"))->plug(m_menu);

    (new KAction(i18n("Edit Time Signature..."), 0, 0, this,
             SLOT(slotEditTimeSignature()), actionCollection(),
             "edit_time_signature"))->plug(m_menu);

    (new KAction(i18n("Open Tempo and Time Signature Editor"), 0, 0, this,
             SLOT(slotEditTempos()), actionCollection(),
             "edit_tempos"))->plug(m_menu);

    setMouseTracking(false);
}

TempoRuler::~TempoRuler()
{
    delete m_menu;
}

void
TempoRuler::connectSignals()
{
    connect(this,
          SIGNAL(doubleClicked(Rosegarden::timeT)),
          RosegardenGUIApp::self(),
          SLOT(slotEditTempos(Rosegarden::timeT)));
    
    connect(this,
            SIGNAL(changeTempo(Rosegarden::timeT,
                               Rosegarden::tempoT,
                               Rosegarden::tempoT,
                         TempoDialog::TempoDialogAction)),
          RosegardenGUIApp::self(),
            SLOT(slotChangeTempo(Rosegarden::timeT,
                                 Rosegarden::tempoT,
                                 Rosegarden::tempoT,
                         TempoDialog::TempoDialogAction)));

    connect(this,
            SIGNAL(moveTempo(Rosegarden::timeT,
                       Rosegarden::timeT)),
          RosegardenGUIApp::self(),
            SLOT(slotMoveTempo(Rosegarden::timeT,
                         Rosegarden::timeT)));

    connect(this,
          SIGNAL(editTempo(Rosegarden::timeT)),
          RosegardenGUIApp::self(),
          SLOT(slotEditTempo(Rosegarden::timeT)));

    connect(this,
          SIGNAL(editTimeSignature(Rosegarden::timeT)),
          RosegardenGUIApp::self(),
          SLOT(slotEditTimeSignature(Rosegarden::timeT)));

    connect(this,
          SIGNAL(editTempos(Rosegarden::timeT)),
          RosegardenGUIApp::self(),
          SLOT(slotEditTempos(Rosegarden::timeT)));
}

void
TempoRuler::slotScrollHoriz(int x)
{
    int w = width(), h = height();
    int dx = x - (-m_currentXOffset);
    m_currentXOffset = -x;

    if (dx > w*3/4 || dx < -w*3/4) {
      update();
      return;
    }

    if (dx > 0) { // moving right, so the existing stuff moves left
      bitBlt(this, 0, 0, this, dx, 0, w-dx, h);
      repaint(w-dx, 0, dx, h);
    } else {      // moving left, so the existing stuff moves right
      bitBlt(this, -dx, 0, this, 0, 0, w+dx, h);
      repaint(0, 0, -dx, h);
    }
}


void
TempoRuler::mousePressEvent(QMouseEvent *e)
{
    if (e->button() == LeftButton) {

      if (e->type() == QEvent::MouseButtonDblClick) {
          timeT t = m_rulerScale->getTimeForX
            (e->x() - m_currentXOffset - m_xorigin);
          emit doubleClicked(t);
          return;
      }

      int x = e->x() + 1;
      int y = e->y();
      timeT t = m_rulerScale->getTimeForX(x - m_currentXOffset - m_xorigin);
      int tcn = m_composition->getTempoChangeNumberAt(t);

      if (tcn < 0 || tcn >= m_composition->getTempoChangeCount()) return;

      std::pair<timeT, tempoT> tc = m_composition->getTempoChange(tcn);
      std::pair<bool, tempoT> tr = m_composition->getTempoRamping(tcn, true);

      m_dragStartY = y;
      m_dragStartX = x;
      m_dragStartTime = tc.first;
      m_dragPreviousTime = m_dragStartTime;
      m_dragStartTempo = tc.second;
      m_dragStartTarget = tr.first ? tr.second : -1;
      m_dragOriginalTempo = m_dragStartTempo;
      m_dragOriginalTarget = m_dragStartTarget;
      m_dragFine = ((e->state() & Qt::ShiftButton) != 0);

      int px = m_rulerScale->getXForTime(tc.first) + m_currentXOffset + m_xorigin;
      if (x >= px && x < px + 5) {
          m_dragHoriz = true;
          m_dragVert = false;
          setCursor(Qt::SplitHCursor);
      } else {
          timeT nt = m_composition->getEndMarker();
          if (tcn < m_composition->getTempoChangeCount() - 1) {
            nt = m_composition->getTempoChange(tcn + 1).first;
          }
          int nx = m_rulerScale->getXForTime(nt) + m_currentXOffset + m_xorigin;
          if (x > px + 5 && x > nx - 5) {
            m_dragTarget = true;
            setCursor(Qt::SizeVerCursor);
          } else {
            m_dragTarget = false;
            setCursor(Qt::SplitVCursor);
          }
          m_dragVert = true;
          m_dragHoriz = false;
      }

    } else if (e->button() == RightButton) {

      m_clickX = e->x();
      if (m_menu) m_menu->exec(QCursor::pos());

    }
}

void
TempoRuler::mouseReleaseEvent(QMouseEvent *e)
{
    if (m_dragVert) {

      m_dragVert = false;
      unsetCursor();

      if (e->x() < 0 || e->x() >= width() ||
          e->y() < 0 || e->y() >= height()) {
          leaveEvent(0);
      }

      // First we make a note of the values that we just set and
      // restore the tempo to whatever it was previously, so that
      // the undo for any following command will work correctly.
      // Then we emit so that our user can issue the right command.
      
      int tcn = m_composition->getTempoChangeNumberAt(m_dragStartTime);
      std::pair<timeT, tempoT> tc = m_composition->getTempoChange(tcn);
      std::pair<bool, tempoT> tr = m_composition->getTempoRamping(tcn, true);

      if (tc.second != m_dragOriginalTempo) {
          m_composition->addTempoAtTime(m_dragStartTime,
                                m_dragOriginalTempo,
                                m_dragOriginalTarget);
          emit changeTempo(m_dragStartTime, tc.second,
                       tr.first ? tr.second : -1,
                       TempoDialog::AddTempo);
      }

      return;

    } else if (m_dragHoriz) {

      m_dragHoriz = false;
      unsetCursor();

      if (e->x() < 0 || e->x() >= width() ||
          e->y() < 0 || e->y() >= height()) {
          leaveEvent(0);
      }

      if (m_dragPreviousTime != m_dragStartTime) {

          // As above, restore the original tempo and then emit a
          // signal to ensure a proper command happens.

          int tcn = m_composition->getTempoChangeNumberAt(m_dragPreviousTime);
          m_composition->removeTempoChange(tcn);
          m_composition->addTempoAtTime(m_dragStartTime,
                                m_dragStartTempo,
                                m_dragStartTarget);

          emit moveTempo(m_dragStartTime, m_dragPreviousTime);
      }

      return;
    } 
}

void
00351 TempoRuler::mouseMoveEvent(QMouseEvent *e)
{
    bool shiftPressed = ((e->state() & Qt::ShiftButton) != 0);

    if (m_dragVert) {

      if (shiftPressed != m_dragFine) {

          m_dragFine = shiftPressed;
          m_dragStartY = e->y();

          // reset the start tempi to whatever we last updated them
          // to as we switch into or out of fine mode
          int tcn = m_composition->getTempoChangeNumberAt(m_dragStartTime);
          std::pair<timeT, tempoT> tc = m_composition->getTempoChange(tcn);
          std::pair<bool, tempoT> tr = m_composition->getTempoRamping(tcn, true);
          m_dragStartTempo = tc.second;
          m_dragStartTarget = tr.first ? tr.second : -1;
      }

      int diff = m_dragStartY - e->y(); // +ve for upwards drag
      tempoT newTempo = m_dragStartTempo;
      tempoT newTarget = m_dragStartTarget;

      if (diff != 0) {

          float qpm = m_composition->getTempoQpm(newTempo);

          if (m_dragTarget && newTarget > 0) {
            qpm = m_composition->getTempoQpm(newTarget);
          }

          float qdiff = (m_dragFine ? diff * 0.05 : diff * 0.5);
          qpm += qdiff;
          if (qpm < 1) qpm = 1;

          if (m_dragTarget) {

            newTarget = m_composition->getTempoForQpm(qpm);

          } else {

            newTempo = m_composition->getTempoForQpm(qpm);

            if (newTarget >= 0) {
                qpm = m_composition->getTempoQpm(newTarget);
                qpm += qdiff;
                if (qpm < 1) qpm = 1;
                newTarget = m_composition->getTempoForQpm(qpm);
            }
          }
      }

      showTextFloat(newTempo, newTarget, m_dragStartTime);
      m_composition->addTempoAtTime(m_dragStartTime, newTempo, newTarget);
      update();

    } else if (m_dragHoriz) {

      int x = e->x();

      SnapGrid grid(m_rulerScale);
      if (shiftPressed) {
          grid.setSnapTime(SnapGrid::NoSnap);
      } else {
          grid.setSnapTime(SnapGrid::SnapToUnit);
      }
      timeT newTime = grid.snapX(x - m_currentXOffset - m_xorigin,
                           SnapGrid::SnapEither);

      int tcn = m_composition->getTempoChangeNumberAt(m_dragPreviousTime);
      int ncn = m_composition->getTempoChangeNumberAt(newTime);
      if (ncn > tcn || ncn < tcn - 1) return;
      if (ncn >= 0 && ncn == tcn - 1) {
          std::pair<timeT, tempoT> nc = m_composition->getTempoChange(ncn);
          if (nc.first == newTime) return;
      }

//    std::cerr << " -> " << newTime << std::endl;

      m_composition->removeTempoChange(tcn);
      m_composition->addTempoAtTime(newTime,
                              m_dragStartTempo,
                              m_dragStartTarget);
      showTextFloat(m_dragStartTempo, m_dragStartTarget, newTime, true);
      m_dragPreviousTime = newTime;
      update();

    } else {
      
      int x = e->x() + 1;
      timeT t = m_rulerScale->getTimeForX(x - m_currentXOffset - m_xorigin);
      int tcn = m_composition->getTempoChangeNumberAt(t);

      if (tcn < 0 || tcn >= m_composition->getTempoChangeCount()) return;

      std::pair<timeT, tempoT> tc = m_composition->getTempoChange(tcn);
      std::pair<bool, tempoT> tr = m_composition->getTempoRamping(tcn, true);

      int bar, beat, fraction, remainder;
      m_composition->getMusicalTimeForAbsoluteTime(tc.first, bar, beat,
                                         fraction, remainder);
      RG_DEBUG << "Tempo change: tempo " << m_composition->getTempoQpm(tc.second) << " at " << bar << ":" << beat << ":" << fraction << ":" << remainder << endl;

      m_illuminate = tcn;
      m_illuminatePoint = false;
      m_illuminateTarget = false;
//!!! m_refreshLinesOnly = true;

      //!!! merge this test with the one in mousePressEvent as
      //isCloseToStart or equiv, and likewise for close to end

      int px = m_rulerScale->getXForTime(tc.first) + m_currentXOffset + m_xorigin;
      if (x >= px && x < px + 5) {
          m_illuminatePoint = true;
      } else {
          timeT nt = m_composition->getEndMarker();
          if (tcn < m_composition->getTempoChangeCount() - 1) {
            nt = m_composition->getTempoChange(tcn + 1).first;
          }
          int nx = m_rulerScale->getXForTime(nt) + m_currentXOffset + m_xorigin;
          if (x > px + 5 && x > nx - 5) {
            m_illuminateTarget = true;
          }

//        std::cerr << "nt = " << nt << ", nx = " << nx << ", x = " << x << ", m_illuminateTarget = " << m_illuminateTarget << std::endl;
      }

      showTextFloat(tc.second, tr.first ? tr.second : -1,
                  tc.first, m_illuminatePoint);

      update();
    }
}

void
TempoRuler::wheelEvent(QWheelEvent *e)
{
}

void
TempoRuler::enterEvent(QEvent *)
{
    setMouseTracking(true);
}    

void
00498 TempoRuler::leaveEvent(QEvent *)
{
    if (!m_dragVert && !m_dragHoriz) {
      setMouseTracking(false);
      m_illuminate = -1;
      m_illuminatePoint = false;
//!!! m_refreshLinesOnly = true;
      m_textFloat->hide();
      update();
    }
}    

void
TempoRuler::showTextFloat(tempoT tempo, tempoT target,
                    timeT time, bool showTime)
{
    float qpm = m_composition->getTempoQpm(tempo);
    int qi = int(qpm + 0.0001);
    int q0 = int(qpm * 10 + 0.0001) % 10;
    int q00 = int(qpm * 100 + 0.0001) % 10;

    bool haveSet = false;

    QString tempoText, timeText;

    if (time >= 0) {

      if (showTime) {
          int bar, beat, fraction, remainder;
          m_composition->getMusicalTimeForAbsoluteTime
            (time, bar, beat, fraction, remainder);
          RealTime rt = m_composition->getElapsedRealTime(time);

          // blargh -- duplicated with TempoView::makeTimeString
          timeText = QString("%1%2%3-%4%5-%6%7-%8%9")
            .arg(bar/100)
            .arg((bar%100)/10)
            .arg(bar%10)
            .arg(beat/10)
            .arg(beat%10)
            .arg(fraction/10)
            .arg(fraction%10)
            .arg(remainder/10)
            .arg(remainder%10);
          
          timeText = QString("%1\n%2")
            .arg(timeText)
//          .arg(rt.toString().c_str());
            .arg(rt.toText(true).c_str());
      }

      Rosegarden::TimeSignature sig =
          m_composition->getTimeSignatureAt(time);

      if (sig.getBeatDuration() != 
          Rosegarden::Note(Rosegarden::Note::Crotchet).getDuration()) {

          float bpm =
            (qpm *
             Rosegarden::Note(Rosegarden::Note::Crotchet).getDuration())
            / sig.getBeatDuration();
          int bi = int(bpm + 0.0001);
          int b0 = int(bpm * 10 + 0.0001) % 10;
          int b00 = int(bpm * 100 + 0.0001) % 10;

          tempoText = i18n("%1.%2%3 (%4.%5%6 bpm)")
            .arg(qi).arg(q0).arg(q00)
            .arg(bi).arg(b0).arg(b00);
          haveSet = true;
      }
    }

    if (!haveSet) {
      tempoText = i18n("%1.%2%3 bpm").arg(qi).arg(q0).arg(q00);
    }

    if (target > 0 && target != tempo) {
      float tq = m_composition->getTempoQpm(target);
      int tqi = int(tq + 0.0001);
      int tq0 = int(tq * 10 + 0.0001) % 10;
      int tq00 = int(tq * 100 + 0.0001) % 10;
      tempoText = i18n("%1 - %2.%3%4").arg(tempoText).arg(tqi).arg(tq0).arg(tq00);
    }

    if (showTime && time >= 0) {
      m_textFloat->setText(QString("%1\n%2").arg(timeText).arg(tempoText));
    } else {
      m_textFloat->setText(tempoText);
    }

    QPoint cp = mapFromGlobal(QPoint(QCursor::pos()));
//    std::cerr << "cp = " << cp.x() << "," << cp.y() << ", tempo = " << qpm << std::endl;
    QPoint mp = cp + pos();

    QWidget *parent = parentWidget();
    while (parent->parentWidget() &&
         !parent->isTopLevel() &&
         !parent->isDialog()) { 
      mp += parent->pos();
      parent = parent->parentWidget();
    }

    int yoff = cp.y() + m_textFloat->height() + 3;
    mp = QPoint(mp.x() + 10, mp.y() > yoff ? mp.y() - yoff : 0);

    m_textFloat->move(mp);
    m_textFloat->show();
}

QSize
TempoRuler::sizeHint() const
{
    double width =
      m_rulerScale->getBarPosition(m_rulerScale->getLastVisibleBar()) +
      m_rulerScale->getBarWidth(m_rulerScale->getLastVisibleBar()) +
      m_xorigin;

    QSize res(std::max(int(width), m_width), m_height);

    return res;
}

QSize
TempoRuler::minimumSizeHint() const
{
    double firstBarWidth = m_rulerScale->getBarWidth(0) + m_xorigin;
    QSize res = QSize(int(firstBarWidth), m_height);
    return res;
}

int
TempoRuler::getYForTempo(tempoT tempo)
{
    int drawh = height() - 4;
    int y = drawh / 2;

    tempoT minTempo = m_composition->getMinTempo();
    tempoT maxTempo = m_composition->getMaxTempo();

    if (maxTempo > minTempo) {
      y = drawh - 
          int((double(tempo - minTempo) / double(maxTempo - minTempo))
            * drawh + 0.5);
    }

    return y;
}

tempoT
TempoRuler::getTempoForY(int y)
{
    int drawh = height() - 4;

    tempoT minTempo = m_composition->getMinTempo();
    tempoT maxTempo = m_composition->getMaxTempo();

    tempoT tempo = minTempo;

    if (maxTempo > minTempo) {
      tempo = (maxTempo - minTempo) *
          (double(drawh - y) / double(drawh)) + minTempo + 0.5;
    }

    return tempo;
}    

void
00665 TempoRuler::paintEvent(QPaintEvent* e)
{
    QRect clipRect = e->rect();

    if (m_buffer.width() < width() || m_buffer.height() < height()) {
      m_buffer = QPixmap(width(), height());
    }

    m_buffer.fill(Rosegarden::GUIPalette::getColour
              (Rosegarden::GUIPalette::TextRulerBackground));

    QPainter paint(&m_buffer);
    paint.setPen(Rosegarden::GUIPalette::getColour
             (Rosegarden::GUIPalette::TextRulerForeground));

    paint.setClipRegion(e->region());
    paint.setClipRect(clipRect);

    if (m_xorigin > 0) {
      paint.fillRect(0, 0, m_xorigin, height(), paletteBackgroundColor());
    }

    timeT from = m_rulerScale->getTimeForX
      (clipRect.x() - m_currentXOffset - 100 - m_xorigin);
    timeT   to = m_rulerScale->getTimeForX
      (clipRect.x() + clipRect.width() - m_currentXOffset + 100 - m_xorigin);

    QRect boundsForHeight = m_fontMetrics.boundingRect("019");
    int fontHeight = boundsForHeight.height();
    int textY = fontHeight + 2;

    double prevEndX = -1000.0;
    double prevTempo = 0.0;
    long prevBpm = 0;

    typedef std::map<timeT, int> TimePoints;
    int tempoChangeHere = 1;
    int timeSigChangeHere = 2;
    TimePoints timePoints;

    for (int tempoNo = m_composition->getTempoChangeNumberAt(from);
       tempoNo <= m_composition->getTempoChangeNumberAt(to) + 1; ++tempoNo) {

      if (tempoNo >= 0 && tempoNo < m_composition->getTempoChangeCount()) {
          timePoints.insert
            (TimePoints::value_type
             (m_composition->getTempoChange(tempoNo).first,
              tempoChangeHere));
      }
    }

    for (int sigNo = m_composition->getTimeSignatureNumberAt(from);
       sigNo <= m_composition->getTimeSignatureNumberAt(to) + 1; ++sigNo) {

      if (sigNo >= 0 && sigNo < m_composition->getTimeSignatureCount()) {
          timeT time(m_composition->getTimeSignatureChange(sigNo).first);
          if (timePoints.find(time) != timePoints.end()) {
            timePoints[time] |= timeSigChangeHere;
          } else {
            timePoints.insert(TimePoints::value_type(time, timeSigChangeHere));
          }
      }
    }

    int lastx = 0, lasty = 0, lastx1 = 0;
    bool haveSome = false;
//    tempoT minTempo = m_composition->getMinTempo();
//    tempoT maxTempo = m_composition->getMaxTempo();
    bool illuminate = false;

    if (m_illuminate >= 0) {
      int tcn = m_composition->getTempoChangeNumberAt(from);
      illuminate = (m_illuminate == tcn);
    }

    for (TimePoints::iterator i = timePoints.begin(); ; ++i) {

      timeT t0, t1;

      if (i == timePoints.begin()) {
          t0 = from;
      } else {
          TimePoints::iterator j(i);
          --j;
          t0 = j->first;
      }

      if (i == timePoints.end()) {
          t1 = to;
      } else {
          t1 = i->first;
      }

      if (t1 <= t0) t1 = to;

      int tcn = m_composition->getTempoChangeNumberAt(t0);
      tempoT tempo = m_composition->getTempoAtTime(t0);

      std::pair<bool, tempoT> ramping(false, tempo);
      if (tcn > 0 && tcn < m_composition->getTempoChangeCount() + 1) {
          ramping = m_composition->getTempoRamping(tcn - 1, true);
      }

      double x0, x1;
      x0 = m_rulerScale->getXForTime(t0) + m_currentXOffset + m_xorigin;
      x1 = m_rulerScale->getXForTime(t1) + m_currentXOffset + m_xorigin;
/*!!!
      if (x0 > e->rect().x()) {
          paint.fillRect(e->rect().x(), 0, x0 - e->rect().x(), height(),
                     paletteBackgroundColor());
      }
*/
      QColor colour = TempoColour::getColour(m_composition->getTempoQpm(tempo));
        paint.setPen(colour);
        paint.setBrush(colour);

      if (!m_refreshLinesOnly) {
//        RG_DEBUG << "TempoRuler: draw rect from " << x0 << " to " << x1 << endl;
          paint.drawRect(int(x0), 0, int(x1 - x0) + 1, height());
      }

      int y = getYForTempo(tempo);
/*!!!
      int drawh = height() - 4;
      int y = drawh / 2;
      if (maxTempo > minTempo) {
          y = drawh - 
            int((double(tempo - minTempo) / double(maxTempo - minTempo))
                * drawh + 0.5);
      }
*/
      y += 2;

      if (haveSome) {

          int x = int(x0) + 1;
          int ry = lasty;

          bool illuminateLine = (illuminate &&
                           !m_illuminatePoint && !m_illuminateTarget);

          paint.setPen(illuminateLine ? Qt::white : Qt::black);

          if (ramping.first) {
            ry = getYForTempo(ramping.second);
            ry += 2;
/*!!!
            ry = drawh - 
                int((double(ramping.second - minTempo) /
                   double(maxTempo - minTempo))
                  * drawh + 0.5);
*/
          }

          paint.drawLine(lastx + 1, lasty, x - 2, ry);

          if (!illuminateLine && illuminate && m_illuminateTarget) {
            if (x > lastx) {
                paint.setPen(Qt::white);
                paint.drawLine(x - 6, ry - ((ry - lasty) * 6) / (x - lastx),
                           x - 2, ry);
            }
          }

          if (m_illuminate >= 0) {
            illuminate = (m_illuminate == tcn);
          }

          bool illuminatePoint = (illuminate && m_illuminatePoint);

          paint.setPen(illuminatePoint ? Qt::white : Qt::black);
          paint.drawRect(x - 1, y - 1, 3, 3);

          paint.setPen(illuminatePoint ? Qt::black : Qt::white);
          paint.drawPoint(x, y);
      }

      lastx = int(x0) + 1;
      lastx1 = int(x1) + 1;
      lasty = y;
      if (i == timePoints.end()) break;
      haveSome = true;
    }

    if (lastx1 < e->rect().x() + e->rect().width()) {
/*!!!
      paint.fillRect(lastx1, 0,
                   e->rect().x() + e->rect().width() - lastx1, height(),
                   paletteBackgroundColor());
*/
    }

    if (haveSome) {
      bool illuminateLine = (illuminate && !m_illuminatePoint);
      paint.setPen(illuminateLine ? Qt::white : Qt::black);
      paint.drawLine(lastx + 1, lasty, width(), lasty);
    } else if (!m_refreshLinesOnly) {
      tempoT tempo = m_composition->getTempoAtTime(from);
      QColor colour = TempoColour::getColour(m_composition->getTempoQpm(tempo));
        paint.setPen(colour);
        paint.setBrush(colour);
      paint.drawRect(e->rect());
    }

    paint.setPen(Qt::black);
    paint.setBrush(Qt::black);
    paint.drawLine(0, 0, width(), 0);

    for (TimePoints::iterator i = timePoints.begin();
       i != timePoints.end(); ++i) {

      timeT time = i->first;
      double x = m_rulerScale->getXForTime(time) + m_currentXOffset
                   + m_xorigin;

/*    
      paint.drawLine(static_cast<int>(x),
                   height() - (height()/4),
                   static_cast<int>(x),
                   height());
*/

      if ((i->second & timeSigChangeHere) && !m_refreshLinesOnly) {

          Rosegarden::TimeSignature sig =
            m_composition->getTimeSignatureAt(time);

          QString str = QString("%1/%2")
            .arg(sig.getNumerator())
            .arg(sig.getDenominator());

          paint.setFont(m_boldFont);
          paint.drawText(static_cast<int>(x) + 2, m_height - 2, str);
      }

      if ((i->second & tempoChangeHere) && !m_refreshLinesOnly) { 

          double tempo = m_composition->getTempoQpm(m_composition->getTempoAtTime(time));
          long bpm = long(tempo);
//        long frac = long(tempo * 100 + 0.001) - 100 * bpm;

          QString tempoString = QString("%1").arg(bpm);

          if (tempo == prevTempo) {
            if (m_small) continue;
            tempoString = "=";
          } else if (bpm == prevBpm) {
            tempoString = (tempo > prevTempo ? "+" : "-");
          } else {
            if (m_small && (bpm != (bpm / 10 * 10))) {
                if (bpm == prevBpm + 1) tempoString = "+";
                else if (bpm == prevBpm - 1) tempoString = "-";
            }
          }
          prevTempo = tempo;
          prevBpm = bpm;

          QRect bounds = m_fontMetrics.boundingRect(tempoString);

          paint.setFont(m_font);
          if (time > 0) x -= bounds.width() / 2;
//        if (x > bounds.width() / 2) x -= bounds.width() / 2;
          if (prevEndX >= x - 3) x = prevEndX + 3;
          paint.drawText(static_cast<int>(x), textY, tempoString);
          prevEndX = x + bounds.width();
      }
    }

    paint.end();

    QPainter dbpaint(this);
//    dbpaint.drawPixmap(0, 0, m_buffer);
    dbpaint.drawPixmap(clipRect.x(), clipRect.y(),
                   m_buffer,
                   clipRect.x(), clipRect.y(),
                   clipRect.width(), clipRect.height());
                   
    dbpaint.end();

    m_refreshLinesOnly = false;
}

void
TempoRuler::slotInsertTempoHere()
{
    SnapGrid grid(m_rulerScale);
    grid.setSnapTime(SnapGrid::SnapToUnit);
    timeT t = grid.snapX(m_clickX - m_currentXOffset - m_xorigin,
                   SnapGrid::SnapLeft);
    tempoT tempo = Composition::getTempoForQpm(120.0);

    int tcn = m_composition->getTempoChangeNumberAt(t);
    if (tcn >= 0 && tcn < m_composition->getTempoChangeCount()) {
      std::pair<timeT, tempoT> tc = m_composition->getTempoChange(tcn);
      if (tc.first == t) return;
      tempo = tc.second;
    }

    emit changeTempo(t, tempo, -1, TempoDialog::AddTempo);
}

void
TempoRuler::slotInsertTempoAtPointer()
{
    timeT t = m_composition->getPosition();
    tempoT tempo = Composition::getTempoForQpm(120.0);

    int tcn = m_composition->getTempoChangeNumberAt(t);
    if (tcn >= 0 && tcn < m_composition->getTempoChangeCount()) {
      std::pair<timeT, tempoT> tc = m_composition->getTempoChange(tcn);
      if (tc.first == t) return;
      tempo = tc.second;
    }

    emit changeTempo(t, tempo, -1, TempoDialog::AddTempo);
}

void
TempoRuler::slotDeleteTempoChange()
{
    timeT t = m_rulerScale->getTimeForX(m_clickX - m_currentXOffset - m_xorigin);
    emit deleteTempo(t);
}

void
TempoRuler::slotRampToNext()
{
    timeT t = m_rulerScale->getTimeForX(m_clickX - m_currentXOffset - m_xorigin);

    int tcn = m_composition->getTempoChangeNumberAt(t);
    if (tcn < 0 || tcn >= m_composition->getTempoChangeCount()) return;

    std::pair<timeT, tempoT> tc = m_composition->getTempoChange(tcn);

    emit changeTempo(tc.first, tc.second, 0, TempoDialog::AddTempo);
}

void
TempoRuler::slotUnramp()
{
    timeT t = m_rulerScale->getTimeForX(m_clickX - m_currentXOffset - m_xorigin);

    int tcn = m_composition->getTempoChangeNumberAt(t);
    if (tcn < 0 || tcn >= m_composition->getTempoChangeCount()) return;

    std::pair<timeT, tempoT> tc = m_composition->getTempoChange(tcn);
    
    emit changeTempo(tc.first, tc.second, -1, TempoDialog::AddTempo);
}

void
TempoRuler::slotEditTempo()
{
    timeT t = m_rulerScale->getTimeForX(m_clickX - m_currentXOffset - m_xorigin);
    emit editTempo(t);
}
 
void
TempoRuler::slotEditTimeSignature()
{
    timeT t = m_rulerScale->getTimeForX(m_clickX - m_currentXOffset - m_xorigin);
    emit editTimeSignature(t);
}
 
void
TempoRuler::slotEditTempos()
{
    timeT t = m_rulerScale->getTimeForX(m_clickX - m_currentXOffset - m_xorigin);
    emit editTempos(t);
}
    

#include "temporuler.moc"

Generated by  Doxygen 1.6.0   Back to index