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);
189 if (apply_move_threshold() && _move_threshold_passed) {
191 _grab_frame = _current_pointer_frame;
192 _grab_x = _current_pointer_x;
193 _grab_y = _current_pointer_y;
194 _last_pointer_frame = _grab_frame;
195 _pointer_frame_offset = _grab_frame - _last_frame_position;
200 bool old_had_movement = _had_movement;
202 /* a motion event has happened, so we've had movement... */
203 _had_movement = true;
205 /* ... unless we're using a move threshold and we've not yet passed it */
206 if (apply_move_threshold() && !_move_threshold_passed) {
207 _had_movement = false;
210 if (active (_editor->mouse_mode)) {
212 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
213 if (!from_autoscroll) {
214 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
217 motion (event, _had_movement != old_had_movement);
229 _editor->stop_canvas_autoscroll ();
230 _editor->hide_verbose_canvas_cursor ();
235 /* put it back where it came from */
240 _item->i2w (cxw, cyw);
241 _item->move (_original_x - cxw, _original_y - cyw);
246 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
251 RegionView::RegionViewGoingAway.connect (mem_fun (*this, &RegionDrag::region_going_away));
255 RegionDrag::region_going_away (RegionView* v)
260 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
261 : RegionDrag (e, i, p, v),
271 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
273 Drag::start_grab (event);
275 _editor->show_verbose_time_cursor (_last_frame_position, 10);
278 RegionMotionDrag::TimeAxisViewSummary
279 RegionMotionDrag::get_time_axis_view_summary ()
281 int32_t children = 0;
282 TimeAxisViewSummary sum;
284 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
286 /* get a bitmask representing the visible tracks */
288 for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
289 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
290 TimeAxisView::Children children_list;
292 /* zeroes are audio/MIDI tracks. ones are other types. */
294 if (!rtv->hidden()) {
296 if (!rtv->is_track()) {
297 /* not an audio nor MIDI track */
298 sum.tracks = sum.tracks |= (0x01 << rtv->order());
301 sum.height_list[rtv->order()] = (*i)->current_height();
304 if ((children_list = rtv->get_child_list()).size() > 0) {
305 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
306 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
307 sum.height_list[rtv->order() + children] = (*j)->current_height();
318 RegionMotionDrag::compute_y_delta (
319 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
320 int32_t last_pointer_layer, int32_t current_pointer_layer,
321 TimeAxisViewSummary const & tavs,
322 int32_t* pointer_order_span, int32_t* pointer_layer_span,
323 int32_t* canvas_pointer_order_span
327 *pointer_order_span = 0;
328 *pointer_layer_span = 0;
332 bool clamp_y_axis = false;
334 /* the change in track order between this callback and the last */
335 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
336 /* the change in layer between this callback and the last;
337 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
338 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
340 if (*pointer_order_span != 0) {
342 /* find the actual pointer span, in terms of the number of visible tracks;
343 to do this, we reduce |pointer_order_span| by the number of hidden tracks
346 *canvas_pointer_order_span = *pointer_order_span;
347 if (last_pointer_view->order() >= current_pointer_view->order()) {
348 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
349 if (tavs.height_list[y] == 0) {
350 *canvas_pointer_order_span--;
354 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
355 if (tavs.height_list[y] == 0) {
356 *canvas_pointer_order_span++;
361 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
363 RegionView* rv = (*i);
365 if (rv->region()->locked()) {
369 double ix1, ix2, iy1, iy2;
370 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
371 rv->get_canvas_frame()->i2w (ix1, iy1);
372 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
374 /* get the new trackview for this particular region */
375 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
377 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
379 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
380 as surely this is a per-region thing... */
382 clamp_y_axis = y_movement_disallowed (
383 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
391 } else if (_dest_trackview == current_pointer_view) {
393 if (current_pointer_layer == last_pointer_layer) {
394 /* No movement; clamp */
400 _dest_trackview = current_pointer_view;
401 _dest_layer = current_pointer_layer;
409 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
411 *pending_region_position = 0;
413 /* compute the amount of pointer motion in frames, and where
414 the region would be if we moved it by that much.
416 if (_current_pointer_frame >= _pointer_frame_offset) {
418 nframes64_t sync_frame;
419 nframes64_t sync_offset;
422 *pending_region_position = _current_pointer_frame - _pointer_frame_offset;
424 sync_offset = _primary->region()->sync_offset (sync_dir);
426 /* we don't handle a sync point that lies before zero.
428 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
430 sync_frame = *pending_region_position + (sync_dir*sync_offset);
432 _editor->snap_to_with_modifier (sync_frame, event);
434 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
437 *pending_region_position = _last_frame_position;
442 if (*pending_region_position > max_frames - _primary->region()->length()) {
443 *pending_region_position = _last_frame_position;
448 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
450 /* now compute the canvas unit distance we need to move the regionview
451 to make it appear at the new location.
454 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
456 if (*pending_region_position <= _last_frame_position) {
458 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
460 RegionView* rv = (*i);
462 // If any regionview is at zero, we need to know so we can stop further leftward motion.
464 double ix1, ix2, iy1, iy2;
465 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
466 rv->get_canvas_frame()->i2w (ix1, iy1);
468 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
470 *pending_region_position = _last_frame_position;
477 _last_frame_position = *pending_region_position;
484 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
488 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
490 vector<int32_t>::iterator j;
492 /* *pointer* variables reflect things about the pointer; as we may be moving
493 multiple regions, much detail must be computed per-region */
495 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
496 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
497 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
498 is always 0 regardless of what the region's "real" layer is */
499 RouteTimeAxisView* current_pointer_view;
500 layer_t current_pointer_layer;
501 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
505 /* TimeAxisView that we were pointing at last time we entered this method */
506 TimeAxisView const * const last_pointer_view = _dest_trackview;
507 /* the order of the track that we were pointing at last time we entered this method */
508 int32_t const last_pointer_order = last_pointer_view->order ();
509 /* the layer that we were pointing at last time we entered this method */
510 layer_t const last_pointer_layer = _dest_layer;
512 int32_t pointer_order_span;
513 int32_t pointer_layer_span;
514 int32_t canvas_pointer_order_span;
516 bool const clamp_y_axis = compute_y_delta (
517 last_pointer_view, current_pointer_view,
518 last_pointer_layer, current_pointer_layer, tavs,
519 &pointer_order_span, &pointer_layer_span,
520 &canvas_pointer_order_span
523 nframes64_t pending_region_position;
524 double const x_delta = compute_x_delta (event, &pending_region_position);
526 /*************************************************************
528 ************************************************************/
530 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0) {
531 /* haven't reached next snap point, and we're not switching
532 trackviews nor layers. nothing to do.
537 /*************************************************************
539 ************************************************************/
541 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
543 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
545 RegionView* rv = (*i);
547 if (rv->region()->locked()) {
551 /* here we are calculating the y distance from the
552 top of the first track view to the top of the region
553 area of the track view that we're working on */
555 /* this x value is just a dummy value so that we have something
560 /* distance from the top of this track view to the region area
561 of our track view is always 1 */
565 /* convert to world coordinates, ie distance from the top of
568 rv->get_canvas_frame()->i2w (ix1, iy1);
570 /* compensate for the ruler section and the vertical scrollbar position */
571 iy1 += _editor->get_trackview_group_vertical_offset ();
575 // hide any dependent views
577 rv->get_time_axis_view().hide_dependent_views (*rv);
580 reparent to a non scrolling group so that we can keep the
581 region selection above all time axis views.
582 reparenting means we have to move the rv as the two
583 parent groups have different coordinates.
586 rv->get_canvas_group()->property_y() = iy1 - 1;
587 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
589 rv->fake_set_opaque (true);
592 /* current view for this particular region */
593 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
594 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
596 if (pointer_order_span != 0 && !clamp_y_axis) {
598 /* INTER-TRACK MOVEMENT */
600 /* move through the height list to the track that the region is currently on */
601 vector<int32_t>::iterator j = tavs.height_list.begin ();
603 while (j != tavs.height_list.end () && x != rtv->order ()) {
609 int32_t temp_pointer_order_span = canvas_pointer_order_span;
611 if (j != tavs.height_list.end ()) {
613 /* Account for layers in the original and
614 destination tracks. If we're moving around in layers we assume
615 that only one track is involved, so it's ok to use *pointer*
618 StreamView* lv = last_pointer_view->view ();
621 /* move to the top of the last trackview */
622 if (lv->layer_display () == Stacked) {
623 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
626 StreamView* cv = current_pointer_view->view ();
629 /* move to the right layer on the current trackview */
630 if (cv->layer_display () == Stacked) {
631 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
634 /* And for being on a non-topmost layer on the new
637 while (temp_pointer_order_span > 0) {
638 /* we're moving up canvas-wise,
639 so we need to find the next track height
641 if (j != tavs.height_list.begin()) {
645 if (x != last_pointer_order) {
647 ++temp_pointer_order_span;
652 temp_pointer_order_span--;
655 while (temp_pointer_order_span < 0) {
659 if (x != last_pointer_order) {
661 --temp_pointer_order_span;
665 if (j != tavs.height_list.end()) {
669 temp_pointer_order_span++;
673 /* find out where we'll be when we move and set height accordingly */
675 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
676 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
677 rv->set_height (temp_rtv->view()->child_height());
679 /* if you un-comment the following, the region colours will follow
680 the track colours whilst dragging; personally
681 i think this can confuse things, but never mind.
684 //const GdkColor& col (temp_rtv->view->get_region_color());
685 //rv->set_color (const_cast<GdkColor&>(col));
689 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
691 /* INTER-LAYER MOVEMENT in the same track */
692 y_delta = rtv->view()->child_height () * pointer_layer_span;
697 _editor->mouse_brush_insert_region (rv, pending_region_position);
699 rv->move (x_delta, y_delta);
702 } /* foreach region */
705 _editor->cursor_group->raise_to_top();
708 if (x_delta != 0 && !_brushing) {
709 _editor->show_verbose_time_cursor (_last_frame_position, 10);
714 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
716 if (_copy && first_move) {
717 copy_regions (event);
720 RegionMotionDrag::motion (event, first_move);
724 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
726 vector<RegionView*> copies;
727 boost::shared_ptr<Diskstream> ds;
728 boost::shared_ptr<Playlist> from_playlist;
729 RegionSelection new_views;
730 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
731 PlaylistSet modified_playlists;
732 PlaylistSet frozen_playlists;
733 list <sigc::connection> modified_playlist_connections;
734 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
735 nframes64_t drag_delta;
736 bool changed_tracks, changed_position;
737 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
738 RouteTimeAxisView* source_tv;
740 if (!movement_occurred) {
745 if (Config->get_edit_mode() == Splice && !_editor->pre_drag_region_selection.empty()) {
746 _editor->selection->set (_editor->pre_drag_region_selection);
747 _editor->pre_drag_region_selection.clear ();
751 /* all changes were made during motion event handlers */
754 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
755 copies.push_back (*i);
762 /* reverse this here so that we have the correct logic to finalize
766 if (Config->get_edit_mode() == Lock) {
767 _x_constrained = !_x_constrained;
771 if (_x_constrained) {
772 _editor->begin_reversible_command (_("fixed time region copy"));
774 _editor->begin_reversible_command (_("region copy"));
777 if (_x_constrained) {
778 _editor->begin_reversible_command (_("fixed time region drag"));
780 _editor->begin_reversible_command (_("region drag"));
784 _have_transaction = true;
786 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
787 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
789 drag_delta = _primary->region()->position() - _last_frame_position;
791 _editor->update_canvas_now ();
793 /* make a list of where each region ended up */
794 final = find_time_axis_views_and_layers ();
796 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
798 RegionView* rv = (*i);
799 RouteTimeAxisView* dest_rtv = final[*i].first;
800 layer_t dest_layer = final[*i].second;
804 if (rv->region()->locked()) {
809 if (changed_position && !_x_constrained) {
810 where = rv->region()->position() - drag_delta;
812 where = rv->region()->position();
815 boost::shared_ptr<Region> new_region;
818 /* we already made a copy */
819 new_region = rv->region();
821 /* undo the previous hide_dependent_views so that xfades don't
822 disappear on copying regions
825 //rv->get_time_axis_view().reveal_dependent_views (*rv);
827 } else if (changed_tracks && dest_rtv->playlist()) {
828 new_region = RegionFactory::create (rv->region());
831 if (changed_tracks || _copy) {
833 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
840 _editor->latest_regionviews.clear ();
842 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
844 insert_result = modified_playlists.insert (to_playlist);
846 if (insert_result.second) {
847 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
850 to_playlist->add_region (new_region, where);
851 if (dest_rtv->view()->layer_display() == Stacked) {
852 new_region->set_layer (dest_layer);
853 new_region->set_pending_explicit_relayer (true);
858 if (!_editor->latest_regionviews.empty()) {
859 // XXX why just the first one ? we only expect one
860 // commented out in nick_m's canvas reworking. is that intended?
861 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
862 new_views.push_back (_editor->latest_regionviews.front());
867 motion on the same track. plonk the previously reparented region
868 back to its original canvas group (its streamview).
869 No need to do anything for copies as they are fake regions which will be deleted.
872 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
873 rv->get_canvas_group()->property_y() = 0;
875 /* just change the model */
877 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
879 if (dest_rtv->view()->layer_display() == Stacked) {
880 rv->region()->set_layer (dest_layer);
881 rv->region()->set_pending_explicit_relayer (true);
884 insert_result = modified_playlists.insert (playlist);
886 if (insert_result.second) {
887 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
889 /* freeze to avoid lots of relayering in the case of a multi-region drag */
890 frozen_insert_result = frozen_playlists.insert(playlist);
892 if (frozen_insert_result.second) {
896 rv->region()->set_position (where, (void*) this);
899 if (changed_tracks && !_copy) {
901 /* get the playlist where this drag started. we can't use rv->region()->playlist()
902 because we may have copied the region and it has not been attached to a playlist.
905 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
906 ds = source_tv->get_diskstream();
907 from_playlist = ds->playlist();
911 assert (from_playlist);
913 /* moved to a different audio track, without copying */
915 /* the region that used to be in the old playlist is not
916 moved to the new one - we use a copy of it. as a result,
917 any existing editor for the region should no longer be
921 rv->hide_region_editor();
922 rv->fake_set_opaque (false);
924 /* remove the region from the old playlist */
926 insert_result = modified_playlists.insert (from_playlist);
928 if (insert_result.second) {
929 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
932 from_playlist->remove_region (rv->region());
934 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
935 was selected in all of them, then removing it from a playlist will have removed all
936 trace of it from the selection (i.e. there were N regions selected, we removed 1,
937 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
938 corresponding regionview, and the selection is now empty).
940 this could have invalidated any and all iterators into the region selection.
942 the heuristic we use here is: if the region selection is empty, break out of the loop
943 here. if the region selection is not empty, then restart the loop because we know that
944 we must have removed at least the region(view) we've just been working on as well as any
945 that we processed on previous iterations.
947 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
951 if (_views.empty()) {
962 copies.push_back (rv);
966 _editor->selection->add (new_views);
968 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
973 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
974 _editor->session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
977 _editor->commit_reversible_command ();
979 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
986 RegionMotionDrag::x_move_allowed () const
988 if (Config->get_edit_mode() == Lock) {
989 /* in locked edit mode, reverse the usual meaning of _x_constrained */
990 return _x_constrained;
993 return !_x_constrained;
997 RegionMotionDrag::copy_regions (GdkEvent* event)
999 /* duplicate the regionview(s) and region(s) */
1001 list<RegionView*> new_regionviews;
1003 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1005 RegionView* rv = (*i);
1006 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1007 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1009 const boost::shared_ptr<const Region> original = rv->region();
1010 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1014 boost::shared_ptr<AudioRegion> audioregion_copy
1015 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1016 nrv = new AudioRegionView (*arv, audioregion_copy);
1018 boost::shared_ptr<MidiRegion> midiregion_copy
1019 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1020 nrv = new MidiRegionView (*mrv, midiregion_copy);
1025 nrv->get_canvas_group()->show ();
1026 new_regionviews.push_back (nrv);
1029 if (new_regionviews.empty()) {
1033 /* reflect the fact that we are dragging the copies */
1035 _primary = new_regionviews.front();
1036 _views = new_regionviews;
1038 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1041 sync the canvas to what we think is its current state
1042 without it, the canvas seems to
1043 "forget" to update properly after the upcoming reparent()
1044 ..only if the mouse is in rapid motion at the time of the grab.
1045 something to do with regionview creation raking so long?
1047 _editor->update_canvas_now();
1051 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1053 /* Which trackview is this ? */
1055 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1056 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1057 (*layer) = tvp.second;
1059 if (*tv && (*tv)->layer_display() == Overlaid) {
1063 /* The region motion is only processed if the pointer is over
1067 if (!(*tv) || !(*tv)->is_track()) {
1068 /* To make sure we hide the verbose canvas cursor when the mouse is
1069 not held over and audiotrack.
1071 _editor->hide_verbose_canvas_cursor ();
1078 /** @param new_order New track order.
1079 * @param old_order Old track order.
1080 * @param visible_y_low Lowest visible order.
1081 * @return true if y movement should not happen, otherwise false.
1084 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1086 if (new_order != old_order) {
1088 /* this isn't the pointer track */
1092 /* moving up the canvas */
1093 if ( (new_order - y_span) >= tavs.visible_y_low) {
1097 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1098 int32_t visible_tracks = 0;
1099 while (visible_tracks < y_span ) {
1101 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1102 /* passing through a hidden track */
1107 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1108 /* moving to a non-track; disallow */
1114 /* moving beyond the lowest visible track; disallow */
1118 } else if (y_span < 0) {
1120 /* moving down the canvas */
1121 if ((new_order - y_span) <= tavs.visible_y_high) {
1123 int32_t visible_tracks = 0;
1125 while (visible_tracks > y_span ) {
1128 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1129 /* passing through a hidden track */
1134 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1135 /* moving to a non-track; disallow */
1142 /* moving beyond the highest visible track; disallow */
1149 /* this is the pointer's track */
1151 if ((new_order - y_span) > tavs.visible_y_high) {
1152 /* we will overflow */
1154 } else if ((new_order - y_span) < tavs.visible_y_low) {
1155 /* we will overflow */
1164 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1165 : RegionMotionDrag (e, i, p, v, b),
1168 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1170 _dest_trackview = tv;
1171 if (tv->layer_display() == Overlaid) {
1174 _dest_layer = _primary->region()->layer ();
1178 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1179 if (rtv && rtv->is_track()) {
1180 speed = rtv->get_diskstream()->speed ();
1183 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1187 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1189 RegionMotionDrag::start_grab (event, c);
1191 _pointer_frame_offset = _grab_frame - _last_frame_position;
1194 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1195 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1197 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1198 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1200 _primary = v->view()->create_region_view (r, false, false);
1202 _primary->get_canvas_group()->show ();
1203 _primary->set_position (pos, 0);
1204 _views.push_back (_primary);
1206 _last_frame_position = pos;
1208 _item = _primary->get_canvas_group ();
1209 _dest_trackview = v;
1210 _dest_layer = _primary->region()->layer ();
1213 map<RegionView*, pair<RouteTimeAxisView*, int> >
1214 RegionMotionDrag::find_time_axis_views_and_layers ()
1216 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1218 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1220 double ix1, ix2, iy1, iy2;
1221 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1222 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1223 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1225 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1226 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1234 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1236 _editor->update_canvas_now ();
1238 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1240 RouteTimeAxisView* dest_rtv = final[_primary].first;
1242 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1243 _primary->get_canvas_group()->property_y() = 0;
1245 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1247 _editor->begin_reversible_command (_("insert region"));
1248 XMLNode& before = playlist->get_state ();
1249 playlist->add_region (_primary->region (), _last_frame_position);
1250 _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1251 _editor->commit_reversible_command ();
1258 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1259 : RegionMoveDrag (e, i, p, v, false, false)
1264 struct RegionSelectionByPosition {
1265 bool operator() (RegionView*a, RegionView* b) {
1266 return a->region()->position () < b->region()->position();
1271 RegionSpliceDrag::motion (GdkEvent* /*event*/, bool)
1273 RouteTimeAxisView* tv;
1276 if (!check_possible (&tv, &layer)) {
1282 if (_current_pointer_x - _grab_x > 0) {
1288 RegionSelection copy (_editor->selection->regions);
1290 RegionSelectionByPosition cmp;
1293 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1295 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1301 boost::shared_ptr<Playlist> playlist;
1303 if ((playlist = atv->playlist()) == 0) {
1307 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1312 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1316 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1322 playlist->shuffle ((*i)->region(), dir);
1324 _grab_x = _current_pointer_x;
1329 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1335 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1343 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1345 _dest_trackview = _view;
1347 Drag::start_grab (event);
1352 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1355 // TODO: create region-create-drag region view here
1358 // TODO: resize region-create-drag region view here
1362 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1364 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1370 if (!movement_occurred) {
1371 mtv->add_region (_grab_frame);
1373 motion (event, false);
1374 // TODO: create region-create-drag region here
1378 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1386 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1389 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1391 Drag::start_grab (event);
1393 region = &cnote->region_view();
1395 double region_start = region->get_position_pixels();
1396 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1398 if (_grab_x <= middle_point) {
1399 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1402 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1406 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1408 if (event->motion.state & Keyboard::PrimaryModifier) {
1414 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1416 if (ms.size() > 1) {
1417 /* has to be relative, may make no sense otherwise */
1421 region->note_selected (cnote, true);
1423 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1424 MidiRegionSelection::iterator next;
1427 (*r)->begin_resizing (at_front);
1433 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1435 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1436 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1437 (*r)->update_resizing (at_front, _current_pointer_x - _grab_x, relative);
1442 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1444 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1445 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1446 (*r)->commit_resizing (at_front, _current_pointer_x - _grab_x, relative);
1451 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1457 RegionGainDrag::finished (GdkEvent *, bool)
1462 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1463 : RegionDrag (e, i, p, v)
1469 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1472 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1473 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1475 if (tv && tv->is_track()) {
1476 speed = tv->get_diskstream()->speed();
1479 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1480 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1481 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1483 Drag::start_grab (event, _editor->trimmer_cursor);
1485 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1486 _operation = ContentsTrim;
1488 /* These will get overridden for a point trim.*/
1489 if (_current_pointer_frame < (region_start + region_length/2)) {
1490 /* closer to start */
1491 _operation = StartTrim;
1492 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1494 _operation = EndTrim;
1498 switch (_operation) {
1500 _editor->show_verbose_time_cursor (region_start, 10);
1503 _editor->show_verbose_time_cursor (region_end, 10);
1506 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1512 TrimDrag::motion (GdkEvent* event, bool first_move)
1514 RegionView* rv = _primary;
1515 nframes64_t frame_delta = 0;
1517 bool left_direction;
1518 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1520 /* snap modifier works differently here..
1521 its' current state has to be passed to the
1522 various trim functions in order to work properly
1526 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1527 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1528 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1530 if (tv && tv->is_track()) {
1531 speed = tv->get_diskstream()->speed();
1534 if (_last_pointer_frame > _current_pointer_frame) {
1535 left_direction = true;
1537 left_direction = false;
1540 _editor->snap_to_with_modifier (_current_pointer_frame, event);
1546 switch (_operation) {
1548 trim_type = "Region start trim";
1551 trim_type = "Region end trim";
1554 trim_type = "Region content trim";
1558 _editor->begin_reversible_command (trim_type);
1559 _have_transaction = true;
1561 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1562 (*i)->fake_set_opaque(false);
1563 (*i)->region()->freeze ();
1565 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1568 arv->temporarily_hide_envelope ();
1571 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1572 insert_result = _editor->motion_frozen_playlists.insert (pl);
1574 if (insert_result.second) {
1575 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1581 if (_current_pointer_frame == _last_pointer_frame) {
1585 /* XXX i hope to god that we can really conclude this ... */
1586 _have_transaction = true;
1588 if (left_direction) {
1589 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1591 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1594 bool non_overlap_trim = false;
1596 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1597 non_overlap_trim = true;
1600 switch (_operation) {
1602 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1606 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1607 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1613 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1617 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1618 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1625 bool swap_direction = false;
1627 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1628 swap_direction = true;
1631 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1633 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1639 switch (_operation) {
1641 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1644 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1647 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1651 _last_pointer_frame = _current_pointer_frame;
1656 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1658 if (movement_occurred) {
1659 motion (event, false);
1661 if (!_editor->selection->selected (_primary)) {
1662 _editor->thaw_region_after_trim (*_primary);
1665 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1666 _editor->thaw_region_after_trim (**i);
1667 (*i)->fake_set_opaque (true);
1670 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1672 if (_have_transaction) {
1673 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1677 _editor->motion_frozen_playlists.clear ();
1679 if (_have_transaction) {
1680 _editor->commit_reversible_command();
1684 /* no mouse movement */
1685 _editor->point_trim (event);
1689 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1693 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1698 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1701 // create a dummy marker for visual representation of moving the copy.
1702 // The actual copying is not done before we reach the finish callback.
1704 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1705 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1706 *new MeterSection (_marker->meter()));
1708 _item = &new_marker->the_item ();
1709 _marker = new_marker;
1713 MetricSection& section (_marker->meter());
1715 if (!section.movable()) {
1721 Drag::start_grab (event, cursor);
1723 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1725 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1729 MeterMarkerDrag::motion (GdkEvent* event, bool)
1731 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1733 if (adjusted_frame == _last_pointer_frame) {
1737 _marker->set_position (adjusted_frame);
1739 _last_pointer_frame = adjusted_frame;
1741 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1745 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1747 if (!movement_occurred) {
1751 motion (event, false);
1755 TempoMap& map (_editor->session->tempo_map());
1756 map.bbt_time (_last_pointer_frame, when);
1758 if (_copy == true) {
1759 _editor->begin_reversible_command (_("copy meter mark"));
1760 XMLNode &before = map.get_state();
1761 map.add_meter (_marker->meter(), when);
1762 XMLNode &after = map.get_state();
1763 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1764 _editor->commit_reversible_command ();
1766 // delete the dummy marker we used for visual representation of copying.
1767 // a new visual marker will show up automatically.
1770 _editor->begin_reversible_command (_("move meter mark"));
1771 XMLNode &before = map.get_state();
1772 map.move_meter (_marker->meter(), when);
1773 XMLNode &after = map.get_state();
1774 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1775 _editor->commit_reversible_command ();
1779 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1783 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1788 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1793 // create a dummy marker for visual representation of moving the copy.
1794 // The actual copying is not done before we reach the finish callback.
1796 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1797 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1798 *new TempoSection (_marker->tempo()));
1800 _item = &new_marker->the_item ();
1801 _marker = new_marker;
1805 MetricSection& section (_marker->tempo());
1807 if (!section.movable()) {
1812 Drag::start_grab (event, cursor);
1814 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1815 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1819 TempoMarkerDrag::motion (GdkEvent* event, bool)
1821 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1823 if (adjusted_frame == _last_pointer_frame) {
1827 /* OK, we've moved far enough to make it worth actually move the thing. */
1829 _marker->set_position (adjusted_frame);
1831 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1833 _last_pointer_frame = adjusted_frame;
1837 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1839 if (!movement_occurred) {
1843 motion (event, false);
1847 TempoMap& map (_editor->session->tempo_map());
1848 map.bbt_time (_last_pointer_frame, when);
1850 if (_copy == true) {
1851 _editor->begin_reversible_command (_("copy tempo mark"));
1852 XMLNode &before = map.get_state();
1853 map.add_tempo (_marker->tempo(), when);
1854 XMLNode &after = map.get_state();
1855 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1856 _editor->commit_reversible_command ();
1858 // delete the dummy marker we used for visual representation of copying.
1859 // a new visual marker will show up automatically.
1862 _editor->begin_reversible_command (_("move tempo mark"));
1863 XMLNode &before = map.get_state();
1864 map.move_tempo (_marker->tempo(), when);
1865 XMLNode &after = map.get_state();
1866 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1867 _editor->commit_reversible_command ();
1872 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1876 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1881 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1883 Drag::start_grab (event, c);
1887 nframes64_t where = _editor->event_frame (event, 0, 0);
1889 _editor->snap_to_with_modifier (where, event);
1890 _editor->playhead_cursor->set_position (where);
1894 if (_cursor == _editor->playhead_cursor) {
1895 _editor->_dragging_playhead = true;
1897 if (_editor->session && _was_rolling && _stop) {
1898 _editor->session->request_stop ();
1901 if (_editor->session && _editor->session->is_auditioning()) {
1902 _editor->session->cancel_audition ();
1906 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1910 CursorDrag::motion (GdkEvent* event, bool)
1912 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1914 if (adjusted_frame == _last_pointer_frame) {
1918 _cursor->set_position (adjusted_frame);
1920 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1923 _editor->update_canvas_now ();
1925 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1927 _last_pointer_frame = adjusted_frame;
1931 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1933 _editor->_dragging_playhead = false;
1935 if (!movement_occurred && _stop) {
1939 motion (event, false);
1941 if (_item == &_editor->playhead_cursor->canvas_item) {
1942 if (_editor->session) {
1943 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1944 _editor->_pending_locate_request = true;
1949 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1950 : RegionDrag (e, i, p, v)
1956 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1958 Drag::start_grab (event, cursor);
1960 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1961 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1963 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1964 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
1968 FadeInDrag::motion (GdkEvent* event, bool)
1970 nframes64_t fade_length;
1972 nframes64_t const pos = adjusted_current_frame (event);
1974 boost::shared_ptr<Region> region = _primary->region ();
1976 if (pos < (region->position() + 64)) {
1977 fade_length = 64; // this should be a minimum defined somewhere
1978 } else if (pos > region->last_frame()) {
1979 fade_length = region->length();
1981 fade_length = pos - region->position();
1984 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1986 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1992 tmp->reset_fade_in_shape_width (fade_length);
1995 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1999 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2001 if (!movement_occurred) {
2005 nframes64_t fade_length;
2007 nframes64_t const pos = adjusted_current_frame (event);
2009 boost::shared_ptr<Region> region = _primary->region ();
2011 if (pos < (region->position() + 64)) {
2012 fade_length = 64; // this should be a minimum defined somewhere
2013 } else if (pos > region->last_frame()) {
2014 fade_length = region->length();
2016 fade_length = pos - region->position();
2019 _editor->begin_reversible_command (_("change fade in length"));
2021 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2023 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2029 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2030 XMLNode &before = alist->get_state();
2032 tmp->audio_region()->set_fade_in_length (fade_length);
2033 tmp->audio_region()->set_fade_in_active (true);
2035 XMLNode &after = alist->get_state();
2036 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2039 _editor->commit_reversible_command ();
2042 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2043 : RegionDrag (e, i, p, v)
2049 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2051 Drag::start_grab (event, cursor);
2053 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2054 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2056 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2057 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2061 FadeOutDrag::motion (GdkEvent* event, bool)
2063 nframes64_t fade_length;
2065 nframes64_t const pos = adjusted_current_frame (event);
2067 boost::shared_ptr<Region> region = _primary->region ();
2069 if (pos > (region->last_frame() - 64)) {
2070 fade_length = 64; // this should really be a minimum fade defined somewhere
2072 else if (pos < region->position()) {
2073 fade_length = region->length();
2076 fade_length = region->last_frame() - pos;
2079 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2081 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2087 tmp->reset_fade_out_shape_width (fade_length);
2090 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2094 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2096 if (!movement_occurred) {
2100 nframes64_t fade_length;
2102 nframes64_t const pos = adjusted_current_frame (event);
2104 boost::shared_ptr<Region> region = _primary->region ();
2106 if (pos > (region->last_frame() - 64)) {
2107 fade_length = 64; // this should really be a minimum fade defined somewhere
2109 else if (pos < region->position()) {
2110 fade_length = region->length();
2113 fade_length = region->last_frame() - pos;
2116 _editor->begin_reversible_command (_("change fade out length"));
2118 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2120 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2126 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2127 XMLNode &before = alist->get_state();
2129 tmp->audio_region()->set_fade_out_length (fade_length);
2130 tmp->audio_region()->set_fade_out_active (true);
2132 XMLNode &after = alist->get_state();
2133 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2136 _editor->commit_reversible_command ();
2139 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2142 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2145 _points.push_back (Gnome::Art::Point (0, 0));
2146 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2148 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2149 _line->property_width_pixels() = 1;
2150 _line->property_points () = _points;
2153 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2156 MarkerDrag::~MarkerDrag ()
2158 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2164 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2166 Drag::start_grab (event, cursor);
2170 Location *location = _editor->find_location_from_marker (_marker, is_start);
2171 _editor->_dragging_edit_point = true;
2173 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2175 update_item (location);
2177 // _drag_line->show();
2178 // _line->raise_to_top();
2181 _editor->show_verbose_time_cursor (location->start(), 10);
2183 _editor->show_verbose_time_cursor (location->end(), 10);
2186 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2189 case Selection::Toggle:
2190 _editor->selection->toggle (_marker);
2192 case Selection::Set:
2193 if (!_editor->selection->selected (_marker)) {
2194 _editor->selection->set (_marker);
2197 case Selection::Extend:
2199 Locations::LocationList ll;
2200 list<Marker*> to_add;
2202 _editor->selection->markers.range (s, e);
2203 s = min (_marker->position(), s);
2204 e = max (_marker->position(), e);
2207 if (e < max_frames) {
2210 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2211 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2212 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2215 to_add.push_back (lm->start);
2218 to_add.push_back (lm->end);
2222 if (!to_add.empty()) {
2223 _editor->selection->add (to_add);
2227 case Selection::Add:
2228 _editor->selection->add (_marker);
2232 /* set up copies for us to manipulate during the drag */
2234 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2235 Location *l = _editor->find_location_from_marker (*i, is_start);
2236 _copied_locations.push_back (new Location (*l));
2241 MarkerDrag::motion (GdkEvent* event, bool)
2243 nframes64_t f_delta = 0;
2245 bool move_both = false;
2247 Location *real_location;
2248 Location *copy_location = 0;
2250 nframes64_t const newframe = adjusted_current_frame (event);
2252 nframes64_t next = newframe;
2254 if (_current_pointer_frame == _last_pointer_frame) {
2258 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2262 MarkerSelection::iterator i;
2263 list<Location*>::iterator x;
2265 /* find the marker we're dragging, and compute the delta */
2267 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2268 x != _copied_locations.end() && i != _editor->selection->markers.end();
2274 if (marker == _marker) {
2276 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2281 if (real_location->is_mark()) {
2282 f_delta = newframe - copy_location->start();
2286 switch (marker->type()) {
2288 case Marker::LoopStart:
2289 case Marker::PunchIn:
2290 f_delta = newframe - copy_location->start();
2294 case Marker::LoopEnd:
2295 case Marker::PunchOut:
2296 f_delta = newframe - copy_location->end();
2299 /* what kind of marker is this ? */
2307 if (i == _editor->selection->markers.end()) {
2308 /* hmm, impossible - we didn't find the dragged marker */
2312 /* now move them all */
2314 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2315 x != _copied_locations.end() && i != _editor->selection->markers.end();
2321 /* call this to find out if its the start or end */
2323 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2327 if (real_location->locked()) {
2331 if (copy_location->is_mark()) {
2335 copy_location->set_start (copy_location->start() + f_delta);
2339 nframes64_t new_start = copy_location->start() + f_delta;
2340 nframes64_t new_end = copy_location->end() + f_delta;
2342 if (is_start) { // start-of-range marker
2345 copy_location->set_start (new_start);
2346 copy_location->set_end (new_end);
2347 } else if (new_start < copy_location->end()) {
2348 copy_location->set_start (new_start);
2350 _editor->snap_to (next, 1, true);
2351 copy_location->set_end (next);
2352 copy_location->set_start (newframe);
2355 } else { // end marker
2358 copy_location->set_end (new_end);
2359 copy_location->set_start (new_start);
2360 } else if (new_end > copy_location->start()) {
2361 copy_location->set_end (new_end);
2362 } else if (newframe > 0) {
2363 _editor->snap_to (next, -1, true);
2364 copy_location->set_start (next);
2365 copy_location->set_end (newframe);
2370 update_item (copy_location);
2372 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2375 lm->set_position (copy_location->start(), copy_location->end());
2379 _last_pointer_frame = _current_pointer_frame;
2381 assert (!_copied_locations.empty());
2383 _editor->show_verbose_time_cursor (newframe, 10);
2386 _editor->update_canvas_now ();
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 = ArdourKeyboard::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 = ArdourKeyboard::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);