Fix region content drag direction
[ardour.git] / gtk2_ardour / editor_drag.cc
index a68493f93b2678696374c76967e7469508d343ce..a3c07b86726fac58e0dcc15f38c480228fbc3fcb 100644 (file)
@@ -127,7 +127,7 @@ DragManager::start_grab (GdkEvent* e, Gdk::Cursor* c)
        _old_follow_playhead = _editor->follow_playhead ();
        _editor->set_follow_playhead (false);
 
-       _current_pointer_frame = _editor->canvas_event_frame (e, &_current_pointer_x, &_current_pointer_y);
+       _current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y);
 
        for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
                (*i)->start_grab (e, c);
@@ -173,7 +173,7 @@ DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
 {
        bool r = false;
 
-       _current_pointer_frame = _editor->canvas_event_frame (e, &_current_pointer_x, &_current_pointer_y);
+       _current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y);
 
        for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
                bool const t = (*i)->motion_handler (e, from_autoscroll);
@@ -191,7 +191,7 @@ DragManager::window_motion_handler (GdkEvent* e, bool from_autoscroll)
 {
        bool r = false;
 
-       _current_pointer_frame = _editor->window_event_frame (e, &_current_pointer_x, &_current_pointer_y);
+       _current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y);
 
        for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
                bool const t = (*i)->motion_handler (e, from_autoscroll);
@@ -259,7 +259,7 @@ Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
                _y_constrained = false;
        }
 
-       _raw_grab_frame = _editor->canvas_event_frame (event, &_grab_x, &_grab_y);
+       _raw_grab_frame = _editor->canvas_event_sample (event, &_grab_x, &_grab_y);
        setup_pointer_frame_offset ();
        _grab_frame = adjusted_frame (_raw_grab_frame, event);
        _last_pointer_frame = _grab_frame;
@@ -361,16 +361,16 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
 
                if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
                        if (!from_autoscroll) {
-                               bool const moving_left = _drags->current_pointer_x() < _last_pointer_x;
-                               bool const moving_up = _drags->current_pointer_y() < _last_pointer_y;
-                               _editor->maybe_autoscroll (true, allow_vertical_autoscroll (), moving_left, moving_up);
+                               _editor->maybe_autoscroll (true, allow_vertical_autoscroll (), false);
                        }
 
-                       motion (event, _move_threshold_passed != old_move_threshold_passed);
-
-                       _last_pointer_x = _drags->current_pointer_x ();
-                       _last_pointer_y = _drags->current_pointer_y ();
-                       _last_pointer_frame = adjusted_current_frame (event);
+                       if (!_editor->autoscroll_active() || from_autoscroll) {
+                               motion (event, _move_threshold_passed != old_move_threshold_passed);
+                               
+                               _last_pointer_x = _drags->current_pointer_x ();
+                               _last_pointer_y = _drags->current_pointer_y ();
+                               _last_pointer_frame = adjusted_current_frame (event);
+                       }
 
                        return true;
                }
@@ -450,7 +450,7 @@ struct EditorOrderTimeAxisViewSorter {
            RouteTimeAxisView* ra = dynamic_cast<RouteTimeAxisView*> (a);
            RouteTimeAxisView* rb = dynamic_cast<RouteTimeAxisView*> (b);
            assert (ra && rb);
-           return ra->route()->order_key (EditorSort) < rb->route()->order_key (EditorSort);
+           return ra->route()->order_key () < rb->route()->order_key ();
     }
 };
 
@@ -872,7 +872,15 @@ RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred)
        RegionMotionDrag::finished (ev, movement_occurred);
        
        if (!movement_occurred) {
+               
                /* just a click */
+
+               if (was_double_click() && !_views.empty()) {
+                       DraggingView dv = _views.front();
+                       dv.view->show_region_editor ();
+                       
+               }
+
                return;
        }
 
