make middle-click on piano roll track header more usefully select/unselect notes
[ardour.git] / gtk2_ardour / editor_drag.cc
index 0d64d940f2d77fde145f9a409f450a17afc0e5bf..01d81a156d29b645b7b5126a997b271ac024077b 100644 (file)
@@ -160,6 +160,14 @@ DragManager::end_grab (GdkEvent* e)
        return r;
 }
 
+void
+DragManager::mark_double_click ()
+{
+       for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
+               (*i)->set_double_click (true);
+       }
+}
+
 bool
 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
 {
@@ -178,6 +186,24 @@ DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
        return r;
 }
 
+bool
+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);
+
+       for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
+               bool const t = (*i)->motion_handler (e, from_autoscroll);
+               if (t) {
+                       r = true;
+               }
+
+       }
+
+       return r;
+}
+
 bool
 DragManager::have_item (ArdourCanvas::Item* i) const
 {
@@ -194,6 +220,7 @@ Drag::Drag (Editor* e, ArdourCanvas::Item* i)
        , _item (i)
        , _pointer_frame_offset (0)
        , _move_threshold_passed (false)
+       , _was_double_click (false)
        , _raw_grab_frame (0)
        , _grab_frame (0)
        , _last_pointer_frame (0)
@@ -370,8 +397,8 @@ Drag::show_verbose_cursor_time (framepos_t frame)
 {
        _editor->verbose_cursor()->set_time (
                frame,
-               _drags->current_pointer_x() + 10 - _editor->horizontal_position(),
-               _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value()
+               _drags->current_pointer_x() + 10,
+               _drags->current_pointer_y() + 10
                );
 
        _editor->verbose_cursor()->show ();
@@ -384,8 +411,8 @@ Drag::show_verbose_cursor_duration (framepos_t start, framepos_t end, double xof
 
        _editor->verbose_cursor()->set_duration (
                start, end,
-               _drags->current_pointer_x() + 10 - _editor->horizontal_position(),
-               _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value()
+               _drags->current_pointer_x() + 10,
+               _drags->current_pointer_y() + 10
                );
 }
 
@@ -396,8 +423,8 @@ Drag::show_verbose_cursor_text (string const & text)
 
        _editor->verbose_cursor()->set (
                text,
-               _drags->current_pointer_x() + 10 - _editor->horizontal_position(),
-               _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value()
+               _drags->current_pointer_x() + 10,
+               _drags->current_pointer_y() + 10
                );
 }
 
@@ -423,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 ();
     }
 };
 
@@ -492,9 +519,11 @@ RegionDrag::find_time_axis_view (TimeAxisView* t) const
 }
 
 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
-       : RegionDrag (e, i, p, v),
-         _brushing (b),
-         _total_x_delta (0)
+       : RegionDrag (e, i, p, v)
+       , _brushing (b)
+       , _total_x_delta (0)
+       , _last_pointer_time_axis_view (0)
+       , _last_pointer_layer (0)
 {
        DEBUG_TRACE (DEBUG::Drags, "New RegionMotionDrag\n");
 }
@@ -507,8 +536,10 @@ RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        show_verbose_cursor_time (_last_frame_position);
 
        pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
-       _last_pointer_time_axis_view = find_time_axis_view (tv.first);
-       _last_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
+       if (tv.first) {
+               _last_pointer_time_axis_view = find_time_axis_view (tv.first);
+               _last_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
+       }
 }
 
 double
@@ -615,17 +646,18 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
        /* Find the TimeAxisView that the pointer is now over */
        pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
 
-       if (first_move && tv.first->view()->layer_display() == Stacked) {
-               tv.first->view()->set_layer_display (Expanded);
-       }
-
        /* Bail early if we're not over a track */
        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv.first);
+
        if (!rtv || !rtv->is_track()) {
                _editor->verbose_cursor()->hide ();
                return;
        }
 
+       if (first_move && tv.first->view()->layer_display() == Stacked) {
+               tv.first->view()->set_layer_display (Expanded);
+       }
+
        /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */
 
        /* Here's the current pointer position in terms of time axis view and layer */
@@ -637,6 +669,7 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
        double const x_delta = compute_x_delta (event, &pending_region_position);
 
        /* Work out the change in y */
+
        int delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
        double delta_layer = current_pointer_layer - _last_pointer_layer;
 
@@ -667,20 +700,19 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
 
                        rv->drag_start (); 
 
-                       /* Absolutely no idea why this is necessary, but it is; without
-                          it, the region view disappears after the reparent.
-                       */
-                       _editor->update_canvas_now ();
-                       
                        /* Reparent to a non scrolling group so that we can keep the
                           region selection above all time axis views.
                           Reparenting means that we will have to move the region view
-                          later, as the two parent groups have different coordinates.
+                          within its new parent, as the two parent groups have different coordinates.
                        */
 
+                       ArdourCanvas::Group* rvg = rv->get_canvas_group();
+                       Duple rv_canvas_offset = rvg->item_to_canvas (Duple (0,0));
+
                        rv->get_canvas_group()->reparent (_editor->_region_motion_group);
