Fix wonky note length when create-dragging notes backwards.
[ardour.git] / gtk2_ardour / editor_drag.cc
index 91bfb2ce0c4bda4b5249dcdc1ea5df01167128f2..0aaec8d24d5e4e8129b1f919fd2b5bf45d668696 100644 (file)
@@ -40,6 +40,7 @@
 #include "ardour/region_factory.h"
 #include "ardour/session.h"
 
+#include "canvas/canvas.h"
 #include "canvas/scroll_group.h"
 
 #include "editor.h"
@@ -94,6 +95,8 @@ DragManager::abort ()
 {
        _ending = true;
 
+       cerr << "Aborting drag\n";
+
        for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
                (*i)->abort ();
                delete *i;
@@ -1572,10 +1575,16 @@ RegionSpliceDrag::aborted (bool)
 void
 RegionRippleDrag::add_all_after_to_views(TimeAxisView *tav, framepos_t where, const RegionSelection &exclude, bool drag_in_progress)
 {
+
+       boost::shared_ptr<RegionList> rl = tav->playlist()->regions_with_start_within (Evoral::Range<framepos_t>(where, max_framepos));
+
+       RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(tav);
        RegionSelection to_ripple;
-       TrackViewList tracks;
-       tracks.push_back (tav);
-       _editor->get_regions_after (to_ripple, where, tracks);
+       for (RegionList::iterator i = rl->begin(); i != rl->end(); ++i) {
+               if ((*i)->position() >= where) {
+                       to_ripple.push_back (rtv->view()->find_view(*i));
+               }
+       }
 
        for (RegionSelection::iterator i = to_ripple.begin(); i != to_ripple.end(); ++i) {
                if (!exclude.contains (*i)) {
@@ -1691,7 +1700,7 @@ RegionRippleDrag::RegionRippleDrag (Editor* e, ArdourCanvas::Item* i, RegionView
                assert (first_selected_on_this_track); // we should always find the region in one of the playlists...
                add_all_after_to_views (
                                &first_selected_on_this_track->get_time_axis_view(),
-                               first_selected_on_this_track->region()->position() + first_selected_on_this_track->region()->length(),
+                               first_selected_on_this_track->region()->position(),
                                selected_regions, false);
        }
 
@@ -1782,6 +1791,15 @@ void
 RegionRippleDrag::finished (GdkEvent* event, bool movement_occurred)
 {
        if (!movement_occurred) {
+               
+               /* just a click */
+
+               if (was_double_click() && !_views.empty()) {
+                       DraggingView dv = _views.front();
+                       dv.view->show_region_editor ();
+                       
+               }
+
                return;
        }
 
@@ -1949,7 +1967,10 @@ NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/)
                MidiRegionSelection::iterator next;
                next = r;
                ++next;
-               (*r)->begin_resizing (at_front);
+               MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*r);
+               if (mrv) {
+                       mrv->begin_resizing (at_front);
+               }
                r = next;
        }
 }
@@ -1961,7 +1982,10 @@ NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
        for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
                NoteBase* nb = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
                assert (nb);
-               (*r)->update_resizing (nb, at_front, _drags->current_pointer_x() - grab_x(), relative);
+               MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*r);
+               if (mrv) {
+                       mrv->update_resizing (nb, at_front, _drags->current_pointer_x() - grab_x(), relative);
+               }
        }
 }
 
@@ -1972,7 +1996,10 @@ NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
        for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
                NoteBase* nb = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
                assert (nb);
-               (*r)->commit_resizing (nb, at_front, _drags->current_pointer_x() - grab_x(), relative);
+               MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*r);
+               if (mrv) {
+                       mrv->commit_resizing (nb, at_front, _drags->current_pointer_x() - grab_x(), relative);
+               }
        }
 }
 
@@ -1981,7 +2008,10 @@ NoteResizeDrag::aborted (bool)
 {
        MidiRegionSelection& ms (_editor->get_selection().midi_regions);
        for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
-               (*r)->abort_resizing ();
+               MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*r);
+               if (mrv) {
+                       mrv->abort_resizing ();
+               }
        }
 }
 
@@ -2565,7 +2595,7 @@ MeterMarkerDrag::motion (GdkEvent* event, bool first_move)
                _marker = new MeterMarker (
                        *_editor,
                        *_editor->meter_group,
-                       ARDOUR_UI::config()->get_canvasvar_MeterMarker(),
+                       ARDOUR_UI::config()->get_MeterMarker(),
                        name,
                        *new MeterSection (_marker->meter())
                );