@@ -1069,6 +1077,17 @@ RegionMoveDrag::finished_no_copy (
 
                } else {
 
+                       boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
+
+                       /* this movement may result in a crossfade being modified, or a layering change,
+                          so we need to get undo data from the playlist as well as the region.
+                       */
+
+                       pair<PlaylistSet::iterator, bool> r = modified_playlists.insert (playlist);
+                       if (r.second) {
+                               playlist->clear_changes ();
+                       }
+
                        rv->region()->clear_changes ();
 
                        /*
@@ -1082,30 +1101,18 @@ RegionMoveDrag::finished_no_copy (
                        rv->drag_end ();
 
                        /* just change the model */
-
-                       boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
-
                        if (dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded) {
                                playlist->set_layer (rv->region(), dest_layer);
                        }
 
                        /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
 
-                       pair<PlaylistSet::iterator, bool> r = frozen_playlists.insert (playlist);
+                       r = frozen_playlists.insert (playlist);
 
                        if (r.second) {
                                playlist->freeze ();
                        }
 
-                       /* this movement may result in a crossfade being modified, so we need to get undo
-                          data from the playlist as well as the region.
-                       */
-
-                       r = modified_playlists.insert (playlist);
-                       if (r.second) {
-                               playlist->clear_changes ();
-                       }
-
                        rv->region()->set_position (where);
 
                        _editor->session()->add_command (new StatefulDiffCommand (rv->region()));
@@ -1498,7 +1505,7 @@ RegionCreateDrag::motion (GdkEvent* event, bool first_move)
                           place snapped notes at the start of the region.
                        */
 
-                       framecnt_t const len = (framecnt_t) fabs (f - grab_frame () - 1);
+                       framecnt_t const len = (framecnt_t) fabs ((double)(f - grab_frame () - 1));
                        _region->set_length (len < 1 ? 1 : len);
                }
        }
@@ -1687,7 +1694,7 @@ VideoTimeLineDrag::motion (GdkEvent* event, bool first_move)
        }
 
        framecnt_t dt = adjusted_current_frame (event) - raw_grab_frame() + _pointer_frame_offset;
-       dt = ARDOUR_UI::instance()->video_timeline->quantify_frames_to_apv(dt);
+       dt = ARDOUR_UI::instance()->video_timeline->quantify_frames_to_apv(_startdrag_video_offset+dt) - _startdrag_video_offset;
 
        if (_max_backwards_drag >= 0 && dt <= - _max_backwards_drag) {
                dt = - _max_backwards_drag;
@@ -1781,9 +1788,10 @@ VideoTimeLineDrag::aborted (bool)
 
 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool preserve_fade_anchor)
        : RegionDrag (e, i, p, v)
+       , _preserve_fade_anchor (preserve_fade_anchor)
+       , _jump_position_when_done (false)
 {
        DEBUG_TRACE (DEBUG::Drags, "New TrimDrag\n");
-       _preserve_fade_anchor = preserve_fade_anchor;
 }
 
 void
@@ -1820,6 +1828,10 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
                }
        }
 
+       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
+               _jump_position_when_done = true;
+       }
+
        switch (_operation) {
        case StartTrim:
                show_verbose_cursor_time (region_start);
@@ -1946,8 +1958,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
 
        case ContentsTrim:
                {
-                       frame_delta = (adjusted_current_frame(event) - last_pointer_frame());
-                       // frame_delta = (last_pointer_frame() - adjusted_current_frame(event));
+                       frame_delta = (last_pointer_frame() - adjusted_current_frame(event));
 
                        for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
                                i->view->move_contents (frame_delta);
@@ -1999,6 +2010,9 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
                                                ar->set_fade_in_length(new_length);
                                        }
                                }
+                               if (_jump_position_when_done) {
+                                       i->view->region()->set_position (i->initial_position);
+                               }
                        }
                } else if (_operation == EndTrim) {
                        for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
@@ -2016,6 +2030,9 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
                                                ar->set_fade_out_length(new_length);
                                        }
                                }
+                               if (_jump_position_when_done) {
+                                       i->view->region()->set_position (i->initial_end - i->view->region()->length());
+                               }
                        }
                }
 
