AbstractScopeWidget::AbstractScopeWidget(bool trackMouse, QWidget *parent) : QWidget(parent) , m_mousePos(0, 0) , m_mouseWithinWidget(false) , offset(5) , m_accelFactorHUD(1) , m_accelFactorScope(1) , m_accelFactorBackground(1) , m_semaphoreHUD(1) , m_semaphoreScope(1) , m_semaphoreBackground(1) , initialDimensionUpdateDone(false) , m_requestForcedUpdate(false) , m_rescaleMinDist(4) , m_rescaleVerticalThreshold(2.0f) , m_rescaleActive(false) , m_rescalePropertiesLocked(false) , m_rescaleFirstRescaleDone(true) , m_rescaleDirection(North) { m_scopePalette = QPalette(); m_scopePalette.setBrush(QPalette::Window, QBrush(dark2)); m_scopePalette.setBrush(QPalette::Base, QBrush(dark)); m_scopePalette.setBrush(QPalette::Button, QBrush(dark)); m_scopePalette.setBrush(QPalette::Text, QBrush(light)); m_scopePalette.setBrush(QPalette::WindowText, QBrush(light)); m_scopePalette.setBrush(QPalette::ButtonText, QBrush(light)); this->setPalette(m_scopePalette); this->setAutoFillBackground(true); m_aAutoRefresh = new QAction(i18n("Auto Refresh"), this); m_aAutoRefresh->setCheckable(true); m_aRealtime = new QAction(i18n("Realtime (with precision loss)"), this); m_aRealtime->setCheckable(true); m_menu = new QMenu(this); // Disabled dark palette on menus since it breaks up with some themes: kdenlive issue #2950 //m_menu->setPalette(m_scopePalette); m_menu->addAction(m_aAutoRefresh); m_menu->addAction(m_aRealtime); this->setContextMenuPolicy(Qt::CustomContextMenu); bool b = true; b &= connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint))); b &= connect(this, SIGNAL(signalHUDRenderingFinished(uint, uint)), this, SLOT(slotHUDRenderingFinished(uint, uint))); b &= connect(this, SIGNAL(signalScopeRenderingFinished(uint, uint)), this, SLOT(slotScopeRenderingFinished(uint, uint))); b &= connect(this, SIGNAL(signalBackgroundRenderingFinished(uint, uint)), this, SLOT(slotBackgroundRenderingFinished(uint, uint))); b &= connect(m_aRealtime, SIGNAL(toggled(bool)), this, SLOT(slotResetRealtimeFactor(bool))); b &= connect(m_aAutoRefresh, SIGNAL(toggled(bool)), this, SLOT(slotAutoRefreshToggled(bool))); Q_ASSERT(b); // Enable mouse tracking if desired. // Causes the mouseMoved signal to be emitted when the mouse moves inside the // widget, even when no mouse button is pressed. this->setMouseTracking(trackMouse); }
QImage AudioSpectrum::renderHUD(uint) { QTime start = QTime::currentTime(); if (m_innerScopeRect.height() > 0 && m_innerScopeRect.width() > 0) { // May be below 0 if widget is too small // Minimum distance between two lines const uint minDistY = 30; const uint minDistX = 40; const uint textDistX = 10; const uint textDistY = 25; const uint topDist = m_innerScopeRect.top() - m_scopeRect.top(); const uint leftDist = m_innerScopeRect.left() - m_scopeRect.left(); const uint dbDiff = ceil((float)minDistY/m_innerScopeRect.height() * (m_dBmax-m_dBmin)); const int mouseX = m_mousePos.x() - m_innerScopeRect.left(); const int mouseY = m_mousePos.y() - m_innerScopeRect.top(); QImage hud(m_scopeRect.size(), QImage::Format_ARGB32); hud.fill(qRgba(0,0,0,0)); QPainter davinci(&hud); davinci.setPen(AbstractScopeWidget::penLight); int y; for (int db = -dbDiff; db > m_dBmin; db -= dbDiff) { y = topDist + m_innerScopeRect.height() * ((float)db)/(m_dBmin - m_dBmax); if (y-topDist > m_innerScopeRect.height()-minDistY+10) { // Abort here, there is still a line left for min dB to paint which needs some room. break; } davinci.drawLine(leftDist, y, leftDist + m_innerScopeRect.width()-1, y); davinci.drawText(leftDist + m_innerScopeRect.width() + textDistX, y + 6, i18n("%1 dB", m_dBmax + db)); } davinci.drawLine(leftDist, topDist, leftDist + m_innerScopeRect.width()-1, topDist); davinci.drawText(leftDist + m_innerScopeRect.width() + textDistX, topDist+6, i18n("%1 dB", m_dBmax)); davinci.drawLine(leftDist, topDist+m_innerScopeRect.height()-1, leftDist + m_innerScopeRect.width()-1, topDist+m_innerScopeRect.height()-1); davinci.drawText(leftDist + m_innerScopeRect.width() + textDistX, topDist+m_innerScopeRect.height()+6, i18n("%1 dB", m_dBmin)); const uint hzDiff = ceil( ((float)minDistX)/m_innerScopeRect.width() * m_freqMax / 1000 ) * 1000; int x = 0; const int rightBorder = leftDist + m_innerScopeRect.width()-1; y = topDist + m_innerScopeRect.height() + textDistY; for (int hz = 0; x <= rightBorder; hz += hzDiff) { davinci.setPen(AbstractScopeWidget::penLighter); x = leftDist + m_innerScopeRect.width() * ((float)hz)/m_freqMax; if (x <= rightBorder) { davinci.drawLine(x, topDist, x, topDist + m_innerScopeRect.height()+6); } if (hz < m_freqMax && x+textDistY < leftDist + m_innerScopeRect.width()) { davinci.drawText(x-4, y, QVariant(hz/1000).toString()); } else { x = leftDist + m_innerScopeRect.width(); davinci.drawLine(x, topDist, x, topDist + m_innerScopeRect.height()+6); davinci.drawText(x-10, y, i18n("%1 kHz", QString("%1").arg((double)m_freqMax/1000, 0, 'f', 1))); } if (hz > 0) { // Draw finer lines between the main lines davinci.setPen(AbstractScopeWidget::penLightDots); for (uint dHz = 3; dHz > 0; dHz--) { x = leftDist + m_innerScopeRect.width() * ((float)hz - dHz * hzDiff/4.0f)/m_freqMax; if (x > rightBorder) { break; } davinci.drawLine(x, topDist, x, topDist + m_innerScopeRect.height()-1); } } } if (m_aTrackMouse->isChecked() && m_mouseWithinWidget && mouseX < m_innerScopeRect.width()-1) { davinci.setPen(AbstractScopeWidget::penThin); x = leftDist + mouseX; float db = 0; float freq = ((float) mouseX)/(m_innerScopeRect.width()-1) * m_freqMax; bool drawDb = false; m_lastFFTLock.acquire(); // We need to test whether the mouse is inside the widget // because the position could already have changed in the meantime (-> crash) if (m_lastFFT.size() > 0 && mouseX >= 0 && mouseX < m_innerScopeRect.width()) { uint right = ((float) m_freqMax)/(m_freq/2) * (m_lastFFT.size() - 1); QVector<float> dbMap = FFTTools::interpolatePeakPreserving(m_lastFFT, m_innerScopeRect.width(), 0, right, -120); db = dbMap[mouseX]; y = topDist + m_innerScopeRect.height()-1 - (dbMap[mouseX] - m_dBmin) / (m_dBmax-m_dBmin) * (m_innerScopeRect.height()-1); if (y < (int)topDist + m_innerScopeRect.height()-1) { drawDb = true; davinci.drawLine(x, y, leftDist + m_innerScopeRect.width()-1, y); } } else { y = topDist + mouseY; } m_lastFFTLock.release(); if (y > (int)topDist + mouseY) { y = topDist+ mouseY; } davinci.drawLine(x, y, x, topDist + m_innerScopeRect.height()-1); if (drawDb) { QPoint dist(20, -20); QRect rect( leftDist + mouseX + dist.x(), topDist + mouseY + dist.y(), 100, 40 ); if (rect.right() > (int)leftDist + m_innerScopeRect.width()-1) { // Mirror the rectangle at the y axis to keep it inside the widget rect = QRect( rect.topLeft() - QPoint(rect.width() + 2*dist.x(), 0), rect.size()); } QRect textRect( rect.topLeft() + QPoint(12, 4), rect.size() ); davinci.fillRect(rect, AbstractScopeWidget::penBackground.brush()); davinci.setPen(AbstractScopeWidget::penLighter); davinci.drawRect(rect); davinci.drawText(textRect, QString( i18n("%1 dB", QString("%1").arg(db, 0, 'f', 2)) + '\n' + i18n("%1 kHz", QString("%1").arg(freq/1000, 0, 'f', 2)))); } } emit signalHUDRenderingFinished(start.elapsed(), 1); return hud; } else { #ifdef DEBUG_AUDIOSPEC qDebug() << "Widget is too small for painting inside. Size of inner scope rect is " << m_innerScopeRect.width() << "x" << m_innerScopeRect.height() <<"."; #endif emit signalHUDRenderingFinished(0, 1); return QImage(); } }
QImage Waveform::renderHUD(uint) { QImage hud(m_scopeRect.size(), QImage::Format_ARGB32); hud.fill(qRgba(0,0,0,0)); QPainter davinci(&hud); davinci.setPen(penLight); QMap< QString, QString > values = ProfilesDialog::getSettingsFromFile(KdenliveSettings::current_profile()); // qDebug() << values.value("width"); const int rightX = scopeRect().width()-m_textWidth.width()+3; const int x = m_mousePos.x() - scopeRect().x(); const int y = m_mousePos.y() - scopeRect().y(); if (scopeRect().height() > 0 && m_mouseWithinWidget) { int val = 255*(1-(float)y/scopeRect().height()); if (val >= 0 && val <= 255) { // Draw a horizontal line through the current mouse position // and show the value of the waveform there davinci.drawLine(0, y, scopeRect().size().width()-m_textWidth.width(), y); // Make the value stick to the line unless it is at the top/bottom of the scope int valY = y+5; const int top = 30; const int bottom = 20; if (valY < top) { valY = top; } else if (valY > scopeRect().height()-bottom) { valY = scopeRect().height()-bottom; } davinci.drawText(rightX, valY, QVariant(val).toString()); } if (scopeRect().width() > 0) { // Draw a vertical line and the x position of the source clip bool ok; const int profileWidth = values.value("width").toInt(&ok); if (ok) { const int clipX = (float)x/(scopeRect().width()-m_textWidth.width()-1)*(profileWidth-1); if (clipX >= 0 && clipX <= profileWidth) { int valX = x-15; if (valX < 0) { valX = 0; } if (valX > scopeRect().width()-55-m_textWidth.width()) { valX = scopeRect().width()-55-m_textWidth.width(); } davinci.drawLine(x, y, x, scopeRect().height()-m_paddingBottom); davinci.drawText(valX, scopeRect().height()-5, QVariant(clipX).toString() + " px"); } } } } davinci.drawText(rightX, scopeRect().height()-m_paddingBottom, "0"); davinci.drawText(rightX, 10, "255"); emit signalHUDRenderingFinished(0, 1); return hud; }
QImage Histogram::renderHUD(uint) { emit signalHUDRenderingFinished(0, 1); return QImage(); }