X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_drag.cc;h=0b5b789e9e6e1e2943ae0e6b11ae6a3cb97f2742;hb=5ef06dd439088226683beff5c6fc1d5af55a014b;hp=1784e59944ad0ab13ba5d4a6290115857dc37811;hpb=71596b002e8be6ca99d5eb1e749a893c45804453;p=ardour.git diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 1784e59944..0b5b789e9e 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -29,10 +29,12 @@ #include "gtkmm2ext/utils.h" -#include "ardour/session.h" +#include "ardour/audioregion.h" #include "ardour/dB.h" -#include "ardour/region_factory.h" +#include "ardour/midi_region.h" #include "ardour/operations.h" +#include "ardour/region_factory.h" +#include "ardour/session.h" #include "editor.h" #include "i18n.h" @@ -66,14 +68,13 @@ using namespace ArdourCanvas; using Gtkmm2ext::Keyboard; -double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0)); +double ControlPointDrag::_zero_gain_fraction = -1.0; DragManager::DragManager (Editor* e) : _editor (e) , _ending (false) , _current_pointer_frame (0) { - } DragManager::~DragManager () @@ -86,7 +87,7 @@ void DragManager::abort () { _ending = true; - + for (list::const_iterator i = _drags.begin(); i != _drags.end(); ++i) { (*i)->abort (); delete *i; @@ -97,7 +98,7 @@ DragManager::abort () } _drags.clear (); - + _ending = false; } @@ -122,9 +123,9 @@ DragManager::start_grab (GdkEvent* e, Gdk::Cursor* c) /* Prevent follow playhead during the drag to be nice to the user */ _old_follow_playhead = _editor->follow_playhead (); _editor->set_follow_playhead (false); - + _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y); - + for (list::const_iterator i = _drags.begin(); i != _drags.end(); ++i) { (*i)->start_grab (e, c); } @@ -137,7 +138,7 @@ bool DragManager::end_grab (GdkEvent* e) { _ending = true; - + bool r = false; for (list::iterator i = _drags.begin(); i != _drags.end(); ++i) { bool const t = (*i)->end_grab (e); @@ -152,7 +153,7 @@ DragManager::end_grab (GdkEvent* e) _ending = false; _editor->set_follow_playhead (_old_follow_playhead, false); - + return r; } @@ -162,13 +163,13 @@ DragManager::motion_handler (GdkEvent* e, bool from_autoscroll) bool r = false; _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y); - + for (list::iterator i = _drags.begin(); i != _drags.end(); ++i) { bool const t = (*i)->motion_handler (e, from_autoscroll); if (t) { r = true; } - + } return r; @@ -185,7 +186,7 @@ DragManager::have_item (ArdourCanvas::Item* i) const return j != _drags.end (); } -Drag::Drag (Editor* e, ArdourCanvas::Item* i) +Drag::Drag (Editor* e, ArdourCanvas::Item* i) : _editor (e) , _item (i) , _pointer_frame_offset (0) @@ -337,7 +338,7 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll) _last_pointer_x = _drags->current_pointer_x (); _last_pointer_y = _drags->current_pointer_y (); _last_pointer_frame = adjusted_current_frame (event); - + return true; } } @@ -374,7 +375,7 @@ void Drag::show_verbose_cursor_duration (framepos_t start, framepos_t end, double xoffset) { _editor->verbose_cursor()->show (xoffset); - + _editor->verbose_cursor()->set_duration ( start, end, _drags->current_pointer_x() + 10 - _editor->horizontal_position(), @@ -386,7 +387,7 @@ void Drag::show_verbose_cursor_text (string const & text) { _editor->verbose_cursor()->show (); - + _editor->verbose_cursor()->set ( text, _drags->current_pointer_x() + 10 - _editor->horizontal_position(), @@ -410,30 +411,29 @@ RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, listvisible_order_range (&_visible_y_low, &_visible_y_high); - /* Make a list of non-hidden tracks to refer to during the drag */ + /* Make a list of tracks to refer to during the drag; we include hidden tracks, + as some of the regions we are dragging may be on such tracks. + */ TrackViewList track_views = _editor->track_views; track_views.sort (EditorOrderTimeAxisViewSorter ()); for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - if (!(*i)->hidden()) { - - _time_axis_views.push_back (*i); - - TimeAxisView::Children children_list = (*i)->get_child_list (); - for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) { - _time_axis_views.push_back (j->get()); - } + _time_axis_views.push_back (*i); + + TimeAxisView::Children children_list = (*i)->get_child_list (); + for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) { + _time_axis_views.push_back (j->get()); } } /* the list of views can be empty at this point if this is a region list-insert drag */ - + for (list::const_iterator i = v.begin(); i != v.end(); ++i) { _views.push_back (DraggingView (*i, this)); } - + RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context()); } @@ -450,7 +450,9 @@ RegionDrag::region_going_away (RegionView* v) } } -/** Given a non-hidden TimeAxisView, return the index of it into the _time_axis_views vector */ +/** Given a TimeAxisView, return the index of it into the _time_axis_views vector, + * or -1 if it is not found. + */ int RegionDrag::find_time_axis_view (TimeAxisView* t) const { @@ -463,7 +465,7 @@ RegionDrag::find_time_axis_view (TimeAxisView* t) const if (i == N) { return -1; } - + return i; } @@ -499,19 +501,19 @@ RegionMotionDrag::compute_x_delta (GdkEvent const * event, framepos_t* pending_r framepos_t sync_frame; framecnt_t sync_offset; int32_t sync_dir; - + sync_offset = _primary->region()->sync_offset (sync_dir); - + /* we don't handle a sync point that lies before zero. */ if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) { - + sync_frame = *pending_region_position + (sync_dir*sync_offset); - + _editor->snap_to_with_modifier (sync_frame, event); - + *pending_region_position = _primary->region()->adjust_to_sync (sync_frame); - + } else { *pending_region_position = _last_frame_position; } @@ -566,7 +568,7 @@ RegionMotionDrag::y_movement_allowed (int delta_track, layer_t delta_layer) cons /* not a track, or the wrong type */ return false; } - + int const l = i->layer + delta_layer; if (delta_track == 0 && (l < 0 || l >= int (to->view()->layers()))) { /* Off the top or bottom layer; note that we only refuse if the track hasn't changed. @@ -634,49 +636,24 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) if (first_move) { - /* here we are calculating the y distance from the - top of the first track view to the top of the region - area of the track view that we're working on */ - - /* this x value is just a dummy value so that we have something - to pass to i2w () */ - - double ix1 = 0; - - /* distance from the top of this track view to the region area - of our track view is always 1 */ - - double iy1 = 1; - - /* convert to world coordinates, ie distance from the top of - the ruler section */ - - rv->get_canvas_frame()->i2w (ix1, iy1); - - /* compensate for the ruler section and the vertical scrollbar position */ - iy1 += _editor->get_trackview_group_vertical_offset (); - - // hide any dependent views - rv->get_time_axis_view().hide_dependent_views (*rv); - - /* - reparent to a non scrolling group so that we can keep the - region selection above all time axis views. - reparenting means we have to move the rv as the two - parent groups have different coordinates. + + /* 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. */ - rv->get_canvas_group()->property_y() = iy1 - 1; rv->get_canvas_group()->reparent (*(_editor->_region_motion_group)); rv->fake_set_opaque (true); + + if (!rv->get_time_axis_view().hidden()) { + /* the track that this region view is on is hidden, so hide the region too */ + rv->get_canvas_group()->hide (); + } } - /* Work out the change in y position of this region view */ - - double y_delta = 0; - /* If we have moved tracks, we'll fudge the layer delta so that the region gets moved back onto layer 0 on its new track; this avoids confusion when dragging regions from non-zero layers onto different @@ -687,33 +664,21 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) this_delta_layer = - i->layer; } - /* Move this region to layer 0 on its old track */ - StreamView* lv = _time_axis_views[i->time_axis_view]->view (); - if (lv->layer_display() == Stacked) { - y_delta -= (lv->layers() - i->layer - 1) * lv->child_height (); - } - - /* Now move it to its right layer on the current track */ - StreamView* cv = _time_axis_views[i->time_axis_view + delta_time_axis_view]->view (); - if (cv->layer_display() == Stacked) { - y_delta += (cv->layers() - (i->layer + this_delta_layer) - 1) * cv->child_height (); - } + /* The TimeAxisView that this region is now on */ + TimeAxisView* tv = _time_axis_views[i->time_axis_view + delta_time_axis_view]; + + /* Set height */ + rv->set_height (tv->view()->child_height ()); - /* Move tracks */ - if (delta_time_axis_view > 0) { - for (int j = 0; j < delta_time_axis_view; ++j) { - y_delta += _time_axis_views[i->time_axis_view + j]->current_height (); - } + /* Update show/hidden status as the region view may have come from a hidden track, + or have moved to one. + */ + if (tv->hidden ()) { + rv->get_canvas_group()->hide (); } else { - /* start by subtracting the height of the track above where we are now */ - for (int j = 1; j <= -delta_time_axis_view; ++j) { - y_delta -= _time_axis_views[i->time_axis_view - j]->current_height (); - } + rv->get_canvas_group()->show (); } - /* Set height */ - rv->set_height (_time_axis_views[i->time_axis_view + delta_time_axis_view]->view()->child_height ()); - /* Update the DraggingView */ i->time_axis_view += delta_time_axis_view; i->layer += this_delta_layer; @@ -721,13 +686,27 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) if (_brushing) { _editor->mouse_brush_insert_region (rv, pending_region_position); } else { - rv->move (x_delta, y_delta); + double x = 0; + double y = 0; + + /* Get the y coordinate of the top of the track that this region is now on */ + tv->canvas_display()->i2w (x, y); + y += _editor->get_trackview_group_vertical_offset(); + + /* And adjust for the layer that it should be on */ + StreamView* cv = tv->view (); + if (cv->layer_display() == Stacked) { + y += (cv->layers() - i->layer - 1) * cv->child_height (); + } + + /* Now move the region view */ + rv->move (x_delta, y - rv->get_canvas_group()->property_y()); } } /* foreach region */ _total_x_delta += x_delta; - + if (first_move) { _editor->cursor_group->raise_to_top(); } @@ -750,20 +729,20 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move) list new_regionviews; for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - + RegionView* rv = i->view; AudioRegionView* arv = dynamic_cast(rv); MidiRegionView* mrv = dynamic_cast(rv); const boost::shared_ptr original = rv->region(); boost::shared_ptr region_copy = RegionFactory::create (original, true); - region_copy->set_position (original->position(), this); - + region_copy->set_position (original->position()); + RegionView* nrv; if (arv) { boost::shared_ptr audioregion_copy = boost::dynamic_pointer_cast(region_copy); - + nrv = new AudioRegionView (*arv, audioregion_copy); } else if (mrv) { boost::shared_ptr midiregion_copy @@ -772,29 +751,29 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move) } else { continue; } - + nrv->get_canvas_group()->show (); new_regionviews.push_back (DraggingView (nrv, this)); - + /* swap _primary to the copy */ - + if (rv == _primary) { _primary = nrv; } - + /* ..and deselect the one we copied */ - + rv->set_selected (false); } - + if (!new_regionviews.empty()) { - + /* reflect the fact that we are dragging the copies */ - + _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 @@ -827,28 +806,36 @@ RegionMoveDrag::finished (GdkEvent *, bool movement_occurred) assert (!_views.empty ()); + /* We might have hidden region views so that they weren't visible during the drag + (when they have been reparented). Now everything can be shown again, as region + views are back in their track parent groups. + */ + for (list::iterator i = _views.begin(); i != _views.end(); ++i) { + i->view->get_canvas_group()->show (); + } + bool const changed_position = (_last_frame_position != _primary->region()->position()); 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 (); + _editor->update_canvas_now (); + if (_copy) { - + finished_copy ( changed_position, changed_tracks, drag_delta ); - + } else { - + finished_no_copy ( changed_position, changed_tracks, drag_delta ); - + } } @@ -894,13 +881,13 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed RegionView* new_view = insert_region_into_playlist ( i->view->region(), dynamic_cast (_time_axis_views[i->time_axis_view]), i->layer, where, modified_playlists ); - + if (new_view == 0) { continue; } new_views.push_back (new_view); - + /* we don't need the copied RegionView any more */ views_to_delete.push_back (i->view); } @@ -913,8 +900,8 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed delete *i; } - /* If we've created new regions either by copying or moving - to a new track, we want to replace the old selection with the new ones + /* If we've created new regions either by copying or moving + to a new track, we want to replace the old selection with the new ones */ if (new_views.size() > 0) { @@ -998,7 +985,7 @@ RegionMoveDrag::finished_no_copy ( remove_region_from_playlist (rv->region(), i->initial_playlist, modified_playlists); } else { - + rv->region()->clear_changes (); /* @@ -1014,12 +1001,12 @@ RegionMoveDrag::finished_no_copy ( /* just change the model */ boost::shared_ptr playlist = dest_rtv->playlist(); - + if (dest_rtv->view()->layer_display() == Stacked) { rv->region()->set_layer (dest_layer); rv->region()->set_pending_explicit_relayer (true); } - + /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */ pair r = frozen_playlists.insert (playlist); @@ -1031,19 +1018,19 @@ RegionMoveDrag::finished_no_copy ( /* 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, (void*) this); + rv->region()->set_position (where); _editor->session()->add_command (new StatefulDiffCommand (rv->region())); } if (changed_tracks) { - + /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region was selected in all of them, then removing it from a playlist will have removed all trace of it from _views (i.e. there were N regions selected, we removed 1, @@ -1061,7 +1048,7 @@ RegionMoveDrag::finished_no_copy ( we can just iterate. */ - + if (_views.empty()) { break; } else { @@ -1073,8 +1060,8 @@ RegionMoveDrag::finished_no_copy ( } } - /* If we've created new regions either by copying or moving - to a new track, we want to replace the old selection with the new ones + /* If we've created new regions either by copying or moving + to a new track, we want to replace the old selection with the new ones */ if (new_views.size() > 0) { @@ -1112,7 +1099,7 @@ RegionMoveDrag::remove_region_from_playlist ( playlist->remove_region (region); } - + /** Insert a region into a playlist, handling the recovery of the resulting new RegionView, and * clearing the playlist's diff history first if necessary. @@ -1121,7 +1108,7 @@ RegionMoveDrag::remove_region_from_playlist ( * @param dest_layer Destination layer. * @param where Destination position. * @param modified_playlists The playlist will be added to this if it is not there already; used to ensure - * that clear_changes () is only called once per playlist. + * that clear_changes () is only called once per playlist. * @return New RegionView, or 0 if no insert was performed. */ RegionView * @@ -1142,7 +1129,7 @@ RegionMoveDrag::insert_region_into_playlist ( _new_region_view = 0; sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &RegionMoveDrag::collect_new_region_view)); - /* clear history for the playlist we are about to insert to, provided we haven't already done so */ + /* clear history for the playlist we are about to insert to, provided we haven't already done so */ pair r = modified_playlists.insert (dest_playlist); if (r.second) { dest_playlist->clear_changes (); @@ -1225,7 +1212,7 @@ RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, _copy (c) { DEBUG_TRACE (DEBUG::Drags, "New RegionMoveDrag\n"); - + double speed = 1; RouteTimeAxisView* rtv = dynamic_cast (&_primary->get_time_axis_view ()); if (rtv && rtv->is_track()) { @@ -1245,7 +1232,7 @@ RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr r, Rout : RegionMotionDrag (e, 0, 0, list (), false) { DEBUG_TRACE (DEBUG::Drags, "New RegionInsertDrag\n"); - + assert ((boost::dynamic_pointer_cast (r) && dynamic_cast (v)) || (boost::dynamic_pointer_cast (r) && dynamic_cast (v))); @@ -1310,11 +1297,6 @@ RegionSpliceDrag::motion (GdkEvent* event, bool) pair const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ()); RouteTimeAxisView* tv = dynamic_cast (tvp.first); - layer_t layer = tvp.second; - - if (tv && tv->layer_display() == Overlaid) { - layer = 0; - } /* The region motion is only processed if the pointer is over an audio track. @@ -1393,7 +1375,7 @@ RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisVi _view (dynamic_cast (v)) { DEBUG_TRACE (DEBUG::Drags, "New RegionCreateDrag\n"); - + assert (_view); } @@ -1407,18 +1389,18 @@ RegionCreateDrag::motion (GdkEvent* event, bool first_move) if (_region) { framepos_t const f = adjusted_current_frame (event); if (f < grab_frame()) { - _region->set_position (f, this); + _region->set_position (f); } - + /* Don't use a zero-length region, and subtract 1 frame from the snapped length so that if this region is duplicated, its duplicate starts on a snap point rather than 1 frame after a snap point. Otherwise things get a bit confusing as if a region starts 1 frame after a snap point, one cannot place snapped notes at the start of the region. */ - + framecnt_t const len = abs (f - grab_frame () - 1); - _region->set_length (len < 1 ? 1 : len, this); + _region->set_length (len < 1 ? 1 : len); } } } @@ -1547,7 +1529,10 @@ NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/) void NoteResizeDrag::aborted (bool) { - /* XXX: TODO */ + MidiRegionSelection& ms (_editor->get_selection().midi_regions); + for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) { + (*r)->abort_resizing (); + } } RegionGainDrag::RegionGainDrag (Editor* e, ArdourCanvas::Item* i) @@ -1717,7 +1702,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move) } framecnt_t frame_delta = 0; - + bool left_direction = false; if (last_pointer_frame() > adjusted_current_frame(event)) { left_direction = true; @@ -1765,7 +1750,7 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) i->view->trim_front_ending (); } } - + if (!_editor->selection->selected (_primary)) { _primary->thaw_after_trim (); } else { @@ -1807,7 +1792,7 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) if (_operation == StartTrim) { i->view->trim_front_ending (); } - + i->view->region()->resume_property_changes (); } } @@ -1821,7 +1806,7 @@ TrimDrag::aborted (bool movement_occurred) */ finished (0, true); - + if (movement_occurred) { _editor->undo (); } @@ -1860,7 +1845,7 @@ MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c) _copy (c) { DEBUG_TRACE (DEBUG::Drags, "New MeterMarkerDrag\n"); - + _marker = reinterpret_cast (_item->get_data ("marker")); assert (_marker); } @@ -1912,7 +1897,7 @@ MeterMarkerDrag::motion (GdkEvent* event, bool) framepos_t const pf = adjusted_current_frame (event); _marker->set_position (pf); - + show_verbose_cursor_time (pf); } @@ -1962,7 +1947,7 @@ TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c) _copy (c) { DEBUG_TRACE (DEBUG::Drags, "New TempoMarkerDrag\n"); - + _marker = reinterpret_cast (_item->get_data ("marker")); assert (_marker); } @@ -1999,7 +1984,7 @@ void TempoMarkerDrag::setup_pointer_frame_offset () { _pointer_frame_offset = raw_grab_frame() - _marker->tempo().frame(); -} +} void TempoMarkerDrag::motion (GdkEvent* event, bool) @@ -2065,7 +2050,7 @@ void CursorDrag::fake_locate (framepos_t t) { _editor->playhead_cursor->set_position (t); - + Session* s = _editor->session (); if (s->timecode_transmission_suspended ()) { framepos_t const f = _editor->playhead_cursor->current_frame; @@ -2082,28 +2067,30 @@ CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) { Drag::start_grab (event, c); + _grab_zoom = _editor->frames_per_unit; + framepos_t where = _editor->event_frame (event, 0, 0); _editor->snap_to_with_modifier (where, event); _editor->_dragging_playhead = true; - + Session* s = _editor->session (); - + if (s) { if (_was_rolling && _stop) { s->request_stop (); } - + if (s->is_auditioning()) { s->cancel_audition (); } - + s->request_suspend_timecode_transmission (); while (!s->timecode_transmission_suspended ()) { /* twiddle our thumbs */ } } - + fake_locate (where); } @@ -2111,16 +2098,12 @@ void CursorDrag::motion (GdkEvent* event, bool) { framepos_t const adjusted_frame = adjusted_current_frame (event); - - if (adjusted_frame == last_pointer_frame()) { - return; - } - - fake_locate (adjusted_frame); - + if (adjusted_frame != last_pointer_frame()) { + fake_locate (adjusted_frame); #ifdef GTKOSX - _editor->update_canvas_now (); + _editor->update_canvas_now (); #endif + } } void @@ -2149,7 +2132,7 @@ CursorDrag::aborted (bool) _editor->session()->request_resume_timecode_transmission (); _editor->_dragging_playhead = false; } - + _editor->playhead_cursor->set_position (adjusted_frame (grab_frame (), 0, false)); } @@ -2168,7 +2151,7 @@ FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) boost::shared_ptr 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); } @@ -2287,7 +2270,7 @@ FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) boost::shared_ptr 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); } @@ -2297,7 +2280,7 @@ FadeOutDrag::setup_pointer_frame_offset () AudioRegionView* arv = dynamic_cast (_primary); boost::shared_ptr r = arv->audio_region (); _pointer_frame_offset = raw_grab_frame() - (r->length() - (framecnt_t) r->fade_out()->back()->when + r->position()); -} +} void FadeOutDrag::motion (GdkEvent* event, bool) @@ -2399,7 +2382,7 @@ MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i) : Drag (e, i) { DEBUG_TRACE (DEBUG::Drags, "New MarkerDrag\n"); - + _marker = reinterpret_cast (_item->get_data ("marker")); assert (_marker); @@ -2711,7 +2694,7 @@ MarkerDrag::aborted (bool) } void -MarkerDrag::update_item (Location* location) +MarkerDrag::update_item (Location*) { /* noop */ } @@ -2721,8 +2704,12 @@ ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i) _cumulative_x_drag (0), _cumulative_y_drag (0) { + if (_zero_gain_fraction < 0.0) { + _zero_gain_fraction = gain_to_slider_position_with_max (dB_to_coefficient (0.0), Config->get_max_gain()); + } + DEBUG_TRACE (DEBUG::Drags, "New ControlPointDrag\n"); - + _point = reinterpret_cast (_item->get_data ("control_point")); assert (_point); } @@ -2788,7 +2775,7 @@ ControlPointDrag::motion (GdkEvent* event, bool) cy = min ((double) _point->line().height(), cy); framepos_t cx_frames = _editor->unit_to_frame (cx); - + if (!_x_constrained) { _editor->snap_to_with_modifier (cx_frames, event); } @@ -2818,7 +2805,7 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred) } else { motion (event, false); } - + _point->line().end_drag (); _editor->session()->commit_reversible_command (); } @@ -2870,7 +2857,7 @@ LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) uint32_t before; uint32_t after; - + if (!_line->control_points_adjacent (frame_within_region, before, after)) { /* no adjacent points */ return; @@ -2951,7 +2938,7 @@ void FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) { Drag::start_grab (event); - + _line = reinterpret_cast (_item); assert (_line); @@ -2964,9 +2951,9 @@ FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) /* store grab start in parent frame */ _region_view_grab_x = cx; - + _before = *(float*) _item->get_data ("position"); - + _arv = reinterpret_cast (_item->get_data ("regionview")); _max_x = _editor->frame_to_pixel(_arv->get_duration()); @@ -2976,34 +2963,34 @@ void FeatureLineDrag::motion (GdkEvent*, bool) { double dx = _drags->current_pointer_x() - last_pointer_x(); - + double cx = _region_view_grab_x + _cumulative_x_drag + dx; - + _cumulative_x_drag += dx; - + /* Clamp the min and max extent of the drag to keep it within the region view bounds */ - + if (cx > _max_x){ cx = _max_x; } else if(cx < 0){ cx = 0; } - + ArdourCanvas::Points points; - + double x1 = 0, x2 = 0, y1 = 0, y2 = 0; _line->get_bounds(x1, y2, x2, y2); - + points.push_back(Gnome::Art::Point(cx, 2.0)); // first x-coord needs to be a non-normal value points.push_back(Gnome::Art::Point(cx, y2 - y1)); _line->property_points() = points; - + float *pos = new float; *pos = cx; - + _line->set_data ("position", pos); _before = cx; @@ -3083,45 +3070,51 @@ RubberbandSelectDrag::motion (GdkEvent* event, bool) _editor->rubberband_rect->raise_to_top(); show_verbose_cursor_time (pf); + + do_select_things (event, true); } } void -RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred) +RubberbandSelectDrag::do_select_things (GdkEvent* event, bool drag_in_progress) { - if (movement_occurred) { - - motion (event, false); + framepos_t x1; + framepos_t x2; + + if (grab_frame() < last_pointer_frame()) { + x1 = grab_frame (); + x2 = last_pointer_frame (); + } else { + x2 = grab_frame (); + x1 = last_pointer_frame (); + } - double y1,y2; - if (_drags->current_pointer_y() < grab_y()) { - y1 = _drags->current_pointer_y(); - y2 = grab_y(); - } else { - y2 = _drags->current_pointer_y(); - y1 = grab_y(); - } + double y1; + double y2; + + if (_drags->current_pointer_y() < grab_y()) { + y1 = _drags->current_pointer_y(); + y2 = grab_y(); + } else { + y2 = _drags->current_pointer_y(); + y1 = grab_y(); + } + select_things (event->button.state, x1, x2, y1, y2, drag_in_progress); +} - Selection::Operation op = ArdourKeyboard::selection_type (event->button.state); +void +RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred) +{ + if (movement_occurred) { - _editor->begin_reversible_command (_("rubberband selection")); + motion (event, false); + do_select_things (event, false); - if (grab_frame() < last_pointer_frame()) { - _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op, false); - } else { - _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op, false); - } + } else { - _editor->commit_reversible_command (); + deselect_things (); - } else { - if (!getenv("ARDOUR_SAE")) { - _editor->selection->clear_tracks(); - } - _editor->selection->clear_regions(); - _editor->selection->clear_points (); - _editor->selection->clear_lines (); } _editor->rubberband_rect->hide(); @@ -3323,7 +3316,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) if (pending_time_axis.first == 0) { return; } - + framepos_t const pending_position = adjusted_current_frame (event); /* only alter selection if things have changed */ @@ -3368,7 +3361,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) //_editor->selection->set (_editor->clicked_axisview); _editor->set_selected_track_as_side_effect (Selection::Set); } - + _editor->clicked_selection = _editor->selection->set (start, end); } } @@ -3383,7 +3376,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) /* 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()); @@ -3392,7 +3385,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) list::iterator tmp = i; ++tmp; - + if ((*i)->order() < min_order || (*i)->order() > max_order) { _editor->selection->remove (*i); _added_time_axes.remove (*i); @@ -3487,7 +3480,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred) 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); } @@ -3509,8 +3502,8 @@ RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operat _copy (false) { DEBUG_TRACE (DEBUG::Drags, "New RangeMarkerBarDrag\n"); - - _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, + + _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, physical_screen_height (_editor->get_window())); _drag_rect->hide (); @@ -3578,7 +3571,7 @@ RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move) if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) { framepos_t grab = grab_frame (); _editor->snap_to (grab); - + if (pf < grab_frame()) { start = pf; end = grab; @@ -3652,7 +3645,7 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred) newloc = new Location ( *_editor->session(), _editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags ); - + _editor->session()->locations()->add (newloc, true); XMLNode &after = _editor->session()->locations()->get_state(); _editor->session()->add_command(new MementoCommand(*(_editor->session()->locations()), &before, &after)); @@ -3736,7 +3729,7 @@ MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *) Drag::start_grab (event, _editor->cursors()->zoom_in); _zoom_out = false; } - + show_verbose_cursor_time (adjusted_current_frame (event)); } @@ -3847,55 +3840,37 @@ NoteDrag::total_dx () const frameoffset_t const dx = _editor->unit_to_frame (_drags->current_pointer_x() - grab_x()); /* primary note time */ - frameoffset_t const n = _region->beats_to_frames (_primary->note()->time ()); - - /* new time of the primary note relative to the region position */ + frameoffset_t const n = _region->source_beats_to_absolute_frames (_primary->note()->time ()); + + /* new time of the primary note in session frames */ frameoffset_t st = n + dx; + framepos_t const rp = _region->region()->position (); + /* prevent the note being dragged earlier than the region's position */ - if (st < 0) { - st = 0; - } + st = max (st, rp); /* snap and return corresponding delta */ - return _region->snap_frame_to_frame (st) - n; + return _region->snap_frame_to_frame (st - rp) + rp - n; } -/** @return Current total drag y change in notes */ +/** @return Current total drag y change in note number */ int8_t NoteDrag::total_dy () const { - /* this is `backwards' to make increasing note number go in the right direction */ - double const dy = _drags->current_pointer_y() - grab_y(); - - /* dy in notes */ - int8_t ndy = 0; - - if (abs (dy) >= _note_height) { - if (dy > 0) { - ndy = (int8_t) ceil (dy / _note_height / 2.0); - } else { - ndy = (int8_t) floor (dy / _note_height / 2.0); - } - } - - /* more positive value = higher pitch and higher y-axis position on track, - which is the inverse of the X-centric geometric universe - */ - - return -ndy; -} + return ((int8_t) (grab_y() / _note_height)) - ((int8_t) (_drags->current_pointer_y() / _note_height)); +} void NoteDrag::motion (GdkEvent *, bool) { /* Total change in x and y since the start of the drag */ frameoffset_t const dx = total_dx (); - int8_t const dy = -total_dy (); + 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 = _editor->frame_to_unit (dx) - _cumulative_dx; - double const tdy = dy * _note_height - _cumulative_dy; + double const tdy = -dy * _note_height - _cumulative_dy; if (tdx || tdy) { _cumulative_dx += tdx; @@ -3905,10 +3880,18 @@ NoteDrag::motion (GdkEvent *, bool) _region->move_selection (tdx, tdy, note_delta); + /* the new note value may be the same as the old one, but we + * don't know what that means because the selection may have + * involved more than one note and we might be doing something + * odd with them. so show the note value anyway, always. + */ + char buf[12]; - snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (_primary->note()->note() + note_delta).c_str(), - (int) floor (_primary->note()->note() + note_delta)); - + 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)); + show_verbose_cursor_text (buf); } } @@ -3954,7 +3937,7 @@ AutomationRangeDrag::AutomationRangeDrag (Editor* editor, ArdourCanvas::Item* it , _nothing_to_drag (false) { DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n"); - + _atav = reinterpret_cast (_item->get_data ("trackview")); assert (_atav); @@ -4012,13 +3995,13 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) i->points.push_back (i->line->nth (j)); } } - + } else { for (list::const_iterator i = _ranges.begin(); i != _ranges.end(); ++i) { framecnt_t const half = (i->start + i->end) / 2; - + /* find the line that this audio range starts in */ list::iterator j = _lines.begin(); while (j != _lines.end() && (j->range.first > i->start || j->range.second < i->start)) { @@ -4027,7 +4010,7 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) if (j != _lines.end()) { boost::shared_ptr the_list = j->line->the_list (); - + /* j is the line that this audio range starts in; fade into it; 64 samples length plucked out of thin air. */ @@ -4047,7 +4030,7 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) } /* same thing for the end */ - + j = _lines.begin(); while (j != _lines.end() && (j->range.first > i->end || j->range.second < i->end)) { ++j; @@ -4055,11 +4038,11 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) if (j != _lines.end()) { boost::shared_ptr the_list = j->line->the_list (); - + /* j is the line that this audio range starts in; fade out of it; 64 samples length plucked out of thin air. */ - + framepos_t b = i->end - 64; if (b < half) { b = half; @@ -4067,7 +4050,7 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) double const p = j->line->time_converter().from (b - j->line->time_converter().origin_b ()); double const q = j->line->time_converter().from (i->end - j->line->time_converter().origin_b ()); - + the_list->add (p, the_list->eval (p)); j->line->add_always_in_view (p); the_list->add (q, the_list->eval (q)); @@ -4135,7 +4118,7 @@ AutomationRangeDrag::finished (GdkEvent* event, bool) if (_nothing_to_drag) { return; } - + motion (event, false); for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { i->line->end_drag (); @@ -4181,7 +4164,7 @@ PatchChangeDrag::motion (GdkEvent* ev, bool) boost::shared_ptr r = _region_view->region (); f = max (f, r->position ()); f = min (f, r->last_frame ()); - + framecnt_t const dxf = f - grab_frame(); double const dxu = _editor->frame_to_unit (dxf); _patch_change->move (dxu - _cumulative_dx, 0); @@ -4196,14 +4179,14 @@ PatchChangeDrag::finished (GdkEvent* ev, bool movement_occurred) } boost::shared_ptr r (_region_view->region ()); - + framepos_t f = adjusted_current_frame (ev); f = max (f, r->position ()); f = min (f, r->last_frame ()); - + _region_view->move_patch_change ( *_patch_change, - _region_view->frames_to_beats (f - r->position() - r->start()) + _region_view->region_frames_to_region_beats (f - r->position() - r->start()) ); } @@ -4217,6 +4200,70 @@ void PatchChangeDrag::setup_pointer_frame_offset () { boost::shared_ptr region = _region_view->region (); - _pointer_frame_offset = raw_grab_frame() - _region_view->beats_to_frames (_patch_change->patch()->time()) - region->position() + region->start(); + _pointer_frame_offset = raw_grab_frame() - _region_view->source_beats_to_absolute_frames (_patch_change->patch()->time()); +} + +MidiRubberbandSelectDrag::MidiRubberbandSelectDrag (Editor* e, MidiRegionView* rv) + : RubberbandSelectDrag (e, rv->get_canvas_frame ()) + , _region_view (rv) +{ + +} + +void +MidiRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress) +{ + framepos_t const p = _region_view->region()->position (); + double const y = _region_view->midi_view()->y_position (); + + x1 = max ((framepos_t) 0, x1 - p); + x2 = max ((framepos_t) 0, x2 - p); + y1 = max (0.0, y1 - y); + y2 = max (0.0, y2 - y); + + _region_view->update_drag_selection ( + _editor->frame_to_pixel (x1), + _editor->frame_to_pixel (x2), + y1, + y2, + Keyboard::modifier_state_contains (button_state, Keyboard::TertiaryModifier) + ); } +void +MidiRubberbandSelectDrag::deselect_things () +{ + /* XXX */ +} + +EditorRubberbandSelectDrag::EditorRubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i) + : RubberbandSelectDrag (e, i) +{ + +} + +void +EditorRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress) +{ + if (drag_in_progress) { + /* We just want to select things at the end of the drag, not during it */ + return; + } + + Selection::Operation op = ArdourKeyboard::selection_type (button_state); + + _editor->begin_reversible_command (_("rubberband selection")); + _editor->select_all_within (x1, x2 - 1, y1, y2, _editor->track_views, op, false); + _editor->commit_reversible_command (); +} + +void +EditorRubberbandSelectDrag::deselect_things () +{ + if (!getenv("ARDOUR_SAE")) { + _editor->selection->clear_tracks(); + } + _editor->selection->clear_regions(); + _editor->selection->clear_points (); + _editor->selection->clear_lines (); +}