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 }