Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/waveform/waveformrendermark.cpp

Go to the documentation of this file.
00001 
00002 #include <QDebug>
00003 #include <QColor>
00004 #include <QDomNode>
00005 #include <QPaintEvent>
00006 #include <QPainter>
00007 #include <QObject>
00008 #include <QVector>
00009 
00010 #include "waveformrendermark.h"
00011 
00012 #include "waveformrenderer.h"
00013 #include "configobject.h"
00014 #include "controlobjectthreadmain.h"
00015 #include "controlobject.h"
00016 #include "widget/wskincolor.h"
00017 #include "widget/wwidget.h"
00018 #include "trackinfoobject.h"
00019 
00020 WaveformRenderMark::WaveformRenderMark(const char* pGroup,
00021                                        WaveformRenderer *parent)
00022         : m_pGroup(pGroup),
00023           m_pParent(parent),
00024           m_pMarkPoint(NULL),
00025           m_pTrackSamples(NULL),
00026           m_iMarkPoint(-1),
00027           m_iWidth(0),
00028           m_iHeight(0),
00029           m_bHasCustomPixmap(false),
00030           m_dSamplesPerDownsample(-1),
00031           m_iNumSamples(0),
00032           m_iSampleRate(-1) {
00033     m_pTrackSamples = new ControlObjectThreadMain(
00034         ControlObject::getControl(ConfigKey(pGroup, "track_samples")));
00035     slotUpdateTrackSamples(m_pTrackSamples->get());
00036     connect(m_pTrackSamples, SIGNAL(valueChanged(double)),
00037             this, SLOT(slotUpdateTrackSamples(double)));
00038     m_pTrackSampleRate = new ControlObjectThreadMain(
00039         ControlObject::getControl(ConfigKey(pGroup, "track_samplerate")));
00040     slotUpdateTrackSampleRate(m_pTrackSampleRate->get());
00041     connect(m_pTrackSampleRate, SIGNAL(valueChanged(double)),
00042             this, SLOT(slotUpdateTrackSampleRate(double)));
00043 }
00044 
00045 WaveformRenderMark::~WaveformRenderMark() {
00046     qDebug() << this << "~WaveformRenderMark()";
00047     //m_markPixmap = QPixmap();
00048     delete m_pTrackSamples;
00049     delete m_pTrackSampleRate;
00050     delete m_pMarkPoint;
00051 }
00052 
00053 void WaveformRenderMark::slotUpdateMarkPoint(double v) {
00054     //qDebug() << "WaveformRenderMark :: MarkPoint = " << v;
00055     m_iMarkPoint = (int)v;
00056 }
00057 
00058 void WaveformRenderMark::slotUpdateTrackSamples(double samples) {
00059     //qDebug() << "WaveformRenderMark :: samples = " << int(samples);
00060     m_iNumSamples = (int)samples;
00061 }
00062 
00063 void WaveformRenderMark::slotUpdateTrackSampleRate(double sampleRate) {
00064     //qDebug() << "WaveformRenderMark :: sampleRate = " << int(sampleRate);
00065 
00066     // f = z * m * n
00067     double m = m_pParent->getSubpixelsPerPixel();
00068     double f = sampleRate;
00069     double z = m_pParent->getPixelsPerSecond();
00070     double n = f / (m*z);
00071 
00072     m_iSampleRate = static_cast<int>(sampleRate);
00073     m_dSamplesPerDownsample = n;
00074 }
00075 
00076 void WaveformRenderMark::resize(int w, int h) {
00077     m_iWidth = w;
00078     m_iHeight = h;
00079 }
00080 
00081 void WaveformRenderMark::newTrack(TrackPointer pTrack) {
00082 }
00083 
00084 void WaveformRenderMark::setup(QDomNode node) {
00085     ConfigKey configKey;
00086     configKey.group = m_pGroup;
00087     configKey.item = WWidget::selectNodeQString(node, "Control");
00088 
00089     if (m_pMarkPoint) {
00090         // Disconnect the old control
00091         disconnect(m_pMarkPoint, 0, this, 0);
00092         delete m_pMarkPoint;
00093         m_pMarkPoint = NULL;
00094     }
00095 
00096     m_pMarkPoint = new ControlObjectThreadMain(
00097         ControlObject::getControl(configKey));
00098     slotUpdateMarkPoint(m_pMarkPoint->get());
00099     connect(m_pMarkPoint, SIGNAL(valueChanged(double)),
00100             this, SLOT(slotUpdateMarkPoint(double)));
00101 
00102     // Read the mark color, otherwise get MarkerColor of the Visual element
00103     QString markColor = WWidget::selectNodeQString(node, "Color");
00104     if (markColor == "") {
00105         // As a fallback, grab the mark color from the parent's MarkerColor
00106         markColor = WWidget::selectNodeQString(node.parentNode(), "MarkerColor");
00107         qDebug() << "Didn't get mark Color, using parent's MarkerColor:"
00108                  << markColor;
00109         m_markColor.setNamedColor(markColor);
00110         // m_markColor = QColor(255 - m_markColor.red(),
00111         //                      255 - m_markColor.green(),
00112         //                      255 - m_markColor.blue());
00113     } else {
00114         m_markColor.setNamedColor(markColor);
00115     }
00116     m_markColor = WSkinColor::getCorrectColor(m_markColor);
00117 
00118     // Read the text color, otherwise use the parent's BgColor.
00119     QString textColor = WWidget::selectNodeQString(node, "TextColor");
00120     if (textColor == "") {
00121         textColor = WWidget::selectNodeQString(node.parentNode(), "BgColor");
00122         qDebug() << "Didn't get mark TextColor, using parent's BgColor:"
00123                  << textColor;
00124         m_textColor.setNamedColor(textColor);
00125         // m_textColor = QColor(255 - m_textColor.red(),
00126         //                      255 - m_textColor.green(),
00127         //                      255 - m_textColor.blue());
00128     } else {
00129         m_textColor.setNamedColor(textColor);
00130     }
00131     m_textColor = WSkinColor::getCorrectColor(m_textColor);
00132 
00133     QString markAlign = WWidget::selectNodeQString(node, "Align");
00134     if (markAlign.compare("center", Qt::CaseInsensitive) == 0) {
00135         m_markAlign = WaveformRenderMark::CENTER;
00136     } else if (markAlign.compare("bottom", Qt::CaseInsensitive) == 0) {
00137         m_markAlign = WaveformRenderMark::BOTTOM;
00138     } else {
00139         // Default
00140         m_markAlign = WaveformRenderMark::TOP;
00141     }
00142 
00143     // Read the mark's text
00144     m_markText = WWidget::selectNodeQString(node, "Text");
00145     m_markPixmapPath = WWidget::selectNodeQString(node,"Pixmap");
00146 
00147     setupMarkPixmap();
00148 }
00149 
00150 
00151 void WaveformRenderMark::draw(QPainter *pPainter, QPaintEvent *event,
00152                               QVector<float> *buffer, double dPlayPos,
00153                               double rateAdjust) {
00154     if (m_iSampleRate == -1 || m_iSampleRate == 0 || m_iNumSamples == 0)
00155         return;
00156 
00157     // necessary?
00158     if (buffer == NULL)
00159         return;
00160 
00161     double subpixelsPerPixel = m_pParent->getSubpixelsPerPixel()*(1.0+rateAdjust);
00162 
00163     pPainter->save();
00164     pPainter->scale(1.0/subpixelsPerPixel,1.0);
00165     QPen oldPen = pPainter->pen();
00166     QBrush oldBrush = pPainter->brush();
00167 
00168     double subpixelWidth = m_iWidth * subpixelsPerPixel;
00169     double subpixelHalfWidth = subpixelWidth / 2.0;
00170     double halfh = m_iHeight/2;
00171 
00172     if (m_iMarkPoint != -1) {
00173         double markPointMono = m_iMarkPoint >> 1;
00174         double curPos = dPlayPos * (m_iNumSamples/2);
00175         double i = (markPointMono - curPos)/m_dSamplesPerDownsample;
00176 
00177         if (abs(i) < subpixelHalfWidth) {
00178             double x = (i+subpixelHalfWidth);
00179             QPen newPen = QPen(m_markColor);
00180             newPen.setWidth(subpixelsPerPixel*2);
00181             pPainter->setPen(newPen);
00182             pPainter->drawLine(QLineF(x, halfh, x, -halfh));
00183 
00184             if (!m_bHasCustomPixmap) {
00185                 // If no custom pixmap is provided, draw triangles at top and
00186                 // bottom of the mark.
00187                 pPainter->setPen(m_markColor);
00188                 pPainter->setBrush(QBrush(m_markColor));
00189                 QPolygonF topTriangle;
00190                 QPolygonF bottomTriangle;
00191                 double triWidth = subpixelsPerPixel * 8.0;
00192                 double triHeight = 10.0;
00193                 topTriangle << QPointF(x - 1 - triWidth/2.0f, halfh)
00194                             << QPointF(x + 1 + triWidth/2.0f, halfh)
00195                             << QPointF(x, halfh - triHeight);
00196                 bottomTriangle << QPointF(x - triWidth/2.0f, -halfh)
00197                                << QPointF(x + 1 + triWidth/2.0f, -halfh)
00198                                << QPointF(x, -halfh + triHeight);
00199                 pPainter->drawPolygon(topTriangle);
00200                 pPainter->drawPolygon(bottomTriangle);
00201             }
00202 
00203             if (!m_markPixmap.isNull()) {
00204                 pPainter->scale(subpixelsPerPixel, -1.0);
00205                 x = x / subpixelsPerPixel;
00206                 int pw = m_markPixmap.width();
00207                 int ph = m_markPixmap.height();
00208 
00209                 // Draw the pixmap in the right place
00210                 switch (m_markAlign) {
00211                     case WaveformRenderMark::BOTTOM:
00212                         // Bottom
00213                         pPainter->drawPixmap(x - pw/2.0, halfh - ph, m_markPixmap);
00214                         break;
00215                     case WaveformRenderMark::CENTER:
00216                         // Center
00217                         pPainter->drawPixmap(x - pw/2.0, 0 - ph/2.0, m_markPixmap);
00218                         break;
00219                     case WaveformRenderMark::TOP:
00220                     default:
00221                         // Top
00222                         pPainter->drawPixmap(x - pw/2.0, -halfh + 2.0, m_markPixmap);
00223                         break;
00224                 }
00225             }
00226         }
00227     }
00228 
00229     pPainter->setPen(oldPen);
00230     pPainter->setBrush(oldBrush);
00231     pPainter->restore();
00232 }
00233 
00234 void WaveformRenderMark::setupMarkPixmap() {
00235     // Load the pixmap from file -- takes precedence over text.
00236     if (m_markPixmapPath != "") {
00237         // TODO(XXX) We could use WPixmapStore here, which would recolor the
00238         // pixmap according to the theme. Then we would have to worry about
00239         // deleting it -- for now we'll just load the pixmap directly.
00240         m_markPixmap = QPixmap(WWidget::getPath(m_markPixmapPath));
00241 
00242         // If loading the pixmap didn't fail, then we're done. Otherwise fall
00243         // through and render a label.
00244         if (!m_markPixmap.isNull()) {
00245             m_bHasCustomPixmap = true;
00246             return;
00247         }
00248     }
00249 
00250     // If no text is provided, leave m_markPixmap as a null pixmap
00251     if (m_markText == "") {
00252         return;
00253     }
00254 
00255     //QFont font("Bitstream Vera Sans");
00256     //QFont font("Helvetica");
00257     QFont font; // Uses the application default
00258     font.setPointSize(8);
00259     //font.setWeight(QFont::Bold);
00260     //font.setLetterSpacing(QFont::AbsoluteSpacing, -1);
00261 
00262     QFontMetrics metrics(font);
00263 
00264     // Add left and right margins of one characters worth (based on average
00265     // pixels / character).
00266     double wordWidth = metrics.boundingRect(m_markText).width();
00267     double wordHeight = metrics.height();
00268 
00269     // A sensible margin for the horizontal is a quarter of the average
00270     // character width.
00271     //int marginX = wordWidth/m_markText.size()/4;
00272     //int marginX = metrics.maxWidth() / 4;
00273     double marginX = metrics.averageCharWidth() / 4.0;
00274 
00275     double marginY = 0; // .1 * wordHeight
00276 
00277     double markWidth = wordWidth + 2*marginX;
00278     double markHeight = wordHeight + 2*marginY;
00279 
00280     QRectF internalRect(marginX, marginY, wordWidth-1, wordHeight-1);
00281     QRectF externalRect(0, 0, markWidth-1, markHeight-1);
00282 
00283     m_markPixmap = QPixmap(markWidth, markHeight);
00284 
00285     // Fill with transparent pixels
00286     m_markPixmap.fill(QColor(0,0,0,0));
00287 
00288     QPainter painter(&m_markPixmap);
00289     painter.setRenderHint(QPainter::TextAntialiasing);
00290     //painter.setRenderHint(QPainter::Antialiasing);
00291     painter.setRenderHint(QPainter::HighQualityAntialiasing);
00292     painter.setBackgroundMode(Qt::TransparentMode);
00293     painter.setFont(font);
00294     QColor color = m_textColor;
00295     color = QColor(0xff - color.red(),
00296                    0xff - color.green(),
00297                    0xff - color.blue(),
00298                    128);
00299     painter.setPen(color);
00300     painter.setBrush(QBrush(color));
00301 
00302     // Stuff to test that the rectangles are correct.
00303     //painter.setBrush(QBrush());
00304     //painter.drawRect(externalRect);
00305     //painter.drawRect(internalRect);
00306 
00307     //painter.setBrush(QBrush());
00308     //painter.drawRoundedRect(externalRect, 25, 60, Qt::RelativeSize);
00309     painter.drawRoundedRect(externalRect, 2, 2);
00310 
00311     painter.setPen(m_textColor);
00312     painter.drawText(internalRect,
00313                      Qt::AlignCenter,
00314                      m_markText);
00315 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines