Commit c6a04915 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

allow draggig clip from bin to qml timeline

parent e0a55a1f
......@@ -92,7 +92,6 @@ kconfig_add_kcfg_files(kdenlive_SRCS kdenlivesettings.kcfgc)
add_subdirectory(doc)
add_subdirectory(project)
add_subdirectory(timeline)
add_subdirectory(timeline2)
add_subdirectory(effectstack)
add_subdirectory(dialogs)
add_subdirectory(effectslist)
......@@ -101,6 +100,7 @@ add_subdirectory(capture)
add_subdirectory(dvdwizard)
add_subdirectory(lib)
add_subdirectory(monitor)
add_subdirectory(timeline2)
add_subdirectory(onmonitoritems)
add_subdirectory(simplekeyframes)
add_subdirectory(stopmotion)
......@@ -253,7 +253,6 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/lib
)
# Adds Qt definitions and include directories, and sets QT_LIBRARIES according
# to the components requested in find_package().
#include(${QT_USE_FILE})
......
......@@ -272,6 +272,12 @@ GenTime ProjectClip::duration() const
return GenTime();
}
int ProjectClip::frameDuration() const
{
GenTime d = duration();
return d.frames(m_controller->profile()->fps());
}
void ProjectClip::reloadProducer(bool refreshOnly)
{
QDomDocument doc;
......
......@@ -106,6 +106,7 @@ public:
/** @brief Returns the clip's duration. */
GenTime duration() const;
int frameDuration() const;
/** @brief Returns the original clip's fps. */
double getOriginalFps() const;
......
......@@ -262,6 +262,7 @@ QMimeData *ProjectItemModel::mimeData(const QModelIndexList &indices) const
// Folder ids are represented like: #2 (where 2 is the folder's id)
QMimeData *mimeData = new QMimeData();
QStringList list;
int duration = 0;
for (int i = 0; i < indices.count(); i++) {
QModelIndex ix = indices.at(i);
if (!ix.isValid() || ix.column() != 0) {
......@@ -271,6 +272,7 @@ QMimeData *ProjectItemModel::mimeData(const QModelIndexList &indices) const
AbstractProjectItem::PROJECTITEMTYPE type = item->itemType();
if (type == AbstractProjectItem::ClipItem) {
list << item->clipId();
duration += ((ProjectClip *)(item))->frameDuration();
} else if (type == AbstractProjectItem::SubClipItem) {
QPoint p = item->zone();
list << item->clipId() + "/" + QString::number(p.x()) + "/" + QString::number(p.y());
......@@ -282,6 +284,8 @@ QMimeData *ProjectItemModel::mimeData(const QModelIndexList &indices) const
QByteArray data;
data.append(list.join(QLatin1Char(';')).toUtf8());
mimeData->setData(QStringLiteral("kdenlive/producerslist"), data);
qDebug()<<"/// CLI DURATION: "<<duration;
mimeData->setText(QString::number(duration));
}
return mimeData;
}
......
......@@ -36,6 +36,7 @@
#include <KSelectAction>
#include <KColorSchemeManager>
#include "kdenlive_debug.h"
#include "kdenlivecore_export.h"
#include "effectslist/effectslist.h"
#include "gentime.h"
......
......@@ -20,6 +20,7 @@
#include "bincontroller.h"
#include "clipcontroller.h"
#include "kdenlivesettings.h"
#include "kdenlive_debug.h"
static const char *kPlaylistTrackId = "main bin";
......
......@@ -106,7 +106,7 @@ void ProjectManager::slotLoadOnOpen()
pCore->bin()->droppedUrls(urls);
}
m_loadClipsOnOpen.clear();
TimelineWidget *timelineWidget = new TimelineWidget(m_project->commandStack(), pCore->window());
TimelineWidget *timelineWidget = new TimelineWidget(pCore->binController(), m_project->commandStack(), pCore->window());
pCore->addTimeline(timelineWidget, m_project->url().fileName());
}
......
......@@ -17,6 +17,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include "spacermanager.h"
#include "timeline/customtrackview.h"
#include "timeline/clipitem.h"
......
......@@ -8,4 +8,3 @@ set(kdenlive_SRCS
timeline2/view/timelinewidget.cpp
timeline2/view/qml/timelineitems.cpp
PARENT_SCOPE)
......@@ -19,6 +19,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef CLIPMODEL_H
#define CLIPMODEL_H
#include <memory>
#include <QObject>
#include "undohelper.hpp"
......@@ -121,3 +124,5 @@ private:
std::shared_ptr<Mlt::Producer> m_producer;
};
#endif
......@@ -19,6 +19,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef GROUPMODEL_H
#define GROUPMODEL_H
#include <unordered_map>
#include <unordered_set>
#include <memory>
......@@ -122,3 +125,5 @@ private:
std::unordered_set<int> m_groupIds; //this keeps track of "real" groups (non-leaf elements)
};
#endif
......@@ -26,6 +26,7 @@
#include "groupsmodel.hpp"
#include "doc/docundostack.hpp"
#include "mltcontroller/bincontroller.h"
#include <klocalizedstring.h>
#include <QDebug>
......@@ -43,18 +44,19 @@ int TimelineModel::next_id = 0;
}
TimelineModel::TimelineModel(std::weak_ptr<DocUndoStack> undo_stack) :
TimelineModel::TimelineModel(BinController *binController, std::weak_ptr<DocUndoStack> undo_stack) :
QAbstractItemModel(),
m_tractor(new Mlt::Tractor()),
m_undoStack(undo_stack)
m_undoStack(undo_stack),
m_binController(binController)
{
Mlt::Profile profile;
m_tractor->set_profile(profile);
}
std::shared_ptr<TimelineModel> TimelineModel::construct(std::weak_ptr<DocUndoStack> undo_stack, bool populate)
std::shared_ptr<TimelineModel> TimelineModel::construct(BinController *binController, std::weak_ptr<DocUndoStack> undo_stack, bool populate)
{
std::shared_ptr<TimelineModel> ptr(new TimelineModel(undo_stack));
std::shared_ptr<TimelineModel> ptr(new TimelineModel(binController, undo_stack));
ptr->m_groups = std::unique_ptr<GroupsModel>(new GroupsModel(ptr));
if (populate) {
// Testing: add a clip on first track
......@@ -585,3 +587,10 @@ int TimelineModel::duration() const
{
return m_tractor->get_playtime();
}
void TimelineModel::insertClip(std::shared_ptr<TimelineModel> tl, int track, int position, QString data)
{
std::shared_ptr<Mlt::Producer> prod(new Mlt::Producer(m_binController->getBinProducer(data)));
int clipId = ClipModel::construct(tl, prod);
requestClipMove(clipId, track, position, true);
}
......@@ -34,6 +34,7 @@ class TrackModel;
class ClipModel;
class GroupsModel;
class DocUndoStack;
class BinController;
/* @brief This class represents a Timeline object, as viewed by the backend.
In general, the Gui associated with it will send modification queries (such as resize or move), and this class authorize them or not depending on the validity of the modifications.
......@@ -65,12 +66,12 @@ public:
/* @brief construct a timeline object and returns a pointer to the created object
@param undo_stack is a weak pointer to the undo stack of the project
*/
static std::shared_ptr<TimelineModel> construct(std::weak_ptr<DocUndoStack> undo_stack, bool populate = false);
static std::shared_ptr<TimelineModel> construct(BinController *binController, std::weak_ptr<DocUndoStack> undo_stack, bool populate = false);
protected:
/* @brief this constructor should not be called. Call the static construct instead
*/
TimelineModel(std::weak_ptr<DocUndoStack> undo_stack);
TimelineModel(BinController *binController, std::weak_ptr<DocUndoStack> undo_stack);
public:
friend class TrackModel;
......@@ -155,6 +156,7 @@ public:
bool requestClipMove(int cid, int tid, int position, bool logUndo = true);
bool trimClip(int cid, int delta, bool right, bool ripple = false);
void insertClip(std::shared_ptr<TimelineModel> tl, int track, int position, QString data);
protected:
/* Same function, but accumulates undo and redo, and doesn't check for group*/
bool requestClipMove(int cid, int tid, int position, Fun &undo, Fun &redo);
......@@ -261,7 +263,9 @@ private:
std::unordered_set<int> m_allGroups; //ids of all the groups
std::weak_ptr<DocUndoStack> m_undoStack;
BinController *m_binController;
};
#endif
......@@ -19,6 +19,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef TRACKMODEL_H
#define TRACKMODEL_H
#include <memory>
#include <QSharedPointer>
#include <unordered_map>
......@@ -134,3 +137,5 @@ private:
};
#endif
......@@ -17,7 +17,7 @@
*/
function scrollIfNeeded() {
var x = timeline.position * multitrack.scaleFactor;
var x = timeline.position * timeline.scaleFactor;
if (!scrollView) return;
if (x > scrollView.flickableItem.contentX + scrollView.width - 50)
scrollView.flickableItem.contentX = x - scrollView.width + 50;
......@@ -28,10 +28,11 @@ function scrollIfNeeded() {
}
function dragging(pos, duration) {
console.log("clip duration:", duration)
if (tracksRepeater.count > 0) {
var headerHeight = ruler.height + toolbar.height
var headerHeight = ruler.height
dropTarget.x = pos.x
dropTarget.width = duration * multitrack.scaleFactor
dropTarget.width = duration * timeline.scaleFactor
for (var i = 0; i < tracksRepeater.count; i++) {
var trackY = tracksRepeater.itemAt(i).y + headerHeight - scrollView.flickableItem.contentY
......@@ -71,11 +72,11 @@ function dragging(pos, duration) {
scrollTimer.stop()
}
if (toolbar.scrub) {
if (timeline.scrub) {
timeline.position = Math.round(
(pos.x + scrollView.flickableItem.contentX - headerWidth) / multitrack.scaleFactor)
(pos.x + scrollView.flickableItem.contentX - headerWidth) / timeline.scaleFactor)
}
if (toolbar.snap) {
if (timeline.snap) {
for (i = 0; i < tracksRepeater.count; i++)
tracksRepeater.itemAt(i).snapDrop(pos)
}
......@@ -88,11 +89,12 @@ function dropped() {
}
function acceptDrop(xml) {
var position = Math.round((dropTarget.x + scrollView.flickableItem.contentX - headerWidth) / multitrack.scaleFactor)
if (toolbar.ripple)
var position = Math.round((dropTarget.x + scrollView.flickableItem.contentX - headerWidth) / timeline.scaleFactor)
timeline.insertClip(currentTrack, position, xml)
/*if (timeline.ripple)
timeline.insert(currentTrack, position, xml)
else
timeline.overwrite(currentTrack, position, xml)
timeline.overwrite(currentTrack, position, xml)*/
}
function trackHeight(isAudio) {
......
......@@ -45,18 +45,18 @@ Rectangle {
DropArea {
anchors.fill: parent
onEntered: {
if (drag.formats.indexOf('application/mlt+xml') >= 0)
if (drag.formats.indexOf('kdenlive/producerslist') >= 0)
drag.acceptProposedAction()
}
onExited: Logic.dropped()
onPositionChanged: {
if (drag.formats.indexOf('application/mlt+xml') >= 0)
if (drag.formats.indexOf('kdenlive/producerslist') >= 0)
Logic.dragging(drag, drag.text)
}
onDropped: {
if (drop.formats.indexOf('application/mlt+xml') >= 0) {
if (drop.formats.indexOf('kdenlive/producerslist') >= 0) {
if (currentTrack >= 0) {
Logic.acceptDrop(drop.getDataAsString('application/mlt+xml'))
Logic.acceptDrop(drop.getDataAsString('kdenlive/producerslist'))
drop.acceptProposedAction()
}
}
......
......@@ -27,9 +27,9 @@
#include <QQuickItem>
#include <QQmlContext>
TimelineWidget::TimelineWidget(std::weak_ptr<DocUndoStack> undoStack, QWidget *parent)
TimelineWidget::TimelineWidget(BinController *binController, std::weak_ptr<DocUndoStack> undoStack, QWidget *parent)
: QQuickWidget(parent)
, m_model(TimelineModel::construct(undoStack, true))
, m_model(TimelineModel::construct(binController, undoStack, true))
, m_position(0)
{
registerTimelineItems();
......@@ -149,6 +149,11 @@ bool TimelineWidget::trimClip(int clipIndex, int delta, bool right)
return m_model->trimClip(clipIndex, delta, right);
}
void TimelineWidget::insertClip(int track, int position, QString data)
{
m_model->insertClip(m_model, track, position, data);
}
QString TimelineWidget::timecode(int frames)
{
......
......@@ -22,10 +22,10 @@
#ifndef TIMELINEWIDGET_H
#define TIMELINEWIDGET_H
#include "../model/timelinemodel.hpp"
#include "mltcontroller/bincontroller.h"
#include "timeline2/model/timelinemodel.hpp"
#include <QQuickWidget>
class TimelineWidget : public QQuickWidget
{
Q_OBJECT
......@@ -38,7 +38,7 @@ class TimelineWidget : public QQuickWidget
Q_PROPERTY(bool scrub READ scrub NOTIFY scrubChanged)
public:
TimelineWidget(std::weak_ptr<DocUndoStack> undoStack, QWidget *parent = Q_NULLPTR);
TimelineWidget(BinController *binController, std::weak_ptr<DocUndoStack> undoStack, QWidget *parent = Q_NULLPTR);
void setSelection(QList<int> selection = QList<int>(), int trackIndex = -1, bool isMultitrack = false);
QList<int> selection() const;
Q_INVOKABLE bool isMultitrackSelected() const { return m_selection.isMultitrackSelected; }
......@@ -48,13 +48,14 @@ public:
Q_INVOKABLE bool moveClip(int toTrack, int clipIndex, int position, bool logUndo = true);
Q_INVOKABLE bool allowMoveClip(int toTrack, int clipIndex, int position);
Q_INVOKABLE bool trimClip(int clipIndex, int delta, bool right);
int duration() const;
int position() const { return m_position; }
void setPosition(int);
bool snap();
bool ripple();
bool scrub();
Q_INVOKABLE int duration() const;
Q_INVOKABLE int position() const { return m_position; }
Q_INVOKABLE void setPosition(int);
Q_INVOKABLE bool snap();
Q_INVOKABLE bool ripple();
Q_INVOKABLE bool scrub();
Q_INVOKABLE QString timecode(int frames);
Q_INVOKABLE void insertClip(int track, int position, QString xml);
public slots:
void selectMultitrack();
......
......@@ -21,16 +21,17 @@ SET(Tests_SRCS
../src/timeline2/model/undohelper.cpp
)
INCLUDE_DIRECTORIES(../src/)
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}/src
${MLT_INCLUDE_DIR}
${MLTPP_INCLUDE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/lib/external
${CMAKE_CURRENT_SOURCE_DIR}/lib
../src
)
ADD_EXECUTABLE(runTests ${Tests_SRCS})
target_link_libraries(runTests Qt5::Core Qt5::Widgets)
target_link_libraries(runTests Qt5::Core Qt5::Widgets Qt5::Xml)
target_link_libraries(runTests
${MLT_LIBRARIES}
${MLTPP_LIBRARIES}
......
......@@ -14,7 +14,7 @@
TEST_CASE("Functional test of the group hierarchy", "[GroupsModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(nullptr, undoStack);
GroupsModel groups(timeline);
std::function<bool (void)> undo = [](){return true;};
std::function<bool (void)> redo = [](){return true;};
......@@ -191,7 +191,7 @@ TEST_CASE("Functional test of the group hierarchy", "[GroupsModel]")
TEST_CASE("Interface test of the group hierarchy", "[GroupsModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(nullptr, undoStack);
GroupsModel groups(timeline);
std::function<bool (void)> undo = [](){return true;};
......@@ -318,7 +318,7 @@ TEST_CASE("Interface test of the group hierarchy", "[GroupsModel]")
TEST_CASE("Orphan groups deletion", "[GroupsModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(nullptr, undoStack);
GroupsModel groups(timeline);
std::function<bool (void)> undo = [](){return true;};
std::function<bool (void)> redo = [](){return true;};
......@@ -372,7 +372,7 @@ TEST_CASE("Orphan groups deletion", "[GroupsModel]")
TEST_CASE("Undo/redo", "[GroupsModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(nullptr, undoStack);
Mlt::Factory::init( NULL );
Mlt::Profile profile;
......
......@@ -18,7 +18,7 @@ std::default_random_engine g(42);
TEST_CASE("Basic creation/deletion of a track", "[TrackModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(nullptr, undoStack);
int id1 = TrackModel::construct(timeline);
REQUIRE(timeline->getTracksCount() == 1);
......@@ -45,7 +45,7 @@ TEST_CASE("Basic creation/deletion of a track", "[TrackModel]")
TEST_CASE("Basic creation/deletion of a clip", "[ClipModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(nullptr, undoStack);
Mlt::Factory::init( NULL );
Mlt::Profile profile;
......@@ -79,7 +79,7 @@ TEST_CASE("Basic creation/deletion of a clip", "[ClipModel]")
TEST_CASE("Clip manipulation", "[ClipModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(nullptr, undoStack);
Mlt::Factory::init( NULL );
Mlt::Profile profile;
......@@ -525,7 +525,7 @@ TEST_CASE("Clip manipulation", "[ClipModel]")
TEST_CASE("Check id unicity", "[ClipModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(nullptr, undoStack);
Mlt::Factory::init( NULL );
Mlt::Profile profile;
......@@ -565,7 +565,7 @@ TEST_CASE("Check id unicity", "[ClipModel]")
TEST_CASE("Undo and Redo", "[ClipModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(nullptr, undoStack);
Mlt::Factory::init( NULL );
Mlt::Profile profile;
......
......@@ -17,7 +17,7 @@ TEST_CASE("Regression") {
auto repo = Mlt::Factory::init( NULL );
Mlt::Profile profile;
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(nullptr, undoStack);
TimelineModel::next_id = 0;
undoStack->undo();
undoStack->redo();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment