Categorize the mixer actions.
[ardour.git] / gtk2_ardour / editor_drag.cc
index 00989c5454a4489a000623a84325be166a35d699..c62151fc280eff01fd9ba04f3406c30ed1d166e7 100644 (file)
@@ -238,6 +238,7 @@ Drag::Drag (Editor* e, ArdourCanvas::Item* i, bool trackview_only)
        , _grab_frame (0)
        , _last_pointer_frame (0)
        , _snap_delta (0)
+       , _snap_delta_music (0.0)
        , _constraint_pressed (false)
 {
 
@@ -327,7 +328,7 @@ Drag::end_grab (GdkEvent* event)
 MusicFrame
 Drag::adjusted_frame (framepos_t f, GdkEvent const * event, bool snap) const
 {
-       MusicFrame pos (f, 0);
+       MusicFrame pos (0, 0);
 
        if (f > _pointer_frame_offset) {
                pos.frame = f - _pointer_frame_offset;
@@ -355,6 +356,15 @@ Drag::snap_delta (guint state) const
 
        return 0;
 }
+double
+Drag::snap_delta_music (guint state) const
+{
+       if (ArdourKeyboard::indicates_snap_delta (state)) {
+               return _snap_delta_music;
+       }
+
+       return 0.0;
+}
 
 double
 Drag::current_pointer_x() const
@@ -373,11 +383,18 @@ Drag::current_pointer_y () const
 }
 
 void
-Drag::setup_snap_delta (framepos_t pos)
+Drag::setup_snap_delta (MusicFrame pos)
 {
-       MusicFrame snap (pos, 0);
+       TempoMap& map (_editor->session()->tempo_map());
+       MusicFrame snap (pos);
        _editor->snap_to (snap, ARDOUR::RoundNearest, false, true);
-       _snap_delta = snap.frame - pos;
+       _snap_delta = snap.frame - pos.frame;
+
+       _snap_delta_music = 0.0;
+
+       if (_snap_delta != 0) {
+               _snap_delta_music = map.exact_qn_at_frame (snap.frame, snap.division) - map.exact_qn_at_frame (pos.frame, pos.division);
+       }
 }
 
 bool
@@ -618,7 +635,7 @@ void
 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 {
        Drag::start_grab (event, cursor);
-       setup_snap_delta (_last_position.frame);
+       setup_snap_delta (_last_position);
 
        show_verbose_cursor_time (_last_position.frame);
 
@@ -679,23 +696,19 @@ RegionMotionDrag::compute_x_delta (GdkEvent const * event, MusicFrame* pending_r
        if ((pending_region_position->frame != _last_position.frame) && x_move_allowed) {
 
                /* x movement since last time (in pixels) */
-               dx = (static_cast<double> (pending_region_position->frame) - _last_position.frame) / _editor->samples_per_pixel;
+               dx = _editor->sample_to_pixel_unrounded (pending_region_position->frame - _last_position.frame);
 
                /* total x movement */
-               framecnt_t total_dx = pending_region_position->frame;
-               if (regions_came_from_canvas()) {
-                       total_dx = total_dx - grab_frame ();
-               }
+               framecnt_t total_dx = _editor->pixel_to_sample (_total_x_delta + dx);
 
-               /* check that no regions have gone off the start of the session */
                for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-                       if ((i->view->region()->position() + total_dx) < 0) {
-                               dx = 0;
-                               *pending_region_position = _last_position;
+                       frameoffset_t const off = i->view->region()->position() + total_dx;
+                       if (off < 0) {
+                               dx = dx - _editor->sample_to_pixel_unrounded (off);
+                               *pending_region_position = MusicFrame (pending_region_position->frame - off, 0);
                                break;
                        }
                }
-
        }
 
        return dx;
@@ -932,8 +945,13 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
        }
 
        /* Work out the change in x */
+       TempoMap& tmap = _editor->session()->tempo_map();
        MusicFrame pending_region_position (0, 0);
        double const x_delta = compute_x_delta (event, &pending_region_position);
+
+       double const last_pos_qn = tmap.exact_qn_at_frame (_last_position.frame, _last_position.division);
+       double const qn_delta = tmap.exact_qn_at_frame (pending_region_position.frame, pending_region_position.division) - last_pos_qn;
+
        _last_position = pending_region_position;
 
        /* calculate hidden tracks in current y-axis delta */
@@ -1177,7 +1195,15 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                }
 
                /* Now move the region view */
-               rv->move (x_delta, y_delta);
+               if (rv->region()->position_lock_style() == MusicTime) {
+                       double const last_qn = tmap.quarter_note_at_frame (rv->get_position());
+                       framepos_t const x_pos_music = tmap.frame_at_quarter_note (last_qn + qn_delta);
+
+                       rv->set_position (x_pos_music, 0);
+                       rv->move (0, y_delta);
+               } else {
+                       rv->move (x_delta, y_delta);
+               }
 
        } /* foreach region */
 
@@ -1982,7 +2008,9 @@ RegionInsertDrag::finished (GdkEvent * event, bool)
 
        _editor->begin_reversible_command (Operations::insert_region);
        playlist->clear_changes ();
-       playlist->add_region (_primary->region (), _last_position.frame, _editor->get_grid_music_divisions (event->button.state));
+       _editor->snap_to_with_modifier (_last_position, event);
+
+       playlist->add_region (_primary->region (), _last_position.frame, 1.0, false, _last_position.division);
 
        // Mixbus doesn't seem to ripple when inserting regions from the list: should we? yes, probably
        if (Config->get_edit_mode() == Ripple) {
@@ -2852,7 +2880,7 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
        framecnt_t const region_length = (framecnt_t) (_primary->region()->length() / speed);
 
        framepos_t const pf = adjusted_current_frame (event);
-       setup_snap_delta (region_start);
+       setup_snap_delta (MusicFrame(region_start, 0));
 
        if (Keyboard::modifier_state_equals (event->button.state, ArdourKeyboard::trim_contents_modifier ())) {
                /* Move the contents of the region around without changing the region bounds */
@@ -3631,7 +3659,7 @@ void
 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
 {
        Drag::start_grab (event, c);
-       setup_snap_delta (_editor->playhead_cursor->current_frame());
+       setup_snap_delta (MusicFrame (_editor->playhead_cursor->current_frame(), 0));
 
        _grab_zoom = _editor->samples_per_pixel;
 
@@ -3734,7 +3762,7 @@ FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 
        AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
        boost::shared_ptr<AudioRegion> const r = arv->audio_region ();
-       setup_snap_delta (r->position());
+       setup_snap_delta (MusicFrame (r->position(), 0));
 
        show_verbose_cursor_duration (r->position(), r->position() + r->fade_in()->back()->when, 32);
 }
@@ -3860,7 +3888,7 @@ FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 
        AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
        boost::shared_ptr<AudioRegion> r = arv->audio_region ();
-       setup_snap_delta (r->last_frame());
+       setup_snap_delta (MusicFrame (r->last_frame(), 0));
 
        show_verbose_cursor_duration (r->last_frame() - r->fade_out()->back()->when, r->last_frame());
 }
@@ -4021,7 +4049,7 @@ MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        } else {
                show_verbose_cursor_time (location->end());
        }
-       setup_snap_delta (is_start ? location->start() : location->end());
+       setup_snap_delta (MusicFrame (is_start ? location->start() : location->end(), 0));
 
        Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
 
@@ -4408,7 +4436,7 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
        _fixed_grab_x = _point->get_x() + _editor->sample_to_pixel_unrounded (_point->line().offset());
        _fixed_grab_y = _point->get_y();
 
-       setup_snap_delta (_editor->pixel_to_sample (_fixed_grab_x));
+       setup_snap_delta (MusicFrame (_editor->pixel_to_sample (_fixed_grab_x), 0));
 
        float const fraction = 1 - (_point->get_y() / _point->line().height());
        show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction));
@@ -4906,10 +4934,10 @@ TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 
        _editor->get_selection().add (_primary);
 
-       framepos_t where = _primary->region()->position();
+       MusicFrame where (_primary->region()->position(), 0);
        setup_snap_delta (where);
 
-       show_verbose_cursor_duration (where, adjusted_current_frame (event), 0);
+       show_verbose_cursor_duration (where.frame, adjusted_current_frame (event), 0);
 }
 
 void
@@ -5617,6 +5645,7 @@ NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
        : Drag (e, i)
        , _cumulative_dx (0)
        , _cumulative_dy (0)
+       , _earliest (0.0)
        , _was_selected (false)
        , _copy (false)
 {
@@ -5628,18 +5657,25 @@ NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
        _note_height = _region->midi_stream_view()->note_height ();
 }
 
+void
+NoteDrag::setup_pointer_frame_offset ()
+{
+       _pointer_frame_offset = raw_grab_frame()
+               - _editor->session()->tempo_map().frame_at_quarter_note (_region->session_relative_qn (_primary->note()->time().to_double()));
+}
+
 void
 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
 {
        Drag::start_grab (event);
 
-       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::CopyModifier)) {
+       if (ArdourKeyboard::indicates_copy (event->button.state)) {
                _copy = true;
        } else {
                _copy = false;
        }
 
-       setup_snap_delta (_region->source_beats_to_absolute_frames (_primary->note()->time ()));
+       setup_snap_delta (MusicFrame (_region->source_beats_to_absolute_frames (_primary->note()->time ()), 0));
 
        if (!(_was_selected = _primary->selected())) {
 
@@ -5663,55 +5699,38 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
        }
 }
 
