keep velocity value visible in verbose cursor until we leave a note (fixes #5085)
[ardour.git] / gtk2_ardour / editor_drag.cc
index e8bce456e865049806de6eafa304142b92fd8e53..0c309d723458ddb727de2def826b36fc0421d27d 100644 (file)
@@ -1597,10 +1597,11 @@ NoteResizeDrag::aborted (bool)
        }
 }
 
-TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
+TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool preserve_fade_anchor)
        : RegionDrag (e, i, p, v)
 {
        DEBUG_TRACE (DEBUG::Drags, "New TrimDrag\n");
+       _preserve_fade_anchor = preserve_fade_anchor;
 }
 
 void
@@ -1722,13 +1723,41 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
        switch (_operation) {
        case StartTrim:
                for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-                       i->view->trim_front (i->initial_position + dt, non_overlap_trim);
+                       bool changed = i->view->trim_front (i->initial_position + dt, non_overlap_trim);
+                       if (changed && _preserve_fade_anchor) {
+                               AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
+                               if (arv) {
+                                       double distance;
+                                       double new_length;
+                                       framecnt_t len;
+                                       boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+                                       distance = _drags->current_pointer_x() - grab_x();
+                                       len = ar->fade_in()->back()->when;
+                                       new_length = len - _editor->unit_to_frame (distance);
+                                       new_length = ar->verify_xfade_bounds (new_length, true  /*START*/ );
+                                       arv->reset_fade_in_shape_width (ar, new_length);  //the grey shape
+                               }
+                       }
                }
                break;
 
        case EndTrim:
                for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-                       i->view->trim_end (i->initial_end + dt, non_overlap_trim);
+                       bool changed = i->view->trim_end (i->initial_end + dt, non_overlap_trim);
+                       if (changed && _preserve_fade_anchor) {
+                               AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
+                               if (arv) {
+                                       double distance;
+                                       double new_length;
+                                       framecnt_t len;
+                                       boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+                                       distance = grab_x() - _drags->current_pointer_x();
+                                       len = ar->fade_out()->back()->when;
+                                       new_length = len - _editor->unit_to_frame (distance);
+                                       new_length = ar->verify_xfade_bounds (new_length, false  /*END*/ );
+                                       arv->reset_fade_out_shape_width (ar, new_length);  //the grey shape
+                               }
+                       }
                }
                break;
 
@@ -1780,16 +1809,49 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
        if (movement_occurred) {
                motion (event, false);
 
-               /* This must happen before the region's StatefulDiffCommand is created, as it may
-                  `correct' (ahem) the region's _start from being negative to being zero.  It
-                  needs to be zero in the undo record.
-               */
                if (_operation == StartTrim) {
                        for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-                               i->view->trim_front_ending ();
+                               {
+                                       /* This must happen before the region's StatefulDiffCommand is created, as it may
+                                          `correct' (ahem) the region's _start from being negative to being zero.  It
+                                          needs to be zero in the undo record.
+                                       */
+                                       i->view->trim_front_ending ();
+                               }
+                               if (_preserve_fade_anchor) {
+                                       AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
+                                       if (arv) {
+                                               double distance;
+                                               double new_length;
+                                               framecnt_t len;
+                                               boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+                                               distance = _drags->current_pointer_x() - grab_x();
+                                               len = ar->fade_in()->back()->when;
+                                               new_length = len - _editor->unit_to_frame (distance);
+                                               new_length = ar->verify_xfade_bounds (new_length, true  /*START*/ );
+                                               ar->set_fade_in_length(new_length);
+                                       }
+                               }
+                       }
+               } else if (_operation == EndTrim) {
+                       for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+                               if (_preserve_fade_anchor) {
+                                       AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
+                                       if (arv) {
+                                               double distance;
+                                               double new_length;
+                                               framecnt_t len;
+                                               boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+                                               distance = _drags->current_pointer_x() - grab_x();
+                                               len = ar->fade_out()->back()->when;
+                                               new_length = len - _editor->unit_to_frame (distance);
+                                               new_length = ar->verify_xfade_bounds (new_length, false  /*END*/ );
+                                               ar->set_fade_out_length(new_length);
+                                       }
+                               }
                        }
                }
-
+               
                if (_operation == StartTrim) {
                        _editor->maybe_locate_with_edit_preroll ( _views.begin()->view->region()->position() );
                }
@@ -1822,6 +1884,7 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
                                }
                        }
                }
+
                for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
                        (*p)->thaw ();
                }
@@ -1829,10 +1892,6 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
                _editor->motion_frozen_playlists.clear ();
                _editor->commit_reversible_command();
 
-               for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-                       i->view->drag_end ();
-               }
-
        } else {
                /* no mouse movement */
                _editor->point_trim (event, adjusted_current_frame (event));
@@ -2253,8 +2312,6 @@ FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        boost::shared_ptr<AudioRegion> const r = arv->audio_region ();
 
        show_verbose_cursor_duration (r->position(), r->position() + r->fade_in()->back()->when, 32);
-
-       arv->show_fade_line((framepos_t) r->fade_in()->back()->when);
 }
 
 void
@@ -2290,8 +2347,7 @@ FadeInDrag::motion (GdkEvent* event, bool)
                        continue;
                }
 
-               tmp->reset_fade_in_shape_width (fade_length);
-               tmp->show_fade_line((framecnt_t) fade_length);
+               tmp->reset_fade_in_shape_width (tmp->audio_region(), fade_length);
        }
 
        show_verbose_cursor_duration (region->position(), region->position() + fade_length, 32);
@@ -2333,7 +2389,6 @@ FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
 
                tmp->audio_region()->set_fade_in_length (fade_length);
                tmp->audio_region()->set_fade_in_active (true);
-               tmp->hide_fade_line();
 
                XMLNode &after = alist->get_state();
                _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
@@ -2352,8 +2407,7 @@ FadeInDrag::aborted (bool)
                        continue;
                }
 
-               tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
-               tmp->hide_fade_line();
+               tmp->reset_fade_in_shape_width (tmp->audio_region(), tmp->audio_region()->fade_in()->back()->when);
        }
 }
 
@@ -2372,8 +2426,6 @@ FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        boost::shared_ptr<AudioRegion> r = arv->audio_region ();
 
        show_verbose_cursor_duration (r->last_frame() - r->fade_out()->back()->when, r->last_frame());
-
-       arv->show_fade_line(r->length() - r->fade_out()->back()->when);
 }
 
 void
@@ -2411,8 +2463,7 @@ FadeOutDrag::motion (GdkEvent* event, bool)
                        continue;
                }
 
-               tmp->reset_fade_out_shape_width (fade_length);
-               tmp->show_fade_line(region->length() - fade_length);
+               tmp->reset_fade_out_shape_width (tmp->audio_region(), fade_length);
        }
 
        show_verbose_cursor_duration (region->last_frame() - fade_length, region->last_frame());
@@ -2456,7 +2507,6 @@ FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
 
                tmp->audio_region()->set_fade_out_length (fade_length);
                tmp->audio_region()->set_fade_out_active (true);
-               tmp->hide_fade_line();
 
                XMLNode &after = alist->get_state();
                _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
@@ -2475,8 +2525,7 @@ FadeOutDrag::aborted (bool)
                        continue;
                }
 
-               tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
-               tmp->hide_fade_line();
+               tmp->reset_fade_out_shape_width (tmp->audio_region(), tmp->audio_region()->fade_out()->back()->when);
        }
 }
 
@@ -2836,6 +2885,8 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
 
        _editor->verbose_cursor()->show ();
 
+       _pushing = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
+
        if (!_point->can_slide ()) {
                _x_constrained = true;
        }
@@ -2889,9 +2940,8 @@ ControlPointDrag::motion (GdkEvent* event, bool)
        cx_frames = min (cx_frames, _point->line().maximum_time());
 
        float const fraction = 1.0 - (cy / _point->line().height());
-       bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
 
-       _point->line().drag_motion (_editor->frame_to_unit_unrounded (cx_frames), fraction, false, push);
+       _point->line().drag_motion (_editor->frame_to_unit_unrounded (cx_frames), fraction, false, _pushing, _final_index);
 
        _editor->verbose_cursor()->set_text (_point->line().get_verbose_cursor_string (fraction));
 }
@@ -2911,7 +2961,7 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
                motion (event, false);
        }
 
-       _point->line().end_drag ();
+       _point->line().end_drag (_pushing, _final_index);
        _editor->session()->commit_reversible_command ();
 }
 
@@ -3002,10 +3052,10 @@ LineDrag::motion (GdkEvent* event, bool)
        cy = min ((double) _line->height(), cy);
 
        double const fraction = 1.0 - (cy / _line->height());
-       bool const push = !Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
+       uint32_t ignored;
 
        /* we are ignoring x position for this drag, so we can just pass in anything */
-       _line->drag_motion (0, fraction, true, push);
+       _line->drag_motion (0, fraction, true, false, ignored);
 
        _editor->verbose_cursor()->set_text (_line->get_verbose_cursor_string (fraction));
 }
@@ -3014,7 +3064,7 @@ void
 LineDrag::finished (GdkEvent* event, bool)
 {
        motion (event, false);
-       _line->end_drag ();
+       _line->end_drag (false, 0);
        _editor->session()->commit_reversible_command ();
 }
 
@@ -3232,7 +3282,13 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
                        }
                } 
 
-               if (do_deselect) {
+               /* do not deselect if Primary or Tertiary (toggle-select or
+                * extend-select are pressed.
+                */
+
+               if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier) && 
+                   !Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier) && 
+                   do_deselect) {
                        deselect_things ();
                }
 
@@ -3360,12 +3416,18 @@ ScrubDrag::aborted (bool)
 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
        : Drag (e, i)
        , _operation (o)
-       , _copy (false)
+       , _add (false)
+       , _extend (false)
        , _original_pointer_time_axis (-1)
        , _last_pointer_time_axis (-1)
        , _time_selection_at_start (!_editor->get_selection().time.empty())
 {
        DEBUG_TRACE (DEBUG::Drags, "New SelectionDrag\n");
+       
+       if (_time_selection_at_start) {
+               start_at_start = _editor->get_selection().time.start();
+               end_at_start = _editor->get_selection().time.end_frame();
+       }
 }
 
 void