@@ -2695,7 +2725,7 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
                _marker = new TempoMarker (
                        *_editor,
                        *_editor->tempo_group,
-                       ARDOUR_UI::config()->get_canvasvar_TempoMarker(),
+                       ARDOUR_UI::config()->get_TempoMarker(),
                        name,
                        *new TempoSection (_marker->tempo())
                        );
@@ -4230,9 +4260,16 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
                        }
                }
                
+               //if user is selecting a range on an automation track, bail out here before we get to the grouped stuff, 
+               // because the grouped stuff will start working on tracks (routeTAVs), and end up removing this 
+               AutomationTimeAxisView *atest = dynamic_cast<AutomationTimeAxisView *>(_editor->clicked_axisview);
+               if (atest) {
+                       _editor->selection->add (atest);
+                       break; 
+               }
+               
                /* select all tracks within the rectangle that we've marked out so far */
-               TrackViewList to_be_added_to_selection;
-               TrackViewList to_be_removed_from_selection;
+               TrackViewList new_selection;
                TrackViewList& all_tracks (_editor->track_views);
 
                ArdourCanvas::Coord const top = grab_y();
@@ -4240,26 +4277,39 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
 
                if (top >= 0 && bottom >= 0) {
 
+                       //first, find the tracks that are covered in the y range selection
                        for (TrackViewList::const_iterator i = all_tracks.begin(); i != all_tracks.end(); ++i) {
-                       
                                if ((*i)->covered_by_y_range (top, bottom)) {
-                                       if (!(*i)->get_selected()) {
-                                               to_be_added_to_selection.push_back (*i);
-                                       }
-                               } else {
-                                       if ((*i)->get_selected()) {
-                                               to_be_removed_from_selection.push_back (*i);
-                                       }
+                                       new_selection.push_back (*i);
                                }
                        }
 
-                       if (!to_be_added_to_selection.empty()) {
-                               _editor->selection->add (to_be_added_to_selection);
-                       }
-                       
-                       if (!to_be_removed_from_selection.empty()) {
-                               _editor->selection->remove (to_be_removed_from_selection);
+                       //now find any tracks that are GROUPED with the tracks we selected
+                       TrackViewList grouped_add = new_selection;
+                       for (TrackViewList::const_iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
+                               RouteTimeAxisView *n = dynamic_cast<RouteTimeAxisView *>(*i);
+                               if ( n && n->route()->route_group() && n->route()->route_group()->is_active() && n->route()->route_group()->enabled_property (ARDOUR::Properties::select.property_id) ) {
+                                       for (TrackViewList::const_iterator j = all_tracks.begin(); j != all_tracks.end(); ++j) {
+                                               RouteTimeAxisView *check = dynamic_cast<RouteTimeAxisView *>(*j);
+                                               if ( check && (n != check) && (check->route()->route_group() == n->route()->route_group()) )
+                                                       grouped_add.push_back (*j);
+                                       }
+                               }
                        }
+
+                       //now compare our list with the current selection, and add or remove as necessary
+                       //( NOTE: most mouse moves don't change the selection so we can't just SET it for every mouse move; it gets clunky )
+                       TrackViewList tracks_to_add;
+                       TrackViewList tracks_to_remove;
+                       for (TrackViewList::const_iterator i = grouped_add.begin(); i != grouped_add.end(); ++i)
+                               if ( !_editor->selection->tracks.contains ( *i ) )
+                                       tracks_to_add.push_back ( *i );
+                       for (TrackViewList::const_iterator i = _editor->selection->tracks.begin(); i != _editor->selection->tracks.end(); ++i)
+                               if ( !grouped_add.contains ( *i ) )
+                                       tracks_to_remove.push_back ( *i );
+                       _editor->selection->add(tracks_to_add);
+                       _editor->selection->remove(tracks_to_remove);
+
                }
        }
        break;
