Prevent region drags with the middle button in internal edit mode (#3869).
[ardour.git] / gtk2_ardour / editor_drag.cc
index 07fe0ff09a2d1d53c80074087619fee8d00a8c1b..00313d06720b41d00cba917179c48c96f185fa18 100644 (file)
@@ -32,6 +32,8 @@
 #include "ardour/session.h"
 #include "ardour/dB.h"
 #include "ardour/region_factory.h"
+#include "ardour/operations.h"
+
 #include "editor.h"
 #include "i18n.h"
 #include "keyboard.h"
@@ -91,6 +93,8 @@ DragManager::abort ()
 
        _drags.clear ();
 
+       _editor->set_follow_playhead (_old_follow_playhead, false);
+       
        _ending = false;
 }
 
@@ -112,6 +116,10 @@ DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
 void
 DragManager::start_grab (GdkEvent* e, Gdk::Cursor* c)
 {
+       /* Prevent follow playhead during the drag to be nice to the user */
+       _old_follow_playhead = _editor->follow_playhead ();
+       _editor->set_follow_playhead (false);
+               
        _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
        
        for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
@@ -139,6 +147,8 @@ DragManager::end_grab (GdkEvent* e)
        _drags.clear ();
 
        _ending = false;
+
+       _editor->set_follow_playhead (_old_follow_playhead, false);
        
        return r;
 }
@@ -306,7 +316,7 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
 
        if (!from_autoscroll && !_move_threshold_passed) {
 
-               bool const xp = (::llabs (_drags->current_pointer_frame () - _grab_frame) >= threshold.first);
+               bool const xp = (::llabs (_drags->current_pointer_frame () - _raw_grab_frame) >= threshold.first);
                bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
 
                _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
@@ -339,7 +349,7 @@ Drag::abort ()
                _item->ungrab (0);
        }
 
-       aborted ();
+       aborted (_move_threshold_passed);
 
        _editor->stop_canvas_autoscroll ();
        _editor->hide_verbose_canvas_cursor ();
@@ -897,7 +907,7 @@ RegionMoveDrag::finished_no_copy (
        if (_x_constrained) {
                _editor->begin_reversible_command (_("fixed time region drag"));
        } else {
-               _editor->begin_reversible_command (_("region drag"));
+               _editor->begin_reversible_command (Operations::region_drag);
        }
 
        for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
@@ -1124,7 +1134,7 @@ RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & pl
        for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
                StatefulDiffCommand* c = new StatefulDiffCommand (*i);
                if (!c->empty()) {
-                       _editor->session()->add_command (new StatefulDiffCommand (*i));
+                       _editor->session()->add_command (c);
                } else {
                        delete c;
                }
@@ -1133,7 +1143,7 @@ RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & pl
 
 
 void
-RegionMoveDrag::aborted ()
+RegionMoveDrag::aborted (bool movement_occurred)
 {
        if (_copy) {
 
@@ -1144,12 +1154,12 @@ RegionMoveDrag::aborted ()
                _views.clear ();
 
        } else {
-               RegionMotionDrag::aborted ();
+               RegionMotionDrag::aborted (movement_occurred);
        }
 }
 
 void
-RegionMotionDrag::aborted ()
+RegionMotionDrag::aborted (bool)
 {
        for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
                RegionView* rv = i->view;
@@ -1166,7 +1176,10 @@ RegionMotionDrag::aborted ()
 
        _editor->update_canvas_now ();
 }
-                                     
+
+/** @param b true to brush, otherwise false.
+ *  @param c true to make copies of the regions being moved, otherwise false.
+ */
 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
        : RegionMotionDrag (e, i, p, v, b),
          _copy (c)
@@ -1219,7 +1232,7 @@ RegionInsertDrag::finished (GdkEvent *, bool)
 
        boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
 
-       _editor->begin_reversible_command (_("insert region"));
+       _editor->begin_reversible_command (Operations::insert_region);
        playlist->clear_changes ();
        playlist->add_region (_primary->region (), _last_frame_position);
        _editor->session()->add_command (new StatefulDiffCommand (playlist));
@@ -1231,7 +1244,7 @@ RegionInsertDrag::finished (GdkEvent *, bool)
 }
 
 void
