if (_y_constrained) {
return false;
}
+
+ bool all_in_drop_zone = true;
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- int const n = i->time_axis_view + delta_track;
- if (n < 0 || n >= int (_time_axis_views.size())) {
- /* off the top or bottom track */
- return false;
+ int n = i->time_axis_view + delta_track;
+ if (i->time_axis_view < 0) {
+ /* already in the drop zone */
+ if (delta_track > 0) {
+ /* downward motion - might be OK if others are still not in the dropzone,
+ so check at the end of the loop if that is the case.
+ */
+ continue;
+ }
+ /* upward motion, and this view is currently in the drop zone. That's fine, so
+ we have to set all_in_drop_zone correctly to avoid blocking upward motion.
+ */
+ all_in_drop_zone = false;
+ continue;
+ } else {
+
+ all_in_drop_zone = false;
+
+ if (n < 0) {
+ /* off the top */
+ return false;
+ }
}
+ if (n >= int (_time_axis_views.size())) {
+ /* downward motion into drop zone. That's fine. */
+ continue;
+ }
+
RouteTimeAxisView const * to = dynamic_cast<RouteTimeAxisView const *> (_time_axis_views[n]);
if (to == 0 || !to->is_track() || to->track()->data_type() != i->view->region()->data_type()) {
/* not a track, or the wrong type */
}
/* all regions being dragged are ok with this change */
- return true;
+ return !all_in_drop_zone;
}
void
{
double delta_layer = 0;
int delta_time_axis_view = 0;
+ int current_pointer_time_axis_view;
assert (!_views.empty ());
- /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */
-
- /* Find the TimeAxisView that the pointer is now over */
- pair<TimeAxisView*, double> const r = _editor->trackview_by_y_position (current_pointer_y ());
- TimeAxisView* tv = r.first;
-
if (first_move) {
if (_single_axis) {
if (initially_vertical()) {
}
}
+ /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */
+
+ /* Find the TimeAxisView that the pointer is now over */
+
+ pair<TimeAxisView*, double> const r = _editor->trackview_by_y_position (current_pointer_y ());
+ TimeAxisView* tv = r.first;
+
if (tv && tv->view()) {
double layer = r.second;
}
/* Here's the current pointer position in terms of time axis view and layer */
- int const current_pointer_time_axis_view = find_time_axis_view (tv);
+ current_pointer_time_axis_view = find_time_axis_view (tv);
+
double const current_pointer_layer = tv->layer_display() == Overlaid ? 0 : layer;
/* Work out the change in y */
- delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
+ if (_last_pointer_time_axis_view < 0) {
+ /* we can only move up */
+ delta_time_axis_view = -1;
+ } else {
+ delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
+ }
+
delta_layer = current_pointer_layer - _last_pointer_layer;
}
-
+
/* Work out the change in x */
framepos_t pending_region_position;
double const x_delta = compute_x_delta (event, &pending_region_position);
return;
}
- pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
+ typedef pair<int,double> NewTrackIndexAndPosition;
+ typedef map<boost::shared_ptr<Playlist>,NewTrackIndexAndPosition> PlaylistDropzoneMap;
+ PlaylistDropzoneMap playlist_dropzone_map;
+ int biggest_drop_zone_offset = 0;
+ Coord last_track_bottom_edge;
+
+ if (_time_axis_views.empty()) {
+ last_track_bottom_edge = 0;
+ } else {
+ TimeAxisView* last = _time_axis_views.back();
+ last_track_bottom_edge = last->canvas_display()->canvas_origin ().y + last->effective_height();
+ }
+
for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
RegionView* rv = i->view;
if (i->time_axis_view >= 0) {
track_index = i->time_axis_view + delta_time_axis_view;
} else {
- track_index = _time_axis_views.size() - 1 + delta_time_axis_view;
+ /* delta time axis view will be at least -1, because we can only
+ be moving up if some dragged views have i->time_axis_view negative.
+
+ the final real time axis view has index _time_axis_views.size() - 1.
+
+ so for DTAV = -1, the first drop zone track (i->tav == -1) should
+ move to the final TAV.
+
+ the second drop zone track should move to i->tav == -1 (i.e. becomes
+ the first drop zone track). and so on.
+ */
+
+ int index_from_bottom = i->time_axis_view - delta_time_axis_view;
+ int const bottom = _time_axis_views.size() - 1;
+
+ if (index_from_bottom >= 0) {
+ track_index = bottom - index_from_bottom;
+ } else {
+ track_index = index_from_bottom;
+ }
}
-
+
if (track_index < 0 || track_index >= (int) _time_axis_views.size()) {
- continue;
+ goto dropzone;
}
/* The TimeAxisView that this region is now over */
} else {
- /* Only move the region into the empty dropzone at the bottom if the pointer
- * is down there.
- */
-
+ dropzone:
+
if (current_pointer_y() >= 0) {
- Coord last_track_bottom_edge;
- if (!_time_axis_views.empty()) {
- TimeAxisView* last = _time_axis_views.back();
- last_track_bottom_edge = last->canvas_display()->canvas_origin ().y + last->effective_height();
+ NewTrackIndexAndPosition ip;
+ PlaylistDropzoneMap::iterator pdz = playlist_dropzone_map.find (i->view->region()->playlist());
+
+ /* store index of each new playlist as a negative count, starting at -1 */
+
+ if (pdz == playlist_dropzone_map.end()) {
+
+ int n = playlist_dropzone_map.size() + 1;
+
+ /* compute where this new track (which doesn't exist yet) will live
+ on the y-axis.
+ */
+
+ ip.first = -n; /* in time axis units, negative to signify "in drop zone " */
+ ip.second = last_track_bottom_edge; /* where to place the top edge of the regionview */
+
+ /* How high is this region view ? */
+
+ boost::optional<ArdourCanvas::Rect> obbox = rv->get_canvas_group()->bounding_box ();
+ ArdourCanvas::Rect bbox;
+
+ if (obbox) {
+ bbox = obbox.get ();
+ }
+
+ last_track_bottom_edge += bbox.height();
+
+ playlist_dropzone_map.insert (make_pair (i->view->region()->playlist(), ip));
+ i->time_axis_view = -n;
+
} else {
- last_track_bottom_edge = 0;
+ ip = pdz->second;
+ i->time_axis_view = ip.first;
}
- y_delta = last_track_bottom_edge - rv->get_canvas_group()->canvas_origin().y;
- i->time_axis_view = -1;
+ /* values are zero or negative, hence the use of min() */
+ biggest_drop_zone_offset = min (biggest_drop_zone_offset, i->time_axis_view);
+
+ y_delta = ip.second - rv->get_canvas_group()->canvas_origin().y;
}
}
show_verbose_cursor_time (_last_frame_position);
}
- _last_pointer_time_axis_view += delta_time_axis_view;
+ if (tv) {
+
+ /* the pointer is currently over a time axis view */
+
+ if (_last_pointer_time_axis_view < 0) {
+
+ /* last motion event was not over a time axis view */
+
+ if (delta_time_axis_view < 0) {
+ /* was in the drop zone, moving up */
+ _last_pointer_time_axis_view = current_pointer_time_axis_view;
+ } else {
+ /* was in the drop zone, moving down ... not possible */
+ }
+
+ } else {
+
+ /* last motion event was also over a time axis view */
+
+ _last_pointer_time_axis_view = current_pointer_time_axis_view;
+ }
+
+ } else {
+
+ /* the pointer is not over a time axis view */
+
+ _last_pointer_time_axis_view = biggest_drop_zone_offset;
+ }
+
_last_pointer_layer += delta_layer;
}