2 Copyright (C) 2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "pbd/memento_command.h"
21 #include "pbd/basename.h"
22 #include "ardour/diskstream.h"
23 #include "ardour/session.h"
24 #include "ardour/dB.h"
25 #include "ardour/region_factory.h"
26 #include "ardour/midi_diskstream.h"
30 #include "audio_region_view.h"
31 #include "midi_region_view.h"
32 #include "ardour_ui.h"
33 #include "gui_thread.h"
34 #include "control_point.h"
36 #include "region_gain_line.h"
37 #include "editor_drag.h"
38 #include "audio_time_axis.h"
39 #include "midi_time_axis.h"
40 #include "canvas-note.h"
41 #include "selection.h"
42 #include "midi_selection.h"
43 #include "automation_time_axis.h"
46 using namespace ARDOUR;
49 using namespace Editing;
50 using namespace ArdourCanvas;
52 using Gtkmm2ext::Keyboard;
54 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
56 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
59 , _pointer_frame_offset (0)
60 , _have_transaction (false)
61 , _move_threshold_passed (false)
63 , _last_pointer_frame (0)
64 , _current_pointer_frame (0)
70 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
76 cursor = _editor->which_grabber_cursor ();
79 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
83 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
86 cursor = _editor->which_grabber_cursor ();
89 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
91 if (Keyboard::is_button2_event (&event->button)) {
92 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
93 _y_constrained = true;
94 _x_constrained = false;
96 _y_constrained = false;
97 _x_constrained = true;
100 _x_constrained = false;
101 _y_constrained = false;
104 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
105 _grab_frame = adjusted_frame (_grab_frame, event);
106 _last_pointer_frame = _grab_frame;
107 _current_pointer_frame = _grab_frame;
108 _current_pointer_x = _grab_x;
109 _current_pointer_y = _grab_y;
110 _last_pointer_x = _current_pointer_x;
111 _last_pointer_y = _current_pointer_y;
115 _item->i2w (_original_x, _original_y);
117 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
121 if (_editor->session() && _editor->session()->transport_rolling()) {
124 _was_rolling = false;
127 switch (_editor->snap_type()) {
128 case SnapToRegionStart:
129 case SnapToRegionEnd:
130 case SnapToRegionSync:
131 case SnapToRegionBoundary:
132 _editor->build_region_boundary_cache ();
139 /** @param event GDK event, or 0.
140 * @return true if some movement occurred, otherwise false.
143 Drag::end_grab (GdkEvent* event)
147 _editor->stop_canvas_autoscroll ();
149 _item->ungrab (event ? event->button.time : 0);
151 _last_pointer_x = _current_pointer_x;
152 _last_pointer_y = _current_pointer_y;
153 finished (event, _move_threshold_passed);
155 _editor->hide_verbose_canvas_cursor();
159 return _move_threshold_passed;
163 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
167 if (f > _pointer_frame_offset) {
168 pos = f - _pointer_frame_offset;
172 _editor->snap_to_with_modifier (pos, event);
179 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
181 return adjusted_frame (_current_pointer_frame, event, snap);
185 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
187 _last_pointer_x = _current_pointer_x;
188 _last_pointer_y = _current_pointer_y;
189 _last_pointer_frame = adjusted_current_frame (event);
190 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
192 pair<nframes64_t, int> const threshold = move_threshold ();
194 bool const old_move_threshold_passed = _move_threshold_passed;
196 if (!from_autoscroll && !_move_threshold_passed) {
198 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
199 bool const yp = (::fabs ((_current_pointer_y - _grab_y)) >= threshold.second);
201 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
204 if (active (_editor->mouse_mode) && _move_threshold_passed) {
206 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
207 if (!from_autoscroll) {
208 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
211 motion (event, _move_threshold_passed != old_move_threshold_passed);
223 _editor->stop_canvas_autoscroll ();
224 _editor->hide_verbose_canvas_cursor ();
229 /* put it back where it came from */
234 _item->i2w (cxw, cyw);
235 _item->move (_original_x - cxw, _original_y - cyw);
240 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
245 RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
249 RegionDrag::region_going_away (RegionView* v)
254 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
255 : RegionDrag (e, i, p, v),
265 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
267 Drag::start_grab (event);
269 _editor->show_verbose_time_cursor (_last_frame_position, 10);
272 RegionMotionDrag::TimeAxisViewSummary
273 RegionMotionDrag::get_time_axis_view_summary ()
275 int32_t children = 0;
276 TimeAxisViewSummary sum;
278 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
280 /* get a bitmask representing the visible tracks */
282 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
283 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
284 TimeAxisView::Children children_list;
286 /* zeroes are audio/MIDI tracks. ones are other types. */
288 if (!rtv->hidden()) {
290 if (!rtv->is_track()) {
291 /* not an audio nor MIDI track */
292 sum.tracks = sum.tracks |= (0x01 << rtv->order());
295 sum.height_list[rtv->order()] = (*i)->current_height();
298 if ((children_list = rtv->get_child_list()).size() > 0) {
299 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
300 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
301 sum.height_list[rtv->order() + children] = (*j)->current_height();
312 RegionMotionDrag::compute_y_delta (
313 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
314 int32_t last_pointer_layer, int32_t current_pointer_layer,
315 TimeAxisViewSummary const & tavs,
316 int32_t* pointer_order_span, int32_t* pointer_layer_span,
317 int32_t* canvas_pointer_order_span
321 *pointer_order_span = 0;
322 *pointer_layer_span = 0;
326 bool clamp_y_axis = false;
328 /* the change in track order between this callback and the last */
329 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
330 /* the change in layer between this callback and the last;
331 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
332 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
334 if (*pointer_order_span != 0) {
336 /* find the actual pointer span, in terms of the number of visible tracks;
337 to do this, we reduce |pointer_order_span| by the number of hidden tracks
340 *canvas_pointer_order_span = *pointer_order_span;
341 if (last_pointer_view->order() >= current_pointer_view->order()) {
342 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
343 if (tavs.height_list[y] == 0) {
344 *canvas_pointer_order_span--;
348 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
349 if (tavs.height_list[y] == 0) {
350 *canvas_pointer_order_span++;
355 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
357 RegionView* rv = (*i);
359 if (rv->region()->locked()) {
363 double ix1, ix2, iy1, iy2;
364 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
365 rv->get_canvas_frame()->i2w (ix1, iy1);
366 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
368 /* get the new trackview for this particular region */
369 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
371 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
373 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
374 as surely this is a per-region thing... */
376 clamp_y_axis = y_movement_disallowed (
377 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
385 } else if (_dest_trackview == current_pointer_view) {
387 if (current_pointer_layer == last_pointer_layer) {
388 /* No movement; clamp */
394 _dest_trackview = current_pointer_view;
395 _dest_layer = current_pointer_layer;
403 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
405 /* compute the amount of pointer motion in frames, and where
406 the region would be if we moved it by that much.
408 *pending_region_position = adjusted_current_frame (event);
410 nframes64_t sync_frame;
411 nframes64_t sync_offset;
414 sync_offset = _primary->region()->sync_offset (sync_dir);
416 /* we don't handle a sync point that lies before zero.
418 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
420 sync_frame = *pending_region_position + (sync_dir*sync_offset);
422 _editor->snap_to_with_modifier (sync_frame, event);
424 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
427 *pending_region_position = _last_frame_position;
430 if (*pending_region_position > max_frames - _primary->region()->length()) {
431 *pending_region_position = _last_frame_position;
436 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
438 /* now compute the canvas unit distance we need to move the regionview
439 to make it appear at the new location.
442 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
444 if (*pending_region_position <= _last_frame_position) {
446 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
448 RegionView* rv = (*i);
450 // If any regionview is at zero, we need to know so we can stop further leftward motion.
452 double ix1, ix2, iy1, iy2;
453 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
454 rv->get_canvas_frame()->i2w (ix1, iy1);
456 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
458 *pending_region_position = _last_frame_position;
465 _last_frame_position = *pending_region_position;
472 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
476 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
478 vector<int32_t>::iterator j;
480 /* *pointer* variables reflect things about the pointer; as we may be moving
481 multiple regions, much detail must be computed per-region */
483 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
484 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
485 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
486 is always 0 regardless of what the region's "real" layer is */
487 RouteTimeAxisView* current_pointer_view;
488 layer_t current_pointer_layer;
489 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
493 /* TimeAxisView that we were pointing at last time we entered this method */
494 TimeAxisView const * const last_pointer_view = _dest_trackview;
495 /* the order of the track that we were pointing at last time we entered this method */
496 int32_t const last_pointer_order = last_pointer_view->order ();
497 /* the layer that we were pointing at last time we entered this method */
498 layer_t const last_pointer_layer = _dest_layer;
500 int32_t pointer_order_span;
501 int32_t pointer_layer_span;
502 int32_t canvas_pointer_order_span;
504 bool const clamp_y_axis = compute_y_delta (
505 last_pointer_view, current_pointer_view,
506 last_pointer_layer, current_pointer_layer, tavs,
507 &pointer_order_span, &pointer_layer_span,
508 &canvas_pointer_order_span
511 nframes64_t pending_region_position;
512 double const x_delta = compute_x_delta (event, &pending_region_position);
514 /*************************************************************
516 ************************************************************/
518 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
519 /* haven't reached next snap point, and we're not switching
520 trackviews nor layers. nothing to do.
525 /*************************************************************
527 ************************************************************/
529 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
531 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
533 RegionView* rv = (*i);
535 if (rv->region()->locked()) {
539 /* here we are calculating the y distance from the
540 top of the first track view to the top of the region
541 area of the track view that we're working on */
543 /* this x value is just a dummy value so that we have something
548 /* distance from the top of this track view to the region area
549 of our track view is always 1 */
553 /* convert to world coordinates, ie distance from the top of
556 rv->get_canvas_frame()->i2w (ix1, iy1);
558 /* compensate for the ruler section and the vertical scrollbar position */
559 iy1 += _editor->get_trackview_group_vertical_offset ();
563 // hide any dependent views
565 rv->get_time_axis_view().hide_dependent_views (*rv);
568 reparent to a non scrolling group so that we can keep the
569 region selection above all time axis views.
570 reparenting means we have to move the rv as the two
571 parent groups have different coordinates.
574 rv->get_canvas_group()->property_y() = iy1 - 1;
575 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
577 rv->fake_set_opaque (true);
580 /* current view for this particular region */
581 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
582 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
584 if (pointer_order_span != 0 && !clamp_y_axis) {
586 /* INTER-TRACK MOVEMENT */
588 /* move through the height list to the track that the region is currently on */
589 vector<int32_t>::iterator j = tavs.height_list.begin ();
591 while (j != tavs.height_list.end () && x != rtv->order ()) {
597 int32_t temp_pointer_order_span = canvas_pointer_order_span;
599 if (j != tavs.height_list.end ()) {
601 /* Account for layers in the original and
602 destination tracks. If we're moving around in layers we assume
603 that only one track is involved, so it's ok to use *pointer*
606 StreamView* lv = last_pointer_view->view ();
609 /* move to the top of the last trackview */
610 if (lv->layer_display () == Stacked) {
611 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
614 StreamView* cv = current_pointer_view->view ();
617 /* move to the right layer on the current trackview */
618 if (cv->layer_display () == Stacked) {
619 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
622 /* And for being on a non-topmost layer on the new
625 while (temp_pointer_order_span > 0) {
626 /* we're moving up canvas-wise,
627 so we need to find the next track height
629 if (j != tavs.height_list.begin()) {
633 if (x != last_pointer_order) {
635 ++temp_pointer_order_span;
640 temp_pointer_order_span--;
643 while (temp_pointer_order_span < 0) {
647 if (x != last_pointer_order) {
649 --temp_pointer_order_span;
653 if (j != tavs.height_list.end()) {
657 temp_pointer_order_span++;
661 /* find out where we'll be when we move and set height accordingly */
663 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
664 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
665 rv->set_height (temp_rtv->view()->child_height());
667 /* if you un-comment the following, the region colours will follow
668 the track colours whilst dragging; personally
669 i think this can confuse things, but never mind.
672 //const GdkColor& col (temp_rtv->view->get_region_color());
673 //rv->set_color (const_cast<GdkColor&>(col));
677 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
679 /* INTER-LAYER MOVEMENT in the same track */
680 y_delta = rtv->view()->child_height () * pointer_layer_span;
685 _editor->mouse_brush_insert_region (rv, pending_region_position);
687 rv->move (x_delta, y_delta);
690 } /* foreach region */
693 _editor->cursor_group->raise_to_top();
696 if (x_delta != 0 && !_brushing) {
697 _editor->show_verbose_time_cursor (_last_frame_position, 10);
702 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
704 if (_copy && first_move) {
705 copy_regions (event);
708 RegionMotionDrag::motion (event, first_move);
712 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
714 vector<RegionView*> copies;
715 boost::shared_ptr<Diskstream> ds;
716 boost::shared_ptr<Playlist> from_playlist;
717 RegionSelection new_views;
718 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
719 PlaylistSet modified_playlists;
720 PlaylistSet frozen_playlists;
721 list <sigc::connection> modified_playlist_connections;
722 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
723 nframes64_t drag_delta;
724 bool changed_tracks, changed_position;
725 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
726 RouteTimeAxisView* source_tv;
728 if (!movement_occurred) {
734 /* all changes were made during motion event handlers */
737 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
738 copies.push_back (*i);
745 /* reverse this here so that we have the correct logic to finalize
749 if (Config->get_edit_mode() == Lock) {
750 _x_constrained = !_x_constrained;
754 if (_x_constrained) {
755 _editor->begin_reversible_command (_("fixed time region copy"));
757 _editor->begin_reversible_command (_("region copy"));
760 if (_x_constrained) {
761 _editor->begin_reversible_command (_("fixed time region drag"));
763 _editor->begin_reversible_command (_("region drag"));
767 _have_transaction = true;
769 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
770 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
772 drag_delta = _primary->region()->position() - _last_frame_position;
774 _editor->update_canvas_now ();
776 /* make a list of where each region ended up */
777 final = find_time_axis_views_and_layers ();
779 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
781 RegionView* rv = (*i);
782 RouteTimeAxisView* dest_rtv = final[*i].first;
783 layer_t dest_layer = final[*i].second;
787 if (rv->region()->locked()) {
792 if (changed_position && !_x_constrained) {
793 where = rv->region()->position() - drag_delta;
795 where = rv->region()->position();
798 boost::shared_ptr<Region> new_region;
801 /* we already made a copy */
802 new_region = rv->region();
804 /* undo the previous hide_dependent_views so that xfades don't
805 disappear on copying regions
808 //rv->get_time_axis_view().reveal_dependent_views (*rv);
810 } else if (changed_tracks && dest_rtv->playlist()) {
811 new_region = RegionFactory::create (rv->region());
814 if (changed_tracks || _copy) {
816 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
823 _editor->latest_regionviews.clear ();
825 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
827 insert_result = modified_playlists.insert (to_playlist);
829 if (insert_result.second) {
830 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
833 to_playlist->add_region (new_region, where);
834 if (dest_rtv->view()->layer_display() == Stacked) {
835 new_region->set_layer (dest_layer);
836 new_region->set_pending_explicit_relayer (true);
841 if (!_editor->latest_regionviews.empty()) {
842 // XXX why just the first one ? we only expect one
843 // commented out in nick_m's canvas reworking. is that intended?
844 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
845 new_views.push_back (_editor->latest_regionviews.front());
850 motion on the same track. plonk the previously reparented region
851 back to its original canvas group (its streamview).
852 No need to do anything for copies as they are fake regions which will be deleted.
855 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
856 rv->get_canvas_group()->property_y() = 0;
858 /* just change the model */
860 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
862 if (dest_rtv->view()->layer_display() == Stacked) {
863 rv->region()->set_layer (dest_layer);
864 rv->region()->set_pending_explicit_relayer (true);
867 insert_result = modified_playlists.insert (playlist);
869 if (insert_result.second) {
870 _editor->session()->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
872 /* freeze to avoid lots of relayering in the case of a multi-region drag */
873 frozen_insert_result = frozen_playlists.insert(playlist);
875 if (frozen_insert_result.second) {
879 rv->region()->set_position (where, (void*) this);
882 if (changed_tracks && !_copy) {
884 /* get the playlist where this drag started. we can't use rv->region()->playlist()
885 because we may have copied the region and it has not been attached to a playlist.
888 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
889 ds = source_tv->get_diskstream();
890 from_playlist = ds->playlist();
894 assert (from_playlist);
896 /* moved to a different audio track, without copying */
898 /* the region that used to be in the old playlist is not
899 moved to the new one - we use a copy of it. as a result,
900 any existing editor for the region should no longer be
904 rv->hide_region_editor();
905 rv->fake_set_opaque (false);
907 /* remove the region from the old playlist */
909 insert_result = modified_playlists.insert (from_playlist);
911 if (insert_result.second) {
912 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
915 from_playlist->remove_region (rv->region());
917 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
918 was selected in all of them, then removing it from a playlist will have removed all
919 trace of it from the selection (i.e. there were N regions selected, we removed 1,
920 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
921 corresponding regionview, and the selection is now empty).
923 this could have invalidated any and all iterators into the region selection.
925 the heuristic we use here is: if the region selection is empty, break out of the loop
926 here. if the region selection is not empty, then restart the loop because we know that
927 we must have removed at least the region(view) we've just been working on as well as any
928 that we processed on previous iterations.
930 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
934 if (_views.empty()) {
945 copies.push_back (rv);
949 if we've created new regions either by copying or moving
950 to a new track, we want to replace the old selection with the new ones
952 if (new_views.size() > 0) {
953 _editor->selection->set (new_views);
956 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
961 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
962 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
965 _editor->commit_reversible_command ();
967 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
974 RegionMotionDrag::x_move_allowed () const
976 if (Config->get_edit_mode() == Lock) {
977 /* in locked edit mode, reverse the usual meaning of _x_constrained */
978 return _x_constrained;
981 return !_x_constrained;
985 RegionMotionDrag::copy_regions (GdkEvent* event)
987 /* duplicate the regionview(s) and region(s) */
989 list<RegionView*> new_regionviews;
991 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
993 RegionView* rv = (*i);
994 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
995 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
997 const boost::shared_ptr<const Region> original = rv->region();
998 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1002 boost::shared_ptr<AudioRegion> audioregion_copy
1003 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1004 nrv = new AudioRegionView (*arv, audioregion_copy);
1006 boost::shared_ptr<MidiRegion> midiregion_copy
1007 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1008 nrv = new MidiRegionView (*mrv, midiregion_copy);
1013 nrv->get_canvas_group()->show ();
1014 new_regionviews.push_back (nrv);
1016 /* swap _primary to the copy */
1018 if (rv == _primary) {
1022 /* ..and deselect the one we copied */
1024 rv->set_selected (false);
1027 if (new_regionviews.empty()) {
1031 /* reflect the fact that we are dragging the copies */
1033 _views = new_regionviews;
1035 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1038 sync the canvas to what we think is its current state
1039 without it, the canvas seems to
1040 "forget" to update properly after the upcoming reparent()
1041 ..only if the mouse is in rapid motion at the time of the grab.
1042 something to do with regionview creation raking so long?
1044 _editor->update_canvas_now();
1048 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1050 /* Which trackview is this ? */
1052 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1053 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1054 (*layer) = tvp.second;
1056 if (*tv && (*tv)->layer_display() == Overlaid) {
1060 /* The region motion is only processed if the pointer is over
1064 if (!(*tv) || !(*tv)->is_track()) {
1065 /* To make sure we hide the verbose canvas cursor when the mouse is
1066 not held over and audiotrack.
1068 _editor->hide_verbose_canvas_cursor ();
1075 /** @param new_order New track order.
1076 * @param old_order Old track order.
1077 * @param visible_y_low Lowest visible order.
1078 * @return true if y movement should not happen, otherwise false.
1081 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1083 if (new_order != old_order) {
1085 /* this isn't the pointer track */
1089 /* moving up the canvas */
1090 if ( (new_order - y_span) >= tavs.visible_y_low) {
1094 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1095 int32_t visible_tracks = 0;
1096 while (visible_tracks < y_span ) {
1098 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1099 /* passing through a hidden track */
1104 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1105 /* moving to a non-track; disallow */
1111 /* moving beyond the lowest visible track; disallow */
1115 } else if (y_span < 0) {
1117 /* moving down the canvas */
1118 if ((new_order - y_span) <= tavs.visible_y_high) {
1120 int32_t visible_tracks = 0;
1122 while (visible_tracks > y_span ) {
1125 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1126 /* passing through a hidden track */
1131 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1132 /* moving to a non-track; disallow */
1139 /* moving beyond the highest visible track; disallow */
1146 /* this is the pointer's track */
1148 if ((new_order - y_span) > tavs.visible_y_high) {
1149 /* we will overflow */
1151 } else if ((new_order - y_span) < tavs.visible_y_low) {
1152 /* we will overflow */
1161 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1162 : RegionMotionDrag (e, i, p, v, b),
1165 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1167 _dest_trackview = tv;
1168 if (tv->layer_display() == Overlaid) {
1171 _dest_layer = _primary->region()->layer ();
1175 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1176 if (rtv && rtv->is_track()) {
1177 speed = rtv->get_diskstream()->speed ();
1180 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1184 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1186 RegionMotionDrag::start_grab (event, c);
1188 _pointer_frame_offset = grab_frame() - _last_frame_position;
1191 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1192 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1194 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1195 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1197 _primary = v->view()->create_region_view (r, false, false);
1199 _primary->get_canvas_group()->show ();
1200 _primary->set_position (pos, 0);
1201 _views.push_back (_primary);
1203 _last_frame_position = pos;
1205 _item = _primary->get_canvas_group ();
1206 _dest_trackview = v;
1207 _dest_layer = _primary->region()->layer ();
1210 map<RegionView*, pair<RouteTimeAxisView*, int> >
1211 RegionMotionDrag::find_time_axis_views_and_layers ()
1213 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1215 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1217 double ix1, ix2, iy1, iy2;
1218 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1219 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1220 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1222 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1223 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1231 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1233 _editor->update_canvas_now ();
1235 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1237 RouteTimeAxisView* dest_rtv = final[_primary].first;
1239 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1240 _primary->get_canvas_group()->property_y() = 0;
1242 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1244 _editor->begin_reversible_command (_("insert region"));
1245 XMLNode& before = playlist->get_state ();
1246 playlist->add_region (_primary->region (), _last_frame_position);
1247 _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1248 _editor->commit_reversible_command ();
1255 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1256 : RegionMoveDrag (e, i, p, v, false, false)
1261 struct RegionSelectionByPosition {
1262 bool operator() (RegionView*a, RegionView* b) {
1263 return a->region()->position () < b->region()->position();
1268 RegionSpliceDrag::motion (GdkEvent* event, bool)
1270 RouteTimeAxisView* tv;
1273 if (!check_possible (&tv, &layer)) {
1279 if ((current_pointer_x() - last_pointer_x()) > 0) {
1285 RegionSelection copy (_editor->selection->regions);
1287 RegionSelectionByPosition cmp;
1290 nframes64_t const pf = adjusted_current_frame (event);
1292 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1294 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1300 boost::shared_ptr<Playlist> playlist;
1302 if ((playlist = atv->playlist()) == 0) {
1306 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1311 if (pf < (*i)->region()->last_frame() + 1) {
1315 if (pf > (*i)->region()->first_frame()) {
1321 playlist->shuffle ((*i)->region(), dir);
1326 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1332 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1340 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1342 _dest_trackview = _view;
1344 Drag::start_grab (event);
1349 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1352 // TODO: create region-create-drag region view here
1355 // TODO: resize region-create-drag region view here
1359 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1361 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1367 if (!movement_occurred) {
1368 mtv->add_region (grab_frame ());
1370 motion (event, false);
1371 // TODO: create region-create-drag region here
1375 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1383 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1386 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1388 Drag::start_grab (event);
1390 region = &cnote->region_view();
1392 double region_start = region->get_position_pixels();
1393 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1395 if (grab_x() <= middle_point) {
1396 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1399 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1403 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1405 if (event->motion.state & Keyboard::PrimaryModifier) {
1411 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1413 if (ms.size() > 1) {
1414 /* has to be relative, may make no sense otherwise */
1418 region->note_selected (cnote, true);
1420 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1421 MidiRegionSelection::iterator next;
1424 (*r)->begin_resizing (at_front);
1430 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1432 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1433 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1434 (*r)->update_resizing (at_front, current_pointer_x() - grab_x(), relative);
1439 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1441 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1442 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1443 (*r)->commit_resizing (at_front, current_pointer_x() - grab_x(), relative);
1448 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1454 RegionGainDrag::finished (GdkEvent *, bool)
1459 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1460 : RegionDrag (e, i, p, v)
1466 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1469 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1470 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1472 if (tv && tv->is_track()) {
1473 speed = tv->get_diskstream()->speed();
1476 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1477 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1478 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1480 Drag::start_grab (event, _editor->trimmer_cursor);
1482 nframes64_t const pf = adjusted_current_frame (event);
1484 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1485 _operation = ContentsTrim;
1487 /* These will get overridden for a point trim.*/
1488 if (pf < (region_start + region_length/2)) {
1489 /* closer to start */
1490 _operation = StartTrim;
1491 } else if (pf > (region_end - region_length/2)) {
1493 _operation = EndTrim;
1497 switch (_operation) {
1499 _editor->show_verbose_time_cursor (region_start, 10);
1502 _editor->show_verbose_time_cursor (region_end, 10);
1505 _editor->show_verbose_time_cursor (pf, 10);
1511 TrimDrag::motion (GdkEvent* event, bool first_move)
1513 RegionView* rv = _primary;
1514 nframes64_t frame_delta = 0;
1516 bool left_direction;
1517 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1519 /* snap modifier works differently here..
1520 its current state has to be passed to the
1521 various trim functions in order to work properly
1525 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1526 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1527 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1529 if (tv && tv->is_track()) {
1530 speed = tv->get_diskstream()->speed();
1533 nframes64_t const pf = adjusted_current_frame (event);
1535 if (last_pointer_frame() > pf) {
1536 left_direction = true;
1538 left_direction = false;
1545 switch (_operation) {
1547 trim_type = "Region start trim";
1550 trim_type = "Region end trim";
1553 trim_type = "Region content trim";
1557 _editor->begin_reversible_command (trim_type);
1558 _have_transaction = true;
1560 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1561 (*i)->fake_set_opaque(false);
1562 (*i)->region()->freeze ();
1564 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1567 arv->temporarily_hide_envelope ();
1570 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1571 insert_result = _editor->motion_frozen_playlists.insert (pl);
1573 if (insert_result.second) {
1574 _editor->session()->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1580 if (pf == last_pointer_frame()) {
1584 /* XXX i hope to god that we can really conclude this ... */
1585 _have_transaction = true;
1587 if (left_direction) {
1588 frame_delta = (last_pointer_frame() - pf);
1590 frame_delta = (pf - last_pointer_frame());
1593 bool non_overlap_trim = false;
1595 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1596 non_overlap_trim = true;
1599 switch (_operation) {
1601 if ((left_direction == false) && (pf <= rv->region()->first_frame()/speed)) {
1605 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1606 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1612 if ((left_direction == true) && (pf > (nframes64_t) (rv->region()->last_frame()/speed))) {
1616 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1617 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1624 bool swap_direction = false;
1626 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1627 swap_direction = true;
1630 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1631 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1637 switch (_operation) {
1639 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1642 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1645 _editor->show_verbose_time_cursor (pf, 10);
1652 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1654 if (movement_occurred) {
1655 motion (event, false);
1657 if (!_editor->selection->selected (_primary)) {
1658 _editor->thaw_region_after_trim (*_primary);
1661 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1662 _editor->thaw_region_after_trim (**i);
1663 (*i)->fake_set_opaque (true);
1666 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1668 if (_have_transaction) {
1669 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1673 _editor->motion_frozen_playlists.clear ();
1675 if (_have_transaction) {
1676 _editor->commit_reversible_command();
1680 /* no mouse movement */
1681 _editor->point_trim (event);
1685 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1689 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1694 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1697 // create a dummy marker for visual representation of moving the copy.
1698 // The actual copying is not done before we reach the finish callback.
1700 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1701 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1702 *new MeterSection (_marker->meter()));
1704 _item = &new_marker->the_item ();
1705 _marker = new_marker;
1709 MetricSection& section (_marker->meter());
1711 if (!section.movable()) {
1717 Drag::start_grab (event, cursor);
1719 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1721 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1725 MeterMarkerDrag::motion (GdkEvent* event, bool)
1727 nframes64_t const pf = adjusted_current_frame (event);
1729 if (pf == last_pointer_frame()) {
1733 _marker->set_position (pf);
1735 _editor->show_verbose_time_cursor (pf, 10);
1739 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1741 if (!movement_occurred) {
1745 motion (event, false);
1749 TempoMap& map (_editor->session()->tempo_map());
1750 map.bbt_time (last_pointer_frame(), when);
1752 if (_copy == true) {
1753 _editor->begin_reversible_command (_("copy meter mark"));
1754 XMLNode &before = map.get_state();
1755 map.add_meter (_marker->meter(), when);
1756 XMLNode &after = map.get_state();
1757 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1758 _editor->commit_reversible_command ();
1760 // delete the dummy marker we used for visual representation of copying.
1761 // a new visual marker will show up automatically.
1764 _editor->begin_reversible_command (_("move meter mark"));
1765 XMLNode &before = map.get_state();
1766 map.move_meter (_marker->meter(), when);
1767 XMLNode &after = map.get_state();
1768 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1769 _editor->commit_reversible_command ();
1773 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1777 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1782 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1787 // create a dummy marker for visual representation of moving the copy.
1788 // The actual copying is not done before we reach the finish callback.
1790 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1791 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1792 *new TempoSection (_marker->tempo()));
1794 _item = &new_marker->the_item ();
1795 _marker = new_marker;
1799 MetricSection& section (_marker->tempo());
1801 if (!section.movable()) {
1806 Drag::start_grab (event, cursor);
1808 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
1809 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
1813 TempoMarkerDrag::motion (GdkEvent* event, bool)
1815 nframes64_t const pf = adjusted_current_frame (event);
1817 if (pf == last_pointer_frame()) {
1821 /* OK, we've moved far enough to make it worth actually move the thing. */
1823 _marker->set_position (pf);
1825 _editor->show_verbose_time_cursor (pf, 10);
1829 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1831 if (!movement_occurred) {
1835 motion (event, false);
1839 TempoMap& map (_editor->session()->tempo_map());
1840 map.bbt_time (last_pointer_frame(), when);
1842 if (_copy == true) {
1843 _editor->begin_reversible_command (_("copy tempo mark"));
1844 XMLNode &before = map.get_state();
1845 map.add_tempo (_marker->tempo(), when);
1846 XMLNode &after = map.get_state();
1847 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1848 _editor->commit_reversible_command ();
1850 // delete the dummy marker we used for visual representation of copying.
1851 // a new visual marker will show up automatically.
1854 _editor->begin_reversible_command (_("move tempo mark"));
1855 XMLNode &before = map.get_state();
1856 map.move_tempo (_marker->tempo(), when);
1857 XMLNode &after = map.get_state();
1858 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1859 _editor->commit_reversible_command ();
1864 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1868 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1873 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1875 Drag::start_grab (event, c);
1879 nframes64_t where = _editor->event_frame (event, 0, 0);
1881 _editor->snap_to_with_modifier (where, event);
1882 _editor->playhead_cursor->set_position (where);
1886 if (_cursor == _editor->playhead_cursor) {
1887 _editor->_dragging_playhead = true;
1889 if (_editor->session() && _was_rolling && _stop) {
1890 _editor->session()->request_stop ();
1893 if (_editor->session() && _editor->session()->is_auditioning()) {
1894 _editor->session()->cancel_audition ();
1898 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1902 CursorDrag::motion (GdkEvent* event, bool)
1904 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1906 if (adjusted_frame == last_pointer_frame()) {
1910 _cursor->set_position (adjusted_frame);
1912 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1915 _editor->update_canvas_now ();
1917 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1921 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1923 _editor->_dragging_playhead = false;
1925 if (!movement_occurred && _stop) {
1929 motion (event, false);
1931 if (_item == &_editor->playhead_cursor->canvas_item) {
1932 if (_editor->session()) {
1933 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1934 _editor->_pending_locate_request = true;
1939 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1940 : RegionDrag (e, i, p, v)
1946 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1948 Drag::start_grab (event, cursor);
1950 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1951 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1953 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
1954 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
1958 FadeInDrag::motion (GdkEvent* event, bool)
1960 nframes64_t fade_length;
1962 nframes64_t const pos = adjusted_current_frame (event);
1964 boost::shared_ptr<Region> region = _primary->region ();
1966 if (pos < (region->position() + 64)) {
1967 fade_length = 64; // this should be a minimum defined somewhere
1968 } else if (pos > region->last_frame()) {
1969 fade_length = region->length();
1971 fade_length = pos - region->position();
1974 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1976 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1982 tmp->reset_fade_in_shape_width (fade_length);
1985 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1989 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1991 if (!movement_occurred) {
1995 nframes64_t fade_length;
1997 nframes64_t const pos = adjusted_current_frame (event);
1999 boost::shared_ptr<Region> region = _primary->region ();
2001 if (pos < (region->position() + 64)) {
2002 fade_length = 64; // this should be a minimum defined somewhere
2003 } else if (pos > region->last_frame()) {
2004 fade_length = region->length();
2006 fade_length = pos - region->position();
2009 _editor->begin_reversible_command (_("change fade in length"));
2011 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2013 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2019 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2020 XMLNode &before = alist->get_state();
2022 tmp->audio_region()->set_fade_in_length (fade_length);
2023 tmp->audio_region()->set_fade_in_active (true);
2025 XMLNode &after = alist->get_state();
2026 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2029 _editor->commit_reversible_command ();
2032 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2033 : RegionDrag (e, i, p, v)
2039 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2041 Drag::start_grab (event, cursor);
2043 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2044 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2046 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2047 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2051 FadeOutDrag::motion (GdkEvent* event, bool)
2053 nframes64_t fade_length;
2055 nframes64_t const pos = adjusted_current_frame (event);
2057 boost::shared_ptr<Region> region = _primary->region ();
2059 if (pos > (region->last_frame() - 64)) {
2060 fade_length = 64; // this should really be a minimum fade defined somewhere
2062 else if (pos < region->position()) {
2063 fade_length = region->length();
2066 fade_length = region->last_frame() - pos;
2069 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2071 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2077 tmp->reset_fade_out_shape_width (fade_length);
2080 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2084 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2086 if (!movement_occurred) {
2090 nframes64_t fade_length;
2092 nframes64_t const pos = adjusted_current_frame (event);
2094 boost::shared_ptr<Region> region = _primary->region ();
2096 if (pos > (region->last_frame() - 64)) {
2097 fade_length = 64; // this should really be a minimum fade defined somewhere
2099 else if (pos < region->position()) {
2100 fade_length = region->length();
2103 fade_length = region->last_frame() - pos;
2106 _editor->begin_reversible_command (_("change fade out length"));
2108 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2110 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2116 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2117 XMLNode &before = alist->get_state();
2119 tmp->audio_region()->set_fade_out_length (fade_length);
2120 tmp->audio_region()->set_fade_out_active (true);
2122 XMLNode &after = alist->get_state();
2123 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2126 _editor->commit_reversible_command ();
2129 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2132 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2135 _points.push_back (Gnome::Art::Point (0, 0));
2136 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2138 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2139 _line->property_width_pixels() = 1;
2140 _line->property_points () = _points;
2143 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2146 MarkerDrag::~MarkerDrag ()
2148 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2154 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2156 Drag::start_grab (event, cursor);
2160 Location *location = _editor->find_location_from_marker (_marker, is_start);
2161 _editor->_dragging_edit_point = true;
2163 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2165 update_item (location);
2167 // _drag_line->show();
2168 // _line->raise_to_top();
2171 _editor->show_verbose_time_cursor (location->start(), 10);
2173 _editor->show_verbose_time_cursor (location->end(), 10);
2176 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2179 case Selection::Toggle:
2180 _editor->selection->toggle (_marker);
2182 case Selection::Set:
2183 if (!_editor->selection->selected (_marker)) {
2184 _editor->selection->set (_marker);
2187 case Selection::Extend:
2189 Locations::LocationList ll;
2190 list<Marker*> to_add;
2192 _editor->selection->markers.range (s, e);
2193 s = min (_marker->position(), s);
2194 e = max (_marker->position(), e);
2197 if (e < max_frames) {
2200 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2201 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2202 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2205 to_add.push_back (lm->start);
2208 to_add.push_back (lm->end);
2212 if (!to_add.empty()) {
2213 _editor->selection->add (to_add);
2217 case Selection::Add:
2218 _editor->selection->add (_marker);
2222 /* set up copies for us to manipulate during the drag */
2224 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2225 Location *l = _editor->find_location_from_marker (*i, is_start);
2226 _copied_locations.push_back (new Location (*l));
2231 MarkerDrag::motion (GdkEvent* event, bool)
2233 nframes64_t f_delta = 0;
2235 bool move_both = false;
2237 Location *real_location;
2238 Location *copy_location = 0;
2240 nframes64_t const newframe = adjusted_current_frame (event);
2242 nframes64_t next = newframe;
2244 if (newframe == last_pointer_frame()) {
2248 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2252 MarkerSelection::iterator i;
2253 list<Location*>::iterator x;
2255 /* find the marker we're dragging, and compute the delta */
2257 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2258 x != _copied_locations.end() && i != _editor->selection->markers.end();
2264 if (marker == _marker) {
2266 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2271 if (real_location->is_mark()) {
2272 f_delta = newframe - copy_location->start();
2276 switch (marker->type()) {
2278 case Marker::LoopStart:
2279 case Marker::PunchIn:
2280 f_delta = newframe - copy_location->start();
2284 case Marker::LoopEnd:
2285 case Marker::PunchOut:
2286 f_delta = newframe - copy_location->end();
2289 /* what kind of marker is this ? */
2297 if (i == _editor->selection->markers.end()) {
2298 /* hmm, impossible - we didn't find the dragged marker */
2302 /* now move them all */
2304 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2305 x != _copied_locations.end() && i != _editor->selection->markers.end();
2311 /* call this to find out if its the start or end */
2313 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2317 if (real_location->locked()) {
2321 if (copy_location->is_mark()) {
2325 copy_location->set_start (copy_location->start() + f_delta);
2329 nframes64_t new_start = copy_location->start() + f_delta;
2330 nframes64_t new_end = copy_location->end() + f_delta;
2332 if (is_start) { // start-of-range marker
2335 copy_location->set_start (new_start);
2336 copy_location->set_end (new_end);
2337 } else if (new_start < copy_location->end()) {
2338 copy_location->set_start (new_start);
2340 _editor->snap_to (next, 1, true);
2341 copy_location->set_end (next);
2342 copy_location->set_start (newframe);
2345 } else { // end marker
2348 copy_location->set_end (new_end);
2349 copy_location->set_start (new_start);
2350 } else if (new_end > copy_location->start()) {
2351 copy_location->set_end (new_end);
2352 } else if (newframe > 0) {
2353 _editor->snap_to (next, -1, true);
2354 copy_location->set_start (next);
2355 copy_location->set_end (newframe);
2360 update_item (copy_location);
2362 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2365 lm->set_position (copy_location->start(), copy_location->end());
2369 assert (!_copied_locations.empty());
2371 _editor->show_verbose_time_cursor (newframe, 10);
2374 _editor->update_canvas_now ();
2379 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2381 if (!movement_occurred) {
2383 /* just a click, do nothing but finish
2384 off the selection process
2387 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2390 case Selection::Set:
2391 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2392 _editor->selection->set (_marker);
2396 case Selection::Toggle:
2397 case Selection::Extend:
2398 case Selection::Add:
2405 _editor->_dragging_edit_point = false;
2407 _editor->begin_reversible_command ( _("move marker") );
2408 XMLNode &before = _editor->session()->locations()->get_state();
2410 MarkerSelection::iterator i;
2411 list<Location*>::iterator x;
2414 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2415 x != _copied_locations.end() && i != _editor->selection->markers.end();
2418 Location * location = _editor->find_location_from_marker (*i, is_start);
2422 if (location->locked()) {
2426 if (location->is_mark()) {
2427 location->set_start ((*x)->start());
2429 location->set ((*x)->start(), (*x)->end());
2434 XMLNode &after = _editor->session()->locations()->get_state();
2435 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2436 _editor->commit_reversible_command ();
2442 MarkerDrag::update_item (Location* location)
2444 double const x1 = _editor->frame_to_pixel (location->start());
2446 _points.front().set_x(x1);
2447 _points.back().set_x(x1);
2448 _line->property_points() = _points;
2451 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2453 _cumulative_x_drag (0),
2454 _cumulative_y_drag (0)
2456 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2462 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2464 Drag::start_grab (event, _editor->fader_cursor);
2466 // start the grab at the center of the control point so
2467 // the point doesn't 'jump' to the mouse after the first drag
2468 _time_axis_view_grab_x = _point->get_x();
2469 _time_axis_view_grab_y = _point->get_y();
2470 nframes64_t grab_frame = _editor->pixel_to_frame (_time_axis_view_grab_x);
2472 float const fraction = 1 - (_point->get_y() / _point->line().height());
2474 _point->line().start_drag_single (_point, grab_frame, fraction);
2476 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2477 event->button.x + 10, event->button.y + 10);
2479 _editor->show_verbose_canvas_cursor ();
2483 ControlPointDrag::motion (GdkEvent* event, bool)
2485 double dx = current_pointer_x() - last_pointer_x();
2486 double dy = current_pointer_y() - last_pointer_y();
2488 if (event->button.state & Keyboard::SecondaryModifier) {
2493 /* coordinate in TimeAxisView's space */
2494 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2495 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2497 // calculate zero crossing point. back off by .01 to stay on the
2498 // positive side of zero
2499 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2501 // make sure we hit zero when passing through
2502 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2506 if (_x_constrained) {
2507 cx = _time_axis_view_grab_x;
2509 if (_y_constrained) {
2510 cy = _time_axis_view_grab_y;
2513 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2514 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2518 cy = min ((double) _point->line().height(), cy);
2520 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2522 if (!_x_constrained) {
2523 _editor->snap_to_with_modifier (cx_frames, event);
2526 float const fraction = 1.0 - (cy / _point->line().height());
2528 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2530 _point->line().drag_motion (cx_frames, fraction, push);
2532 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2536 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2538 if (!movement_occurred) {
2542 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2543 _editor->reset_point_selection ();
2547 motion (event, false);
2549 _point->line().end_drag ();
2553 ControlPointDrag::active (Editing::MouseMode m)
2555 if (m == Editing::MouseGain) {
2556 /* always active in mouse gain */
2560 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2561 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2564 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2567 _cumulative_y_drag (0)
2572 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2574 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2577 _item = &_line->grab_item ();
2579 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2580 origin, and ditto for y.
2583 double cx = event->button.x;
2584 double cy = event->button.y;
2586 _line->parent_group().w2i (cx, cy);
2588 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2593 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2594 /* no adjacent points */
2598 Drag::start_grab (event, _editor->fader_cursor);
2600 /* store grab start in parent frame */
2602 _time_axis_view_grab_x = cx;
2603 _time_axis_view_grab_y = cy;
2605 double fraction = 1.0 - (cy / _line->height());
2607 _line->start_drag_line (before, after, fraction);
2609 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2610 event->button.x + 10, event->button.y + 10);
2612 _editor->show_verbose_canvas_cursor ();
2616 LineDrag::motion (GdkEvent* event, bool)
2618 double dy = current_pointer_y() - last_pointer_y();
2620 if (event->button.state & Keyboard::SecondaryModifier) {
2624 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2626 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2629 cy = min ((double) _line->height(), cy);
2631 double const fraction = 1.0 - (cy / _line->height());
2635 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2641 /* we are ignoring x position for this drag, so we can just pass in 0 */
2642 _line->drag_motion (0, fraction, push);
2644 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2648 LineDrag::finished (GdkEvent* event, bool)
2650 motion (event, false);
2655 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2657 Drag::start_grab (event);
2658 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2662 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2669 /* use a bigger drag threshold than the default */
2671 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2673 if (abs ((int) (pf - grab_frame())) < 8) {
2677 nframes64_t grab = grab_frame ();
2678 if (Config->get_rubberbanding_snaps_to_grid ()) {
2679 _editor->snap_to_with_modifier (grab, event);
2682 /* base start and end on initial click position */
2692 if (current_pointer_y() < grab_y()) {
2693 y1 = current_pointer_y();
2696 y2 = current_pointer_y();
2701 if (start != end || y1 != y2) {
2703 double x1 = _editor->frame_to_pixel (start);
2704 double x2 = _editor->frame_to_pixel (end);
2706 _editor->rubberband_rect->property_x1() = x1;
2707 _editor->rubberband_rect->property_y1() = y1;
2708 _editor->rubberband_rect->property_x2() = x2;
2709 _editor->rubberband_rect->property_y2() = y2;
2711 _editor->rubberband_rect->show();
2712 _editor->rubberband_rect->raise_to_top();
2714 _editor->show_verbose_time_cursor (pf, 10);
2719 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2721 if (movement_occurred) {
2723 motion (event, false);
2726 if (current_pointer_y() < grab_y()) {
2727 y1 = current_pointer_y();
2730 y2 = current_pointer_y();
2735 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2738 _editor->begin_reversible_command (_("rubberband selection"));
2740 if (grab_frame() < last_pointer_frame()) {
2741 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
2743 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
2747 _editor->commit_reversible_command ();
2751 if (!getenv("ARDOUR_SAE")) {
2752 _editor->selection->clear_tracks();
2754 _editor->selection->clear_regions();
2755 _editor->selection->clear_points ();
2756 _editor->selection->clear_lines ();
2759 _editor->rubberband_rect->hide();
2763 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2765 Drag::start_grab (event);
2767 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2771 TimeFXDrag::motion (GdkEvent* event, bool)
2773 RegionView* rv = _primary;
2775 nframes64_t const pf = adjusted_current_frame (event);
2777 if (pf == last_pointer_frame()) {
2781 if (pf > rv->region()->position()) {
2782 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
2785 _editor->show_verbose_time_cursor (pf, 10);
2789 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2791 _primary->get_time_axis_view().hide_timestretch ();
2793 if (!movement_occurred) {
2797 if (last_pointer_frame() < _primary->region()->position()) {
2798 /* backwards drag of the left edge - not usable */
2802 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
2804 float percentage = (double) newlen / (double) _primary->region()->length();
2806 #ifndef USE_RUBBERBAND
2807 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2808 if (_primary->region()->data_type() == DataType::AUDIO) {
2809 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2813 _editor->begin_reversible_command (_("timestretch"));
2815 // XXX how do timeFX on multiple regions ?
2820 if (!_editor->time_stretch (rs, percentage) == 0) {
2821 error << _("An error occurred while executing time stretch operation") << endmsg;
2826 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2828 Drag::start_grab (event);
2832 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2838 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2840 if (movement_occurred && _editor->session()) {
2841 /* make sure we stop */
2842 _editor->session()->request_transport_speed (0.0);
2846 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2850 , _original_pointer_time_axis (-1)
2851 , _last_pointer_time_axis (-1)
2857 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2859 nframes64_t start = 0;
2860 nframes64_t end = 0;
2862 if (_editor->session() == 0) {
2866 Gdk::Cursor* cursor = 0;
2868 switch (_operation) {
2869 case CreateSelection:
2870 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2875 cursor = _editor->selector_cursor;
2876 Drag::start_grab (event, cursor);
2879 case SelectionStartTrim:
2880 if (_editor->clicked_axisview) {
2881 _editor->clicked_axisview->order_selection_trims (_item, true);
2883 Drag::start_grab (event, _editor->trimmer_cursor);
2884 start = _editor->selection->time[_editor->clicked_selection].start;
2885 _pointer_frame_offset = grab_frame() - start;
2888 case SelectionEndTrim:
2889 if (_editor->clicked_axisview) {
2890 _editor->clicked_axisview->order_selection_trims (_item, false);
2892 Drag::start_grab (event, _editor->trimmer_cursor);
2893 end = _editor->selection->time[_editor->clicked_selection].end;
2894 _pointer_frame_offset = grab_frame() - end;
2898 start = _editor->selection->time[_editor->clicked_selection].start;
2899 Drag::start_grab (event, cursor);
2900 _pointer_frame_offset = grab_frame() - start;
2904 if (_operation == SelectionMove) {
2905 _editor->show_verbose_time_cursor (start, 10);
2907 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2910 _original_pointer_time_axis = _editor->trackview_by_y_position (current_pointer_y ()).first->order ();
2914 SelectionDrag::motion (GdkEvent* event, bool first_move)
2916 nframes64_t start = 0;
2917 nframes64_t end = 0;
2920 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (current_pointer_y ());
2921 if (pending_time_axis.first == 0) {
2925 nframes64_t const pending_position = adjusted_current_frame (event);
2927 /* only alter selection if things have changed */
2929 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
2933 switch (_operation) {
2934 case CreateSelection:
2936 nframes64_t grab = grab_frame ();
2939 _editor->snap_to (grab);
2942 if (pending_position < grab_frame()) {
2943 start = pending_position;
2946 end = pending_position;
2950 /* first drag: Either add to the selection
2951 or create a new selection
2956 _editor->begin_reversible_command (_("range selection"));
2957 _have_transaction = true;
2960 /* adding to the selection */
2961 _editor->selection->add (_editor->clicked_axisview);
2962 _editor->clicked_selection = _editor->selection->add (start, end);
2967 if (!_editor->selection->selected (_editor->clicked_axisview)) {
2968 _editor->selection->set (_editor->clicked_axisview);
2971 _editor->clicked_selection = _editor->selection->set (start, end);
2975 /* select the track that we're in */
2976 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
2977 _editor->selection->add (pending_time_axis.first);
2978 _added_time_axes.push_back (pending_time_axis.first);
2981 /* deselect any tracks that this drag no longer includes, being careful to only deselect
2982 tracks that we selected in the first place.
2985 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
2986 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
2988 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
2989 while (i != _added_time_axes.end()) {
2991 list<TimeAxisView*>::iterator tmp = i;
2994 if ((*i)->order() < min_order || (*i)->order() > max_order) {
2995 _editor->selection->remove (*i);
2996 _added_time_axes.remove (*i);
3005 case SelectionStartTrim:
3008 _editor->begin_reversible_command (_("trim selection start"));
3009 _have_transaction = true;
3012 start = _editor->selection->time[_editor->clicked_selection].start;
3013 end = _editor->selection->time[_editor->clicked_selection].end;
3015 if (pending_position > end) {
3018 start = pending_position;
3022 case SelectionEndTrim:
3025 _editor->begin_reversible_command (_("trim selection end"));
3026 _have_transaction = true;
3029 start = _editor->selection->time[_editor->clicked_selection].start;
3030 end = _editor->selection->time[_editor->clicked_selection].end;
3032 if (pending_position < start) {
3035 end = pending_position;
3043 _editor->begin_reversible_command (_("move selection"));
3044 _have_transaction = true;
3047 start = _editor->selection->time[_editor->clicked_selection].start;
3048 end = _editor->selection->time[_editor->clicked_selection].end;
3050 length = end - start;
3052 start = pending_position;
3053 _editor->snap_to (start);
3055 end = start + length;
3060 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3061 _editor->start_canvas_autoscroll (1, 0);
3065 _editor->selection->replace (_editor->clicked_selection, start, end);
3068 if (_operation == SelectionMove) {
3069 _editor->show_verbose_time_cursor(start, 10);
3071 _editor->show_verbose_time_cursor(pending_position, 10);
3076 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3078 Session* s = _editor->session();
3080 if (movement_occurred) {
3081 motion (event, false);
3082 /* XXX this is not object-oriented programming at all. ick */
3083 if (_editor->selection->time.consolidate()) {
3084 _editor->selection->TimeChanged ();
3087 if (_have_transaction) {
3088 _editor->commit_reversible_command ();
3091 /* XXX what if its a music time selection? */
3092 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3093 s->request_play_range (&_editor->selection->time, true);
3098 /* just a click, no pointer movement.*/
3100 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3101 _editor->selection->clear_time();
3104 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3105 _editor->selection->set (_editor->clicked_axisview);
3108 if (s && s->get_play_range () && s->transport_rolling()) {
3109 s->request_stop (false, false);
3114 _editor->stop_canvas_autoscroll ();
3117 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3122 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3123 _drag_rect->hide ();
3125 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3126 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3130 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3132 if (_editor->session() == 0) {
3136 Gdk::Cursor* cursor = 0;
3138 if (!_editor->temp_location) {
3139 _editor->temp_location = new Location;
3142 switch (_operation) {
3143 case CreateRangeMarker:
3144 case CreateTransportMarker:
3145 case CreateCDMarker:
3147 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3152 cursor = _editor->selector_cursor;
3156 Drag::start_grab (event, cursor);
3158 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3162 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3164 nframes64_t start = 0;
3165 nframes64_t end = 0;
3166 ArdourCanvas::SimpleRect *crect;
3168 switch (_operation) {
3169 case CreateRangeMarker:
3170 crect = _editor->range_bar_drag_rect;
3172 case CreateTransportMarker:
3173 crect = _editor->transport_bar_drag_rect;
3175 case CreateCDMarker:
3176 crect = _editor->cd_marker_bar_drag_rect;
3179 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3184 nframes64_t const pf = adjusted_current_frame (event);
3186 /* only alter selection if the current frame is
3187 different from the last frame position.
3190 if (pf == last_pointer_frame()) {
3194 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3195 nframes64_t grab = grab_frame ();
3196 _editor->snap_to (grab);
3198 if (pf < grab_frame()) {
3206 /* first drag: Either add to the selection
3207 or create a new selection.
3212 _editor->temp_location->set (start, end);
3216 update_item (_editor->temp_location);
3218 //_drag_rect->raise_to_top();
3223 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3224 _editor->start_canvas_autoscroll (1, 0);
3228 _editor->temp_location->set (start, end);
3230 double x1 = _editor->frame_to_pixel (start);
3231 double x2 = _editor->frame_to_pixel (end);
3232 crect->property_x1() = x1;
3233 crect->property_x2() = x2;
3235 update_item (_editor->temp_location);
3238 _editor->show_verbose_time_cursor (pf, 10);
3243 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3245 Location * newloc = 0;
3249 if (movement_occurred) {
3250 motion (event, false);
3253 switch (_operation) {
3254 case CreateRangeMarker:
3255 case CreateCDMarker:
3257 _editor->begin_reversible_command (_("new range marker"));
3258 XMLNode &before = _editor->session()->locations()->get_state();
3259 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3260 if (_operation == CreateCDMarker) {
3261 flags = Location::IsRangeMarker | Location::IsCDMarker;
3262 _editor->cd_marker_bar_drag_rect->hide();
3265 flags = Location::IsRangeMarker;
3266 _editor->range_bar_drag_rect->hide();
3268 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3269 _editor->session()->locations()->add (newloc, true);
3270 XMLNode &after = _editor->session()->locations()->get_state();
3271 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3272 _editor->commit_reversible_command ();
3276 case CreateTransportMarker:
3277 // popup menu to pick loop or punch
3278 _editor->new_transport_marker_context_menu (&event->button, _item);
3282 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3284 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3289 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3291 if (end == max_frames) {
3292 end = _editor->session()->current_end_frame ();
3295 if (start == max_frames) {
3296 start = _editor->session()->current_start_frame ();
3299 switch (_editor->mouse_mode) {
3301 /* find the two markers on either side and then make the selection from it */
3302 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3306 /* find the two markers on either side of the click and make the range out of it */
3307 _editor->selection->set (start, end);
3316 _editor->stop_canvas_autoscroll ();
3322 RangeMarkerBarDrag::update_item (Location* location)
3324 double const x1 = _editor->frame_to_pixel (location->start());
3325 double const x2 = _editor->frame_to_pixel (location->end());
3327 _drag_rect->property_x1() = x1;
3328 _drag_rect->property_x2() = x2;
3332 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3334 Drag::start_grab (event, _editor->zoom_cursor);
3335 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3339 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3344 nframes64_t const pf = adjusted_current_frame (event);
3346 if (pf == last_pointer_frame()) {
3350 nframes64_t grab = grab_frame ();
3351 _editor->snap_to_with_modifier (grab, event);
3353 /* base start and end on initial click position */
3365 _editor->zoom_rect->show();
3366 _editor->zoom_rect->raise_to_top();
3369 _editor->reposition_zoom_rect(start, end);
3371 _editor->show_verbose_time_cursor (pf, 10);
3376 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3378 if (movement_occurred) {
3379 motion (event, false);
3381 if (grab_frame() < last_pointer_frame()) {
3382 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3384 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3387 _editor->temporal_zoom_to_frame (false, grab_frame());
3389 temporal_zoom_step (false);
3390 center_screen (grab_frame());
3394 _editor->zoom_rect->hide();
3397 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3400 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3401 region = &cnote->region_view();
3405 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3407 Drag::start_grab (event);
3410 drag_delta_note = 0;
3415 event_x = current_pointer_x();
3416 event_y = current_pointer_y();
3418 _item->property_parent().get_value()->w2i(event_x, event_y);
3420 last_x = region->snap_to_pixel(event_x);
3423 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3425 if (!(was_selected = cnote->selected())) {
3427 /* tertiary-click means extend selection - we'll do that on button release,
3428 so don't add it here, because otherwise we make it hard to figure
3429 out the "extend-to" range.
3432 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3435 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3438 region->note_selected (cnote, true);
3440 region->unique_select (cnote);
3447 NoteDrag::motion (GdkEvent*, bool)
3449 MidiStreamView* streamview = region->midi_stream_view();
3453 event_x = current_pointer_x();
3454 event_y = current_pointer_y();
3456 _item->property_parent().get_value()->w2i(event_x, event_y);
3458 event_x = region->snap_to_pixel(event_x);
3460 double dx = event_x - last_x;
3461 double dy = event_y - last_y;
3466 // Snap to note rows
3468 if (abs (dy) < streamview->note_height()) {
3471 int8_t this_delta_note;
3473 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3475 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3477 drag_delta_note -= this_delta_note;
3478 dy = streamview->note_height() * this_delta_note;
3479 last_y = last_y + dy;
3483 region->move_selection (dx, dy);
3485 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3487 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3488 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3489 _editor->show_verbose_canvas_cursor_with (buf);
3494 NoteDrag::finished (GdkEvent* ev, bool moved)
3496 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3499 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3502 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3504 region->note_deselected (cnote);
3507 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3508 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3510 if (!extend && !add && region->selection_size() > 1) {
3511 region->unique_select(cnote);
3512 } else if (extend) {
3513 region->note_selected (cnote, true, true);
3515 /* it was added during button press */
3520 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3524 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3527 , _nothing_to_drag (false)
3529 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3532 _line = _atav->line ();
3536 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3538 Drag::start_grab (event, cursor);
3540 list<ControlPoint*> points;
3542 XMLNode* state = &_line->get_state ();
3544 if (_ranges.empty()) {
3546 uint32_t const N = _line->npoints ();
3547 for (uint32_t i = 0; i < N; ++i) {
3548 points.push_back (_line->nth (i));
3553 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3554 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3556 /* fade into and out of the region that we're dragging;
3557 64 samples length plucked out of thin air.
3559 nframes64_t const h = (j->start + j->end) / 2;
3560 nframes64_t a = j->start + 64;
3564 nframes64_t b = j->end - 64;
3569 the_list->add (j->start, the_list->eval (j->start));
3570 _line->add_always_in_view (j->start);
3571 the_list->add (a, the_list->eval (a));
3572 _line->add_always_in_view (a);
3573 the_list->add (b, the_list->eval (b));
3574 _line->add_always_in_view (b);
3575 the_list->add (j->end, the_list->eval (j->end));
3576 _line->add_always_in_view (j->end);
3579 uint32_t const N = _line->npoints ();
3580 for (uint32_t i = 0; i < N; ++i) {
3582 ControlPoint* p = _line->nth (i);
3584 list<AudioRange>::const_iterator j = _ranges.begin ();
3585 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3589 if (j != _ranges.end()) {
3590 points.push_back (p);
3595 if (points.empty()) {
3596 _nothing_to_drag = true;
3600 _line->start_drag_multiple (points, 1 - (current_pointer_y() / _line->height ()), state);
3604 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3606 if (_nothing_to_drag) {
3610 float const f = 1 - (current_pointer_y() / _line->height());
3612 /* we are ignoring x position for this drag, so we can just pass in 0 */
3613 _line->drag_motion (0, f, false);
3617 AutomationRangeDrag::finished (GdkEvent* event, bool)
3619 if (_nothing_to_drag) {
3623 motion (event, false);
3625 _line->clear_always_in_view ();