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 "control_point.h"
35 #include "region_gain_line.h"
36 #include "editor_drag.h"
37 #include "audio_time_axis.h"
38 #include "midi_time_axis.h"
39 #include "canvas-note.h"
40 #include "selection.h"
41 #include "midi_selection.h"
44 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 (mem_fun (*this, &RegionDrag::region_going_away));
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 (Editor::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 (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;
2938 nframes64_t const pending_position = adjusted_current_frame (event);
2940 /* only alter selection if the current frame is
2941 different from the last frame position (adjusted)
2944 if (pending_position == _last_pointer_frame) {
2948 switch (_operation) {
2949 case CreateSelection:
2952 _editor->snap_to (_grab_frame);
2955 if (pending_position < _grab_frame) {
2956 start = pending_position;
2959 end = pending_position;
2960 start = _grab_frame;
2963 /* first drag: Either add to the selection
2964 or create a new selection->
2969 _editor->begin_reversible_command (_("range selection"));
2970 _have_transaction = true;
2973 /* adding to the selection */
2974 _editor->clicked_selection = _editor->selection->add (start, end);
2977 /* new selection-> */
2978 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2983 case SelectionStartTrim:
2986 _editor->begin_reversible_command (_("trim selection start"));
2987 _have_transaction = true;
2990 start = _editor->selection->time[_editor->clicked_selection].start;
2991 end = _editor->selection->time[_editor->clicked_selection].end;
2993 if (pending_position > end) {
2996 start = pending_position;
3000 case SelectionEndTrim:
3003 _editor->begin_reversible_command (_("trim selection end"));
3004 _have_transaction = true;
3007 start = _editor->selection->time[_editor->clicked_selection].start;
3008 end = _editor->selection->time[_editor->clicked_selection].end;
3010 if (pending_position < start) {
3013 end = pending_position;
3021 _editor->begin_reversible_command (_("move selection"));
3022 _have_transaction = true;
3025 start = _editor->selection->time[_editor->clicked_selection].start;
3026 end = _editor->selection->time[_editor->clicked_selection].end;
3028 length = end - start;
3030 start = pending_position;
3031 _editor->snap_to (start);
3033 end = start + length;
3038 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3039 _editor->start_canvas_autoscroll (1, 0);
3043 _editor->selection->replace (_editor->clicked_selection, start, end);
3046 _last_pointer_frame = pending_position;
3048 if (_operation == SelectionMove) {
3049 _editor->show_verbose_time_cursor(start, 10);
3051 _editor->show_verbose_time_cursor(pending_position, 10);
3056 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3058 Session* s = _editor->session;
3060 if (movement_occurred) {
3061 motion (event, false);
3062 /* XXX this is not object-oriented programming at all. ick */
3063 if (_editor->selection->time.consolidate()) {
3064 _editor->selection->TimeChanged ();
3067 if (_have_transaction) {
3068 _editor->commit_reversible_command ();
3071 /* XXX what if its a music time selection? */
3072 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3073 s->request_play_range (&_editor->selection->time, true);
3078 /* just a click, no pointer movement.*/
3080 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3082 _editor->selection->clear_time();
3086 if (s && s->get_play_range () && s->transport_rolling()) {
3087 s->request_stop (false, false);
3092 _editor->stop_canvas_autoscroll ();
3095 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3100 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3101 _drag_rect->hide ();
3103 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3104 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3108 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3110 if (_editor->session == 0) {
3114 Gdk::Cursor* cursor = 0;
3116 if (!_editor->temp_location) {
3117 _editor->temp_location = new Location;
3120 switch (_operation) {
3121 case CreateRangeMarker:
3122 case CreateTransportMarker:
3123 case CreateCDMarker:
3125 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3130 cursor = _editor->selector_cursor;
3134 Drag::start_grab (event, cursor);
3136 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3140 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3142 nframes64_t start = 0;
3143 nframes64_t end = 0;
3144 ArdourCanvas::SimpleRect *crect;
3146 switch (_operation) {
3147 case CreateRangeMarker:
3148 crect = _editor->range_bar_drag_rect;
3150 case CreateTransportMarker:
3151 crect = _editor->transport_bar_drag_rect;
3153 case CreateCDMarker:
3154 crect = _editor->cd_marker_bar_drag_rect;
3157 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3162 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3164 /* only alter selection if the current frame is
3165 different from the last frame position.
3168 if (_current_pointer_frame == _last_pointer_frame) {
3172 switch (_operation) {
3173 case CreateRangeMarker:
3174 case CreateTransportMarker:
3175 case CreateCDMarker:
3177 _editor->snap_to (_grab_frame);
3180 if (_current_pointer_frame < _grab_frame) {
3181 start = _current_pointer_frame;
3184 end = _current_pointer_frame;
3185 start = _grab_frame;
3188 /* first drag: Either add to the selection
3189 or create a new selection.
3194 _editor->temp_location->set (start, end);
3198 update_item (_editor->temp_location);
3200 //_drag_rect->raise_to_top();
3206 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3207 _editor->start_canvas_autoscroll (1, 0);
3211 _editor->temp_location->set (start, end);
3213 double x1 = _editor->frame_to_pixel (start);
3214 double x2 = _editor->frame_to_pixel (end);
3215 crect->property_x1() = x1;
3216 crect->property_x2() = x2;
3218 update_item (_editor->temp_location);
3221 _last_pointer_frame = _current_pointer_frame;
3223 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3228 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3230 Location * newloc = 0;
3234 if (movement_occurred) {
3235 motion (event, false);
3238 switch (_operation) {
3239 case CreateRangeMarker:
3240 case CreateCDMarker:
3242 _editor->begin_reversible_command (_("new range marker"));
3243 XMLNode &before = _editor->session->locations()->get_state();
3244 _editor->session->locations()->next_available_name(rangename,"unnamed");
3245 if (_operation == CreateCDMarker) {
3246 flags = Location::IsRangeMarker | Location::IsCDMarker;
3247 _editor->cd_marker_bar_drag_rect->hide();
3250 flags = Location::IsRangeMarker;
3251 _editor->range_bar_drag_rect->hide();
3253 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3254 _editor->session->locations()->add (newloc, true);
3255 XMLNode &after = _editor->session->locations()->get_state();
3256 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3257 _editor->commit_reversible_command ();
3261 case CreateTransportMarker:
3262 // popup menu to pick loop or punch
3263 _editor->new_transport_marker_context_menu (&event->button, _item);
3267 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3269 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3274 _editor->session->locations()->marks_either_side (_grab_frame, start, end);
3276 if (end == max_frames) {
3277 end = _editor->session->current_end_frame ();
3280 if (start == max_frames) {
3281 start = _editor->session->current_start_frame ();
3284 switch (_editor->mouse_mode) {
3286 /* find the two markers on either side and then make the selection from it */
3287 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3291 /* find the two markers on either side of the click and make the range out of it */
3292 _editor->selection->set (0, start, end);
3301 _editor->stop_canvas_autoscroll ();
3307 RangeMarkerBarDrag::update_item (Location* location)
3309 double const x1 = _editor->frame_to_pixel (location->start());
3310 double const x2 = _editor->frame_to_pixel (location->end());
3312 _drag_rect->property_x1() = x1;
3313 _drag_rect->property_x2() = x2;
3317 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3319 Drag::start_grab (event, _editor->zoom_cursor);
3320 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3324 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3329 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3332 _editor->snap_to_with_modifier (_grab_frame, event);
3335 if (_current_pointer_frame == _last_pointer_frame) {
3339 /* base start and end on initial click position */
3340 if (_current_pointer_frame < _grab_frame) {
3341 start = _current_pointer_frame;
3344 end = _current_pointer_frame;
3345 start = _grab_frame;
3351 _editor->zoom_rect->show();
3352 _editor->zoom_rect->raise_to_top();
3355 _editor->reposition_zoom_rect(start, end);
3357 _last_pointer_frame = _current_pointer_frame;
3359 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3364 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3366 if (movement_occurred) {
3367 motion (event, false);
3369 if (_grab_frame < _last_pointer_frame) {
3370 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3372 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3375 _editor->temporal_zoom_to_frame (false, _grab_frame);
3377 temporal_zoom_step (false);
3378 center_screen (_grab_frame);
3382 _editor->zoom_rect->hide();
3385 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3388 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3389 region = &cnote->region_view();
3393 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3395 Drag::start_grab (event);
3398 drag_delta_note = 0;
3403 event_x = _current_pointer_x;
3404 event_y = _current_pointer_y;
3406 _item->property_parent().get_value()->w2i(event_x, event_y);
3408 last_x = region->snap_to_pixel(event_x);
3411 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3413 if (!(was_selected = cnote->selected())) {
3415 /* tertiary-click means extend selection - we'll do that on button release,
3416 so don't add it here, because otherwise we make it hard to figure
3417 out the "extend-to" range.
3420 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3423 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3426 region->note_selected (cnote, true);
3428 region->unique_select (cnote);
3435 NoteDrag::motion (GdkEvent*, bool)
3437 MidiStreamView* streamview = region->midi_stream_view();
3441 event_x = _current_pointer_x;
3442 event_y = _current_pointer_y;
3444 _item->property_parent().get_value()->w2i(event_x, event_y);
3446 event_x = region->snap_to_pixel(event_x);
3448 double dx = event_x - last_x;
3449 double dy = event_y - last_y;
3454 // Snap to note rows
3456 if (abs (dy) < streamview->note_height()) {
3459 int8_t this_delta_note;
3461 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3463 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3465 drag_delta_note -= this_delta_note;
3466 dy = streamview->note_height() * this_delta_note;
3467 last_y = last_y + dy;
3471 region->move_selection (dx, dy);
3473 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3475 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3476 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3477 _editor->show_verbose_canvas_cursor_with (buf);
3482 NoteDrag::finished (GdkEvent* ev, bool moved)
3484 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3487 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3490 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3492 region->note_deselected (cnote);
3495 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3496 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3498 if (!extend && !add && region->selection_size() > 1) {
3499 region->unique_select(cnote);
3500 } else if (extend) {
3501 region->note_selected (cnote, true, true);
3503 /* it was added during button press */
3508 region->note_dropped (cnote, drag_delta_x, drag_delta_note);