Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit ea03e79c authored by Nicolas Carion's avatar Nicolas Carion

[Timeline2] Fix various issues related to snapping and dropping

parent a410d691
......@@ -96,21 +96,15 @@ int SnapModel::getPreviousPoint(int position)
void SnapModel::ignore(const std::vector<int>& pts)
{
for (int pt : pts) {
auto it = m_snaps.find(pt);
if (it != m_snaps.end()) {
m_ignore.push_back(*it);
m_snaps.erase(it);
}
removePoint(pt);
m_ignore.push_back(pt);
}
}
void SnapModel::unIgnore()
{
for (const auto& pt : m_ignore) {
if (m_snaps.count(pt.first) == 0) {
m_snaps[pt.first] = 0;
}
m_snaps[pt.first] += pt.second;
addPoint(pt);
}
m_ignore.clear();
}
......@@ -64,7 +64,7 @@ public:
private:
std::map<int, int> m_snaps; //This represents the snappoints internally. The keys are the positions and the values are the number of elements at this position. Note that it is important that the datastructure is ordered. QMap is NOT ordered, and therefore not suitable.
std::vector<std::pair<int, int> > m_ignore;
std::vector<int > m_ignore;
};
#endif
......@@ -211,11 +211,30 @@ int TimelineModel::suggestClipMove(int cid, int tid, int position)
if (currentPos == position || currentTrack != tid) {
return position;
}
int snapped = requestBestSnapPos(position, m_allClips[cid]->getPlaytime());
//For snapping, we must ignore all in/outs of the clips of the group being moved
std::vector<int> ignored_pts;
if (m_groups->isInGroup(cid)) {
int gid = m_groups->getRootId(cid);
auto all_clips = m_groups->getLeaves(gid);
for (int current_cid : all_clips) {
int in = getClipPosition(current_cid);
int out = in + getClipPlaytime(current_cid) - 1;
ignored_pts.push_back(in);
ignored_pts.push_back(out);
}
} else {
int in = getClipPosition(cid);
int out = in + getClipPlaytime(cid) - 1;
ignored_pts.push_back(in);
ignored_pts.push_back(out);
}
int snapped = requestBestSnapPos(position, m_allClips[cid]->getPlaytime(), ignored_pts);
qDebug() << "Starting suggestion "<<cid << position << currentPos << "snapped to "<<snapped;
if (snapped >= 0) {
position = snapped;
}
qDebug() << "Starting suggestion "<<cid << position << currentPos;
//we check if move is possible
Fun undo = [](){return true;};
Fun redo = [](){return true;};
......@@ -775,7 +794,6 @@ bool TimelineModel::requestReset(Fun& undo, Fun& redo)
for (int tid : all_ids) {
ok = ok && requestTrackDeletion(tid, undo, redo);
}
TimelineModel::next_id = 0;
return ok;
}
......@@ -784,14 +802,16 @@ void TimelineModel::setUndoStack(std::weak_ptr<DocUndoStack> undo_stack)
m_undoStack = undo_stack;
}
int TimelineModel::requestBestSnapPos(int pos, int length, const std::vector<int> pts)
int TimelineModel::requestBestSnapPos(int pos, int length, const std::vector<int>& pts)
{
if (pts.size() > 0) {
m_snaps->ignore(pts);
}
int snapped_start = m_snaps->getClosestPoint(pos);
qDebug() << "snapping start suggestion" <<snapped_start;
int snapped_end = m_snaps->getClosestPoint(pos + length);
m_snaps->unIgnore();
int startDiff = qAbs(pos - snapped_start);
int endDiff = qAbs(pos + length - snapped_end);
if (startDiff < endDiff && snapped_start >= 0) {
......
......@@ -269,7 +269,7 @@ public:
@param pts snap points to ignore (for example currently moved clip)
@returns best snap position or -1 if no snap point is near
*/
int requestBestSnapPos(int pos, int length, const std::vector<int> pts = std::vector<int>());
int requestBestSnapPos(int pos, int length, const std::vector<int>& pts = std::vector<int>());
/* @brief Requests the next snapped point
@param pos is the current position
......
......@@ -95,7 +95,7 @@ Fun TrackModel::requestClipInsertion_lambda(int cid, int position, bool updateVi
clip->setPosition(position);
clip->setCurrentTrackId(getId());
int new_in = clip->getPosition();
int new_out = new_in + clip->getPlaytime();
int new_out = new_in + clip->getPlaytime() - 1;
ptr->m_snaps->addPoint(new_in);
ptr->m_snaps->addPoint(new_out);
if (updateView) {
......@@ -183,7 +183,7 @@ Fun TrackModel::requestClipDeletion_lambda(int cid, bool updateView)
delete prod;
if (auto ptr = m_parent.lock()) {
ptr->m_snaps->removePoint(old_in);
ptr->m_snaps->removePoint(old_out + 1);
ptr->m_snaps->removePoint(old_out);
}
return true;
}
......@@ -254,9 +254,9 @@ Fun TrackModel::requestClipResize_lambda(int cid, int in, int out, bool right)
auto update_snaps = [old_in, old_out, this](int new_in, int new_out) {
if (auto ptr = m_parent.lock()) {
ptr->m_snaps->removePoint(old_in);
ptr->m_snaps->removePoint(old_out + 1);
ptr->m_snaps->removePoint(old_out);
ptr->m_snaps->addPoint(new_in);
ptr->m_snaps->addPoint(new_out + 1);
ptr->m_snaps->addPoint(new_out);
} else {
qDebug() << "Error : clip resize failed because parent timeline is not available anymore";
Q_ASSERT(false);
......
......@@ -60,6 +60,7 @@ Rectangle {
property int duration: timeline.duration
property color shotcutBlue: Qt.rgba(23/255, 92/255, 118/255, 1.0)
property int clipBeingDroppedId: -1
property int clipBeingMovedId: -1
//property alias ripple: toolbar.ripple
//onCurrentTrackChanged: timeline.selection = []
......@@ -70,7 +71,7 @@ Rectangle {
y: ruler.height
x: headerWidth
onEntered: {
if (drag.formats.indexOf('kdenlive/producerslist') >= 0) {
if (clipBeingMovedId == -1 && drag.formats.indexOf('kdenlive/producerslist') >= 0) {
var track = Logic.getTrackIdFromPos(drag.y)
var frame = Math.round((drag.x + scrollView.flickableItem.contentX) / timeline.scaleFactor)
if (track >= 0) {
......@@ -91,12 +92,17 @@ Rectangle {
scrollTimer.running = false
}
onPositionChanged: {
if (clipBeingDroppedId >= 0){
if (clipBeingMovedId == -1) {
var track = Logic.getTrackIdFromPos(drag.y)
var frame = Math.round((drag.x + scrollView.flickableItem.contentX) / timeline.scaleFactor)
timeline.moveClip(clipBeingDroppedId, track, frame, true)
continuousScrolling(drag.x + scrollView.flickableItem.contentX)
if (clipBeingDroppedId >= 0){
timeline.moveClip(clipBeingDroppedId, track, frame, true)
continuousScrolling(drag.x + scrollView.flickableItem.contentX)
} else {
clipBeingDroppedId = timeline.insertClip(track, frame, drag.getDataAsString('kdenlive/producerslist'))
continuousScrolling(drag.x + scrollView.flickableItem.contentX)
}
}
}
onDropped: {
......@@ -450,11 +456,13 @@ Rectangle {
s = s.substring(3)
s = ((delta < 0)? '-' : (delta > 0)? '+' : '') + s
bubbleHelp.show(x, track.y + height/2, s)
clipBeingMovedId = clip.clipId
}
onClipDropped: {
console.log(" + + + ++ + DROPPED + + + + + + +");
scrollTimer.running = false
bubbleHelp.hide()
clipBeingMovedId = -1
}
onClipDraggedToTrack: {
var y = pos - ruler.height
......
......@@ -76,6 +76,7 @@ TEST_CASE("Snap points model test", "[SnapModel]")
REQUIRE(snap.getClosestPoint(0) == -1);
REQUIRE(snap.getClosestPoint(10) == -1);
snap.addPoint(10);
snap.addPoint(10);
auto state = [&]() {
REQUIRE(snap.getClosestPoint(0) == 10);
......@@ -86,17 +87,9 @@ TEST_CASE("Snap points model test", "[SnapModel]")
};
state();
snap.ignore({0});
state();
snap.ignore({10});
REQUIRE(snap.getClosestPoint(0) == -1);
REQUIRE(snap.getClosestPoint(10) == -1);
snap.unIgnore();
state();
snap.addPoint(10);
state();
snap.ignore({10});
REQUIRE(snap.getClosestPoint(0) == -1);
REQUIRE(snap.getClosestPoint(10) == -1);
......
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