-/** @return Current total drag x change in frames */
-frameoffset_t
-NoteDrag::total_dx (const guint state) const
+/** @return Current total drag x change in quarter notes */
+double
+NoteDrag::total_dx (GdkEvent * event) const
 {
        if (_x_constrained) {
                return 0;
        }
+
        TempoMap& map (_editor->session()->tempo_map());
 
        /* dx in frames */
        frameoffset_t const dx = _editor->pixel_to_sample (_drags->current_pointer_x() - grab_x());
 
        /* primary note time */
-       double const quarter_note_start = _region->region()->quarter_note() - _region->midi_region()->start_beats();
-       frameoffset_t const n = map.frame_at_quarter_note (quarter_note_start + _primary->note()->time().to_double());
+       frameoffset_t const n = map.frame_at_quarter_note (_region->session_relative_qn (_primary->note()->time().to_double()));
 
-       /* new time of the primary note in session frames */
-       frameoffset_t st = n + dx + snap_delta (state);
-
-       framepos_t const rp = _region->region()->position ();
-
-       /* prevent the note being dragged earlier than the region's position */
-       st = max (st, rp);
+       /* primary note time in quarter notes */
+       double const n_qn = _region->session_relative_qn (_primary->note()->time().to_double());
 
-       /* possibly snap and return corresponding delta */
+       /* new time of the primary note in session frames */
+       frameoffset_t st = n + dx + snap_delta (event->button.state);
 
-       bool snap = true;
+       /* possibly snap and return corresponding delta in quarter notes */
+       MusicFrame snap (st, 0);
+       _editor->snap_to_with_modifier (snap, event);
+       double ret = map.exact_qn_at_frame (snap.frame, snap.division) - n_qn - snap_delta_music (event->button.state);
 
-       if (ArdourKeyboard::indicates_snap (state)) {
-               if (_editor->snap_mode () != SnapOff) {
-                       snap = false;
-               }
-       } else {
-               if (_editor->snap_mode () == SnapOff) {
-                       snap = false;
-                       /* inverted logic here - we;re in snapoff but we've pressed the snap delta modifier */
-                       if (ArdourKeyboard::indicates_snap_delta (state)) {
-                               snap = true;
-                       }
-               }
+       /* prevent the earliest note being dragged earlier than the region's start position */
+       if (_earliest + ret < _region->midi_region()->start_beats()) {
+               ret -= (_earliest + ret) - _region->midi_region()->start_beats();
        }
 
-       frameoffset_t ret;
-       if (snap) {
-               bool const ensure_snap = _editor->snap_mode () != SnapMagnetic;
-               ret =  _region->snap_frame_to_frame (st - rp, ensure_snap) + rp - n - snap_delta (state);
-       } else {
-               ret = st - n - snap_delta (state);
-       }
        return ret;
 }
 
@@ -5737,30 +5756,33 @@ NoteDrag::total_dy () const
 void
 NoteDrag::motion (GdkEvent * event, bool first_move)
 {
-       if (_copy && first_move) {
-               /* make copies of all the selected notes */
-               _primary = _region->copy_selection ();
+       if (first_move) {
+               _earliest = _region->earliest_in_selection().to_double();
+               if (_copy) {
+                       /* make copies of all the selected notes */
+                       _primary = _region->copy_selection (_primary);
+               }
        }
 
        /* Total change in x and y since the start of the drag */
-       frameoffset_t const dx = total_dx (event->button.state);
+       double const dx_qn = total_dx (event);
        int8_t const dy = total_dy ();
 
        /* Now work out what we have to do to the note canvas items to set this new drag delta */
-       double const tdx = _x_constrained ? 0 : _editor->sample_to_pixel (dx) - _cumulative_dx;
+       double const tdx = _x_constrained ? 0 : dx_qn - _cumulative_dx;
        double const tdy = _y_constrained ? 0 : -dy * _note_height - _cumulative_dy;
 
        if (tdx || tdy) {
-               _cumulative_dx += tdx;
+               _cumulative_dx = dx_qn;
                _cumulative_dy += tdy;
 
                int8_t note_delta = total_dy();
 
                if (tdx || tdy) {
                        if (_copy) {
-                               _region->move_copies (tdx, tdy, note_delta);
+                               _region->move_copies (dx_qn, tdy, note_delta);
                        } else {
-                               _region->move_selection (tdx, tdy, note_delta);
+                               _region->move_selection (dx_qn, tdy, note_delta);
                        }
 
                        /* the new note value may be the same as the old one, but we
@@ -5821,7 +5843,7 @@ NoteDrag::finished (GdkEvent* ev, bool moved)
                        }
                }
        } else {
-               _region->note_dropped (_primary, total_dx (ev->button.state), total_dy(), _copy);
+               _region->note_dropped (_primary, total_dx (ev), total_dy(), _copy);
        }
 }