![]() |
Mixxx
|
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 }