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"
45 using namespace ARDOUR;
48 using namespace Editing;
49 using namespace ArdourCanvas;
51 using Gtkmm2ext::Keyboard;
53 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
55 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
58 , _pointer_frame_offset (0)
60 , _last_pointer_frame (0)
61 , _current_pointer_frame (0)
62 , _have_transaction (false)
63 , _had_movement (false)
64 , _move_threshold_passed (false)
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 _last_pointer_frame = _grab_frame;
106 _current_pointer_frame = _grab_frame;
107 _current_pointer_x = _grab_x;
108 _current_pointer_y = _grab_y;
109 _last_pointer_x = _current_pointer_x;
110 _last_pointer_y = _current_pointer_y;
114 _item->i2w (_original_x, _original_y);
116 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
120 if (_editor->session() && _editor->session()->transport_rolling()) {
123 _was_rolling = false;
126 switch (_editor->snap_type()) {
127 case SnapToRegionStart:
128 case SnapToRegionEnd:
129 case SnapToRegionSync:
130 case SnapToRegionBoundary:
131 _editor->build_region_boundary_cache ();
138 /** @param event GDK event, or 0.
139 * @return true if some movement occurred, otherwise false.
142 Drag::end_grab (GdkEvent* event)
146 _editor->stop_canvas_autoscroll ();
148 _item->ungrab (event ? event->button.time : 0);
150 _last_pointer_x = _current_pointer_x;
151 _last_pointer_y = _current_pointer_y;
152 finished (event, _had_movement);
154 _editor->hide_verbose_canvas_cursor();
158 return _had_movement;
162 Drag::adjusted_current_frame (GdkEvent* event) const
166 if (_current_pointer_frame > _pointer_frame_offset) {
167 pos = _current_pointer_frame - _pointer_frame_offset;
170 _editor->snap_to_with_modifier (pos, event);
176 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
178 _last_pointer_x = _current_pointer_x;
179 _last_pointer_y = _current_pointer_y;
180 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
182 if (!from_autoscroll && !_move_threshold_passed) {
184 bool const xp = (::llabs ((nframes64_t) (_current_pointer_x - _grab_x)) > 4LL);
185 bool const yp = (::llabs ((nframes64_t) (_current_pointer_y - _grab_y)) > 4LL);
187 _move_threshold_passed = (xp || yp);
190 bool old_had_movement = _had_movement;
192 /* a motion event has happened, so we've had movement... */
193 _had_movement = true;
195 /* ... unless we're using a move threshold and we've not yet passed it */
196 if (apply_move_threshold() && !_move_threshold_passed) {
197 _had_movement = false;
200 if (active (_editor->mouse_mode) && _had_movement) {
202 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
203 if (!from_autoscroll) {
204 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
207 motion (event, _had_movement != old_had_movement);
219 _editor->stop_canvas_autoscroll ();
220 _editor->hide_verbose_canvas_cursor ();
225 /* put it back where it came from */
230 _item->i2w (cxw, cyw);
231 _item->move (_original_x - cxw, _original_y - cyw);
236 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
241 RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
245 RegionDrag::region_going_away (RegionView* v)
250 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
251 : RegionDrag (e, i, p, v),
261 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
263 Drag::start_grab (event);
265 _editor->show_verbose_time_cursor (_last_frame_position, 10);
268 RegionMotionDrag::TimeAxisViewSummary
269 RegionMotionDrag::get_time_axis_view_summary ()
271 int32_t children = 0;
272 TimeAxisViewSummary sum;
274 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
276 /* get a bitmask representing the visible tracks */
278 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
279 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
280 TimeAxisView::Children children_list;
282 /* zeroes are audio/MIDI tracks. ones are other types. */
284 if (!rtv->hidden()) {
286 if (!rtv->is_track()) {
287 /* not an audio nor MIDI track */
288 sum.tracks = sum.tracks |= (0x01 << rtv->order());
291 sum.height_list[rtv->order()] = (*i)->current_height();
294 if ((children_list = rtv->get_child_list()).size() > 0) {
295 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
296 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
297 sum.height_list[rtv->order() + children] = (*j)->current_height();
308 RegionMotionDrag::compute_y_delta (
309 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
310 int32_t last_pointer_layer, int32_t current_pointer_layer,
311 TimeAxisViewSummary const & tavs,
312 int32_t* pointer_order_span, int32_t* pointer_layer_span,
313 int32_t* canvas_pointer_order_span
317 *pointer_order_span = 0;
318 *pointer_layer_span = 0;
322 bool clamp_y_axis = false;
324 /* the change in track order between this callback and the last */
325 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
326 /* the change in layer between this callback and the last;
327 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
328 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
330 if (*pointer_order_span != 0) {
332 /* find the actual pointer span, in terms of the number of visible tracks;
333 to do this, we reduce |pointer_order_span| by the number of hidden tracks
336 *canvas_pointer_order_span = *pointer_order_span;
337 if (last_pointer_view->order() >= current_pointer_view->order()) {
338 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
339 if (tavs.height_list[y] == 0) {
340 *canvas_pointer_order_span--;
344 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
345 if (tavs.height_list[y] == 0) {
346 *canvas_pointer_order_span++;
351 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
353 RegionView* rv = (*i);
355 if (rv->region()->locked()) {
359 double ix1, ix2, iy1, iy2;
360 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
361 rv->get_canvas_frame()->i2w (ix1, iy1);
362 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
364 /* get the new trackview for this particular region */
365 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
367 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
369 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
370 as surely this is a per-region thing... */
372 clamp_y_axis = y_movement_disallowed (
373 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
381 } else if (_dest_trackview == current_pointer_view) {
383 if (current_pointer_layer == last_pointer_layer) {
384 /* No movement; clamp */
390 _dest_trackview = current_pointer_view;
391 _dest_layer = current_pointer_layer;
399 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
401 *pending_region_position = 0;
403 /* compute the amount of pointer motion in frames, and where
404 the region would be if we moved it by that much.
406 if (_current_pointer_frame >= _pointer_frame_offset) {
408 nframes64_t sync_frame;
409 nframes64_t sync_offset;
412 *pending_region_position = _current_pointer_frame - _pointer_frame_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;
432 if (*pending_region_position > max_frames - _primary->region()->length()) {
433 *pending_region_position = _last_frame_position;
438 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
440 /* now compute the canvas unit distance we need to move the regionview
441 to make it appear at the new location.
444 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
446 if (*pending_region_position <= _last_frame_position) {
448 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
450 RegionView* rv = (*i);
452 // If any regionview is at zero, we need to know so we can stop further leftward motion.
454 double ix1, ix2, iy1, iy2;
455 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
456 rv->get_canvas_frame()->i2w (ix1, iy1);
458 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
460 *pending_region_position = _last_frame_position;
467 _last_frame_position = *pending_region_position;
474 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
478 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
480 vector<int32_t>::iterator j;
482 /* *pointer* variables reflect things about the pointer; as we may be moving
483 multiple regions, much detail must be computed per-region */
485 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
486 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
487 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
488 is always 0 regardless of what the region's "real" layer is */
489 RouteTimeAxisView* current_pointer_view;
490 layer_t current_pointer_layer;
491 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
495 /* TimeAxisView that we were pointing at last time we entered this method */
496 TimeAxisView const * const last_pointer_view = _dest_trackview;
497 /* the order of the track that we were pointing at last time we entered this method */
498 int32_t const last_pointer_order = last_pointer_view->order ();
499 /* the layer that we were pointing at last time we entered this method */
500 layer_t const last_pointer_layer = _dest_layer;
502 int32_t pointer_order_span;
503 int32_t pointer_layer_span;
504 int32_t canvas_pointer_order_span;
506 bool const clamp_y_axis = compute_y_delta (
507 last_pointer_view, current_pointer_view,
508 last_pointer_layer, current_pointer_layer, tavs,
509 &pointer_order_span, &pointer_layer_span,
510 &canvas_pointer_order_span
513 nframes64_t pending_region_position;
514 double const x_delta = compute_x_delta (event, &pending_region_position);
516 /*************************************************************
518 ************************************************************/
520 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
521 /* haven't reached next snap point, and we're not switching
522 trackviews nor layers. nothing to do.
527 /*************************************************************
529 ************************************************************/
531 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
533 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
535 RegionView* rv = (*i);
537 if (rv->region()->locked()) {
541 /* here we are calculating the y distance from the
542 top of the first track view to the top of the region
543 area of the track view that we're working on */
545 /* this x value is just a dummy value so that we have something
550 /* distance from the top of this track view to the region area
551 of our track view is always 1 */
555 /* convert to world coordinates, ie distance from the top of
558 rv->get_canvas_frame()->i2w (ix1, iy1);
560 /* compensate for the ruler section and the vertical scrollbar position */
561 iy1 += _editor->get_trackview_group_vertical_offset ();
565 // hide any dependent views
567 rv->get_time_axis_view().hide_dependent_views (*rv);
570 reparent to a non scrolling group so that we can keep the
571 region selection above all time axis views.
572 reparenting means we have to move the rv as the two
573 parent groups have different coordinates.
576 rv->get_canvas_group()->property_y() = iy1 - 1;
577 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
579 rv->fake_set_opaque (true);
582 /* current view for this particular region */
583 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
584 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
586 if (pointer_order_span != 0 && !clamp_y_axis) {
588 /* INTER-TRACK MOVEMENT */
590 /* move through the height list to the track that the region is currently on */
591 vector<int32_t>::iterator j = tavs.height_list.begin ();
593 while (j != tavs.height_list.end () && x != rtv->order ()) {
599 int32_t temp_pointer_order_span = canvas_pointer_order_span;
601 if (j != tavs.height_list.end ()) {
603 /* Account for layers in the original and
604 destination tracks. If we're moving around in layers we assume
605 that only one track is involved, so it's ok to use *pointer*
608 StreamView* lv = last_pointer_view->view ();
611 /* move to the top of the last trackview */
612 if (lv->layer_display () == Stacked) {
613 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
616 StreamView* cv = current_pointer_view->view ();
619 /* move to the right layer on the current trackview */
620 if (cv->layer_display () == Stacked) {
621 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
624 /* And for being on a non-topmost layer on the new
627 while (temp_pointer_order_span > 0) {
628 /* we're moving up canvas-wise,
629 so we need to find the next track height
631 if (j != tavs.height_list.begin()) {
635 if (x != last_pointer_order) {
637 ++temp_pointer_order_span;
642 temp_pointer_order_span--;
645 while (temp_pointer_order_span < 0) {
649 if (x != last_pointer_order) {
651 --temp_pointer_order_span;
655 if (j != tavs.height_list.end()) {
659 temp_pointer_order_span++;
663 /* find out where we'll be when we move and set height accordingly */
665 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
666 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
667 rv->set_height (temp_rtv->view()->child_height());
669 /* if you un-comment the following, the region colours will follow
670 the track colours whilst dragging; personally
671 i think this can confuse things, but never mind.
674 //const GdkColor& col (temp_rtv->view->get_region_color());
675 //rv->set_color (const_cast<GdkColor&>(col));
679 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
681 /* INTER-LAYER MOVEMENT in the same track */
682 y_delta = rtv->view()->child_height () * pointer_layer_span;
687 _editor->mouse_brush_insert_region (rv, pending_region_position);
689 rv->move (x_delta, y_delta);
692 } /* foreach region */
695 _editor->cursor_group->raise_to_top();
698 if (x_delta != 0 && !_brushing) {
699 _editor->show_verbose_time_cursor (_last_frame_position, 10);
704 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
706 if (_copy && first_move) {
707 copy_regions (event);
710 RegionMotionDrag::motion (event, first_move);
714 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
716 vector<RegionView*> copies;
717 boost::shared_ptr<Diskstream> ds;
718 boost::shared_ptr<Playlist> from_playlist;
719 RegionSelection new_views;
720 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
721 PlaylistSet modified_playlists;
722 PlaylistSet frozen_playlists;
723 list <sigc::connection> modified_playlist_connections;
724 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
725 nframes64_t drag_delta;
726 bool changed_tracks, changed_position;
727 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
728 RouteTimeAxisView* source_tv;
730 if (!movement_occurred) {
736 /* all changes were made during motion event handlers */
739 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
740 copies.push_back (*i);
747 /* reverse this here so that we have the correct logic to finalize
751 if (Config->get_edit_mode() == Lock) {
752 _x_constrained = !_x_constrained;
756 if (_x_constrained) {
757 _editor->begin_reversible_command (_("fixed time region copy"));
759 _editor->begin_reversible_command (_("region copy"));
762 if (_x_constrained) {
763 _editor->begin_reversible_command (_("fixed time region drag"));
765 _editor->begin_reversible_command (_("region drag"));
769 _have_transaction = true;
771 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
772 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
774 drag_delta = _primary->region()->position() - _last_frame_position;
776 _editor->update_canvas_now ();
778 /* make a list of where each region ended up */
779 final = find_time_axis_views_and_layers ();
781 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
783 RegionView* rv = (*i);
784 RouteTimeAxisView* dest_rtv = final[*i].first;
785 layer_t dest_layer = final[*i].second;
789 if (rv->region()->locked()) {
794 if (changed_position && !_x_constrained) {
795 where = rv->region()->position() - drag_delta;
797 where = rv->region()->position();
800 boost::shared_ptr<Region> new_region;
803 /* we already made a copy */
804 new_region = rv->region();
806 /* undo the previous hide_dependent_views so that xfades don't
807 disappear on copying regions
810 //rv->get_time_axis_view().reveal_dependent_views (*rv);
812 } else if (changed_tracks && dest_rtv->playlist()) {
813 new_region = RegionFactory::create (rv->region());
816 if (changed_tracks || _copy) {
818 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
825 _editor->latest_regionviews.clear ();
827 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
829 insert_result = modified_playlists.insert (to_playlist);
831 if (insert_result.second) {
832 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
835 to_playlist->add_region (new_region, where);
836 if (dest_rtv->view()->layer_display() == Stacked) {
837 new_region->set_layer (dest_layer);
838 new_region->set_pending_explicit_relayer (true);
843 if (!_editor->latest_regionviews.empty()) {
844 // XXX why just the first one ? we only expect one
845 // commented out in nick_m's canvas reworking. is that intended?
846 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
847 new_views.push_back (_editor->latest_regionviews.front());
852 motion on the same track. plonk the previously reparented region
853 back to its original canvas group (its streamview).
854 No need to do anything for copies as they are fake regions which will be deleted.
857 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
858 rv->get_canvas_group()->property_y() = 0;
860 /* just change the model */
862 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
864 if (dest_rtv->view()->layer_display() == Stacked) {
865 rv->region()->set_layer (dest_layer);
866 rv->region()->set_pending_explicit_relayer (true);
869 insert_result = modified_playlists.insert (playlist);
871 if (insert_result.second) {
872 _editor->session()->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
874 /* freeze to avoid lots of relayering in the case of a multi-region drag */
875 frozen_insert_result = frozen_playlists.insert(playlist);
877 if (frozen_insert_result.second) {
881 rv->region()->set_position (where, (void*) this);
884 if (changed_tracks && !_copy) {
886 /* get the playlist where this drag started. we can't use rv->region()->playlist()
887 because we may have copied the region and it has not been attached to a playlist.
890 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
891 ds = source_tv->get_diskstream();
892 from_playlist = ds->playlist();
896 assert (from_playlist);
898 /* moved to a different audio track, without copying */
900 /* the region that used to be in the old playlist is not
901 moved to the new one - we use a copy of it. as a result,
902 any existing editor for the region should no longer be
906 rv->hide_region_editor();
907 rv->fake_set_opaque (false);
909 /* remove the region from the old playlist */
911 insert_result = modified_playlists.insert (from_playlist);
913 if (insert_result.second) {
914 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
917 from_playlist->remove_region (rv->region());
919 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
920 was selected in all of them, then removing it from a playlist will have removed all
921 trace of it from the selection (i.e. there were N regions selected, we removed 1,
922 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
923 corresponding regionview, and the selection is now empty).
925 this could have invalidated any and all iterators into the region selection.
927 the heuristic we use here is: if the region selection is empty, break out of the loop
928 here. if the region selection is not empty, then restart the loop because we know that
929 we must have removed at least the region(view) we've just been working on as well as any
930 that we processed on previous iterations.
932 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
936 if (_views.empty()) {
947 copies.push_back (rv);
951 if we've created new regions either by copying or moving
952 to a new track, we want to replace the old selection with the new ones
954 if (new_views.size() > 0) {
955 _editor->selection->set (new_views);
958 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
963 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
964 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
967 _editor->commit_reversible_command ();
969 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
976 RegionMotionDrag::x_move_allowed () const
978 if (Config->get_edit_mode() == Lock) {
979 /* in locked edit mode, reverse the usual meaning of _x_constrained */
980 return _x_constrained;
983 return !_x_constrained;
987 RegionMotionDrag::copy_regions (GdkEvent* event)
989 /* duplicate the regionview(s) and region(s) */
991 list<RegionView*> new_regionviews;
993 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
995 RegionView* rv = (*i);
996 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
997 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
999 const boost::shared_ptr<const Region> original = rv->region();
1000 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1004 boost::shared_ptr<AudioRegion> audioregion_copy
1005 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1006 nrv = new AudioRegionView (*arv, audioregion_copy);
1008 boost::shared_ptr<MidiRegion> midiregion_copy
1009 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1010 nrv = new MidiRegionView (*mrv, midiregion_copy);
1015 nrv->get_canvas_group()->show ();
1016 new_regionviews.push_back (nrv);
1018 /* swap _primary to the copy */
1020 if (rv == _primary) {
1024 /* ..and deselect the one we copied */
1026 rv->set_selected (false);
1029 if (new_regionviews.empty()) {
1033 /* reflect the fact that we are dragging the copies */
1035 _views = new_regionviews;
1037 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1040 sync the canvas to what we think is its current state
1041 without it, the canvas seems to
1042 "forget" to update properly after the upcoming reparent()
1043 ..only if the mouse is in rapid motion at the time of the grab.
1044 something to do with regionview creation raking so long?
1046 _editor->update_canvas_now();
1050 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1052 /* Which trackview is this ? */
1054 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1055 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1056 (*layer) = tvp.second;
1058 if (*tv && (*tv)->layer_display() == Overlaid) {
1062 /* The region motion is only processed if the pointer is over
1066 if (!(*tv) || !(*tv)->is_track()) {
1067 /* To make sure we hide the verbose canvas cursor when the mouse is
1068 not held over and audiotrack.
1070 _editor->hide_verbose_canvas_cursor ();
1077 /** @param new_order New track order.
1078 * @param old_order Old track order.
1079 * @param visible_y_low Lowest visible order.
1080 * @return true if y movement should not happen, otherwise false.
1083 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1085 if (new_order != old_order) {
1087 /* this isn't the pointer track */
1091 /* moving up the canvas */
1092 if ( (new_order - y_span) >= tavs.visible_y_low) {
1096 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1097 int32_t visible_tracks = 0;
1098 while (visible_tracks < y_span ) {
1100 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1101 /* passing through a hidden track */
1106 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1107 /* moving to a non-track; disallow */
1113 /* moving beyond the lowest visible track; disallow */
1117 } else if (y_span < 0) {
1119 /* moving down the canvas */
1120 if ((new_order - y_span) <= tavs.visible_y_high) {
1122 int32_t visible_tracks = 0;
1124 while (visible_tracks > y_span ) {
1127 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1128 /* passing through a hidden track */
1133 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1134 /* moving to a non-track; disallow */
1141 /* moving beyond the highest visible track; disallow */
1148 /* this is the pointer's track */
1150 if ((new_order - y_span) > tavs.visible_y_high) {
1151 /* we will overflow */
1153 } else if ((new_order - y_span) < tavs.visible_y_low) {
1154 /* we will overflow */
1163 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1164 : RegionMotionDrag (e, i, p, v, b),
1167 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1169 _dest_trackview = tv;
1170 if (tv->layer_display() == Overlaid) {
1173 _dest_layer = _primary->region()->layer ();
1177 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1178 if (rtv && rtv->is_track()) {
1179 speed = rtv->get_diskstream()->speed ();
1182 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1186 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1188 RegionMotionDrag::start_grab (event, c);
1190 _pointer_frame_offset = _grab_frame - _last_frame_position;
1193 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1194 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1196 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1197 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1199 _primary = v->view()->create_region_view (r, false, false);
1201 _primary->get_canvas_group()->show ();
1202 _primary->set_position (pos, 0);
1203 _views.push_back (_primary);
1205 _last_frame_position = pos;
1207 _item = _primary->get_canvas_group ();
1208 _dest_trackview = v;
1209 _dest_layer = _primary->region()->layer ();
1212 map<RegionView*, pair<RouteTimeAxisView*, int> >
1213 RegionMotionDrag::find_time_axis_views_and_layers ()
1215 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1217 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1219 double ix1, ix2, iy1, iy2;
1220 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1221 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1222 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1224 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1225 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1233 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1235 _editor->update_canvas_now ();
1237 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1239 RouteTimeAxisView* dest_rtv = final[_primary].first;
1241 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1242 _primary->get_canvas_group()->property_y() = 0;
1244 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1246 _editor->begin_reversible_command (_("insert region"));
1247 XMLNode& before = playlist->get_state ();
1248 playlist->add_region (_primary->region (), _last_frame_position);
1249 _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1250 _editor->commit_reversible_command ();
1257 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1258 : RegionMoveDrag (e, i, p, v, false, false)
1263 struct RegionSelectionByPosition {
1264 bool operator() (RegionView*a, RegionView* b) {
1265 return a->region()->position () < b->region()->position();
1270 RegionSpliceDrag::motion (GdkEvent* /*event*/, bool)
1272 RouteTimeAxisView* tv;
1275 if (!check_possible (&tv, &layer)) {
1281 if (_current_pointer_x - _grab_x > 0) {
1287 RegionSelection copy (_editor->selection->regions);
1289 RegionSelectionByPosition cmp;
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 (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1315 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1321 playlist->shuffle ((*i)->region(), dir);
1323 _grab_x = _current_pointer_x;
1328 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1334 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1342 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1344 _dest_trackview = _view;
1346 Drag::start_grab (event);
1351 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1354 // TODO: create region-create-drag region view here
1357 // TODO: resize region-create-drag region view here
1361 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1363 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1369 if (!movement_occurred) {
1370 mtv->add_region (_grab_frame);
1372 motion (event, false);
1373 // TODO: create region-create-drag region here
1377 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1385 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1388 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1390 Drag::start_grab (event);
1392 region = &cnote->region_view();
1394 double region_start = region->get_position_pixels();
1395 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1397 if (_grab_x <= middle_point) {
1398 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1401 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1405 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1407 if (event->motion.state & Keyboard::PrimaryModifier) {
1413 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1415 if (ms.size() > 1) {
1416 /* has to be relative, may make no sense otherwise */
1420 region->note_selected (cnote, true);
1422 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1423 MidiRegionSelection::iterator next;
1426 (*r)->begin_resizing (at_front);
1432 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1434 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1435 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1436 (*r)->update_resizing (at_front, _current_pointer_x - _grab_x, relative);
1441 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1443 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1444 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1445 (*r)->commit_resizing (at_front, _current_pointer_x - _grab_x, relative);
1450 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1456 RegionGainDrag::finished (GdkEvent *, bool)
1461 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1462 : RegionDrag (e, i, p, v)
1468 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1471 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1472 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1474 if (tv && tv->is_track()) {
1475 speed = tv->get_diskstream()->speed();
1478 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1479 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1480 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1482 Drag::start_grab (event, _editor->trimmer_cursor);
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 (_current_pointer_frame < (region_start + region_length/2)) {
1489 /* closer to start */
1490 _operation = StartTrim;
1491 } else if (_current_pointer_frame > (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 (_current_pointer_frame, 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 if (_last_pointer_frame > _current_pointer_frame) {
1534 left_direction = true;
1536 left_direction = false;
1539 _editor->snap_to_with_modifier (_current_pointer_frame, event);
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 (_current_pointer_frame == _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 - _current_pointer_frame);
1590 frame_delta = (_current_pointer_frame - _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) && (_current_pointer_frame <= 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) && (_current_pointer_frame > (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)
1632 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1638 switch (_operation) {
1640 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1643 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1646 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1650 _last_pointer_frame = _current_pointer_frame;
1655 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1657 if (movement_occurred) {
1658 motion (event, false);
1660 if (!_editor->selection->selected (_primary)) {
1661 _editor->thaw_region_after_trim (*_primary);
1664 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1665 _editor->thaw_region_after_trim (**i);
1666 (*i)->fake_set_opaque (true);
1669 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1671 if (_have_transaction) {
1672 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1676 _editor->motion_frozen_playlists.clear ();
1678 if (_have_transaction) {
1679 _editor->commit_reversible_command();
1683 /* no mouse movement */
1684 _editor->point_trim (event);
1688 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1692 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1697 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1700 // create a dummy marker for visual representation of moving the copy.
1701 // The actual copying is not done before we reach the finish callback.
1703 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1704 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1705 *new MeterSection (_marker->meter()));
1707 _item = &new_marker->the_item ();
1708 _marker = new_marker;
1712 MetricSection& section (_marker->meter());
1714 if (!section.movable()) {
1720 Drag::start_grab (event, cursor);
1722 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1724 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1728 MeterMarkerDrag::motion (GdkEvent* event, bool)
1730 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1732 if (adjusted_frame == _last_pointer_frame) {
1736 _marker->set_position (adjusted_frame);
1738 _last_pointer_frame = adjusted_frame;
1740 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1744 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1746 if (!movement_occurred) {
1750 motion (event, false);
1754 TempoMap& map (_editor->session()->tempo_map());
1755 map.bbt_time (_last_pointer_frame, when);
1757 if (_copy == true) {
1758 _editor->begin_reversible_command (_("copy meter mark"));
1759 XMLNode &before = map.get_state();
1760 map.add_meter (_marker->meter(), when);
1761 XMLNode &after = map.get_state();
1762 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1763 _editor->commit_reversible_command ();
1765 // delete the dummy marker we used for visual representation of copying.
1766 // a new visual marker will show up automatically.
1769 _editor->begin_reversible_command (_("move meter mark"));
1770 XMLNode &before = map.get_state();
1771 map.move_meter (_marker->meter(), when);
1772 XMLNode &after = map.get_state();
1773 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1774 _editor->commit_reversible_command ();
1778 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1782 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1787 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1792 // create a dummy marker for visual representation of moving the copy.
1793 // The actual copying is not done before we reach the finish callback.
1795 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1796 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1797 *new TempoSection (_marker->tempo()));
1799 _item = &new_marker->the_item ();
1800 _marker = new_marker;
1804 MetricSection& section (_marker->tempo());
1806 if (!section.movable()) {
1811 Drag::start_grab (event, cursor);
1813 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1814 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1818 TempoMarkerDrag::motion (GdkEvent* event, bool)
1820 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1822 if (adjusted_frame == _last_pointer_frame) {
1826 /* OK, we've moved far enough to make it worth actually move the thing. */
1828 _marker->set_position (adjusted_frame);
1830 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1832 _last_pointer_frame = adjusted_frame;
1836 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1838 if (!movement_occurred) {
1842 motion (event, false);
1846 TempoMap& map (_editor->session()->tempo_map());
1847 map.bbt_time (_last_pointer_frame, when);
1849 if (_copy == true) {
1850 _editor->begin_reversible_command (_("copy tempo mark"));
1851 XMLNode &before = map.get_state();
1852 map.add_tempo (_marker->tempo(), when);
1853 XMLNode &after = map.get_state();
1854 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1855 _editor->commit_reversible_command ();
1857 // delete the dummy marker we used for visual representation of copying.
1858 // a new visual marker will show up automatically.
1861 _editor->begin_reversible_command (_("move tempo mark"));
1862 XMLNode &before = map.get_state();
1863 map.move_tempo (_marker->tempo(), when);
1864 XMLNode &after = map.get_state();
1865 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1866 _editor->commit_reversible_command ();
1871 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1875 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1880 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1882 Drag::start_grab (event, c);
1886 nframes64_t where = _editor->event_frame (event, 0, 0);
1888 _editor->snap_to_with_modifier (where, event);
1889 _editor->playhead_cursor->set_position (where);
1893 if (_cursor == _editor->playhead_cursor) {
1894 _editor->_dragging_playhead = true;
1896 if (_editor->session() && _was_rolling && _stop) {
1897 _editor->session()->request_stop ();
1900 if (_editor->session() && _editor->session()->is_auditioning()) {
1901 _editor->session()->cancel_audition ();
1905 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1909 CursorDrag::motion (GdkEvent* event, bool)
1911 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1913 if (adjusted_frame == _last_pointer_frame) {
1917 _cursor->set_position (adjusted_frame);
1919 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1922 _editor->update_canvas_now ();
1924 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1926 _last_pointer_frame = adjusted_frame;
1930 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1932 _editor->_dragging_playhead = false;
1934 if (!movement_occurred && _stop) {
1938 motion (event, false);
1940 if (_item == &_editor->playhead_cursor->canvas_item) {
1941 if (_editor->session()) {
1942 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1943 _editor->_pending_locate_request = true;
1948 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1949 : RegionDrag (e, i, p, v)
1955 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1957 Drag::start_grab (event, cursor);
1959 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1960 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1962 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1963 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
1967 FadeInDrag::motion (GdkEvent* event, bool)
1969 nframes64_t fade_length;
1971 nframes64_t const pos = adjusted_current_frame (event);
1973 boost::shared_ptr<Region> region = _primary->region ();
1975 if (pos < (region->position() + 64)) {
1976 fade_length = 64; // this should be a minimum defined somewhere
1977 } else if (pos > region->last_frame()) {
1978 fade_length = region->length();
1980 fade_length = pos - region->position();
1983 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1985 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1991 tmp->reset_fade_in_shape_width (fade_length);
1994 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1998 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2000 if (!movement_occurred) {
2004 nframes64_t fade_length;
2006 nframes64_t const pos = adjusted_current_frame (event);
2008 boost::shared_ptr<Region> region = _primary->region ();
2010 if (pos < (region->position() + 64)) {
2011 fade_length = 64; // this should be a minimum defined somewhere
2012 } else if (pos > region->last_frame()) {
2013 fade_length = region->length();
2015 fade_length = pos - region->position();
2018 _editor->begin_reversible_command (_("change fade in length"));
2020 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2022 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2028 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2029 XMLNode &before = alist->get_state();
2031 tmp->audio_region()->set_fade_in_length (fade_length);
2032 tmp->audio_region()->set_fade_in_active (true);
2034 XMLNode &after = alist->get_state();
2035 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2038 _editor->commit_reversible_command ();
2041 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2042 : RegionDrag (e, i, p, v)
2048 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2050 Drag::start_grab (event, cursor);
2052 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2053 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2055 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2056 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2060 FadeOutDrag::motion (GdkEvent* event, bool)
2062 nframes64_t fade_length;
2064 nframes64_t const pos = adjusted_current_frame (event);
2066 boost::shared_ptr<Region> region = _primary->region ();
2068 if (pos > (region->last_frame() - 64)) {
2069 fade_length = 64; // this should really be a minimum fade defined somewhere
2071 else if (pos < region->position()) {
2072 fade_length = region->length();
2075 fade_length = region->last_frame() - pos;
2078 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2080 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2086 tmp->reset_fade_out_shape_width (fade_length);
2089 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2093 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2095 if (!movement_occurred) {
2099 nframes64_t fade_length;
2101 nframes64_t const pos = adjusted_current_frame (event);
2103 boost::shared_ptr<Region> region = _primary->region ();
2105 if (pos > (region->last_frame() - 64)) {
2106 fade_length = 64; // this should really be a minimum fade defined somewhere
2108 else if (pos < region->position()) {
2109 fade_length = region->length();
2112 fade_length = region->last_frame() - pos;
2115 _editor->begin_reversible_command (_("change fade out length"));
2117 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2119 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2125 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2126 XMLNode &before = alist->get_state();
2128 tmp->audio_region()->set_fade_out_length (fade_length);
2129 tmp->audio_region()->set_fade_out_active (true);
2131 XMLNode &after = alist->get_state();
2132 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2135 _editor->commit_reversible_command ();
2138 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2141 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2144 _points.push_back (Gnome::Art::Point (0, 0));
2145 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2147 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2148 _line->property_width_pixels() = 1;
2149 _line->property_points () = _points;
2152 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2155 MarkerDrag::~MarkerDrag ()
2157 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2163 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2165 Drag::start_grab (event, cursor);
2169 Location *location = _editor->find_location_from_marker (_marker, is_start);
2170 _editor->_dragging_edit_point = true;
2172 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2174 update_item (location);
2176 // _drag_line->show();
2177 // _line->raise_to_top();
2180 _editor->show_verbose_time_cursor (location->start(), 10);
2182 _editor->show_verbose_time_cursor (location->end(), 10);
2185 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2188 case Selection::Toggle:
2189 _editor->selection->toggle (_marker);
2191 case Selection::Set:
2192 if (!_editor->selection->selected (_marker)) {
2193 _editor->selection->set (_marker);
2196 case Selection::Extend:
2198 Locations::LocationList ll;
2199 list<Marker*> to_add;
2201 _editor->selection->markers.range (s, e);
2202 s = min (_marker->position(), s);
2203 e = max (_marker->position(), e);
2206 if (e < max_frames) {
2209 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2210 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2211 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2214 to_add.push_back (lm->start);
2217 to_add.push_back (lm->end);
2221 if (!to_add.empty()) {
2222 _editor->selection->add (to_add);
2226 case Selection::Add:
2227 _editor->selection->add (_marker);
2231 /* set up copies for us to manipulate during the drag */
2233 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2234 Location *l = _editor->find_location_from_marker (*i, is_start);
2235 _copied_locations.push_back (new Location (*l));
2240 MarkerDrag::motion (GdkEvent* event, bool)
2242 nframes64_t f_delta = 0;
2244 bool move_both = false;
2246 Location *real_location;
2247 Location *copy_location = 0;
2249 nframes64_t const newframe = adjusted_current_frame (event);
2251 nframes64_t next = newframe;
2253 if (_current_pointer_frame == _last_pointer_frame) {
2257 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2261 MarkerSelection::iterator i;
2262 list<Location*>::iterator x;
2264 /* find the marker we're dragging, and compute the delta */
2266 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2267 x != _copied_locations.end() && i != _editor->selection->markers.end();
2273 if (marker == _marker) {
2275 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2280 if (real_location->is_mark()) {
2281 f_delta = newframe - copy_location->start();
2285 switch (marker->type()) {
2287 case Marker::LoopStart:
2288 case Marker::PunchIn:
2289 f_delta = newframe - copy_location->start();
2293 case Marker::LoopEnd:
2294 case Marker::PunchOut:
2295 f_delta = newframe - copy_location->end();
2298 /* what kind of marker is this ? */
2306 if (i == _editor->selection->markers.end()) {
2307 /* hmm, impossible - we didn't find the dragged marker */
2311 /* now move them all */
2313 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2314 x != _copied_locations.end() && i != _editor->selection->markers.end();
2320 /* call this to find out if its the start or end */
2322 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2326 if (real_location->locked()) {
2330 if (copy_location->is_mark()) {
2334 copy_location->set_start (copy_location->start() + f_delta);
2338 nframes64_t new_start = copy_location->start() + f_delta;
2339 nframes64_t new_end = copy_location->end() + f_delta;
2341 if (is_start) { // start-of-range marker
2344 copy_location->set_start (new_start);
2345 copy_location->set_end (new_end);
2346 } else if (new_start < copy_location->end()) {
2347 copy_location->set_start (new_start);
2349 _editor->snap_to (next, 1, true);
2350 copy_location->set_end (next);
2351 copy_location->set_start (newframe);
2354 } else { // end marker
2357 copy_location->set_end (new_end);
2358 copy_location->set_start (new_start);
2359 } else if (new_end > copy_location->start()) {
2360 copy_location->set_end (new_end);
2361 } else if (newframe > 0) {
2362 _editor->snap_to (next, -1, true);
2363 copy_location->set_start (next);
2364 copy_location->set_end (newframe);
2369 update_item (copy_location);
2371 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2374 lm->set_position (copy_location->start(), copy_location->end());
2378 _last_pointer_frame = _current_pointer_frame;
2380 assert (!_copied_locations.empty());
2382 _editor->show_verbose_time_cursor (newframe, 10);
2385 _editor->update_canvas_now ();
2390 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2392 if (!movement_occurred) {
2394 /* just a click, do nothing but finish
2395 off the selection process
2398 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2401 case Selection::Set:
2402 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2403 _editor->selection->set (_marker);
2407 case Selection::Toggle:
2408 case Selection::Extend:
2409 case Selection::Add:
2416 _editor->_dragging_edit_point = false;
2418 _editor->begin_reversible_command ( _("move marker") );
2419 XMLNode &before = _editor->session()->locations()->get_state();
2421 MarkerSelection::iterator i;
2422 list<Location*>::iterator x;
2425 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2426 x != _copied_locations.end() && i != _editor->selection->markers.end();
2429 Location * location = _editor->find_location_from_marker (*i, is_start);
2433 if (location->locked()) {
2437 if (location->is_mark()) {
2438 location->set_start ((*x)->start());
2440 location->set ((*x)->start(), (*x)->end());
2445 XMLNode &after = _editor->session()->locations()->get_state();
2446 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2447 _editor->commit_reversible_command ();
2453 MarkerDrag::update_item (Location* location)
2455 double const x1 = _editor->frame_to_pixel (location->start());
2457 _points.front().set_x(x1);
2458 _points.back().set_x(x1);
2459 _line->property_points() = _points;
2462 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2464 _cumulative_x_drag (0),
2465 _cumulative_y_drag (0)
2467 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2473 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2475 Drag::start_grab (event, _editor->fader_cursor);
2477 // start the grab at the center of the control point so
2478 // the point doesn't 'jump' to the mouse after the first drag
2479 _grab_x = _point->get_x();
2480 _grab_y = _point->get_y();
2482 _point->line().parent_group().i2w (_grab_x, _grab_y);
2483 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2485 _grab_frame = _editor->pixel_to_frame (_grab_x);
2487 _point->line().start_drag (_point, _grab_frame, 0);
2489 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2490 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2491 _current_pointer_x + 10, _current_pointer_y + 10);
2493 _editor->show_verbose_canvas_cursor ();
2497 ControlPointDrag::motion (GdkEvent* event, bool)
2499 double dx = _current_pointer_x - _last_pointer_x;
2500 double dy = _current_pointer_y - _last_pointer_y;
2502 if (event->button.state & Keyboard::SecondaryModifier) {
2507 double cx = _grab_x + _cumulative_x_drag + dx;
2508 double cy = _grab_y + _cumulative_y_drag + dy;
2510 // calculate zero crossing point. back off by .01 to stay on the
2511 // positive side of zero
2513 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2514 _point->line().parent_group().i2w(_unused, zero_gain_y);
2516 // make sure we hit zero when passing through
2517 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2518 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2522 if (_x_constrained) {
2525 if (_y_constrained) {
2529 _cumulative_x_drag = cx - _grab_x;
2530 _cumulative_y_drag = cy - _grab_y;
2532 _point->line().parent_group().w2i (cx, cy);
2536 cy = min ((double) _point->line().height(), cy);
2538 //translate cx to frames
2539 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2541 if (!_x_constrained) {
2542 _editor->snap_to_with_modifier (cx_frames, event);
2545 float const fraction = 1.0 - (cy / _point->line().height());
2547 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2549 _point->line().point_drag (*_point, cx_frames, fraction, push);
2551 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2555 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2557 if (!movement_occurred) {
2561 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2562 _editor->reset_point_selection ();
2566 motion (event, false);
2568 _point->line().end_drag (_point);
2572 ControlPointDrag::active (Editing::MouseMode m)
2574 if (m == Editing::MouseGain) {
2575 /* always active in mouse gain */
2579 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2580 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2583 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2586 _cumulative_y_drag (0)
2591 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2593 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2596 _item = &_line->grab_item ();
2598 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2599 origin, and ditto for y.
2602 double cx = event->button.x;
2603 double cy = event->button.y;
2605 _line->parent_group().w2i (cx, cy);
2607 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2609 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2610 /* no adjacent points */
2614 Drag::start_grab (event, _editor->fader_cursor);
2616 /* store grab start in parent frame */
2621 double fraction = 1.0 - (cy / _line->height());
2623 _line->start_drag (0, _grab_frame, fraction);
2625 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2626 _current_pointer_x + 10, _current_pointer_y + 10);
2628 _editor->show_verbose_canvas_cursor ();
2632 LineDrag::motion (GdkEvent* event, bool)
2634 double dy = _current_pointer_y - _last_pointer_y;
2636 if (event->button.state & Keyboard::SecondaryModifier) {
2640 double cy = _grab_y + _cumulative_y_drag + dy;
2642 _cumulative_y_drag = cy - _grab_y;
2645 cy = min ((double) _line->height(), cy);
2647 double const fraction = 1.0 - (cy / _line->height());
2651 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2657 _line->line_drag (_before, _after, fraction, push);
2659 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2663 LineDrag::finished (GdkEvent* event, bool)
2665 motion (event, false);
2666 _line->end_drag (0);
2670 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2672 Drag::start_grab (event);
2673 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2677 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2684 /* use a bigger drag threshold than the default */
2686 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2690 if (Config->get_rubberbanding_snaps_to_grid()) {
2692 _editor->snap_to_with_modifier (_grab_frame, event);
2694 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2697 /* base start and end on initial click position */
2699 if (_current_pointer_frame < _grab_frame) {
2700 start = _current_pointer_frame;
2703 end = _current_pointer_frame;
2704 start = _grab_frame;
2707 if (_current_pointer_y < _grab_y) {
2708 y1 = _current_pointer_y;
2711 y2 = _current_pointer_y;
2716 if (start != end || y1 != y2) {
2718 double x1 = _editor->frame_to_pixel (start);
2719 double x2 = _editor->frame_to_pixel (end);
2721 _editor->rubberband_rect->property_x1() = x1;
2722 _editor->rubberband_rect->property_y1() = y1;
2723 _editor->rubberband_rect->property_x2() = x2;
2724 _editor->rubberband_rect->property_y2() = y2;
2726 _editor->rubberband_rect->show();
2727 _editor->rubberband_rect->raise_to_top();
2729 _last_pointer_frame = _current_pointer_frame;
2731 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2736 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2738 if (movement_occurred) {
2740 motion (event, false);
2743 if (_current_pointer_y < _grab_y) {
2744 y1 = _current_pointer_y;
2747 y2 = _current_pointer_y;
2752 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2755 _editor->begin_reversible_command (_("rubberband selection"));
2757 if (_grab_frame < _last_pointer_frame) {
2758 committed = _editor->select_all_within (_grab_frame, _last_pointer_frame - 1, y1, y2, _editor->track_views, op);
2760 committed = _editor->select_all_within (_last_pointer_frame, _grab_frame - 1, y1, y2, _editor->track_views, op);
2764 _editor->commit_reversible_command ();
2768 if (!getenv("ARDOUR_SAE")) {
2769 _editor->selection->clear_tracks();
2771 _editor->selection->clear_regions();
2772 _editor->selection->clear_points ();
2773 _editor->selection->clear_lines ();
2776 _editor->rubberband_rect->hide();
2780 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2782 Drag::start_grab (event);
2784 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2788 TimeFXDrag::motion (GdkEvent* event, bool)
2790 RegionView* rv = _primary;
2792 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2794 if (_current_pointer_frame == _last_pointer_frame) {
2798 if (_current_pointer_frame > rv->region()->position()) {
2799 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2802 _last_pointer_frame = _current_pointer_frame;
2804 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2808 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2810 _primary->get_time_axis_view().hide_timestretch ();
2812 if (!movement_occurred) {
2816 if (_last_pointer_frame < _primary->region()->position()) {
2817 /* backwards drag of the left edge - not usable */
2821 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2823 float percentage = (double) newlen / (double) _primary->region()->length();
2825 #ifndef USE_RUBBERBAND
2826 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2827 if (_primary->region()->data_type() == DataType::AUDIO) {
2828 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2832 _editor->begin_reversible_command (_("timestretch"));
2834 // XXX how do timeFX on multiple regions ?
2839 if (!_editor->time_stretch (rs, percentage) == 0) {
2840 error << _("An error occurred while executing time stretch operation") << endmsg;
2845 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2847 Drag::start_grab (event);
2851 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2857 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2859 if (movement_occurred && _editor->session()) {
2860 /* make sure we stop */
2861 _editor->session()->request_transport_speed (0.0);
2865 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2874 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2876 nframes64_t start = 0;
2877 nframes64_t end = 0;
2879 if (_editor->session() == 0) {
2883 Gdk::Cursor* cursor = 0;
2885 switch (_operation) {
2886 case CreateSelection:
2887 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2892 cursor = _editor->selector_cursor;
2893 Drag::start_grab (event, cursor);
2896 case SelectionStartTrim:
2897 if (_editor->clicked_axisview) {
2898 _editor->clicked_axisview->order_selection_trims (_item, true);
2900 Drag::start_grab (event, cursor);
2901 cursor = _editor->trimmer_cursor;
2902 start = _editor->selection->time[_editor->clicked_selection].start;
2903 _pointer_frame_offset = _grab_frame - start;
2906 case SelectionEndTrim:
2907 if (_editor->clicked_axisview) {
2908 _editor->clicked_axisview->order_selection_trims (_item, false);
2910 Drag::start_grab (event, cursor);
2911 cursor = _editor->trimmer_cursor;
2912 end = _editor->selection->time[_editor->clicked_selection].end;
2913 _pointer_frame_offset = _grab_frame - end;
2917 start = _editor->selection->time[_editor->clicked_selection].start;
2918 Drag::start_grab (event, cursor);
2919 _pointer_frame_offset = _grab_frame - start;
2923 if (_operation == SelectionMove) {
2924 _editor->show_verbose_time_cursor (start, 10);
2926 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2931 SelectionDrag::motion (GdkEvent* event, bool first_move)
2933 nframes64_t start = 0;
2934 nframes64_t end = 0;
2937 nframes64_t const pending_position = adjusted_current_frame (event);
2939 /* only alter selection if the current frame is
2940 different from the last frame position (adjusted)
2943 if (pending_position == _last_pointer_frame) {
2947 switch (_operation) {
2948 case CreateSelection:
2951 _editor->snap_to (_grab_frame);
2954 if (pending_position < _grab_frame) {
2955 start = pending_position;
2958 end = pending_position;
2959 start = _grab_frame;
2962 /* first drag: Either add to the selection
2963 or create a new selection
2968 _editor->begin_reversible_command (_("range selection"));
2969 _have_transaction = true;
2972 /* adding to the selection */
2973 _editor->selection->add (_editor->clicked_axisview);
2974 _editor->clicked_selection = _editor->selection->add (start, end);
2979 if (!_editor->selection->selected (_editor->clicked_axisview)) {
2980 _editor->selection->set (_editor->clicked_axisview);
2983 _editor->clicked_selection = _editor->selection->set (start, end);
2988 case SelectionStartTrim:
2991 _editor->begin_reversible_command (_("trim selection start"));
2992 _have_transaction = true;
2995 start = _editor->selection->time[_editor->clicked_selection].start;
2996 end = _editor->selection->time[_editor->clicked_selection].end;
2998 if (pending_position > end) {
3001 start = pending_position;
3005 case SelectionEndTrim:
3008 _editor->begin_reversible_command (_("trim selection end"));
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 < start) {
3018 end = pending_position;
3026 _editor->begin_reversible_command (_("move selection"));
3027 _have_transaction = true;
3030 start = _editor->selection->time[_editor->clicked_selection].start;
3031 end = _editor->selection->time[_editor->clicked_selection].end;
3033 length = end - start;
3035 start = pending_position;
3036 _editor->snap_to (start);
3038 end = start + length;
3043 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3044 _editor->start_canvas_autoscroll (1, 0);
3048 _editor->selection->replace (_editor->clicked_selection, start, end);
3051 _last_pointer_frame = pending_position;
3053 if (_operation == SelectionMove) {
3054 _editor->show_verbose_time_cursor(start, 10);
3056 _editor->show_verbose_time_cursor(pending_position, 10);
3061 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3063 Session* s = _editor->session();
3065 if (movement_occurred) {
3066 motion (event, false);
3067 /* XXX this is not object-oriented programming at all. ick */
3068 if (_editor->selection->time.consolidate()) {
3069 _editor->selection->TimeChanged ();
3072 if (_have_transaction) {
3073 _editor->commit_reversible_command ();
3076 /* XXX what if its a music time selection? */
3077 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3078 s->request_play_range (&_editor->selection->time, true);
3083 /* just a click, no pointer movement.*/
3085 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3086 _editor->selection->clear_time();
3089 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3090 _editor->selection->set (_editor->clicked_axisview);
3093 if (s && s->get_play_range () && s->transport_rolling()) {
3094 s->request_stop (false, false);
3099 _editor->stop_canvas_autoscroll ();
3102 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3107 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3108 _drag_rect->hide ();
3110 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3111 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3115 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3117 if (_editor->session() == 0) {
3121 Gdk::Cursor* cursor = 0;
3123 if (!_editor->temp_location) {
3124 _editor->temp_location = new Location;
3127 switch (_operation) {
3128 case CreateRangeMarker:
3129 case CreateTransportMarker:
3130 case CreateCDMarker:
3132 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3137 cursor = _editor->selector_cursor;
3141 Drag::start_grab (event, cursor);
3143 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3147 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3149 nframes64_t start = 0;
3150 nframes64_t end = 0;
3151 ArdourCanvas::SimpleRect *crect;
3153 switch (_operation) {
3154 case CreateRangeMarker:
3155 crect = _editor->range_bar_drag_rect;
3157 case CreateTransportMarker:
3158 crect = _editor->transport_bar_drag_rect;
3160 case CreateCDMarker:
3161 crect = _editor->cd_marker_bar_drag_rect;
3164 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3169 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3171 /* only alter selection if the current frame is
3172 different from the last frame position.
3175 if (_current_pointer_frame == _last_pointer_frame) {
3179 switch (_operation) {
3180 case CreateRangeMarker:
3181 case CreateTransportMarker:
3182 case CreateCDMarker:
3184 _editor->snap_to (_grab_frame);
3187 if (_current_pointer_frame < _grab_frame) {
3188 start = _current_pointer_frame;
3191 end = _current_pointer_frame;
3192 start = _grab_frame;
3195 /* first drag: Either add to the selection
3196 or create a new selection.
3201 _editor->temp_location->set (start, end);
3205 update_item (_editor->temp_location);
3207 //_drag_rect->raise_to_top();
3213 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3214 _editor->start_canvas_autoscroll (1, 0);
3218 _editor->temp_location->set (start, end);
3220 double x1 = _editor->frame_to_pixel (start);
3221 double x2 = _editor->frame_to_pixel (end);
3222 crect->property_x1() = x1;
3223 crect->property_x2() = x2;
3225 update_item (_editor->temp_location);
3228 _last_pointer_frame = _current_pointer_frame;
3230 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3235 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3237 Location * newloc = 0;
3241 if (movement_occurred) {
3242 motion (event, false);
3245 switch (_operation) {
3246 case CreateRangeMarker:
3247 case CreateCDMarker:
3249 _editor->begin_reversible_command (_("new range marker"));
3250 XMLNode &before = _editor->session()->locations()->get_state();
3251 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3252 if (_operation == CreateCDMarker) {
3253 flags = Location::IsRangeMarker | Location::IsCDMarker;
3254 _editor->cd_marker_bar_drag_rect->hide();
3257 flags = Location::IsRangeMarker;
3258 _editor->range_bar_drag_rect->hide();
3260 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3261 _editor->session()->locations()->add (newloc, true);
3262 XMLNode &after = _editor->session()->locations()->get_state();
3263 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3264 _editor->commit_reversible_command ();
3268 case CreateTransportMarker:
3269 // popup menu to pick loop or punch
3270 _editor->new_transport_marker_context_menu (&event->button, _item);
3274 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3276 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3281 _editor->session()->locations()->marks_either_side (_grab_frame, start, end);
3283 if (end == max_frames) {
3284 end = _editor->session()->current_end_frame ();
3287 if (start == max_frames) {
3288 start = _editor->session()->current_start_frame ();
3291 switch (_editor->mouse_mode) {
3293 /* find the two markers on either side and then make the selection from it */
3294 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3298 /* find the two markers on either side of the click and make the range out of it */
3299 _editor->selection->set (start, end);
3308 _editor->stop_canvas_autoscroll ();
3314 RangeMarkerBarDrag::update_item (Location* location)
3316 double const x1 = _editor->frame_to_pixel (location->start());
3317 double const x2 = _editor->frame_to_pixel (location->end());
3319 _drag_rect->property_x1() = x1;
3320 _drag_rect->property_x2() = x2;
3324 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3326 Drag::start_grab (event, _editor->zoom_cursor);
3327 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3331 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3336 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3339 _editor->snap_to_with_modifier (_grab_frame, event);
3342 if (_current_pointer_frame == _last_pointer_frame) {
3346 /* base start and end on initial click position */
3347 if (_current_pointer_frame < _grab_frame) {
3348 start = _current_pointer_frame;
3351 end = _current_pointer_frame;
3352 start = _grab_frame;
3358 _editor->zoom_rect->show();
3359 _editor->zoom_rect->raise_to_top();
3362 _editor->reposition_zoom_rect(start, end);
3364 _last_pointer_frame = _current_pointer_frame;
3366 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3371 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3373 if (movement_occurred) {
3374 motion (event, false);
3376 if (_grab_frame < _last_pointer_frame) {
3377 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3379 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3382 _editor->temporal_zoom_to_frame (false, _grab_frame);
3384 temporal_zoom_step (false);
3385 center_screen (_grab_frame);
3389 _editor->zoom_rect->hide();
3392 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3395 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3396 region = &cnote->region_view();
3400 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3402 Drag::start_grab (event);
3405 drag_delta_note = 0;
3410 event_x = _current_pointer_x;
3411 event_y = _current_pointer_y;
3413 _item->property_parent().get_value()->w2i(event_x, event_y);
3415 last_x = region->snap_to_pixel(event_x);
3418 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3420 if (!(was_selected = cnote->selected())) {
3422 /* tertiary-click means extend selection - we'll do that on button release,
3423 so don't add it here, because otherwise we make it hard to figure
3424 out the "extend-to" range.
3427 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3430 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3433 region->note_selected (cnote, true);
3435 region->unique_select (cnote);
3442 NoteDrag::motion (GdkEvent*, bool)
3444 MidiStreamView* streamview = region->midi_stream_view();
3448 event_x = _current_pointer_x;
3449 event_y = _current_pointer_y;
3451 _item->property_parent().get_value()->w2i(event_x, event_y);
3453 event_x = region->snap_to_pixel(event_x);
3455 double dx = event_x - last_x;
3456 double dy = event_y - last_y;
3461 // Snap to note rows
3463 if (abs (dy) < streamview->note_height()) {
3466 int8_t this_delta_note;
3468 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3470 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3472 drag_delta_note -= this_delta_note;
3473 dy = streamview->note_height() * this_delta_note;
3474 last_y = last_y + dy;
3478 region->move_selection (dx, dy);
3480 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3482 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3483 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3484 _editor->show_verbose_canvas_cursor_with (buf);
3489 NoteDrag::finished (GdkEvent* ev, bool moved)
3491 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3494 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3497 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3499 region->note_deselected (cnote);
3502 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3503 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3505 if (!extend && !add && region->selection_size() > 1) {
3506 region->unique_select(cnote);
3507 } else if (extend) {
3508 region->note_selected (cnote, true, true);
3510 /* it was added during button press */
3515 region->note_dropped (cnote, drag_delta_x, drag_delta_note);