@@ -2146,6 +2163,10 @@ MeterMarkerDrag::setup_pointer_frame_offset ()
 void
 MeterMarkerDrag::motion (GdkEvent* event, bool first_move)
 {
+       if (!_marker->meter().movable()) {
+               return;
+       }
+
        if (first_move) {
 
                // create a dummy marker for visual representation of moving the
@@ -2191,6 +2212,13 @@ void
 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
 {
        if (!movement_occurred) {
+               if (was_double_click()) {
+                       _editor->edit_meter_marker (*_marker);
+               }
+               return;
+       }
+
+       if (!_marker->meter().movable()) {
                return;
        }
 
@@ -2266,6 +2294,10 @@ TempoMarkerDrag::setup_pointer_frame_offset ()
 void
 TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
 {
+       if (!_marker->tempo().movable()) {
+               return;
+       }
+
        if (first_move) {
 
                // create a dummy marker for visual representation of moving the
@@ -2310,6 +2342,13 @@ void
 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
 {
        if (!movement_occurred) {
+               if (was_double_click()) {
+                       _editor->edit_tempo_marker (*_marker);
+               }
+               return;
+       }
+
+       if (!_marker->tempo().movable()) {
                return;
        }
 
@@ -2377,8 +2416,14 @@ CursorDrag::fake_locate (framepos_t t)
        Session* s = _editor->session ();
        if (s->timecode_transmission_suspended ()) {
                framepos_t const f = _editor->playhead_cursor->current_frame ();
+               /* This is asynchronous so it will be sent "now"
+                */
                s->send_mmc_locate (f);
-               s->send_full_time_code (f);
+               /* These are synchronous and will be sent during the next
+                  process cycle
+               */
+               s->queue_full_time_code ();
+               s->queue_song_position_pointer ();
        }
 
        show_verbose_cursor_time (t);
@@ -2392,7 +2437,7 @@ CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
 
        _grab_zoom = _editor->samples_per_pixel;
 
-       framepos_t where = _editor->canvas_event_frame (event, 0, 0);
+       framepos_t where = _editor->canvas_event_sample (event);
 
        _editor->snap_to_with_modifier (where, event);
 
@@ -2995,7 +3040,8 @@ MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
        if (!movement_occurred) {
                
                if (was_double_click()) {
-                       cerr << "End of marker double click\n";
+                       _editor->rename_marker (_marker);
+                       return;
                }
 
                /* just a click, do nothing but finish
@@ -3281,10 +3327,24 @@ LineDrag::motion (GdkEvent* event, bool)
 }
 
 void
-LineDrag::finished (GdkEvent* event, bool)
+LineDrag::finished (GdkEvent* event, bool movement_occured)
 {
-       motion (event, false);
-       _line->end_drag (false, 0);
+       if (movement_occured) {
+               motion (event, false);
+               _line->end_drag (false, 0);
+       } else {
+               /* add a new control point on the line */
+
+               AutomationTimeAxisView* atv;
+
+               _line->end_drag (false, 0);
+
+               if ((atv = dynamic_cast<AutomationTimeAxisView*>(_editor->clicked_axisview)) != 0) {
+                       framepos_t where = _editor->window_event_sample (event, 0, 0);
+                       atv->add_automation_event (event, where, event->button.y, false);
+               }
+       }
+
        _editor->session()->commit_reversible_command ();
 }
 
@@ -3422,16 +3482,28 @@ RubberbandSelectDrag::motion (GdkEvent* event, bool)
 
                double x1 = _editor->sample_to_pixel (start);
                double x2 = _editor->sample_to_pixel (end);
+               const double min_dimension = 2.0;
 
                _editor->rubberband_rect->set_x0 (x1);
                if (_vertical_only) {
                        /* fixed 10 pixel width */
                        _editor->rubberband_rect->set_x1 (x1 + 10);
                } else {
+                       if (x2 < x1) {
+                               x2 = min (x1 - min_dimension, x2);
+                       } else {
+                               x2 = max (x1 + min_dimension, x2);
+                       }
                        _editor->rubberband_rect->set_x1 (x2);
                } 
 
                _editor->rubberband_rect->set_y0 (y1);
+               if (y2 < y1) {
+                       y2 = min (y1 - min_dimension, y2);
+               } else {
+                       y2 = max (y1 + min_dimension, y2);
+               }
+
                _editor->rubberband_rect->set_y1 (y2);
                
                _editor->rubberband_rect->show();
@@ -3725,16 +3797,9 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
        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) {
-               return;
-       }
-
        framepos_t const pending_position = adjusted_current_frame (event);
 
-       /* only alter selection if things have changed */
-
-       if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
+       if (_operation != CreateSelection && pending_position == last_pointer_frame()) {
                return;
        }
 
@@ -3767,51 +3832,49 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
                if (first_move) {
 
                        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);
                                _add = false;
+                               
                        } else {
+
                                /* new selection */
 
                                if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
-                                       //_editor->selection->set (_editor->clicked_axisview);
                                        _editor->set_selected_track_as_side_effect (Selection::Set);
                                }
 
                                _editor->clicked_selection = _editor->selection->set (start, end);
                        }
                }
+               
+               /* 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& all_tracks (_editor->track_views);
 
-               /* select the track that we're in */
-               if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
-                       // _editor->set_selected_track_as_side_effect (Selection::Add);
-                       _editor->selection->add (pending_time_axis.first);
-                       _added_time_axes.push_back (pending_time_axis.first);
-               }
-
-               /* deselect any tracks that this drag no longer includes, being careful to only deselect
-                  tracks that we selected in the first place.
-               */
-
-               int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
-               int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
-
-               list<TimeAxisView*>::iterator i = _added_time_axes.begin();
-               while (i != _added_time_axes.end()) {
-
-                       list<TimeAxisView*>::iterator tmp = i;
-                       ++tmp;
-
-                       if ((*i)->order() < min_order || (*i)->order() > max_order) {
-                               _editor->selection->remove (*i);
-                               _added_time_axes.remove (*i);
+               for (TrackViewList::const_iterator i = all_tracks.begin(); i != all_tracks.end(); ++i) {
+                       
+                       if ((*i)->covered_by_y_range (grab_y(), _drags->current_pointer_y())) {
+                               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);
+                               }
                        }
+               }
 