@@ -4343,8 +4393,11 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
                        if ( s->get_play_range() && s->transport_rolling() ) {
                                s->request_play_range (&_editor->selection->time, true);
                        } else {
-                               if (Config->get_always_play_range() && !s->transport_rolling()) {
-                                       s->request_locate (_editor->get_selection().time.start());
+                               if (Config->get_follow_edits() && !s->transport_rolling()) {
+                                       if (_operation == SelectionEndTrim)
+                                               _editor->maybe_locate_with_edit_preroll( _editor->get_selection().time.end_frame());
+                                       else
+                                               s->request_locate (_editor->get_selection().time.start());
                                }
                        }
                }
@@ -4404,8 +4457,8 @@ RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operat
                                                                      physical_screen_height (_editor->get_window())));
        _drag_rect->hide ();
 
-       _drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragRect());
-       _drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragRect());
+       _drag_rect->set_fill_color (ARDOUR_UI::config()->get_RangeDragRect());
+       _drag_rect->set_outline_color (ARDOUR_UI::config()->get_RangeDragRect());
 }
 
 void
@@ -4422,6 +4475,7 @@ RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
        }
 
        switch (_operation) {
+       case CreateSkipMarker:
        case CreateRangeMarker:
        case CreateTransportMarker:
        case CreateCDMarker:
@@ -4448,6 +4502,9 @@ RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
        ArdourCanvas::Rectangle *crect;
 
        switch (_operation) {
+       case CreateSkipMarker:
+               crect = _editor->range_bar_drag_rect;
+               break;
        case CreateRangeMarker:
                crect = _editor->range_bar_drag_rect;
                break;
@@ -4465,7 +4522,7 @@ RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
 
        framepos_t const pf = adjusted_current_frame (event);
 
-       if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
+       if (_operation == CreateSkipMarker || _operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
                framepos_t grab = grab_frame ();
                _editor->snap_to (grab);
 
@@ -4521,17 +4578,24 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
                _drag_rect->hide();
 
                switch (_operation) {
+               case CreateSkipMarker:
                case CreateRangeMarker:
                case CreateCDMarker:
                    {
-                       _editor->begin_reversible_command (_("new range marker"));
                        XMLNode &before = _editor->session()->locations()->get_state();
-                       _editor->session()->locations()->next_available_name(rangename,"unnamed");
-                       if (_operation == CreateCDMarker) {
+                       if (_operation == CreateSkipMarker) {
+                               _editor->begin_reversible_command (_("new skip marker"));
+                               _editor->session()->locations()->next_available_name(rangename,_("skip"));
+                               flags = Location::IsRangeMarker | Location::IsSkip;
+                               _editor->range_bar_drag_rect->hide();
+                       } else if (_operation == CreateCDMarker) {
+                               _editor->session()->locations()->next_available_name(rangename, _("CD"));
+                               _editor->begin_reversible_command (_("new CD marker"));
                                flags = Location::IsRangeMarker | Location::IsCDMarker;
                                _editor->cd_marker_bar_drag_rect->hide();
-                       }
-                       else {
+                       } else {
+                               _editor->begin_reversible_command (_("new skip marker"));
+                               _editor->session()->locations()->next_available_name(rangename, _("unnamed"));
                                flags = Location::IsRangeMarker;
                                _editor->range_bar_drag_rect->hide();
                        }
@@ -4567,7 +4631,7 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
                        /* didn't drag, but mark is already created so do
                         * nothing */
 
-               } else { /* operation == CreateRangeMarker */
+               } else { /* operation == CreateRangeMarker || CreateSkipMarker */
                        
 
                        framepos_t start;
@@ -4619,88 +4683,6 @@ RangeMarkerBarDrag::update_item (Location* location)
        _drag_rect->set_x1 (x2);
 }
 
-MouseZoomDrag::MouseZoomDrag (Editor* e, ArdourCanvas::Item* i)
-       : Drag (e, i)
-       , _zoom_out (false)
-{
-       DEBUG_TRACE (DEBUG::Drags, "New MouseZoomDrag\n");
-}
-
-void
-MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
-{
-       if (Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
-               Drag::start_grab (event, _editor->cursors()->zoom_out);
-               _zoom_out = true;
-       } else {
-               Drag::start_grab (event, _editor->cursors()->zoom_in);
-               _zoom_out = false;
-       }
-
-       show_verbose_cursor_time (adjusted_current_frame (event));
-}
-
-void
-MouseZoomDrag::motion (GdkEvent* event, bool first_move)
-{
-       framepos_t start;
-       framepos_t end;
-
-       framepos_t const pf = adjusted_current_frame (event);
-
-       framepos_t grab = grab_frame ();
-       _editor->snap_to_with_modifier (grab, event);
-
-       /* base start and end on initial click position */
-       if (pf < grab) {
-               start = pf;
-               end = grab;
-       } else {
-               end = pf;
-               start = grab;
-       }
-
-       if (start != end) {
-
-               if (first_move) {
-                       _editor->zoom_rect->show();
-                       _editor->zoom_rect->raise_to_top();
-               }
-
-               _editor->reposition_zoom_rect(start, end);
-
-               show_verbose_cursor_time (pf);
-       }
-}
-
-void
-MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
-{
-       if (movement_occurred) {
-               motion (event, false);
-
-               if (grab_frame() < last_pointer_frame()) {
-                       _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame());
-               } else {
-                       _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame());
-               }
-       } else {
-               if (Keyboard::the_keyboard().key_is_down (GDK_Shift_L)) {
-                       _editor->tav_zoom_step (_zoom_out);
-               } else {
-                       _editor->temporal_zoom_to_frame (_zoom_out, grab_frame());
-               }
-       }
-
-       _editor->zoom_rect->hide();
-}
-
-void
-MouseZoomDrag::aborted (bool)
-{
-       _editor->zoom_rect->hide ();
-}
-
 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
        : Drag (e, i)
        , _cumulative_dx (0)
@@ -4967,8 +4949,8 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
                                double const p = j->line->time_converter().from (i->start - j->line->time_converter().origin_b ());
                                double const q = j->line->time_converter().from (a - j->line->time_converter().origin_b ());
 
-                               the_list->add (p, the_list->eval (p));
-                               the_list->add (q, the_list->eval (q));
+                               the_list->editor_add (p, the_list->eval (p));
+                               the_list->editor_add (q, the_list->eval (q));
                        }
 
                        /* same thing for the end */
@@ -4993,8 +4975,8 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
                                double const p = j->line->time_converter().from (b - j->line->time_converter().origin_b ());
                                double const q = j->line->time_converter().from (i->end - j->line->time_converter().origin_b ());
 
-                               the_list->add (p, the_list->eval (p));
-                               the_list->add (q, the_list->eval (q));
+                               the_list->editor_add (p, the_list->eval (p));
+                               the_list->editor_add (q, the_list->eval (q));
                        }
                }
 
