File indexing completed on 2024-05-05 04:54:18
0001 /* 0002 SPDX-FileCopyrightText: 2017 Nicolas Carion 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #include "mixstackview.hpp" 0007 #include "assets/keyframes/model/keyframemodellist.hpp" 0008 #include "assets/model/assetparametermodel.hpp" 0009 #include "core.h" 0010 #include "monitor/monitor.h" 0011 #include "widgets/positionwidget.h" 0012 #include "widgets/timecodedisplay.h" 0013 0014 #include <KLocalizedString> 0015 #include <QComboBox> 0016 #include <QDebug> 0017 #include <QHBoxLayout> 0018 #include <QLabel> 0019 #include <QSignalBlocker> 0020 #include <QToolButton> 0021 0022 MixStackView::MixStackView(QWidget *parent) 0023 : AssetParameterView(parent) 0024 { 0025 // Position widget 0026 m_position = new PositionWidget(i18n("Position"), 0, 0, 0); 0027 // Duration widget 0028 m_durationLayout = new QHBoxLayout; 0029 m_duration = new TimecodeDisplay(this); 0030 m_duration->setRange(1, -1); 0031 m_durationLayout->addWidget(new QLabel(i18n("Duration:"))); 0032 m_durationLayout->addWidget(m_duration); 0033 m_alignLeft = new QToolButton(this); 0034 m_alignLeft->setIcon(QIcon::fromTheme(QStringLiteral("align-horizontal-left"))); 0035 m_alignLeft->setToolTip(i18n("Align left")); 0036 m_alignLeft->setAutoRaise(true); 0037 m_alignLeft->setCheckable(true); 0038 connect(m_alignLeft, &QToolButton::clicked, this, &MixStackView::slotAlignLeft); 0039 m_alignRight = new QToolButton(this); 0040 m_alignRight->setIcon(QIcon::fromTheme(QStringLiteral("align-horizontal-right"))); 0041 m_alignRight->setToolTip(i18n("Align right")); 0042 m_alignRight->setAutoRaise(true); 0043 m_alignRight->setCheckable(true); 0044 connect(m_alignRight, &QToolButton::clicked, this, &MixStackView::slotAlignRight); 0045 m_alignCenter = new QToolButton(this); 0046 m_alignCenter->setIcon(QIcon::fromTheme(QStringLiteral("align-horizontal-center"))); 0047 m_alignCenter->setToolTip(i18n("Center")); 0048 m_alignCenter->setAutoRaise(true); 0049 m_alignCenter->setCheckable(true); 0050 connect(m_alignCenter, &QToolButton::clicked, this, &MixStackView::slotAlignCenter); 0051 m_durationLayout->addStretch(); 0052 m_durationLayout->addWidget(m_alignRight); 0053 m_durationLayout->addWidget(m_alignCenter); 0054 m_durationLayout->addWidget(m_alignLeft); 0055 connect(m_duration, &TimecodeDisplay::timeCodeUpdated, this, &MixStackView::updateDuration); 0056 connect(m_position, &PositionWidget::valueChanged, this, &MixStackView::updatePosition); 0057 connect(this, &AssetParameterView::seekToPos, [this](int pos) { 0058 // at this point, the effects returns a pos relative to the clip. We need to convert it to a global time 0059 int clipIn = pCore->getItemPosition(m_model->getOwnerId()); 0060 Q_EMIT seekToTransPos(pos + clipIn); 0061 }); 0062 } 0063 0064 void MixStackView::setModel(const std::shared_ptr<AssetParameterModel> &model, QSize frameSize, bool addSpacer) 0065 { 0066 AssetParameterView::setModel(model, frameSize, addSpacer); 0067 m_model->setActive(true); 0068 auto kfr = model->getKeyframeModel(); 0069 if (kfr) { 0070 connect(kfr.get(), &KeyframeModelList::modelChanged, this, &AssetParameterView::slotRefresh); 0071 } 0072 Q_EMIT initKeyframeView(true); 0073 pCore->getMonitor(m_model->monitorId)->slotShowEffectScene(needsMonitorEffectScene()); 0074 0075 const QSignalBlocker bk0(m_duration); 0076 const QSignalBlocker bk1(m_position); 0077 int duration = m_model->data(m_model->index(0, 0), AssetParameterModel::ParentDurationRole).toInt(); 0078 m_duration->setValue(duration + 1); 0079 m_position->setRange(0, duration); 0080 m_position->setPosition(duration - pCore->getMixCutPos(stackOwner())); 0081 connect(m_model.get(), &AssetParameterModel::dataChanged, this, &MixStackView::durationChanged); 0082 0083 // The layout is handled by AssetParameterView, so we can only add our custom stuff later here 0084 m_lay->addLayout(m_durationLayout); 0085 m_lay->addWidget(m_position); 0086 m_lay->addStretch(10); 0087 checkAlignment(); 0088 } 0089 0090 void MixStackView::checkAlignment() 0091 { 0092 MixAlignment align = pCore->getMixAlign(stackOwner()); 0093 QSignalBlocker bk1(m_alignLeft); 0094 QSignalBlocker bk2(m_alignRight); 0095 QSignalBlocker bk3(m_alignCenter); 0096 m_alignLeft->setChecked(false); 0097 m_alignRight->setChecked(false); 0098 m_alignCenter->setChecked(false); 0099 switch (align) { 0100 case MixAlignment::AlignLeft: 0101 m_alignLeft->setChecked(true); 0102 break; 0103 case MixAlignment::AlignRight: 0104 m_alignRight->setChecked(true); 0105 break; 0106 case MixAlignment::AlignCenter: 0107 m_alignCenter->setChecked(true); 0108 break; 0109 default: 0110 // No alignment 0111 break; 0112 } 0113 } 0114 0115 void MixStackView::durationChanged(const QModelIndex &, const QModelIndex &, const QVector<int> &roles) 0116 { 0117 if (roles.contains(AssetParameterModel::ParentDurationRole)) { 0118 int duration = m_model->data(m_model->index(0, 0), AssetParameterModel::ParentDurationRole).toInt(); 0119 int mixCutPos = pCore->getMixCutPos(stackOwner()); 0120 if (duration + 1 == m_duration->getValue() && mixCutPos == m_position->getPosition()) { 0121 // No change 0122 return; 0123 } 0124 QSignalBlocker bk1(m_duration); 0125 QSignalBlocker bk2(m_position); 0126 m_duration->setValue(duration + 1); 0127 m_position->setRange(0, duration); 0128 m_position->setPosition(duration - mixCutPos); 0129 checkAlignment(); 0130 } 0131 } 0132 0133 MixAlignment MixStackView::alignment() const 0134 { 0135 if (m_alignRight->isChecked()) { 0136 return MixAlignment::AlignRight; 0137 } 0138 if (m_alignLeft->isChecked()) { 0139 return MixAlignment::AlignLeft; 0140 } 0141 if (m_alignCenter->isChecked()) { 0142 return MixAlignment::AlignCenter; 0143 } 0144 return MixAlignment::AlignNone; 0145 } 0146 0147 void MixStackView::updateDuration() 0148 { 0149 if (m_model) { 0150 pCore->resizeMix(stackOwner().itemId, m_duration->getValue() - 1, alignment()); 0151 } 0152 } 0153 0154 void MixStackView::updatePosition() 0155 { 0156 if (m_model) { 0157 pCore->resizeMix(stackOwner().itemId, m_duration->getValue() - 1, MixAlignment::AlignNone, m_position->getPosition()); 0158 } 0159 } 0160 0161 void MixStackView::slotAlignLeft() 0162 { 0163 if (!m_alignLeft->isChecked()) { 0164 return; 0165 } 0166 m_alignRight->setChecked(false); 0167 m_alignCenter->setChecked(false); 0168 pCore->resizeMix(stackOwner().itemId, m_duration->getValue() - 1, MixAlignment::AlignLeft); 0169 } 0170 0171 void MixStackView::slotAlignRight() 0172 { 0173 if (!m_alignRight->isChecked()) { 0174 return; 0175 } 0176 m_alignLeft->setChecked(false); 0177 m_alignCenter->setChecked(false); 0178 pCore->resizeMix(stackOwner().itemId, m_duration->getValue() - 1, MixAlignment::AlignRight); 0179 } 0180 0181 void MixStackView::slotAlignCenter() 0182 { 0183 if (!m_alignCenter->isChecked()) { 0184 return; 0185 } 0186 m_alignLeft->setChecked(false); 0187 m_alignRight->setChecked(false); 0188 pCore->resizeMix(stackOwner().itemId, m_duration->getValue() - 1, MixAlignment::AlignCenter); 0189 } 0190 0191 void MixStackView::unsetModel() 0192 { 0193 if (m_model) { 0194 m_model->setActive(false); 0195 m_lay->removeItem(m_durationLayout); 0196 m_lay->removeWidget(m_position); 0197 auto kfr = m_model->getKeyframeModel(); 0198 if (kfr) { 0199 disconnect(kfr.get(), &KeyframeModelList::modelChanged, this, &AssetParameterView::slotRefresh); 0200 } 0201 disconnect(m_model.get(), &AssetParameterModel::dataChanged, this, &MixStackView::durationChanged); 0202 pCore->getMonitor(m_model->monitorId)->slotShowEffectScene(MonitorSceneDefault); 0203 } 0204 AssetParameterView::unsetModel(); 0205 } 0206 0207 ObjectId MixStackView::stackOwner() const 0208 { 0209 if (m_model) { 0210 return m_model->getOwnerId(); 0211 } 0212 return ObjectId(); 0213 }