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 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
53 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
56 , _pointer_frame_offset (0)
58 , _last_pointer_frame (0)
59 , _current_pointer_frame (0)
60 , _have_transaction (false)
61 , _had_movement (false)
62 , _move_threshold_passed (false)
68 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
74 cursor = _editor->which_grabber_cursor ();
77 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
81 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
84 cursor = _editor->which_grabber_cursor ();
87 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
89 if (Keyboard::is_button2_event (&event->button)) {
90 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
91 _y_constrained = true;
92 _x_constrained = false;
94 _y_constrained = false;
95 _x_constrained = true;
98 _x_constrained = false;
99 _y_constrained = false;
102 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
103 _last_pointer_frame = _grab_frame;
104 _current_pointer_frame = _grab_frame;
105 _current_pointer_x = _grab_x;
106 _current_pointer_y = _grab_y;
107 _last_pointer_x = _current_pointer_x;
108 _last_pointer_y = _current_pointer_y;
112 _item->i2w (_original_x, _original_y);
114 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
118 if (_editor->session && _editor->session->transport_rolling()) {
121 _was_rolling = false;
124 switch (_editor->snap_type()) {
125 case SnapToRegionStart:
126 case SnapToRegionEnd:
127 case SnapToRegionSync:
128 case SnapToRegionBoundary:
129 _editor->build_region_boundary_cache ();
136 /** @param event GDK event, or 0.
137 * @return true if some movement occurred, otherwise false.
140 Drag::end_grab (GdkEvent* event)
144 _editor->stop_canvas_autoscroll ();
146 _item->ungrab (event ? event->button.time : 0);
148 _last_pointer_x = _current_pointer_x;
149 _last_pointer_y = _current_pointer_y;
150 finished (event, _had_movement);
152 _editor->hide_verbose_canvas_cursor();
156 return _had_movement;
160 Drag::adjusted_current_frame (GdkEvent* event) const
164 if (_current_pointer_frame > _pointer_frame_offset) {
165 pos = _current_pointer_frame - _pointer_frame_offset;
168 _editor->snap_to_with_modifier (pos, event);
174 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
176 _last_pointer_x = _current_pointer_x;
177 _last_pointer_y = _current_pointer_y;
178 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
180 if (!from_autoscroll && !_move_threshold_passed) {
182 bool const xp = (::llabs ((nframes64_t) (_current_pointer_x - _grab_x)) > 4LL);
183 bool const yp = (::llabs ((nframes64_t) (_current_pointer_y - _grab_y)) > 4LL);
185 _move_threshold_passed = (xp || yp);
187 if (apply_move_threshold() && _move_threshold_passed) {
189 _grab_frame = _current_pointer_frame;
190 _grab_x = _current_pointer_x;
191 _grab_y = _current_pointer_y;
192 _last_pointer_frame = _grab_frame;
193 _pointer_frame_offset = _grab_frame - _last_frame_position;
198 bool old_had_movement = _had_movement;
200 /* a motion event has happened, so we've had movement... */
201 _had_movement = true;
203 /* ... unless we're using a move threshold and we've not yet passed it */
204 if (apply_move_threshold() && !_move_threshold_passed) {
205 _had_movement = false;
208 if (active (_editor->mouse_mode)) {
210 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
211 if (!from_autoscroll) {
212 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
215 motion (event, _had_movement != old_had_movement);
227 _editor->stop_canvas_autoscroll ();
228 _editor->hide_verbose_canvas_cursor ();
233 /* put it back where it came from */
238 _item->i2w (cxw, cyw);
239 _item->move (_original_x - cxw, _original_y - cyw);
244 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
249 RegionView::RegionViewGoingAway.connect (mem_fun (*this, &RegionDrag::region_going_away));
253 RegionDrag::region_going_away (RegionView* v)
258 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
259 : RegionDrag (e, i, p, v),
269 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
271 Drag::start_grab (event);
273 _editor->show_verbose_time_cursor (_last_frame_position, 10);
276 RegionMotionDrag::TimeAxisViewSummary
277 RegionMotionDrag::get_time_axis_view_summary ()
279 int32_t children = 0;
280 TimeAxisViewSummary sum;
282 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
284 /* get a bitmask representing the visible tracks */
286 for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
287 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
288 TimeAxisView::Children children_list;
290 /* zeroes are audio/MIDI tracks. ones are other types. */
292 if (!rtv->hidden()) {
294 if (!rtv->is_track()) {
295 /* not an audio nor MIDI track */
296 sum.tracks = sum.tracks |= (0x01 << rtv->order());
299 sum.height_list[rtv->order()] = (*i)->current_height();
302 if ((children_list = rtv->get_child_list()).size() > 0) {
303 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
304 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
305 sum.height_list[rtv->order() + children] = (*j)->current_height();
316 RegionMotionDrag::compute_y_delta (
317 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
318 int32_t last_pointer_layer, int32_t current_pointer_layer,
319 TimeAxisViewSummary const & tavs,
320 int32_t* pointer_order_span, int32_t* pointer_layer_span,
321 int32_t* canvas_pointer_order_span
325 *pointer_order_span = 0;
326 *pointer_layer_span = 0;
330 bool clamp_y_axis = false;
332 /* the change in track order between this callback and the last */
333 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
334 /* the change in layer between this callback and the last;
335 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
336 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
338 if (*pointer_order_span != 0) {
340 /* find the actual pointer span, in terms of the number of visible tracks;
341 to do this, we reduce |pointer_order_span| by the number of hidden tracks
344 *canvas_pointer_order_span = *pointer_order_span;
345 if (last_pointer_view->order() >= current_pointer_view->order()) {
346 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
347 if (tavs.height_list[y] == 0) {
348 *canvas_pointer_order_span--;
352 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
353 if (tavs.height_list[y] == 0) {
354 *canvas_pointer_order_span++;
359 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
361 RegionView* rv = (*i);
363 if (rv->region()->locked()) {
367 double ix1, ix2, iy1, iy2;
368 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
369 rv->get_canvas_frame()->i2w (ix1, iy1);
370 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
372 /* get the new trackview for this particular region */
373 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
375 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
377 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
378 as surely this is a per-region thing... */
380 clamp_y_axis = y_movement_disallowed (
381 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
389 } else if (_dest_trackview == current_pointer_view) {
391 if (current_pointer_layer == last_pointer_layer) {
392 /* No movement; clamp */
398 _dest_trackview = current_pointer_view;
399 _dest_layer = current_pointer_layer;
407 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
409 *pending_region_position = 0;
411 /* compute the amount of pointer motion in frames, and where
412 the region would be if we moved it by that much.
414 if (_current_pointer_frame >= _pointer_frame_offset) {
416 nframes64_t sync_frame;
417 nframes64_t sync_offset;
420 *pending_region_position = _current_pointer_frame - _pointer_frame_offset;
422 sync_offset = _primary->region()->sync_offset (sync_dir);
424 /* we don't handle a sync point that lies before zero.
426 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
428 sync_frame = *pending_region_position + (sync_dir*sync_offset);
430 _editor->snap_to_with_modifier (sync_frame, event);
432 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
435 *pending_region_position = _last_frame_position;
440 if (*pending_region_position > max_frames - _primary->region()->length()) {
441 *pending_region_position = _last_frame_position;
446 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
448 /* now compute the canvas unit distance we need to move the regionview
449 to make it appear at the new location.
452 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
454 if (*pending_region_position <= _last_frame_position) {
456 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
458 RegionView* rv = (*i);
460 // If any regionview is at zero, we need to know so we can stop further leftward motion.
462 double ix1, ix2, iy1, iy2;
463 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
464 rv->get_canvas_frame()->i2w (ix1, iy1);
466 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
468 *pending_region_position = _last_frame_position;
475 _last_frame_position = *pending_region_position;
482 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
486 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
488 vector<int32_t>::iterator j;
490 /* *pointer* variables reflect things about the pointer; as we may be moving
491 multiple regions, much detail must be computed per-region */
493 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
494 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
495 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
496 is always 0 regardless of what the region's "real" layer is */
497 RouteTimeAxisView* current_pointer_view;
498 layer_t current_pointer_layer;
499 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
503 /* TimeAxisView that we were pointing at last time we entered this method */
504 TimeAxisView const * const last_pointer_view = _dest_trackview;
505 /* the order of the track that we were pointing at last time we entered this method */
506 int32_t const last_pointer_order = last_pointer_view->order ();
507 /* the layer that we were pointing at last time we entered this method */
508 layer_t const last_pointer_layer = _dest_layer;
510 int32_t pointer_order_span;
511 int32_t pointer_layer_span;
512 int32_t canvas_pointer_order_span;
514 bool const clamp_y_axis = compute_y_delta (
515 last_pointer_view, current_pointer_view,
516 last_pointer_layer, current_pointer_layer, tavs,
517 &pointer_order_span, &pointer_layer_span,
518 &canvas_pointer_order_span
521 nframes64_t pending_region_position;
522 double const x_delta = compute_x_delta (event, &pending_region_position);
524 /*************************************************************
526 ************************************************************/
528 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0) {
529 /* haven't reached next snap point, and we're not switching
530 trackviews nor layers. nothing to do.
535 /*************************************************************
537 ************************************************************/
539 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
541 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
543 RegionView* rv = (*i);
545 if (rv->region()->locked()) {
549 /* here we are calculating the y distance from the
550 top of the first track view to the top of the region
551 area of the track view that we're working on */
553 /* this x value is just a dummy value so that we have something
558 /* distance from the top of this track view to the region area
559 of our track view is always 1 */
563 /* convert to world coordinates, ie distance from the top of
566 rv->get_canvas_frame()->i2w (ix1, iy1);
568 /* compensate for the ruler section and the vertical scrollbar position */
569 iy1 += _editor->get_trackview_group_vertical_offset ();
573 // hide any dependent views
575 rv->get_time_axis_view().hide_dependent_views (*rv);
578 reparent to a non scrolling group so that we can keep the
579 region selection above all time axis views.
580 reparenting means we have to move the rv as the two
581 parent groups have different coordinates.
584 rv->get_canvas_group()->property_y() = iy1 - 1;
585 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
587 rv->fake_set_opaque (true);
590 /* current view for this particular region */
591 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
592 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
594 if (pointer_order_span != 0 && !clamp_y_axis) {
596 /* INTER-TRACK MOVEMENT */
598 /* move through the height list to the track that the region is currently on */
599 vector<int32_t>::iterator j = tavs.height_list.begin ();
601 while (j != tavs.height_list.end () && x != rtv->order ()) {
607 int32_t temp_pointer_order_span = canvas_pointer_order_span;
609 if (j != tavs.height_list.end ()) {
611 /* Account for layers in the original and
612 destination tracks. If we're moving around in layers we assume
613 that only one track is involved, so it's ok to use *pointer*
616 StreamView* lv = last_pointer_view->view ();
619 /* move to the top of the last trackview */
620 if (lv->layer_display () == Stacked) {
621 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
624 StreamView* cv = current_pointer_view->view ();
627 /* move to the right layer on the current trackview */
628 if (cv->layer_display () == Stacked) {
629 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
632 /* And for being on a non-topmost layer on the new
635 while (temp_pointer_order_span > 0) {
636 /* we're moving up canvas-wise,
637 so we need to find the next track height
639 if (j != tavs.height_list.begin()) {
643 if (x != last_pointer_order) {
645 ++temp_pointer_order_span;
650 temp_pointer_order_span--;
653 while (temp_pointer_order_span < 0) {
657 if (x != last_pointer_order) {
659 --temp_pointer_order_span;
663 if (j != tavs.height_list.end()) {
667 temp_pointer_order_span++;
671 /* find out where we'll be when we move and set height accordingly */
673 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
674 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
675 rv->set_height (temp_rtv->view()->child_height());
677 /* if you un-comment the following, the region colours will follow
678 the track colours whilst dragging; personally
679 i think this can confuse things, but never mind.
682 //const GdkColor& col (temp_rtv->view->get_region_color());
683 //rv->set_color (const_cast<GdkColor&>(col));
687 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
689 /* INTER-LAYER MOVEMENT in the same track */
690 y_delta = rtv->view()->child_height () * pointer_layer_span;
695 _editor->mouse_brush_insert_region (rv, pending_region_position);
697 rv->move (x_delta, y_delta);
700 } /* foreach region */
703 _editor->cursor_group->raise_to_top();
706 if (x_delta != 0 && !_brushing) {
707 _editor->show_verbose_time_cursor (_last_frame_position, 10);
712 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
714 if (_copy && first_move) {
715 copy_regions (event);
718 RegionMotionDrag::motion (event, first_move);
722 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
724 vector<RegionView*> copies;
725 boost::shared_ptr<Diskstream> ds;
726 boost::shared_ptr<Playlist> from_playlist;
727 RegionSelection new_views;
728 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
729 PlaylistSet modified_playlists;
730 PlaylistSet frozen_playlists;
731 list <sigc::connection> modified_playlist_connections;
732 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
733 nframes64_t drag_delta;
734 bool changed_tracks, changed_position;
735 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
736 RouteTimeAxisView* source_tv;
738 if (!movement_occurred) {
743 if (Config->get_edit_mode() == Splice && !_editor->pre_drag_region_selection.empty()) {
744 _editor->selection->set (_editor->pre_drag_region_selection);
745 _editor->pre_drag_region_selection.clear ();
749 /* all changes were made during motion event handlers */
752 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
753 copies.push_back (*i);
760 /* reverse this here so that we have the correct logic to finalize
764 if (Config->get_edit_mode() == Lock) {
765 _x_constrained = !_x_constrained;
769 if (_x_constrained) {
770 _editor->begin_reversible_command (_("fixed time region copy"));
772 _editor->begin_reversible_command (_("region copy"));
775 if (_x_constrained) {
776 _editor->begin_reversible_command (_("fixed time region drag"));
778 _editor->begin_reversible_command (_("region drag"));
782 _have_transaction = true;
784 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
785 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
787 drag_delta = _primary->region()->position() - _last_frame_position;
789 _editor->update_canvas_now ();
791 /* make a list of where each region ended up */
792 final = find_time_axis_views_and_layers ();
794 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
796 RegionView* rv = (*i);
797 RouteTimeAxisView* dest_rtv = final[*i].first;
798 layer_t dest_layer = final[*i].second;
802 if (rv->region()->locked()) {
807 if (changed_position && !_x_constrained) {
808 where = rv->region()->position() - drag_delta;
810 where = rv->region()->position();
813 boost::shared_ptr<Region> new_region;
816 /* we already made a copy */
817 new_region = rv->region();
819 /* undo the previous hide_dependent_views so that xfades don't
820 disappear on copying regions
823 //rv->get_time_axis_view().reveal_dependent_views (*rv);
825 } else if (changed_tracks && dest_rtv->playlist()) {
826 new_region = RegionFactory::create (rv->region());
829 if (changed_tracks || _copy) {
831 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
838 _editor->latest_regionviews.clear ();
840 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
842 insert_result = modified_playlists.insert (to_playlist);
844 if (insert_result.second) {
845 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
848 to_playlist->add_region (new_region, where);
849 if (dest_rtv->view()->layer_display() == Stacked) {
850 new_region->set_layer (dest_layer);
851 new_region->set_pending_explicit_relayer (true);
856 if (!_editor->latest_regionviews.empty()) {
857 // XXX why just the first one ? we only expect one
858 // commented out in nick_m's canvas reworking. is that intended?
859 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
860 new_views.push_back (_editor->latest_regionviews.front());
865 motion on the same track. plonk the previously reparented region
866 back to its original canvas group (its streamview).
867 No need to do anything for copies as they are fake regions which will be deleted.
870 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
871 rv->get_canvas_group()->property_y() = 0;
873 /* just change the model */
875 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
877 if (dest_rtv->view()->layer_display() == Stacked) {
878 rv->region()->set_layer (dest_layer);
879 rv->region()->set_pending_explicit_relayer (true);
882 insert_result = modified_playlists.insert (playlist);
884 if (insert_result.second) {
885 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
887 /* freeze to avoid lots of relayering in the case of a multi-region drag */
888 frozen_insert_result = frozen_playlists.insert(playlist);
890 if (frozen_insert_result.second) {
894 rv->region()->set_position (where, (void*) this);
897 if (changed_tracks && !_copy) {
899 /* get the playlist where this drag started. we can't use rv->region()->playlist()
900 because we may have copied the region and it has not been attached to a playlist.
903 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
904 ds = source_tv->get_diskstream();
905 from_playlist = ds->playlist();
909 assert (from_playlist);
911 /* moved to a different audio track, without copying */
913 /* the region that used to be in the old playlist is not
914 moved to the new one - we use a copy of it. as a result,
915 any existing editor for the region should no longer be
919 rv->hide_region_editor();
920 rv->fake_set_opaque (false);
922 /* remove the region from the old playlist */
924 insert_result = modified_playlists.insert (from_playlist);
926 if (insert_result.second) {
927 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
930 from_playlist->remove_region (rv->region());
932 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
933 was selected in all of them, then removing it from a playlist will have removed all
934 trace of it from the selection (i.e. there were N regions selected, we removed 1,
935 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
936 corresponding regionview, and the selection is now empty).
938 this could have invalidated any and all iterators into the region selection.
940 the heuristic we use here is: if the region selection is empty, break out of the loop
941 here. if the region selection is not empty, then restart the loop because we know that
942 we must have removed at least the region(view) we've just been working on as well as any
943 that we processed on previous iterations.
945 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
949 if (_views.empty()) {
960 copies.push_back (rv);
964 _editor->selection->add (new_views);
966 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
971 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
972 _editor->session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
975 _editor->commit_reversible_command ();
977 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
984 RegionMotionDrag::x_move_allowed () const
986 if (Config->get_edit_mode() == Lock) {
987 /* in locked edit mode, reverse the usual meaning of _x_constrained */
988 return _x_constrained;
991 return !_x_constrained;
995 RegionMotionDrag::copy_regions (GdkEvent* event)
997 /* duplicate the regionview(s) and region(s) */
999 list<RegionView*> new_regionviews;
1001 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1003 RegionView* rv = (*i);
1004 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1005 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1007 const boost::shared_ptr<const Region> original = rv->region();
1008 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1012 boost::shared_ptr<AudioRegion> audioregion_copy
1013 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1014 nrv = new AudioRegionView (*arv, audioregion_copy);
1016 boost::shared_ptr<MidiRegion> midiregion_copy
1017 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1018 nrv = new MidiRegionView (*mrv, midiregion_copy);
1023 nrv->get_canvas_group()->show ();
1024 new_regionviews.push_back (nrv);
1027 if (new_regionviews.empty()) {
1031 /* reflect the fact that we are dragging the copies */
1033 _primary = new_regionviews.front();
1034 _views = new_regionviews;
1036 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1039 sync the canvas to what we think is its current state
1040 without it, the canvas seems to
1041 "forget" to update properly after the upcoming reparent()
1042 ..only if the mouse is in rapid motion at the time of the grab.
1043 something to do with regionview creation raking so long?
1045 _editor->update_canvas_now();
1049 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1051 /* Which trackview is this ? */
1053 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1054 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1055 (*layer) = tvp.second;
1057 if (*tv && (*tv)->layer_display() == Overlaid) {
1061 /* The region motion is only processed if the pointer is over
1065 if (!(*tv) || !(*tv)->is_track()) {
1066 /* To make sure we hide the verbose canvas cursor when the mouse is
1067 not held over and audiotrack.
1069 _editor->hide_verbose_canvas_cursor ();
1076 /** @param new_order New track order.
1077 * @param old_order Old track order.
1078 * @param visible_y_low Lowest visible order.
1079 * @return true if y movement should not happen, otherwise false.
1082 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1084 if (new_order != old_order) {
1086 /* this isn't the pointer track */
1090 /* moving up the canvas */
1091 if ( (new_order - y_span) >= tavs.visible_y_low) {
1095 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1096 int32_t visible_tracks = 0;
1097 while (visible_tracks < y_span ) {
1099 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1100 /* passing through a hidden track */
1105 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1106 /* moving to a non-track; disallow */
1112 /* moving beyond the lowest visible track; disallow */
1116 } else if (y_span < 0) {
1118 /* moving down the canvas */
1119 if ((new_order - y_span) <= tavs.visible_y_high) {
1121 int32_t visible_tracks = 0;
1123 while (visible_tracks > y_span ) {
1126 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1127 /* passing through a hidden track */
1132 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1133 /* moving to a non-track; disallow */
1140 /* moving beyond the highest visible track; disallow */
1147 /* this is the pointer's track */
1149 if ((new_order - y_span) > tavs.visible_y_high) {
1150 /* we will overflow */
1152 } else if ((new_order - y_span) < tavs.visible_y_low) {
1153 /* we will overflow */
1162 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1163 : RegionMotionDrag (e, i, p, v, b),
1166 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1168 _dest_trackview = tv;
1169 if (tv->layer_display() == Overlaid) {
1172 _dest_layer = _primary->region()->layer ();
1176 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1177 if (rtv && rtv->is_track()) {
1178 speed = rtv->get_diskstream()->speed ();
1181 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1185 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1187 RegionMotionDrag::start_grab (event, c);
1189 _pointer_frame_offset = _grab_frame - _last_frame_position;
1192 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1193 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1195 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1196 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1198 _primary = v->view()->create_region_view (r, false, false);
1200 _primary->get_canvas_group()->show ();
1201 _primary->set_position (pos, 0);
1202 _views.push_back (_primary);
1204 _last_frame_position = pos;
1206 _item = _primary->get_canvas_group ();
1207 _dest_trackview = v;
1208 _dest_layer = _primary->region()->layer ();
1211 map<RegionView*, pair<RouteTimeAxisView*, int> >
1212 RegionMotionDrag::find_time_axis_views_and_layers ()
1214 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1216 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1218 double ix1, ix2, iy1, iy2;
1219 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1220 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1221 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1223 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1224 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1232 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1234 _editor->update_canvas_now ();
1236 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1238 RouteTimeAxisView* dest_rtv = final[_primary].first;
1240 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1241 _primary->get_canvas_group()->property_y() = 0;
1243 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1245 _editor->begin_reversible_command (_("insert region"));
1246 XMLNode& before = playlist->get_state ();
1247 playlist->add_region (_primary->region (), _last_frame_position);
1248 _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1249 _editor->commit_reversible_command ();
1256 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1257 : RegionMoveDrag (e, i, p, v, false, false)
1262 struct RegionSelectionByPosition {
1263 bool operator() (RegionView*a, RegionView* b) {
1264 return a->region()->position () < b->region()->position();
1269 RegionSpliceDrag::motion (GdkEvent* /*event*/, bool)
1271 RouteTimeAxisView* tv;
1274 if (!check_possible (&tv, &layer)) {
1280 if (_current_pointer_x - _grab_x > 0) {
1286 RegionSelection copy (_editor->selection->regions);
1288 RegionSelectionByPosition cmp;
1291 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1293 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1299 boost::shared_ptr<Playlist> playlist;
1301 if ((playlist = atv->playlist()) == 0) {
1305 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1310 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1314 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1320 playlist->shuffle ((*i)->region(), dir);
1322 _grab_x = _current_pointer_x;
1327 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1333 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1341 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1343 _dest_trackview = _view;
1345 Drag::start_grab (event);
1350 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1353 // TODO: create region-create-drag region view here
1356 // TODO: resize region-create-drag region view here
1360 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1362 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1368 if (!movement_occurred) {
1369 mtv->add_region (_grab_frame);
1371 motion (event, false);
1372 // TODO: create region-create-drag region here
1376 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1384 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1387 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1389 Drag::start_grab (event);
1391 region = &cnote->region_view();
1393 double region_start = region->get_position_pixels();
1394 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1396 if (_grab_x <= middle_point) {
1397 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1400 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1404 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1406 if (event->motion.state & Keyboard::PrimaryModifier) {
1412 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1414 if (ms.size() > 1) {
1415 /* has to be relative, may make no sense otherwise */
1419 region->note_selected (cnote, true);
1421 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1422 MidiRegionSelection::iterator next;
1425 (*r)->begin_resizing (at_front);
1431 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1433 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1434 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1435 (*r)->update_resizing (at_front, _current_pointer_x - _grab_x, relative);
1440 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1442 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1443 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1444 (*r)->commit_resizing (at_front, _current_pointer_x - _grab_x, relative);
1449 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1455 RegionGainDrag::finished (GdkEvent *, bool)
1460 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1461 : RegionDrag (e, i, p, v)
1467 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1470 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1471 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1473 if (tv && tv->is_track()) {
1474 speed = tv->get_diskstream()->speed();
1477 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1478 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1479 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1481 Drag::start_grab (event, _editor->trimmer_cursor);
1483 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1484 _operation = ContentsTrim;
1486 /* These will get overridden for a point trim.*/
1487 if (_current_pointer_frame < (region_start + region_length/2)) {
1488 /* closer to start */
1489 _operation = StartTrim;
1490 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1492 _operation = EndTrim;
1496 switch (_operation) {
1498 _editor->show_verbose_time_cursor (region_start, 10);
1501 _editor->show_verbose_time_cursor (region_end, 10);
1504 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1510 TrimDrag::motion (GdkEvent* event, bool first_move)
1512 RegionView* rv = _primary;
1513 nframes64_t frame_delta = 0;
1515 bool left_direction;
1516 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1518 /* snap modifier works differently here..
1519 its' current state has to be passed to the
1520 various trim functions in order to work properly
1524 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1525 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1526 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1528 if (tv && tv->is_track()) {
1529 speed = tv->get_diskstream()->speed();
1532 if (_last_pointer_frame > _current_pointer_frame) {
1533 left_direction = true;
1535 left_direction = false;
1538 _editor->snap_to_with_modifier (_current_pointer_frame, event);
1544 switch (_operation) {
1546 trim_type = "Region start trim";
1549 trim_type = "Region end trim";
1552 trim_type = "Region content trim";
1556 _editor->begin_reversible_command (trim_type);
1557 _have_transaction = true;
1559 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1560 (*i)->fake_set_opaque(false);
1561 (*i)->region()->freeze ();
1563 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1566 arv->temporarily_hide_envelope ();
1569 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1570 insert_result = _editor->motion_frozen_playlists.insert (pl);
1572 if (insert_result.second) {
1573 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1579 if (_current_pointer_frame == _last_pointer_frame) {
1583 /* XXX i hope to god that we can really conclude this ... */
1584 _have_transaction = true;
1586 if (left_direction) {
1587 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1589 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1592 bool non_overlap_trim = false;
1594 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1595 non_overlap_trim = true;
1598 switch (_operation) {
1600 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1604 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1605 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1611 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1615 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1616 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1623 bool swap_direction = false;
1625 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1626 swap_direction = true;
1629 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1631 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1637 switch (_operation) {
1639 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1642 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1645 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1649 _last_pointer_frame = _current_pointer_frame;
1654 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1656 if (movement_occurred) {
1657 motion (event, false);
1659 if (!_editor->selection->selected (_primary)) {
1660 _editor->thaw_region_after_trim (*_primary);
1663 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1664 _editor->thaw_region_after_trim (**i);
1665 (*i)->fake_set_opaque (true);
1668 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1670 if (_have_transaction) {
1671 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1675 _editor->motion_frozen_playlists.clear ();
1677 if (_have_transaction) {
1678 _editor->commit_reversible_command();
1682 /* no mouse movement */
1683 _editor->point_trim (event);
1687 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1691 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1696 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1699 // create a dummy marker for visual representation of moving the copy.
1700 // The actual copying is not done before we reach the finish callback.
1702 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1703 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1704 *new MeterSection (_marker->meter()));
1706 _item = &new_marker->the_item ();
1707 _marker = new_marker;
1711 MetricSection& section (_marker->meter());
1713 if (!section.movable()) {
1719 Drag::start_grab (event, cursor);
1721 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1723 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1727 MeterMarkerDrag::motion (GdkEvent* event, bool)
1729 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1731 if (adjusted_frame == _last_pointer_frame) {
1735 _marker->set_position (adjusted_frame);
1737 _last_pointer_frame = adjusted_frame;
1739 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1743 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1745 if (!movement_occurred) {
1749 motion (event, false);
1753 TempoMap& map (_editor->session->tempo_map());
1754 map.bbt_time (_last_pointer_frame, when);
1756 if (_copy == true) {
1757 _editor->begin_reversible_command (_("copy meter mark"));
1758 XMLNode &before = map.get_state();
1759 map.add_meter (_marker->meter(), when);
1760 XMLNode &after = map.get_state();
1761 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1762 _editor->commit_reversible_command ();
1764 // delete the dummy marker we used for visual representation of copying.
1765 // a new visual marker will show up automatically.
1768 _editor->begin_reversible_command (_("move meter mark"));
1769 XMLNode &before = map.get_state();
1770 map.move_meter (_marker->meter(), when);
1771 XMLNode &after = map.get_state();
1772 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1773 _editor->commit_reversible_command ();
1777 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1781 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1786 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1791 // create a dummy marker for visual representation of moving the copy.
1792 // The actual copying is not done before we reach the finish callback.
1794 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1795 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1796 *new TempoSection (_marker->tempo()));
1798 _item = &new_marker->the_item ();
1799 _marker = new_marker;
1803 MetricSection& section (_marker->tempo());
1805 if (!section.movable()) {
1810 Drag::start_grab (event, cursor);
1812 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1813 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1817 TempoMarkerDrag::motion (GdkEvent* event, bool)
1819 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1821 if (adjusted_frame == _last_pointer_frame) {
1825 /* OK, we've moved far enough to make it worth actually move the thing. */
1827 _marker->set_position (adjusted_frame);
1829 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1831 _last_pointer_frame = adjusted_frame;
1835 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1837 if (!movement_occurred) {
1841 motion (event, false);
1845 TempoMap& map (_editor->session->tempo_map());
1846 map.bbt_time (_last_pointer_frame, when);
1848 if (_copy == true) {
1849 _editor->begin_reversible_command (_("copy tempo mark"));
1850 XMLNode &before = map.get_state();
1851 map.add_tempo (_marker->tempo(), when);
1852 XMLNode &after = map.get_state();
1853 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1854 _editor->commit_reversible_command ();
1856 // delete the dummy marker we used for visual representation of copying.
1857 // a new visual marker will show up automatically.
1860 _editor->begin_reversible_command (_("move tempo mark"));
1861 XMLNode &before = map.get_state();
1862 map.move_tempo (_marker->tempo(), when);
1863 XMLNode &after = map.get_state();
1864 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1865 _editor->commit_reversible_command ();
1870 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1874 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1879 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1881 Drag::start_grab (event, c);
1885 nframes64_t where = _editor->event_frame (event, 0, 0);
1887 _editor->snap_to_with_modifier (where, event);
1888 _editor->playhead_cursor->set_position (where);
1892 if (_cursor == _editor->playhead_cursor) {
1893 _editor->_dragging_playhead = true;
1895 if (_editor->session && _was_rolling && _stop) {
1896 _editor->session->request_stop ();
1899 if (_editor->session && _editor->session->is_auditioning()) {
1900 _editor->session->cancel_audition ();
1904 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1908 CursorDrag::motion (GdkEvent* event, bool)
1910 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1912 if (adjusted_frame == _last_pointer_frame) {
1916 _cursor->set_position (adjusted_frame);
1918 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1921 _editor->update_canvas_now ();
1923 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1925 _last_pointer_frame = adjusted_frame;
1929 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1931 _editor->_dragging_playhead = false;
1933 if (!movement_occurred && _stop) {
1937 motion (event, false);
1939 if (_item == &_editor->playhead_cursor->canvas_item) {
1940 if (_editor->session) {
1941 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1942 _editor->_pending_locate_request = true;
1947 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1948 : RegionDrag (e, i, p, v)
1954 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1956 Drag::start_grab (event, cursor);
1958 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1959 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1961 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1962 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
1966 FadeInDrag::motion (GdkEvent* event, bool)
1968 nframes64_t fade_length;
1970 nframes64_t const pos = adjusted_current_frame (event);
1972 boost::shared_ptr<Region> region = _primary->region ();
1974 if (pos < (region->position() + 64)) {
1975 fade_length = 64; // this should be a minimum defined somewhere
1976 } else if (pos > region->last_frame()) {
1977 fade_length = region->length();
1979 fade_length = pos - region->position();
1982 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1984 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1990 tmp->reset_fade_in_shape_width (fade_length);
1993 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1997 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1999 if (!movement_occurred) {
2003 nframes64_t fade_length;
2005 nframes64_t const pos = adjusted_current_frame (event);
2007 boost::shared_ptr<Region> region = _primary->region ();
2009 if (pos < (region->position() + 64)) {
2010 fade_length = 64; // this should be a minimum defined somewhere
2011 } else if (pos > region->last_frame()) {
2012 fade_length = region->length();
2014 fade_length = pos - region->position();
2017 _editor->begin_reversible_command (_("change fade in length"));
2019 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2021 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2027 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2028 XMLNode &before = alist->get_state();
2030 tmp->audio_region()->set_fade_in_length (fade_length);
2031 tmp->audio_region()->set_fade_in_active (true);
2033 XMLNode &after = alist->get_state();
2034 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2037 _editor->commit_reversible_command ();
2040 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2041 : RegionDrag (e, i, p, v)
2047 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2049 Drag::start_grab (event, cursor);
2051 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2052 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2054 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2055 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2059 FadeOutDrag::motion (GdkEvent* event, bool)
2061 nframes64_t fade_length;
2063 nframes64_t const pos = adjusted_current_frame (event);
2065 boost::shared_ptr<Region> region = _primary->region ();
2067 if (pos > (region->last_frame() - 64)) {
2068 fade_length = 64; // this should really be a minimum fade defined somewhere
2070 else if (pos < region->position()) {
2071 fade_length = region->length();
2074 fade_length = region->last_frame() - pos;
2077 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2079 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2085 tmp->reset_fade_out_shape_width (fade_length);
2088 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2092 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2094 if (!movement_occurred) {
2098 nframes64_t fade_length;
2100 nframes64_t const pos = adjusted_current_frame (event);
2102 boost::shared_ptr<Region> region = _primary->region ();
2104 if (pos > (region->last_frame() - 64)) {
2105 fade_length = 64; // this should really be a minimum fade defined somewhere
2107 else if (pos < region->position()) {
2108 fade_length = region->length();
2111 fade_length = region->last_frame() - pos;
2114 _editor->begin_reversible_command (_("change fade out length"));
2116 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2118 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2124 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2125 XMLNode &before = alist->get_state();
2127 tmp->audio_region()->set_fade_out_length (fade_length);
2128 tmp->audio_region()->set_fade_out_active (true);
2130 XMLNode &after = alist->get_state();
2131 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2134 _editor->commit_reversible_command ();
2137 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2140 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2143 _points.push_back (Gnome::Art::Point (0, 0));
2144 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2146 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2147 _line->property_width_pixels() = 1;
2148 _line->property_points () = _points;
2151 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2154 MarkerDrag::~MarkerDrag ()
2156 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2162 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2164 Drag::start_grab (event, cursor);
2168 Location *location = _editor->find_location_from_marker (_marker, is_start);
2169 _editor->_dragging_edit_point = true;
2171 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2173 update_item (location);
2175 // _drag_line->show();
2176 // _line->raise_to_top();
2179 _editor->show_verbose_time_cursor (location->start(), 10);
2181 _editor->show_verbose_time_cursor (location->end(), 10);
2184 Selection::Operation op = Keyboard::selection_type (event->button.state);
2187 case Selection::Toggle:
2188 _editor->selection->toggle (_marker);
2190 case Selection::Set:
2191 if (!_editor->selection->selected (_marker)) {
2192 _editor->selection->set (_marker);
2195 case Selection::Extend:
2197 Locations::LocationList ll;
2198 list<Marker*> to_add;
2200 _editor->selection->markers.range (s, e);
2201 s = min (_marker->position(), s);
2202 e = max (_marker->position(), e);
2205 if (e < max_frames) {
2208 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2209 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2210 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2213 to_add.push_back (lm->start);
2216 to_add.push_back (lm->end);
2220 if (!to_add.empty()) {
2221 _editor->selection->add (to_add);
2225 case Selection::Add:
2226 _editor->selection->add (_marker);
2230 /* set up copies for us to manipulate during the drag */
2232 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2233 Location *l = _editor->find_location_from_marker (*i, is_start);
2234 _copied_locations.push_back (new Location (*l));
2239 MarkerDrag::motion (GdkEvent* event, bool)
2241 nframes64_t f_delta = 0;
2243 bool move_both = false;
2245 Location *real_location;
2246 Location *copy_location = 0;
2248 nframes64_t const newframe = adjusted_current_frame (event);
2250 nframes64_t next = newframe;
2252 if (_current_pointer_frame == _last_pointer_frame) {
2256 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2260 MarkerSelection::iterator i;
2261 list<Location*>::iterator x;
2263 /* find the marker we're dragging, and compute the delta */
2265 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2266 x != _copied_locations.end() && i != _editor->selection->markers.end();
2272 if (marker == _marker) {
2274 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2279 if (real_location->is_mark()) {
2280 f_delta = newframe - copy_location->start();
2284 switch (marker->type()) {
2286 case Marker::LoopStart:
2287 case Marker::PunchIn:
2288 f_delta = newframe - copy_location->start();
2292 case Marker::LoopEnd:
2293 case Marker::PunchOut:
2294 f_delta = newframe - copy_location->end();
2297 /* what kind of marker is this ? */
2305 if (i == _editor->selection->markers.end()) {
2306 /* hmm, impossible - we didn't find the dragged marker */
2310 /* now move them all */
2312 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2313 x != _copied_locations.end() && i != _editor->selection->markers.end();
2319 /* call this to find out if its the start or end */
2321 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2325 if (real_location->locked()) {
2329 if (copy_location->is_mark()) {
2333 copy_location->set_start (copy_location->start() + f_delta);
2337 nframes64_t new_start = copy_location->start() + f_delta;
2338 nframes64_t new_end = copy_location->end() + f_delta;
2340 if (is_start) { // start-of-range marker
2343 copy_location->set_start (new_start);
2344 copy_location->set_end (new_end);
2345 } else if (new_start < copy_location->end()) {
2346 copy_location->set_start (new_start);
2348 _editor->snap_to (next, 1, true);
2349 copy_location->set_end (next);
2350 copy_location->set_start (newframe);
2353 } else { // end marker
2356 copy_location->set_end (new_end);
2357 copy_location->set_start (new_start);
2358 } else if (new_end > copy_location->start()) {
2359 copy_location->set_end (new_end);
2360 } else if (newframe > 0) {
2361 _editor->snap_to (next, -1, true);
2362 copy_location->set_start (next);
2363 copy_location->set_end (newframe);
2368 update_item (copy_location);
2370 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2373 lm->set_position (copy_location->start(), copy_location->end());
2377 _last_pointer_frame = _current_pointer_frame;
2379 assert (!_copied_locations.empty());
2381 _editor->edit_point_clock.set (_copied_locations.front()->start());
2382 _editor->show_verbose_time_cursor (newframe, 10);
2385 _editor->update_canvas_now ();
2387 _editor->edit_point_clock.set (copy_location->start());
2391 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2393 if (!movement_occurred) {
2395 /* just a click, do nothing but finish
2396 off the selection process
2399 Selection::Operation op = Keyboard::selection_type (event->button.state);
2402 case Selection::Set:
2403 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2404 _editor->selection->set (_marker);
2408 case Selection::Toggle:
2409 case Selection::Extend:
2410 case Selection::Add:
2417 _editor->_dragging_edit_point = false;
2419 _editor->begin_reversible_command ( _("move marker") );
2420 XMLNode &before = _editor->session->locations()->get_state();
2422 MarkerSelection::iterator i;
2423 list<Location*>::iterator x;
2426 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2427 x != _copied_locations.end() && i != _editor->selection->markers.end();
2430 Location * location = _editor->find_location_from_marker (*i, is_start);
2434 if (location->locked()) {
2438 if (location->is_mark()) {
2439 location->set_start ((*x)->start());
2441 location->set ((*x)->start(), (*x)->end());
2446 XMLNode &after = _editor->session->locations()->get_state();
2447 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
2448 _editor->commit_reversible_command ();
2454 MarkerDrag::update_item (Location* location)
2456 double const x1 = _editor->frame_to_pixel (location->start());
2458 _points.front().set_x(x1);
2459 _points.back().set_x(x1);
2460 _line->property_points() = _points;
2463 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2465 _cumulative_x_drag (0),
2466 _cumulative_y_drag (0)
2468 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2474 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2476 Drag::start_grab (event, _editor->fader_cursor);
2478 // start the grab at the center of the control point so
2479 // the point doesn't 'jump' to the mouse after the first drag
2480 _grab_x = _point->get_x();
2481 _grab_y = _point->get_y();
2483 _point->line().parent_group().i2w (_grab_x, _grab_y);
2484 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2486 _grab_frame = _editor->pixel_to_frame (_grab_x);
2488 _point->line().start_drag (_point, _grab_frame, 0);
2490 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2491 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2492 _current_pointer_x + 10, _current_pointer_y + 10);
2494 _editor->show_verbose_canvas_cursor ();
2498 ControlPointDrag::motion (GdkEvent* event, bool)
2500 double dx = _current_pointer_x - _last_pointer_x;
2501 double dy = _current_pointer_y - _last_pointer_y;
2503 if (event->button.state & Keyboard::SecondaryModifier) {
2508 double cx = _grab_x + _cumulative_x_drag + dx;
2509 double cy = _grab_y + _cumulative_y_drag + dy;
2511 // calculate zero crossing point. back off by .01 to stay on the
2512 // positive side of zero
2514 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2515 _point->line().parent_group().i2w(_unused, zero_gain_y);
2517 // make sure we hit zero when passing through
2518 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2519 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2523 if (_x_constrained) {
2526 if (_y_constrained) {
2530 _cumulative_x_drag = cx - _grab_x;
2531 _cumulative_y_drag = cy - _grab_y;
2533 _point->line().parent_group().w2i (cx, cy);
2537 cy = min ((double) _point->line().height(), cy);
2539 //translate cx to frames
2540 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2542 if (!_x_constrained) {
2543 _editor->snap_to_with_modifier (cx_frames, event);
2546 float const fraction = 1.0 - (cy / _point->line().height());
2548 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2550 _point->line().point_drag (*_point, cx_frames, fraction, push);
2552 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2556 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2558 if (!movement_occurred) {
2562 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2563 _editor->reset_point_selection ();
2567 motion (event, false);
2569 _point->line().end_drag (_point);
2573 ControlPointDrag::active (Editing::MouseMode m)
2575 if (m == Editing::MouseGain) {
2576 /* always active in mouse gain */
2580 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2581 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2584 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2587 _cumulative_y_drag (0)
2592 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2594 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2597 _item = &_line->grab_item ();
2599 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2600 origin, and ditto for y.
2603 double cx = event->button.x;
2604 double cy = event->button.y;
2606 _line->parent_group().w2i (cx, cy);
2608 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2610 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2611 /* no adjacent points */
2615 Drag::start_grab (event, _editor->fader_cursor);
2617 /* store grab start in parent frame */
2622 double fraction = 1.0 - (cy / _line->height());
2624 _line->start_drag (0, _grab_frame, fraction);
2626 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2627 _current_pointer_x + 10, _current_pointer_y + 10);
2629 _editor->show_verbose_canvas_cursor ();
2633 LineDrag::motion (GdkEvent* event, bool)
2635 double dy = _current_pointer_y - _last_pointer_y;
2637 if (event->button.state & Keyboard::SecondaryModifier) {
2641 double cy = _grab_y + _cumulative_y_drag + dy;
2643 _cumulative_y_drag = cy - _grab_y;
2646 cy = min ((double) _line->height(), cy);
2648 double const fraction = 1.0 - (cy / _line->height());
2652 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2658 _line->line_drag (_before, _after, fraction, push);
2660 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2664 LineDrag::finished (GdkEvent* event, bool)
2666 motion (event, false);
2667 _line->end_drag (0);
2671 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2673 Drag::start_grab (event);
2674 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2678 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2685 /* use a bigger drag threshold than the default */
2687 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2691 if (Config->get_rubberbanding_snaps_to_grid()) {
2693 _editor->snap_to_with_modifier (_grab_frame, event);
2695 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2698 /* base start and end on initial click position */
2700 if (_current_pointer_frame < _grab_frame) {
2701 start = _current_pointer_frame;
2704 end = _current_pointer_frame;
2705 start = _grab_frame;
2708 if (_current_pointer_y < _grab_y) {
2709 y1 = _current_pointer_y;
2712 y2 = _current_pointer_y;
2717 if (start != end || y1 != y2) {
2719 double x1 = _editor->frame_to_pixel (start);
2720 double x2 = _editor->frame_to_pixel (end);
2722 _editor->rubberband_rect->property_x1() = x1;
2723 _editor->rubberband_rect->property_y1() = y1;
2724 _editor->rubberband_rect->property_x2() = x2;
2725 _editor->rubberband_rect->property_y2() = y2;
2727 _editor->rubberband_rect->show();
2728 _editor->rubberband_rect->raise_to_top();
2730 _last_pointer_frame = _current_pointer_frame;
2732 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2737 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2739 if (movement_occurred) {
2741 motion (event, false);
2744 if (_current_pointer_y < _grab_y) {
2745 y1 = _current_pointer_y;
2748 y2 = _current_pointer_y;
2753 Selection::Operation op = Keyboard::selection_type (event->button.state);
2756 _editor->begin_reversible_command (_("rubberband selection"));
2758 if (_grab_frame < _last_pointer_frame) {
2759 committed = _editor->select_all_within (_grab_frame, _last_pointer_frame - 1, y1, y2, _editor->track_views, op);
2761 committed = _editor->select_all_within (_last_pointer_frame, _grab_frame - 1, y1, y2, _editor->track_views, op);
2765 _editor->commit_reversible_command ();
2769 if (!getenv("ARDOUR_SAE")) {
2770 _editor->selection->clear_tracks();
2772 _editor->selection->clear_regions();
2773 _editor->selection->clear_points ();
2774 _editor->selection->clear_lines ();
2777 _editor->rubberband_rect->hide();
2781 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2783 Drag::start_grab (event);
2785 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2789 TimeFXDrag::motion (GdkEvent* event, bool)
2791 RegionView* rv = _primary;
2793 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2795 if (_current_pointer_frame == _last_pointer_frame) {
2799 if (_current_pointer_frame > rv->region()->position()) {
2800 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2803 _last_pointer_frame = _current_pointer_frame;
2805 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2809 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2811 _primary->get_time_axis_view().hide_timestretch ();
2813 if (!movement_occurred) {
2817 if (_last_pointer_frame < _primary->region()->position()) {
2818 /* backwards drag of the left edge - not usable */
2822 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2824 float percentage = (double) newlen / (double) _primary->region()->length();
2826 #ifndef USE_RUBBERBAND
2827 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2828 if (_primary->region()->data_type() == DataType::AUDIO) {
2829 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2833 _editor->begin_reversible_command (_("timestretch"));
2835 // XXX how do timeFX on multiple regions ?
2840 if (_editor->time_stretch (rs, percentage) == 0) {
2841 _editor->session->commit_reversible_command ();
2846 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2848 Drag::start_grab (event);
2852 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2858 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2860 if (movement_occurred && _editor->session) {
2861 /* make sure we stop */
2862 _editor->session->request_transport_speed (0.0);
2866 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2875 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2877 nframes64_t start = 0;
2878 nframes64_t end = 0;
2880 if (_editor->session == 0) {
2884 Gdk::Cursor* cursor = 0;
2886 switch (_operation) {
2887 case CreateSelection:
2888 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2893 cursor = _editor->selector_cursor;
2894 Drag::start_grab (event, cursor);
2897 case SelectionStartTrim:
2898 if (_editor->clicked_axisview) {
2899 _editor->clicked_axisview->order_selection_trims (_item, true);
2901 Drag::start_grab (event, cursor);
2902 cursor = _editor->trimmer_cursor;
2903 start = _editor->selection->time[_editor->clicked_selection].start;
2904 _pointer_frame_offset = _grab_frame - start;
2907 case SelectionEndTrim:
2908 if (_editor->clicked_axisview) {
2909 _editor->clicked_axisview->order_selection_trims (_item, false);
2911 Drag::start_grab (event, cursor);
2912 cursor = _editor->trimmer_cursor;
2913 end = _editor->selection->time[_editor->clicked_selection].end;
2914 _pointer_frame_offset = _grab_frame - end;
2918 start = _editor->selection->time[_editor->clicked_selection].start;
2919 Drag::start_grab (event, cursor);
2920 _pointer_frame_offset = _grab_frame - start;
2924 if (_operation == SelectionMove) {
2925 _editor->show_verbose_time_cursor (start, 10);
2927 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2932 SelectionDrag::motion (GdkEvent* event, bool first_move)
2934 nframes64_t start = 0;
2935 nframes64_t end = 0;
2939 nframes64_t const pending_position = adjusted_current_frame (event);
2941 /* only alter selection if the current frame is
2942 different from the last frame position (adjusted)
2945 if (pending_position == _last_pointer_frame) {
2949 switch (_operation) {
2950 case CreateSelection:
2953 _editor->snap_to (_grab_frame);
2956 if (pending_position < _grab_frame) {
2957 start = pending_position;
2960 end = pending_position;
2961 start = _grab_frame;
2964 /* first drag: Either add to the selection
2965 or create a new selection->
2970 _editor->begin_reversible_command (_("range selection"));
2971 _have_transaction = true;
2974 /* adding to the selection */
2975 _editor->clicked_selection = _editor->selection->add (start, end);
2978 /* new selection-> */
2979 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2984 case SelectionStartTrim:
2987 _editor->begin_reversible_command (_("trim selection start"));
2988 _have_transaction = true;
2991 start = _editor->selection->time[_editor->clicked_selection].start;
2992 end = _editor->selection->time[_editor->clicked_selection].end;
2994 if (pending_position > end) {
2997 start = pending_position;
3001 case SelectionEndTrim:
3004 _editor->begin_reversible_command (_("trim selection end"));
3005 _have_transaction = true;
3008 start = _editor->selection->time[_editor->clicked_selection].start;
3009 end = _editor->selection->time[_editor->clicked_selection].end;
3011 if (pending_position < start) {
3014 end = pending_position;
3022 _editor->begin_reversible_command (_("move selection"));
3023 _have_transaction = true;
3026 start = _editor->selection->time[_editor->clicked_selection].start;
3027 end = _editor->selection->time[_editor->clicked_selection].end;
3029 length = end - start;
3031 start = pending_position;
3032 _editor->snap_to (start);
3034 end = start + length;
3039 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3040 _editor->start_canvas_autoscroll (1, 0);
3044 _editor->selection->replace (_editor->clicked_selection, start, end);
3047 _last_pointer_frame = pending_position;
3049 if (_operation == SelectionMove) {
3050 _editor->show_verbose_time_cursor(start, 10);
3052 _editor->show_verbose_time_cursor(pending_position, 10);
3057 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3059 Session* s = _editor->session;
3061 if (movement_occurred) {
3062 motion (event, false);
3063 /* XXX this is not object-oriented programming at all. ick */
3064 if (_editor->selection->time.consolidate()) {
3065 _editor->selection->TimeChanged ();
3068 if (_have_transaction) {
3069 _editor->commit_reversible_command ();
3072 /* XXX what if its a music time selection? */
3073 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3074 s->request_play_range (&_editor->selection->time, true);
3079 /* just a click, no pointer movement.*/
3081 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3083 _editor->selection->clear_time();
3087 if (s && s->get_play_range () && s->transport_rolling()) {
3088 s->request_stop (false, false);
3093 _editor->stop_canvas_autoscroll ();
3096 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3101 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3102 _drag_rect->hide ();
3104 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3105 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3109 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3111 if (_editor->session == 0) {
3115 Gdk::Cursor* cursor = 0;
3117 if (!_editor->temp_location) {
3118 _editor->temp_location = new Location;
3121 switch (_operation) {
3122 case CreateRangeMarker:
3123 case CreateTransportMarker:
3124 case CreateCDMarker:
3126 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3131 cursor = _editor->selector_cursor;
3135 Drag::start_grab (event, cursor);
3137 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3141 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3143 nframes64_t start = 0;
3144 nframes64_t end = 0;
3145 ArdourCanvas::SimpleRect *crect;
3147 switch (_operation) {
3148 case CreateRangeMarker:
3149 crect = _editor->range_bar_drag_rect;
3151 case CreateTransportMarker:
3152 crect = _editor->transport_bar_drag_rect;
3154 case CreateCDMarker:
3155 crect = _editor->cd_marker_bar_drag_rect;
3158 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3163 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3165 /* only alter selection if the current frame is
3166 different from the last frame position.
3169 if (_current_pointer_frame == _last_pointer_frame) {
3173 switch (_operation) {
3174 case CreateRangeMarker:
3175 case CreateTransportMarker:
3176 case CreateCDMarker:
3178 _editor->snap_to (_grab_frame);
3181 if (_current_pointer_frame < _grab_frame) {
3182 start = _current_pointer_frame;
3185 end = _current_pointer_frame;
3186 start = _grab_frame;
3189 /* first drag: Either add to the selection
3190 or create a new selection.
3195 _editor->temp_location->set (start, end);
3199 update_item (_editor->temp_location);
3201 //_drag_rect->raise_to_top();
3207 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3208 _editor->start_canvas_autoscroll (1, 0);
3212 _editor->temp_location->set (start, end);
3214 double x1 = _editor->frame_to_pixel (start);
3215 double x2 = _editor->frame_to_pixel (end);
3216 crect->property_x1() = x1;
3217 crect->property_x2() = x2;
3219 update_item (_editor->temp_location);
3222 _last_pointer_frame = _current_pointer_frame;
3224 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3229 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3231 Location * newloc = 0;
3235 if (movement_occurred) {
3236 motion (event, false);
3239 switch (_operation) {
3240 case CreateRangeMarker:
3241 case CreateCDMarker:
3243 _editor->begin_reversible_command (_("new range marker"));
3244 XMLNode &before = _editor->session->locations()->get_state();
3245 _editor->session->locations()->next_available_name(rangename,"unnamed");
3246 if (_operation == CreateCDMarker) {
3247 flags = Location::IsRangeMarker | Location::IsCDMarker;
3248 _editor->cd_marker_bar_drag_rect->hide();
3251 flags = Location::IsRangeMarker;
3252 _editor->range_bar_drag_rect->hide();
3254 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3255 _editor->session->locations()->add (newloc, true);
3256 XMLNode &after = _editor->session->locations()->get_state();
3257 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3258 _editor->commit_reversible_command ();
3262 case CreateTransportMarker:
3263 // popup menu to pick loop or punch
3264 _editor->new_transport_marker_context_menu (&event->button, _item);
3268 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3270 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3275 _editor->session->locations()->marks_either_side (_grab_frame, start, end);
3277 if (end == max_frames) {
3278 end = _editor->session->current_end_frame ();
3281 if (start == max_frames) {
3282 start = _editor->session->current_start_frame ();
3285 switch (_editor->mouse_mode) {
3287 /* find the two markers on either side and then make the selection from it */
3288 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3292 /* find the two markers on either side of the click and make the range out of it */
3293 _editor->selection->set (0, start, end);
3302 _editor->stop_canvas_autoscroll ();
3308 RangeMarkerBarDrag::update_item (Location* location)
3310 double const x1 = _editor->frame_to_pixel (location->start());
3311 double const x2 = _editor->frame_to_pixel (location->end());
3313 _drag_rect->property_x1() = x1;
3314 _drag_rect->property_x2() = x2;
3318 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3320 Drag::start_grab (event, _editor->zoom_cursor);
3321 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3325 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3330 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3333 _editor->snap_to_with_modifier (_grab_frame, event);
3336 if (_current_pointer_frame == _last_pointer_frame) {
3340 /* base start and end on initial click position */
3341 if (_current_pointer_frame < _grab_frame) {
3342 start = _current_pointer_frame;
3345 end = _current_pointer_frame;
3346 start = _grab_frame;
3352 _editor->zoom_rect->show();
3353 _editor->zoom_rect->raise_to_top();
3356 _editor->reposition_zoom_rect(start, end);
3358 _last_pointer_frame = _current_pointer_frame;
3360 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3365 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3367 if (movement_occurred) {
3368 motion (event, false);
3370 if (_grab_frame < _last_pointer_frame) {
3371 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3373 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3376 _editor->temporal_zoom_to_frame (false, _grab_frame);
3378 temporal_zoom_step (false);
3379 center_screen (_grab_frame);
3383 _editor->zoom_rect->hide();
3386 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3389 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3390 region = &cnote->region_view();
3394 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3396 Drag::start_grab (event);
3399 drag_delta_note = 0;
3404 event_x = _current_pointer_x;
3405 event_y = _current_pointer_y;
3407 _item->property_parent().get_value()->w2i(event_x, event_y);
3409 last_x = region->snap_to_pixel(event_x);
3412 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3414 if (!(was_selected = cnote->selected())) {
3416 /* tertiary-click means extend selection - we'll do that on button release,
3417 so don't add it here, because otherwise we make it hard to figure
3418 out the "extend-to" range.
3421 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3424 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3427 region->note_selected (cnote, true);
3429 region->unique_select (cnote);
3436 NoteDrag::motion (GdkEvent*, bool)
3438 MidiStreamView* streamview = region->midi_stream_view();
3442 event_x = _current_pointer_x;
3443 event_y = _current_pointer_y;
3445 _item->property_parent().get_value()->w2i(event_x, event_y);
3447 event_x = region->snap_to_pixel(event_x);
3449 double dx = event_x - last_x;
3450 double dy = event_y - last_y;
3455 // Snap to note rows
3457 if (abs (dy) < streamview->note_height()) {
3460 int8_t this_delta_note;
3462 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3464 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3466 drag_delta_note -= this_delta_note;
3467 dy = streamview->note_height() * this_delta_note;
3468 last_y = last_y + dy;
3472 region->move_selection (dx, dy);
3474 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3476 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3477 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3478 _editor->show_verbose_canvas_cursor_with (buf);
3483 NoteDrag::finished (GdkEvent* ev, bool moved)
3485 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3488 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3491 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3493 region->note_deselected (cnote);
3496 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3497 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3499 if (!extend && !add && region->selection_size() > 1) {
3500 region->unique_select(cnote);
3501 } else if (extend) {
3502 region->note_selected (cnote, true, true);
3504 /* it was added during button press */
3509 region->note_dropped (cnote, drag_delta_x, drag_delta_note);