File indexing completed on 2024-04-21 04:52:31

0001 /*
0002     SPDX-FileCopyrightText: 2017 Jean-Baptiste Mardelle
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #include "geometrywidget.h"
0007 #include "core.h"
0008 #include "doublewidget.h"
0009 #include "dragvalue.h"
0010 #include "monitor/monitor.h"
0011 
0012 #include <KLocalizedString>
0013 #include <QGridLayout>
0014 
0015 GeometryWidget::GeometryWidget(Monitor *monitor, QPair<int, int> range, const QRect &rect, double opacity, const QSize frameSize, bool useRatioLock,
0016                                bool useOpacity, QWidget *parent)
0017     : QWidget(parent)
0018     , m_min(range.first)
0019     , m_max(range.second)
0020     , m_active(false)
0021     , m_monitor(monitor)
0022     , m_opacity(nullptr)
0023     , m_opacityFactor(100.)
0024 {
0025     Q_UNUSED(useRatioLock)
0026     setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
0027     auto *layout = new QVBoxLayout(this);
0028     layout->setContentsMargins(0, 0, 0, 0);
0029     layout->setSpacing(0);
0030     m_defaultSize = pCore->getCurrentFrameSize();
0031     m_sourceSize = (frameSize.isValid() && !frameSize.isNull()) ? frameSize : m_defaultSize;
0032     /*QString paramName = i18n(paramTag.toUtf8().data());
0033     QString comment = m_model->data(ix, AssetParameterModel::CommentRole).toString();
0034     if (!comment.isEmpty()) {
0035         comment = i18n(comment.toUtf8().data());
0036     }*/
0037 
0038     auto *horLayout = new QHBoxLayout;
0039     horLayout->setSpacing(2);
0040     m_spinX = new DragValue(i18nc("x axis position", "X"), 0, 0, -99000, 99000, -1, QString(), false, false, this);
0041     connect(m_spinX, &DragValue::valueChanged, this, &GeometryWidget::slotAdjustRectKeyframeValue);
0042     horLayout->addWidget(m_spinX);
0043     m_spinX->setObjectName("spinX");
0044 
0045     m_spinY = new DragValue(i18nc("y axis position", "Y"), 0, 0, -99000, 99000, -1, QString(), false, false, this);
0046     connect(m_spinY, &DragValue::valueChanged, this, &GeometryWidget::slotAdjustRectKeyframeValue);
0047     horLayout->addWidget(m_spinY);
0048     m_spinY->setObjectName("spinY");
0049 
0050     m_spinWidth = new DragValue(i18nc("Frame width", "W"), m_defaultSize.width(), 0, 1, 99000, -1, QString(), false, false, this);
0051     connect(m_spinWidth, &DragValue::valueChanged, this, &GeometryWidget::slotAdjustRectWidth);
0052     horLayout->addWidget(m_spinWidth);
0053     m_spinWidth->setObjectName("spinW");
0054 
0055     // Lock ratio stuff
0056     m_lockRatio = new QAction(QIcon::fromTheme(QStringLiteral("link")), i18n("Lock aspect ratio"), this);
0057     m_lockRatio->setCheckable(true);
0058     connect(m_lockRatio, &QAction::triggered, this, &GeometryWidget::slotLockRatio);
0059     auto *ratioButton = new QToolButton;
0060     ratioButton->setDefaultAction(m_lockRatio);
0061     horLayout->addWidget(ratioButton);
0062 
0063     m_spinHeight = new DragValue(i18nc("Frame height", "H"), m_defaultSize.height(), 0, 1, 99000, -1, QString(), false, false, this);
0064     connect(m_spinHeight, &DragValue::valueChanged, this, &GeometryWidget::slotAdjustRectHeight);
0065     m_spinHeight->setObjectName("spinH");
0066     horLayout->addWidget(m_spinHeight);
0067     horLayout->addStretch(10);
0068 
0069     auto *horLayout2 = new QHBoxLayout;
0070     horLayout2->setSpacing(2);
0071     m_spinSize = new DragValue(i18n("Size"), 100, 2, 1, 99000, -1, i18n("%"), false, false, this);
0072     m_spinSize->setStep(5);
0073     m_spinSize->setObjectName("spinS");
0074     connect(m_spinSize, &DragValue::valueChanged, this, &GeometryWidget::slotResize);
0075     horLayout2->addWidget(m_spinSize);
0076 
0077     if (useOpacity) {
0078         m_opacity = new DragValue(i18n("Opacity"), 100, 0, 0, 100, -1, i18n("%"), true, false, this);
0079         m_opacity->setValue((int)(opacity * m_opacityFactor));
0080         connect(m_opacity, &DragValue::valueChanged, this, [&]() { Q_EMIT valueChanged(getValue()); });
0081         m_opacity->setObjectName("spinO");
0082         horLayout2->addWidget(m_opacity);
0083     }
0084     horLayout2->addStretch(10);
0085 
0086     // Build buttons
0087     m_originalSize = new QAction(QIcon::fromTheme(QStringLiteral("zoom-original")), i18n("Adjust to original size"), this);
0088     connect(m_originalSize, &QAction::triggered, this, &GeometryWidget::slotAdjustToSource);
0089     m_originalSize->setCheckable(true);
0090     QAction *adjustSize = new QAction(QIcon::fromTheme(QStringLiteral("zoom-fit-best")), i18n("Adjust and center in frame"), this);
0091     connect(adjustSize, &QAction::triggered, this, &GeometryWidget::slotAdjustToFrameSize);
0092     QAction *fitToWidth = new QAction(QIcon::fromTheme(QStringLiteral("zoom-fit-width")), i18n("Fit to width"), this);
0093     connect(fitToWidth, &QAction::triggered, this, &GeometryWidget::slotFitToWidth);
0094     QAction *fitToHeight = new QAction(QIcon::fromTheme(QStringLiteral("zoom-fit-height")), i18n("Fit to height"), this);
0095     connect(fitToHeight, &QAction::triggered, this, &GeometryWidget::slotFitToHeight);
0096 
0097     QAction *alignleft = new QAction(QIcon::fromTheme(QStringLiteral("align-horizontal-left")), i18n("Align left"), this);
0098     connect(alignleft, &QAction::triggered, this, &GeometryWidget::slotMoveLeft);
0099     QAction *alignhcenter = new QAction(QIcon::fromTheme(QStringLiteral("align-horizontal-center")), i18n("Center horizontally"), this);
0100     connect(alignhcenter, &QAction::triggered, this, &GeometryWidget::slotCenterH);
0101     QAction *alignright = new QAction(QIcon::fromTheme(QStringLiteral("align-horizontal-right")), i18n("Align right"), this);
0102     connect(alignright, &QAction::triggered, this, &GeometryWidget::slotMoveRight);
0103     QAction *aligntop = new QAction(QIcon::fromTheme(QStringLiteral("align-vertical-top")), i18n("Align top"), this);
0104     connect(aligntop, &QAction::triggered, this, &GeometryWidget::slotMoveTop);
0105     QAction *alignvcenter = new QAction(QIcon::fromTheme(QStringLiteral("align-vertical-center")), i18n("Center vertically"), this);
0106     connect(alignvcenter, &QAction::triggered, this, &GeometryWidget::slotCenterV);
0107     QAction *alignbottom = new QAction(QIcon::fromTheme(QStringLiteral("align-vertical-bottom")), i18n("Align bottom"), this);
0108     connect(alignbottom, &QAction::triggered, this, &GeometryWidget::slotMoveBottom);
0109 
0110     auto *alignLayout = new QHBoxLayout;
0111     alignLayout->setSpacing(0);
0112     auto *alignButton = new QToolButton;
0113     alignButton->setDefaultAction(alignleft);
0114     alignButton->setAutoRaise(true);
0115     alignLayout->addWidget(alignButton);
0116 
0117     alignButton = new QToolButton;
0118     alignButton->setDefaultAction(alignhcenter);
0119     alignButton->setAutoRaise(true);
0120     alignLayout->addWidget(alignButton);
0121 
0122     alignButton = new QToolButton;
0123     alignButton->setDefaultAction(alignright);
0124     alignButton->setAutoRaise(true);
0125     alignLayout->addWidget(alignButton);
0126 
0127     alignButton = new QToolButton;
0128     alignButton->setDefaultAction(aligntop);
0129     alignButton->setAutoRaise(true);
0130     alignLayout->addWidget(alignButton);
0131 
0132     alignButton = new QToolButton;
0133     alignButton->setDefaultAction(alignvcenter);
0134     alignButton->setAutoRaise(true);
0135     alignLayout->addWidget(alignButton);
0136 
0137     alignButton = new QToolButton;
0138     alignButton->setDefaultAction(alignbottom);
0139     alignButton->setAutoRaise(true);
0140     alignLayout->addWidget(alignButton);
0141 
0142     alignButton = new QToolButton;
0143     alignButton->setDefaultAction(m_originalSize);
0144     alignButton->setAutoRaise(true);
0145     alignLayout->addWidget(alignButton);
0146 
0147     alignButton = new QToolButton;
0148     alignButton->setDefaultAction(adjustSize);
0149     alignButton->setAutoRaise(true);
0150     alignLayout->addWidget(alignButton);
0151 
0152     alignButton = new QToolButton;
0153     alignButton->setDefaultAction(fitToWidth);
0154     alignButton->setAutoRaise(true);
0155     alignLayout->addWidget(alignButton);
0156 
0157     alignButton = new QToolButton;
0158     alignButton->setDefaultAction(fitToHeight);
0159     alignButton->setAutoRaise(true);
0160     alignLayout->addWidget(alignButton);
0161     alignLayout->addStretch(10);
0162 
0163     layout->addLayout(horLayout);
0164     layout->addLayout(alignLayout);
0165     layout->addLayout(horLayout2);
0166     slotUpdateGeometryRect(rect);
0167     slotAdjustRectKeyframeValue();
0168     setMinimumHeight(horLayout->sizeHint().height() + horLayout2->sizeHint().height() + alignLayout->sizeHint().height());
0169 }
0170 
0171 void GeometryWidget::slotAdjustToSource()
0172 {
0173     m_spinWidth->blockSignals(true);
0174     m_spinHeight->blockSignals(true);
0175     m_spinWidth->setValue(qRound(m_sourceSize.width() / pCore->getCurrentSar()), false);
0176     m_spinHeight->setValue(m_sourceSize.height(), false);
0177     m_spinWidth->blockSignals(false);
0178     m_spinHeight->blockSignals(false);
0179     slotAdjustRectKeyframeValue();
0180     if (m_lockRatio->isChecked()) {
0181         m_monitor->setEffectSceneProperty(QStringLiteral("lockratio"), m_originalSize->isChecked() ? (double)m_sourceSize.width() / m_sourceSize.height()
0182                                                                                                    : (double)m_defaultSize.width() / m_defaultSize.height());
0183     }
0184 }
0185 void GeometryWidget::slotAdjustToFrameSize()
0186 {
0187     double monitorDar = pCore->getCurrentDar();
0188     double sourceDar = m_sourceSize.width() / m_sourceSize.height();
0189     QSignalBlocker bk1(m_spinWidth);
0190     QSignalBlocker bk2(m_spinHeight);
0191     if (sourceDar > monitorDar) {
0192         // Fit to width
0193         double factor = (double)m_defaultSize.width() / m_sourceSize.width() * pCore->getCurrentSar();
0194         m_spinHeight->setValue(qRound(m_sourceSize.height() * factor));
0195         m_spinWidth->setValue(m_defaultSize.width());
0196     } else {
0197         // Fit to height
0198         double factor = (double)m_defaultSize.height() / m_sourceSize.height();
0199         m_spinHeight->setValue(m_defaultSize.height());
0200         m_spinWidth->setValue(qRound(m_sourceSize.width() / pCore->getCurrentSar() * factor));
0201     }
0202     // Center
0203     QSignalBlocker bk3(m_spinX);
0204     QSignalBlocker bk4(m_spinY);
0205     m_spinX->setValue((m_defaultSize.width() - m_spinWidth->value()) / 2);
0206     m_spinY->setValue((m_defaultSize.height() - m_spinHeight->value()) / 2);
0207     slotAdjustRectKeyframeValue();
0208 }
0209 
0210 void GeometryWidget::slotFitToWidth()
0211 {
0212     double factor = (double)m_defaultSize.width() / m_sourceSize.width() * pCore->getCurrentSar();
0213     m_spinWidth->blockSignals(true);
0214     m_spinHeight->blockSignals(true);
0215     m_spinHeight->setValue(qRound(m_sourceSize.height() * factor));
0216     m_spinWidth->setValue(m_defaultSize.width());
0217     m_spinWidth->blockSignals(false);
0218     m_spinHeight->blockSignals(false);
0219     slotAdjustRectKeyframeValue();
0220 }
0221 void GeometryWidget::slotFitToHeight()
0222 {
0223     double factor = (double)m_defaultSize.height() / m_sourceSize.height();
0224     m_spinWidth->blockSignals(true);
0225     m_spinHeight->blockSignals(true);
0226     m_spinHeight->setValue(m_defaultSize.height());
0227     m_spinWidth->setValue(qRound(m_sourceSize.width() / pCore->getCurrentSar() * factor));
0228     m_spinWidth->blockSignals(false);
0229     m_spinHeight->blockSignals(false);
0230     slotAdjustRectKeyframeValue();
0231 }
0232 void GeometryWidget::slotResize(double value)
0233 {
0234     QSignalBlocker bkh(m_spinHeight);
0235     QSignalBlocker bkw(m_spinWidth);
0236     QSignalBlocker bkx(m_spinX);
0237     QSignalBlocker bky(m_spinY);
0238     int w = (m_originalSize->isChecked() ? m_sourceSize.width() : m_defaultSize.width()) * value / 100.0;
0239     int h = (m_originalSize->isChecked() ? m_sourceSize.height() : m_defaultSize.height()) * value / 100.0;
0240     int delta_x = (m_spinWidth->value() - w) / 2;
0241     int delta_y = (m_spinHeight->value() - h) / 2;
0242     m_spinWidth->setValue(w);
0243     m_spinHeight->setValue(h);
0244     m_spinX->setValue(m_spinX->value() + delta_x);
0245     m_spinY->setValue(m_spinY->value() + delta_y);
0246     slotAdjustRectKeyframeValue();
0247 }
0248 
0249 /** @brief Moves the rect to the left frame border (x position = 0). */
0250 void GeometryWidget::slotMoveLeft()
0251 {
0252     m_spinX->setValue(0);
0253 }
0254 /** @brief Centers the rect horizontally. */
0255 void GeometryWidget::slotCenterH()
0256 {
0257     m_spinX->setValue((m_defaultSize.width() - m_spinWidth->value()) / 2);
0258 }
0259 /** @brief Moves the rect to the right frame border (x position = frame width - rect width). */
0260 void GeometryWidget::slotMoveRight()
0261 {
0262     m_spinX->setValue(m_defaultSize.width() - m_spinWidth->value());
0263 }
0264 
0265 /** @brief Moves the rect to the top frame border (y position = 0). */
0266 void GeometryWidget::slotMoveTop()
0267 {
0268     m_spinY->setValue(0);
0269 }
0270 
0271 /** @brief Centers the rect vertically. */
0272 void GeometryWidget::slotCenterV()
0273 {
0274     m_spinY->setValue((m_defaultSize.height() - m_spinHeight->value()) / 2);
0275 }
0276 
0277 /** @brief Moves the rect to the bottom frame border (y position = frame height - rect height). */
0278 void GeometryWidget::slotMoveBottom()
0279 {
0280     m_spinY->setValue(m_defaultSize.height() - m_spinHeight->value());
0281 }
0282 
0283 /** @brief Un/Lock aspect ratio for size in effect parameter. */
0284 void GeometryWidget::slotLockRatio()
0285 {
0286     auto *lockRatio = qobject_cast<QAction *>(QObject::sender());
0287     if (lockRatio->isChecked()) {
0288         m_monitor->setEffectSceneProperty(QStringLiteral("lockratio"), m_originalSize->isChecked() ? (double)m_sourceSize.width() / m_sourceSize.height()
0289                                                                                                    : (double)m_defaultSize.width() / m_defaultSize.height());
0290     } else {
0291         m_monitor->setEffectSceneProperty(QStringLiteral("lockratio"), -1);
0292     }
0293 }
0294 void GeometryWidget::slotAdjustRectHeight()
0295 {
0296     if (m_lockRatio->isChecked()) {
0297         m_spinWidth->blockSignals(true);
0298         if (m_originalSize->isChecked()) {
0299             m_spinWidth->setValue(qRound(m_spinHeight->value() * m_sourceSize.width() / m_sourceSize.height()));
0300         } else {
0301             m_spinWidth->setValue(qRound(m_spinHeight->value() * m_defaultSize.width() / m_defaultSize.height()));
0302         }
0303         m_spinWidth->blockSignals(false);
0304     }
0305     adjustSizeValue();
0306     slotAdjustRectKeyframeValue();
0307 }
0308 
0309 void GeometryWidget::slotAdjustRectWidth()
0310 {
0311     if (m_lockRatio->isChecked()) {
0312         m_spinHeight->blockSignals(true);
0313         if (m_originalSize->isChecked()) {
0314             m_spinHeight->setValue(qRound(m_spinWidth->value() * m_sourceSize.height() / m_sourceSize.width()));
0315         } else {
0316             m_spinHeight->setValue(qRound(m_spinWidth->value() * m_defaultSize.height() / m_defaultSize.width()));
0317         }
0318         m_spinHeight->blockSignals(false);
0319     }
0320     adjustSizeValue();
0321     slotAdjustRectKeyframeValue();
0322 }
0323 
0324 void GeometryWidget::adjustSizeValue()
0325 {
0326     double size;
0327     if ((double)m_spinWidth->value() / m_spinHeight->value() < pCore->getCurrentDar()) {
0328         if (m_originalSize->isChecked()) {
0329             size = m_spinWidth->value() * 100.0 / m_sourceSize.width();
0330         } else {
0331             size = m_spinWidth->value() * 100.0 / m_defaultSize.width();
0332         }
0333     } else {
0334         if (m_originalSize->isChecked()) {
0335             size = m_spinHeight->value() * 100.0 / m_sourceSize.height();
0336         } else {
0337             size = m_spinHeight->value() * 100.0 / m_defaultSize.height();
0338         }
0339     }
0340     m_spinSize->blockSignals(true);
0341     m_spinSize->setValue(size);
0342     m_spinSize->blockSignals(false);
0343 }
0344 
0345 void GeometryWidget::slotAdjustRectKeyframeValue()
0346 {
0347     QRect rect(m_spinX->value(), m_spinY->value(), m_spinWidth->value(), m_spinHeight->value());
0348     Q_EMIT updateMonitorGeometry(rect);
0349     Q_EMIT valueChanged(getValue());
0350 }
0351 
0352 void GeometryWidget::slotUpdateGeometryRect(const QRect r)
0353 {
0354     if (!r.isValid()) {
0355         return;
0356     }
0357     m_spinX->blockSignals(true);
0358     m_spinY->blockSignals(true);
0359     m_spinWidth->blockSignals(true);
0360     m_spinHeight->blockSignals(true);
0361     m_spinX->setValue(r.x());
0362     m_spinY->setValue(r.y());
0363     m_spinWidth->setValue(r.width());
0364     m_spinHeight->setValue(r.height());
0365     m_spinX->blockSignals(false);
0366     m_spinY->blockSignals(false);
0367     m_spinWidth->blockSignals(false);
0368     m_spinHeight->blockSignals(false);
0369     // Q_EMIT updateMonitorGeometry(r);
0370     adjustSizeValue();
0371     Q_EMIT valueChanged(getValue());
0372 }
0373 
0374 void GeometryWidget::setValue(const QRect r, double opacity)
0375 {
0376     if (!r.isValid()) {
0377         return;
0378     }
0379     m_spinX->blockSignals(true);
0380     m_spinY->blockSignals(true);
0381     m_spinWidth->blockSignals(true);
0382     m_spinHeight->blockSignals(true);
0383     m_spinX->setValue(r.x());
0384     m_spinY->setValue(r.y());
0385     m_spinWidth->setValue(r.width());
0386     m_spinHeight->setValue(r.height());
0387     if (m_opacity) {
0388         m_opacity->blockSignals(true);
0389         if (opacity < 0) {
0390             opacity = 100 / m_opacityFactor;
0391         }
0392         m_opacity->setValue(qRound(opacity * m_opacityFactor));
0393         m_opacity->blockSignals(false);
0394     }
0395     m_spinX->blockSignals(false);
0396     m_spinY->blockSignals(false);
0397     m_spinWidth->blockSignals(false);
0398     m_spinHeight->blockSignals(false);
0399     adjustSizeValue();
0400     Q_EMIT updateMonitorGeometry(r);
0401 }
0402 
0403 const QString GeometryWidget::getValue() const
0404 {
0405     if (m_opacity) {
0406         return QStringLiteral("%1 %2 %3 %4 %5")
0407             .arg(m_spinX->value())
0408             .arg(m_spinY->value())
0409             .arg(m_spinWidth->value())
0410             .arg(m_spinHeight->value())
0411             .arg(QString::number(m_opacity->value() / m_opacityFactor, 'f'));
0412     }
0413     return QStringLiteral("%1 %2 %3 %4").arg(m_spinX->value()).arg(m_spinY->value()).arg(m_spinWidth->value()).arg(m_spinHeight->value());
0414 }
0415 
0416 void GeometryWidget::connectMonitor(bool activate)
0417 {
0418     if (m_active == activate) {
0419         return;
0420     }
0421     m_active = activate;
0422     if (activate) {
0423         connect(m_monitor, &Monitor::effectChanged, this, &GeometryWidget::slotUpdateGeometryRect, Qt::UniqueConnection);
0424         QRect rect(m_spinX->value(), m_spinY->value(), m_spinWidth->value(), m_spinHeight->value());
0425         Q_EMIT updateMonitorGeometry(rect);
0426     } else {
0427         m_monitor->setEffectKeyframe(false);
0428         disconnect(m_monitor, &Monitor::effectChanged, this, &GeometryWidget::slotUpdateGeometryRect);
0429     }
0430 }
0431 
0432 void GeometryWidget::slotSetRange(QPair<int, int> range)
0433 {
0434     m_min = range.first;
0435     m_max = range.second;
0436 }