-                       i = tmp;
+               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);
+               }
        }
        break;
 
@@ -3858,9 +3921,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
                break;
        }
 
-       if (event->button.x >= _editor->horizontal_position() + _editor->_visible_canvas_width) {
-               _editor->start_canvas_autoscroll (1, 0);
-       }
+       _editor->maybe_autoscroll (true, false, false);
 
        if (start != end) {
                switch (_operation) {
@@ -4049,9 +4110,7 @@ RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
                }
        }
 
-       if (event->button.x >= _editor->horizontal_position() + _editor->_visible_canvas_width) {
-               _editor->start_canvas_autoscroll (1, 0);
-       }
+       _editor->maybe_autoscroll (true, false, false);
 
        if (start != end) {
                _editor->temp_location->set (start, end);
@@ -4110,10 +4169,24 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
                        _editor->new_transport_marker_context_menu (&event->button, _item);
                        break;
                }
+
        } else {
+
                /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
 
-               if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
+               if (_operation == CreateTransportMarker) {
+
+                       /* didn't drag, so just locate */
+
+                       _editor->session()->request_locate (grab_frame(), _editor->session()->transport_rolling());
+
+               } else if (_operation == CreateCDMarker) {
+
+                       /* didn't drag, but mark is already created so do
+                        * nothing */
+
+               } else { /* operation == CreateRangeMarker */
+                       
 
                        framepos_t start;
                        framepos_t end;
@@ -4351,7 +4424,7 @@ NoteDrag::motion (GdkEvent *, bool)
                uint8_t new_note = min (max (_primary->note()->note() + note_delta, 0), 127);
                
                snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (new_note).c_str(),
-                         (int) floor (new_note));
+                         (int) floor ((double)new_note));
 
                show_verbose_cursor_text (buf);
        }
@@ -4830,7 +4903,7 @@ NoteCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        double const y = sv->note_to_y (sv->y_to_note (y_to_region (event->button.y)));
 
        _drag_rect->set (ArdourCanvas::Rect (x, y, x, y + floor (_region_view->midi_stream_view()->note_height ())));
-       _drag_rect->set_outline_what (0xff);
+       _drag_rect->set_outline_all ();
        _drag_rect->set_outline_color (0xffffff99);
        _drag_rect->set_fill_color (0xffffff66);
 }
@@ -4855,7 +4928,7 @@ NoteCreateDrag::finished (GdkEvent*, bool had_movement)
        }
        
        framepos_t const start = min (_note[0], _note[1]);
-       framecnt_t length = (framecnt_t) fabs (_note[0] - _note[1]);
+       framecnt_t length = (framecnt_t) fabs ((double)(_note[0] - _note[1]));
 
        framecnt_t const g = grid_frames (start);
        double const one_tick = 1 / Timecode::BBT_Time::ticks_per_beat;