-                       
+
                        rv->fake_set_opaque (true);
+                       rvg->set_position (rv_canvas_offset);
                }
 
                /* If we have moved tracks, we'll fudge the layer delta so that the
@@ -730,8 +762,7 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
 
                        /* Get the y coordinate of the top of the track that this region is now on */
                        tv->canvas_display()->item_to_canvas (x, y);
-                       y += _editor->get_trackview_group_vertical_offset();
-                       
+
                        /* And adjust for the layer that it should be on */
                        StreamView* cv = tv->view ();
                        switch (cv->layer_display ()) {
@@ -815,15 +846,6 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                        _views = new_regionviews;
 
                        swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0);
-
-                       /*
-                         sync the canvas to what we think is its current state
-                         without it, the canvas seems to
-                         "forget" to update properly after the upcoming reparent()
-                         ..only if the mouse is in rapid motion at the time of the grab.
-                         something to do with regionview creation taking so long?
-                       */
-                       _editor->update_canvas_now();
                }
        }
 
@@ -876,8 +898,6 @@ RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred)
        bool const changed_tracks = (_time_axis_views[_views.front().time_axis_view] != &_views.front().view->get_time_axis_view());
        framecnt_t const drag_delta = _primary->region()->position() - _last_frame_position;
        
-       _editor->update_canvas_now ();
-
        if (_copy) {
 
                finished_copy (
@@ -1261,8 +1281,13 @@ void
 RegionMotionDrag::aborted (bool)
 {
        for (vector<TimeAxisView*>::iterator i = _time_axis_views.begin(); i != _time_axis_views.end(); ++i) {
-               if ((*i)->view()->layer_display() == Expanded) {
-                       (*i)->view()->set_layer_display (Stacked);
+
+               StreamView* sview = (*i)->view();
+
+               if (sview) {
+                       if (sview->layer_display() == Expanded) {
+                               sview->set_layer_display (Stacked);
+                       }
                }
        }
        
@@ -1278,8 +1303,6 @@ RegionMotionDrag::aborted (bool)
                rv->move (-_total_x_delta, 0);
                rv->set_height (rtv->view()->child_height ());
        }
-
-       _editor->update_canvas_now ();
 }
 
 /** @param b true to brush, otherwise false.
@@ -1328,8 +1351,6 @@ RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, Rout
 void
 RegionInsertDrag::finished (GdkEvent *, bool)
 {
-       _editor->update_canvas_now ();
-
        RouteTimeAxisView* dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[_views.front().time_axis_view]);
 
        _primary->get_canvas_group()->reparent (dest_rtv->view()->canvas_item());
@@ -1666,7 +1687,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;
@@ -1680,7 +1701,6 @@ VideoTimeLineDrag::motion (GdkEvent* event, bool first_move)
                DEBUG_TRACE (DEBUG::Drags, string_compose("SHIFT REGION at %1 by %2\n", i->initial_position, dt));
                if (first_move) {
                        rv->drag_start ();
-                       _editor->update_canvas_now ();
                        rv->fake_set_opaque (true);
                        rv->region()->clear_changes ();
                        rv->region()->suspend_property_changes();
@@ -1742,7 +1762,6 @@ VideoTimeLineDrag::finished (GdkEvent * /*event*/, bool movement_occurred)
 
 
        _editor->commit_reversible_command ();
-       _editor->update_canvas_now ();
 }
 
 void
@@ -1830,6 +1849,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
        TimeAxisView* tvp = &_primary->get_time_axis_view ();
        RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
        pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
+       frameoffset_t frame_delta = 0;
 
        if (tv && tv->is_track()) {
                speed = tv->track()->speed();
@@ -1926,27 +1946,11 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
 
        case ContentsTrim:
                {
-                       bool swap_direction = false;
-
-                       if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
-                               swap_direction = true;
-                       }
-
-                       framecnt_t frame_delta = 0;
-
-                       bool left_direction = false;
-                       if (last_pointer_frame() > adjusted_current_frame(event)) {
-                               left_direction = true;
-                       }
-
-                       if (left_direction) {
-                               frame_delta = (last_pointer_frame() - adjusted_current_frame(event));
-                       } else {
-                               frame_delta = (adjusted_current_frame(event) - last_pointer_frame());
-                       }
+                       frame_delta = (adjusted_current_frame(event) - last_pointer_frame());
+                       // frame_delta = (last_pointer_frame() - adjusted_current_frame(event));
 
                        for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-                               i->view->trim_contents (frame_delta, left_direction, swap_direction);
+                               i->view->move_contents (frame_delta);
                        }
                }
                break;
@@ -1960,7 +1964,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
                show_verbose_cursor_time ((framepos_t) (rv->region()->last_frame() / speed));
                break;
        case ContentsTrim:
-               show_verbose_cursor_time (adjusted_current_frame (event));
+               // show_verbose_cursor_time (frame_delta);
                break;
        }
 }
