X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fgeometrywidget.cpp;h=44377e0fdfc57f113ef6cb931fe74f031cbd3b66;hb=4ae3260592acc87712db77b7d3fe0cc2be7d76bc;hp=ed9dd5eb60a5b33922262008523fc6da2e4d1b81;hpb=297e484a74fe72ebd1bcf346d82f208b03bde0b6;p=kdenlive diff --git a/src/geometrywidget.cpp b/src/geometrywidget.cpp index ed9dd5eb..44377e0f 100644 --- a/src/geometrywidget.cpp +++ b/src/geometrywidget.cpp @@ -24,149 +24,282 @@ #include "keyframehelper.h" #include "timecodedisplay.h" #include "monitorscene.h" +#include "monitoreditwidget.h" +#include "onmonitoritems/onmonitorrectitem.h" +#include "onmonitoritems/onmonitorpathitem.h" #include "kdenlivesettings.h" +#include "dragvalue.h" #include #include -#include #include #include - -GeometryWidget::GeometryWidget(Monitor* monitor, Timecode timecode, int clipPos, bool isEffect, QWidget* parent ): - QWidget(parent), - m_monitor(monitor), - m_timePos(new TimecodeDisplay(timecode)), - m_clipPos(clipPos), - m_inPoint(0), - m_outPoint(1), - m_isEffect(isEffect), - m_rect(NULL), - m_geometry(NULL), - m_showScene(true) +#include + + + +GeometryWidget::GeometryWidget(Monitor* monitor, const Timecode &timecode, int clipPos, bool isEffect, bool showRotation, QWidget* parent): + QWidget(parent), + m_monitor(monitor), + m_timePos(new TimecodeDisplay(timecode)), + m_clipPos(clipPos), + m_inPoint(0), + m_outPoint(1), + m_isEffect(isEffect), + m_rect(NULL), + m_geomPath(NULL), + m_previous(NULL), + m_geometry(NULL), + m_showScene(true), + m_showRotation(showRotation) { m_ui.setupUi(this); - m_scene = monitor->getEffectScene(); - + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum); + MonitorEditWidget *edit = monitor->getEffectEdit(); + edit->removeCustomControls(); + edit->addCustomButton(KIcon("draw-path"), i18n("Show path"), this, SLOT(slotShowPath(bool)), true, KdenliveSettings::onmonitoreffects_geometryshowpath()); + edit->addCustomButton(KIcon("transform-crop"), i18n("Show previous keyframe"), this, SLOT(slotShowPreviousKeyFrame(bool)), true, KdenliveSettings::onmonitoreffects_geometryshowprevious()); + m_scene = edit->getScene(); + m_scene->cleanup(); /* Setup of timeline and keyframe controls */ - ((QGridLayout *)(m_ui.widgetTimeWrapper->layout()))->addWidget(m_timePos, 1, 6); + ((QGridLayout *)(m_ui.widgetTimeWrapper->layout()))->addWidget(m_timePos, 1, 5); QVBoxLayout *layout = new QVBoxLayout(m_ui.frameTimeline); m_timeline = new KeyframeHelper(m_ui.frameTimeline); layout->addWidget(m_timeline); layout->setContentsMargins(0, 0, 0, 0); + + int size = style()->pixelMetric(QStyle::PM_SmallIconSize); + QSize iconSize(size, size); m_ui.buttonPrevious->setIcon(KIcon("media-skip-backward")); m_ui.buttonPrevious->setToolTip(i18n("Go to previous keyframe")); + m_ui.buttonPrevious->setIconSize(iconSize); m_ui.buttonNext->setIcon(KIcon("media-skip-forward")); m_ui.buttonNext->setToolTip(i18n("Go to next keyframe")); - m_ui.buttonAddDelete->setIcon(KIcon("document-new")); + m_ui.buttonNext->setIconSize(iconSize); + m_ui.buttonAddDelete->setIcon(KIcon("list-add")); m_ui.buttonAddDelete->setToolTip(i18n("Add keyframe")); + m_ui.buttonAddDelete->setIconSize(iconSize); - m_ui.buttonSync->setIcon(KIcon("insert-link")); - m_ui.buttonSync->setToolTip(i18n("Synchronize with timeline cursor")); - m_ui.buttonSync->setChecked(KdenliveSettings::transitionfollowcursor()); - - connect(m_timeline, SIGNAL(positionChanged(int)), this, SLOT(slotPositionChanged(int))); + connect(m_timeline, SIGNAL(requestSeek(int)), this, SLOT(slotRequestSeek(int))); connect(m_timeline, SIGNAL(keyframeMoved(int)), this, SLOT(slotKeyframeMoved(int))); connect(m_timeline, SIGNAL(addKeyframe(int)), this, SLOT(slotAddKeyframe(int))); connect(m_timeline, SIGNAL(removeKeyframe(int)), this, SLOT(slotDeleteKeyframe(int))); - connect(m_timePos, SIGNAL(editingFinished()), this, SLOT(slotPositionChanged())); + connect(m_timePos, SIGNAL(timeCodeEditingFinished()), this, SLOT(slotPositionChanged())); connect(m_ui.buttonPrevious, SIGNAL(clicked()), this, SLOT(slotPreviousKeyframe())); connect(m_ui.buttonNext, SIGNAL(clicked()), this, SLOT(slotNextKeyframe())); connect(m_ui.buttonAddDelete, SIGNAL(clicked()), this, SLOT(slotAddDeleteKeyframe())); - connect(m_ui.buttonSync, SIGNAL(toggled(bool)), this, SLOT(slotSetSynchronize(bool))); - + m_spinX = new DragValue(i18nc("x axis position", "X"), 0, 0, -99000, 99000, -1, QString(), false, this); + m_ui.horizontalLayout->addWidget(m_spinX, 0, 0); + + m_spinY = new DragValue(i18nc("y axis position", "Y"), 0, 0, -99000, 99000, -1, QString(), false, this); + m_ui.horizontalLayout->addWidget(m_spinY, 0, 1); + + m_spinWidth = new DragValue(i18nc("Frame width", "W"), m_monitor->render->frameRenderWidth(), 0, 1, 99000, -1, QString(), false, this); + m_ui.horizontalLayout->addWidget(m_spinWidth, 0, 2); + + m_spinHeight = new DragValue(i18nc("Frame height", "H"), m_monitor->render->renderHeight(), 0, 1, 99000, -1, QString(), false, this); + m_ui.horizontalLayout->addWidget(m_spinHeight, 0, 3); + + m_ui.horizontalLayout->setColumnStretch(4, 10); + + QMenu *menu = new QMenu(this); + QAction *adjustSize = new QAction(KIcon("zoom-fit-best"), i18n("Adjust to original size"), this); + connect(adjustSize, SIGNAL(triggered()), this, SLOT(slotAdjustToFrameSize())); + QAction *fitToWidth = new QAction(KIcon("zoom-fit-width"), i18n("Fit to width"), this); + connect(fitToWidth, SIGNAL(triggered()), this, SLOT(slotFitToWidth())); + QAction *fitToHeight = new QAction(KIcon("zoom-fit-height"), i18n("Fit to height"), this); + connect(fitToHeight, SIGNAL(triggered()), this, SLOT(slotFitToHeight())); + + QAction *importKeyframes = new QAction(i18n("Import keyframes from clip"), this); + connect(importKeyframes, SIGNAL(triggered()), this, SIGNAL(importClipKeyframes())); + menu->addAction(importKeyframes); + QAction *resetKeyframes = new QAction(i18n("Reset all keyframes"), this); + connect(resetKeyframes, SIGNAL(triggered()), this, SLOT(slotResetKeyframes())); + menu->addAction(resetKeyframes); + + QAction *resetNextKeyframes = new QAction(i18n("Reset keyframes after cursor"), this); + connect(resetNextKeyframes, SIGNAL(triggered()), this, SLOT(slotResetNextKeyframes())); + menu->addAction(resetNextKeyframes); + QAction *resetPreviousKeyframes = new QAction(i18n("Reset keyframes before cursor"), this); + connect(resetPreviousKeyframes, SIGNAL(triggered()), this, SLOT(slotResetPreviousKeyframes())); + menu->addAction(resetPreviousKeyframes); + menu->addSeparator(); + + QAction *syncTimeline = new QAction(KIcon("insert-link"), i18n("Synchronize with timeline cursor"), this); + syncTimeline->setCheckable(true); + syncTimeline->setChecked(KdenliveSettings::transitionfollowcursor()); + connect(syncTimeline, SIGNAL(toggled(bool)), this, SLOT(slotSetSynchronize(bool))); + menu->addAction(syncTimeline); + + QAction *alignleft = new QAction(KIcon("kdenlive-align-left"), i18n("Align left"), this); + connect(alignleft, SIGNAL(triggered()), this, SLOT(slotMoveLeft())); + QAction *alignhcenter = new QAction(KIcon("kdenlive-align-hor"), i18n("Center horizontally"), this); + connect(alignhcenter, SIGNAL(triggered()), this, SLOT(slotCenterH())); + QAction *alignright = new QAction(KIcon("kdenlive-align-right"), i18n("Align right"), this); + connect(alignright, SIGNAL(triggered()), this, SLOT(slotMoveRight())); + QAction *aligntop = new QAction(KIcon("kdenlive-align-top"), i18n("Align top"), this); + connect(aligntop, SIGNAL(triggered()), this, SLOT(slotMoveTop())); + QAction *alignvcenter = new QAction(KIcon("kdenlive-align-vert"), i18n("Center vertically"), this); + connect(alignvcenter, SIGNAL(triggered()), this, SLOT(slotCenterV())); + QAction *alignbottom = new QAction(KIcon("kdenlive-align-bottom"), i18n("Align bottom"), this); + connect(alignbottom, SIGNAL(triggered()), this, SLOT(slotMoveBottom())); + + m_ui.buttonOptions->setMenu(menu); + m_ui.buttonOptions->setIcon(KIcon("configure")); + m_ui.buttonOptions->setToolTip(i18n("Options")); + m_ui.buttonOptions->setIconSize(iconSize); + + QHBoxLayout *alignLayout = new QHBoxLayout; + alignLayout->setSpacing(0); + QToolButton *alignButton = new QToolButton; + alignButton->setDefaultAction(alignleft); + alignButton->setAutoRaise(true); + alignLayout->addWidget(alignButton); + + alignButton = new QToolButton; + alignButton->setDefaultAction(alignhcenter); + alignButton->setAutoRaise(true); + alignLayout->addWidget(alignButton); + + alignButton = new QToolButton; + alignButton->setDefaultAction(alignright); + alignButton->setAutoRaise(true); + alignLayout->addWidget(alignButton); + + alignButton = new QToolButton; + alignButton->setDefaultAction(aligntop); + alignButton->setAutoRaise(true); + alignLayout->addWidget(alignButton); + + alignButton = new QToolButton; + alignButton->setDefaultAction(alignvcenter); + alignButton->setAutoRaise(true); + alignLayout->addWidget(alignButton); + + alignButton = new QToolButton; + alignButton->setDefaultAction(alignbottom); + alignButton->setAutoRaise(true); + alignLayout->addWidget(alignButton); + + alignButton = new QToolButton; + alignButton->setDefaultAction(adjustSize); + alignButton->setAutoRaise(true); + alignLayout->addWidget(alignButton); + + alignButton = new QToolButton; + alignButton->setDefaultAction(fitToWidth); + alignButton->setAutoRaise(true); + alignLayout->addWidget(alignButton); + + alignButton = new QToolButton; + alignButton->setDefaultAction(fitToHeight); + alignButton->setAutoRaise(true); + alignLayout->addWidget(alignButton); + alignLayout->addStretch(10); + + m_ui.horizontalLayout->addLayout(alignLayout, 1, 0, 1, 4); + //m_ui.horizontalLayout->addStretch(10); + + m_spinSize = new DragValue(i18n("Size"), 100, 2, 1, 99000, -1, i18n("%"), false, this); + m_ui.horizontalLayout2->addWidget(m_spinSize); + + m_opacity = new DragValue(i18n("Opacity"), 100, 0, 0, 100, -1, i18n("%"), true, this); + m_ui.horizontalLayout2->addWidget(m_opacity); + + + if (showRotation) { + m_rotateX = new DragValue(i18n("Rotate X"), 0, 0, -1800, 1800, -1, QString(), true, this); + m_rotateX->setObjectName("rotate_x"); + m_ui.horizontalLayout3->addWidget(m_rotateX); + m_rotateY = new DragValue(i18n("Rotate Y"), 0, 0, -1800, 1800, -1, QString(), true, this); + m_rotateY->setObjectName("rotate_y"); + m_ui.horizontalLayout3->addWidget(m_rotateY); + m_rotateZ = new DragValue(i18n("Rotate Z"), 0, 0, -1800, 1800, -1, QString(), true, this); + m_rotateZ->setObjectName("rotate_z"); + m_ui.horizontalLayout3->addWidget(m_rotateZ); + connect(m_rotateX, SIGNAL(valueChanged(double)), this, SLOT(slotUpdateGeometry())); + connect(m_rotateY, SIGNAL(valueChanged(double)), this, SLOT(slotUpdateGeometry())); + connect(m_rotateZ, SIGNAL(valueChanged(double)), this, SLOT(slotUpdateGeometry())); + } + /* Setup of geometry controls */ - m_ui.buttonMoveLeft->setIcon(KIcon("kdenlive-align-left")); - m_ui.buttonMoveLeft->setToolTip(i18n("Move to left")); - m_ui.buttonCenterH->setIcon(KIcon("kdenlive-align-hor")); - m_ui.buttonCenterH->setToolTip(i18n("Center horizontally")); - m_ui.buttonMoveRight->setIcon(KIcon("kdenlive-align-right")); - m_ui.buttonMoveRight->setToolTip(i18n("Move to right")); - m_ui.buttonMoveTop->setIcon(KIcon("kdenlive-align-top")); - m_ui.buttonMoveTop->setToolTip(i18n("Move to top")); - m_ui.buttonCenterV->setIcon(KIcon("kdenlive-align-vert")); - m_ui.buttonCenterV->setToolTip(i18n("Center vertically")); - m_ui.buttonMoveBottom->setIcon(KIcon("kdenlive-align-bottom")); - m_ui.buttonMoveBottom->setToolTip(i18n("Move to bottom")); - - connect(m_ui.spinX, SIGNAL(valueChanged(int)), this, SLOT(slotSetX(int))); - connect(m_ui.spinY, SIGNAL(valueChanged(int)), this, SLOT(slotSetY(int))); - connect(m_ui.spinWidth, SIGNAL(valueChanged(int)), this, SLOT(slotSetWidth(int))); - connect(m_ui.spinHeight, SIGNAL(valueChanged(int)), this, SLOT(slotSetHeight(int))); - - connect(m_ui.spinSize, SIGNAL(valueChanged(int)), this, SLOT(slotResize(int))); - - connect(m_ui.spinOpacity, SIGNAL(valueChanged(int)), this, SLOT(slotSetOpacity(int))); - connect(m_ui.sliderOpacity, SIGNAL(valueChanged(int)), m_ui.spinOpacity, SLOT(setValue(int))); - - connect(m_ui.buttonMoveLeft, SIGNAL(clicked()), this, SLOT(slotMoveLeft())); + connect(m_spinX, SIGNAL(valueChanged(double)), this, SLOT(slotSetX(double))); + connect(m_spinY, SIGNAL(valueChanged(double)), this, SLOT(slotSetY(double))); + connect(m_spinWidth, SIGNAL(valueChanged(double)), this, SLOT(slotSetWidth(double))); + connect(m_spinHeight, SIGNAL(valueChanged(double)), this, SLOT(slotSetHeight(double))); + + connect(m_spinSize, SIGNAL(valueChanged(double)), this, SLOT(slotResize(double))); + + connect(m_opacity, SIGNAL(valueChanged(double)), this, SLOT(slotSetOpacity(double))); + + /*connect(m_ui.buttonMoveLeft, SIGNAL(clicked()), this, SLOT(slotMoveLeft())); connect(m_ui.buttonCenterH, SIGNAL(clicked()), this, SLOT(slotCenterH())); connect(m_ui.buttonMoveRight, SIGNAL(clicked()), this, SLOT(slotMoveRight())); connect(m_ui.buttonMoveTop, SIGNAL(clicked()), this, SLOT(slotMoveTop())); connect(m_ui.buttonCenterV, SIGNAL(clicked()), this, SLOT(slotCenterV())); - connect(m_ui.buttonMoveBottom, SIGNAL(clicked()), this, SLOT(slotMoveBottom())); + connect(m_ui.buttonMoveBottom, SIGNAL(clicked()), this, SLOT(slotMoveBottom()));*/ /* Setup of configuration controls */ - m_ui.buttonConfig->setIcon(KIcon("system-run")); - m_ui.buttonConfig->setToolTip(i18n("Show/Hide settings")); - m_ui.groupSettings->setHidden(true); - - m_ui.buttonShowScene->setIcon(KIcon("video-display")); - m_ui.buttonShowScene->setToolTip(i18n("Show monitor scene")); - m_ui.buttonDirectUpdate->setIcon(KIcon("transform-scale")); - m_ui.buttonDirectUpdate->setToolTip(i18n("Update parameters while monitor scene changes")); - m_ui.buttonDirectUpdate->setChecked(KdenliveSettings::monitorscene_directupdate()); - - m_ui.buttonZoomFit->setIcon(KIcon("zoom-fit-best")); - m_ui.buttonZoomFit->setToolTip(i18n("Fit zoom to monitor size")); - m_ui.buttonZoomOriginal->setIcon(KIcon("zoom-original")); - m_ui.buttonZoomOriginal->setToolTip(i18n("Original size")); - m_ui.buttonZoomIn->setIcon(KIcon("zoom-in")); - m_ui.buttonZoomIn->setToolTip(i18n("Zoom in")); - m_ui.buttonZoomOut->setIcon(KIcon("zoom-out")); - m_ui.buttonZoomOut->setToolTip(i18n("Zoom out")); - - connect(m_ui.buttonConfig, SIGNAL(toggled(bool)), m_ui.groupSettings, SLOT(setVisible(bool))); - - connect(m_ui.sliderZoom, SIGNAL(valueChanged(int)), m_scene, SLOT(slotZoom(int))); - connect(m_scene, SIGNAL(zoomChanged(int)), m_ui.sliderZoom, SLOT(setValue(int))); - connect(m_ui.buttonZoomFit, SIGNAL(clicked()), m_scene, SLOT(slotZoomFit())); - connect(m_ui.buttonZoomOriginal, SIGNAL(clicked()), m_scene, SLOT(slotZoomOriginal())); - connect(m_ui.buttonZoomIn, SIGNAL(clicked()), m_scene, SLOT(slotZoomIn())); - connect(m_ui.buttonZoomOut, SIGNAL(clicked()), m_scene, SLOT(slotZoomOut())); - m_scene->slotZoomFit(); - - connect(m_ui.buttonShowScene, SIGNAL(toggled(bool)), this, SLOT(slotShowScene(bool))); - connect(m_ui.buttonDirectUpdate, SIGNAL(toggled(bool)), m_scene, SLOT(slotSetDirectUpdate(bool))); - - - connect(m_scene, SIGNAL(actionFinished()), this, SLOT(slotUpdateGeometry())); connect(m_scene, SIGNAL(addKeyframe()), this, SLOT(slotAddKeyframe())); - connect(m_monitor, SIGNAL(renderPosition(int)), this, SLOT(slotCheckMonitorPosition(int))); connect(this, SIGNAL(parameterChanged()), this, SLOT(slotUpdateProperties())); } GeometryWidget::~GeometryWidget() { + m_scene->setEnabled(false); delete m_timePos; delete m_timeline; - m_scene->removeItem(m_rect); + delete m_spinX; + delete m_spinY; + delete m_spinWidth; + delete m_spinHeight; + delete m_opacity; + if (m_rect) { + m_scene->removeItem(m_rect); + delete m_rect; + } + if (m_geomPath) { + m_scene->removeItem(m_geomPath); + delete m_geomPath; + } + delete m_previous; delete m_geometry; - if (m_monitor) - m_monitor->slotEffectScene(false); + m_extraGeometryNames.clear(); + m_extraFactors.clear(); + while (!m_extraGeometries.isEmpty()) { + Mlt::Geometry *g = m_extraGeometries.takeFirst(); + delete g; + } +} + +void GeometryWidget::slotShowPreviousKeyFrame(bool show) +{ + KdenliveSettings::setOnmonitoreffects_geometryshowprevious(show); + slotPositionChanged(-1, false); +} + +void GeometryWidget::slotShowPath(bool show) +{ + KdenliveSettings::setOnmonitoreffects_geometryshowpath(show); + if (m_geomPath) { + if (show) m_scene->addItem(m_geomPath); + else m_scene->removeItem(m_geomPath); + } + slotPositionChanged(-1, false); } void GeometryWidget::updateTimecodeFormat() @@ -179,60 +312,102 @@ QString GeometryWidget::getValue() const return m_geometry->serialise(); } -void GeometryWidget::setupParam(const QDomElement elem, int minframe, int maxframe) +QString GeometryWidget::getExtraValue(const QString &name) const +{ + int ix = m_extraGeometryNames.indexOf(name); + QString val = m_extraGeometries.at(ix)->serialise(); + if (!val.contains("=")) val = val.section('/', 0, 0); + else { + QStringList list = val.split(';', QString::SkipEmptyParts); + val.clear(); + val.append(list.takeFirst().section('/', 0, 0)); + foreach (const QString &value, list) { + val.append(';' + value.section('/', 0, 0)); + } + } + return val; +} + +void GeometryWidget::setupParam(const QDomElement &elem, int minframe, int maxframe) { m_inPoint = minframe; m_outPoint = maxframe; if (m_geometry) - m_geometry->parse(elem.attribute("value").toUtf8().data(), maxframe - minframe, m_monitor->render->renderWidth(), m_monitor->render->renderHeight()); + m_geometry->parse(elem.attribute("value").toUtf8().data(), maxframe - minframe, m_monitor->render->frameRenderWidth(), m_monitor->render->renderHeight()); else - m_geometry = new Mlt::Geometry(elem.attribute("value").toUtf8().data(), maxframe - minframe, m_monitor->render->renderWidth(), m_monitor->render->renderHeight()); + m_geometry = new Mlt::Geometry(elem.attribute("value").toUtf8().data(), maxframe - minframe, m_monitor->render->frameRenderWidth(), m_monitor->render->renderHeight()); if (elem.attribute("fixed") == "1" || maxframe < minframe) { // Keyframes are disabled m_ui.widgetTimeWrapper->setHidden(true); } else { m_ui.widgetTimeWrapper->setHidden(false); - m_timeline->setKeyGeometry(m_geometry, m_outPoint - m_inPoint - 1); - m_timeline->update(); - m_timePos->setRange(0, m_outPoint - m_inPoint - 1); + m_timeline->setKeyGeometry(m_geometry, m_outPoint - m_inPoint); } + m_timePos->setRange(0, m_outPoint - m_inPoint); // no opacity - if (elem.attribute("opacity") == "false") - m_ui.widgetOpacity->setHidden(true); + if (elem.attribute("opacity") == "false") { + m_opacity->setHidden(true); + m_ui.horizontalLayout2->addStretch(2); + } Mlt::GeometryItem item; - m_geometry->fetch(&item, 0); - delete m_rect; - m_rect = new QGraphicsRectItem(QRectF(0, 0, item.w(), item.h())); + if (m_rect) { + m_scene->removeItem(m_rect); + delete m_rect; + } + if (m_geomPath) { + m_scene->removeItem(m_geomPath); + delete m_geomPath; + } + m_rect = new OnMonitorRectItem(QRectF(0, 0, item.w(), item.h()), m_monitor->render->dar()); m_rect->setPos(item.x(), item.y()); m_rect->setZValue(0); - m_rect->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); - - QPen framepen(Qt::SolidLine); - framepen.setColor(Qt::yellow); - m_rect->setPen(framepen); - m_rect->setBrush(Qt::transparent); m_scene->addItem(m_rect); - + connect(m_rect, SIGNAL(changed()), this, SLOT(slotUpdateGeometry())); + m_geomPath = new OnMonitorPathItem(m_monitor->render->dar()); + connect(m_geomPath, SIGNAL(changed()), this, SLOT(slotUpdatePath())); + m_geomPath->setPen(QPen(Qt::red)); + m_geomPath->setPoints(m_geometry); + if (KdenliveSettings::onmonitoreffects_geometryshowpath()) + m_scene->addItem(m_geomPath); + m_scene->centerView(); slotPositionChanged(0, false); - slotCheckMonitorPosition(m_monitor->render->seekFramePosition()); +} + +void GeometryWidget::addParameter(const QDomElement &elem) +{ + Mlt::Geometry *geometry = new Mlt::Geometry(elem.attribute("value").toUtf8().data(), m_outPoint - m_inPoint, m_monitor->render->frameRenderWidth(), m_monitor->render->renderHeight()); + m_extraGeometries.append(geometry); + m_timeline->addGeometry(geometry); + m_extraFactors.append(elem.attribute("factor", "1")); + m_extraGeometryNames.append(elem.attribute("name")); } void GeometryWidget::slotSyncPosition(int relTimelinePos) { // do only sync if this effect is keyframable if (m_timePos->maximum() > 0 && KdenliveSettings::transitionfollowcursor()) { - relTimelinePos = qMax(0, relTimelinePos); - relTimelinePos = qMin(relTimelinePos, m_timePos->maximum()); + relTimelinePos = qBound(0, relTimelinePos, m_timePos->maximum()); if (relTimelinePos != m_timePos->getValue()) slotPositionChanged(relTimelinePos, false); } } +int GeometryWidget::currentPosition() const +{ + return m_inPoint + m_timePos->getValue(); +} + +void GeometryWidget::slotRequestSeek(int pos) +{ + if (KdenliveSettings::transitionfollowcursor()) + emit seekToPos(m_clipPos + pos); +} + void GeometryWidget::slotPositionChanged(int pos, bool seek) { @@ -241,34 +416,72 @@ void GeometryWidget::slotPositionChanged(int pos, bool seek) else m_timePos->setValue(pos); - m_timeline->blockSignals(true); + //m_timeline->blockSignals(true); m_timeline->setValue(pos); - m_timeline->blockSignals(false); + //m_timeline->blockSignals(false); Mlt::GeometryItem item; + Mlt::GeometryItem previousItem; if (m_geometry->fetch(&item, pos) || item.key() == false) { // no keyframe + m_rect->setEnabled(false); m_scene->setEnabled(false); m_ui.widgetGeometry->setEnabled(false); - m_ui.buttonAddDelete->setIcon(KIcon("document-new")); + m_ui.buttonAddDelete->setIcon(KIcon("list-add")); m_ui.buttonAddDelete->setToolTip(i18n("Add keyframe")); } else { // keyframe + m_rect->setEnabled(true); m_scene->setEnabled(true); m_ui.widgetGeometry->setEnabled(true); - m_ui.buttonAddDelete->setIcon(KIcon("edit-delete")); + m_ui.buttonAddDelete->setIcon(KIcon("list-remove")); m_ui.buttonAddDelete->setToolTip(i18n("Delete keyframe")); } + + if (KdenliveSettings::onmonitoreffects_geometryshowprevious() == false || m_geometry->prev_key(&previousItem, pos - 1) || previousItem.frame() == item.frame()) { + if (m_previous) { + m_scene->removeItem(m_previous); + } + } + else if (m_previous && m_previous->scene() && m_previous->data(Qt::UserRole).toInt() == previousItem.frame()) { + // previous frame already here, do nothing + } + else { + if (m_previous == NULL) { + m_previous = new QGraphicsRectItem(0, 0, previousItem.w(), previousItem.h()); + m_previous->setBrush(QColor(200, 200, 0, 20)); + m_previous->setPen(QPen(Qt::white, 0, Qt::DotLine)); + m_previous->setPos(previousItem.x(), previousItem.y()); + m_previous->setZValue(-1); + m_previous->setEnabled(false); + } + else { + m_previous->setPos(previousItem.x(), previousItem.y()); + m_previous->setRect(0, 0, previousItem.w(), previousItem.h()); + } + m_previous->setData(Qt::UserRole, previousItem.frame()); + if (m_previous->scene() == 0) m_scene->addItem(m_previous); + } m_rect->setPos(item.x(), item.y()); m_rect->setRect(0, 0, item.w(), item.h()); - m_ui.spinOpacity->blockSignals(true); - m_ui.sliderOpacity->blockSignals(true); - m_ui.spinOpacity->setValue(item.mix()); - m_ui.sliderOpacity->setValue(item.mix()); - m_ui.spinOpacity->blockSignals(false); - m_ui.sliderOpacity->blockSignals(false); + m_opacity->blockSignals(true); + m_opacity->setValue(item.mix()); + m_opacity->blockSignals(false); + + for (int i = 0; i < m_extraGeometries.count(); ++i) { + Mlt::Geometry *geom = m_extraGeometries.at(i); + QString name = m_extraGeometryNames.at(i); + if (!geom->fetch(&item, pos)) { + DragValue *widget = findChild(name); + if (widget) { + widget->blockSignals(true); + widget->setValue(item.x() * m_extraFactors.at(i).toInt()); + widget->blockSignals(false); + } + } + } slotUpdateProperties(); @@ -295,9 +508,21 @@ void GeometryWidget::slotAddKeyframe(int pos) item.y(rectpos.y()); item.w(r.width()); item.h(r.height()); - item.mix(m_ui.spinOpacity->value()); + item.mix(m_opacity->value()); m_geometry->insert(item); + for (int i = 0; i < m_extraGeometries.count(); ++i) { + Mlt::Geometry *geom = m_extraGeometries.at(i); + QString name = m_extraGeometryNames.at(i); + DragValue *widget = findChild(name); + if (widget) { + Mlt::GeometryItem item2; + item2.frame(pos); + item2.x((double) widget->value() / m_extraFactors.at(i).toInt()); + geom->insert(item2); + } + } + m_timeline->update(); slotPositionChanged(pos, false); emit parameterChanged(); @@ -315,7 +540,17 @@ void GeometryWidget::slotDeleteKeyframe(int pos) } m_geometry->remove(pos); + for (int i = 0; i < m_extraGeometries.count(); ++i) { + Mlt::Geometry *geom = m_extraGeometries.at(i); + geom->remove(pos); + } + m_timeline->update(); + if (m_geomPath && KdenliveSettings::onmonitoreffects_geometryshowpath()) { + m_scene->removeItem(m_geomPath); + m_geomPath->setPoints(m_geometry); + m_scene->addItem(m_geomPath); + } slotPositionChanged(pos, false); emit parameterChanged(); } @@ -326,7 +561,7 @@ void GeometryWidget::slotPreviousKeyframe() // Go to start if no keyframe is found int currentPos = m_timePos->getValue(); int pos = 0; - if(!m_geometry->prev_key(&item, currentPos - 1) && item.frame() < currentPos) + if (!m_geometry->prev_key(&item, currentPos - 1) && item.frame() < currentPos) pos = item.frame(); slotPositionChanged(pos); @@ -352,25 +587,24 @@ void GeometryWidget::slotAddDeleteKeyframe() slotDeleteKeyframe(); } - -void GeometryWidget::slotCheckMonitorPosition(int renderPos) +void GeometryWidget::slotUpdatePath() { - if (m_showScene) { - /* - We do only get the position in timeline if this geometry belongs to a transition, - therefore we need to ways here. - */ - if (m_isEffect) { - emit checkMonitorPosition(renderPos); - } else { - if (renderPos >= m_clipPos && renderPos <= m_clipPos + m_outPoint - m_inPoint) { - if (!m_scene->views().at(0)->isVisible()) - m_monitor->slotEffectScene(true); - } else { - m_monitor->slotEffectScene(false); - } - } + if (!m_geomPath) return; + QList points = m_geomPath->points(); + Mlt::GeometryItem item; + int pos = 0; + int ix = 0; + while (ix < points.count() && !m_geometry->next_key(&item, pos)) { + QPointF center = points.at(ix); + QSizeF size(item.w(), item.h()); + item.x(center.x() - size.width()/2); + item.y(center.y() - size.height()/2); + m_geometry->insert(item); + pos = item.frame() + 1; + ix++; } + slotPositionChanged(-1, false); + emit parameterChanged(); } @@ -378,6 +612,7 @@ void GeometryWidget::slotUpdateGeometry() { Mlt::GeometryItem item; int pos = m_timePos->getValue(); + // get keyframe and make sure it is the correct one if (m_geometry->next_key(&item, pos) || item.frame() != pos) return; @@ -389,6 +624,22 @@ void GeometryWidget::slotUpdateGeometry() item.w(rectSize.width()); item.h(rectSize.height()); m_geometry->insert(item); + + for (int i = 0; i < m_extraGeometries.count(); ++i) { + Mlt::Geometry *geom = m_extraGeometries.at(i); + QString name = m_extraGeometryNames.at(i); + Mlt::GeometryItem item2; + DragValue *widget = findChild(name); + if (widget && !geom->next_key(&item2, pos) && item2.frame() == pos) { + item2.x((double) widget->value() / m_extraFactors.at(i).toInt()); + geom->insert(item2); + } + } + if (m_geomPath && KdenliveSettings::onmonitoreffects_geometryshowpath()) { + m_scene->removeItem(m_geomPath); + m_geomPath->setPoints(m_geometry); + m_scene->addItem(m_geomPath); + } emit parameterChanged(); } @@ -396,79 +647,80 @@ void GeometryWidget::slotUpdateProperties() { QRectF rectSize = m_rect->rect().normalized(); QPointF rectPos = m_rect->pos(); - int size; - if (rectSize.width() / m_monitor->render->dar() < rectSize.height()) - size = (int)((rectSize.width() * 100.0 / m_monitor->render->renderWidth()) + 0.5); + double size; + if (rectSize.width() / m_monitor->render->dar() > rectSize.height()) + size = rectSize.width() * 100.0 / m_monitor->render->frameRenderWidth(); else - size = (int)((rectSize.height() * 100.0 / m_monitor->render->renderHeight()) + 0.5); - - m_ui.spinX->blockSignals(true); - m_ui.spinY->blockSignals(true); - m_ui.spinWidth->blockSignals(true); - m_ui.spinHeight->blockSignals(true); - m_ui.spinSize->blockSignals(true); + size = rectSize.height() * 100.0 / m_monitor->render->renderHeight(); + + m_spinX->blockSignals(true); + m_spinY->blockSignals(true); + m_spinWidth->blockSignals(true); + m_spinHeight->blockSignals(true); + m_spinSize->blockSignals(true); + + m_spinX->setValue(rectPos.x()); + m_spinY->setValue(rectPos.y()); + m_spinWidth->setValue(rectSize.width()); + m_spinHeight->setValue(rectSize.height()); + m_spinSize->setValue(size); + + m_spinX->blockSignals(false); + m_spinY->blockSignals(false); + m_spinWidth->blockSignals(false); + m_spinHeight->blockSignals(false); + m_spinSize->blockSignals(false); +} - m_ui.spinX->setValue(rectPos.x()); - m_ui.spinY->setValue(rectPos.y()); - m_ui.spinWidth->setValue(rectSize.width()); - m_ui.spinHeight->setValue(rectSize.height()); - m_ui.spinSize->setValue(size); - m_ui.spinX->blockSignals(false); - m_ui.spinY->blockSignals(false); - m_ui.spinWidth->blockSignals(false); - m_ui.spinHeight->blockSignals(false); - m_ui.spinSize->blockSignals(false); +void GeometryWidget::slotSetX(double value) +{ + m_rect->setPos(value, m_spinY->value()); + slotUpdateGeometry(); } - -void GeometryWidget::slotSetX(int value) +void GeometryWidget::slotSetY(double value) { - m_rect->setPos(value, m_ui.spinY->value()); + m_rect->setPos(m_spinX->value(), value); slotUpdateGeometry(); } -void GeometryWidget::slotSetY(int value) +void GeometryWidget::slotSetWidth(double value) { - m_rect->setPos(m_ui.spinX->value(), value); + m_rect->setRect(0, 0, value, m_spinHeight->value()); slotUpdateGeometry(); } -void GeometryWidget::slotSetWidth(int value) +void GeometryWidget::slotSetHeight(double value) { - m_rect->setRect(0, 0, value, m_ui.spinHeight->value()); + m_rect->setRect(0, 0, m_spinWidth->value(), value); slotUpdateGeometry(); } -void GeometryWidget::slotSetHeight(int value) +void GeometryWidget::updateMonitorGeometry() { - m_rect->setRect(0, 0, m_ui.spinWidth->value(), value); + m_rect->setRect(0, 0, m_spinWidth->value(), m_spinHeight->value()); slotUpdateGeometry(); } -void GeometryWidget::slotResize(int value) +void GeometryWidget::slotResize(double value) { m_rect->setRect(0, 0, - (int)((m_monitor->render->renderWidth() * value / 100.0) + 0.5), + (int)((m_monitor->render->frameRenderWidth() * value / 100.0) + 0.5), (int)((m_monitor->render->renderHeight() * value / 100.0) + 0.5)); slotUpdateGeometry(); } -void GeometryWidget::slotSetOpacity(int value) +void GeometryWidget::slotSetOpacity(double value) { - m_ui.sliderOpacity->blockSignals(true); - m_ui.sliderOpacity->setValue(value); - m_ui.sliderOpacity->blockSignals(false); - int pos = m_timePos->getValue(); Mlt::GeometryItem item; if (m_geometry->fetch(&item, pos) || item.key() == false) return; item.mix(value); m_geometry->insert(item); - emit parameterChanged(); } @@ -481,13 +733,13 @@ void GeometryWidget::slotMoveLeft() void GeometryWidget::slotCenterH() { - m_rect->setPos((m_monitor->render->renderWidth() - m_rect->rect().width()) / 2, m_rect->pos().y()); + m_rect->setPos((m_monitor->render->frameRenderWidth() - m_rect->rect().width()) / 2, m_rect->pos().y()); slotUpdateGeometry(); } void GeometryWidget::slotMoveRight() { - m_rect->setPos(m_monitor->render->renderWidth() - m_rect->rect().width(), m_rect->pos().y()); + m_rect->setPos(m_monitor->render->frameRenderWidth() - m_rect->rect().width(), m_rect->pos().y()); slotUpdateGeometry(); } @@ -517,13 +769,237 @@ void GeometryWidget::slotSetSynchronize(bool sync) emit seekToPos(m_clipPos + m_timePos->getValue()); } -void GeometryWidget::slotShowScene(bool show) +void GeometryWidget::setFrameSize(const QPoint &size) { - m_showScene = show; - if (!m_showScene) - m_monitor->slotEffectScene(false); - else - slotCheckMonitorPosition(m_monitor->render->seekFramePosition()); + m_frameSize = size; +} + +void GeometryWidget::slotAdjustToFrameSize() +{ + if (m_frameSize == QPoint() || m_frameSize.x() == 0 || m_frameSize.y() == 0) { + m_frameSize = QPoint(m_monitor->render->frameRenderWidth(), m_monitor->render->renderHeight()); + } + m_spinWidth->blockSignals(true); + m_spinHeight->blockSignals(true); + m_spinWidth->setValue((int) (m_frameSize.x() / m_monitor->render->sar() + 0.5)); + m_spinHeight->setValue(m_frameSize.y()); + m_spinWidth->blockSignals(false); + m_spinHeight->blockSignals(false); + updateMonitorGeometry(); +} + +void GeometryWidget::slotFitToWidth() +{ + if (m_frameSize == QPoint() || m_frameSize.x() == 0 || m_frameSize.y() == 0) { + m_frameSize = QPoint(m_monitor->render->frameRenderWidth(), m_monitor->render->renderHeight()); + } + double factor = (double) m_monitor->render->frameRenderWidth() / m_frameSize.x() * m_monitor->render->sar(); + m_spinWidth->blockSignals(true); + m_spinHeight->blockSignals(true); + m_spinHeight->setValue((int) (m_frameSize.y() * factor + 0.5)); + m_spinWidth->setValue(m_monitor->render->frameRenderWidth()); + m_spinWidth->blockSignals(false); + m_spinHeight->blockSignals(false); + updateMonitorGeometry(); +} + +void GeometryWidget::slotFitToHeight() +{ + if (m_frameSize == QPoint() || m_frameSize.x() == 0 || m_frameSize.y() == 0) { + m_frameSize = QPoint(m_monitor->render->frameRenderWidth(), m_monitor->render->renderHeight()); + } + double factor = (double) m_monitor->render->renderHeight() / m_frameSize.y(); + m_spinWidth->blockSignals(true); + m_spinHeight->blockSignals(true); + m_spinHeight->setValue(m_monitor->render->renderHeight()); + m_spinWidth->setValue((int) (m_frameSize.x() / m_monitor->render->sar() * factor + 0.5)); + m_spinWidth->blockSignals(false); + m_spinHeight->blockSignals(false); + updateMonitorGeometry(); +} + +void GeometryWidget::slotResetKeyframes() +{ + // Delete existing keyframes + Mlt::GeometryItem item; + while (!m_geometry->next_key(&item, 1)) { + m_geometry->remove(item.frame()); + } + + // Delete extra geometry keyframes too + for (int i = 0; i < m_extraGeometries.count(); ++i) { + Mlt::Geometry *geom = m_extraGeometries.at(i); + while (!geom->next_key(&item, 1)) { + geom->remove(item.frame()); + } + } + + // Create neutral first keyframe + item.frame(0); + item.x(0); + item.y(0); + item.w(m_monitor->render->frameRenderWidth()); + item.h(m_monitor->render->renderHeight()); + item.mix(100); + m_geometry->insert(item); + m_timeline->setKeyGeometry(m_geometry, m_outPoint - m_inPoint); + if (m_geomPath && KdenliveSettings::onmonitoreffects_geometryshowpath()) { + m_scene->removeItem(m_geomPath); + m_geomPath->setPoints(m_geometry); + m_scene->addItem(m_geomPath); + } + slotPositionChanged(-1, false); + emit parameterChanged(); +} + +void GeometryWidget::slotResetNextKeyframes() +{ + // Delete keyframes after cursor pos + Mlt::GeometryItem item; + int pos = m_timePos->getValue(); + while (!m_geometry->next_key(&item, pos)) { + m_geometry->remove(item.frame()); + } + + // Delete extra geometry keyframes too + for (int i = 0; i < m_extraGeometries.count(); ++i) { + Mlt::Geometry *geom = m_extraGeometries.at(i); + while (!geom->next_key(&item, pos)) { + geom->remove(item.frame()); + } + } + + // Make sure we have at least one keyframe + if (m_geometry->next_key(&item, 0)) { + item.frame(0); + item.x(0); + item.y(0); + item.w(m_monitor->render->frameRenderWidth()); + item.h(m_monitor->render->renderHeight()); + item.mix(100); + m_geometry->insert(item); + } + m_timeline->setKeyGeometry(m_geometry, m_outPoint - m_inPoint); + if (m_geomPath && KdenliveSettings::onmonitoreffects_geometryshowpath()) { + m_scene->removeItem(m_geomPath); + m_geomPath->setPoints(m_geometry); + m_scene->addItem(m_geomPath); + } + slotPositionChanged(-1, false); + emit parameterChanged(); +} + +void GeometryWidget::slotResetPreviousKeyframes() +{ + // Delete keyframes before cursor pos + Mlt::GeometryItem item; + int pos = 0; + while (!m_geometry->next_key(&item, pos) && pos < m_timePos->getValue()) { + pos = item.frame() + 1; + m_geometry->remove(item.frame()); + } + + // Delete extra geometry keyframes too + for (int i = 0; i < m_extraGeometries.count(); ++i) { + Mlt::Geometry *geom = m_extraGeometries.at(i); + pos = 0; + while (!geom->next_key(&item, pos) && pos < m_timePos->getValue()) { + pos = item.frame() + 1; + geom->remove(item.frame()); + } + } + + // Make sure we have at least one keyframe + if (!m_geometry->next_key(&item, 0)) { + item.frame(0); + /*item.x(0); + item.y(0); + item.w(m_monitor->render->frameRenderWidth()); + item.h(m_monitor->render->renderHeight()); + item.mix(100);*/ + m_geometry->insert(item); + } + else { + item.frame(0); + item.x(0); + item.y(0); + item.w(m_monitor->render->frameRenderWidth()); + item.h(m_monitor->render->renderHeight()); + item.mix(100); + m_geometry->insert(item); + } + m_timeline->setKeyGeometry(m_geometry, m_outPoint - m_inPoint); + if (m_geomPath && KdenliveSettings::onmonitoreffects_geometryshowpath()) { + m_scene->removeItem(m_geomPath); + m_geomPath->setPoints(m_geometry); + m_scene->addItem(m_geomPath); + } + slotPositionChanged(-1, false); + emit parameterChanged(); +} + +void GeometryWidget::importKeyframes(const QString &data, int maximum) +{ + QStringList list = data.split(';', QString::SkipEmptyParts); + if (list.isEmpty()) return; + QPoint screenSize = m_frameSize; + if (screenSize == QPoint() || screenSize.x() == 0 || screenSize.y() == 0) { + screenSize = QPoint(m_monitor->render->frameRenderWidth(), m_monitor->render->renderHeight()); + } + // Clear existing keyframes + Mlt::GeometryItem item; + + while (!m_geometry->next_key(&item, 0)) { + m_geometry->remove(item.frame()); + } + + int offset = 1; + if (maximum > 0 && list.count() > maximum) { + offset = list.count() / maximum; + } + for (int i = 0; i < list.count(); i += offset) { + QString geom = list.at(i); + if (geom.contains('=')) { + item.frame(geom.section('=', 0, 0).toInt()); + geom = geom.section('=', 1); + } + else item.frame(0); + if (geom.contains('/')) { + item.x(geom.section('/', 0, 0).toDouble()); + item.y(geom.section('/', 1, 1).section(':', 0, 0).toDouble()); + } + else { + item.x(0); + item.y(0); + } + if (geom.contains('x')) { + item.w(geom.section('x', 0, 0).section(':', 1, 1).toDouble()); + item.h(geom.section('x', 1, 1).section(':', 0, 0).toDouble()); + } + else { + item.w(screenSize.x()); + item.h(screenSize.y()); + } + //TODO: opacity + item.mix(100); + m_geometry->insert(item); + } + m_timeline->setKeyGeometry(m_geometry, m_outPoint - m_inPoint); + if (m_geomPath && KdenliveSettings::onmonitoreffects_geometryshowpath()) { + m_scene->removeItem(m_geomPath); + m_geomPath->setPoints(m_geometry); + m_scene->addItem(m_geomPath); + } + slotPositionChanged(-1, false); + emit parameterChanged(); +} + +void GeometryWidget::slotUpdateRange(int inPoint, int outPoint) +{ + m_inPoint = inPoint; + m_outPoint = outPoint; + m_timeline->setKeyGeometry(m_geometry, m_outPoint - m_inPoint); + m_timePos->setRange(0, m_outPoint - m_inPoint); } #include "geometrywidget.moc"