X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fgeometrywidget.cpp;h=44377e0fdfc57f113ef6cb931fe74f031cbd3b66;hb=b6d6c25f1bd07f11a0ceaf32a3a5bcaeab367336;hp=d654a7995eb9163674382b49472424b58c2cef22;hpb=92abe16daaa5167ca9dff9c30aae3208d8221636;p=kdenlive diff --git a/src/geometrywidget.cpp b/src/geometrywidget.cpp index d654a799..44377e0f 100644 --- a/src/geometrywidget.cpp +++ b/src/geometrywidget.cpp @@ -26,6 +26,7 @@ #include "monitorscene.h" #include "monitoreditwidget.h" #include "onmonitoritems/onmonitorrectitem.h" +#include "onmonitoritems/onmonitorpathitem.h" #include "kdenlivesettings.h" #include "dragvalue.h" @@ -37,7 +38,7 @@ -GeometryWidget::GeometryWidget(Monitor* monitor, Timecode timecode, int clipPos, bool isEffect, bool showRotation, QWidget* parent): +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)), @@ -46,6 +47,7 @@ GeometryWidget::GeometryWidget(Monitor* monitor, Timecode timecode, int clipPos, m_outPoint(1), m_isEffect(isEffect), m_rect(NULL), + m_geomPath(NULL), m_previous(NULL), m_geometry(NULL), m_showScene(true), @@ -55,16 +57,16 @@ GeometryWidget::GeometryWidget(Monitor* monitor, Timecode timecode, int clipPos, 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()); - edit->showVisibilityButton(true); 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); @@ -80,24 +82,18 @@ GeometryWidget::GeometryWidget(Monitor* monitor, Timecode timecode, int clipPos, m_ui.buttonNext->setIcon(KIcon("media-skip-forward")); m_ui.buttonNext->setToolTip(i18n("Go to next keyframe")); m_ui.buttonNext->setIconSize(iconSize); - m_ui.buttonAddDelete->setIcon(KIcon("document-new")); + 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()); - m_ui.buttonSync->setIconSize(iconSize); - - 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); @@ -111,37 +107,54 @@ GeometryWidget::GeometryWidget(Monitor* monitor, Timecode timecode, int clipPos, 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(i18n("Adjust to original size"), this); + QAction *adjustSize = new QAction(KIcon("zoom-fit-best"), i18n("Adjust to original size"), this); connect(adjustSize, SIGNAL(triggered()), this, SLOT(slotAdjustToFrameSize())); - menu->addAction(adjustSize); - QAction *fitToWidth = new QAction(i18n("Fit to width"), this); + QAction *fitToWidth = new QAction(KIcon("zoom-fit-width"), i18n("Fit to width"), this); connect(fitToWidth, SIGNAL(triggered()), this, SLOT(slotFitToWidth())); - menu->addAction(fitToWidth); - QAction *fitToHeight = new QAction(i18n("Fit to height"), this); + QAction *fitToHeight = new QAction(KIcon("zoom-fit-height"), i18n("Fit to height"), this); connect(fitToHeight, SIGNAL(triggered()), this, SLOT(slotFitToHeight())); - menu->addAction(fitToHeight); + + 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())); - menu->addAction(alignleft); QAction *alignhcenter = new QAction(KIcon("kdenlive-align-hor"), i18n("Center horizontally"), this); connect(alignhcenter, SIGNAL(triggered()), this, SLOT(slotCenterH())); - menu->addAction(alignhcenter); QAction *alignright = new QAction(KIcon("kdenlive-align-right"), i18n("Align right"), this); connect(alignright, SIGNAL(triggered()), this, SLOT(slotMoveRight())); - menu->addAction(alignright); QAction *aligntop = new QAction(KIcon("kdenlive-align-top"), i18n("Align top"), this); connect(aligntop, SIGNAL(triggered()), this, SLOT(slotMoveTop())); - menu->addAction(aligntop); QAction *alignvcenter = new QAction(KIcon("kdenlive-align-vert"), i18n("Center vertically"), this); connect(alignvcenter, SIGNAL(triggered()), this, SLOT(slotCenterV())); - menu->addAction(alignvcenter); QAction *alignbottom = new QAction(KIcon("kdenlive-align-bottom"), i18n("Align bottom"), this); connect(alignbottom, SIGNAL(triggered()), this, SLOT(slotMoveBottom())); - menu->addAction(alignbottom); + 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); @@ -174,6 +187,21 @@ GeometryWidget::GeometryWidget(Monitor* monitor, Timecode timecode, int clipPos, 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); @@ -210,7 +238,7 @@ GeometryWidget::GeometryWidget(Monitor* monitor, Timecode timecode, int clipPos, 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_spinSize, SIGNAL(valueChanged(double)), this, SLOT(slotResize(double))); connect(m_opacity, SIGNAL(valueChanged(double)), this, SLOT(slotSetOpacity(double))); @@ -226,16 +254,13 @@ GeometryWidget::GeometryWidget(Monitor* monitor, Timecode timecode, int clipPos, Setup of configuration controls */ - connect(edit, SIGNAL(showEdit(bool)), this, SLOT(slotShowScene(bool))); - 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(true); + m_scene->setEnabled(false); delete m_timePos; delete m_timeline; delete m_spinX; @@ -243,9 +268,15 @@ GeometryWidget::~GeometryWidget() delete m_spinWidth; delete m_spinHeight; delete m_opacity; - m_scene->removeItem(m_rect); - if (m_rect) delete m_rect; - if (m_previous) delete m_previous; + 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; m_extraGeometryNames.clear(); m_extraFactors.clear(); @@ -253,10 +284,6 @@ GeometryWidget::~GeometryWidget() Mlt::Geometry *g = m_extraGeometries.takeFirst(); delete g; } - if (m_monitor) { - m_monitor->getEffectEdit()->showVisibilityButton(false); - m_monitor->slotShowEffectScene(false); - } } void GeometryWidget::slotShowPreviousKeyFrame(bool show) @@ -265,6 +292,16 @@ void GeometryWidget::slotShowPreviousKeyFrame(bool 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() { m_timePos->slotUpdateTimeCodeFormat(); @@ -284,18 +321,17 @@ QString GeometryWidget::getExtraValue(const QString &name) const QStringList list = val.split(';', QString::SkipEmptyParts); val.clear(); val.append(list.takeFirst().section('/', 0, 0)); - foreach (const QString value, list) { + foreach (const QString &value, list) { val.append(';' + value.section('/', 0, 0)); } } return val; } -void GeometryWidget::setupParam(const QDomElement elem, int minframe, int maxframe) +void GeometryWidget::setupParam(const QDomElement &elem, int minframe, int maxframe) { m_inPoint = minframe; m_outPoint = maxframe; - m_scene->cleanup(); if (m_geometry) m_geometry->parse(elem.attribute("value").toUtf8().data(), maxframe - minframe, m_monitor->render->frameRenderWidth(), m_monitor->render->renderHeight()); @@ -308,9 +344,8 @@ void GeometryWidget::setupParam(const QDomElement elem, int minframe, int maxfra } else { m_ui.widgetTimeWrapper->setHidden(false); m_timeline->setKeyGeometry(m_geometry, m_outPoint - m_inPoint); - m_timeline->update(); - m_timePos->setRange(0, m_outPoint - m_inPoint); } + m_timePos->setRange(0, m_outPoint - m_inPoint); // no opacity if (elem.attribute("opacity") == "false") { @@ -319,27 +354,37 @@ void GeometryWidget::setupParam(const QDomElement elem, int minframe, int maxfra } Mlt::GeometryItem item; - m_geometry->fetch(&item, 0); - delete m_rect; + 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_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) +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")); - //kDebug()<<"ADDED PARAM: "<getValue(); +} + +void GeometryWidget::slotRequestSeek(int pos) +{ + if (KdenliveSettings::transitionfollowcursor()) + emit seekToPos(m_clipPos + pos); +} + void GeometryWidget::slotPositionChanged(int pos, bool seek) { @@ -360,9 +416,9 @@ 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; @@ -371,14 +427,14 @@ void GeometryWidget::slotPositionChanged(int pos, bool seek) 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")); } @@ -414,7 +470,7 @@ void GeometryWidget::slotPositionChanged(int pos, bool seek) m_opacity->setValue(item.mix()); m_opacity->blockSignals(false); - for (int i = 0; i < m_extraGeometries.count(); i++) { + 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)) { @@ -455,7 +511,7 @@ void GeometryWidget::slotAddKeyframe(int pos) item.mix(m_opacity->value()); m_geometry->insert(item); - for (int i = 0; i < m_extraGeometries.count(); i++) { + 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); @@ -484,12 +540,17 @@ void GeometryWidget::slotDeleteKeyframe(int pos) } m_geometry->remove(pos); - for (int i = 0; i < m_extraGeometries.count(); i++) { + 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(); } @@ -526,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 two 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->slotShowEffectScene(true); - } else { - m_monitor->slotShowEffectScene(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(); } @@ -565,7 +625,7 @@ void GeometryWidget::slotUpdateGeometry() item.h(rectSize.height()); m_geometry->insert(item); - for (int i = 0; i < m_extraGeometries.count(); i++) { + 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; @@ -575,6 +635,11 @@ void GeometryWidget::slotUpdateGeometry() 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(); } @@ -704,16 +769,7 @@ void GeometryWidget::slotSetSynchronize(bool sync) emit seekToPos(m_clipPos + m_timePos->getValue()); } -void GeometryWidget::slotShowScene(bool show) -{ - m_showScene = show; - if (!m_showScene) - m_monitor->slotShowEffectScene(false); - else - slotCheckMonitorPosition(m_monitor->render->seekFramePosition()); -} - -void GeometryWidget::setFrameSize(QPoint size) +void GeometryWidget::setFrameSize(const QPoint &size) { m_frameSize = size; } @@ -762,4 +818,188 @@ void GeometryWidget::slotFitToHeight() 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"