2 Copyright (C) 2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "pbd/memento_command.h"
21 #include "pbd/basename.h"
22 #include "ardour/diskstream.h"
23 #include "ardour/session.h"
24 #include "ardour/dB.h"
25 #include "ardour/region_factory.h"
26 #include "ardour/midi_diskstream.h"
30 #include "audio_region_view.h"
31 #include "midi_region_view.h"
32 #include "ardour_ui.h"
33 #include "gui_thread.h"
34 #include "control_point.h"
36 #include "region_gain_line.h"
37 #include "editor_drag.h"
38 #include "audio_time_axis.h"
39 #include "midi_time_axis.h"
40 #include "canvas-note.h"
41 #include "selection.h"
42 #include "midi_selection.h"
43 #include "automation_time_axis.h"
46 using namespace ARDOUR;
49 using namespace Editing;
50 using namespace ArdourCanvas;
52 using Gtkmm2ext::Keyboard;
54 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
56 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
59 , _pointer_frame_offset (0)
60 , _have_transaction (false)
62 , _move_threshold_passed (false)
64 , _last_pointer_frame (0)
65 , _current_pointer_frame (0)
71 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
77 cursor = _editor->which_grabber_cursor ();
80 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
84 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
87 cursor = _editor->which_grabber_cursor ();
90 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
92 if (Keyboard::is_button2_event (&event->button)) {
93 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
94 _y_constrained = true;
95 _x_constrained = false;
97 _y_constrained = false;
98 _x_constrained = true;
101 _x_constrained = false;
102 _y_constrained = false;
105 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
106 _grab_frame = adjusted_frame (_grab_frame, event);
107 _last_pointer_frame = _grab_frame;
108 _current_pointer_frame = _grab_frame;
109 _current_pointer_x = _grab_x;
110 _current_pointer_y = _grab_y;
111 _last_pointer_x = _current_pointer_x;
112 _last_pointer_y = _current_pointer_y;
114 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
118 if (_editor->session() && _editor->session()->transport_rolling()) {
121 _was_rolling = false;
124 switch (_editor->snap_type()) {
125 case SnapToRegionStart:
126 case SnapToRegionEnd:
127 case SnapToRegionSync:
128 case SnapToRegionBoundary:
129 _editor->build_region_boundary_cache ();
136 /** @param event GDK event, or 0.
137 * @return true if some movement occurred, otherwise false.
140 Drag::end_grab (GdkEvent* event)
144 _editor->stop_canvas_autoscroll ();
146 _item->ungrab (event ? event->button.time : 0);
148 _last_pointer_x = _current_pointer_x;
149 _last_pointer_y = _current_pointer_y;
150 finished (event, _move_threshold_passed);
152 _editor->hide_verbose_canvas_cursor();
156 return _move_threshold_passed;
160 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
164 if (f > _pointer_frame_offset) {
165 pos = f - _pointer_frame_offset;
169 _editor->snap_to_with_modifier (pos, event);
176 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
178 return adjusted_frame (_current_pointer_frame, event, snap);
182 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
184 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
186 /* check to see if we have moved in any way that matters since the last motion event */
187 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
188 (!y_movement_matters() || _last_pointer_y == _current_pointer_y) ) {
192 pair<nframes64_t, int> const threshold = move_threshold ();
194 bool const old_move_threshold_passed = _move_threshold_passed;
196 if (!from_autoscroll && !_move_threshold_passed) {
198 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
199 bool const yp = (::fabs ((_current_pointer_y - _grab_y)) >= threshold.second);
201 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
204 if (active (_editor->mouse_mode) && _move_threshold_passed) {
206 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
207 if (!from_autoscroll) {
208 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
211 motion (event, _move_threshold_passed != old_move_threshold_passed);
213 _last_pointer_x = _current_pointer_x;
214 _last_pointer_y = _current_pointer_y;
215 _last_pointer_frame = adjusted_current_frame (event);
235 _editor->stop_canvas_autoscroll ();
236 _editor->hide_verbose_canvas_cursor ();
241 pair<nframes64_t, nframes64_t>
242 Drag::extent () const
244 nframes64_t const f = adjusted_current_frame (0);
245 return make_pair (f, f);
248 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
253 RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
257 RegionDrag::region_going_away (RegionView* v)
264 pair<nframes64_t, nframes64_t>
265 RegionDrag::extent () const
267 nframes64_t const f = adjusted_current_frame (0);
268 return make_pair (f, f + _primary->region()->length ());
272 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
273 : RegionDrag (e, i, p, v),
284 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
286 Drag::start_grab (event);
288 _editor->show_verbose_time_cursor (_last_frame_position, 10);
291 RegionMotionDrag::TimeAxisViewSummary
292 RegionMotionDrag::get_time_axis_view_summary ()
294 int32_t children = 0;
295 TimeAxisViewSummary sum;
297 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
299 /* get a bitmask representing the visible tracks */
301 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
302 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
303 TimeAxisView::Children children_list;
305 /* zeroes are audio/MIDI tracks. ones are other types. */
307 if (!rtv->hidden()) {
309 if (!rtv->is_track()) {
310 /* not an audio nor MIDI track */
311 sum.tracks = sum.tracks |= (0x01 << rtv->order());
314 sum.height_list[rtv->order()] = (*i)->current_height();
317 if ((children_list = rtv->get_child_list()).size() > 0) {
318 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
319 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
320 sum.height_list[rtv->order() + children] = (*j)->current_height();
331 RegionMotionDrag::compute_y_delta (
332 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
333 int32_t last_pointer_layer, int32_t current_pointer_layer,
334 TimeAxisViewSummary const & tavs,
335 int32_t* pointer_order_span, int32_t* pointer_layer_span,
336 int32_t* canvas_pointer_order_span
340 *pointer_order_span = 0;
341 *pointer_layer_span = 0;
345 bool clamp_y_axis = false;
347 /* the change in track order between this callback and the last */
348 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
349 /* the change in layer between this callback and the last;
350 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
351 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
353 if (*pointer_order_span != 0) {
355 /* find the actual pointer span, in terms of the number of visible tracks;
356 to do this, we reduce |pointer_order_span| by the number of hidden tracks
359 *canvas_pointer_order_span = *pointer_order_span;
360 if (last_pointer_view->order() >= current_pointer_view->order()) {
361 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
362 if (tavs.height_list[y] == 0) {
363 *canvas_pointer_order_span--;
367 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
368 if (tavs.height_list[y] == 0) {
369 *canvas_pointer_order_span++;
374 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
376 RegionView* rv = (*i);
378 if (rv->region()->locked()) {
382 double ix1, ix2, iy1, iy2;
383 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
384 rv->get_canvas_frame()->i2w (ix1, iy1);
385 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
387 /* get the new trackview for this particular region */
388 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
390 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
392 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
393 as surely this is a per-region thing... */
395 clamp_y_axis = y_movement_disallowed (
396 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
404 } else if (_dest_trackview == current_pointer_view) {
406 if (current_pointer_layer == last_pointer_layer) {
407 /* No movement; clamp */
413 _dest_trackview = current_pointer_view;
414 _dest_layer = current_pointer_layer;
422 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
424 /* compute the amount of pointer motion in frames, and where
425 the region would be if we moved it by that much.
427 *pending_region_position = adjusted_current_frame (event);
429 nframes64_t sync_frame;
430 nframes64_t sync_offset;
433 sync_offset = _primary->region()->sync_offset (sync_dir);
435 /* we don't handle a sync point that lies before zero.
437 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
439 sync_frame = *pending_region_position + (sync_dir*sync_offset);
441 _editor->snap_to_with_modifier (sync_frame, event);
443 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
446 *pending_region_position = _last_frame_position;
449 if (*pending_region_position > max_frames - _primary->region()->length()) {
450 *pending_region_position = _last_frame_position;
455 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
457 /* now compute the canvas unit distance we need to move the regionview
458 to make it appear at the new location.
461 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
463 if (*pending_region_position <= _last_frame_position) {
465 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
467 RegionView* rv = (*i);
469 // If any regionview is at zero, we need to know so we can stop further leftward motion.
471 double ix1, ix2, iy1, iy2;
472 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
473 rv->get_canvas_frame()->i2w (ix1, iy1);
475 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
477 *pending_region_position = _last_frame_position;
484 _last_frame_position = *pending_region_position;
491 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
495 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
497 vector<int32_t>::iterator j;
499 /* *pointer* variables reflect things about the pointer; as we may be moving
500 multiple regions, much detail must be computed per-region */
502 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
503 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
504 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
505 is always 0 regardless of what the region's "real" layer is */
506 RouteTimeAxisView* current_pointer_view;
507 layer_t current_pointer_layer;
508 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
512 /* TimeAxisView that we were pointing at last time we entered this method */
513 TimeAxisView const * const last_pointer_view = _dest_trackview;
514 /* the order of the track that we were pointing at last time we entered this method */
515 int32_t const last_pointer_order = last_pointer_view->order ();
516 /* the layer that we were pointing at last time we entered this method */
517 layer_t const last_pointer_layer = _dest_layer;
519 int32_t pointer_order_span;
520 int32_t pointer_layer_span;
521 int32_t canvas_pointer_order_span;
523 bool const clamp_y_axis = compute_y_delta (
524 last_pointer_view, current_pointer_view,
525 last_pointer_layer, current_pointer_layer, tavs,
526 &pointer_order_span, &pointer_layer_span,
527 &canvas_pointer_order_span
530 nframes64_t pending_region_position;
531 double const x_delta = compute_x_delta (event, &pending_region_position);
533 /*************************************************************
535 ************************************************************/
537 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
538 /* haven't reached next snap point, and we're not switching
539 trackviews nor layers. nothing to do.
544 /*************************************************************
546 ************************************************************/
548 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
550 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
552 RegionView* rv = (*i);
554 if (rv->region()->locked()) {
558 /* here we are calculating the y distance from the
559 top of the first track view to the top of the region
560 area of the track view that we're working on */
562 /* this x value is just a dummy value so that we have something
567 /* distance from the top of this track view to the region area
568 of our track view is always 1 */
572 /* convert to world coordinates, ie distance from the top of
575 rv->get_canvas_frame()->i2w (ix1, iy1);
577 /* compensate for the ruler section and the vertical scrollbar position */
578 iy1 += _editor->get_trackview_group_vertical_offset ();
582 // hide any dependent views
584 rv->get_time_axis_view().hide_dependent_views (*rv);
587 reparent to a non scrolling group so that we can keep the
588 region selection above all time axis views.
589 reparenting means we have to move the rv as the two
590 parent groups have different coordinates.
593 rv->get_canvas_group()->property_y() = iy1 - 1;
594 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
596 rv->fake_set_opaque (true);
599 /* current view for this particular region */
600 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
601 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
603 if (pointer_order_span != 0 && !clamp_y_axis) {
605 /* INTER-TRACK MOVEMENT */
607 /* move through the height list to the track that the region is currently on */
608 vector<int32_t>::iterator j = tavs.height_list.begin ();
610 while (j != tavs.height_list.end () && x != rtv->order ()) {
616 int32_t temp_pointer_order_span = canvas_pointer_order_span;
618 if (j != tavs.height_list.end ()) {
620 /* Account for layers in the original and
621 destination tracks. If we're moving around in layers we assume
622 that only one track is involved, so it's ok to use *pointer*
625 StreamView* lv = last_pointer_view->view ();
628 /* move to the top of the last trackview */
629 if (lv->layer_display () == Stacked) {
630 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
633 StreamView* cv = current_pointer_view->view ();
636 /* move to the right layer on the current trackview */
637 if (cv->layer_display () == Stacked) {
638 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
641 /* And for being on a non-topmost layer on the new
644 while (temp_pointer_order_span > 0) {
645 /* we're moving up canvas-wise,
646 so we need to find the next track height
648 if (j != tavs.height_list.begin()) {
652 if (x != last_pointer_order) {
654 ++temp_pointer_order_span;
659 temp_pointer_order_span--;
662 while (temp_pointer_order_span < 0) {
666 if (x != last_pointer_order) {
668 --temp_pointer_order_span;
672 if (j != tavs.height_list.end()) {
676 temp_pointer_order_span++;
680 /* find out where we'll be when we move and set height accordingly */
682 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
683 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
684 rv->set_height (temp_rtv->view()->child_height());
686 /* if you un-comment the following, the region colours will follow
687 the track colours whilst dragging; personally
688 i think this can confuse things, but never mind.
691 //const GdkColor& col (temp_rtv->view->get_region_color());
692 //rv->set_color (const_cast<GdkColor&>(col));
696 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
698 /* INTER-LAYER MOVEMENT in the same track */
699 y_delta = rtv->view()->child_height () * pointer_layer_span;
704 _editor->mouse_brush_insert_region (rv, pending_region_position);
706 rv->move (x_delta, y_delta);
709 } /* foreach region */
711 _total_x_delta += x_delta;
714 _editor->cursor_group->raise_to_top();
717 if (x_delta != 0 && !_brushing) {
718 _editor->show_verbose_time_cursor (_last_frame_position, 10);
723 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
725 if (_copy && first_move) {
726 copy_regions (event);
729 RegionMotionDrag::motion (event, first_move);
733 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
735 vector<RegionView*> copies;
736 boost::shared_ptr<Diskstream> ds;
737 boost::shared_ptr<Playlist> from_playlist;
738 RegionSelection new_views;
739 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
740 PlaylistSet modified_playlists;
741 PlaylistSet frozen_playlists;
742 list <sigc::connection> modified_playlist_connections;
743 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
744 nframes64_t drag_delta;
745 bool changed_tracks, changed_position;
746 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
747 RouteTimeAxisView* source_tv;
749 if (!movement_occurred) {
755 /* all changes were made during motion event handlers */
758 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
759 copies.push_back (*i);
766 /* reverse this here so that we have the correct logic to finalize
770 if (Config->get_edit_mode() == Lock) {
771 _x_constrained = !_x_constrained;
775 if (_x_constrained) {
776 _editor->begin_reversible_command (_("fixed time region copy"));
778 _editor->begin_reversible_command (_("region copy"));
781 if (_x_constrained) {
782 _editor->begin_reversible_command (_("fixed time region drag"));
784 _editor->begin_reversible_command (_("region drag"));
788 _have_transaction = true;
790 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
791 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
793 drag_delta = _primary->region()->position() - _last_frame_position;
795 _editor->update_canvas_now ();
797 /* make a list of where each region ended up */
798 final = find_time_axis_views_and_layers ();
800 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
802 RegionView* rv = (*i);
803 RouteTimeAxisView* dest_rtv = final[*i].first;
804 layer_t dest_layer = final[*i].second;
808 if (rv->region()->locked()) {
813 if (changed_position && !_x_constrained) {
814 where = rv->region()->position() - drag_delta;
816 where = rv->region()->position();
819 boost::shared_ptr<Region> new_region;
822 /* we already made a copy */
823 new_region = rv->region();
825 /* undo the previous hide_dependent_views so that xfades don't
826 disappear on copying regions
829 //rv->get_time_axis_view().reveal_dependent_views (*rv);
831 } else if (changed_tracks && dest_rtv->playlist()) {
832 new_region = RegionFactory::create (rv->region());
835 if (changed_tracks || _copy) {
837 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
844 _editor->latest_regionviews.clear ();
846 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
848 insert_result = modified_playlists.insert (to_playlist);
850 if (insert_result.second) {
851 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
854 to_playlist->add_region (new_region, where);
855 if (dest_rtv->view()->layer_display() == Stacked) {
856 new_region->set_layer (dest_layer);
857 new_region->set_pending_explicit_relayer (true);
862 if (!_editor->latest_regionviews.empty()) {
863 // XXX why just the first one ? we only expect one
864 // commented out in nick_m's canvas reworking. is that intended?
865 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
866 new_views.push_back (_editor->latest_regionviews.front());
871 motion on the same track. plonk the previously reparented region
872 back to its original canvas group (its streamview).
873 No need to do anything for copies as they are fake regions which will be deleted.
876 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
877 rv->get_canvas_group()->property_y() = 0;
878 rv->get_time_axis_view().reveal_dependent_views (*rv);
880 /* just change the model */
882 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
884 if (dest_rtv->view()->layer_display() == Stacked) {
885 rv->region()->set_layer (dest_layer);
886 rv->region()->set_pending_explicit_relayer (true);
889 insert_result = modified_playlists.insert (playlist);
891 if (insert_result.second) {
892 _editor->session()->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
894 /* freeze to avoid lots of relayering in the case of a multi-region drag */
895 frozen_insert_result = frozen_playlists.insert(playlist);
897 if (frozen_insert_result.second) {
901 rv->region()->set_position (where, (void*) this);
904 if (changed_tracks && !_copy) {
906 /* get the playlist where this drag started. we can't use rv->region()->playlist()
907 because we may have copied the region and it has not been attached to a playlist.
910 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
911 ds = source_tv->get_diskstream();
912 from_playlist = ds->playlist();
916 assert (from_playlist);
918 /* moved to a different audio track, without copying */
920 /* the region that used to be in the old playlist is not
921 moved to the new one - we use a copy of it. as a result,
922 any existing editor for the region should no longer be
926 rv->hide_region_editor();
927 rv->fake_set_opaque (false);
929 /* remove the region from the old playlist */
931 insert_result = modified_playlists.insert (from_playlist);
933 if (insert_result.second) {
934 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
937 from_playlist->remove_region (rv->region());
939 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
940 was selected in all of them, then removing it from a playlist will have removed all
941 trace of it from the selection (i.e. there were N regions selected, we removed 1,
942 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
943 corresponding regionview, and the selection is now empty).
945 this could have invalidated any and all iterators into the region selection.
947 the heuristic we use here is: if the region selection is empty, break out of the loop
948 here. if the region selection is not empty, then restart the loop because we know that
949 we must have removed at least the region(view) we've just been working on as well as any
950 that we processed on previous iterations.
952 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
956 if (_views.empty()) {
967 copies.push_back (rv);
971 if we've created new regions either by copying or moving
972 to a new track, we want to replace the old selection with the new ones
974 if (new_views.size() > 0) {
975 _editor->selection->set (new_views);
978 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
983 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
984 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
987 _editor->commit_reversible_command ();
989 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
995 RegionMoveDrag::aborted ()
999 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1006 RegionMotionDrag::aborted ();
1011 RegionMotionDrag::aborted ()
1013 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1014 TimeAxisView* tv = &(*i)->get_time_axis_view ();
1015 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1017 (*i)->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1018 (*i)->get_canvas_group()->property_y() = 0;
1019 (*i)->get_time_axis_view().reveal_dependent_views (**i);
1020 (*i)->fake_set_opaque (false);
1021 (*i)->move (-_total_x_delta, 0);
1022 (*i)->set_height (rtv->view()->child_height ());
1025 _editor->update_canvas_now ();
1030 RegionMotionDrag::x_move_allowed () const
1032 if (Config->get_edit_mode() == Lock) {
1033 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1034 return _x_constrained;
1037 return !_x_constrained;
1041 RegionMotionDrag::copy_regions (GdkEvent* event)
1043 /* duplicate the regionview(s) and region(s) */
1045 list<RegionView*> new_regionviews;
1047 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1049 RegionView* rv = (*i);
1050 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1051 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1053 const boost::shared_ptr<const Region> original = rv->region();
1054 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1058 boost::shared_ptr<AudioRegion> audioregion_copy
1059 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1060 nrv = new AudioRegionView (*arv, audioregion_copy);
1062 boost::shared_ptr<MidiRegion> midiregion_copy
1063 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1064 nrv = new MidiRegionView (*mrv, midiregion_copy);
1069 nrv->get_canvas_group()->show ();
1070 new_regionviews.push_back (nrv);
1072 /* swap _primary to the copy */
1074 if (rv == _primary) {
1078 /* ..and deselect the one we copied */
1080 rv->set_selected (false);
1083 if (new_regionviews.empty()) {
1087 /* reflect the fact that we are dragging the copies */
1089 _views = new_regionviews;
1091 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1094 sync the canvas to what we think is its current state
1095 without it, the canvas seems to
1096 "forget" to update properly after the upcoming reparent()
1097 ..only if the mouse is in rapid motion at the time of the grab.
1098 something to do with regionview creation taking so long?
1100 _editor->update_canvas_now();
1104 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1106 /* Which trackview is this ? */
1108 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1109 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1110 (*layer) = tvp.second;
1112 if (*tv && (*tv)->layer_display() == Overlaid) {
1116 /* The region motion is only processed if the pointer is over
1120 if (!(*tv) || !(*tv)->is_track()) {
1121 /* To make sure we hide the verbose canvas cursor when the mouse is
1122 not held over and audiotrack.
1124 _editor->hide_verbose_canvas_cursor ();
1131 /** @param new_order New track order.
1132 * @param old_order Old track order.
1133 * @param visible_y_low Lowest visible order.
1134 * @return true if y movement should not happen, otherwise false.
1137 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1139 if (new_order != old_order) {
1141 /* this isn't the pointer track */
1145 /* moving up the canvas */
1146 if ( (new_order - y_span) >= tavs.visible_y_low) {
1150 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1151 int32_t visible_tracks = 0;
1152 while (visible_tracks < y_span ) {
1154 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1155 /* passing through a hidden track */
1160 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1161 /* moving to a non-track; disallow */
1167 /* moving beyond the lowest visible track; disallow */
1171 } else if (y_span < 0) {
1173 /* moving down the canvas */
1174 if ((new_order - y_span) <= tavs.visible_y_high) {
1176 int32_t visible_tracks = 0;
1178 while (visible_tracks > y_span ) {
1181 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1182 /* passing through a hidden track */
1187 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1188 /* moving to a non-track; disallow */
1195 /* moving beyond the highest visible track; disallow */
1202 /* this is the pointer's track */
1204 if ((new_order - y_span) > tavs.visible_y_high) {
1205 /* we will overflow */
1207 } else if ((new_order - y_span) < tavs.visible_y_low) {
1208 /* we will overflow */
1217 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1218 : RegionMotionDrag (e, i, p, v, b),
1221 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1223 _dest_trackview = tv;
1224 if (tv->layer_display() == Overlaid) {
1227 _dest_layer = _primary->region()->layer ();
1231 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1232 if (rtv && rtv->is_track()) {
1233 speed = rtv->get_diskstream()->speed ();
1236 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1240 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1242 RegionMotionDrag::start_grab (event, c);
1244 _pointer_frame_offset = grab_frame() - _last_frame_position;
1247 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1248 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1250 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1251 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1253 _primary = v->view()->create_region_view (r, false, false);
1255 _primary->get_canvas_group()->show ();
1256 _primary->set_position (pos, 0);
1257 _views.push_back (_primary);
1259 _last_frame_position = pos;
1261 _item = _primary->get_canvas_group ();
1262 _dest_trackview = v;
1263 _dest_layer = _primary->region()->layer ();
1266 map<RegionView*, pair<RouteTimeAxisView*, int> >
1267 RegionMotionDrag::find_time_axis_views_and_layers ()
1269 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1271 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1273 double ix1, ix2, iy1, iy2;
1274 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1275 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1276 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1278 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1279 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1287 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1289 _editor->update_canvas_now ();
1291 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1293 RouteTimeAxisView* dest_rtv = final[_primary].first;
1295 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1296 _primary->get_canvas_group()->property_y() = 0;
1298 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1300 _editor->begin_reversible_command (_("insert region"));
1301 XMLNode& before = playlist->get_state ();
1302 playlist->add_region (_primary->region (), _last_frame_position);
1303 _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1304 _editor->commit_reversible_command ();
1312 RegionInsertDrag::aborted ()
1317 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1318 : RegionMoveDrag (e, i, p, v, false, false)
1323 struct RegionSelectionByPosition {
1324 bool operator() (RegionView*a, RegionView* b) {
1325 return a->region()->position () < b->region()->position();
1330 RegionSpliceDrag::motion (GdkEvent* event, bool)
1332 RouteTimeAxisView* tv;
1335 if (!check_possible (&tv, &layer)) {
1341 if ((current_pointer_x() - last_pointer_x()) > 0) {
1347 RegionSelection copy (_editor->selection->regions);
1349 RegionSelectionByPosition cmp;
1352 nframes64_t const pf = adjusted_current_frame (event);
1354 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1356 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1362 boost::shared_ptr<Playlist> playlist;
1364 if ((playlist = atv->playlist()) == 0) {
1368 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1373 if (pf < (*i)->region()->last_frame() + 1) {
1377 if (pf > (*i)->region()->first_frame()) {
1383 playlist->shuffle ((*i)->region(), dir);
1388 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1394 RegionSpliceDrag::aborted ()
1399 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1407 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1409 _dest_trackview = _view;
1411 Drag::start_grab (event);
1416 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1419 // TODO: create region-create-drag region view here
1422 // TODO: resize region-create-drag region view here
1426 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1428 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1434 if (!movement_occurred) {
1435 mtv->add_region (grab_frame ());
1437 motion (event, false);
1438 // TODO: create region-create-drag region here
1443 RegionCreateDrag::aborted ()
1448 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1456 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1459 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1461 Drag::start_grab (event);
1463 region = &cnote->region_view();
1465 double region_start = region->get_position_pixels();
1466 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1468 if (grab_x() <= middle_point) {
1469 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1472 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1476 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1478 if (event->motion.state & Keyboard::PrimaryModifier) {
1484 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1486 if (ms.size() > 1) {
1487 /* has to be relative, may make no sense otherwise */
1491 region->note_selected (cnote, true);
1493 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1494 MidiRegionSelection::iterator next;
1497 (*r)->begin_resizing (at_front);
1503 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1505 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1506 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1507 (*r)->update_resizing (at_front, current_pointer_x() - grab_x(), relative);
1512 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1514 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1515 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1516 (*r)->commit_resizing (at_front, current_pointer_x() - grab_x(), relative);
1521 NoteResizeDrag::aborted ()
1527 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1533 RegionGainDrag::finished (GdkEvent *, bool)
1539 RegionGainDrag::aborted ()
1544 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1545 : RegionDrag (e, i, p, v)
1551 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1554 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1555 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1557 if (tv && tv->is_track()) {
1558 speed = tv->get_diskstream()->speed();
1561 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1562 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1563 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1565 Drag::start_grab (event, _editor->trimmer_cursor);
1567 nframes64_t const pf = adjusted_current_frame (event);
1569 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1570 _operation = ContentsTrim;
1572 /* These will get overridden for a point trim.*/
1573 if (pf < (region_start + region_length/2)) {
1574 /* closer to start */
1575 _operation = StartTrim;
1576 } else if (pf > (region_end - region_length/2)) {
1578 _operation = EndTrim;
1582 switch (_operation) {
1584 _editor->show_verbose_time_cursor (region_start, 10);
1587 _editor->show_verbose_time_cursor (region_end, 10);
1590 _editor->show_verbose_time_cursor (pf, 10);
1596 TrimDrag::motion (GdkEvent* event, bool first_move)
1598 RegionView* rv = _primary;
1599 nframes64_t frame_delta = 0;
1601 bool left_direction;
1602 bool obey_snap = event ? !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) : false;
1604 /* snap modifier works differently here..
1605 its current state has to be passed to the
1606 various trim functions in order to work properly
1610 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1611 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1612 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1614 if (tv && tv->is_track()) {
1615 speed = tv->get_diskstream()->speed();
1618 nframes64_t const pf = adjusted_current_frame (event);
1620 if (last_pointer_frame() > pf) {
1621 left_direction = true;
1623 left_direction = false;
1630 switch (_operation) {
1632 trim_type = "Region start trim";
1635 trim_type = "Region end trim";
1638 trim_type = "Region content trim";
1642 _editor->begin_reversible_command (trim_type);
1643 _have_transaction = true;
1645 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1646 (*i)->fake_set_opaque(false);
1647 (*i)->region()->freeze ();
1649 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1652 arv->temporarily_hide_envelope ();
1655 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1656 insert_result = _editor->motion_frozen_playlists.insert (pl);
1658 if (insert_result.second) {
1659 _editor->session()->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1665 /* XXX i hope to god that we can really conclude this ... */
1666 _have_transaction = true;
1668 if (left_direction) {
1669 frame_delta = (last_pointer_frame() - pf);
1671 frame_delta = (pf - last_pointer_frame());
1674 bool non_overlap_trim = false;
1676 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1677 non_overlap_trim = true;
1680 switch (_operation) {
1682 if ((left_direction == false) && (pf <= rv->region()->first_frame()/speed)) {
1686 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1687 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1693 if ((left_direction == true) && (pf > (nframes64_t) (rv->region()->last_frame()/speed))) {
1697 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1698 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1705 bool swap_direction = false;
1707 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1708 swap_direction = true;
1711 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1712 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1718 switch (_operation) {
1720 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1723 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1726 _editor->show_verbose_time_cursor (pf, 10);
1733 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1735 if (movement_occurred) {
1736 motion (event, false);
1738 if (!_editor->selection->selected (_primary)) {
1739 _editor->thaw_region_after_trim (*_primary);
1742 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1743 _editor->thaw_region_after_trim (**i);
1744 (*i)->fake_set_opaque (true);
1747 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1749 if (_have_transaction) {
1750 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1754 _editor->motion_frozen_playlists.clear ();
1756 if (_have_transaction) {
1757 _editor->commit_reversible_command();
1761 /* no mouse movement */
1762 _editor->point_trim (event);
1767 TrimDrag::aborted ()
1769 /* Our motion method is changing model state, so use the Undo system
1770 to cancel. Perhaps not ideal, as this will leave an Undo point
1771 behind which may be slightly odd from the user's point of view.
1776 if (_have_transaction) {
1781 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1785 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1790 MeterMarkerDrag::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), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1797 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1798 *new MeterSection (_marker->meter()));
1800 _item = &new_marker->the_item ();
1801 _marker = new_marker;
1805 MetricSection& section (_marker->meter());
1807 if (!section.movable()) {
1813 Drag::start_grab (event, cursor);
1815 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1817 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1821 MeterMarkerDrag::motion (GdkEvent* event, bool)
1823 nframes64_t const pf = adjusted_current_frame (event);
1825 _marker->set_position (pf);
1827 _editor->show_verbose_time_cursor (pf, 10);
1831 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1833 if (!movement_occurred) {
1837 motion (event, false);
1841 TempoMap& map (_editor->session()->tempo_map());
1842 map.bbt_time (last_pointer_frame(), when);
1844 if (_copy == true) {
1845 _editor->begin_reversible_command (_("copy meter mark"));
1846 XMLNode &before = map.get_state();
1847 map.add_meter (_marker->meter(), when);
1848 XMLNode &after = map.get_state();
1849 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1850 _editor->commit_reversible_command ();
1852 // delete the dummy marker we used for visual representation of copying.
1853 // a new visual marker will show up automatically.
1856 _editor->begin_reversible_command (_("move meter mark"));
1857 XMLNode &before = map.get_state();
1858 map.move_meter (_marker->meter(), when);
1859 XMLNode &after = map.get_state();
1860 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1861 _editor->commit_reversible_command ();
1866 MeterMarkerDrag::aborted ()
1868 _marker->set_position (_marker->meter().frame ());
1871 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1875 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1880 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1885 // create a dummy marker for visual representation of moving the copy.
1886 // The actual copying is not done before we reach the finish callback.
1888 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1889 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1890 *new TempoSection (_marker->tempo()));
1892 _item = &new_marker->the_item ();
1893 _marker = new_marker;
1897 MetricSection& section (_marker->tempo());
1899 if (!section.movable()) {
1904 Drag::start_grab (event, cursor);
1906 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
1907 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
1911 TempoMarkerDrag::motion (GdkEvent* event, bool)
1913 nframes64_t const pf = adjusted_current_frame (event);
1914 _marker->set_position (pf);
1915 _editor->show_verbose_time_cursor (pf, 10);
1919 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1921 if (!movement_occurred) {
1925 motion (event, false);
1929 TempoMap& map (_editor->session()->tempo_map());
1930 map.bbt_time (last_pointer_frame(), when);
1932 if (_copy == true) {
1933 _editor->begin_reversible_command (_("copy tempo mark"));
1934 XMLNode &before = map.get_state();
1935 map.add_tempo (_marker->tempo(), when);
1936 XMLNode &after = map.get_state();
1937 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1938 _editor->commit_reversible_command ();
1940 // delete the dummy marker we used for visual representation of copying.
1941 // a new visual marker will show up automatically.
1944 _editor->begin_reversible_command (_("move tempo mark"));
1945 XMLNode &before = map.get_state();
1946 map.move_tempo (_marker->tempo(), when);
1947 XMLNode &after = map.get_state();
1948 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1949 _editor->commit_reversible_command ();
1954 TempoMarkerDrag::aborted ()
1956 _marker->set_position (_marker->tempo().frame());
1959 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1963 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1968 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1970 Drag::start_grab (event, c);
1974 nframes64_t where = _editor->event_frame (event, 0, 0);
1976 _editor->snap_to_with_modifier (where, event);
1977 _editor->playhead_cursor->set_position (where);
1981 if (_cursor == _editor->playhead_cursor) {
1982 _editor->_dragging_playhead = true;
1984 if (_editor->session() && _was_rolling && _stop) {
1985 _editor->session()->request_stop ();
1988 if (_editor->session() && _editor->session()->is_auditioning()) {
1989 _editor->session()->cancel_audition ();
1993 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
1995 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1999 CursorDrag::motion (GdkEvent* event, bool)
2001 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2003 if (adjusted_frame == last_pointer_frame()) {
2007 _cursor->set_position (adjusted_frame);
2009 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2012 _editor->update_canvas_now ();
2014 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2018 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2020 _editor->_dragging_playhead = false;
2022 if (!movement_occurred && _stop) {
2026 motion (event, false);
2028 if (_item == &_editor->playhead_cursor->canvas_item) {
2029 if (_editor->session()) {
2030 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2031 _editor->_pending_locate_request = true;
2037 CursorDrag::aborted ()
2039 _editor->_dragging_playhead = false;
2040 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2043 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2044 : RegionDrag (e, i, p, v)
2050 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2052 Drag::start_grab (event, cursor);
2054 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2055 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2057 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2058 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2062 FadeInDrag::motion (GdkEvent* event, bool)
2064 nframes64_t fade_length;
2066 nframes64_t const pos = adjusted_current_frame (event);
2068 boost::shared_ptr<Region> region = _primary->region ();
2070 if (pos < (region->position() + 64)) {
2071 fade_length = 64; // this should be a minimum defined somewhere
2072 } else if (pos > region->last_frame()) {
2073 fade_length = region->length();
2075 fade_length = pos - region->position();
2078 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2080 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2086 tmp->reset_fade_in_shape_width (fade_length);
2089 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2093 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2095 if (!movement_occurred) {
2099 nframes64_t fade_length;
2101 nframes64_t const pos = adjusted_current_frame (event);
2103 boost::shared_ptr<Region> region = _primary->region ();
2105 if (pos < (region->position() + 64)) {
2106 fade_length = 64; // this should be a minimum defined somewhere
2107 } else if (pos > region->last_frame()) {
2108 fade_length = region->length();
2110 fade_length = pos - region->position();
2113 _editor->begin_reversible_command (_("change fade in length"));
2115 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2117 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2123 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2124 XMLNode &before = alist->get_state();
2126 tmp->audio_region()->set_fade_in_length (fade_length);
2127 tmp->audio_region()->set_fade_in_active (true);
2129 XMLNode &after = alist->get_state();
2130 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2133 _editor->commit_reversible_command ();
2137 FadeInDrag::aborted ()
2139 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2140 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2146 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2150 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2151 : RegionDrag (e, i, p, v)
2157 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2159 Drag::start_grab (event, cursor);
2161 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2162 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2164 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2165 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2169 FadeOutDrag::motion (GdkEvent* event, bool)
2171 nframes64_t fade_length;
2173 nframes64_t const pos = adjusted_current_frame (event);
2175 boost::shared_ptr<Region> region = _primary->region ();
2177 if (pos > (region->last_frame() - 64)) {
2178 fade_length = 64; // this should really be a minimum fade defined somewhere
2180 else if (pos < region->position()) {
2181 fade_length = region->length();
2184 fade_length = region->last_frame() - pos;
2187 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2189 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2195 tmp->reset_fade_out_shape_width (fade_length);
2198 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2202 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2204 if (!movement_occurred) {
2208 nframes64_t fade_length;
2210 nframes64_t const pos = adjusted_current_frame (event);
2212 boost::shared_ptr<Region> region = _primary->region ();
2214 if (pos > (region->last_frame() - 64)) {
2215 fade_length = 64; // this should really be a minimum fade defined somewhere
2217 else if (pos < region->position()) {
2218 fade_length = region->length();
2221 fade_length = region->last_frame() - pos;
2224 _editor->begin_reversible_command (_("change fade out length"));
2226 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2228 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2234 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2235 XMLNode &before = alist->get_state();
2237 tmp->audio_region()->set_fade_out_length (fade_length);
2238 tmp->audio_region()->set_fade_out_active (true);
2240 XMLNode &after = alist->get_state();
2241 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2244 _editor->commit_reversible_command ();
2248 FadeOutDrag::aborted ()
2250 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2251 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2257 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2261 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2264 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2267 _points.push_back (Gnome::Art::Point (0, 0));
2268 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2270 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2271 _line->property_width_pixels() = 1;
2272 _line->property_points () = _points;
2275 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2278 MarkerDrag::~MarkerDrag ()
2280 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2286 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2288 Drag::start_grab (event, cursor);
2292 Location *location = _editor->find_location_from_marker (_marker, is_start);
2293 _editor->_dragging_edit_point = true;
2295 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2297 update_item (location);
2299 // _drag_line->show();
2300 // _line->raise_to_top();
2303 _editor->show_verbose_time_cursor (location->start(), 10);
2305 _editor->show_verbose_time_cursor (location->end(), 10);
2308 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2311 case Selection::Toggle:
2312 _editor->selection->toggle (_marker);
2314 case Selection::Set:
2315 if (!_editor->selection->selected (_marker)) {
2316 _editor->selection->set (_marker);
2319 case Selection::Extend:
2321 Locations::LocationList ll;
2322 list<Marker*> to_add;
2324 _editor->selection->markers.range (s, e);
2325 s = min (_marker->position(), s);
2326 e = max (_marker->position(), e);
2329 if (e < max_frames) {
2332 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2333 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2334 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2337 to_add.push_back (lm->start);
2340 to_add.push_back (lm->end);
2344 if (!to_add.empty()) {
2345 _editor->selection->add (to_add);
2349 case Selection::Add:
2350 _editor->selection->add (_marker);
2354 /* set up copies for us to manipulate during the drag */
2356 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2357 Location *l = _editor->find_location_from_marker (*i, is_start);
2358 _copied_locations.push_back (new Location (*l));
2363 MarkerDrag::motion (GdkEvent* event, bool)
2365 nframes64_t f_delta = 0;
2367 bool move_both = false;
2369 Location *real_location;
2370 Location *copy_location = 0;
2372 nframes64_t const newframe = adjusted_current_frame (event);
2374 nframes64_t next = newframe;
2376 if (newframe == last_pointer_frame()) {
2380 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2384 MarkerSelection::iterator i;
2385 list<Location*>::iterator x;
2387 /* find the marker we're dragging, and compute the delta */
2389 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2390 x != _copied_locations.end() && i != _editor->selection->markers.end();
2396 if (marker == _marker) {
2398 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2403 if (real_location->is_mark()) {
2404 f_delta = newframe - copy_location->start();
2408 switch (marker->type()) {
2410 case Marker::LoopStart:
2411 case Marker::PunchIn:
2412 f_delta = newframe - copy_location->start();
2416 case Marker::LoopEnd:
2417 case Marker::PunchOut:
2418 f_delta = newframe - copy_location->end();
2421 /* what kind of marker is this ? */
2429 if (i == _editor->selection->markers.end()) {
2430 /* hmm, impossible - we didn't find the dragged marker */
2434 /* now move them all */
2436 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2437 x != _copied_locations.end() && i != _editor->selection->markers.end();
2443 /* call this to find out if its the start or end */
2445 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2449 if (real_location->locked()) {
2453 if (copy_location->is_mark()) {
2457 copy_location->set_start (copy_location->start() + f_delta);
2461 nframes64_t new_start = copy_location->start() + f_delta;
2462 nframes64_t new_end = copy_location->end() + f_delta;
2464 if (is_start) { // start-of-range marker
2467 copy_location->set_start (new_start);
2468 copy_location->set_end (new_end);
2469 } else if (new_start < copy_location->end()) {
2470 copy_location->set_start (new_start);
2472 _editor->snap_to (next, 1, true);
2473 copy_location->set_end (next);
2474 copy_location->set_start (newframe);
2477 } else { // end marker
2480 copy_location->set_end (new_end);
2481 copy_location->set_start (new_start);
2482 } else if (new_end > copy_location->start()) {
2483 copy_location->set_end (new_end);
2484 } else if (newframe > 0) {
2485 _editor->snap_to (next, -1, true);
2486 copy_location->set_start (next);
2487 copy_location->set_end (newframe);
2492 update_item (copy_location);
2494 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2497 lm->set_position (copy_location->start(), copy_location->end());
2501 assert (!_copied_locations.empty());
2503 _editor->show_verbose_time_cursor (newframe, 10);
2506 _editor->update_canvas_now ();
2511 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2513 if (!movement_occurred) {
2515 /* just a click, do nothing but finish
2516 off the selection process
2519 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2522 case Selection::Set:
2523 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2524 _editor->selection->set (_marker);
2528 case Selection::Toggle:
2529 case Selection::Extend:
2530 case Selection::Add:
2537 _editor->_dragging_edit_point = false;
2539 _editor->begin_reversible_command ( _("move marker") );
2540 XMLNode &before = _editor->session()->locations()->get_state();
2542 MarkerSelection::iterator i;
2543 list<Location*>::iterator x;
2546 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2547 x != _copied_locations.end() && i != _editor->selection->markers.end();
2550 Location * location = _editor->find_location_from_marker (*i, is_start);
2554 if (location->locked()) {
2558 if (location->is_mark()) {
2559 location->set_start ((*x)->start());
2561 location->set ((*x)->start(), (*x)->end());
2566 XMLNode &after = _editor->session()->locations()->get_state();
2567 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2568 _editor->commit_reversible_command ();
2574 MarkerDrag::aborted ()
2580 MarkerDrag::update_item (Location* location)
2582 double const x1 = _editor->frame_to_pixel (location->start());
2584 _points.front().set_x(x1);
2585 _points.back().set_x(x1);
2586 _line->property_points() = _points;
2589 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2591 _cumulative_x_drag (0),
2592 _cumulative_y_drag (0)
2594 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2600 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2602 Drag::start_grab (event, _editor->fader_cursor);
2604 // start the grab at the center of the control point so
2605 // the point doesn't 'jump' to the mouse after the first drag
2606 _time_axis_view_grab_x = _point->get_x();
2607 _time_axis_view_grab_y = _point->get_y();
2609 float const fraction = 1 - (_point->get_y() / _point->line().height());
2611 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2613 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2614 event->button.x + 10, event->button.y + 10);
2616 _editor->show_verbose_canvas_cursor ();
2620 ControlPointDrag::motion (GdkEvent* event, bool)
2622 double dx = current_pointer_x() - last_pointer_x();
2623 double dy = current_pointer_y() - last_pointer_y();
2625 if (event->button.state & Keyboard::SecondaryModifier) {
2630 /* coordinate in TimeAxisView's space */
2631 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2632 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2634 // calculate zero crossing point. back off by .01 to stay on the
2635 // positive side of zero
2636 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2638 // make sure we hit zero when passing through
2639 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2643 if (_x_constrained) {
2644 cx = _time_axis_view_grab_x;
2646 if (_y_constrained) {
2647 cy = _time_axis_view_grab_y;
2650 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2651 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2655 cy = min ((double) _point->line().height(), cy);
2657 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2659 if (!_x_constrained) {
2660 _editor->snap_to_with_modifier (cx_frames, event);
2663 float const fraction = 1.0 - (cy / _point->line().height());
2665 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2667 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2669 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2673 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2675 if (!movement_occurred) {
2679 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2680 _editor->reset_point_selection ();
2684 motion (event, false);
2686 _point->line().end_drag ();
2690 ControlPointDrag::aborted ()
2692 _point->line().reset ();
2696 ControlPointDrag::active (Editing::MouseMode m)
2698 if (m == Editing::MouseGain) {
2699 /* always active in mouse gain */
2703 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2704 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2707 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2710 _cumulative_y_drag (0)
2715 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2717 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2720 _item = &_line->grab_item ();
2722 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2723 origin, and ditto for y.
2726 double cx = event->button.x;
2727 double cy = event->button.y;
2729 _line->parent_group().w2i (cx, cy);
2731 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2736 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2737 /* no adjacent points */
2741 Drag::start_grab (event, _editor->fader_cursor);
2743 /* store grab start in parent frame */
2745 _time_axis_view_grab_x = cx;
2746 _time_axis_view_grab_y = cy;
2748 double fraction = 1.0 - (cy / _line->height());
2750 _line->start_drag_line (before, after, fraction);
2752 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2753 event->button.x + 10, event->button.y + 10);
2755 _editor->show_verbose_canvas_cursor ();
2759 LineDrag::motion (GdkEvent* event, bool)
2761 double dy = current_pointer_y() - last_pointer_y();
2763 if (event->button.state & Keyboard::SecondaryModifier) {
2767 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2769 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2772 cy = min ((double) _line->height(), cy);
2774 double const fraction = 1.0 - (cy / _line->height());
2778 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2784 /* we are ignoring x position for this drag, so we can just pass in anything */
2785 _line->drag_motion (0, fraction, true, push);
2787 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2791 LineDrag::finished (GdkEvent* event, bool)
2793 motion (event, false);
2798 LineDrag::aborted ()
2804 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2806 Drag::start_grab (event);
2807 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2811 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2818 /* use a bigger drag threshold than the default */
2820 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2822 if (abs ((int) (pf - grab_frame())) < 8) {
2826 nframes64_t grab = grab_frame ();
2827 if (Config->get_rubberbanding_snaps_to_grid ()) {
2828 _editor->snap_to_with_modifier (grab, event);
2831 /* base start and end on initial click position */
2841 if (current_pointer_y() < grab_y()) {
2842 y1 = current_pointer_y();
2845 y2 = current_pointer_y();
2850 if (start != end || y1 != y2) {
2852 double x1 = _editor->frame_to_pixel (start);
2853 double x2 = _editor->frame_to_pixel (end);
2855 _editor->rubberband_rect->property_x1() = x1;
2856 _editor->rubberband_rect->property_y1() = y1;
2857 _editor->rubberband_rect->property_x2() = x2;
2858 _editor->rubberband_rect->property_y2() = y2;
2860 _editor->rubberband_rect->show();
2861 _editor->rubberband_rect->raise_to_top();
2863 _editor->show_verbose_time_cursor (pf, 10);
2868 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2870 if (movement_occurred) {
2872 motion (event, false);
2875 if (current_pointer_y() < grab_y()) {
2876 y1 = current_pointer_y();
2879 y2 = current_pointer_y();
2884 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2887 _editor->begin_reversible_command (_("rubberband selection"));
2889 if (grab_frame() < last_pointer_frame()) {
2890 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
2892 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
2896 _editor->commit_reversible_command ();
2900 if (!getenv("ARDOUR_SAE")) {
2901 _editor->selection->clear_tracks();
2903 _editor->selection->clear_regions();
2904 _editor->selection->clear_points ();
2905 _editor->selection->clear_lines ();
2908 _editor->rubberband_rect->hide();
2912 RubberbandSelectDrag::aborted ()
2914 _editor->rubberband_rect->hide ();
2918 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2920 Drag::start_grab (event);
2922 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2926 TimeFXDrag::motion (GdkEvent* event, bool)
2928 RegionView* rv = _primary;
2930 nframes64_t const pf = adjusted_current_frame (event);
2932 if (pf > rv->region()->position()) {
2933 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
2936 _editor->show_verbose_time_cursor (pf, 10);
2940 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2942 _primary->get_time_axis_view().hide_timestretch ();
2944 if (!movement_occurred) {
2948 if (last_pointer_frame() < _primary->region()->position()) {
2949 /* backwards drag of the left edge - not usable */
2953 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
2955 float percentage = (double) newlen / (double) _primary->region()->length();
2957 #ifndef USE_RUBBERBAND
2958 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2959 if (_primary->region()->data_type() == DataType::AUDIO) {
2960 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2964 _editor->begin_reversible_command (_("timestretch"));
2966 // XXX how do timeFX on multiple regions ?
2971 if (!_editor->time_stretch (rs, percentage) == 0) {
2972 error << _("An error occurred while executing time stretch operation") << endmsg;
2977 TimeFXDrag::aborted ()
2979 _primary->get_time_axis_view().hide_timestretch ();
2984 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2986 Drag::start_grab (event);
2990 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2996 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2998 if (movement_occurred && _editor->session()) {
2999 /* make sure we stop */
3000 _editor->session()->request_transport_speed (0.0);
3005 ScrubDrag::aborted ()
3010 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3014 , _original_pointer_time_axis (-1)
3015 , _last_pointer_time_axis (-1)
3021 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3023 nframes64_t start = 0;
3024 nframes64_t end = 0;
3026 if (_editor->session() == 0) {
3030 Gdk::Cursor* cursor = 0;
3032 switch (_operation) {
3033 case CreateSelection:
3034 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3039 cursor = _editor->selector_cursor;
3040 Drag::start_grab (event, cursor);
3043 case SelectionStartTrim:
3044 if (_editor->clicked_axisview) {
3045 _editor->clicked_axisview->order_selection_trims (_item, true);
3047 Drag::start_grab (event, _editor->trimmer_cursor);
3048 start = _editor->selection->time[_editor->clicked_selection].start;
3049 _pointer_frame_offset = grab_frame() - start;
3052 case SelectionEndTrim:
3053 if (_editor->clicked_axisview) {
3054 _editor->clicked_axisview->order_selection_trims (_item, false);
3056 Drag::start_grab (event, _editor->trimmer_cursor);
3057 end = _editor->selection->time[_editor->clicked_selection].end;
3058 _pointer_frame_offset = grab_frame() - end;
3062 start = _editor->selection->time[_editor->clicked_selection].start;
3063 Drag::start_grab (event, cursor);
3064 _pointer_frame_offset = grab_frame() - start;
3068 if (_operation == SelectionMove) {
3069 _editor->show_verbose_time_cursor (start, 10);
3071 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3074 _original_pointer_time_axis = _editor->trackview_by_y_position (current_pointer_y ()).first->order ();
3078 SelectionDrag::motion (GdkEvent* event, bool first_move)
3080 nframes64_t start = 0;
3081 nframes64_t end = 0;
3084 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (current_pointer_y ());
3085 if (pending_time_axis.first == 0) {
3089 nframes64_t const pending_position = adjusted_current_frame (event);
3091 /* only alter selection if things have changed */
3093 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3097 switch (_operation) {
3098 case CreateSelection:
3100 nframes64_t grab = grab_frame ();
3103 _editor->snap_to (grab);
3106 if (pending_position < grab_frame()) {
3107 start = pending_position;
3110 end = pending_position;
3114 /* first drag: Either add to the selection
3115 or create a new selection
3120 _editor->begin_reversible_command (_("range selection"));
3121 _have_transaction = true;
3124 /* adding to the selection */
3125 _editor->selection->add (_editor->clicked_axisview);
3126 _editor->clicked_selection = _editor->selection->add (start, end);
3131 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3132 _editor->selection->set (_editor->clicked_axisview);
3135 _editor->clicked_selection = _editor->selection->set (start, end);
3139 /* select the track that we're in */
3140 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3141 _editor->selection->add (pending_time_axis.first);
3142 _added_time_axes.push_back (pending_time_axis.first);
3145 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3146 tracks that we selected in the first place.
3149 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3150 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3152 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3153 while (i != _added_time_axes.end()) {
3155 list<TimeAxisView*>::iterator tmp = i;
3158 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3159 _editor->selection->remove (*i);
3160 _added_time_axes.remove (*i);
3169 case SelectionStartTrim:
3172 _editor->begin_reversible_command (_("trim selection start"));
3173 _have_transaction = true;
3176 start = _editor->selection->time[_editor->clicked_selection].start;
3177 end = _editor->selection->time[_editor->clicked_selection].end;
3179 if (pending_position > end) {
3182 start = pending_position;
3186 case SelectionEndTrim:
3189 _editor->begin_reversible_command (_("trim selection end"));
3190 _have_transaction = true;
3193 start = _editor->selection->time[_editor->clicked_selection].start;
3194 end = _editor->selection->time[_editor->clicked_selection].end;
3196 if (pending_position < start) {
3199 end = pending_position;
3207 _editor->begin_reversible_command (_("move selection"));
3208 _have_transaction = true;
3211 start = _editor->selection->time[_editor->clicked_selection].start;
3212 end = _editor->selection->time[_editor->clicked_selection].end;
3214 length = end - start;
3216 start = pending_position;
3217 _editor->snap_to (start);
3219 end = start + length;
3224 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3225 _editor->start_canvas_autoscroll (1, 0);
3229 _editor->selection->replace (_editor->clicked_selection, start, end);
3232 if (_operation == SelectionMove) {
3233 _editor->show_verbose_time_cursor(start, 10);
3235 _editor->show_verbose_time_cursor(pending_position, 10);
3240 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3242 Session* s = _editor->session();
3244 if (movement_occurred) {
3245 motion (event, false);
3246 /* XXX this is not object-oriented programming at all. ick */
3247 if (_editor->selection->time.consolidate()) {
3248 _editor->selection->TimeChanged ();
3251 if (_have_transaction) {
3252 _editor->commit_reversible_command ();
3255 /* XXX what if its a music time selection? */
3256 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3257 s->request_play_range (&_editor->selection->time, true);
3262 /* just a click, no pointer movement.*/
3264 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3265 _editor->selection->clear_time();
3268 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3269 _editor->selection->set (_editor->clicked_axisview);
3272 if (s && s->get_play_range () && s->transport_rolling()) {
3273 s->request_stop (false, false);
3278 _editor->stop_canvas_autoscroll ();
3282 SelectionDrag::aborted ()
3287 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3292 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3293 _drag_rect->hide ();
3295 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3296 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3300 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3302 if (_editor->session() == 0) {
3306 Gdk::Cursor* cursor = 0;
3308 if (!_editor->temp_location) {
3309 _editor->temp_location = new Location;
3312 switch (_operation) {
3313 case CreateRangeMarker:
3314 case CreateTransportMarker:
3315 case CreateCDMarker:
3317 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3322 cursor = _editor->selector_cursor;
3326 Drag::start_grab (event, cursor);
3328 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3332 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3334 nframes64_t start = 0;
3335 nframes64_t end = 0;
3336 ArdourCanvas::SimpleRect *crect;
3338 switch (_operation) {
3339 case CreateRangeMarker:
3340 crect = _editor->range_bar_drag_rect;
3342 case CreateTransportMarker:
3343 crect = _editor->transport_bar_drag_rect;
3345 case CreateCDMarker:
3346 crect = _editor->cd_marker_bar_drag_rect;
3349 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3354 nframes64_t const pf = adjusted_current_frame (event);
3356 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3357 nframes64_t grab = grab_frame ();
3358 _editor->snap_to (grab);
3360 if (pf < grab_frame()) {
3368 /* first drag: Either add to the selection
3369 or create a new selection.
3374 _editor->temp_location->set (start, end);
3378 update_item (_editor->temp_location);
3380 //_drag_rect->raise_to_top();
3385 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3386 _editor->start_canvas_autoscroll (1, 0);
3390 _editor->temp_location->set (start, end);
3392 double x1 = _editor->frame_to_pixel (start);
3393 double x2 = _editor->frame_to_pixel (end);
3394 crect->property_x1() = x1;
3395 crect->property_x2() = x2;
3397 update_item (_editor->temp_location);
3400 _editor->show_verbose_time_cursor (pf, 10);
3405 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3407 Location * newloc = 0;
3411 if (movement_occurred) {
3412 motion (event, false);
3415 switch (_operation) {
3416 case CreateRangeMarker:
3417 case CreateCDMarker:
3419 _editor->begin_reversible_command (_("new range marker"));
3420 XMLNode &before = _editor->session()->locations()->get_state();
3421 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3422 if (_operation == CreateCDMarker) {
3423 flags = Location::IsRangeMarker | Location::IsCDMarker;
3424 _editor->cd_marker_bar_drag_rect->hide();
3427 flags = Location::IsRangeMarker;
3428 _editor->range_bar_drag_rect->hide();
3430 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3431 _editor->session()->locations()->add (newloc, true);
3432 XMLNode &after = _editor->session()->locations()->get_state();
3433 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3434 _editor->commit_reversible_command ();
3438 case CreateTransportMarker:
3439 // popup menu to pick loop or punch
3440 _editor->new_transport_marker_context_menu (&event->button, _item);
3444 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3446 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3451 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3453 if (end == max_frames) {
3454 end = _editor->session()->current_end_frame ();
3457 if (start == max_frames) {
3458 start = _editor->session()->current_start_frame ();
3461 switch (_editor->mouse_mode) {
3463 /* find the two markers on either side and then make the selection from it */
3464 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3468 /* find the two markers on either side of the click and make the range out of it */
3469 _editor->selection->set (start, end);
3478 _editor->stop_canvas_autoscroll ();
3482 RangeMarkerBarDrag::aborted ()
3488 RangeMarkerBarDrag::update_item (Location* location)
3490 double const x1 = _editor->frame_to_pixel (location->start());
3491 double const x2 = _editor->frame_to_pixel (location->end());
3493 _drag_rect->property_x1() = x1;
3494 _drag_rect->property_x2() = x2;
3498 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3500 Drag::start_grab (event, _editor->zoom_cursor);
3501 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3505 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3510 nframes64_t const pf = adjusted_current_frame (event);
3512 nframes64_t grab = grab_frame ();
3513 _editor->snap_to_with_modifier (grab, event);
3515 /* base start and end on initial click position */
3527 _editor->zoom_rect->show();
3528 _editor->zoom_rect->raise_to_top();
3531 _editor->reposition_zoom_rect(start, end);
3533 _editor->show_verbose_time_cursor (pf, 10);
3538 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3540 if (movement_occurred) {
3541 motion (event, false);
3543 if (grab_frame() < last_pointer_frame()) {
3544 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3546 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3549 _editor->temporal_zoom_to_frame (false, grab_frame());
3551 temporal_zoom_step (false);
3552 center_screen (grab_frame());
3556 _editor->zoom_rect->hide();
3560 MouseZoomDrag::aborted ()
3562 _editor->zoom_rect->hide ();
3565 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3568 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3569 region = &cnote->region_view();
3573 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3575 Drag::start_grab (event);
3578 drag_delta_note = 0;
3583 event_x = current_pointer_x();
3584 event_y = current_pointer_y();
3586 _item->property_parent().get_value()->w2i(event_x, event_y);
3588 last_x = region->snap_to_pixel(event_x);
3591 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3593 if (!(was_selected = cnote->selected())) {
3595 /* tertiary-click means extend selection - we'll do that on button release,
3596 so don't add it here, because otherwise we make it hard to figure
3597 out the "extend-to" range.
3600 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3603 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3606 region->note_selected (cnote, true);
3608 region->unique_select (cnote);
3615 NoteDrag::motion (GdkEvent*, bool)
3617 MidiStreamView* streamview = region->midi_stream_view();
3621 event_x = current_pointer_x();
3622 event_y = current_pointer_y();
3624 _item->property_parent().get_value()->w2i(event_x, event_y);
3626 event_x = region->snap_to_pixel(event_x);
3628 double dx = event_x - last_x;
3629 double dy = event_y - last_y;
3634 // Snap to note rows
3636 if (abs (dy) < streamview->note_height()) {
3639 int8_t this_delta_note;
3641 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3643 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3645 drag_delta_note -= this_delta_note;
3646 dy = streamview->note_height() * this_delta_note;
3647 last_y = last_y + dy;
3651 region->move_selection (dx, dy);
3653 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3655 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3656 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3657 _editor->show_verbose_canvas_cursor_with (buf);
3662 NoteDrag::finished (GdkEvent* ev, bool moved)
3664 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3667 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3670 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3672 region->note_deselected (cnote);
3675 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3676 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3678 if (!extend && !add && region->selection_size() > 1) {
3679 region->unique_select(cnote);
3680 } else if (extend) {
3681 region->note_selected (cnote, true, true);
3683 /* it was added during button press */
3688 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3693 NoteDrag::aborted ()
3698 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3701 , _nothing_to_drag (false)
3703 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3706 _line = _atav->line ();
3710 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3712 Drag::start_grab (event, cursor);
3714 list<ControlPoint*> points;
3716 XMLNode* state = &_line->get_state ();
3718 if (_ranges.empty()) {
3720 uint32_t const N = _line->npoints ();
3721 for (uint32_t i = 0; i < N; ++i) {
3722 points.push_back (_line->nth (i));
3727 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3728 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3730 /* fade into and out of the region that we're dragging;
3731 64 samples length plucked out of thin air.
3733 nframes64_t const h = (j->start + j->end) / 2;
3734 nframes64_t a = j->start + 64;
3738 nframes64_t b = j->end - 64;
3743 the_list->add (j->start, the_list->eval (j->start));
3744 _line->add_always_in_view (j->start);
3745 the_list->add (a, the_list->eval (a));
3746 _line->add_always_in_view (a);
3747 the_list->add (b, the_list->eval (b));
3748 _line->add_always_in_view (b);
3749 the_list->add (j->end, the_list->eval (j->end));
3750 _line->add_always_in_view (j->end);
3753 uint32_t const N = _line->npoints ();
3754 for (uint32_t i = 0; i < N; ++i) {
3756 ControlPoint* p = _line->nth (i);
3758 list<AudioRange>::const_iterator j = _ranges.begin ();
3759 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3763 if (j != _ranges.end()) {
3764 points.push_back (p);
3769 if (points.empty()) {
3770 _nothing_to_drag = true;
3774 _line->start_drag_multiple (points, 1 - (current_pointer_y() / _line->height ()), state);
3778 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3780 if (_nothing_to_drag) {
3784 float const f = 1 - (current_pointer_y() / _line->height());
3786 /* we are ignoring x position for this drag, so we can just pass in anything */
3787 _line->drag_motion (0, f, true, false);
3791 AutomationRangeDrag::finished (GdkEvent* event, bool)
3793 if (_nothing_to_drag) {
3797 motion (event, false);
3799 _line->clear_always_in_view ();
3803 AutomationRangeDrag::aborted ()
3805 _line->clear_always_in_view ();