@@ -5298,12 +5280,10 @@ void
 NoteCreateDrag::motion (GdkEvent* event, bool)
 {
        _note[1] = max ((framepos_t)0, adjusted_current_frame (event) - _region_view->region()->position ());
-       double const x = _editor->sample_to_pixel (_note[1]);
-       if (_note[1] > _note[0]) {
-               _drag_rect->set_x1 (x);
-       } else {
-               _drag_rect->set_x0 (x);
-       }
+       double const x0 = _editor->sample_to_pixel (_note[0]);
+       double const x1 = _editor->sample_to_pixel (_note[1]);
+       _drag_rect->set_x0 (std::min(x0, x1));
+       _drag_rect->set_x1 (std::max(x0, x1));
 }
 
 void
@@ -5438,3 +5418,47 @@ CrossfadeEdgeDrag::aborted (bool)
        }
 }
 
+RegionCutDrag::RegionCutDrag (Editor* e, ArdourCanvas::Item* item, framepos_t pos)
+       : Drag (e, item, true)
+       , line (new EditorCursor (*e))
+{
+       line->set_position (pos);
+       line->show ();
+}
+
+RegionCutDrag::~RegionCutDrag ()
+{
+       delete line;
+}
+
+void
+RegionCutDrag::motion (GdkEvent*, bool)
+{
+       framepos_t where = _drags->current_pointer_frame();
+       _editor->snap_to (where);
+
+       line->set_position (where);
+}
+
+void
+RegionCutDrag::finished (GdkEvent*, bool)
+{
+       _editor->get_track_canvas()->canvas()->re_enter();
+
+       framepos_t pos = _drags->current_pointer_frame();
+       
+       line->hide ();
+
+       RegionSelection rs = _editor->get_regions_from_selection_and_mouse (pos);
+
+       if (rs.empty()) {
+               return;
+       }
+
+       _editor->split_regions_at (pos, rs);
+}
+
+void
+RegionCutDrag::aborted (bool)
+{
+}