-RegionInsertDrag::aborted ()
+RegionInsertDrag::aborted (bool)
 {
        delete _primary;
        _primary = 0;
@@ -1330,7 +1343,7 @@ RegionSpliceDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-RegionSpliceDrag::aborted ()
+RegionSpliceDrag::aborted (bool)
 {
        /* XXX: TODO */
 }
@@ -1349,6 +1362,7 @@ RegionCreateDrag::motion (GdkEvent* event, bool first_move)
 {
        if (first_move) {
                add_region();
+               _view->playlist()->freeze ();
        } else {
                if (_region) {
                        framepos_t const f = adjusted_current_frame (event);
@@ -1368,6 +1382,8 @@ RegionCreateDrag::finished (GdkEvent*, bool movement_occurred)
 {
        if (!movement_occurred) {
                add_region ();
+       } else {
+               _view->playlist()->thaw ();
        }
 
        if (_region) {
@@ -1391,8 +1407,12 @@ RegionCreateDrag::add_region ()
 }
 
 void
-RegionCreateDrag::aborted ()
+RegionCreateDrag::aborted (bool)
 {
+       if (_region) {
+               _view->playlist()->thaw ();
+       }
+
        /* XXX */
 }
 
@@ -1479,7 +1499,7 @@ NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
 }
 
 void
-NoteResizeDrag::aborted ()
+NoteResizeDrag::aborted (bool)
 {
        /* XXX: TODO */
 }
@@ -1503,14 +1523,13 @@ RegionGainDrag::finished (GdkEvent *, bool)
 }
 
 void
-RegionGainDrag::aborted ()
+RegionGainDrag::aborted (bool)
 {
        /* XXX: TODO */
 }
 
 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
        : RegionDrag (e, i, p, v)
-       , _have_transaction (false)
 {
        DEBUG_TRACE (DEBUG::Drags, "New TrimDrag\n");
 }
@@ -1602,13 +1621,12 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
                }
 
                _editor->begin_reversible_command (trim_type);
-               _have_transaction = true;
 
                for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
                        RegionView* rv = i->view;
                        rv->fake_set_opaque (false);
                        rv->enable_display (false);
-                       rv->region()->clear_changes ();
+                       rv->region()->playlist()->clear_owned_changes ();
 
                        AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
 
@@ -1706,12 +1724,24 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
                        _primary->thaw_after_trim ();
                } else {
 
+                       set<boost::shared_ptr<Playlist> > diffed_playlists;
+
                        for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-                               i->view->thaw_after_trim ();
+                                i->view->thaw_after_trim ();
                                i->view->enable_display (true);
                                i->view->fake_set_opaque (true);
-                               if (_have_transaction) {
-                                       _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
+
+                               /* Trimming one region may affect others on the playlist, so we need
+                                  to get undo Commands from the whole playlist rather than just the
+                                  region.  Use diffed_playlists to make sure we don't diff a given
+                                  playlist more than once.
+                               */
+                               boost::shared_ptr<Playlist> p = i->view->region()->playlist ();
+                               if (diffed_playlists.find (p) == diffed_playlists.end()) {
+                                       vector<Command*> cmds;
+                                       p->rdiff (cmds);
+                                       _editor->session()->add_commands (cmds);
+                                       diffed_playlists.insert (p);
                                }
                        }
                }
@@ -1720,9 +1750,7 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
                }
 
                _editor->motion_frozen_playlists.clear ();
