From: Ed Rogalsky Date: Mon, 5 Nov 2012 06:44:39 +0000 (+0100) Subject: Merge branch 'master' into feature/pkey X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=563a57ad4786d528755a99973cf3bffbdce96bcf;hp=ba471399b55c3b761ccc7aa5008c25bd43cfe90b;p=kdenlive Merge branch 'master' into feature/pkey --- diff --git a/effects/automask.xml b/effects/automask.xml index ae68503a..7651d394 100644 --- a/effects/automask.xml +++ b/effects/automask.xml @@ -27,7 +27,7 @@ Obscure - + motion_vector_list diff --git a/src/abstractclipitem.cpp b/src/abstractclipitem.cpp index 1a0adfd0..713bbcfb 100644 --- a/src/abstractclipitem.cpp +++ b/src/abstractclipitem.cpp @@ -38,7 +38,8 @@ AbstractClipItem::AbstractClipItem(const ItemInfo &info, const QRectF& rect, dou m_selectedKeyframe(0), m_keyframeFactor(1), m_keyframeOffset(0), - m_fps(fps) + m_fps(fps), + m_isMainSelectedClip(false) { setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); #if QT_VERSION >= 0x040600 @@ -126,7 +127,7 @@ void AbstractClipItem::updateRectGeometry() setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); } -void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit) +void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit, bool /*emitChange*/) { GenTime durationDiff = GenTime(posx, m_fps) - m_info.startPos; if (durationDiff == GenTime()) return; @@ -189,7 +190,7 @@ void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit) }*/ } -void AbstractClipItem::resizeEnd(int posx) +void AbstractClipItem::resizeEnd(int posx, bool /*emitChange*/) { GenTime durationDiff = GenTime(posx, m_fps) - endPos(); if (durationDiff == GenTime()) return; @@ -508,4 +509,15 @@ int AbstractClipItem::itemOffset() return 0; } +void AbstractClipItem::setMainSelectedClip(bool selected) +{ + if (selected == m_isMainSelectedClip) return; + m_isMainSelectedClip = selected; + update(); +} + +bool AbstractClipItem::isMainSelectedClip() +{ + return m_isMainSelectedClip; +} diff --git a/src/abstractclipitem.h b/src/abstractclipitem.h index 1cdcf0cb..3e6a7ad9 100644 --- a/src/abstractclipitem.h +++ b/src/abstractclipitem.h @@ -82,16 +82,21 @@ public: /** @brief Resizes the clip from the start. * @param posx Absolute position of new in point * @param hasSizeLimit (optional) Whether the clip has a maximum size */ - virtual void resizeStart(int posx, bool hasSizeLimit = true); + virtual void resizeStart(int posx, bool hasSizeLimit = true, bool emitChange = true); /** @brief Resizes the clip from the end. * @param posx Absolute position of new out point */ - virtual void resizeEnd(int posx); + virtual void resizeEnd(int posx, bool emitChange = true); virtual double fps() const; virtual void updateFps(double fps); virtual GenTime maxDuration() const; virtual void setCropStart(GenTime pos); + /** @brief Set this clip as the main selected clip (or not). */ + void setMainSelectedClip(bool selected); + /** @brief Is this clip selected as the main clip. */ + bool isMainSelectedClip(); + protected: ItemInfo m_info; /** The position of the current keyframe when it has moved */ @@ -112,6 +117,8 @@ protected: /** The (keyframe) parameter that is visible and editable in timeline (on the clip) */ int m_visibleParam; double m_fps; + /** @brief True if this is the last clip the user selected */ + bool m_isMainSelectedClip; /** @brief Draw the keyframes of a clip * @param painter The painter device for the clip * @param limitedKeyFrames The keyframes can be of type "keyframe" or "simplekeyframe". In the diff --git a/src/clipitem.cpp b/src/clipitem.cpp index 6553c6bd..8670aed3 100644 --- a/src/clipitem.cpp +++ b/src/clipitem.cpp @@ -60,8 +60,7 @@ ClipItem::ClipItem(DocClipBase *clip, ItemInfo info, double fps, double speed, i m_speed(speed), m_strobe(strobe), m_framePixelWidth(0), - m_limitedKeyFrames(false), - m_isMainSelectedClip(false) + m_limitedKeyFrames(false) { setZValue(2); m_effectList = EffectsList(true); @@ -1251,7 +1250,7 @@ void ClipItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) } */ -void ClipItem::resizeStart(int posx, bool /*size*/) +void ClipItem::resizeStart(int posx, bool /*size*/, bool emitChange) { bool sizeLimit = false; if (clipType() != IMAGE && clipType() != COLOR && clipType() != TEXT) { @@ -1274,9 +1273,15 @@ void ClipItem::resizeStart(int posx, bool /*size*/) m_startThumbTimer.start(150); } } + if (emitChange) slotUpdateRange(); } -void ClipItem::resizeEnd(int posx) +void ClipItem::slotUpdateRange() +{ + if (m_isMainSelectedClip) emit updateRange(); +} + +void ClipItem::resizeEnd(int posx, bool emitChange) { const int max = (startPos() - cropStart() + maxDuration()).frames(m_fps); if (posx > max && maxDuration() != GenTime()) posx = max; @@ -1295,6 +1300,7 @@ void ClipItem::resizeEnd(int posx) m_endThumbTimer.start(150); } } + if (emitChange) slotUpdateRange(); } //virtual @@ -2087,17 +2093,6 @@ void ClipItem::slotGotThumbsCache() update(); } -void ClipItem::setMainSelectedClip(bool selected) -{ - if (selected == m_isMainSelectedClip) return; - m_isMainSelectedClip = selected; - update(); -} - -bool ClipItem::isMainSelectedClip() -{ - return m_isMainSelectedClip; -} #include "clipitem.moc" diff --git a/src/clipitem.h b/src/clipitem.h index 47434366..74e9255a 100644 --- a/src/clipitem.h +++ b/src/clipitem.h @@ -52,8 +52,8 @@ public: const QStyleOptionGraphicsItem *option, QWidget *); virtual int type() const; - void resizeStart(int posx, bool size = true); - void resizeEnd(int posx); + void resizeStart(int posx, bool size = true, bool emitChange = true); + void resizeEnd(int posx, bool emitChange = true); OPERATIONTYPE operationMode(QPointF pos); static int itemHeight(); const QString clipProducer() const; @@ -189,10 +189,6 @@ public: /** @brief Get a free index value for effect group. */ int nextFreeEffectGroupIndex() const; - /** @brief Set this clip as the main selected clip (or not). */ - void setMainSelectedClip(bool selected); - /** @brief Is this clip selected as the main clip. */ - bool isMainSelectedClip(); protected: //virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event); @@ -242,8 +238,6 @@ private: /** @brief Keyframes type can be "keyframe" or "simplekeyframe" which have to be painted differently. * True if keyframe type is "keyframe" */ bool m_limitedKeyFrames; - /** @brief True if this is the last clip the user selected */ - bool m_isMainSelectedClip; private slots: void slotGetStartThumb(); @@ -261,10 +255,11 @@ public slots: void slotFetchThumbs(); void slotSetStartThumb(const QPixmap pix); void slotSetEndThumb(const QPixmap pix); + void slotUpdateRange(); signals: - void getThumb(int, int); void prepareAudioThumb(double, int, int, int); + void updateRange(); }; #endif diff --git a/src/cornerswidget.cpp b/src/cornerswidget.cpp index f985cf4b..1c2326bf 100644 --- a/src/cornerswidget.cpp +++ b/src/cornerswidget.cpp @@ -246,4 +246,5 @@ void CornersWidget::slotInsertKeyframe() keyframe_list->selectRow(row); } + #include "cornerswidget.moc" diff --git a/src/customtrackview.cpp b/src/customtrackview.cpp index 166990f4..6e9706fe 100644 --- a/src/customtrackview.cpp +++ b/src/customtrackview.cpp @@ -459,7 +459,7 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event) if (parent) parent->resizeStart((int)(snappedPos - m_dragItemInfo.startPos.frames(m_document->fps()))); } else { - m_dragItem->resizeStart((int)(snappedPos)); + m_dragItem->resizeStart((int)(snappedPos), true, false); } QString crop = m_document->timecode().getDisplayTimecode(m_dragItem->cropStart(), KdenliveSettings::frametimecode()); QString duration = m_document->timecode().getDisplayTimecode(m_dragItem->cropDuration(), KdenliveSettings::frametimecode()); @@ -472,7 +472,7 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event) if (parent) parent->resizeEnd((int)(snappedPos - m_dragItemInfo.endPos.frames(m_document->fps()))); } else { - m_dragItem->resizeEnd((int)(snappedPos)); + m_dragItem->resizeEnd((int)(snappedPos), false); } QString duration = m_document->timecode().getDisplayTimecode(m_dragItem->cropDuration(), KdenliveSettings::frametimecode()); QString offset = m_document->timecode().getDisplayTimecode(m_dragItem->cropDuration() - m_dragItemInfo.cropDuration, KdenliveSettings::frametimecode()); @@ -2770,7 +2770,9 @@ void CustomTrackView::adjustTimelineClips(EDITMODE mode, ClipItem *item, ItemInf new RazorClipCommand(this, clipInfo, info.startPos, false, command); new ResizeClipCommand(this, dupInfo, newdupInfo, false, false, command); ClipItem *dup = cutClip(clipInfo, info.startPos, true, false); - if (dup) dup->resizeStart(info.endPos.frames(m_document->fps())); + if (dup) { + dup->resizeStart(info.endPos.frames(m_document->fps())); + } } else { ItemInfo newclipInfo = clip->info(); newclipInfo.endPos = info.startPos; @@ -3943,6 +3945,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) } } else { prepareResizeClipStart(m_dragItem, m_dragItemInfo, m_dragItem->startPos().frames(m_document->fps())); + if (m_dragItem->type() == AVWIDGET) static_cast (m_dragItem)->slotUpdateRange(); } } else if (m_operationMode == RESIZEEND && m_dragItem->endPos() != m_dragItemInfo.endPos) { // resize end @@ -3968,6 +3971,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) } } else { prepareResizeClipEnd(m_dragItem, m_dragItemInfo, m_dragItem->endPos().frames(m_document->fps())); + if (m_dragItem->type() == AVWIDGET) static_cast (m_dragItem)->slotUpdateRange(); } } else if (m_operationMode == FADEIN) { // resize fade in effect @@ -4881,8 +4885,9 @@ void CustomTrackView::resizeClip(const ItemInfo &start, const ItemInfo &end, boo ItemInfo clipinfo = item->info(); clipinfo.track = m_document->tracksCount() - clipinfo.track; bool success = m_document->renderer()->mltResizeClipStart(clipinfo, end.startPos - clipinfo.startPos); - if (success) + if (success) { item->resizeStart((int) end.startPos.frames(m_document->fps())); + } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage); } else { diff --git a/src/docclipbase.cpp b/src/docclipbase.cpp index 5f2f01a1..5d41cc04 100644 --- a/src/docclipbase.cpp +++ b/src/docclipbase.cpp @@ -32,12 +32,14 @@ #include #include +#include #include #include #include #include +#include DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QString &id) : QObject(), @@ -1276,21 +1278,56 @@ QImage DocClipBase::extractImage(int frame, int width, int height) return m_thumbProd->extractImage(frame, width, height); } -void DocClipBase::setAnalysisData(const QString &name, const QString &data) +void DocClipBase::setAnalysisData(const QString &name, const QString &data, int offset) { if (data.isEmpty()) m_analysisdata.remove(name); else { if (m_analysisdata.contains(name)) { - int i = 1; - QString newname = name + " " + QString::number(i); - while (m_analysisdata.contains(newname)) { - i++; - newname = name + " " + QString::number(i); + if (KMessageBox::questionYesNo(kapp->activeWindow(), i18n("Clip already contains analysis data %1", name), QString(), KGuiItem(i18n("Merge")), KGuiItem(i18n("Add"))) == KMessageBox::Yes) { + // Merge data + Mlt::Profile *profile = m_baseTrackProducers.at(0)->profile(); + Mlt::Geometry geometry(m_analysisdata.value(name).toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height()); + Mlt::Geometry newGeometry(data.toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height()); + Mlt::GeometryItem item; + int pos = 0; + while (!newGeometry.next_key(&item, pos)) { + pos = item.frame(); + item.frame(pos + offset); + pos++; + geometry.insert(item); + } + m_analysisdata.insert(name, geometry.serialise()); + } + else { + // Add data with another name + int i = 1; + QString newname = name + " " + QString::number(i); + while (m_analysisdata.contains(newname)) { + i++; + newname = name + " " + QString::number(i); + } + m_analysisdata.insert(newname, geometryWithOffset(data, offset)); } - m_analysisdata.insert(newname, data); } - else m_analysisdata.insert(name, data); + else m_analysisdata.insert(name, geometryWithOffset(data, offset)); + } +} + +const QString DocClipBase::geometryWithOffset(QString data, int offset) +{ + if (offset == 0) return data; + Mlt::Profile *profile = m_baseTrackProducers.at(0)->profile(); + Mlt::Geometry geometry(data.toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height()); + Mlt::Geometry newgeometry("", m_properties.value("duration").toInt(), profile->width(), profile->height()); + Mlt::GeometryItem item; + int pos = 0; + while (!geometry.next_key(&item, pos)) { + pos = item.frame(); + item.frame(pos + offset); + pos++; + newgeometry.insert(item); } + return newgeometry.serialise(); } QMap DocClipBase::analysisData() const diff --git a/src/docclipbase.h b/src/docclipbase.h index e6e722c2..6ac74221 100644 --- a/src/docclipbase.h +++ b/src/docclipbase.h @@ -200,7 +200,7 @@ Q_OBJECT public: void cleanupProducers(); bool isClean() const; bool getAudioThumbs(); - void setAnalysisData(const QString &name, const QString &data); + void setAnalysisData(const QString &name, const QString &data, int offset = 0); QMap analysisData() const; int lastSeekPosition; /** Cache for every audio Frame with 10 Bytes */ @@ -256,6 +256,8 @@ private: // Private attributes void adjustProducerProperties(Mlt::Producer *prod, const QString &id, bool mute, bool blind); /** @brief Create another instance of a producer. */ Mlt::Producer *cloneProducer(Mlt::Producer *source); + /** @brief Offset all keyframes of a geometry. */ + const QString geometryWithOffset(QString data, int offset); public slots: diff --git a/src/dvdwizardvob.cpp b/src/dvdwizardvob.cpp index 0d99f697..9cdfd8d0 100644 --- a/src/dvdwizardvob.cpp +++ b/src/dvdwizardvob.cpp @@ -34,6 +34,7 @@ #include #include #include +#include DvdTreeWidget::DvdTreeWidget(QWidget *parent) : QTreeWidget(parent) @@ -201,11 +202,11 @@ void DvdWizardVob::slotAddVobFile(KUrl url, const QString &chapters, bool checkF item->setData(1, Qt::UserRole, playTime); int standard = -1; int aspect = profile.dar() * 100; - if (profile.height() == 576) { + if (profile.height() == 576 && profile.fps() == 25.0) { if (aspect > 150) standard = 1; else standard = 0; } - else if (profile.height() == 480) { + else if (profile.height() == 480 && qAbs(profile.fps() - 30000.0 / 1001) < 0.2) { if (aspect > 150) standard = 3; else standard = 2; } @@ -226,6 +227,7 @@ void DvdWizardVob::slotAddVobFile(KUrl url, const QString &chapters, bool checkF default: standardName = i18n("Unknown"); } + standardName.append(QString(" | %1x%2, %3fps").arg(profile.width()).arg(profile.height()).arg(profile.fps())); item->setData(0, Qt::UserRole, standardName); item->setData(0, Qt::UserRole + 1, standard); item->setData(0, Qt::UserRole + 2, QSize(profile.dar() * profile.height(), profile.height())); diff --git a/src/effectstack/collapsibleeffect.cpp b/src/effectstack/collapsibleeffect.cpp index 70733f31..8b5ca260 100644 --- a/src/effectstack/collapsibleeffect.cpp +++ b/src/effectstack/collapsibleeffect.cpp @@ -593,4 +593,7 @@ bool CollapsibleEffect::needsMonitorEffectScene() const return m_paramWidget->needsMonitorEffectScene(); } - +void CollapsibleEffect::setRange(int inPoint , int outPoint) +{ + m_paramWidget->setRange(inPoint, outPoint); +} diff --git a/src/effectstack/collapsibleeffect.h b/src/effectstack/collapsibleeffect.h index 0d053546..42d4aab4 100644 --- a/src/effectstack/collapsibleeffect.h +++ b/src/effectstack/collapsibleeffect.h @@ -73,6 +73,8 @@ public: void adjustButtons(int ix, int max); /** @brief Returns true of this effect requires an on monitor adjustable effect scene. */ bool needsMonitorEffectScene() const; + /** @brief Set clip in / out points. */ + void setRange(int inPoint , int outPoint); public slots: void slotSyncEffectsPos(int pos); diff --git a/src/effectstack/effectstackview2.cpp b/src/effectstack/effectstackview2.cpp index 69c28d75..2c9ceb7a 100644 --- a/src/effectstack/effectstackview2.cpp +++ b/src/effectstack/effectstackview2.cpp @@ -93,14 +93,26 @@ void EffectStackView2::slotRenderPos(int pos) m_effects.at(i)->slotSyncEffectsPos(pos); } +void EffectStackView2::slotClipItemUpdate() +{ + int inPoint = m_clipref->cropStart().frames(KdenliveSettings::project_fps()); + int outPoint = m_clipref->cropDuration().frames(KdenliveSettings::project_fps()) - inPoint; + CollapsibleEffect *effectToMove = NULL; + for (int i = 0; i < m_effects.count(); i++) { + m_effects.at(i)->setRange(inPoint, outPoint); + } +} + void EffectStackView2::slotClipItemSelected(ClipItem* c) { if (c && !c->isEnabled()) return; if (c && c == m_clipref) { } else { + if (m_clipref) disconnect(m_clipref, SIGNAL(updateRange()), this, SLOT(slotClipItemUpdate())); m_clipref = c; if (c) { + connect(m_clipref, SIGNAL(updateRange()), this, SLOT(slotClipItemUpdate())); QString cname = m_clipref->clipName(); if (cname.length() > 30) { m_ui.checkAll->setToolTip(i18n("Effects for %1", cname)); diff --git a/src/effectstack/effectstackview2.h b/src/effectstack/effectstackview2.h index dd34fe09..90b4e9cc 100644 --- a/src/effectstack/effectstackview2.h +++ b/src/effectstack/effectstackview2.h @@ -128,6 +128,10 @@ public slots: * @param c Clip whose effect list should be managed */ void slotClipItemSelected(ClipItem* c); + /** @brief Update the clip range (in-out points) + * @param c Clip whose effect list should be managed */ + void slotClipItemUpdate(); + void slotTrackItemSelected(int ix, const TrackInfo info); /** @brief Check if the mouse wheel events should be used for scrolling the widget view. */ diff --git a/src/effectstack/parametercontainer.cpp b/src/effectstack/parametercontainer.cpp index 89256436..937ab746 100644 --- a/src/effectstack/parametercontainer.cpp +++ b/src/effectstack/parametercontainer.cpp @@ -220,8 +220,10 @@ ParameterContainer::ParameterContainer(QDomElement effect, ItemInfo info, Effect m_geometryWidget = new GeometryWidget(m_metaInfo->monitor, m_metaInfo->timecode, 0, true, effect.hasAttribute("showrotation"), parent); m_geometryWidget->setFrameSize(m_metaInfo->frameSize); connect(m_geometryWidget, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); - if (minFrame == maxFrame) + if (minFrame == maxFrame) { m_geometryWidget->setupParam(pa, m_in, m_out); + connect(this, SIGNAL(updateRange(int,int)), m_geometryWidget, SLOT(slotUpdateRange(int,int))); + } else m_geometryWidget->setupParam(pa, minFrame, maxFrame); m_vbox->addWidget(m_geometryWidget); @@ -231,8 +233,10 @@ ParameterContainer::ParameterContainer(QDomElement effect, ItemInfo info, Effect connect(this, SIGNAL(syncEffectsPos(int)), m_geometryWidget, SLOT(slotSyncPosition(int))); } else { Geometryval *geo = new Geometryval(m_metaInfo->profile, m_metaInfo->timecode, m_metaInfo->frameSize, 0); - if (minFrame == maxFrame) + if (minFrame == maxFrame) { geo->setupParam(pa, m_in, m_out); + connect(this, SIGNAL(updateRange(int,int)), geo, SLOT(slotUpdateRange(int,int))); + } else geo->setupParam(pa, minFrame, maxFrame); m_vbox->addWidget(geo); @@ -251,11 +255,13 @@ ParameterContainer::ParameterContainer(QDomElement effect, ItemInfo info, Effect if (pa.attribute("widget") == "corners") { // we want a corners-keyframe-widget CornersWidget *corners = new CornersWidget(m_metaInfo->monitor, pa, m_in, m_out, m_metaInfo->timecode, e.attribute("active_keyframe", "-1").toInt(), parent); + connect(this, SIGNAL(updateRange(int,int)), corners, SLOT(slotUpdateRange(int,int))); m_needsMonitorEffectScene = true; connect(this, SIGNAL(syncEffectsPos(int)), corners, SLOT(slotSyncPosition(int))); geo = static_cast(corners); } else { geo = new KeyframeEdit(pa, m_in, m_out, m_metaInfo->timecode, e.attribute("active_keyframe", "-1").toInt()); + connect(this, SIGNAL(updateRange(int,int)), geo, SLOT(slotUpdateRange(int,int))); } m_vbox->addWidget(geo); m_valueItems[paramName+"keyframe"] = geo; @@ -286,6 +292,7 @@ ParameterContainer::ParameterContainer(QDomElement effect, ItemInfo info, Effect pos = m_out - pos; } PositionEdit *posedit = new PositionEdit(paramName, pos, 0, m_out - m_in, m_metaInfo->timecode); + connect(this, SIGNAL(updateRange(int,int)), posedit, SLOT(setRange(int,int))); m_vbox->addWidget(posedit); m_valueItems[paramName+"position"] = posedit; connect(posedit, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); @@ -810,6 +817,9 @@ void ParameterContainer::slotStartFilterJobAction() QString type = pa.attribute("type"); if (type == "filterjob") { QString filterparams = pa.attribute("filterparams"); + if (filterparams.contains("%position")) { + if (m_geometryWidget) filterparams.replace("%position", QString::number(m_geometryWidget->currentPosition())); + } if (filterparams.contains("%params")) { // Replace with current geometry EffectsParameterList parameters; @@ -826,6 +836,7 @@ void ParameterContainer::slotStartFilterJobAction() QDomElement e = jobparams.item(j).toElement(); extraParams.insert(e.attribute("name"), e.text().toUtf8()); } + extraParams.insert("offset", QString::number(m_in)); emit startFilterJob(pa.attribute("filtertag"), filterparams, pa.attribute("consumer"), pa.attribute("consumerparams"), extraParams); kDebug()<<" - - -PROPS:\n"<extra); /** @brief Request import of keyframes from clip data. */ void importClipKeyframes(); + /** @brief Master clip was resized, update effect. */ + void updateRange(int inPoint, int outPoint); }; #endif diff --git a/src/geometryval.cpp b/src/geometryval.cpp index 9dfe5f3e..f28cb1b5 100644 --- a/src/geometryval.cpp +++ b/src/geometryval.cpp @@ -578,4 +578,9 @@ bool Geometryval::keyframeSelected() } - +void Geometryval::slotUpdateRange(int inPoint, int outPoint) +{ + m_helper->setKeyGeometry(m_geom, outPoint - inPoint - 1); + m_helper->update(); + m_timePos.setRange(0, outPoint - inPoint - 1); +} diff --git a/src/geometryval.h b/src/geometryval.h index bccad661..a337d594 100644 --- a/src/geometryval.h +++ b/src/geometryval.h @@ -48,6 +48,7 @@ public: void setFrameSize(QPoint p); /** @brief Updates the timecode display according to settings (frame number or hh:mm:ss:ff) */ void updateTimecodeFormat(); + void slotUpdateRange(int inPoint, int outPoint); private: MltVideoProfile m_profile; diff --git a/src/geometrywidget.cpp b/src/geometrywidget.cpp index 304a1094..7067b94c 100644 --- a/src/geometrywidget.cpp +++ b/src/geometrywidget.cpp @@ -326,8 +326,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_timePos->setRange(0, m_outPoint - m_inPoint); } + m_timePos->setRange(0, m_outPoint - m_inPoint); // no opacity if (elem.attribute("opacity") == "false") { @@ -379,6 +379,11 @@ void GeometryWidget::slotSyncPosition(int relTimelinePos) } } +int GeometryWidget::currentPosition() const +{ + return m_inPoint + m_timePos->getValue(); +} + void GeometryWidget::slotRequestSeek(int pos) { if (KdenliveSettings::transitionfollowcursor()) @@ -878,5 +883,12 @@ void GeometryWidget::importKeyframes(const QString &data, int maximum) 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" diff --git a/src/geometrywidget.h b/src/geometrywidget.h index cdd01cd6..d8e4b9e1 100644 --- a/src/geometrywidget.h +++ b/src/geometrywidget.h @@ -59,6 +59,7 @@ public: void setFrameSize(QPoint size); void addParameter(const QDomElement elem); void importKeyframes(const QString &data, int maximum); + int currentPosition() const; public slots: /** @brief Sets up the rect and the geometry object. @@ -69,6 +70,7 @@ public slots: /** @brief Updates position of the local timeline to @param relTimelinePos. */ void slotSyncPosition(int relTimelinePos); void slotResetKeyframes(); + void slotUpdateRange(int inPoint, int outPoint); private: Ui::GeometryWidget_UI m_ui; diff --git a/src/keyframeedit.cpp b/src/keyframeedit.cpp index e6769721..0d4bc1d3 100644 --- a/src/keyframeedit.cpp +++ b/src/keyframeedit.cpp @@ -471,4 +471,10 @@ void KeyframeEdit::checkVisibleParam() slotUpdateVisibleParameter(0); } +void KeyframeEdit::slotUpdateRange(int inPoint, int outPoint) +{ + m_min = inPoint; + m_max = outPoint; +} + #include "keyframeedit.moc" diff --git a/src/keyframeedit.h b/src/keyframeedit.h index 210192e4..165ccc17 100644 --- a/src/keyframeedit.h +++ b/src/keyframeedit.h @@ -94,6 +94,10 @@ public: /** @brief Makes the first parameter visible in timeline if no parameter is selected. */ void checkVisibleParam(); +public slots: + + void slotUpdateRange(int inPoint, int outPoint); + protected: /** @brief Gets the position of a keyframe from the table. * @param row Row of the keyframe in the table */ diff --git a/src/positionedit.h b/src/positionedit.h index 70dff2ff..dda7b8ee 100644 --- a/src/positionedit.h +++ b/src/positionedit.h @@ -35,8 +35,10 @@ public: int getPosition() const; void setPosition(int pos); void updateTimecodeFormat(); - void setRange(int min, int max); +public slots: + void setRange(int min, int max); + private: TimecodeDisplay *m_display; QSlider *m_slider; diff --git a/src/projectitem.cpp b/src/projectitem.cpp index 711865cb..c26f5ce9 100644 --- a/src/projectitem.cpp +++ b/src/projectitem.cpp @@ -35,24 +35,26 @@ const int JobTypeRole = Qt::UserRole + 6; const int JobStatusMessage = Qt::UserRole + 7; const int itemHeight = 38; -ProjectItem::ProjectItem(QTreeWidget * parent, DocClipBase *clip) : +ProjectItem::ProjectItem(QTreeWidget * parent, DocClipBase *clip, QSize pixmapSize) : QTreeWidgetItem(parent, PROJECTCLIPTYPE), m_clip(clip), - m_clipId(clip->getId()) + m_clipId(clip->getId()), + m_pixmapSet(false) { - buildItem(); + buildItem(pixmapSize); } -ProjectItem::ProjectItem(QTreeWidgetItem * parent, DocClipBase *clip) : +ProjectItem::ProjectItem(QTreeWidgetItem * parent, DocClipBase *clip, QSize pixmapSize) : QTreeWidgetItem(parent, PROJECTCLIPTYPE), m_clip(clip), - m_clipId(clip->getId()) + m_clipId(clip->getId()), + m_pixmapSet(false) { - buildItem(); + buildItem(pixmapSize); } -void ProjectItem::buildItem() +void ProjectItem::buildItem(QSize pixmapSize) { setSizeHint(0, QSize(itemHeight * 3, itemHeight)); if (m_clip->isPlaceHolder()) setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDropEnabled); @@ -60,6 +62,19 @@ void ProjectItem::buildItem() QString name = m_clip->getProperty("name"); if (name.isEmpty()) name = KUrl(m_clip->getProperty("resource")).fileName(); m_clipType = (CLIPTYPE) m_clip->getProperty("type").toInt(); + switch(m_clipType) { + case AUDIO: + setData(0, Qt::DecorationRole, KIcon("audio-x-generic").pixmap(pixmapSize)); + m_pixmapSet = true; + break; + case IMAGE: + case SLIDESHOW: + setData(0, Qt::DecorationRole, KIcon("image-x-generic").pixmap(pixmapSize)); + break; + default: + setData(0, Qt::DecorationRole, KIcon("video-x-generic").pixmap(pixmapSize)); + } + setText(0, name); setText(1, m_clip->description()); GenTime duration = m_clip->duration(); @@ -80,6 +95,17 @@ ProjectItem::~ProjectItem() { } +bool ProjectItem::hasPixmap() const +{ + return m_pixmapSet; +} + +void ProjectItem::setPixmap(const QPixmap p) +{ + m_pixmapSet = true; + setData(0, Qt::DecorationRole, p); +} + //static int ProjectItem::itemDefaultHeight() { diff --git a/src/projectitem.h b/src/projectitem.h index c6fd3b4a..6d07b1b8 100644 --- a/src/projectitem.h +++ b/src/projectitem.h @@ -41,8 +41,8 @@ class DocClipBase; class ProjectItem : public QTreeWidgetItem { public: - ProjectItem(QTreeWidget * parent, DocClipBase *clip); - ProjectItem(QTreeWidgetItem * parent, DocClipBase *clip); + ProjectItem(QTreeWidget * parent, DocClipBase *clip, QSize pixmapSize); + ProjectItem(QTreeWidgetItem * parent, DocClipBase *clip, QSize pixmapSize); virtual ~ProjectItem(); QDomElement toXml() const; int numReferences() const; @@ -76,6 +76,10 @@ public: bool isJobRunning() const; /** \brief Returns true if we are currently creating the proxy for this clip. */ bool isProxyRunning() const; + /** \brief Returns true if the thumbnail for this clip has been loaded. */ + bool hasPixmap() const; + /** \brief Sets the thumbnail for this clip. */ + void setPixmap(const QPixmap p); virtual bool operator<(const QTreeWidgetItem &other)const { int column = treeWidget()->sortColumn(); @@ -88,8 +92,9 @@ private: CLIPTYPE m_clipType; DocClipBase *m_clip; QString m_clipId; + bool m_pixmapSet; /** @brief Setup basic properties */ - void buildItem(); + void buildItem(QSize pixmapSize); /** @brief Check if an xml project file has proxies */ bool playlistHasProxies(const QString path); }; diff --git a/src/projectlist.cpp b/src/projectlist.cpp index 5db34b1a..231e6e4f 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -739,7 +739,7 @@ void ProjectList::slotModifiedClip(const QString &id) } else { pixmap = KIcon("view-refresh").pixmap(m_listView->iconSize()); } - item->setData(0, Qt::DecorationRole, pixmap); + item->setPixmap(pixmap); } } @@ -763,7 +763,7 @@ void ProjectList::slotMissingClip(const QString &id) QPainter p(&pixmap); p.drawPixmap(3, 3, icon.pixmap(width - 6, height - 6)); p.end(); - item->setData(0, Qt::DecorationRole, pixmap); + item->setPixmap(pixmap); if (item->referencedClip()) { item->referencedClip()->setPlaceHolder(true); Mlt::Producer *newProd = m_render->invalidProducer(id); @@ -1295,6 +1295,7 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties) //m_listView->setEnabled(false); const QString parent = clip->getProperty("groupid"); QString groupName = clip->getProperty("groupname"); + QSize pixelSize((int)(m_listView->iconSize().height() * m_render->dar()), m_listView->iconSize().height()); ProjectItem *item = NULL; monitorItemEditing(false); if (!parent.isEmpty()) { @@ -1308,19 +1309,16 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties) } if (parentitem) - item = new ProjectItem(parentitem, clip); + item = new ProjectItem(parentitem, clip, pixelSize); } if (item == NULL) { - item = new ProjectItem(m_listView, clip); + item = new ProjectItem(m_listView, clip, pixelSize); } if (item->data(0, DurationRole).isNull()) item->setData(0, DurationRole, i18n("Loading")); connect(clip, SIGNAL(createProxy(const QString &)), this, SLOT(slotCreateProxy(const QString &))); connect(clip, SIGNAL(abortProxy(const QString &, const QString &)), this, SLOT(slotAbortProxy(const QString, const QString))); + if (getProperties) { - int height = m_listView->iconSize().height(); - int width = (int)(height * m_render->dar()); - QPixmap pix = KIcon("video-x-generic").pixmap(QSize(width, height)); - item->setData(0, Qt::DecorationRole, pix); //item->setFlags(Qt::ItemIsSelectable); m_listView->processLayout(); QDomElement e = clip->toXML().cloneNode().toElement(); @@ -1469,8 +1467,9 @@ void ProjectList::getCachedThumbnail(ProjectItem *item) requestClipThumbnail(item->clipId()); } else { - processThumbOverlays(item, pix); - item->setData(0, Qt::DecorationRole, pix); + QPixmap result = roundedPixmap(pix); + processThumbOverlays(item, result); + item->setPixmap(result); } } else { @@ -1478,6 +1477,34 @@ void ProjectList::getCachedThumbnail(ProjectItem *item) } } +QPixmap ProjectList::roundedPixmap(QImage img) +{ + QPixmap pix(img.width(), img.height()); + pix.fill(Qt::transparent); + QPainter p(&pix); + p.setRenderHint(QPainter::Antialiasing, true); + QPainterPath path; + path.addRoundedRect(0.5, 0.5, pix.width() - 1, pix.height() - 1, 2, 2); + p.setClipPath(path); + p.drawImage(0, 0, img); + p.end(); + return pix; +} + +QPixmap ProjectList::roundedPixmap(QPixmap source) +{ + QPixmap pix(source.width(), source.height()); + pix.fill(Qt::transparent); + QPainter p(&pix); + p.setRenderHint(QPainter::Antialiasing, true); + QPainterPath path; + path.addRoundedRect(0.5, 0.5, pix.width() - 1, pix.height() - 1, 2, 2); + p.setClipPath(path); + p.drawPixmap(0, 0, source); + p.end(); + return pix; +} + void ProjectList::getCachedThumbnail(SubProjectItem *item) { if (!item) return; @@ -1565,22 +1592,22 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged, QStr } else if (clip->isPlaceHolder()) { item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDropEnabled); - if (item->data(0, Qt::DecorationRole).isNull()) { - item->setData(0, Qt::DecorationRole, missingPixmap); + if (!item->hasPixmap()) { + item->setPixmap(missingPixmap); } else { QPixmap pixmap = qVariantValue(item->data(0, Qt::DecorationRole)); QPainter p(&pixmap); p.drawPixmap(3, 3, KIcon("dialog-close").pixmap(pixmap.width() - 6, pixmap.height() - 6)); p.end(); - item->setData(0, Qt::DecorationRole, pixmap); + item->setPixmap(pixmap); } } } else { if (displayRatioChanged) { requestClipThumbnail(clip->getId()); } - else if (item->data(0, Qt::DecorationRole).isNull()) { + else if (!item->hasPixmap()) { getCachedThumbnail(item); } if (item->data(0, DurationRole).toString().isEmpty()) { @@ -1595,7 +1622,7 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged, QStr QPainter p(&pixmap); p.drawPixmap(3, 3, KIcon("dialog-close").pixmap(pixmap.width() - 6, pixmap.height() - 6)); p.end(); - item->setData(0, Qt::DecorationRole, pixmap); + item->setPixmap(pixmap); } else if (clip->getProperty("_replaceproxy") == "1") { clip->setProperty("_replaceproxy", QString()); @@ -2013,8 +2040,11 @@ void ProjectList::slotSetThumbnail(const QString &id, int framePos, QImage img) if (item && item->parent()) pItem = static_cast (item->parent()); if (!item && framePos == 0) pItem = getItemById(id); if (!item && !pItem) return; - if (item) item->setData(0, Qt::DecorationRole, QPixmap::fromImage(img)); - else if (pItem) pItem->setData(0, Qt::DecorationRole, QPixmap::fromImage(img)); + if (item) { + if (item->type() == PROJECTCLIPTYPE) static_cast(item)->setPixmap(QPixmap::fromImage(img)); + else item->setData(0, Qt::DecorationRole, QPixmap::fromImage(img)); + } + else if (pItem) pItem->setPixmap(QPixmap::fromImage(img)); if (pItem) { QString hash = pItem->getClipHash(); if (!hash.isEmpty()) m_doc->cacheImage(hash + '#' + QString::number(framePos), img); @@ -2124,26 +2154,22 @@ void ProjectList::slotRefreshClipThumbnail(QTreeWidgetItem *it, bool update) slotProcessNextThumbnail(); return; } - QPixmap pix; QImage img; int height = m_listView->iconSize().height(); int swidth = (int)(height * m_render->frameRenderWidth() / m_render->renderHeight()+ 0.5); int dwidth = (int)(height * m_render->dar() + 0.5); - if (clip->clipType() == AUDIO) - pix = KIcon("audio-x-generic").pixmap(QSize(dwidth, height)); - else if (clip->clipType() == IMAGE) { + if (clip->clipType() == IMAGE) { img = KThumb::getFrame(item->referencedClip()->getProducer(), 0, swidth, dwidth, height); } - else { + else if (clip->clipType() != AUDIO) { img = item->referencedClip()->extractImage(frame, dwidth, height); } - if (!pix.isNull() || !img.isNull()) { + if (!img.isNull()) { monitorItemEditing(false); - if (!img.isNull()) { - pix = QPixmap::fromImage(img); - processThumbOverlays(item, pix); - } - it->setData(0, Qt::DecorationRole, pix); + QPixmap pix = roundedPixmap(img); + processThumbOverlays(item, pix); + if (isSubItem) it->setData(0, Qt::DecorationRole, pix); + else item->setPixmap(pix); monitorItemEditing(true); QString hash = item->getClipHash(); @@ -2212,7 +2238,7 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce } } - if (!replace && m_allClipsProcessed && item->data(0, Qt::DecorationRole).isNull()) { + if (!replace && m_allClipsProcessed && !item->hasPixmap()) { getCachedThumbnail(item); } if (!toReload.isEmpty()) @@ -2335,18 +2361,10 @@ void ProjectList::slotReplyGetImage(const QString &clipId, const QImage &img) { ProjectItem *item = getItemById(clipId); if (item && !img.isNull()) { - QPixmap pix(img.width(), img.height()); - pix.fill(Qt::transparent); - QPainter p(&pix); - p.setRenderHint(QPainter::Antialiasing, true); - QPainterPath path; - path.addRoundedRect(0.5, 0.5, pix.width() - 1, pix.height() - 1, 2, 2); - p.setClipPath(path); - p.drawImage(0, 0, img); - p.end(); + QPixmap pix = roundedPixmap(img); processThumbOverlays(item, pix); monitorItemEditing(false); - item->setData(0, Qt::DecorationRole, pix); + item->setPixmap(pix); monitorItemEditing(true); QString hash = item->getClipHash(); if (!hash.isEmpty()) m_doc->cacheImage(hash, img); @@ -3496,7 +3514,8 @@ void ProjectList::startClipFilterJob(const QString &filterName, const QString &c QMap extraParams; extraParams.insert("key", "shot_change_list"); extraParams.insert("projecttreefilter", "1"); - extraParams.insert("resultmessage", i18n("Found %1 scenes.", "%count")); + QString keyword("%count"); + extraParams.insert("resultmessage", i18n("Found %1 scenes.", keyword)); if (ui.add_markers->isChecked()) { // We want to create markers extraParams.insert("addmarkers", QString::number(ui.marker_type->currentIndex())); @@ -3676,7 +3695,7 @@ void ProjectList::slotGotFilterJobResults(QString id, int , int , stringMap resu } if (!dataProcessed || filterInfo.contains("storedata")) { // Store returned data as clip extra data - clip->referencedClip()->setAnalysisData(filterInfo.contains("displaydataname") ? filterInfo.value("displaydataname") : key, results.value(key)); + clip->referencedClip()->setAnalysisData(filterInfo.contains("displaydataname") ? filterInfo.value("displaydataname") : key, results.value(key), filterInfo.value("offset").toInt()); emit updateAnalysisData(clip->referencedClip()); } } diff --git a/src/projectlist.h b/src/projectlist.h index af8605b1..8c5cd95c 100644 --- a/src/projectlist.h +++ b/src/projectlist.h @@ -168,31 +168,28 @@ public: QString subText = index.data(DurationRole).toString(); int usage = index.data(UsageRole).toInt(); if (usage != 0) subText.append(QString(" (%1)").arg(usage)); - if (option.state & (QStyle::State_Selected)) painter->setPen(option.palette.color(QPalette::Mid)); QRectF bounding; painter->drawText(r2, Qt::AlignLeft | Qt::AlignVCenter , subText, &bounding); - int jobProgress = index.data(Qt::UserRole + 5).toInt(); if (jobProgress != 0 && jobProgress != JOBDONE && jobProgress != JOBABORTED) { if (jobProgress != JOBCRASHED) { // Draw job progress bar QColor color = option.palette.alternateBase().color(); - painter->setPen(Qt::NoPen); - color.setAlpha(180); - painter->setBrush(QBrush(color)); - QRect progress(pixmapPoint.x() + 1, pixmapPoint.y() + pixmap.height() - 9, pixmap.width() - 2, 8); - painter->drawRect(progress); - painter->setBrush(option.palette.text()); - if (jobProgress > 0) { - progress.adjust(1, 1, 0, -1); - progress.setWidth((pixmap.width() - 4) * jobProgress / 100); - painter->drawRect(progress); - } else if (jobProgress == JOBWAITING) { - // Draw kind of a pause icon - progress.adjust(1, 1, 0, -1); - progress.setWidth(2); - painter->drawRect(progress); - progress.moveLeft(progress.right() + 2); + color.setAlpha(150); + painter->setPen(option.palette.link().color()); + QRect progress(pixmapPoint.x() + 2, pixmapPoint.y() + pixmap.height() - 9, pixmap.width() - 4, 7); + painter->setBrush(QBrush(color)); + painter->drawRect(progress); + painter->setBrush(option.palette.link()); + progress.adjust(2, 2, -2, -2); + if (jobProgress == JOBWAITING) { + progress.setLeft(progress.right() - 2); + painter->drawRect(progress); + progress.moveLeft(progress.left() - 5); + painter->drawRect(progress); + } + else if (jobProgress > 0) { + progress.setWidth(progress.width() * jobProgress / 100); painter->drawRect(progress); } } else if (jobProgress == JOBCRASHED) { @@ -426,6 +423,9 @@ private: QStringList getPendingJobs(const QString &id); /** @brief Start an MLT process job. */ void processClipJob(QStringList ids, const QString&destination, bool autoAdd, QStringList jobParams, const QString &description, QMap extraParams = QMap ()); + /** @brief Create rounded shape pixmap for project tree thumb. */ + QPixmap roundedPixmap(QImage img); + QPixmap roundedPixmap(QPixmap source); private slots: void slotClipSelected(); diff --git a/src/titlewidget.cpp b/src/titlewidget.cpp index f1ce84d8..5a938749 100644 --- a/src/titlewidget.cpp +++ b/src/titlewidget.cpp @@ -2034,7 +2034,7 @@ void TitleWidget::readChoices() QColor bgColor = QColor(titleConfig.readEntry("rect_background_color", rectBColor->color())); #if KDE_IS_VERSION(4,5,0) - fgColor.setAlpha(titleConfig.readEntry("rect_background_alpha", fgColor.alpha())); + fgColor.setAlpha(titleConfig.readEntry("rect_foreground_alpha", fgColor.alpha())); bgColor.setAlpha(titleConfig.readEntry("rect_background_alpha", bgColor.alpha())); #else rectFAlpha->setValue(titleConfig.readEntry("rect_foreground_alpha", rectFAlpha->value()));