@@ -3379,10 +3441,10 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
 
        switch (_operation) {
        case CreateSelection:
-               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
-                       _copy = true;
+               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::CopyModifier)) {
+                       _add = true;
                } else {
-                       _copy = false;
+                       _add = false;
                }
                cursor = _editor->cursors()->selector;
                Drag::start_grab (event, cursor);
@@ -3405,6 +3467,10 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
        case SelectionMove:
                Drag::start_grab (event, cursor);
                break;
+
+       case SelectionExtend:
+               Drag::start_grab (event, cursor);
+               break;
        }
 
        if (_operation == SelectionMove) {
@@ -3432,6 +3498,9 @@ SelectionDrag::setup_pointer_frame_offset ()
        case SelectionEndTrim:
                _pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].end;
                break;
+
+       case SelectionExtend:
+               break;
        }
 }
 
@@ -3440,7 +3509,8 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
 {
        framepos_t start = 0;
        framepos_t end = 0;
-       framecnt_t length;
+       framecnt_t length = 0;
+       framecnt_t distance = 0;
 
        pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
        if (pending_time_axis.first == 0) {
@@ -3483,12 +3553,12 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
 
                if (first_move) {
 
-                       if (_copy) {
+                       if (_add) {
                                /* adding to the selection */
                                _editor->set_selected_track_as_side_effect (Selection::Add);
                                //_editor->selection->add (_editor->clicked_axisview);
                                _editor->clicked_selection = _editor->selection->add (start, end);
-                               _copy = false;
+                               _add = false;
                        } else {
                                /* new selection */
 
@@ -3556,20 +3626,23 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
                }
 
                break;
-
+               
        case SelectionMove:
 
                start = _editor->selection->time[_editor->clicked_selection].start;
                end = _editor->selection->time[_editor->clicked_selection].end;
 
                length = end - start;
-
+               distance = pending_position - start;
                start = pending_position;
                _editor->snap_to (start);
 
                end = start + length;
 
                break;
+
+       case SelectionExtend:
+               break;
        }
 
        if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
@@ -3577,7 +3650,15 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
        }
 
        if (start != end) {
-               _editor->selection->replace (_editor->clicked_selection, start, end);
+               switch (_operation) {
+               case SelectionMove:     
+                       if (_time_selection_at_start) {
+                               _editor->selection->move_time (distance);
+                       }
+                       break;
+               default:
+                       _editor->selection->replace (_editor->clicked_selection, start, end);
+               }
        }
 
        if (_operation == SelectionMove) {
@@ -3613,12 +3694,30 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
        } else {
                /* just a click, no pointer movement.
                 */
-               _editor->selection->clear_time();
+
+               if (_operation == SelectionExtend) {
+                       if (_time_selection_at_start) {
+                               framepos_t pos = adjusted_current_frame (event, false);
+                               framepos_t start = min (pos, start_at_start);
+                               framepos_t end = max (pos, end_at_start);
+                               _editor->selection->set (start, end);
+                       }
+               } else {
+                       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::CopyModifier)) {
+                               if (_editor->clicked_selection) {
+                                       _editor->selection->remove (_editor->clicked_selection);
+                               }
+                       } else {
+                               if (!_editor->clicked_selection) {
+                                       _editor->selection->clear_time();
+                               }
+                       }
+               }
 
                if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
                        _editor->selection->set (_editor->clicked_axisview);
                }
-
+                       
                if (s && s->get_play_range () && s->transport_rolling()) {
                        s->request_stop (false, false);
                }
@@ -3626,6 +3725,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
        }
 
        _editor->stop_canvas_autoscroll ();
+       _editor->clicked_selection = 0;
 }
 
 void
@@ -4277,7 +4377,8 @@ AutomationRangeDrag::motion (GdkEvent*, bool /*first_move*/)
        for (list<Line>::iterator l = _lines.begin(); l != _lines.end(); ++l) {
                float const f = y_fraction (l->line, _drags->current_pointer_y());
                /* we are ignoring x position for this drag, so we can just pass in anything */
-               l->line->drag_motion (0, f, true, false);
+               uint32_t ignored;
+               l->line->drag_motion (0, f, true, false, ignored);
                show_verbose_cursor_text (l->line->get_verbose_cursor_relative_string (l->original_fraction, f));
        }
 }
@@ -4291,7 +4392,7 @@ AutomationRangeDrag::finished (GdkEvent* event, bool)
 
        motion (event, false);
        for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
-               i->line->end_drag ();
+               i->line->end_drag (false, 0);
        }
 
        _editor->session()->commit_reversible_command ();
@@ -4576,6 +4677,7 @@ CrossfadeEdgeDrag::CrossfadeEdgeDrag (Editor* e, AudioRegionView* rv, ArdourCanv
        , arv (rv)
        , start (start_yn)
 {
+       std::cout << ("CrossfadeEdgeDrag is DEPRECATED.  See TrimDrag::preserve_fade_anchor") << endl;
 }
 
 void