-               if (_have_transaction) {
-                       _editor->commit_reversible_command();
-               }
+               _editor->commit_reversible_command();
 
        } else {
                /* no mouse movement */
@@ -1739,7 +1767,7 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-TrimDrag::aborted ()
+TrimDrag::aborted (bool movement_occurred)
 {
        /* Our motion method is changing model state, so use the Undo system
           to cancel.  Perhaps not ideal, as this will leave an Undo point
@@ -1748,7 +1776,7 @@ TrimDrag::aborted ()
 
        finished (0, true);
        
-       if (_have_transaction) {
+       if (movement_occurred) {
                _editor->undo ();
        }
 
@@ -1803,7 +1831,6 @@ MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
                MeterMarker* new_marker = new MeterMarker (
                        *_editor,
                        *_editor->meter_group,
-                       *_editor->cursor_group,
                        ARDOUR_UI::config()->canvasvar_MeterMarker.get(),
                        name,
                        *new MeterSection (_marker->meter())
@@ -1879,7 +1906,7 @@ MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-MeterMarkerDrag::aborted ()
+MeterMarkerDrag::aborted (bool)
 {
        _marker->set_position (_marker->meter().frame ());
 }
@@ -1907,7 +1934,6 @@ TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
                TempoMarker* new_marker = new TempoMarker (
                        *_editor,
                        *_editor->tempo_group,
-                       *_editor->cursor_group,
                        ARDOUR_UI::config()->canvasvar_TempoMarker.get(),
                        name,
                        *new TempoSection (_marker->tempo())
@@ -1973,7 +1999,7 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-TempoMarkerDrag::aborted ()
+TempoMarkerDrag::aborted (bool)
 {
        _marker->set_position (_marker->tempo().frame());
 }
@@ -2071,7 +2097,7 @@ CursorDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-CursorDrag::aborted ()
+CursorDrag::aborted (bool)
 {
        if (_editor->_dragging_playhead) {
                _editor->session()->request_resume_timecode_transmission ();
@@ -2186,7 +2212,7 @@ FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-FadeInDrag::aborted ()
+FadeInDrag::aborted (bool)
 {
        for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
                AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
@@ -2309,7 +2335,7 @@ FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-FadeOutDrag::aborted ()
+FadeOutDrag::aborted (bool)
 {
        for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
                AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
@@ -2333,13 +2359,6 @@ MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
 
        _points.push_back (Gnome::Art::Point (0, 0));
        _points.push_back (Gnome::Art::Point (0, physical_screen_height (_editor->get_window())));
-
-       _line = new ArdourCanvas::Line (*_editor->timebar_group);
-       _line->property_width_pixels() = 1;
-       _line->property_points () = _points;
-       _line->hide ();
-
-       _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
 }
 
 MarkerDrag::~MarkerDrag ()
@@ -2446,10 +2465,6 @@ MarkerDrag::motion (GdkEvent* event, bool)
 
        framepos_t next = newframe;
 
-       if (newframe == last_pointer_frame()) {
-               return;
-       }
-
        if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
                move_both = true;
        }
@@ -2543,7 +2558,7 @@ MarkerDrag::motion (GdkEvent* event, bool)
                                        copy_location->set_end (new_end);
                                } else  if (new_start < copy_location->end()) {
                                        copy_location->set_start (new_start);
-                               } else {
+                               } else if (newframe > 0) {
                                        _editor->snap_to (next, 1, true);
                                        copy_location->set_end (next);
                                        copy_location->set_start (newframe);
@@ -2641,12 +2656,10 @@ MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
        XMLNode &after = _editor->session()->locations()->get_state();
        _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
        _editor->commit_reversible_command ();
-
-       _line->hide();
 }
 
 void
-MarkerDrag::aborted ()
+MarkerDrag::aborted (bool)
 {
        /* XXX: TODO */
 }
@@ -2654,11 +2667,7 @@ MarkerDrag::aborted ()
 void
 MarkerDrag::update_item (Location* location)
 {
-       double const x1 = _editor->frame_to_pixel (location->start());
-
-       _points.front().set_x(x1);
-       _points.back().set_x(x1);
-       _line->property_points() = _points;
+        /* noop */
 }
 
 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
@@ -2769,7 +2778,7 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-ControlPointDrag::aborted ()
+ControlPointDrag::aborted (bool)
 {
        _point->line().reset ();
 }
@@ -2879,7 +2888,7 @@ LineDrag::finished (GdkEvent* event, bool)
 }
 
 void
-LineDrag::aborted ()
+LineDrag::aborted (bool)
 {
        _line->reset ();
 }
