insanely complex fixes for dragging to and from the drop zone.
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 13 Feb 2015 17:36:08 +0000 (12:36 -0500)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 13 Feb 2015 22:00:30 +0000 (17:00 -0500)
This probably breaks some of ardour's functionality (e.g. layered mode), but seems to
be either just right or very close to it for tracks

Conflicts:
gtk2_ardour/editor_routes.cc

gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_routes.cc

index 2fd642fb2969de389de737803468941b55103b30..c09d92b6f91eaa9205901fb3e449f06ffde65c5d 100644 (file)
@@ -645,14 +645,39 @@ RegionMotionDrag::y_movement_allowed (int delta_track, double delta_layer) const
        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 */
@@ -673,7 +698,7 @@ RegionMotionDrag::y_movement_allowed (int delta_track, double delta_layer) const
        }
 
        /* all regions being dragged are ok with this change */
-       return true;
+       return !all_in_drop_zone;
 }
 
 void
@@ -681,15 +706,10 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
 {
        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()) {
@@ -702,6 +722,13 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                }
        }
        
+       /* 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;
 
@@ -710,15 +737,22 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                }
 
                /* 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);
@@ -738,8 +772,20 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                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;
@@ -785,11 +831,30 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                        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 */
@@ -855,22 +920,49 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
 
                } 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;
                        }
                }
                
@@ -885,7 +977,35 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                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;
 }
 
index c7ad7c54ffa7dee36d3baae45c82f6f1d8e65f5f..30082adec4642b81a52dc510a911c15b8dd783f3 100644 (file)
@@ -515,8 +515,17 @@ EditorRoutes::redisplay_real ()
                        continue;
                }
 
+               if (route->is_master()) {
+                       
+                       tv->hide(); // never show master bus
+                       if (_editor->master_bus_ui ()) {
+                               _editor->master_bus_ui ()->set_route (route);
+                       }
+                       continue;
+               }
+               
                bool visible = tv->marked_for_display ();
-
+               
                /* show or hide the TimeAxisView */
                if (visible) {
                        position += tv->show_at (position, n, &_editor->edit_controls_vbox);