@@ -2161,7 +2165,7 @@ MeterMarkerDrag::motion (GdkEvent* event, bool first_move)
                _marker = new MeterMarker (
                        *_editor,
                        *_editor->meter_group,
-                       ARDOUR_UI::config()->canvasvar_MeterMarker.get(),
+                       ARDOUR_UI::config()->get_canvasvar_MeterMarker(),
                        name,
                        *new MeterSection (_marker->meter())
                );
@@ -2280,7 +2284,7 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
                _marker = new TempoMarker (
                        *_editor,
                        *_editor->tempo_group,
-                       ARDOUR_UI::config()->canvasvar_TempoMarker.get(),
+                       ARDOUR_UI::config()->get_canvasvar_TempoMarker(),
                        name,
                        *new TempoSection (_marker->tempo())
                        );
@@ -2353,9 +2357,10 @@ TempoMarkerDrag::aborted (bool moved)
        }
 }
 
-CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
-       : Drag (e, i),
-         _stop (s)
+CursorDrag::CursorDrag (Editor* e, EditorCursor& c, bool s)
+       : Drag (e, &c.time_bar_canvas_item())
+       , _cursor (c)
+       , _stop (s)
 {
        DEBUG_TRACE (DEBUG::Drags, "New CursorDrag\n");
 }
@@ -2372,8 +2377,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);
@@ -2387,13 +2398,18 @@ 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_frame (event);
+
        _editor->snap_to_with_modifier (where, event);
 
        _editor->_dragging_playhead = true;
 
        Session* s = _editor->session ();
 
+       /* grab the track canvas item as well */
+
+       _cursor.track_canvas_item().grab();
+
        if (s) {
                if (_was_rolling && _stop) {
                        s->request_stop ();
@@ -2429,9 +2445,6 @@ CursorDrag::motion (GdkEvent* event, bool)
        framepos_t const adjusted_frame = adjusted_current_frame (event);
        if (adjusted_frame != last_pointer_frame()) {
                fake_locate (adjusted_frame);
-#ifdef GTKOSX
-               _editor->update_canvas_now ();
-#endif
        }
 }
 
@@ -2440,6 +2453,8 @@ CursorDrag::finished (GdkEvent* event, bool movement_occurred)
 {
        _editor->_dragging_playhead = false;
 
+       _cursor.track_canvas_item().ungrab();
+
        if (!movement_occurred && _stop) {
                return;
        }
@@ -2457,6 +2472,8 @@ CursorDrag::finished (GdkEvent* event, bool movement_occurred)
 void
 CursorDrag::aborted (bool)
 {
+       _cursor.track_canvas_item().ungrab();
+
        if (_editor->_dragging_playhead) {
                _editor->session()->request_resume_timecode_transmission ();
                _editor->_dragging_playhead = false;
@@ -2976,16 +2993,16 @@ MarkerDrag::motion (GdkEvent* event, bool)
        assert (!_copied_locations.empty());
 
        show_verbose_cursor_time (newframe);
-
-#ifdef GTKOSX
-       _editor->update_canvas_now ();
-#endif
 }
 
 void
 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
 {
        if (!movement_occurred) {
+               
+               if (was_double_click()) {
+                       cerr << "End of marker double click\n";
+               }
 
                /* just a click, do nothing but finish
                   off the selection process
@@ -3422,7 +3439,7 @@ RubberbandSelectDrag::motion (GdkEvent* event, bool)
 
                _editor->rubberband_rect->set_y0 (y1);
                _editor->rubberband_rect->set_y1 (y2);
-
+               
                _editor->rubberband_rect->show();
                _editor->rubberband_rect->raise_to_top();
 
@@ -3948,8 +3965,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()->canvasvar_RangeDragRect.get());
-       _drag_rect->set_outline_color (ARDOUR_UI::config()->canvasvar_RangeDragRect.get());
+       _drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragRect());
+       _drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragRect());
 }
 
 void
@@ -4678,7 +4695,7 @@ PatchChangeDrag::setup_pointer_frame_offset ()
 }
 
 MidiRubberbandSelectDrag::MidiRubberbandSelectDrag (Editor* e, MidiRegionView* rv)
-       : RubberbandSelectDrag (e, rv->get_canvas_frame ())
+       : RubberbandSelectDrag (e, rv->get_canvas_group ())
        , _region_view (rv)
 {
 
@@ -4711,7 +4728,7 @@ MidiRubberbandSelectDrag::deselect_things ()
 }
 
 MidiVerticalSelectDrag::MidiVerticalSelectDrag (Editor* e, MidiRegionView* rv)
-       : RubberbandSelectDrag (e, rv->get_canvas_frame ())
+       : RubberbandSelectDrag (e, rv->get_canvas_group ())
        , _region_view (rv)
 {
        _vertical_only = true;
@@ -4912,9 +4929,9 @@ CrossfadeEdgeDrag::motion (GdkEvent*, bool)
        new_length = ar->verify_xfade_bounds (new_length, start);
 
        if (start) {
-               arv->redraw_start_xfade_to (ar, new_length);
+               arv->reset_fade_in_shape_width (ar, new_length);
        } else {
-               arv->redraw_end_xfade_to (ar, new_length);
+               arv->reset_fade_out_shape_width (ar, new_length);
        }
 }