@@ -2897,7 +2906,7 @@ FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
 {
        Drag::start_grab (event);
        
-       _line = reinterpret_cast<SimpleLine*> (_item);
+       _line = reinterpret_cast<Line*> (_item);
        assert (_line);
 
        /* need to get x coordinate in terms of parent (AudioRegionView) origin. */
@@ -2910,10 +2919,10 @@ FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
        /* store grab start in parent frame */
        _region_view_grab_x = cx;
        
-       _before = _line->property_x1();
+       _before = *(float*) _item->get_data ("position");
        
        _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
-               
+
        _max_x = _editor->frame_to_pixel(_arv->get_duration());
 }
 
@@ -2935,21 +2944,34 @@ FeatureLineDrag::motion (GdkEvent*, bool)
                cx = 0;
        }
        
-       _line->property_x1() = cx; 
-       _line->property_x2() = cx;
+       ArdourCanvas::Points points;
+       
+       double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
 
-       _before = _line->property_x1();
+       _line->get_bounds(x1, y2, x2, y2);
+       
+       points.push_back(Gnome::Art::Point(cx, 2.0)); // first x-coord needs to be a non-normal value
+       points.push_back(Gnome::Art::Point(cx, y2 - y1));
+
+       _line->property_points() = points;
+       
+       float *pos = new float;
+       *pos = cx;
+       
+       _line->set_data ("position", pos);
+
+       _before = cx;
 }
 
 void
 FeatureLineDrag::finished (GdkEvent*, bool)
 {
        _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
-       _arv->update_transient(_before, _line->property_x1());
+       _arv->update_transient(_before, _before);
 }
 
 void
-FeatureLineDrag::aborted ()
+FeatureLineDrag::aborted (bool)
 {
        //_line->reset ();
 }
@@ -3036,19 +3058,16 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
 
 
                Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
-               bool committed;
 
                _editor->begin_reversible_command (_("rubberband selection"));
 
                if (grab_frame() < last_pointer_frame()) {
-                       committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op, false);
+                       _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op, false);
                } else {
-                       committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op, false);
+                       _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op, false);
                }
 
-               if (!committed) {
-                       _editor->commit_reversible_command ();
-               }
+               _editor->commit_reversible_command ();
 
        } else {
                if (!getenv("ARDOUR_SAE")) {
@@ -3063,7 +3082,7 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-RubberbandSelectDrag::aborted ()
+RubberbandSelectDrag::aborted (bool)
 {
        _editor->rubberband_rect->hide ();
 }
@@ -3134,7 +3153,7 @@ TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
 }
 
 void
-TimeFXDrag::aborted ()
+TimeFXDrag::aborted (bool)
 {
        _primary->get_time_axis_view().hide_timestretch ();
 }
@@ -3167,7 +3186,7 @@ ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
 }
 
 void
-ScrubDrag::aborted ()
+ScrubDrag::aborted (bool)
 {
        /* XXX: TODO */
 }
@@ -3435,7 +3454,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-SelectionDrag::aborted ()
+SelectionDrag::aborted (bool)
 {
        /* XXX: TODO */
 }
@@ -3641,7 +3660,7 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-RangeMarkerBarDrag::aborted ()
+RangeMarkerBarDrag::aborted (bool)
 {
        /* XXX: TODO */
 }
@@ -3722,14 +3741,18 @@ MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
                        _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
                }
        } else {
-               _editor->temporal_zoom_to_frame (_zoom_out, grab_frame());
+               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 ()
+MouseZoomDrag::aborted (bool)
 {
        _editor->zoom_rect->hide ();
 }
@@ -3871,7 +3894,7 @@ NoteDrag::finished (GdkEvent* ev, bool moved)
 }
 
 void
-NoteDrag::aborted ()
+NoteDrag::aborted (bool)
 {
        /* XXX: TODO */
 }
@@ -4074,7 +4097,7 @@ AutomationRangeDrag::finished (GdkEvent* event, bool)
 }
 
 void
-AutomationRangeDrag::aborted ()
+AutomationRangeDrag::aborted (bool)
 {
        for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
                i->line->clear_always_in_view ();
@@ -4136,7 +4159,7 @@ PatchChangeDrag::finished (GdkEvent* ev, bool movement_occurred)
 }
 
 void
-PatchChangeDrag::aborted ()
+PatchChangeDrag::aborted (bool)
 {
        _patch_change->move (-_cumulative_dx, 0);
 }