File indexing completed on 2023-12-03 04:55:10
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 }