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/dB.h"
24 #include "ardour/region_factory.h"
25 #include "ardour/midi_diskstream.h"
29 #include "audio_region_view.h"
30 #include "midi_region_view.h"
31 #include "ardour_ui.h"
32 #include "control_point.h"
34 #include "region_gain_line.h"
35 #include "editor_drag.h"
36 #include "audio_time_axis.h"
37 #include "midi_time_axis.h"
38 #include "canvas-note.h"
39 #include "selection.h"
40 #include "midi_selection.h"
43 using namespace ARDOUR;
47 using namespace Editing;
48 using namespace ArdourCanvas;
50 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
52 Drag::Drag (Editor* e, ArdourCanvas::Item* i) :
55 _pointer_frame_offset (0),
57 _last_pointer_frame (0),
58 _current_pointer_frame (0),
59 _had_movement (false),
60 _move_threshold_passed (false)
66 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
72 cursor = _editor->which_grabber_cursor ();
75 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
79 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
82 cursor = _editor->which_grabber_cursor ();
85 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
87 if (Keyboard::is_button2_event (&event->button)) {
88 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
89 _y_constrained = true;
90 _x_constrained = false;
92 _y_constrained = false;
93 _x_constrained = true;
96 _x_constrained = false;
97 _y_constrained = false;
100 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
101 _last_pointer_frame = _grab_frame;
102 _current_pointer_frame = _grab_frame;
103 _current_pointer_x = _grab_x;
104 _current_pointer_y = _grab_y;
105 _last_pointer_x = _current_pointer_x;
106 _last_pointer_y = _current_pointer_y;
110 _item->i2w (_original_x, _original_y);
112 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
116 if (_editor->session && _editor->session->transport_rolling()) {
119 _was_rolling = false;
122 switch (_editor->snap_type()) {
123 case SnapToRegionStart:
124 case SnapToRegionEnd:
125 case SnapToRegionSync:
126 case SnapToRegionBoundary:
127 _editor->build_region_boundary_cache ();
134 /** @param event GDK event, or 0.
135 * @return true if some movement occurred, otherwise false.
138 Drag::end_grab (GdkEvent* event)
142 _editor->stop_canvas_autoscroll ();
144 _item->ungrab (event ? event->button.time : 0);
146 _last_pointer_x = _current_pointer_x;
147 _last_pointer_y = _current_pointer_y;
148 finished (event, _had_movement);
150 _editor->hide_verbose_canvas_cursor();
154 return _had_movement;
158 Drag::adjusted_current_frame (GdkEvent* event) const
162 if (_current_pointer_frame > _pointer_frame_offset) {
163 pos = _current_pointer_frame - _pointer_frame_offset;
166 _editor->snap_to_with_modifier (pos, event);
172 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
174 _last_pointer_x = _current_pointer_x;
175 _last_pointer_y = _current_pointer_y;
176 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
178 if (!from_autoscroll && !_move_threshold_passed) {
180 bool const xp = (::llabs ((nframes64_t) (_current_pointer_x - _grab_x)) > 4LL);
181 bool const yp = (::llabs ((nframes64_t) (_current_pointer_y - _grab_y)) > 4LL);
183 _move_threshold_passed = (xp || yp);
185 if (apply_move_threshold() && _move_threshold_passed) {
187 _grab_frame = _current_pointer_frame;
188 _grab_x = _current_pointer_x;
189 _grab_y = _current_pointer_y;
190 _last_pointer_frame = _grab_frame;
191 _pointer_frame_offset = _grab_frame - _last_frame_position;
196 bool old_had_movement = _had_movement;
198 /* a motion event has happened, so we've had movement... */
199 _had_movement = true;
201 /* ... unless we're using a move threshold and we've not yet passed it */
202 if (apply_move_threshold() && !_move_threshold_passed) {
203 _had_movement = false;
206 if (active (_editor->mouse_mode)) {
208 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
209 if (!from_autoscroll) {
210 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
213 motion (event, _had_movement != old_had_movement);
225 _editor->stop_canvas_autoscroll ();
226 _editor->hide_verbose_canvas_cursor ();
231 /* put it back where it came from */
236 _item->i2w (cxw, cyw);
237 _item->move (_original_x - cxw, _original_y - cyw);
242 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
247 RegionView::RegionViewGoingAway.connect (mem_fun (*this, &RegionDrag::region_going_away));
251 RegionDrag::region_going_away (RegionView* v)
256 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
257 : RegionDrag (e, i, p, v),
267 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
269 Drag::start_grab (event);
271 _editor->show_verbose_time_cursor (_last_frame_position, 10);
274 RegionMotionDrag::TimeAxisViewSummary
275 RegionMotionDrag::get_time_axis_view_summary ()
277 int32_t children = 0;
278 TimeAxisViewSummary sum;
280 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
282 /* get a bitmask representing the visible tracks */
284 for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
285 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
286 TimeAxisView::Children children_list;
288 /* zeroes are audio/MIDI tracks. ones are other types. */
290 if (!rtv->hidden()) {
292 if (!rtv->is_track()) {
293 /* not an audio nor MIDI track */
294 sum.tracks = sum.tracks |= (0x01 << rtv->order());
297 sum.height_list[rtv->order()] = (*i)->current_height();
300 if ((children_list = rtv->get_child_list()).size() > 0) {
301 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
302 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
303 sum.height_list[rtv->order() + children] = (*j)->current_height();
314 RegionMotionDrag::compute_y_delta (
315 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
316 int32_t last_pointer_layer, int32_t current_pointer_layer,
317 TimeAxisViewSummary const & tavs,
318 int32_t* pointer_order_span, int32_t* pointer_layer_span,
319 int32_t* canvas_pointer_order_span
323 *pointer_order_span = 0;
324 *pointer_layer_span = 0;
328 bool clamp_y_axis = false;
330 /* the change in track order between this callback and the last */
331 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
332 /* the change in layer between this callback and the last;
333 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
334 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
336 if (*pointer_order_span != 0) {
338 /* find the actual pointer span, in terms of the number of visible tracks;
339 to do this, we reduce |pointer_order_span| by the number of hidden tracks
342 *canvas_pointer_order_span = *pointer_order_span;
343 if (last_pointer_view->order() >= current_pointer_view->order()) {
344 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
345 if (tavs.height_list[y] == 0) {
346 *canvas_pointer_order_span--;
350 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
351 if (tavs.height_list[y] == 0) {
352 *canvas_pointer_order_span++;
357 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
359 RegionView* rv = (*i);
361 if (rv->region()->locked()) {
365 double ix1, ix2, iy1, iy2;
366 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
367 rv->get_canvas_frame()->i2w (ix1, iy1);
368 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
370 /* get the new trackview for this particular region */
371 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
373 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
375 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
376 as surely this is a per-region thing... */
378 clamp_y_axis = y_movement_disallowed (
379 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
387 } else if (_dest_trackview == current_pointer_view) {
389 if (current_pointer_layer == last_pointer_layer) {
390 /* No movement; clamp */
396 _dest_trackview = current_pointer_view;
397 _dest_layer = current_pointer_layer;
405 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
407 *pending_region_position = 0;
409 /* compute the amount of pointer motion in frames, and where
410 the region would be if we moved it by that much.
412 if (_current_pointer_frame >= _pointer_frame_offset) {
414 nframes64_t sync_frame;
415 nframes64_t sync_offset;
418 *pending_region_position = _current_pointer_frame - _pointer_frame_offset;
420 sync_offset = _primary->region()->sync_offset (sync_dir);
422 /* we don't handle a sync point that lies before zero.
424 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
426 sync_frame = *pending_region_position + (sync_dir*sync_offset);
428 _editor->snap_to_with_modifier (sync_frame, event);
430 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
433 *pending_region_position = _last_frame_position;
438 if (*pending_region_position > max_frames - _primary->region()->length()) {
439 *pending_region_position = _last_frame_position;
444 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
446 /* now compute the canvas unit distance we need to move the regionview
447 to make it appear at the new location.
450 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
452 if (*pending_region_position <= _last_frame_position) {
454 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
456 RegionView* rv = (*i);
458 // If any regionview is at zero, we need to know so we can stop further leftward motion.
460 double ix1, ix2, iy1, iy2;
461 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
462 rv->get_canvas_frame()->i2w (ix1, iy1);
464 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
466 *pending_region_position = _last_frame_position;
473 _last_frame_position = *pending_region_position;
480 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
484 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
486 vector<int32_t>::iterator j;
488 /* *pointer* variables reflect things about the pointer; as we may be moving
489 multiple regions, much detail must be computed per-region */
491 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
492 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
493 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
494 is always 0 regardless of what the region's "real" layer is */
495 RouteTimeAxisView* current_pointer_view;
496 layer_t current_pointer_layer;
497 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
501 /* TimeAxisView that we were pointing at last time we entered this method */
502 TimeAxisView const * const last_pointer_view = _dest_trackview;
503 /* the order of the track that we were pointing at last time we entered this method */
504 int32_t const last_pointer_order = last_pointer_view->order ();
505 /* the layer that we were pointing at last time we entered this method */
506 layer_t const last_pointer_layer = _dest_layer;
508 int32_t pointer_order_span;
509 int32_t pointer_layer_span;
510 int32_t canvas_pointer_order_span;
512 bool const clamp_y_axis = compute_y_delta (
513 last_pointer_view, current_pointer_view,
514 last_pointer_layer, current_pointer_layer, tavs,
515 &pointer_order_span, &pointer_layer_span,
516 &canvas_pointer_order_span
519 nframes64_t pending_region_position;
520 double const x_delta = compute_x_delta (event, &pending_region_position);
522 /*************************************************************
524 ************************************************************/
526 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0) {
527 /* haven't reached next snap point, and we're not switching
528 trackviews nor layers. nothing to do.
533 /*************************************************************
535 ************************************************************/
537 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
539 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
541 RegionView* rv = (*i);
543 if (rv->region()->locked()) {
547 /* here we are calculating the y distance from the
548 top of the first track view to the top of the region
549 area of the track view that we're working on */
551 /* this x value is just a dummy value so that we have something
556 /* distance from the top of this track view to the region area
557 of our track view is always 1 */
561 /* convert to world coordinates, ie distance from the top of
564 rv->get_canvas_frame()->i2w (ix1, iy1);
566 /* compensate for the ruler section and the vertical scrollbar position */
567 iy1 += _editor->get_trackview_group_vertical_offset ();
571 // hide any dependent views
573 rv->get_time_axis_view().hide_dependent_views (*rv);
576 reparent to a non scrolling group so that we can keep the
577 region selection above all time axis views.
578 reparenting means we have to move the rv as the two
579 parent groups have different coordinates.
582 rv->get_canvas_group()->property_y() = iy1 - 1;
583 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
585 rv->fake_set_opaque (true);
588 /* current view for this particular region */
589 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
590 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
592 if (pointer_order_span != 0 && !clamp_y_axis) {
594 /* INTER-TRACK MOVEMENT */
596 /* move through the height list to the track that the region is currently on */
597 vector<int32_t>::iterator j = tavs.height_list.begin ();
599 while (j != tavs.height_list.end () && x != rtv->order ()) {
605 int32_t temp_pointer_order_span = canvas_pointer_order_span;
607 if (j != tavs.height_list.end ()) {
609 /* Account for layers in the original and
610 destination tracks. If we're moving around in layers we assume
611 that only one track is involved, so it's ok to use *pointer*
614 StreamView* lv = last_pointer_view->view ();
617 /* move to the top of the last trackview */
618 if (lv->layer_display () == Stacked) {
619 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
622 StreamView* cv = current_pointer_view->view ();
625 /* move to the right layer on the current trackview */
626 if (cv->layer_display () == Stacked) {
627 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
630 /* And for being on a non-topmost layer on the new
633 while (temp_pointer_order_span > 0) {
634 /* we're moving up canvas-wise,
635 so we need to find the next track height
637 if (j != tavs.height_list.begin()) {
641 if (x != last_pointer_order) {
643 ++temp_pointer_order_span;
648 temp_pointer_order_span--;
651 while (temp_pointer_order_span < 0) {
655 if (x != last_pointer_order) {
657 --temp_pointer_order_span;
661 if (j != tavs.height_list.end()) {
665 temp_pointer_order_span++;
669 /* find out where we'll be when we move and set height accordingly */
671 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
672 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
673 rv->set_height (temp_rtv->view()->child_height());
675 /* if you un-comment the following, the region colours will follow
676 the track colours whilst dragging; personally
677 i think this can confuse things, but never mind.
680 //const GdkColor& col (temp_rtv->view->get_region_color());
681 //rv->set_color (const_cast<GdkColor&>(col));
685 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
687 /* INTER-LAYER MOVEMENT in the same track */
688 y_delta = rtv->view()->child_height () * pointer_layer_span;
693 _editor->mouse_brush_insert_region (rv, pending_region_position);
695 rv->move (x_delta, y_delta);
698 } /* foreach region */
701 _editor->cursor_group->raise_to_top();
704 if (x_delta != 0 && !_brushing) {
705 _editor->show_verbose_time_cursor (_last_frame_position, 10);
710 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
712 if (_copy && first_move) {
713 copy_regions (event);
716 RegionMotionDrag::motion (event, first_move);
720 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
722 vector<RegionView*> copies;
723 boost::shared_ptr<Diskstream> ds;
724 boost::shared_ptr<Playlist> from_playlist;
725 RegionSelection new_views;
726 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
727 PlaylistSet modified_playlists;
728 PlaylistSet frozen_playlists;
729 list <sigc::connection> modified_playlist_connections;
730 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
731 nframes64_t drag_delta;
732 bool changed_tracks, changed_position;
733 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
734 RouteTimeAxisView* source_tv;
736 if (!movement_occurred) {
741 if (Config->get_edit_mode() == Splice && !_editor->pre_drag_region_selection.empty()) {
742 _editor->selection->set (_editor->pre_drag_region_selection);
743 _editor->pre_drag_region_selection.clear ();
747 /* all changes were made during motion event handlers */
750 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
751 copies.push_back (*i);
758 /* reverse this here so that we have the correct logic to finalize
762 if (Config->get_edit_mode() == Lock) {
763 _x_constrained = !_x_constrained;
767 if (_x_constrained) {
768 _editor->begin_reversible_command (_("fixed time region copy"));
770 _editor->begin_reversible_command (_("region copy"));
773 if (_x_constrained) {
774 _editor->begin_reversible_command (_("fixed time region drag"));
776 _editor->begin_reversible_command (_("region drag"));
780 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
781 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
783 drag_delta = _primary->region()->position() - _last_frame_position;
785 _editor->update_canvas_now ();
787 /* make a list of where each region ended up */
788 final = find_time_axis_views_and_layers ();
790 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
792 RegionView* rv = (*i);
793 RouteTimeAxisView* dest_rtv = final[*i].first;
794 layer_t dest_layer = final[*i].second;
798 if (rv->region()->locked()) {
803 if (changed_position && !_x_constrained) {
804 where = rv->region()->position() - drag_delta;
806 where = rv->region()->position();
809 boost::shared_ptr<Region> new_region;
812 /* we already made a copy */
813 new_region = rv->region();
815 /* undo the previous hide_dependent_views so that xfades don't
816 disappear on copying regions
819 //rv->get_time_axis_view().reveal_dependent_views (*rv);
821 } else if (changed_tracks && dest_rtv->playlist()) {
822 new_region = RegionFactory::create (rv->region());
825 if (changed_tracks || _copy) {
827 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
834 _editor->latest_regionviews.clear ();
836 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
838 insert_result = modified_playlists.insert (to_playlist);
840 if (insert_result.second) {
841 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
844 to_playlist->add_region (new_region, where);
845 if (dest_rtv->view()->layer_display() == Stacked) {
846 new_region->set_layer (dest_layer);
847 new_region->set_pending_explicit_relayer (true);
852 if (!_editor->latest_regionviews.empty()) {
853 // XXX why just the first one ? we only expect one
854 // commented out in nick_m's canvas reworking. is that intended?
855 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
856 new_views.push_back (_editor->latest_regionviews.front());
861 motion on the same track. plonk the previously reparented region
862 back to its original canvas group (its streamview).
863 No need to do anything for copies as they are fake regions which will be deleted.
866 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
867 rv->get_canvas_group()->property_y() = 0;
869 /* just change the model */
871 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
873 if (dest_rtv->view()->layer_display() == Stacked) {
874 rv->region()->set_layer (dest_layer);
875 rv->region()->set_pending_explicit_relayer (true);
878 insert_result = modified_playlists.insert (playlist);
880 if (insert_result.second) {
881 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
883 /* freeze to avoid lots of relayering in the case of a multi-region drag */
884 frozen_insert_result = frozen_playlists.insert(playlist);
886 if (frozen_insert_result.second) {
890 rv->region()->set_position (where, (void*) this);
893 if (changed_tracks && !_copy) {
895 /* get the playlist where this drag started. we can't use rv->region()->playlist()
896 because we may have copied the region and it has not been attached to a playlist.
899 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
900 ds = source_tv->get_diskstream();
901 from_playlist = ds->playlist();
905 assert (from_playlist);
907 /* moved to a different audio track, without copying */
909 /* the region that used to be in the old playlist is not
910 moved to the new one - we use a copy of it. as a result,
911 any existing editor for the region should no longer be
915 rv->hide_region_editor();
916 rv->fake_set_opaque (false);
918 /* remove the region from the old playlist */
920 insert_result = modified_playlists.insert (from_playlist);
922 if (insert_result.second) {
923 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
926 from_playlist->remove_region (rv->region());
928 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
929 was selected in all of them, then removing it from a playlist will have removed all
930 trace of it from the selection (i.e. there were N regions selected, we removed 1,
931 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
932 corresponding regionview, and the selection is now empty).
934 this could have invalidated any and all iterators into the region selection.
936 the heuristic we use here is: if the region selection is empty, break out of the loop
937 here. if the region selection is not empty, then restart the loop because we know that
938 we must have removed at least the region(view) we've just been working on as well as any
939 that we processed on previous iterations.
941 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
945 if (_views.empty()) {
956 copies.push_back (rv);
960 _editor->selection->add (new_views);
962 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
967 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
968 _editor->session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
971 _editor->commit_reversible_command ();
973 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
980 RegionMotionDrag::x_move_allowed () const
982 if (Config->get_edit_mode() == Lock) {
983 /* in locked edit mode, reverse the usual meaning of _x_constrained */
984 return _x_constrained;
987 return !_x_constrained;
991 RegionMotionDrag::copy_regions (GdkEvent* event)
993 /* duplicate the regionview(s) and region(s) */
995 list<RegionView*> new_regionviews;
997 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
999 RegionView* rv = (*i);
1000 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1001 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1003 const boost::shared_ptr<const Region> original = rv->region();
1004 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1008 boost::shared_ptr<AudioRegion> audioregion_copy
1009 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1010 nrv = new AudioRegionView (*arv, audioregion_copy);
1012 boost::shared_ptr<MidiRegion> midiregion_copy
1013 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1014 nrv = new MidiRegionView (*mrv, midiregion_copy);
1019 nrv->get_canvas_group()->show ();
1020 new_regionviews.push_back (nrv);
1023 if (new_regionviews.empty()) {
1027 /* reflect the fact that we are dragging the copies */
1029 _primary = new_regionviews.front();
1030 _views = new_regionviews;
1032 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1035 sync the canvas to what we think is its current state
1036 without it, the canvas seems to
1037 "forget" to update properly after the upcoming reparent()
1038 ..only if the mouse is in rapid motion at the time of the grab.
1039 something to do with regionview creation raking so long?
1041 _editor->update_canvas_now();
1045 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1047 /* Which trackview is this ? */
1049 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1050 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1051 (*layer) = tvp.second;
1053 if (*tv && (*tv)->layer_display() == Overlaid) {
1057 /* The region motion is only processed if the pointer is over
1061 if (!(*tv) || !(*tv)->is_track()) {
1062 /* To make sure we hide the verbose canvas cursor when the mouse is
1063 not held over and audiotrack.
1065 _editor->hide_verbose_canvas_cursor ();
1072 /** @param new_order New track order.
1073 * @param old_order Old track order.
1074 * @param visible_y_low Lowest visible order.
1075 * @return true if y movement should not happen, otherwise false.
1078 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1080 if (new_order != old_order) {
1082 /* this isn't the pointer track */
1086 /* moving up the canvas */
1087 if ( (new_order - y_span) >= tavs.visible_y_low) {
1091 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1092 int32_t visible_tracks = 0;
1093 while (visible_tracks < y_span ) {
1095 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1096 /* passing through a hidden track */
1101 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1102 /* moving to a non-track; disallow */
1108 /* moving beyond the lowest visible track; disallow */
1112 } else if (y_span < 0) {
1114 /* moving down the canvas */
1115 if ((new_order - y_span) <= tavs.visible_y_high) {
1117 int32_t visible_tracks = 0;
1119 while (visible_tracks > y_span ) {
1122 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1123 /* passing through a hidden track */
1128 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1129 /* moving to a non-track; disallow */
1136 /* moving beyond the highest visible track; disallow */
1143 /* this is the pointer's track */
1145 if ((new_order - y_span) > tavs.visible_y_high) {
1146 /* we will overflow */
1148 } else if ((new_order - y_span) < tavs.visible_y_low) {
1149 /* we will overflow */
1158 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1159 : RegionMotionDrag (e, i, p, v, b),
1162 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1164 _dest_trackview = tv;
1165 if (tv->layer_display() == Overlaid) {
1168 _dest_layer = _primary->region()->layer ();
1172 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1173 if (rtv && rtv->is_track()) {
1174 speed = rtv->get_diskstream()->speed ();
1177 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1181 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1183 RegionMotionDrag::start_grab (event, c);
1185 _pointer_frame_offset = _grab_frame - _last_frame_position;
1188 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1189 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1191 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1192 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1194 _primary = v->view()->create_region_view (r, false, false);
1196 _primary->get_canvas_group()->show ();
1197 _primary->set_position (pos, 0);
1198 _views.push_back (_primary);
1200 _last_frame_position = pos;
1202 _item = _primary->get_canvas_group ();
1203 _dest_trackview = v;
1204 _dest_layer = _primary->region()->layer ();
1207 map<RegionView*, pair<RouteTimeAxisView*, int> >
1208 RegionMotionDrag::find_time_axis_views_and_layers ()
1210 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1212 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1214 double ix1, ix2, iy1, iy2;
1215 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1216 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1217 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1219 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1220 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1228 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1230 _editor->update_canvas_now ();
1232 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1234 RouteTimeAxisView* dest_rtv = final[_primary].first;
1236 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1237 _primary->get_canvas_group()->property_y() = 0;
1239 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1241 _editor->begin_reversible_command (_("insert region"));
1242 XMLNode& before = playlist->get_state ();
1243 playlist->add_region (_primary->region (), _last_frame_position);
1244 _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1245 _editor->commit_reversible_command ();
1252 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1253 : RegionMoveDrag (e, i, p, v, false, false)
1258 struct RegionSelectionByPosition {
1259 bool operator() (RegionView*a, RegionView* b) {
1260 return a->region()->position () < b->region()->position();
1265 RegionSpliceDrag::motion (GdkEvent* /*event*/, bool)
1267 RouteTimeAxisView* tv;
1270 if (!check_possible (&tv, &layer)) {
1276 if (_current_pointer_x - _grab_x > 0) {
1282 RegionSelection copy (_editor->selection->regions);
1284 RegionSelectionByPosition cmp;
1287 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1289 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1295 boost::shared_ptr<Playlist> playlist;
1297 if ((playlist = atv->playlist()) == 0) {
1301 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1306 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1310 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1316 playlist->shuffle ((*i)->region(), dir);
1318 _grab_x = _current_pointer_x;
1323 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1329 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1337 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1339 _dest_trackview = _view;
1341 Drag::start_grab (event);
1346 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1349 // TODO: create region-create-drag region view here
1352 // TODO: resize region-create-drag region view here
1356 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1358 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1364 if (!movement_occurred) {
1365 mtv->add_region (_grab_frame);
1367 motion (event, false);
1368 // TODO: create region-create-drag region here
1372 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1380 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1383 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1385 Drag::start_grab (event);
1387 region = &cnote->region_view();
1389 double region_start = region->get_position_pixels();
1390 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1392 if (_grab_x <= middle_point) {
1393 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1396 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1400 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1402 if (event->motion.state & Keyboard::PrimaryModifier) {
1408 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1410 if (ms.size() > 1) {
1411 /* has to be relative, may make no sense otherwise */
1415 region->note_selected (cnote, true);
1417 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1418 MidiRegionSelection::iterator next;
1421 (*r)->begin_resizing (at_front);
1427 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1429 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1430 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1431 (*r)->update_resizing (at_front, _current_pointer_x - _grab_x, relative);
1436 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1438 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1439 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1440 (*r)->commit_resizing (at_front, _current_pointer_x - _grab_x, relative);
1445 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1451 RegionGainDrag::finished (GdkEvent *, bool)
1456 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1457 : RegionDrag (e, i, p, v)
1463 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1466 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1467 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1469 if (tv && tv->is_track()) {
1470 speed = tv->get_diskstream()->speed();
1473 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1474 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1475 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1477 Drag::start_grab (event, _editor->trimmer_cursor);
1479 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1480 _operation = ContentsTrim;
1482 /* These will get overridden for a point trim.*/
1483 if (_current_pointer_frame < (region_start + region_length/2)) {
1484 /* closer to start */
1485 _operation = StartTrim;
1486 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1488 _operation = EndTrim;
1492 switch (_operation) {
1494 _editor->show_verbose_time_cursor (region_start, 10);
1497 _editor->show_verbose_time_cursor (region_end, 10);
1500 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1506 TrimDrag::motion (GdkEvent* event, bool first_move)
1508 RegionView* rv = _primary;
1509 nframes64_t frame_delta = 0;
1511 bool left_direction;
1512 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1514 /* snap modifier works differently here..
1515 its' current state has to be passed to the
1516 various trim functions in order to work properly
1520 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1521 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1522 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1524 if (tv && tv->is_track()) {
1525 speed = tv->get_diskstream()->speed();
1528 if (_last_pointer_frame > _current_pointer_frame) {
1529 left_direction = true;
1531 left_direction = false;
1534 _editor->snap_to_with_modifier (_current_pointer_frame, event);
1540 switch (_operation) {
1542 trim_type = "Region start trim";
1545 trim_type = "Region end trim";
1548 trim_type = "Region content trim";
1552 _editor->begin_reversible_command (trim_type);
1554 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1555 (*i)->fake_set_opaque(false);
1556 (*i)->region()->freeze ();
1558 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1561 arv->temporarily_hide_envelope ();
1564 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1565 insert_result = _editor->motion_frozen_playlists.insert (pl);
1567 if (insert_result.second) {
1568 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1574 if (_current_pointer_frame == _last_pointer_frame) {
1578 if (left_direction) {
1579 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1581 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1584 bool non_overlap_trim = false;
1586 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1587 non_overlap_trim = true;
1590 switch (_operation) {
1592 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1596 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1597 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1603 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1607 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1608 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1615 bool swap_direction = false;
1617 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1618 swap_direction = true;
1621 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1623 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1629 switch (_operation) {
1631 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1634 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1637 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1641 _last_pointer_frame = _current_pointer_frame;
1646 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1648 if (movement_occurred) {
1649 motion (event, false);
1651 if (!_editor->selection->selected (_primary)) {
1652 _editor->thaw_region_after_trim (*_primary);
1655 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1656 _editor->thaw_region_after_trim (**i);
1657 (*i)->fake_set_opaque (true);
1661 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1663 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1666 _editor->motion_frozen_playlists.clear ();
1668 _editor->commit_reversible_command();
1670 /* no mouse movement */
1671 _editor->point_trim (event);
1675 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1679 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1684 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1687 // create a dummy marker for visual representation of moving the copy.
1688 // The actual copying is not done before we reach the finish callback.
1690 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1691 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1692 *new MeterSection (_marker->meter()));
1694 _item = &new_marker->the_item ();
1695 _marker = new_marker;
1699 MetricSection& section (_marker->meter());
1701 if (!section.movable()) {
1707 Drag::start_grab (event, cursor);
1709 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1711 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1715 MeterMarkerDrag::motion (GdkEvent* event, bool)
1717 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1719 if (adjusted_frame == _last_pointer_frame) {
1723 _marker->set_position (adjusted_frame);
1725 _last_pointer_frame = adjusted_frame;
1727 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1731 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1733 if (!movement_occurred) {
1737 motion (event, false);
1741 TempoMap& map (_editor->session->tempo_map());
1742 map.bbt_time (_last_pointer_frame, when);
1744 if (_copy == true) {
1745 _editor->begin_reversible_command (_("copy meter mark"));
1746 XMLNode &before = map.get_state();
1747 map.add_meter (_marker->meter(), when);
1748 XMLNode &after = map.get_state();
1749 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1750 _editor->commit_reversible_command ();
1752 // delete the dummy marker we used for visual representation of copying.
1753 // a new visual marker will show up automatically.
1756 _editor->begin_reversible_command (_("move meter mark"));
1757 XMLNode &before = map.get_state();
1758 map.move_meter (_marker->meter(), when);
1759 XMLNode &after = map.get_state();
1760 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1761 _editor->commit_reversible_command ();
1765 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1769 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1774 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1779 // create a dummy marker for visual representation of moving the copy.
1780 // The actual copying is not done before we reach the finish callback.
1782 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1783 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1784 *new TempoSection (_marker->tempo()));
1786 _item = &new_marker->the_item ();
1787 _marker = new_marker;
1791 MetricSection& section (_marker->tempo());
1793 if (!section.movable()) {
1798 Drag::start_grab (event, cursor);
1800 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1801 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1805 TempoMarkerDrag::motion (GdkEvent* event, bool)
1807 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1809 if (adjusted_frame == _last_pointer_frame) {
1813 /* OK, we've moved far enough to make it worth actually move the thing. */
1815 _marker->set_position (adjusted_frame);
1817 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1819 _last_pointer_frame = adjusted_frame;
1823 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1825 if (!movement_occurred) {
1829 motion (event, false);
1833 TempoMap& map (_editor->session->tempo_map());
1834 map.bbt_time (_last_pointer_frame, when);
1836 if (_copy == true) {
1837 _editor->begin_reversible_command (_("copy tempo mark"));
1838 XMLNode &before = map.get_state();
1839 map.add_tempo (_marker->tempo(), when);
1840 XMLNode &after = map.get_state();
1841 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1842 _editor->commit_reversible_command ();
1844 // delete the dummy marker we used for visual representation of copying.
1845 // a new visual marker will show up automatically.
1848 _editor->begin_reversible_command (_("move tempo mark"));
1849 XMLNode &before = map.get_state();
1850 map.move_tempo (_marker->tempo(), when);
1851 XMLNode &after = map.get_state();
1852 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1853 _editor->commit_reversible_command ();
1858 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1862 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1867 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1869 Drag::start_grab (event, c);
1873 nframes64_t where = _editor->event_frame (event, 0, 0);
1875 _editor->snap_to_with_modifier (where, event);
1876 _editor->playhead_cursor->set_position (where);
1880 if (_cursor == _editor->playhead_cursor) {
1881 _editor->_dragging_playhead = true;
1883 if (_editor->session && _was_rolling && _stop) {
1884 _editor->session->request_stop ();
1887 if (_editor->session && _editor->session->is_auditioning()) {
1888 _editor->session->cancel_audition ();
1892 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1896 CursorDrag::motion (GdkEvent* event, bool)
1898 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1900 if (adjusted_frame == _last_pointer_frame) {
1904 _cursor->set_position (adjusted_frame);
1906 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1909 _editor->update_canvas_now ();
1911 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1913 _last_pointer_frame = adjusted_frame;
1917 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1919 _editor->_dragging_playhead = false;
1921 if (!movement_occurred && _stop) {
1925 motion (event, false);
1927 if (_item == &_editor->playhead_cursor->canvas_item) {
1928 if (_editor->session) {
1929 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1930 _editor->_pending_locate_request = true;
1935 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1936 : RegionDrag (e, i, p, v)
1942 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1944 Drag::start_grab (event, cursor);
1946 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1947 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1949 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1950 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
1954 FadeInDrag::motion (GdkEvent* event, bool)
1956 nframes64_t fade_length;
1958 nframes64_t const pos = adjusted_current_frame (event);
1960 boost::shared_ptr<Region> region = _primary->region ();
1962 if (pos < (region->position() + 64)) {
1963 fade_length = 64; // this should be a minimum defined somewhere
1964 } else if (pos > region->last_frame()) {
1965 fade_length = region->length();
1967 fade_length = pos - region->position();
1970 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1972 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1978 tmp->reset_fade_in_shape_width (fade_length);
1981 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1985 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1987 if (!movement_occurred) {
1991 nframes64_t fade_length;
1993 nframes64_t const pos = adjusted_current_frame (event);
1995 boost::shared_ptr<Region> region = _primary->region ();
1997 if (pos < (region->position() + 64)) {
1998 fade_length = 64; // this should be a minimum defined somewhere
1999 } else if (pos > region->last_frame()) {
2000 fade_length = region->length();
2002 fade_length = pos - region->position();
2005 _editor->begin_reversible_command (_("change fade in length"));
2007 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2009 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2015 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2016 XMLNode &before = alist->get_state();
2018 tmp->audio_region()->set_fade_in_length (fade_length);
2019 tmp->audio_region()->set_fade_in_active (true);
2021 XMLNode &after = alist->get_state();
2022 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2025 _editor->commit_reversible_command ();
2028 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2029 : RegionDrag (e, i, p, v)
2035 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2037 Drag::start_grab (event, cursor);
2039 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2040 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2042 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2043 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2047 FadeOutDrag::motion (GdkEvent* event, bool)
2049 nframes64_t fade_length;
2051 nframes64_t const pos = adjusted_current_frame (event);
2053 boost::shared_ptr<Region> region = _primary->region ();
2055 if (pos > (region->last_frame() - 64)) {
2056 fade_length = 64; // this should really be a minimum fade defined somewhere
2058 else if (pos < region->position()) {
2059 fade_length = region->length();
2062 fade_length = region->last_frame() - pos;
2065 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2067 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2073 tmp->reset_fade_out_shape_width (fade_length);
2076 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2080 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2082 if (!movement_occurred) {
2086 nframes64_t fade_length;
2088 nframes64_t const pos = adjusted_current_frame (event);
2090 boost::shared_ptr<Region> region = _primary->region ();
2092 if (pos > (region->last_frame() - 64)) {
2093 fade_length = 64; // this should really be a minimum fade defined somewhere
2095 else if (pos < region->position()) {
2096 fade_length = region->length();
2099 fade_length = region->last_frame() - pos;
2102 _editor->begin_reversible_command (_("change fade out length"));
2104 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2106 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2112 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2113 XMLNode &before = alist->get_state();
2115 tmp->audio_region()->set_fade_out_length (fade_length);
2116 tmp->audio_region()->set_fade_out_active (true);
2118 XMLNode &after = alist->get_state();
2119 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2122 _editor->commit_reversible_command ();
2125 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2128 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2131 _points.push_back (Gnome::Art::Point (0, 0));
2132 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2134 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2135 _line->property_width_pixels() = 1;
2136 _line->property_points () = _points;
2139 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2142 MarkerDrag::~MarkerDrag ()
2144 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2150 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2152 Drag::start_grab (event, cursor);
2156 Location *location = _editor->find_location_from_marker (_marker, is_start);
2157 _editor->_dragging_edit_point = true;
2159 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2161 update_item (location);
2163 // _drag_line->show();
2164 // _line->raise_to_top();
2167 _editor->show_verbose_time_cursor (location->start(), 10);
2169 _editor->show_verbose_time_cursor (location->end(), 10);
2172 Selection::Operation op = Keyboard::selection_type (event->button.state);
2175 case Selection::Toggle:
2176 _editor->selection->toggle (_marker);
2178 case Selection::Set:
2179 if (!_editor->selection->selected (_marker)) {
2180 _editor->selection->set (_marker);
2183 case Selection::Extend:
2185 Locations::LocationList ll;
2186 list<Marker*> to_add;
2188 _editor->selection->markers.range (s, e);
2189 s = min (_marker->position(), s);
2190 e = max (_marker->position(), e);
2193 if (e < max_frames) {
2196 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2197 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2198 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2201 to_add.push_back (lm->start);
2204 to_add.push_back (lm->end);
2208 if (!to_add.empty()) {
2209 _editor->selection->add (to_add);
2213 case Selection::Add:
2214 _editor->selection->add (_marker);
2218 /* set up copies for us to manipulate during the drag */
2220 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2221 Location *l = _editor->find_location_from_marker (*i, is_start);
2222 _copied_locations.push_back (new Location (*l));
2227 MarkerDrag::motion (GdkEvent* event, bool)
2229 nframes64_t f_delta = 0;
2231 bool move_both = false;
2233 Location *real_location;
2234 Location *copy_location = 0;
2236 nframes64_t const newframe = adjusted_current_frame (event);
2238 nframes64_t next = newframe;
2240 if (_current_pointer_frame == _last_pointer_frame) {
2244 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2248 MarkerSelection::iterator i;
2249 list<Location*>::iterator x;
2251 /* find the marker we're dragging, and compute the delta */
2253 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2254 x != _copied_locations.end() && i != _editor->selection->markers.end();
2260 if (marker == _marker) {
2262 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2267 if (real_location->is_mark()) {
2268 f_delta = newframe - copy_location->start();
2272 switch (marker->type()) {
2274 case Marker::LoopStart:
2275 case Marker::PunchIn:
2276 f_delta = newframe - copy_location->start();
2280 case Marker::LoopEnd:
2281 case Marker::PunchOut:
2282 f_delta = newframe - copy_location->end();
2285 /* what kind of marker is this ? */
2293 if (i == _editor->selection->markers.end()) {
2294 /* hmm, impossible - we didn't find the dragged marker */
2298 /* now move them all */
2300 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2301 x != _copied_locations.end() && i != _editor->selection->markers.end();
2307 /* call this to find out if its the start or end */
2309 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2313 if (real_location->locked()) {
2317 if (copy_location->is_mark()) {
2321 copy_location->set_start (copy_location->start() + f_delta);
2325 nframes64_t new_start = copy_location->start() + f_delta;
2326 nframes64_t new_end = copy_location->end() + f_delta;
2328 if (is_start) { // start-of-range marker
2331 copy_location->set_start (new_start);
2332 copy_location->set_end (new_end);
2333 } else if (new_start < copy_location->end()) {
2334 copy_location->set_start (new_start);
2336 _editor->snap_to (next, 1, true);
2337 copy_location->set_end (next);
2338 copy_location->set_start (newframe);
2341 } else { // end marker
2344 copy_location->set_end (new_end);
2345 copy_location->set_start (new_start);
2346 } else if (new_end > copy_location->start()) {
2347 copy_location->set_end (new_end);
2348 } else if (newframe > 0) {
2349 _editor->snap_to (next, -1, true);
2350 copy_location->set_start (next);
2351 copy_location->set_end (newframe);
2356 update_item (copy_location);
2358 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2361 lm->set_position (copy_location->start(), copy_location->end());
2365 _last_pointer_frame = _current_pointer_frame;
2367 assert (!_copied_locations.empty());
2369 _editor->edit_point_clock.set (_copied_locations.front()->start());
2370 _editor->show_verbose_time_cursor (newframe, 10);
2373 _editor->update_canvas_now ();
2375 _editor->edit_point_clock.set (copy_location->start());
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 = Keyboard::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 _grab_x = _point->get_x();
2469 _grab_y = _point->get_y();
2471 _point->line().parent_group().i2w (_grab_x, _grab_y);
2472 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2474 _grab_frame = _editor->pixel_to_frame (_grab_x);
2476 _point->line().start_drag (_point, _grab_frame, 0);
2478 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2479 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2480 _current_pointer_x + 10, _current_pointer_y + 10);
2482 _editor->show_verbose_canvas_cursor ();
2486 ControlPointDrag::motion (GdkEvent* event, bool)
2488 double dx = _current_pointer_x - _last_pointer_x;
2489 double dy = _current_pointer_y - _last_pointer_y;
2491 if (event->button.state & Keyboard::SecondaryModifier) {
2496 double cx = _grab_x + _cumulative_x_drag + dx;
2497 double cy = _grab_y + _cumulative_y_drag + dy;
2499 // calculate zero crossing point. back off by .01 to stay on the
2500 // positive side of zero
2502 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2503 _point->line().parent_group().i2w(_unused, zero_gain_y);
2505 // make sure we hit zero when passing through
2506 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2507 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2511 if (_x_constrained) {
2514 if (_y_constrained) {
2518 _cumulative_x_drag = cx - _grab_x;
2519 _cumulative_y_drag = cy - _grab_y;
2521 _point->line().parent_group().w2i (cx, cy);
2525 cy = min ((double) _point->line().height(), cy);
2527 //translate cx to frames
2528 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2530 if (!_x_constrained) {
2531 _editor->snap_to_with_modifier (cx_frames, event);
2534 float const fraction = 1.0 - (cy / _point->line().height());
2536 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2538 _point->line().point_drag (*_point, cx_frames, fraction, push);
2540 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2544 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2546 if (!movement_occurred) {
2550 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2551 _editor->reset_point_selection ();
2555 motion (event, false);
2557 _point->line().end_drag (_point);
2561 ControlPointDrag::active (Editing::MouseMode m)
2563 if (m == Editing::MouseGain) {
2564 /* always active in mouse gain */
2568 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2569 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2572 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2575 _cumulative_y_drag (0)
2580 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2582 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2585 _item = &_line->grab_item ();
2587 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2588 origin, and ditto for y.
2591 double cx = event->button.x;
2592 double cy = event->button.y;
2594 _line->parent_group().w2i (cx, cy);
2596 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2598 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2599 /* no adjacent points */
2603 Drag::start_grab (event, _editor->fader_cursor);
2605 /* store grab start in parent frame */
2610 double fraction = 1.0 - (cy / _line->height());
2612 _line->start_drag (0, _grab_frame, fraction);
2614 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2615 _current_pointer_x + 10, _current_pointer_y + 10);
2617 _editor->show_verbose_canvas_cursor ();
2621 LineDrag::motion (GdkEvent* event, bool)
2623 double dy = _current_pointer_y - _last_pointer_y;
2625 if (event->button.state & Keyboard::SecondaryModifier) {
2629 double cy = _grab_y + _cumulative_y_drag + dy;
2631 _cumulative_y_drag = cy - _grab_y;
2634 cy = min ((double) _line->height(), cy);
2636 double const fraction = 1.0 - (cy / _line->height());
2640 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2646 _line->line_drag (_before, _after, fraction, push);
2648 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2652 LineDrag::finished (GdkEvent* event, bool)
2654 motion (event, false);
2655 _line->end_drag (0);
2659 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2661 Drag::start_grab (event);
2662 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2666 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2673 /* use a bigger drag threshold than the default */
2675 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2679 if (Config->get_rubberbanding_snaps_to_grid()) {
2681 _editor->snap_to_with_modifier (_grab_frame, event);
2683 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2686 /* base start and end on initial click position */
2688 if (_current_pointer_frame < _grab_frame) {
2689 start = _current_pointer_frame;
2692 end = _current_pointer_frame;
2693 start = _grab_frame;
2696 if (_current_pointer_y < _grab_y) {
2697 y1 = _current_pointer_y;
2700 y2 = _current_pointer_y;
2705 if (start != end || y1 != y2) {
2707 double x1 = _editor->frame_to_pixel (start);
2708 double x2 = _editor->frame_to_pixel (end);
2710 _editor->rubberband_rect->property_x1() = x1;
2711 _editor->rubberband_rect->property_y1() = y1;
2712 _editor->rubberband_rect->property_x2() = x2;
2713 _editor->rubberband_rect->property_y2() = y2;
2715 _editor->rubberband_rect->show();
2716 _editor->rubberband_rect->raise_to_top();
2718 _last_pointer_frame = _current_pointer_frame;
2720 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2725 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2727 if (movement_occurred) {
2729 motion (event, false);
2732 if (_current_pointer_y < _grab_y) {
2733 y1 = _current_pointer_y;
2736 y2 = _current_pointer_y;
2741 Selection::Operation op = Keyboard::selection_type (event->button.state);
2744 _editor->begin_reversible_command (_("rubberband selection"));
2746 if (_grab_frame < _last_pointer_frame) {
2747 committed = _editor->select_all_within (_grab_frame, _last_pointer_frame - 1, y1, y2, _editor->track_views, op);
2749 committed = _editor->select_all_within (_last_pointer_frame, _grab_frame - 1, y1, y2, _editor->track_views, op);
2753 _editor->commit_reversible_command ();
2757 if (!getenv("ARDOUR_SAE")) {
2758 _editor->selection->clear_tracks();
2760 _editor->selection->clear_regions();
2761 _editor->selection->clear_points ();
2762 _editor->selection->clear_lines ();
2765 _editor->rubberband_rect->hide();
2769 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2771 Drag::start_grab (event);
2773 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2777 TimeFXDrag::motion (GdkEvent* event, bool)
2779 RegionView* rv = _primary;
2781 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2783 if (_current_pointer_frame == _last_pointer_frame) {
2787 if (_current_pointer_frame > rv->region()->position()) {
2788 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2791 _last_pointer_frame = _current_pointer_frame;
2793 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2797 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2799 _primary->get_time_axis_view().hide_timestretch ();
2801 if (!movement_occurred) {
2805 if (_last_pointer_frame < _primary->region()->position()) {
2806 /* backwards drag of the left edge - not usable */
2810 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2812 float percentage = (double) newlen / (double) _primary->region()->length();
2814 #ifndef USE_RUBBERBAND
2815 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2816 if (_primary->region()->data_type() == DataType::AUDIO) {
2817 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2821 _editor->begin_reversible_command (_("timestretch"));
2823 // XXX how do timeFX on multiple regions ?
2828 if (_editor->time_stretch (rs, percentage) == 0) {
2829 _editor->session->commit_reversible_command ();
2834 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2836 Drag::start_grab (event);
2840 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2846 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2848 if (movement_occurred && _editor->session) {
2849 /* make sure we stop */
2850 _editor->session->request_transport_speed (0.0);
2854 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2863 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2865 nframes64_t start = 0;
2866 nframes64_t end = 0;
2868 if (_editor->session == 0) {
2872 Gdk::Cursor* cursor = 0;
2874 switch (_operation) {
2875 case CreateSelection:
2876 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2881 cursor = _editor->selector_cursor;
2882 Drag::start_grab (event, cursor);
2885 case SelectionStartTrim:
2886 if (_editor->clicked_axisview) {
2887 _editor->clicked_axisview->order_selection_trims (_item, true);
2889 Drag::start_grab (event, cursor);
2890 cursor = _editor->trimmer_cursor;
2891 start = _editor->selection->time[_editor->clicked_selection].start;
2892 _pointer_frame_offset = _grab_frame - start;
2895 case SelectionEndTrim:
2896 if (_editor->clicked_axisview) {
2897 _editor->clicked_axisview->order_selection_trims (_item, false);
2899 Drag::start_grab (event, cursor);
2900 cursor = _editor->trimmer_cursor;
2901 end = _editor->selection->time[_editor->clicked_selection].end;
2902 _pointer_frame_offset = _grab_frame - end;
2906 start = _editor->selection->time[_editor->clicked_selection].start;
2907 Drag::start_grab (event, cursor);
2908 _pointer_frame_offset = _grab_frame - start;
2912 if (_operation == SelectionMove) {
2913 _editor->show_verbose_time_cursor (start, 10);
2915 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2920 SelectionDrag::motion (GdkEvent* event, bool first_move)
2922 nframes64_t start = 0;
2923 nframes64_t end = 0;
2926 nframes64_t const pending_position = adjusted_current_frame (event);
2928 /* only alter selection if the current frame is
2929 different from the last frame position (adjusted)
2932 if (pending_position == _last_pointer_frame) {
2936 switch (_operation) {
2937 case CreateSelection:
2940 _editor->snap_to (_grab_frame);
2943 if (pending_position < _grab_frame) {
2944 start = pending_position;
2947 end = pending_position;
2948 start = _grab_frame;
2951 /* first drag: Either add to the selection
2952 or create a new selection->
2957 _editor->begin_reversible_command (_("range selection"));
2960 /* adding to the selection */
2961 _editor->clicked_selection = _editor->selection->add (start, end);
2964 /* new selection-> */
2965 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2970 case SelectionStartTrim:
2973 _editor->begin_reversible_command (_("trim selection start"));
2976 start = _editor->selection->time[_editor->clicked_selection].start;
2977 end = _editor->selection->time[_editor->clicked_selection].end;
2979 if (pending_position > end) {
2982 start = pending_position;
2986 case SelectionEndTrim:
2989 _editor->begin_reversible_command (_("trim selection end"));
2992 start = _editor->selection->time[_editor->clicked_selection].start;
2993 end = _editor->selection->time[_editor->clicked_selection].end;
2995 if (pending_position < start) {
2998 end = pending_position;
3006 _editor->begin_reversible_command (_("move selection"));
3009 start = _editor->selection->time[_editor->clicked_selection].start;
3010 end = _editor->selection->time[_editor->clicked_selection].end;
3012 length = end - start;
3014 start = pending_position;
3015 _editor->snap_to (start);
3017 end = start + length;
3022 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3023 _editor->start_canvas_autoscroll (1, 0);
3027 _editor->selection->replace (_editor->clicked_selection, start, end);
3030 _last_pointer_frame = pending_position;
3032 if (_operation == SelectionMove) {
3033 _editor->show_verbose_time_cursor(start, 10);
3035 _editor->show_verbose_time_cursor(pending_position, 10);
3040 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3042 if (movement_occurred) {
3043 motion (event, false);
3044 /* XXX this is not object-oriented programming at all. ick */
3045 if (_editor->selection->time.consolidate()) {
3046 _editor->selection->TimeChanged ();
3048 _editor->commit_reversible_command ();
3050 /* just a click, no pointer movement.*/
3052 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3054 _editor->selection->clear_time();
3059 /* XXX what happens if its a music selection? */
3060 _editor->session->set_audio_range (_editor->selection->time);
3061 _editor->stop_canvas_autoscroll ();
3064 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3069 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3070 _drag_rect->hide ();
3072 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3073 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3077 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3079 if (_editor->session == 0) {
3083 Gdk::Cursor* cursor = 0;
3085 if (!_editor->temp_location) {
3086 _editor->temp_location = new Location;
3089 switch (_operation) {
3090 case CreateRangeMarker:
3091 case CreateTransportMarker:
3092 case CreateCDMarker:
3094 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3099 cursor = _editor->selector_cursor;
3103 Drag::start_grab (event, cursor);
3105 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3109 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3111 nframes64_t start = 0;
3112 nframes64_t end = 0;
3113 ArdourCanvas::SimpleRect *crect;
3115 switch (_operation) {
3116 case CreateRangeMarker:
3117 crect = _editor->range_bar_drag_rect;
3119 case CreateTransportMarker:
3120 crect = _editor->transport_bar_drag_rect;
3122 case CreateCDMarker:
3123 crect = _editor->cd_marker_bar_drag_rect;
3126 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3131 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3133 /* only alter selection if the current frame is
3134 different from the last frame position.
3137 if (_current_pointer_frame == _last_pointer_frame) {
3141 switch (_operation) {
3142 case CreateRangeMarker:
3143 case CreateTransportMarker:
3144 case CreateCDMarker:
3146 _editor->snap_to (_grab_frame);
3149 if (_current_pointer_frame < _grab_frame) {
3150 start = _current_pointer_frame;
3153 end = _current_pointer_frame;
3154 start = _grab_frame;
3157 /* first drag: Either add to the selection
3158 or create a new selection.
3163 _editor->temp_location->set (start, end);
3167 update_item (_editor->temp_location);
3169 //_drag_rect->raise_to_top();
3175 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3176 _editor->start_canvas_autoscroll (1, 0);
3180 _editor->temp_location->set (start, end);
3182 double x1 = _editor->frame_to_pixel (start);
3183 double x2 = _editor->frame_to_pixel (end);
3184 crect->property_x1() = x1;
3185 crect->property_x2() = x2;
3187 update_item (_editor->temp_location);
3190 _last_pointer_frame = _current_pointer_frame;
3192 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3197 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3199 Location * newloc = 0;
3203 if (movement_occurred) {
3204 motion (event, false);
3207 switch (_operation) {
3208 case CreateRangeMarker:
3209 case CreateCDMarker:
3211 _editor->begin_reversible_command (_("new range marker"));
3212 XMLNode &before = _editor->session->locations()->get_state();
3213 _editor->session->locations()->next_available_name(rangename,"unnamed");
3214 if (_operation == CreateCDMarker) {
3215 flags = Location::IsRangeMarker | Location::IsCDMarker;
3216 _editor->cd_marker_bar_drag_rect->hide();
3219 flags = Location::IsRangeMarker;
3220 _editor->range_bar_drag_rect->hide();
3222 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3223 _editor->session->locations()->add (newloc, true);
3224 XMLNode &after = _editor->session->locations()->get_state();
3225 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3226 _editor->commit_reversible_command ();
3230 case CreateTransportMarker:
3231 // popup menu to pick loop or punch
3232 _editor->new_transport_marker_context_menu (&event->button, _item);
3236 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3238 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3243 _editor->session->locations()->marks_either_side (_grab_frame, start, end);
3245 if (end == max_frames) {
3246 end = _editor->session->current_end_frame ();
3249 if (start == max_frames) {
3250 start = _editor->session->current_start_frame ();
3253 switch (_editor->mouse_mode) {
3255 /* find the two markers on either side and then make the selection from it */
3256 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3260 /* find the two markers on either side of the click and make the range out of it */
3261 _editor->selection->set (0, start, end);
3270 _editor->stop_canvas_autoscroll ();
3276 RangeMarkerBarDrag::update_item (Location* location)
3278 double const x1 = _editor->frame_to_pixel (location->start());
3279 double const x2 = _editor->frame_to_pixel (location->end());
3281 _drag_rect->property_x1() = x1;
3282 _drag_rect->property_x2() = x2;
3286 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3288 Drag::start_grab (event, _editor->zoom_cursor);
3289 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3293 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3298 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3301 _editor->snap_to_with_modifier (_grab_frame, event);
3304 if (_current_pointer_frame == _last_pointer_frame) {
3308 /* base start and end on initial click position */
3309 if (_current_pointer_frame < _grab_frame) {
3310 start = _current_pointer_frame;
3313 end = _current_pointer_frame;
3314 start = _grab_frame;
3320 _editor->zoom_rect->show();
3321 _editor->zoom_rect->raise_to_top();
3324 _editor->reposition_zoom_rect(start, end);
3326 _last_pointer_frame = _current_pointer_frame;
3328 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3333 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3335 if (movement_occurred) {
3336 motion (event, false);
3338 if (_grab_frame < _last_pointer_frame) {
3339 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3341 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3344 _editor->temporal_zoom_to_frame (false, _grab_frame);
3346 temporal_zoom_step (false);
3347 center_screen (_grab_frame);
3351 _editor->zoom_rect->hide();
3354 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3357 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3358 region = &cnote->region_view();
3362 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3364 Drag::start_grab (event);
3367 drag_delta_note = 0;
3372 event_x = _current_pointer_x;
3373 event_y = _current_pointer_y;
3375 _item->property_parent().get_value()->w2i(event_x, event_y);
3377 last_x = region->snap_to_pixel(event_x);
3380 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3382 if (!(was_selected = cnote->selected())) {
3384 /* tertiary-click means extend selection - we'll do that on button release,
3385 so don't add it here, because otherwise we make it hard to figure
3386 out the "extend-to" range.
3389 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3392 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3395 region->note_selected (cnote, true);
3397 region->unique_select (cnote);
3404 NoteDrag::motion (GdkEvent*, bool)
3406 MidiStreamView* streamview = region->midi_stream_view();
3410 event_x = _current_pointer_x;
3411 event_y = _current_pointer_y;
3413 _item->property_parent().get_value()->w2i(event_x, event_y);
3415 event_x = region->snap_to_pixel(event_x);
3417 double dx = event_x - last_x;
3418 double dy = event_y - last_y;
3423 // Snap to note rows
3425 if (abs (dy) < streamview->note_height()) {
3428 int8_t this_delta_note;
3430 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3432 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3434 drag_delta_note -= this_delta_note;
3435 dy = streamview->note_height() * this_delta_note;
3436 last_y = last_y + dy;
3440 region->move_selection (dx, dy);
3442 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3444 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3445 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3446 _editor->show_verbose_canvas_cursor_with (buf);
3451 NoteDrag::finished (GdkEvent* ev, bool moved)
3453 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3456 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3459 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3461 region->note_deselected (cnote);
3464 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3465 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3467 if (!extend && !add && region->selection_size() > 1) {
3468 region->unique_select(cnote);
3469 } else if (extend) {
3470 region->note_selected (cnote, true, true);
3472 /* it was added during button press */
3477 region->note_dropped (cnote, drag_delta_x, drag_delta_note);