- Time const time_diff = (p.x - _down_point.x) / _pixels_per_time_unit;
- if (_down_view) {
- shared_ptr<Content> c = _down_view->content().lock();
- if (c) {
- c->set_start (max (static_cast<Time> (0), _down_view_start + time_diff));
-
- shared_ptr<Film> film = _film.lock ();
- assert (film);
- film->set_sequence_video (false);
+ if (!_down_view) {
+ return;
+ }
+
+ DCPTime new_position = _down_view_position + DCPTime::from_seconds ((p.x - _down_point.x) / _pixels_per_second);
+
+ if (_snap) {
+
+ bool first = true;
+ DCPTime nearest_distance = DCPTime::max ();
+ DCPTime nearest_new_position = DCPTime::max ();
+
+ /* Find the nearest content edge; this is inefficient */
+ for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
+ shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i);
+ if (!cv || cv == _down_view) {
+ continue;
+ }
+
+ {
+ /* Snap starts to ends */
+ DCPTime const d = DCPTime (cv->content()->end() - new_position).abs ();
+ if (first || d < nearest_distance) {
+ nearest_distance = d;
+ nearest_new_position = cv->content()->end();
+ }
+ }
+
+ {
+ /* Snap ends to starts */
+ DCPTime const d = DCPTime (
+ cv->content()->position() - (new_position + _down_view->content()->length_after_trim())
+ ).abs ();
+
+ if (d < nearest_distance) {
+ nearest_distance = d;
+ nearest_new_position = cv->content()->position() - _down_view->content()->length_after_trim ();
+ }
+ }
+
+ first = false;
+ }
+
+ if (!first) {
+ /* Snap if it's close; `close' means within a proportion of the time on the timeline */
+ if (nearest_distance < DCPTime::from_seconds ((width() / pixels_per_second()) / 32)) {
+ new_position = nearest_new_position;
+ }