diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 64c5f67fd7..1833d10008 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -6184,6 +6184,54 @@ struct TrackViewStripableSorter } }; +static const int track_drag_spacer_height = 25; + +void +Editor::maybe_move_tracks () +{ + for (auto & tv : track_views) { + + if (!tv->marked_for_display () || (tv == track_drag->track)) { + continue; + } + + /* find the track the mouse pointer is within, and if + * we're in the upper or lower half of it (depending on + * drag direction, move the spacer. + */ + + if (track_drag->current >= tv->y_position() && track_drag->current < (tv->y_position() + tv->effective_height())) { + + if (track_drag->bump_track == tv) { + /* already bumped for this track */ + break; + } + + if (track_drag->direction < 0) { + + /* dragging up */ + + if (track_drag->current < (tv->y_position() + (tv->effective_height() / 2))) { + /* in top half of this track, move spacer */ + track_drag->bump_track = tv; + move_selected_tracks (true); + } + + } else if (track_drag->direction > 0) { + + /* dragging down */ + + if (track_drag->current > (tv->y_position() + (tv->effective_height() / 2))) { + track_drag->bump_track = tv; + move_selected_tracks (false); + } + } + + break; + } + } +} + bool Editor::redisplay_track_views () { @@ -6200,21 +6248,24 @@ Editor::redisplay_track_views () track_views.sort (TrackViewStripableSorter ()); - uint32_t position; - TrackViewList::const_iterator i; + if (track_drag) { // && track_drag->spacer) { + maybe_move_tracks (); + } /* n will be the count of tracks plus children (updated by TimeAxisView::show_at), * so we will use that to know where to put things. */ - int n; - for (n = 0, position = 0, i = track_views.begin(); i != track_views.end(); ++i) { - TimeAxisView *tv = (*i); + int n = 0; + uint32_t position = 0; + + for (auto & tv : track_views) { if (tv->marked_for_display ()) { position += tv->show_at (position, n, &edit_controls_vbox); } else { tv->hide (); } + n++; } @@ -7016,3 +7067,74 @@ Editor::default_time_domain () const } return BeatTime; } + +void +Editor::start_track_drag (TimeAxisView& tav, int y, Gtk::Widget& w) +{ + track_drag = new TrackDrag (dynamic_cast (&tav)); + + track_drag->drag_cursor = _cursors->move->gobj(); + track_drag->predrag_cursor = gdk_window_get_cursor (edit_controls_vbox.get_window()->gobj()); + + gdk_window_set_cursor (edit_controls_vbox.get_toplevel()->get_window()->gobj(), track_drag->drag_cursor); + + int xo, yo; + w.translate_coordinates (edit_controls_vbox, 0, y, xo, yo); + + track_drag->have_predrag_cursor = true; + track_drag->bump_track = nullptr; + track_drag->previous = yo; + track_drag->start = yo; +} + +void +Editor::mid_track_drag (GdkEventMotion* ev, Gtk::Widget& w) +{ + int xo, yo; + w.translate_coordinates (edit_controls_vbox, ev->x, ev->y, xo, yo); + + if (track_drag->first_move) { + if (!track_drag->track->selected()) { + set_selected_track (*track_drag->track, Selection::Set, false); + } + track_drag->first_move = false; + } + + track_drag->current = yo; + + if (track_drag->current > track_drag->previous) { + if (track_drag->direction != 1) { + track_drag->bump_track = nullptr; + track_drag->direction = 1; + } + } else if (track_drag->current < track_drag->previous) { + if (track_drag->direction != -1) { + track_drag->bump_track = nullptr; + track_drag->direction = -1; + } + } + + if (track_drag->current == track_drag->previous) { + return; + } + + redisplay_track_views (); + track_drag->previous = yo; +} + +void +Editor::end_track_drag () +{ + if (track_drag->have_predrag_cursor) { + gdk_window_set_cursor (edit_controls_vbox.get_toplevel()->get_window()->gobj(), track_drag->predrag_cursor); + } + + delete track_drag; + track_drag = nullptr; +} + +bool +Editor::track_dragging() const +{ + return (bool) track_drag; +} diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index e9a6153b0b..cb3cda62ad 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1416,8 +1416,7 @@ private: void start_track_drag (TimeAxisView&, int y, Gtk::Widget& w); void mid_track_drag (GdkEventMotion*, Gtk::Widget& e); void end_track_drag (); - void maybe_place_drag_spacer (); - void get_layout_relative_coordinates (Gtk::Widget&, int x, int y, int &xo, int &yo); + void maybe_move_tracks (); bool track_dragging() const; void do_insert_time (); @@ -2607,29 +2606,27 @@ private: struct TrackDrag { RouteTimeAxisView* track; - Gtk::EventBox* spacer; GdkCursor* drag_cursor; GdkCursor* predrag_cursor; TimeAxisView* bump_track; - int spacer_order; double start; double current; double previous; bool have_predrag_cursor; int direction; + bool first_move; TrackDrag (RouteTimeAxisView* rtav) : track (rtav) - , spacer (nullptr) , drag_cursor (nullptr) , predrag_cursor (nullptr) , bump_track (nullptr) - , spacer_order (-1) , start (-1.) , current (0.) , previous (0.) , have_predrag_cursor (false) , direction (0) + , first_move (true) {} }; diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index b29c94a9a4..c7647aceb0 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -591,7 +591,6 @@ public: virtual void start_track_drag (TimeAxisView&, int y, Gtk::Widget&) = 0; virtual void mid_track_drag (GdkEventMotion*, Gtk::Widget&) = 0; virtual void end_track_drag () = 0; - virtual void get_layout_relative_coordinates (Gtk::Widget&, int x, int y, int &xo, int &yo) = 0; virtual bool track_dragging() const = 0; /// Singleton instance, set up by Editor::Editor() diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc index 2d80131689..ccb7fbedd8 100644 --- a/gtk2_ardour/time_axis_view.cc +++ b/gtk2_ardour/time_axis_view.cc @@ -438,7 +438,13 @@ TimeAxisView::controls_ebox_button_press (GdkEventButton* event) _ebox_release_can_act = true; if (maybe_set_cursor (event->y) > 0) { + _resize_drag_start = event->y_root; + + } else { + if (event->button == 1) { + _editor.start_track_drag (*this, event->y, controls_ebox); + } } return true; @@ -453,6 +459,12 @@ TimeAxisView::idle_resize (int32_t h) bool TimeAxisView::controls_ebox_motion (GdkEventMotion* ev) { + if (_editor.track_dragging()) { + _editor.mid_track_drag (ev, controls_ebox); + gdk_event_request_motions (ev); + return true; + } + if (_resize_drag_start >= 0) { /* (ab)use the DragManager to do autoscrolling - basically we @@ -468,13 +480,15 @@ TimeAxisView::controls_ebox_motion (GdkEventMotion* ev) _editor.add_to_idle_resize (this, delta); _resize_drag_start = ev->y_root; _did_resize = true; + gdk_event_request_motions (ev); + return true; } else { /* not dragging but ... */ maybe_set_cursor (ev->y); } - gdk_event_request_motions(ev); - return true; + gdk_event_request_motions (ev); + return false; } bool @@ -519,28 +533,28 @@ bool TimeAxisView::controls_ebox_button_release (GdkEventButton* ev) { if (_editor.track_dragging()) { - return false; + _editor.end_track_drag (); + } else { + if (_resize_drag_start >= 0) { + if (_have_preresize_cursor) { + gdk_window_set_cursor (controls_ebox.get_window()->gobj(), _preresize_cursor); + _preresize_cursor = 0; + _have_preresize_cursor = false; + } + _editor.stop_canvas_autoscroll (); + _resize_drag_start = -1; + if (_did_resize) { + _did_resize = false; + // don't change selection + return true; + } } - if (_resize_drag_start >= 0) { - if (_have_preresize_cursor) { - gdk_window_set_cursor (controls_ebox.get_window()->gobj(), _preresize_cursor); - _preresize_cursor = 0; - _have_preresize_cursor = false; - } - _editor.stop_canvas_autoscroll (); - _resize_drag_start = -1; - if (_did_resize) { - _did_resize = false; - // don't change selection + if (!_ebox_release_can_act) { return true; } } - if (!_ebox_release_can_act) { - return true; - } - switch (ev->button) { case 1: if (selectable()) {