File indexing completed on 2024-04-28 04:52:23
0001 /* 0002 SPDX-FileCopyrightText: 2010 Simon Andreas Eugster <simon.eu@gmail.com> 0003 This file is part of kdenlive. See www.kdenlive.org. 0004 0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "vectorscope.h" 0009 #include "colorplaneexport.h" 0010 #include "utils/colortools.h" 0011 #include "vectorscopegenerator.h" 0012 0013 #include "kdenlive_debug.h" 0014 #include "klocalizedstring.h" 0015 #include <KConfigGroup> 0016 #include <KSharedConfig> 0017 #include <QAction> 0018 #include <QActionGroup> 0019 #include <QElapsedTimer> 0020 #include <QPainter> 0021 #include <cmath> 0022 const double P75 = .75; 0023 0024 const QPointF YUV_R(-.147, .615); 0025 const QPointF YUV_G(-.289, -.515); 0026 const QPointF YUV_B(.437, -.100); 0027 const QPointF YUV_Cy(.147, -.615); 0028 const QPointF YUV_Mg(.289, .515); 0029 const QPointF YUV_Yl(-.437, .100); 0030 0031 const QPointF YPbPr_R(-.169, .5); 0032 const QPointF YPbPr_G(-.331, -.419); 0033 const QPointF YPbPr_B(.5, -.081); 0034 const QPointF YPbPr_Cy(.169, -.5); 0035 const QPointF YPbPr_Mg(.331, .419); 0036 const QPointF YPbPr_Yl(-.5, .081); 0037 0038 Vectorscope::Vectorscope(QWidget *parent) 0039 : AbstractGfxScopeWidget(true, parent) 0040 0041 { 0042 m_ui = new Ui::Vectorscope_UI(); 0043 m_ui->setupUi(this); 0044 0045 m_colorTools = new ColorTools(); 0046 m_vectorscopeGenerator = new VectorscopeGenerator(); 0047 0048 m_ui->paintMode->addItem(i18n("Green 2"), QVariant(VectorscopeGenerator::PaintMode_Green2)); 0049 m_ui->paintMode->addItem(i18n("Green"), QVariant(VectorscopeGenerator::PaintMode_Green)); 0050 m_ui->paintMode->addItem(i18n("Black"), QVariant(VectorscopeGenerator::PaintMode_Black)); 0051 m_ui->paintMode->addItem(i18n("Modified YUV (Chroma)"), QVariant(VectorscopeGenerator::PaintMode_Chroma)); 0052 m_ui->paintMode->addItem(i18n("YUV"), QVariant(VectorscopeGenerator::PaintMode_YUV)); 0053 m_ui->paintMode->addItem(i18n("Original Color"), QVariant(VectorscopeGenerator::PaintMode_Original)); 0054 0055 m_ui->backgroundMode->addItem(i18n("None"), QVariant(BG_NONE)); 0056 m_ui->backgroundMode->addItem(i18n("YUV"), QVariant(BG_YUV)); 0057 m_ui->backgroundMode->addItem(i18n("Modified YUV (Chroma)"), QVariant(BG_CHROMA)); 0058 m_ui->backgroundMode->addItem(i18n("YPbPr"), QVariant(BG_YPbPr)); 0059 0060 m_ui->sliderGain->setMinimum(0); 0061 m_ui->sliderGain->setMaximum(40); 0062 0063 connect(m_ui->backgroundMode, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &Vectorscope::slotBackgroundChanged); 0064 connect(m_ui->sliderGain, &QAbstractSlider::valueChanged, this, &Vectorscope::slotGainChanged); 0065 connect(m_ui->paintMode, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &Vectorscope::forceUpdateScope); 0066 connect(this, &Vectorscope::signalMousePositionChanged, this, &Vectorscope::forceUpdateHUD); 0067 m_ui->sliderGain->setValue(0); 0068 0069 ///// Build context menu ///// 0070 0071 m_menu->addSeparator()->setText(i18n("Tools")); 0072 0073 m_aExportBackground = new QAction(i18n("Export background"), this); 0074 m_menu->addAction(m_aExportBackground); 0075 connect(m_aExportBackground, &QAction::triggered, this, &Vectorscope::slotExportBackground); 0076 0077 m_menu->addSeparator()->setText(i18n("Drawing options")); 0078 0079 m_a75PBox = new QAction(i18n("75% box"), this); 0080 m_a75PBox->setCheckable(true); 0081 m_menu->addAction(m_a75PBox); 0082 connect(m_a75PBox, &QAction::changed, this, &Vectorscope::forceUpdateBackground); 0083 0084 m_aAxisEnabled = new QAction(i18n("Draw axis"), this); 0085 m_aAxisEnabled->setCheckable(true); 0086 m_menu->addAction(m_aAxisEnabled); 0087 connect(m_aAxisEnabled, &QAction::changed, this, &Vectorscope::forceUpdateBackground); 0088 0089 m_aIQLines = new QAction(i18n("Draw I/Q lines"), this); 0090 m_aIQLines->setCheckable(true); 0091 m_menu->addAction(m_aIQLines); 0092 connect(m_aIQLines, &QAction::changed, this, &Vectorscope::forceUpdateBackground); 0093 0094 m_menu->addSeparator()->setText(i18n("Color Space")); 0095 m_aColorSpace_YPbPr = new QAction(i18n("YPbPr"), this); 0096 m_aColorSpace_YPbPr->setCheckable(true); 0097 m_aColorSpace_YUV = new QAction(i18n("YUV"), this); 0098 m_aColorSpace_YUV->setCheckable(true); 0099 m_agColorSpace = new QActionGroup(this); 0100 m_agColorSpace->addAction(m_aColorSpace_YPbPr); 0101 m_agColorSpace->addAction(m_aColorSpace_YUV); 0102 m_menu->addAction(m_aColorSpace_YPbPr); 0103 m_menu->addAction(m_aColorSpace_YUV); 0104 connect(m_aColorSpace_YPbPr, &QAction::toggled, this, &Vectorscope::slotColorSpaceChanged); 0105 connect(m_aColorSpace_YUV, &QAction::toggled, this, &Vectorscope::slotColorSpaceChanged); 0106 0107 // To make the 1.0x text show 0108 slotGainChanged(m_ui->sliderGain->value()); 0109 0110 init(); 0111 } 0112 0113 Vectorscope::~Vectorscope() 0114 { 0115 writeConfig(); 0116 0117 delete m_colorTools; 0118 delete m_vectorscopeGenerator; 0119 0120 delete m_aColorSpace_YPbPr; 0121 delete m_aColorSpace_YUV; 0122 delete m_aExportBackground; 0123 delete m_aAxisEnabled; 0124 delete m_a75PBox; 0125 delete m_agColorSpace; 0126 delete m_ui; 0127 } 0128 0129 QString Vectorscope::widgetName() const 0130 { 0131 return QStringLiteral("Vectorscope"); 0132 } 0133 0134 void Vectorscope::readConfig() 0135 { 0136 AbstractGfxScopeWidget::readConfig(); 0137 0138 KSharedConfigPtr config = KSharedConfig::openConfig(); 0139 KConfigGroup scopeConfig(config, configName()); 0140 m_a75PBox->setChecked(scopeConfig.readEntry("75PBox", false)); 0141 m_aAxisEnabled->setChecked(scopeConfig.readEntry("axis", false)); 0142 m_aIQLines->setChecked(scopeConfig.readEntry("iqlines", false)); 0143 m_ui->backgroundMode->setCurrentIndex(scopeConfig.readEntry("backgroundmode").toInt()); 0144 m_ui->paintMode->setCurrentIndex(scopeConfig.readEntry("paintmode").toInt()); 0145 m_ui->sliderGain->setValue(scopeConfig.readEntry("gain", 1)); 0146 m_aColorSpace_YPbPr->setChecked(scopeConfig.readEntry("colorspace_ypbpr", false)); 0147 m_aColorSpace_YUV->setChecked(!m_aColorSpace_YPbPr->isChecked()); 0148 } 0149 0150 void Vectorscope::writeConfig() 0151 { 0152 KSharedConfigPtr config = KSharedConfig::openConfig(); 0153 KConfigGroup scopeConfig(config, configName()); 0154 scopeConfig.writeEntry("75PBox", m_a75PBox->isChecked()); 0155 scopeConfig.writeEntry("axis", m_aAxisEnabled->isChecked()); 0156 scopeConfig.writeEntry("iqlines", m_aIQLines->isChecked()); 0157 scopeConfig.writeEntry("backgroundmode", m_ui->backgroundMode->currentIndex()); 0158 scopeConfig.writeEntry("paintmode", m_ui->paintMode->currentIndex()); 0159 scopeConfig.writeEntry("gain", m_ui->sliderGain->value()); 0160 scopeConfig.writeEntry("colorspace_ypbpr", m_aColorSpace_YPbPr->isChecked()); 0161 scopeConfig.sync(); 0162 } 0163 0164 QRect Vectorscope::scopeRect() 0165 { 0166 // Distance from top/left/right 0167 int border = 6; 0168 0169 // We want to paint below the controls area. The line is the lowest element. 0170 QPoint topleft(border, m_ui->verticalSpacer->geometry().y() + border); 0171 QPoint bottomright(m_ui->horizontalSpacer->geometry().right() - border, this->size().height() - border); 0172 0173 m_visibleRect = QRect(topleft, bottomright); 0174 0175 QRect scopeRect(topleft, bottomright); 0176 0177 // Circle Width: min of width and height 0178 m_cw = (scopeRect.height() < scopeRect.width()) ? scopeRect.height() : scopeRect.width(); 0179 scopeRect.setWidth(m_cw); 0180 scopeRect.setHeight(m_cw); 0181 0182 m_centerPoint = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), QPointF(0, 0)); 0183 m_pR75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YUV_R); 0184 m_pG75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YUV_G); 0185 m_pB75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YUV_B); 0186 m_pCy75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YUV_Cy); 0187 m_pMg75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YUV_Mg); 0188 m_pYl75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YUV_Yl); 0189 m_qR75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YPbPr_R); 0190 m_qG75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YPbPr_G); 0191 m_qB75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YPbPr_B); 0192 m_qCy75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YPbPr_Cy); 0193 m_qMg75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YPbPr_Mg); 0194 m_qYl75 = m_vectorscopeGenerator->mapToCircle(scopeRect.size(), P75 * VectorscopeGenerator::scaling * YPbPr_Yl); 0195 0196 return scopeRect; 0197 } 0198 0199 bool Vectorscope::isHUDDependingOnInput() const 0200 { 0201 return false; 0202 } 0203 bool Vectorscope::isScopeDependingOnInput() const 0204 { 0205 return true; 0206 } 0207 bool Vectorscope::isBackgroundDependingOnInput() const 0208 { 0209 return false; 0210 } 0211 0212 QImage Vectorscope::renderHUD(uint) 0213 { 0214 0215 QImage hud; 0216 QLocale locale; // Used for UI → OK 0217 locale.setNumberOptions(QLocale::OmitGroupSeparator); 0218 if (m_mouseWithinWidget) { 0219 // Mouse moved: Draw a circle over the scope 0220 0221 hud = QImage(m_visibleRect.size(), QImage::Format_ARGB32); 0222 hud.fill(qRgba(0, 0, 0, 0)); 0223 0224 QPainter davinci; 0225 bool ok = davinci.begin(&hud); 0226 if (!ok) { 0227 qDebug() << "Could not initialise QPainter for Vectorscope HUD."; 0228 return hud; 0229 } 0230 QPoint widgetCenterPoint = m_scopeRect.topLeft() + m_centerPoint; 0231 0232 int dx = -widgetCenterPoint.x() + m_mousePos.x(); 0233 int dy = widgetCenterPoint.y() - m_mousePos.y(); 0234 0235 QPoint reference = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(1, 0)); 0236 0237 float r = sqrtf(dx * dx + dy * dy); 0238 float percent = 100.f * r / float(VectorscopeGenerator::scaling) / m_gain / (reference.x() - widgetCenterPoint.x()); 0239 0240 switch (m_ui->backgroundMode->itemData(m_ui->backgroundMode->currentIndex()).toInt()) { 0241 case BG_NONE: 0242 davinci.setPen(penLight); 0243 break; 0244 default: 0245 if (r > m_cw / 2.0f) { 0246 davinci.setPen(penLight); 0247 } else { 0248 davinci.setPen(penDark); 0249 } 0250 break; 0251 } 0252 davinci.drawEllipse(m_centerPoint, int(r), int(r)); 0253 davinci.setPen(penThin); 0254 davinci.drawText(QPoint(m_scopeRect.width() - 40, m_scopeRect.height()), i18n("%1%", locale.toString(percent, 'f', 0))); 0255 0256 float angle = float(copysignf(std::acos(dx / r) * 180.f / float(M_PI), dy)); 0257 davinci.drawText(QPoint(10, m_scopeRect.height()), i18n("%1°", locale.toString(angle, 'f', 1))); 0258 0259 // m_circleEnabled = false; 0260 } else { 0261 hud = QImage(0, 0, QImage::Format_ARGB32); 0262 } 0263 Q_EMIT signalHUDRenderingFinished(0, 1); 0264 return hud; 0265 } 0266 0267 QImage Vectorscope::renderGfxScope(uint accelerationFactor, const QImage &qimage) 0268 { 0269 QElapsedTimer timer; 0270 timer.start(); 0271 QImage scope; 0272 0273 if (m_cw <= 0) { 0274 qCDebug(KDENLIVE_LOG) << "Scope size not known yet. Aborting."; 0275 } else { 0276 0277 VectorscopeGenerator::ColorSpace colorSpace = 0278 m_aColorSpace_YPbPr->isChecked() ? VectorscopeGenerator::ColorSpace_YPbPr : VectorscopeGenerator::ColorSpace_YUV; 0279 VectorscopeGenerator::PaintMode paintMode = VectorscopeGenerator::PaintMode(m_ui->paintMode->itemData(m_ui->paintMode->currentIndex()).toInt()); 0280 scope = m_vectorscopeGenerator->calculateVectorscope(m_scopeRect.size(), qimage, m_gain, paintMode, colorSpace, m_aAxisEnabled->isChecked(), 0281 accelerationFactor); 0282 } 0283 Q_EMIT signalScopeRenderingFinished(uint(timer.elapsed()), accelerationFactor); 0284 return scope; 0285 } 0286 0287 QImage Vectorscope::renderBackground(uint) 0288 { 0289 QElapsedTimer timer; 0290 timer.start(); 0291 0292 QImage bg(m_visibleRect.size(), QImage::Format_ARGB32); 0293 bg.fill(qRgba(0, 0, 0, 0)); 0294 0295 // Set up tools 0296 QPainter davinci; 0297 bool ok = davinci.begin(&bg); 0298 if (!ok) { 0299 qDebug() << "Could not initialise QPainter for Vectorscope background."; 0300 return bg; 0301 } 0302 davinci.setRenderHint(QPainter::Antialiasing, true); 0303 0304 QPoint vinciPoint; 0305 QPoint vinciPoint2; 0306 0307 // Draw the color plane (if selected) 0308 QImage colorPlane; 0309 switch (m_ui->backgroundMode->itemData(m_ui->backgroundMode->currentIndex()).toInt()) { 0310 case BG_YUV: 0311 colorPlane = m_colorTools->yuvColorWheel(m_scopeRect.size(), 128, 1 / float(VectorscopeGenerator::scaling), false, true); 0312 davinci.drawImage(0, 0, colorPlane); 0313 break; 0314 case BG_CHROMA: 0315 colorPlane = m_colorTools->yuvColorWheel(m_scopeRect.size(), 255, 1 / float(VectorscopeGenerator::scaling), true, true); 0316 davinci.drawImage(0, 0, colorPlane); 0317 break; 0318 case BG_YPbPr: 0319 colorPlane = m_colorTools->yPbPrColorWheel(m_scopeRect.size(), 128, 1 / float(VectorscopeGenerator::scaling), true); 0320 davinci.drawImage(0, 0, colorPlane); 0321 break; 0322 } 0323 0324 // Draw I/Q lines (from the YIQ color space; Skin tones lie on the I line) 0325 // Positions are calculated by transforming YIQ:[0 1 0] or YIQ:[0 0 1] to YUV/YPbPr. 0326 if (m_aIQLines->isChecked()) { 0327 0328 switch (m_ui->backgroundMode->itemData(m_ui->backgroundMode->currentIndex()).toInt()) { 0329 case BG_NONE: 0330 davinci.setPen(penLightDots); 0331 break; 0332 default: 0333 davinci.setPen(penDarkDots); 0334 break; 0335 } 0336 0337 if (m_aColorSpace_YUV->isChecked()) { 0338 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(-.544, .838)); 0339 vinciPoint2 = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(.544, -.838)); 0340 } else { 0341 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(-.675, .737)); 0342 vinciPoint2 = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(.675, -.737)); 0343 } 0344 0345 davinci.drawLine(vinciPoint, vinciPoint2); 0346 davinci.setPen(penThick); 0347 davinci.drawText(vinciPoint - QPoint(11, 5), QStringLiteral("I")); 0348 0349 switch (m_ui->backgroundMode->itemData(m_ui->backgroundMode->currentIndex()).toInt()) { 0350 case BG_NONE: 0351 davinci.setPen(penLightDots); 0352 break; 0353 default: 0354 davinci.setPen(penDarkDots); 0355 break; 0356 } 0357 0358 if (m_aColorSpace_YUV->isChecked()) { 0359 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(.838, .544)); 0360 vinciPoint2 = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(-.838, -.544)); 0361 } else { 0362 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(.908, .443)); 0363 vinciPoint2 = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(-.908, -.443)); 0364 } 0365 0366 davinci.drawLine(vinciPoint, vinciPoint2); 0367 davinci.setPen(penThick); 0368 davinci.drawText(vinciPoint - QPoint(-7, 2), QStringLiteral("Q")); 0369 } 0370 0371 // Draw the vectorscope circle 0372 davinci.setPen(penThick); 0373 davinci.drawEllipse(0, 0, m_cw, m_cw); 0374 0375 // Draw RGB/CMY points with 100% chroma 0376 if (m_aColorSpace_YUV->isChecked()) { 0377 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YUV_R); 0378 davinci.drawEllipse(vinciPoint, 4, 4); 0379 davinci.drawText(vinciPoint - QPoint(20, -10), QStringLiteral("R")); 0380 0381 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YUV_G); 0382 davinci.drawEllipse(vinciPoint, 4, 4); 0383 davinci.drawText(vinciPoint - QPoint(20, 0), QStringLiteral("G")); 0384 0385 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YUV_B); 0386 davinci.drawEllipse(vinciPoint, 4, 4); 0387 davinci.drawText(vinciPoint + QPoint(15, 10), QStringLiteral("B")); 0388 0389 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YUV_Cy); 0390 davinci.drawEllipse(vinciPoint, 4, 4); 0391 davinci.drawText(vinciPoint + QPoint(15, -5), QStringLiteral("Cy")); 0392 0393 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YUV_Mg); 0394 davinci.drawEllipse(vinciPoint, 4, 4); 0395 davinci.drawText(vinciPoint + QPoint(15, 10), QStringLiteral("Mg")); 0396 0397 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YUV_Yl); 0398 davinci.drawEllipse(vinciPoint, 4, 4); 0399 davinci.drawText(vinciPoint - QPoint(25, 0), QStringLiteral("Yl")); 0400 } else { 0401 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YPbPr_R); 0402 davinci.drawEllipse(vinciPoint, 4, 4); 0403 davinci.drawText(vinciPoint - QPoint(20, -10), QStringLiteral("R")); 0404 0405 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YPbPr_G); 0406 davinci.drawEllipse(vinciPoint, 4, 4); 0407 davinci.drawText(vinciPoint - QPoint(20, 0), QStringLiteral("G")); 0408 0409 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YPbPr_B); 0410 davinci.drawEllipse(vinciPoint, 4, 4); 0411 davinci.drawText(vinciPoint + QPoint(15, 10), QStringLiteral("B")); 0412 0413 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YPbPr_Cy); 0414 davinci.drawEllipse(vinciPoint, 4, 4); 0415 davinci.drawText(vinciPoint + QPoint(15, -5), QStringLiteral("Cy")); 0416 0417 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YPbPr_Mg); 0418 davinci.drawEllipse(vinciPoint, 4, 4); 0419 davinci.drawText(vinciPoint + QPoint(15, 10), QStringLiteral("Mg")); 0420 0421 vinciPoint = m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), VectorscopeGenerator::scaling * YPbPr_Yl); 0422 davinci.drawEllipse(vinciPoint, 4, 4); 0423 davinci.drawText(vinciPoint - QPoint(25, 0), QStringLiteral("Yl")); 0424 } 0425 0426 switch (m_ui->backgroundMode->itemData(m_ui->backgroundMode->currentIndex()).toInt()) { 0427 case BG_NONE: 0428 davinci.setPen(penLight); 0429 break; 0430 default: 0431 davinci.setPen(penDark); 0432 break; 0433 } 0434 0435 // Draw axis 0436 if (m_aAxisEnabled->isChecked()) { 0437 davinci.drawLine(m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(0, -.9)), 0438 m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(0, .9))); 0439 davinci.drawLine(m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(-.9, 0)), 0440 m_vectorscopeGenerator->mapToCircle(m_scopeRect.size(), QPointF(.9, 0))); 0441 } 0442 0443 // Draw center point 0444 switch (m_ui->backgroundMode->itemData(m_ui->backgroundMode->currentIndex()).toInt()) { 0445 case BG_CHROMA: 0446 davinci.setPen(penDark); 0447 break; 0448 default: 0449 davinci.setPen(penThin); 0450 break; 0451 } 0452 davinci.drawEllipse(m_centerPoint, 5, 5); 0453 0454 // Draw 75% box 0455 if (m_a75PBox->isChecked()) { 0456 if (m_aColorSpace_YUV->isChecked()) { 0457 davinci.drawLine(m_pR75, m_pYl75); 0458 davinci.drawLine(m_pYl75, m_pG75); 0459 davinci.drawLine(m_pG75, m_pCy75); 0460 davinci.drawLine(m_pCy75, m_pB75); 0461 davinci.drawLine(m_pB75, m_pMg75); 0462 davinci.drawLine(m_pMg75, m_pR75); 0463 } else { 0464 davinci.drawLine(m_qR75, m_qYl75); 0465 davinci.drawLine(m_qYl75, m_qG75); 0466 davinci.drawLine(m_qG75, m_qCy75); 0467 davinci.drawLine(m_qCy75, m_qB75); 0468 davinci.drawLine(m_qB75, m_qMg75); 0469 davinci.drawLine(m_qMg75, m_qR75); 0470 } 0471 } 0472 0473 // Draw RGB/CMY points with 75% chroma (for NTSC) 0474 davinci.setPen(penThin); 0475 if (m_aColorSpace_YUV->isChecked()) { 0476 davinci.drawEllipse(m_pR75, 3, 3); 0477 davinci.drawEllipse(m_pG75, 3, 3); 0478 davinci.drawEllipse(m_pB75, 3, 3); 0479 davinci.drawEllipse(m_pCy75, 3, 3); 0480 davinci.drawEllipse(m_pMg75, 3, 3); 0481 davinci.drawEllipse(m_pYl75, 3, 3); 0482 } else { 0483 davinci.drawEllipse(m_qR75, 3, 3); 0484 davinci.drawEllipse(m_qG75, 3, 3); 0485 davinci.drawEllipse(m_qB75, 3, 3); 0486 davinci.drawEllipse(m_qCy75, 3, 3); 0487 davinci.drawEllipse(m_qMg75, 3, 3); 0488 davinci.drawEllipse(m_qYl75, 3, 3); 0489 } 0490 0491 // Draw realtime factor (number of skipped pixels) 0492 if (m_aRealtime->isChecked()) { 0493 davinci.setPen(penThin); 0494 davinci.drawText(QPoint(m_scopeRect.width() - 40, m_scopeRect.height() - 15), QVariant(m_accelFactorScope).toString().append(QStringLiteral("x"))); 0495 } 0496 0497 Q_EMIT signalBackgroundRenderingFinished(uint(timer.elapsed()), 1); 0498 return bg; 0499 } 0500 0501 ///// Slots ///// 0502 0503 void Vectorscope::slotGainChanged(int newval) 0504 { 0505 QLocale locale; // Used for UI → OK 0506 locale.setNumberOptions(QLocale::OmitGroupSeparator); 0507 m_gain = 1 + newval / 10.f; 0508 m_ui->lblGain->setText(locale.toString(m_gain, 'f', 1) + QLatin1Char('x')); 0509 forceUpdateScope(); 0510 } 0511 0512 void Vectorscope::slotExportBackground() 0513 { 0514 QPointer<ColorPlaneExport> colorPlaneExportDialog = new ColorPlaneExport(this); 0515 colorPlaneExportDialog->exec(); 0516 delete colorPlaneExportDialog; 0517 } 0518 0519 void Vectorscope::slotBackgroundChanged() 0520 { 0521 // Background changed, switch to a suitable color mode now 0522 int index; 0523 switch (m_ui->backgroundMode->itemData(m_ui->backgroundMode->currentIndex()).toInt()) { 0524 case BG_YUV: 0525 index = m_ui->paintMode->findData(QVariant(VectorscopeGenerator::PaintMode_Black)); 0526 if (index >= 0) { 0527 m_ui->paintMode->setCurrentIndex(index); 0528 } 0529 break; 0530 0531 case BG_NONE: 0532 if (m_ui->paintMode->itemData(m_ui->paintMode->currentIndex()).toInt() == VectorscopeGenerator::PaintMode_Black) { 0533 index = m_ui->paintMode->findData(QVariant(VectorscopeGenerator::PaintMode_Green2)); 0534 m_ui->paintMode->setCurrentIndex(index); 0535 } 0536 break; 0537 } 0538 forceUpdateBackground(); 0539 } 0540 0541 void Vectorscope::slotColorSpaceChanged() 0542 { 0543 int index; 0544 if (m_aColorSpace_YPbPr->isChecked()) { 0545 if (m_ui->backgroundMode->itemData(m_ui->backgroundMode->currentIndex()).toInt() == BG_YUV) { 0546 index = m_ui->backgroundMode->findData(QVariant(BG_YPbPr)); 0547 if (index >= 0) { 0548 m_ui->backgroundMode->setCurrentIndex(index); 0549 } 0550 } 0551 } else { 0552 if (m_ui->backgroundMode->itemData(m_ui->backgroundMode->currentIndex()).toInt() == BG_YPbPr) { 0553 index = m_ui->backgroundMode->findData(QVariant(BG_YUV)); 0554 if (index >= 0) { 0555 m_ui->backgroundMode->setCurrentIndex(index); 0556 } 0557 } 0558 } 0559 forceUpdate(); 0560 }