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;
47 using namespace Editing;
48 using namespace ArdourCanvas;
50 using Gtkmm2ext::Keyboard;
52 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
54 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
57 , _pointer_frame_offset (0)
59 , _last_pointer_frame (0)
60 , _current_pointer_frame (0)
61 , _have_transaction (false)
62 , _had_movement (false)
63 , _move_threshold_passed (false)
69 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
75 cursor = _editor->which_grabber_cursor ();
78 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
82 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
85 cursor = _editor->which_grabber_cursor ();
88 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
90 if (Keyboard::is_button2_event (&event->button)) {
91 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
92 _y_constrained = true;
93 _x_constrained = false;
95 _y_constrained = false;
96 _x_constrained = true;
99 _x_constrained = false;
100 _y_constrained = false;
103 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
104 _last_pointer_frame = _grab_frame;
105 _current_pointer_frame = _grab_frame;
106 _current_pointer_x = _grab_x;
107 _current_pointer_y = _grab_y;
108 _last_pointer_x = _current_pointer_x;
109 _last_pointer_y = _current_pointer_y;
113 _item->i2w (_original_x, _original_y);
115 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
119 if (_editor->session() && _editor->session()->transport_rolling()) {
122 _was_rolling = false;
125 switch (_editor->snap_type()) {
126 case SnapToRegionStart:
127 case SnapToRegionEnd:
128 case SnapToRegionSync:
129 case SnapToRegionBoundary:
130 _editor->build_region_boundary_cache ();
137 /** @param event GDK event, or 0.
138 * @return true if some movement occurred, otherwise false.
141 Drag::end_grab (GdkEvent* event)
145 _editor->stop_canvas_autoscroll ();
147 _item->ungrab (event ? event->button.time : 0);
149 _last_pointer_x = _current_pointer_x;
150 _last_pointer_y = _current_pointer_y;
151 finished (event, _had_movement);
153 _editor->hide_verbose_canvas_cursor();
157 return _had_movement;
161 Drag::adjusted_current_frame (GdkEvent* event) const
165 if (_current_pointer_frame > _pointer_frame_offset) {
166 pos = _current_pointer_frame - _pointer_frame_offset;
169 _editor->snap_to_with_modifier (pos, event);
175 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
177 _last_pointer_x = _current_pointer_x;
178 _last_pointer_y = _current_pointer_y;
179 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
181 if (!from_autoscroll && !_move_threshold_passed) {
183 bool const xp = (::llabs ((nframes64_t) (_current_pointer_x - _grab_x)) > 4LL);
184 bool const yp = (::llabs ((nframes64_t) (_current_pointer_y - _grab_y)) > 4LL);
186 _move_threshold_passed = (xp || yp);
189 bool old_had_movement = _had_movement;
191 /* a motion event has happened, so we've had movement... */
192 _had_movement = true;
194 /* ... unless we're using a move threshold and we've not yet passed it */
195 if (apply_move_threshold() && !_move_threshold_passed) {
196 _had_movement = false;
199 if (active (_editor->mouse_mode) && _had_movement) {
201 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
202 if (!from_autoscroll) {
203 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
206 motion (event, _had_movement != old_had_movement);
218 _editor->stop_canvas_autoscroll ();
219 _editor->hide_verbose_canvas_cursor ();
224 /* put it back where it came from */
229 _item->i2w (cxw, cyw);
230 _item->move (_original_x - cxw, _original_y - cyw);
235 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
240 death_connection = RegionView::RegionViewGoingAway.connect (sigc::mem_fun (*this, &RegionDrag::region_going_away));
244 RegionDrag::region_going_away (RegionView* v)
249 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
250 : RegionDrag (e, i, p, v),
260 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
262 Drag::start_grab (event);
264 _editor->show_verbose_time_cursor (_last_frame_position, 10);
267 RegionMotionDrag::TimeAxisViewSummary
268 RegionMotionDrag::get_time_axis_view_summary ()
270 int32_t children = 0;
271 TimeAxisViewSummary sum;
273 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
275 /* get a bitmask representing the visible tracks */
277 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
278 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
279 TimeAxisView::Children children_list;
281 /* zeroes are audio/MIDI tracks. ones are other types. */
283 if (!rtv->hidden()) {
285 if (!rtv->is_track()) {
286 /* not an audio nor MIDI track */
287 sum.tracks = sum.tracks |= (0x01 << rtv->order());
290 sum.height_list[rtv->order()] = (*i)->current_height();
293 if ((children_list = rtv->get_child_list()).size() > 0) {
294 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
295 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
296 sum.height_list[rtv->order() + children] = (*j)->current_height();
307 RegionMotionDrag::compute_y_delta (
308 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
309 int32_t last_pointer_layer, int32_t current_pointer_layer,
310 TimeAxisViewSummary const & tavs,
311 int32_t* pointer_order_span, int32_t* pointer_layer_span,
312 int32_t* canvas_pointer_order_span
316 *pointer_order_span = 0;
317 *pointer_layer_span = 0;
321 bool clamp_y_axis = false;
323 /* the change in track order between this callback and the last */
324 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
325 /* the change in layer between this callback and the last;
326 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
327 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
329 if (*pointer_order_span != 0) {
331 /* find the actual pointer span, in terms of the number of visible tracks;
332 to do this, we reduce |pointer_order_span| by the number of hidden tracks
335 *canvas_pointer_order_span = *pointer_order_span;
336 if (last_pointer_view->order() >= current_pointer_view->order()) {
337 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
338 if (tavs.height_list[y] == 0) {
339 *canvas_pointer_order_span--;
343 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
344 if (tavs.height_list[y] == 0) {
345 *canvas_pointer_order_span++;
350 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
352 RegionView* rv = (*i);
354 if (rv->region()->locked()) {
358 double ix1, ix2, iy1, iy2;
359 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
360 rv->get_canvas_frame()->i2w (ix1, iy1);
361 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
363 /* get the new trackview for this particular region */
364 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
366 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
368 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
369 as surely this is a per-region thing... */
371 clamp_y_axis = y_movement_disallowed (
372 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
380 } else if (_dest_trackview == current_pointer_view) {
382 if (current_pointer_layer == last_pointer_layer) {
383 /* No movement; clamp */
389 _dest_trackview = current_pointer_view;
390 _dest_layer = current_pointer_layer;
398 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
400 *pending_region_position = 0;
402 /* compute the amount of pointer motion in frames, and where
403 the region would be if we moved it by that much.
405 if (_current_pointer_frame >= _pointer_frame_offset) {
407 nframes64_t sync_frame;
408 nframes64_t sync_offset;
411 *pending_region_position = _current_pointer_frame - _pointer_frame_offset;
413 sync_offset = _primary->region()->sync_offset (sync_dir);
415 /* we don't handle a sync point that lies before zero.
417 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
419 sync_frame = *pending_region_position + (sync_dir*sync_offset);
421 _editor->snap_to_with_modifier (sync_frame, event);
423 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
426 *pending_region_position = _last_frame_position;
431 if (*pending_region_position > max_frames - _primary->region()->length()) {
432 *pending_region_position = _last_frame_position;
437 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
439 /* now compute the canvas unit distance we need to move the regionview
440 to make it appear at the new location.
443 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
445 if (*pending_region_position <= _last_frame_position) {
447 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
449 RegionView* rv = (*i);
451 // If any regionview is at zero, we need to know so we can stop further leftward motion.
453 double ix1, ix2, iy1, iy2;
454 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
455 rv->get_canvas_frame()->i2w (ix1, iy1);
457 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
459 *pending_region_position = _last_frame_position;
466 _last_frame_position = *pending_region_position;
473 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
477 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
479 vector<int32_t>::iterator j;
481 /* *pointer* variables reflect things about the pointer; as we may be moving
482 multiple regions, much detail must be computed per-region */
484 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
485 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
486 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
487 is always 0 regardless of what the region's "real" layer is */
488 RouteTimeAxisView* current_pointer_view;
489 layer_t current_pointer_layer;
490 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
494 /* TimeAxisView that we were pointing at last time we entered this method */
495 TimeAxisView const * const last_pointer_view = _dest_trackview;
496 /* the order of the track that we were pointing at last time we entered this method */
497 int32_t const last_pointer_order = last_pointer_view->order ();
498 /* the layer that we were pointing at last time we entered this method */
499 layer_t const last_pointer_layer = _dest_layer;
501 int32_t pointer_order_span;
502 int32_t pointer_layer_span;
503 int32_t canvas_pointer_order_span;
505 bool const clamp_y_axis = compute_y_delta (
506 last_pointer_view, current_pointer_view,
507 last_pointer_layer, current_pointer_layer, tavs,
508 &pointer_order_span, &pointer_layer_span,
509 &canvas_pointer_order_span
512 nframes64_t pending_region_position;
513 double const x_delta = compute_x_delta (event, &pending_region_position);
515 /*************************************************************
517 ************************************************************/
519 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
520 /* haven't reached next snap point, and we're not switching
521 trackviews nor layers. nothing to do.
526 /*************************************************************
528 ************************************************************/
530 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
532 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
534 RegionView* rv = (*i);
536 if (rv->region()->locked()) {
540 /* here we are calculating the y distance from the
541 top of the first track view to the top of the region
542 area of the track view that we're working on */
544 /* this x value is just a dummy value so that we have something
549 /* distance from the top of this track view to the region area
550 of our track view is always 1 */
554 /* convert to world coordinates, ie distance from the top of
557 rv->get_canvas_frame()->i2w (ix1, iy1);
559 /* compensate for the ruler section and the vertical scrollbar position */
560 iy1 += _editor->get_trackview_group_vertical_offset ();
564 // hide any dependent views
566 rv->get_time_axis_view().hide_dependent_views (*rv);
569 reparent to a non scrolling group so that we can keep the
570 region selection above all time axis views.
571 reparenting means we have to move the rv as the two
572 parent groups have different coordinates.
575 rv->get_canvas_group()->property_y() = iy1 - 1;
576 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
578 rv->fake_set_opaque (true);
581 /* current view for this particular region */
582 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
583 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
585 if (pointer_order_span != 0 && !clamp_y_axis) {
587 /* INTER-TRACK MOVEMENT */
589 /* move through the height list to the track that the region is currently on */
590 vector<int32_t>::iterator j = tavs.height_list.begin ();
592 while (j != tavs.height_list.end () && x != rtv->order ()) {
598 int32_t temp_pointer_order_span = canvas_pointer_order_span;
600 if (j != tavs.height_list.end ()) {
602 /* Account for layers in the original and
603 destination tracks. If we're moving around in layers we assume
604 that only one track is involved, so it's ok to use *pointer*
607 StreamView* lv = last_pointer_view->view ();
610 /* move to the top of the last trackview */
611 if (lv->layer_display () == Stacked) {
612 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
615 StreamView* cv = current_pointer_view->view ();
618 /* move to the right layer on the current trackview */
619 if (cv->layer_display () == Stacked) {
620 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
623 /* And for being on a non-topmost layer on the new
626 while (temp_pointer_order_span > 0) {
627 /* we're moving up canvas-wise,
628 so we need to find the next track height
630 if (j != tavs.height_list.begin()) {
634 if (x != last_pointer_order) {
636 ++temp_pointer_order_span;
641 temp_pointer_order_span--;
644 while (temp_pointer_order_span < 0) {
648 if (x != last_pointer_order) {
650 --temp_pointer_order_span;
654 if (j != tavs.height_list.end()) {
658 temp_pointer_order_span++;
662 /* find out where we'll be when we move and set height accordingly */
664 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
665 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
666 rv->set_height (temp_rtv->view()->child_height());
668 /* if you un-comment the following, the region colours will follow
669 the track colours whilst dragging; personally
670 i think this can confuse things, but never mind.
673 //const GdkColor& col (temp_rtv->view->get_region_color());
674 //rv->set_color (const_cast<GdkColor&>(col));
678 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
680 /* INTER-LAYER MOVEMENT in the same track */
681 y_delta = rtv->view()->child_height () * pointer_layer_span;
686 _editor->mouse_brush_insert_region (rv, pending_region_position);
688 rv->move (x_delta, y_delta);
691 } /* foreach region */
694 _editor->cursor_group->raise_to_top();
697 if (x_delta != 0 && !_brushing) {
698 _editor->show_verbose_time_cursor (_last_frame_position, 10);
703 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
705 if (_copy && first_move) {
706 copy_regions (event);
709 RegionMotionDrag::motion (event, first_move);
713 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
715 vector<RegionView*> copies;
716 boost::shared_ptr<Diskstream> ds;
717 boost::shared_ptr<Playlist> from_playlist;
718 RegionSelection new_views;
719 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
720 PlaylistSet modified_playlists;
721 PlaylistSet frozen_playlists;
722 list <sigc::connection> modified_playlist_connections;
723 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
724 nframes64_t drag_delta;
725 bool changed_tracks, changed_position;
726 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
727 RouteTimeAxisView* source_tv;
729 if (!movement_occurred) {
735 /* all changes were made during motion event handlers */
738 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
739 copies.push_back (*i);
746 /* reverse this here so that we have the correct logic to finalize
750 if (Config->get_edit_mode() == Lock) {
751 _x_constrained = !_x_constrained;
755 if (_x_constrained) {
756 _editor->begin_reversible_command (_("fixed time region copy"));
758 _editor->begin_reversible_command (_("region copy"));
761 if (_x_constrained) {
762 _editor->begin_reversible_command (_("fixed time region drag"));
764 _editor->begin_reversible_command (_("region drag"));
768 _have_transaction = true;
770 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
771 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
773 drag_delta = _primary->region()->position() - _last_frame_position;
775 _editor->update_canvas_now ();
777 /* make a list of where each region ended up */
778 final = find_time_axis_views_and_layers ();
780 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
782 RegionView* rv = (*i);
783 RouteTimeAxisView* dest_rtv = final[*i].first;
784 layer_t dest_layer = final[*i].second;
788 if (rv->region()->locked()) {
793 if (changed_position && !_x_constrained) {
794 where = rv->region()->position() - drag_delta;
796 where = rv->region()->position();
799 boost::shared_ptr<Region> new_region;
802 /* we already made a copy */
803 new_region = rv->region();
805 /* undo the previous hide_dependent_views so that xfades don't
806 disappear on copying regions
809 //rv->get_time_axis_view().reveal_dependent_views (*rv);
811 } else if (changed_tracks && dest_rtv->playlist()) {
812 new_region = RegionFactory::create (rv->region());
815 if (changed_tracks || _copy) {
817 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
824 _editor->latest_regionviews.clear ();
826 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
828 insert_result = modified_playlists.insert (to_playlist);
830 if (insert_result.second) {
831 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
834 to_playlist->add_region (new_region, where);
835 if (dest_rtv->view()->layer_display() == Stacked) {
836 new_region->set_layer (dest_layer);
837 new_region->set_pending_explicit_relayer (true);
842 if (!_editor->latest_regionviews.empty()) {
843 // XXX why just the first one ? we only expect one
844 // commented out in nick_m's canvas reworking. is that intended?
845 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
846 new_views.push_back (_editor->latest_regionviews.front());
851 motion on the same track. plonk the previously reparented region
852 back to its original canvas group (its streamview).
853 No need to do anything for copies as they are fake regions which will be deleted.
856 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
857 rv->get_canvas_group()->property_y() = 0;
859 /* just change the model */
861 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
863 if (dest_rtv->view()->layer_display() == Stacked) {
864 rv->region()->set_layer (dest_layer);
865 rv->region()->set_pending_explicit_relayer (true);
868 insert_result = modified_playlists.insert (playlist);
870 if (insert_result.second) {
871 _editor->session()->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
873 /* freeze to avoid lots of relayering in the case of a multi-region drag */
874 frozen_insert_result = frozen_playlists.insert(playlist);
876 if (frozen_insert_result.second) {
880 rv->region()->set_position (where, (void*) this);
883 if (changed_tracks && !_copy) {
885 /* get the playlist where this drag started. we can't use rv->region()->playlist()
886 because we may have copied the region and it has not been attached to a playlist.
889 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
890 ds = source_tv->get_diskstream();
891 from_playlist = ds->playlist();
895 assert (from_playlist);
897 /* moved to a different audio track, without copying */
899 /* the region that used to be in the old playlist is not
900 moved to the new one - we use a copy of it. as a result,
901 any existing editor for the region should no longer be
905 rv->hide_region_editor();
906 rv->fake_set_opaque (false);
908 /* remove the region from the old playlist */
910 insert_result = modified_playlists.insert (from_playlist);
912 if (insert_result.second) {
913 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
916 from_playlist->remove_region (rv->region());
918 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
919 was selected in all of them, then removing it from a playlist will have removed all
920 trace of it from the selection (i.e. there were N regions selected, we removed 1,
921 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
922 corresponding regionview, and the selection is now empty).
924 this could have invalidated any and all iterators into the region selection.
926 the heuristic we use here is: if the region selection is empty, break out of the loop
927 here. if the region selection is not empty, then restart the loop because we know that
928 we must have removed at least the region(view) we've just been working on as well as any
929 that we processed on previous iterations.
931 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
935 if (_views.empty()) {
946 copies.push_back (rv);
950 if we've created new regions either by copying or moving
951 to a new track, we want to replace the old selection with the new ones
953 if (new_views.size() > 0) {
954 _editor->selection->set (new_views);
957 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
962 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
963 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
966 _editor->commit_reversible_command ();
968 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
975 RegionMotionDrag::x_move_allowed () const
977 if (Config->get_edit_mode() == Lock) {
978 /* in locked edit mode, reverse the usual meaning of _x_constrained */
979 return _x_constrained;
982 return !_x_constrained;
986 RegionMotionDrag::copy_regions (GdkEvent* event)
988 /* duplicate the regionview(s) and region(s) */
990 list<RegionView*> new_regionviews;
992 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
994 RegionView* rv = (*i);
995 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
996 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
998 const boost::shared_ptr<const Region> original = rv->region();
999 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1003 boost::shared_ptr<AudioRegion> audioregion_copy
1004 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1005 nrv = new AudioRegionView (*arv, audioregion_copy);
1007 boost::shared_ptr<MidiRegion> midiregion_copy
1008 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1009 nrv = new MidiRegionView (*mrv, midiregion_copy);
1014 nrv->get_canvas_group()->show ();
1015 new_regionviews.push_back (nrv);
1017 /* swap _primary to the copy */
1019 if (rv == _primary) {
1023 /* ..and deselect the one we copied */
1025 rv->set_selected (false);
1028 if (new_regionviews.empty()) {
1032 /* reflect the fact that we are dragging the copies */
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 = ArdourKeyboard::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->show_verbose_time_cursor (newframe, 10);
2384 _editor->update_canvas_now ();
2389 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2391 if (!movement_occurred) {
2393 /* just a click, do nothing but finish
2394 off the selection process
2397 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2400 case Selection::Set:
2401 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2402 _editor->selection->set (_marker);
2406 case Selection::Toggle:
2407 case Selection::Extend:
2408 case Selection::Add:
2415 _editor->_dragging_edit_point = false;
2417 _editor->begin_reversible_command ( _("move marker") );
2418 XMLNode &before = _editor->session()->locations()->get_state();
2420 MarkerSelection::iterator i;
2421 list<Location*>::iterator x;
2424 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2425 x != _copied_locations.end() && i != _editor->selection->markers.end();
2428 Location * location = _editor->find_location_from_marker (*i, is_start);
2432 if (location->locked()) {
2436 if (location->is_mark()) {
2437 location->set_start ((*x)->start());
2439 location->set ((*x)->start(), (*x)->end());
2444 XMLNode &after = _editor->session()->locations()->get_state();
2445 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2446 _editor->commit_reversible_command ();
2452 MarkerDrag::update_item (Location* location)
2454 double const x1 = _editor->frame_to_pixel (location->start());
2456 _points.front().set_x(x1);
2457 _points.back().set_x(x1);
2458 _line->property_points() = _points;
2461 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2463 _cumulative_x_drag (0),
2464 _cumulative_y_drag (0)
2466 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2472 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2474 Drag::start_grab (event, _editor->fader_cursor);
2476 // start the grab at the center of the control point so
2477 // the point doesn't 'jump' to the mouse after the first drag
2478 _grab_x = _point->get_x();
2479 _grab_y = _point->get_y();
2481 _point->line().parent_group().i2w (_grab_x, _grab_y);
2482 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2484 _grab_frame = _editor->pixel_to_frame (_grab_x);
2486 _point->line().start_drag (_point, _grab_frame, 0);
2488 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2489 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2490 _current_pointer_x + 10, _current_pointer_y + 10);
2492 _editor->show_verbose_canvas_cursor ();
2496 ControlPointDrag::motion (GdkEvent* event, bool)
2498 double dx = _current_pointer_x - _last_pointer_x;
2499 double dy = _current_pointer_y - _last_pointer_y;
2501 if (event->button.state & Keyboard::SecondaryModifier) {
2506 double cx = _grab_x + _cumulative_x_drag + dx;
2507 double cy = _grab_y + _cumulative_y_drag + dy;
2509 // calculate zero crossing point. back off by .01 to stay on the
2510 // positive side of zero
2512 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2513 _point->line().parent_group().i2w(_unused, zero_gain_y);
2515 // make sure we hit zero when passing through
2516 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2517 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2521 if (_x_constrained) {
2524 if (_y_constrained) {
2528 _cumulative_x_drag = cx - _grab_x;
2529 _cumulative_y_drag = cy - _grab_y;
2531 _point->line().parent_group().w2i (cx, cy);
2535 cy = min ((double) _point->line().height(), cy);
2537 //translate cx to frames
2538 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2540 if (!_x_constrained) {
2541 _editor->snap_to_with_modifier (cx_frames, event);
2544 float const fraction = 1.0 - (cy / _point->line().height());
2546 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2548 _point->line().point_drag (*_point, cx_frames, fraction, push);
2550 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2554 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2556 if (!movement_occurred) {
2560 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2561 _editor->reset_point_selection ();
2565 motion (event, false);
2567 _point->line().end_drag (_point);
2571 ControlPointDrag::active (Editing::MouseMode m)
2573 if (m == Editing::MouseGain) {
2574 /* always active in mouse gain */
2578 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2579 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2582 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2585 _cumulative_y_drag (0)
2590 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2592 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2595 _item = &_line->grab_item ();
2597 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2598 origin, and ditto for y.
2601 double cx = event->button.x;
2602 double cy = event->button.y;
2604 _line->parent_group().w2i (cx, cy);
2606 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2608 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2609 /* no adjacent points */
2613 Drag::start_grab (event, _editor->fader_cursor);
2615 /* store grab start in parent frame */
2620 double fraction = 1.0 - (cy / _line->height());
2622 _line->start_drag (0, _grab_frame, fraction);
2624 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2625 _current_pointer_x + 10, _current_pointer_y + 10);
2627 _editor->show_verbose_canvas_cursor ();
2631 LineDrag::motion (GdkEvent* event, bool)
2633 double dy = _current_pointer_y - _last_pointer_y;
2635 if (event->button.state & Keyboard::SecondaryModifier) {
2639 double cy = _grab_y + _cumulative_y_drag + dy;
2641 _cumulative_y_drag = cy - _grab_y;
2644 cy = min ((double) _line->height(), cy);
2646 double const fraction = 1.0 - (cy / _line->height());
2650 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2656 _line->line_drag (_before, _after, fraction, push);
2658 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2662 LineDrag::finished (GdkEvent* event, bool)
2664 motion (event, false);
2665 _line->end_drag (0);
2669 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2671 Drag::start_grab (event);
2672 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2676 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2683 /* use a bigger drag threshold than the default */
2685 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2689 if (Config->get_rubberbanding_snaps_to_grid()) {
2691 _editor->snap_to_with_modifier (_grab_frame, event);
2693 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2696 /* base start and end on initial click position */
2698 if (_current_pointer_frame < _grab_frame) {
2699 start = _current_pointer_frame;
2702 end = _current_pointer_frame;
2703 start = _grab_frame;
2706 if (_current_pointer_y < _grab_y) {
2707 y1 = _current_pointer_y;
2710 y2 = _current_pointer_y;
2715 if (start != end || y1 != y2) {
2717 double x1 = _editor->frame_to_pixel (start);
2718 double x2 = _editor->frame_to_pixel (end);
2720 _editor->rubberband_rect->property_x1() = x1;
2721 _editor->rubberband_rect->property_y1() = y1;
2722 _editor->rubberband_rect->property_x2() = x2;
2723 _editor->rubberband_rect->property_y2() = y2;
2725 _editor->rubberband_rect->show();
2726 _editor->rubberband_rect->raise_to_top();
2728 _last_pointer_frame = _current_pointer_frame;
2730 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2735 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2737 if (movement_occurred) {
2739 motion (event, false);
2742 if (_current_pointer_y < _grab_y) {
2743 y1 = _current_pointer_y;
2746 y2 = _current_pointer_y;
2751 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2754 _editor->begin_reversible_command (_("rubberband selection"));
2756 if (_grab_frame < _last_pointer_frame) {
2757 committed = _editor->select_all_within (_grab_frame, _last_pointer_frame - 1, y1, y2, _editor->track_views, op);
2759 committed = _editor->select_all_within (_last_pointer_frame, _grab_frame - 1, y1, y2, _editor->track_views, op);
2763 _editor->commit_reversible_command ();
2767 if (!getenv("ARDOUR_SAE")) {
2768 _editor->selection->clear_tracks();
2770 _editor->selection->clear_regions();
2771 _editor->selection->clear_points ();
2772 _editor->selection->clear_lines ();
2775 _editor->rubberband_rect->hide();
2779 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2781 Drag::start_grab (event);
2783 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2787 TimeFXDrag::motion (GdkEvent* event, bool)
2789 RegionView* rv = _primary;
2791 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2793 if (_current_pointer_frame == _last_pointer_frame) {
2797 if (_current_pointer_frame > rv->region()->position()) {
2798 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2801 _last_pointer_frame = _current_pointer_frame;
2803 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2807 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2809 _primary->get_time_axis_view().hide_timestretch ();
2811 if (!movement_occurred) {
2815 if (_last_pointer_frame < _primary->region()->position()) {
2816 /* backwards drag of the left edge - not usable */
2820 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2822 float percentage = (double) newlen / (double) _primary->region()->length();
2824 #ifndef USE_RUBBERBAND
2825 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2826 if (_primary->region()->data_type() == DataType::AUDIO) {
2827 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2831 _editor->begin_reversible_command (_("timestretch"));
2833 // XXX how do timeFX on multiple regions ?
2838 if (!_editor->time_stretch (rs, percentage) == 0) {
2839 error << _("An error occurred while executing time stretch operation") << endmsg;
2844 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2846 Drag::start_grab (event);
2850 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2856 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2858 if (movement_occurred && _editor->session()) {
2859 /* make sure we stop */
2860 _editor->session()->request_transport_speed (0.0);
2864 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2873 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2875 nframes64_t start = 0;
2876 nframes64_t end = 0;
2878 if (_editor->session() == 0) {
2882 Gdk::Cursor* cursor = 0;
2884 switch (_operation) {
2885 case CreateSelection:
2886 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2891 cursor = _editor->selector_cursor;
2892 Drag::start_grab (event, cursor);
2895 case SelectionStartTrim:
2896 if (_editor->clicked_axisview) {
2897 _editor->clicked_axisview->order_selection_trims (_item, true);
2899 Drag::start_grab (event, cursor);
2900 cursor = _editor->trimmer_cursor;
2901 start = _editor->selection->time[_editor->clicked_selection].start;
2902 _pointer_frame_offset = _grab_frame - start;
2905 case SelectionEndTrim:
2906 if (_editor->clicked_axisview) {
2907 _editor->clicked_axisview->order_selection_trims (_item, false);
2909 Drag::start_grab (event, cursor);
2910 cursor = _editor->trimmer_cursor;
2911 end = _editor->selection->time[_editor->clicked_selection].end;
2912 _pointer_frame_offset = _grab_frame - end;
2916 start = _editor->selection->time[_editor->clicked_selection].start;
2917 Drag::start_grab (event, cursor);
2918 _pointer_frame_offset = _grab_frame - start;
2922 if (_operation == SelectionMove) {
2923 _editor->show_verbose_time_cursor (start, 10);
2925 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2930 SelectionDrag::motion (GdkEvent* event, bool first_move)
2932 nframes64_t start = 0;
2933 nframes64_t end = 0;
2936 nframes64_t const pending_position = adjusted_current_frame (event);
2938 /* only alter selection if the current frame is
2939 different from the last frame position (adjusted)
2942 if (pending_position == _last_pointer_frame) {
2946 switch (_operation) {
2947 case CreateSelection:
2950 _editor->snap_to (_grab_frame);
2953 if (pending_position < _grab_frame) {
2954 start = pending_position;
2957 end = pending_position;
2958 start = _grab_frame;
2961 /* first drag: Either add to the selection
2962 or create a new selection
2967 _editor->begin_reversible_command (_("range selection"));
2968 _have_transaction = true;
2971 /* adding to the selection */
2972 _editor->selection->add (_editor->clicked_axisview);
2973 _editor->clicked_selection = _editor->selection->add (start, end);
2978 if (!_editor->selection->selected (_editor->clicked_axisview)) {
2979 _editor->selection->set (_editor->clicked_axisview);
2982 _editor->clicked_selection = _editor->selection->set (start, end);
2987 case SelectionStartTrim:
2990 _editor->begin_reversible_command (_("trim selection start"));
2991 _have_transaction = true;
2994 start = _editor->selection->time[_editor->clicked_selection].start;
2995 end = _editor->selection->time[_editor->clicked_selection].end;
2997 if (pending_position > end) {
3000 start = pending_position;
3004 case SelectionEndTrim:
3007 _editor->begin_reversible_command (_("trim selection end"));
3008 _have_transaction = true;
3011 start = _editor->selection->time[_editor->clicked_selection].start;
3012 end = _editor->selection->time[_editor->clicked_selection].end;
3014 if (pending_position < start) {
3017 end = pending_position;
3025 _editor->begin_reversible_command (_("move selection"));
3026 _have_transaction = true;
3029 start = _editor->selection->time[_editor->clicked_selection].start;
3030 end = _editor->selection->time[_editor->clicked_selection].end;
3032 length = end - start;
3034 start = pending_position;
3035 _editor->snap_to (start);
3037 end = start + length;
3042 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3043 _editor->start_canvas_autoscroll (1, 0);
3047 _editor->selection->replace (_editor->clicked_selection, start, end);
3050 _last_pointer_frame = pending_position;
3052 if (_operation == SelectionMove) {
3053 _editor->show_verbose_time_cursor(start, 10);
3055 _editor->show_verbose_time_cursor(pending_position, 10);
3060 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3062 Session* s = _editor->session();
3064 if (movement_occurred) {
3065 motion (event, false);
3066 /* XXX this is not object-oriented programming at all. ick */
3067 if (_editor->selection->time.consolidate()) {
3068 _editor->selection->TimeChanged ();
3071 if (_have_transaction) {
3072 _editor->commit_reversible_command ();
3075 /* XXX what if its a music time selection? */
3076 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3077 s->request_play_range (&_editor->selection->time, true);
3082 /* just a click, no pointer movement.*/
3084 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3085 _editor->selection->clear_time();
3088 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3089 _editor->selection->set (_editor->clicked_axisview);
3092 if (s && s->get_play_range () && s->transport_rolling()) {
3093 s->request_stop (false, false);
3098 _editor->stop_canvas_autoscroll ();
3101 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3106 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3107 _drag_rect->hide ();
3109 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3110 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3114 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3116 if (_editor->session() == 0) {
3120 Gdk::Cursor* cursor = 0;
3122 if (!_editor->temp_location) {
3123 _editor->temp_location = new Location;
3126 switch (_operation) {
3127 case CreateRangeMarker:
3128 case CreateTransportMarker:
3129 case CreateCDMarker:
3131 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3136 cursor = _editor->selector_cursor;
3140 Drag::start_grab (event, cursor);
3142 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3146 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3148 nframes64_t start = 0;
3149 nframes64_t end = 0;
3150 ArdourCanvas::SimpleRect *crect;
3152 switch (_operation) {
3153 case CreateRangeMarker:
3154 crect = _editor->range_bar_drag_rect;
3156 case CreateTransportMarker:
3157 crect = _editor->transport_bar_drag_rect;
3159 case CreateCDMarker:
3160 crect = _editor->cd_marker_bar_drag_rect;
3163 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3168 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3170 /* only alter selection if the current frame is
3171 different from the last frame position.
3174 if (_current_pointer_frame == _last_pointer_frame) {
3178 switch (_operation) {
3179 case CreateRangeMarker:
3180 case CreateTransportMarker:
3181 case CreateCDMarker:
3183 _editor->snap_to (_grab_frame);
3186 if (_current_pointer_frame < _grab_frame) {
3187 start = _current_pointer_frame;
3190 end = _current_pointer_frame;
3191 start = _grab_frame;
3194 /* first drag: Either add to the selection
3195 or create a new selection.
3200 _editor->temp_location->set (start, end);
3204 update_item (_editor->temp_location);
3206 //_drag_rect->raise_to_top();
3212 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3213 _editor->start_canvas_autoscroll (1, 0);
3217 _editor->temp_location->set (start, end);
3219 double x1 = _editor->frame_to_pixel (start);
3220 double x2 = _editor->frame_to_pixel (end);
3221 crect->property_x1() = x1;
3222 crect->property_x2() = x2;
3224 update_item (_editor->temp_location);
3227 _last_pointer_frame = _current_pointer_frame;
3229 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3234 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3236 Location * newloc = 0;
3240 if (movement_occurred) {
3241 motion (event, false);
3244 switch (_operation) {
3245 case CreateRangeMarker:
3246 case CreateCDMarker:
3248 _editor->begin_reversible_command (_("new range marker"));
3249 XMLNode &before = _editor->session()->locations()->get_state();
3250 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3251 if (_operation == CreateCDMarker) {
3252 flags = Location::IsRangeMarker | Location::IsCDMarker;
3253 _editor->cd_marker_bar_drag_rect->hide();
3256 flags = Location::IsRangeMarker;
3257 _editor->range_bar_drag_rect->hide();
3259 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3260 _editor->session()->locations()->add (newloc, true);
3261 XMLNode &after = _editor->session()->locations()->get_state();
3262 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3263 _editor->commit_reversible_command ();
3267 case CreateTransportMarker:
3268 // popup menu to pick loop or punch
3269 _editor->new_transport_marker_context_menu (&event->button, _item);
3273 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3275 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3280 _editor->session()->locations()->marks_either_side (_grab_frame, start, end);
3282 if (end == max_frames) {
3283 end = _editor->session()->current_end_frame ();
3286 if (start == max_frames) {
3287 start = _editor->session()->current_start_frame ();
3290 switch (_editor->mouse_mode) {
3292 /* find the two markers on either side and then make the selection from it */
3293 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3297 /* find the two markers on either side of the click and make the range out of it */
3298 _editor->selection->set (start, end);
3307 _editor->stop_canvas_autoscroll ();
3313 RangeMarkerBarDrag::update_item (Location* location)
3315 double const x1 = _editor->frame_to_pixel (location->start());
3316 double const x2 = _editor->frame_to_pixel (location->end());
3318 _drag_rect->property_x1() = x1;
3319 _drag_rect->property_x2() = x2;
3323 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3325 Drag::start_grab (event, _editor->zoom_cursor);
3326 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3330 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3335 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3338 _editor->snap_to_with_modifier (_grab_frame, event);
3341 if (_current_pointer_frame == _last_pointer_frame) {
3345 /* base start and end on initial click position */
3346 if (_current_pointer_frame < _grab_frame) {
3347 start = _current_pointer_frame;
3350 end = _current_pointer_frame;
3351 start = _grab_frame;
3357 _editor->zoom_rect->show();
3358 _editor->zoom_rect->raise_to_top();
3361 _editor->reposition_zoom_rect(start, end);
3363 _last_pointer_frame = _current_pointer_frame;
3365 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3370 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3372 if (movement_occurred) {
3373 motion (event, false);
3375 if (_grab_frame < _last_pointer_frame) {
3376 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3378 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3381 _editor->temporal_zoom_to_frame (false, _grab_frame);
3383 temporal_zoom_step (false);
3384 center_screen (_grab_frame);
3388 _editor->zoom_rect->hide();
3391 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3394 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3395 region = &cnote->region_view();
3399 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3401 Drag::start_grab (event);
3404 drag_delta_note = 0;
3409 event_x = _current_pointer_x;
3410 event_y = _current_pointer_y;
3412 _item->property_parent().get_value()->w2i(event_x, event_y);
3414 last_x = region->snap_to_pixel(event_x);
3417 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3419 if (!(was_selected = cnote->selected())) {
3421 /* tertiary-click means extend selection - we'll do that on button release,
3422 so don't add it here, because otherwise we make it hard to figure
3423 out the "extend-to" range.
3426 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3429 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3432 region->note_selected (cnote, true);
3434 region->unique_select (cnote);
3441 NoteDrag::motion (GdkEvent*, bool)
3443 MidiStreamView* streamview = region->midi_stream_view();
3447 event_x = _current_pointer_x;
3448 event_y = _current_pointer_y;
3450 _item->property_parent().get_value()->w2i(event_x, event_y);
3452 event_x = region->snap_to_pixel(event_x);
3454 double dx = event_x - last_x;
3455 double dy = event_y - last_y;
3460 // Snap to note rows
3462 if (abs (dy) < streamview->note_height()) {
3465 int8_t this_delta_note;
3467 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3469 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3471 drag_delta_note -= this_delta_note;
3472 dy = streamview->note_height() * this_delta_note;
3473 last_y = last_y + dy;
3477 region->move_selection (dx, dy);
3479 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3481 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3482 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3483 _editor->show_verbose_canvas_cursor_with (buf);
3488 NoteDrag::finished (GdkEvent* ev, bool moved)
3490 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3493 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3496 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3498 region->note_deselected (cnote);
3501 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3502 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3504 if (!extend && !add && region->selection_size() > 1) {
3505 region->unique_select(cnote);
3506 } else if (extend) {
3507 region->note_selected (cnote, true, true);
3509 /* it was added during button press */
3514 region->note_dropped (cnote, drag_delta_x, drag_delta_note);