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 #define __STDC_LIMIT_MACROS 1
22 #include "pbd/memento_command.h"
23 #include "pbd/basename.h"
24 #include "pbd/stateful_diff_command.h"
25 #include "ardour/diskstream.h"
26 #include "ardour/region_command.h"
27 #include "ardour/session.h"
28 #include "ardour/dB.h"
29 #include "ardour/region_factory.h"
30 #include "ardour/midi_diskstream.h"
34 #include "audio_region_view.h"
35 #include "midi_region_view.h"
36 #include "ardour_ui.h"
37 #include "gui_thread.h"
38 #include "control_point.h"
40 #include "region_gain_line.h"
41 #include "editor_drag.h"
42 #include "audio_time_axis.h"
43 #include "midi_time_axis.h"
44 #include "canvas-note.h"
45 #include "selection.h"
46 #include "midi_selection.h"
47 #include "automation_time_axis.h"
50 using namespace ARDOUR;
53 using namespace Editing;
54 using namespace ArdourCanvas;
56 using Gtkmm2ext::Keyboard;
58 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
60 DragManager::DragManager (Editor* e)
63 , _current_pointer_frame (0)
68 DragManager::~DragManager ()
76 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
85 DragManager::break_drag ()
89 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
100 DragManager::add (Drag* d)
102 d->set_manager (this);
103 _drags.push_back (d);
107 DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
109 assert (_drags.empty ());
110 d->set_manager (this);
111 _drags.push_back (d);
116 DragManager::start_grab (GdkEvent* e)
118 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
120 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
121 (*i)->start_grab (e);
126 DragManager::end_grab (GdkEvent* e)
131 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
132 bool const t = (*i)->end_grab (e);
147 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
151 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
153 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
154 bool const t = (*i)->motion_handler (e, from_autoscroll);
165 DragManager::have_item (ArdourCanvas::Item* i) const
167 list<Drag*>::const_iterator j = _drags.begin ();
168 while (j != _drags.end() && (*j)->item () != i) {
172 return j != _drags.end ();
175 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
178 , _pointer_frame_offset (0)
179 , _move_threshold_passed (false)
181 , _last_pointer_frame (0)
187 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
193 cursor = _editor->which_grabber_cursor ();
196 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
200 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
203 cursor = _editor->which_grabber_cursor ();
206 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
208 if (Keyboard::is_button2_event (&event->button)) {
209 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
210 _y_constrained = true;
211 _x_constrained = false;
213 _y_constrained = false;
214 _x_constrained = true;
217 _x_constrained = false;
218 _y_constrained = false;
221 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
222 _grab_frame = adjusted_frame (_grab_frame, event);
223 _last_pointer_frame = _grab_frame;
224 _last_pointer_x = _grab_x;
225 _last_pointer_y = _grab_y;
227 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
231 if (_editor->session() && _editor->session()->transport_rolling()) {
234 _was_rolling = false;
237 switch (_editor->snap_type()) {
238 case SnapToRegionStart:
239 case SnapToRegionEnd:
240 case SnapToRegionSync:
241 case SnapToRegionBoundary:
242 _editor->build_region_boundary_cache ();
249 /** @param event GDK event, or 0.
250 * @return true if some movement occurred, otherwise false.
253 Drag::end_grab (GdkEvent* event)
255 _editor->stop_canvas_autoscroll ();
257 _item->ungrab (event ? event->button.time : 0);
259 finished (event, _move_threshold_passed);
261 _editor->hide_verbose_canvas_cursor();
263 return _move_threshold_passed;
267 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
271 if (f > _pointer_frame_offset) {
272 pos = f - _pointer_frame_offset;
276 _editor->snap_to_with_modifier (pos, event);
283 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
285 return adjusted_frame (_drags->current_pointer_frame (), event, snap);
289 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
291 /* check to see if we have moved in any way that matters since the last motion event */
292 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
293 (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
297 pair<nframes64_t, int> const threshold = move_threshold ();
299 bool const old_move_threshold_passed = _move_threshold_passed;
301 if (!from_autoscroll && !_move_threshold_passed) {
303 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
304 bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
306 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
309 if (active (_editor->mouse_mode) && _move_threshold_passed) {
311 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
312 if (!from_autoscroll) {
313 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
316 motion (event, _move_threshold_passed != old_move_threshold_passed);
318 _last_pointer_x = _drags->current_pointer_x ();
319 _last_pointer_y = _drags->current_pointer_y ();
320 _last_pointer_frame = adjusted_current_frame (event);
338 _editor->stop_canvas_autoscroll ();
339 _editor->hide_verbose_canvas_cursor ();
342 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
347 RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
351 RegionDrag::region_going_away (RegionView* v)
356 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
357 : RegionDrag (e, i, p, v),
368 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
370 Drag::start_grab (event);
372 _editor->show_verbose_time_cursor (_last_frame_position, 10);
375 RegionMotionDrag::TimeAxisViewSummary
376 RegionMotionDrag::get_time_axis_view_summary ()
378 int32_t children = 0;
379 TimeAxisViewSummary sum;
381 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
383 /* get a bitmask representing the visible tracks */
385 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
386 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
387 TimeAxisView::Children children_list;
389 /* zeroes are audio/MIDI tracks. ones are other types. */
391 if (!rtv->hidden()) {
393 if (!rtv->is_track()) {
394 /* not an audio nor MIDI track */
395 sum.tracks = sum.tracks |= (0x01 << rtv->order());
398 sum.height_list[rtv->order()] = (*i)->current_height();
401 if ((children_list = rtv->get_child_list()).size() > 0) {
402 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
403 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
404 sum.height_list[rtv->order() + children] = (*j)->current_height();
415 RegionMotionDrag::compute_y_delta (
416 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
417 int32_t last_pointer_layer, int32_t current_pointer_layer,
418 TimeAxisViewSummary const & tavs,
419 int32_t* pointer_order_span, int32_t* pointer_layer_span,
420 int32_t* canvas_pointer_order_span
424 *pointer_order_span = 0;
425 *pointer_layer_span = 0;
429 bool clamp_y_axis = false;
431 /* the change in track order between this callback and the last */
432 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
433 /* the change in layer between this callback and the last;
434 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
435 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
437 if (*pointer_order_span != 0) {
439 /* find the actual pointer span, in terms of the number of visible tracks;
440 to do this, we reduce |pointer_order_span| by the number of hidden tracks
443 *canvas_pointer_order_span = *pointer_order_span;
444 if (last_pointer_view->order() >= current_pointer_view->order()) {
445 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
446 if (tavs.height_list[y] == 0) {
447 *canvas_pointer_order_span--;
451 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
452 if (tavs.height_list[y] == 0) {
453 *canvas_pointer_order_span++;
458 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
460 RegionView* rv = (*i);
462 if (rv->region()->locked()) {
466 double ix1, ix2, iy1, iy2;
467 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
468 rv->get_canvas_frame()->i2w (ix1, iy1);
469 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
471 /* get the new trackview for this particular region */
472 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
474 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
476 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
477 as surely this is a per-region thing... */
479 clamp_y_axis = y_movement_disallowed (
480 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
488 } else if (_dest_trackview == current_pointer_view) {
490 if (current_pointer_layer == last_pointer_layer) {
491 /* No movement; clamp */
497 _dest_trackview = current_pointer_view;
498 _dest_layer = current_pointer_layer;
506 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
508 /* compute the amount of pointer motion in frames, and where
509 the region would be if we moved it by that much.
511 *pending_region_position = adjusted_current_frame (event);
513 nframes64_t sync_frame;
514 nframes64_t sync_offset;
517 sync_offset = _primary->region()->sync_offset (sync_dir);
519 /* we don't handle a sync point that lies before zero.
521 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
523 sync_frame = *pending_region_position + (sync_dir*sync_offset);
525 _editor->snap_to_with_modifier (sync_frame, event);
527 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
530 *pending_region_position = _last_frame_position;
533 if (*pending_region_position > max_frames - _primary->region()->length()) {
534 *pending_region_position = _last_frame_position;
539 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
541 /* now compute the canvas unit distance we need to move the regionview
542 to make it appear at the new location.
545 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
547 if (*pending_region_position <= _last_frame_position) {
549 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
551 RegionView* rv = (*i);
553 // If any regionview is at zero, we need to know so we can stop further leftward motion.
555 double ix1, ix2, iy1, iy2;
556 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
557 rv->get_canvas_frame()->i2w (ix1, iy1);
559 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
561 *pending_region_position = _last_frame_position;
568 _last_frame_position = *pending_region_position;
575 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
579 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
581 vector<int32_t>::iterator j;
583 /* *pointer* variables reflect things about the pointer; as we may be moving
584 multiple regions, much detail must be computed per-region */
586 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
587 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
588 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
589 is always 0 regardless of what the region's "real" layer is */
590 RouteTimeAxisView* current_pointer_view;
591 layer_t current_pointer_layer;
592 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
596 /* TimeAxisView that we were pointing at last time we entered this method */
597 TimeAxisView const * const last_pointer_view = _dest_trackview;
598 /* the order of the track that we were pointing at last time we entered this method */
599 int32_t const last_pointer_order = last_pointer_view->order ();
600 /* the layer that we were pointing at last time we entered this method */
601 layer_t const last_pointer_layer = _dest_layer;
603 int32_t pointer_order_span;
604 int32_t pointer_layer_span;
605 int32_t canvas_pointer_order_span;
607 bool const clamp_y_axis = compute_y_delta (
608 last_pointer_view, current_pointer_view,
609 last_pointer_layer, current_pointer_layer, tavs,
610 &pointer_order_span, &pointer_layer_span,
611 &canvas_pointer_order_span
614 nframes64_t pending_region_position;
615 double const x_delta = compute_x_delta (event, &pending_region_position);
617 /*************************************************************
619 ************************************************************/
621 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
622 /* haven't reached next snap point, and we're not switching
623 trackviews nor layers. nothing to do.
628 /*************************************************************
630 ************************************************************/
632 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
634 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
636 RegionView* rv = (*i);
638 if (rv->region()->locked()) {
642 /* here we are calculating the y distance from the
643 top of the first track view to the top of the region
644 area of the track view that we're working on */
646 /* this x value is just a dummy value so that we have something
651 /* distance from the top of this track view to the region area
652 of our track view is always 1 */
656 /* convert to world coordinates, ie distance from the top of
659 rv->get_canvas_frame()->i2w (ix1, iy1);
661 /* compensate for the ruler section and the vertical scrollbar position */
662 iy1 += _editor->get_trackview_group_vertical_offset ();
666 // hide any dependent views
668 rv->get_time_axis_view().hide_dependent_views (*rv);
671 reparent to a non scrolling group so that we can keep the
672 region selection above all time axis views.
673 reparenting means we have to move the rv as the two
674 parent groups have different coordinates.
677 rv->get_canvas_group()->property_y() = iy1 - 1;
678 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
680 rv->fake_set_opaque (true);
683 /* current view for this particular region */
684 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
685 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
687 if (pointer_order_span != 0 && !clamp_y_axis) {
689 /* INTER-TRACK MOVEMENT */
691 /* move through the height list to the track that the region is currently on */
692 vector<int32_t>::iterator j = tavs.height_list.begin ();
694 while (j != tavs.height_list.end () && x != rtv->order ()) {
700 int32_t temp_pointer_order_span = canvas_pointer_order_span;
702 if (j != tavs.height_list.end ()) {
704 /* Account for layers in the original and
705 destination tracks. If we're moving around in layers we assume
706 that only one track is involved, so it's ok to use *pointer*
709 StreamView* lv = last_pointer_view->view ();
712 /* move to the top of the last trackview */
713 if (lv->layer_display () == Stacked) {
714 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
717 StreamView* cv = current_pointer_view->view ();
720 /* move to the right layer on the current trackview */
721 if (cv->layer_display () == Stacked) {
722 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
725 /* And for being on a non-topmost layer on the new
728 while (temp_pointer_order_span > 0) {
729 /* we're moving up canvas-wise,
730 so we need to find the next track height
732 if (j != tavs.height_list.begin()) {
736 if (x != last_pointer_order) {
738 ++temp_pointer_order_span;
743 temp_pointer_order_span--;
746 while (temp_pointer_order_span < 0) {
750 if (x != last_pointer_order) {
752 --temp_pointer_order_span;
756 if (j != tavs.height_list.end()) {
760 temp_pointer_order_span++;
764 /* find out where we'll be when we move and set height accordingly */
766 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
767 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
768 rv->set_height (temp_rtv->view()->child_height());
770 /* if you un-comment the following, the region colours will follow
771 the track colours whilst dragging; personally
772 i think this can confuse things, but never mind.
775 //const GdkColor& col (temp_rtv->view->get_region_color());
776 //rv->set_color (const_cast<GdkColor&>(col));
780 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
782 /* INTER-LAYER MOVEMENT in the same track */
783 y_delta = rtv->view()->child_height () * pointer_layer_span;
788 _editor->mouse_brush_insert_region (rv, pending_region_position);
790 rv->move (x_delta, y_delta);
793 } /* foreach region */
795 _total_x_delta += x_delta;
798 _editor->cursor_group->raise_to_top();
801 if (x_delta != 0 && !_brushing) {
802 _editor->show_verbose_time_cursor (_last_frame_position, 10);
807 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
809 if (_copy && first_move) {
810 copy_regions (event);
813 RegionMotionDrag::motion (event, first_move);
817 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
819 vector<RegionView*> copies;
820 boost::shared_ptr<Diskstream> ds;
821 boost::shared_ptr<Playlist> from_playlist;
822 RegionSelection new_views;
823 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
824 PlaylistSet modified_playlists;
825 PlaylistSet frozen_playlists;
826 list <sigc::connection> modified_playlist_connections;
827 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
828 nframes64_t drag_delta;
829 bool changed_tracks, changed_position;
830 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
831 RouteTimeAxisView* source_tv;
833 if (!movement_occurred) {
839 /* all changes were made during motion event handlers */
842 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
843 copies.push_back (*i);
850 /* reverse this here so that we have the correct logic to finalize
854 if (Config->get_edit_mode() == Lock) {
855 _x_constrained = !_x_constrained;
859 if (_x_constrained) {
860 _editor->begin_reversible_command (_("fixed time region copy"));
862 _editor->begin_reversible_command (_("region copy"));
865 if (_x_constrained) {
866 _editor->begin_reversible_command (_("fixed time region drag"));
868 _editor->begin_reversible_command (_("region drag"));
872 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
873 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
875 drag_delta = _primary->region()->position() - _last_frame_position;
877 _editor->update_canvas_now ();
879 /* make a list of where each region ended up */
880 final = find_time_axis_views_and_layers ();
882 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
884 RegionView* rv = (*i);
885 RouteTimeAxisView* dest_rtv = final[*i].first;
886 layer_t dest_layer = final[*i].second;
890 if (rv->region()->locked()) {
895 if (changed_position && !_x_constrained) {
896 where = rv->region()->position() - drag_delta;
898 where = rv->region()->position();
901 boost::shared_ptr<Region> new_region;
904 /* we already made a copy */
905 new_region = rv->region();
907 /* undo the previous hide_dependent_views so that xfades don't
908 disappear on copying regions
911 //rv->get_time_axis_view().reveal_dependent_views (*rv);
913 } else if (changed_tracks && dest_rtv->playlist()) {
914 new_region = RegionFactory::create (rv->region());
917 if (changed_tracks || _copy) {
919 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
926 _editor->latest_regionviews.clear ();
928 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
930 insert_result = modified_playlists.insert (to_playlist);
932 if (insert_result.second) {
933 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
936 to_playlist->add_region (new_region, where);
937 if (dest_rtv->view()->layer_display() == Stacked) {
938 new_region->set_layer (dest_layer);
939 new_region->set_pending_explicit_relayer (true);
944 if (!_editor->latest_regionviews.empty()) {
945 // XXX why just the first one ? we only expect one
946 // commented out in nick_m's canvas reworking. is that intended?
947 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
948 new_views.push_back (_editor->latest_regionviews.front());
952 rv->region()->clear_history ();
955 motion on the same track. plonk the previously reparented region
956 back to its original canvas group (its streamview).
957 No need to do anything for copies as they are fake regions which will be deleted.
960 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
961 rv->get_canvas_group()->property_y() = 0;
962 rv->get_time_axis_view().reveal_dependent_views (*rv);
964 /* just change the model */
966 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
968 if (dest_rtv->view()->layer_display() == Stacked) {
969 rv->region()->set_layer (dest_layer);
970 rv->region()->set_pending_explicit_relayer (true);
973 /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
975 frozen_insert_result = frozen_playlists.insert(playlist);
977 if (frozen_insert_result.second) {
981 rv->region()->set_position (where, (void*) this);
983 _editor->session()->add_command (new StatefulDiffCommand (rv->region()));
986 if (changed_tracks && !_copy) {
988 /* get the playlist where this drag started. we can't use rv->region()->playlist()
989 because we may have copied the region and it has not been attached to a playlist.
992 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
993 ds = source_tv->get_diskstream();
994 from_playlist = ds->playlist();
998 assert (from_playlist);
1000 /* moved to a different audio track, without copying */
1002 /* the region that used to be in the old playlist is not
1003 moved to the new one - we use a copy of it. as a result,
1004 any existing editor for the region should no longer be
1008 rv->hide_region_editor();
1009 rv->fake_set_opaque (false);
1011 /* remove the region from the old playlist */
1013 insert_result = modified_playlists.insert (from_playlist);
1015 if (insert_result.second) {
1016 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
1019 from_playlist->remove_region (rv->region());
1021 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1022 was selected in all of them, then removing it from a playlist will have removed all
1023 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1024 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1025 corresponding regionview, and the selection is now empty).
1027 this could have invalidated any and all iterators into the region selection.
1029 the heuristic we use here is: if the region selection is empty, break out of the loop
1030 here. if the region selection is not empty, then restart the loop because we know that
1031 we must have removed at least the region(view) we've just been working on as well as any
1032 that we processed on previous iterations.
1034 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1035 we can just iterate.
1038 if (_views.empty()) {
1049 copies.push_back (rv);
1053 if we've created new regions either by copying or moving
1054 to a new track, we want to replace the old selection with the new ones
1056 if (new_views.size() > 0) {
1057 _editor->selection->set (new_views);
1060 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1065 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
1066 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
1069 _editor->commit_reversible_command ();
1071 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1077 RegionMoveDrag::aborted ()
1081 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1088 RegionMotionDrag::aborted ();
1093 RegionMotionDrag::aborted ()
1095 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1096 TimeAxisView* tv = &(*i)->get_time_axis_view ();
1097 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1099 (*i)->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1100 (*i)->get_canvas_group()->property_y() = 0;
1101 (*i)->get_time_axis_view().reveal_dependent_views (**i);
1102 (*i)->fake_set_opaque (false);
1103 (*i)->move (-_total_x_delta, 0);
1104 (*i)->set_height (rtv->view()->child_height ());
1107 _editor->update_canvas_now ();
1112 RegionMotionDrag::x_move_allowed () const
1114 if (Config->get_edit_mode() == Lock) {
1115 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1116 return _x_constrained;
1119 return !_x_constrained;
1123 RegionMotionDrag::copy_regions (GdkEvent* event)
1125 /* duplicate the regionview(s) and region(s) */
1127 list<RegionView*> new_regionviews;
1129 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1131 RegionView* rv = (*i);
1132 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1133 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1135 const boost::shared_ptr<const Region> original = rv->region();
1136 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1140 boost::shared_ptr<AudioRegion> audioregion_copy
1141 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1142 nrv = new AudioRegionView (*arv, audioregion_copy);
1144 boost::shared_ptr<MidiRegion> midiregion_copy
1145 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1146 nrv = new MidiRegionView (*mrv, midiregion_copy);
1151 nrv->get_canvas_group()->show ();
1152 new_regionviews.push_back (nrv);
1154 /* swap _primary to the copy */
1156 if (rv == _primary) {
1160 /* ..and deselect the one we copied */
1162 rv->set_selected (false);
1165 if (new_regionviews.empty()) {
1169 /* reflect the fact that we are dragging the copies */
1171 _views = new_regionviews;
1173 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1176 sync the canvas to what we think is its current state
1177 without it, the canvas seems to
1178 "forget" to update properly after the upcoming reparent()
1179 ..only if the mouse is in rapid motion at the time of the grab.
1180 something to do with regionview creation taking so long?
1182 _editor->update_canvas_now();
1186 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1188 /* Which trackview is this ? */
1190 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1191 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1192 (*layer) = tvp.second;
1194 if (*tv && (*tv)->layer_display() == Overlaid) {
1198 /* The region motion is only processed if the pointer is over
1202 if (!(*tv) || !(*tv)->is_track()) {
1203 /* To make sure we hide the verbose canvas cursor when the mouse is
1204 not held over and audiotrack.
1206 _editor->hide_verbose_canvas_cursor ();
1213 /** @param new_order New track order.
1214 * @param old_order Old track order.
1215 * @param visible_y_low Lowest visible order.
1216 * @return true if y movement should not happen, otherwise false.
1219 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1221 if (new_order != old_order) {
1223 /* this isn't the pointer track */
1227 /* moving up the canvas */
1228 if ( (new_order - y_span) >= tavs.visible_y_low) {
1232 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1233 int32_t visible_tracks = 0;
1234 while (visible_tracks < y_span ) {
1236 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1237 /* passing through a hidden track */
1242 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1243 /* moving to a non-track; disallow */
1249 /* moving beyond the lowest visible track; disallow */
1253 } else if (y_span < 0) {
1255 /* moving down the canvas */
1256 if ((new_order - y_span) <= tavs.visible_y_high) {
1258 int32_t visible_tracks = 0;
1260 while (visible_tracks > y_span ) {
1263 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1264 /* passing through a hidden track */
1269 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1270 /* moving to a non-track; disallow */
1277 /* moving beyond the highest visible track; disallow */
1284 /* this is the pointer's track */
1286 if ((new_order - y_span) > tavs.visible_y_high) {
1287 /* we will overflow */
1289 } else if ((new_order - y_span) < tavs.visible_y_low) {
1290 /* we will overflow */
1299 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1300 : RegionMotionDrag (e, i, p, v, b),
1303 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1305 _dest_trackview = tv;
1306 if (tv->layer_display() == Overlaid) {
1309 _dest_layer = _primary->region()->layer ();
1313 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1314 if (rtv && rtv->is_track()) {
1315 speed = rtv->get_diskstream()->speed ();
1318 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1322 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1324 RegionMotionDrag::start_grab (event, c);
1326 _pointer_frame_offset = grab_frame() - _last_frame_position;
1329 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1330 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1332 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1333 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1335 _primary = v->view()->create_region_view (r, false, false);
1337 _primary->get_canvas_group()->show ();
1338 _primary->set_position (pos, 0);
1339 _views.push_back (_primary);
1341 _last_frame_position = pos;
1343 _item = _primary->get_canvas_group ();
1344 _dest_trackview = v;
1345 _dest_layer = _primary->region()->layer ();
1348 map<RegionView*, pair<RouteTimeAxisView*, int> >
1349 RegionMotionDrag::find_time_axis_views_and_layers ()
1351 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1353 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1355 double ix1, ix2, iy1, iy2;
1356 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1357 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1358 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1360 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1361 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1369 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1371 _editor->update_canvas_now ();
1373 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1375 RouteTimeAxisView* dest_rtv = final[_primary].first;
1377 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1378 _primary->get_canvas_group()->property_y() = 0;
1380 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1382 _editor->begin_reversible_command (_("insert region"));
1383 XMLNode& before = playlist->get_state ();
1384 playlist->add_region (_primary->region (), _last_frame_position);
1385 _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1386 _editor->commit_reversible_command ();
1394 RegionInsertDrag::aborted ()
1399 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1400 : RegionMoveDrag (e, i, p, v, false, false)
1405 struct RegionSelectionByPosition {
1406 bool operator() (RegionView*a, RegionView* b) {
1407 return a->region()->position () < b->region()->position();
1412 RegionSpliceDrag::motion (GdkEvent* event, bool)
1414 RouteTimeAxisView* tv;
1417 if (!check_possible (&tv, &layer)) {
1423 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1429 RegionSelection copy (_editor->selection->regions);
1431 RegionSelectionByPosition cmp;
1434 nframes64_t const pf = adjusted_current_frame (event);
1436 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1438 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1444 boost::shared_ptr<Playlist> playlist;
1446 if ((playlist = atv->playlist()) == 0) {
1450 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1455 if (pf < (*i)->region()->last_frame() + 1) {
1459 if (pf > (*i)->region()->first_frame()) {
1465 playlist->shuffle ((*i)->region(), dir);
1470 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1476 RegionSpliceDrag::aborted ()
1481 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1489 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1491 _dest_trackview = _view;
1493 Drag::start_grab (event);
1498 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1501 // TODO: create region-create-drag region view here
1504 // TODO: resize region-create-drag region view here
1508 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1510 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1516 if (!movement_occurred) {
1517 mtv->add_region (grab_frame ());
1519 motion (event, false);
1520 // TODO: create region-create-drag region here
1525 RegionCreateDrag::aborted ()
1530 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1538 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1541 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1543 Drag::start_grab (event);
1545 region = &cnote->region_view();
1547 double region_start = region->get_position_pixels();
1548 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1550 if (grab_x() <= middle_point) {
1551 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1554 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1558 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1560 if (event->motion.state & Keyboard::PrimaryModifier) {
1566 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1568 if (ms.size() > 1) {
1569 /* has to be relative, may make no sense otherwise */
1573 region->note_selected (cnote, true);
1575 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1576 MidiRegionSelection::iterator next;
1579 (*r)->begin_resizing (at_front);
1585 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1587 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1588 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1589 (*r)->update_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1594 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1596 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1597 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1598 (*r)->commit_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1603 NoteResizeDrag::aborted ()
1609 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1615 RegionGainDrag::finished (GdkEvent *, bool)
1621 RegionGainDrag::aborted ()
1626 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1627 : RegionDrag (e, i, p, v)
1628 , _have_transaction (false)
1634 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1637 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1638 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1640 if (tv && tv->is_track()) {
1641 speed = tv->get_diskstream()->speed();
1644 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1645 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1646 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1648 Drag::start_grab (event, _editor->trimmer_cursor);
1650 nframes64_t const pf = adjusted_current_frame (event);
1652 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1653 _operation = ContentsTrim;
1655 /* These will get overridden for a point trim.*/
1656 if (pf < (region_start + region_length/2)) {
1657 /* closer to start */
1658 _operation = StartTrim;
1659 } else if (pf > (region_end - region_length/2)) {
1661 _operation = EndTrim;
1665 switch (_operation) {
1667 _editor->show_verbose_time_cursor (region_start, 10);
1670 _editor->show_verbose_time_cursor (region_end, 10);
1673 _editor->show_verbose_time_cursor (pf, 10);
1679 TrimDrag::motion (GdkEvent* event, bool first_move)
1681 RegionView* rv = _primary;
1682 nframes64_t frame_delta = 0;
1684 bool left_direction;
1685 bool obey_snap = event ? !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) : false;
1687 /* snap modifier works differently here..
1688 its current state has to be passed to the
1689 various trim functions in order to work properly
1693 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1694 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1695 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1697 if (tv && tv->is_track()) {
1698 speed = tv->get_diskstream()->speed();
1701 nframes64_t const pf = adjusted_current_frame (event);
1703 if (last_pointer_frame() > pf) {
1704 left_direction = true;
1706 left_direction = false;
1713 switch (_operation) {
1715 trim_type = "Region start trim";
1718 trim_type = "Region end trim";
1721 trim_type = "Region content trim";
1725 _editor->begin_reversible_command (trim_type);
1726 _have_transaction = true;
1728 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1729 (*i)->fake_set_opaque(false);
1730 (*i)->region()->freeze ();
1732 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1735 arv->temporarily_hide_envelope ();
1738 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1739 insert_result = _editor->motion_frozen_playlists.insert (pl);
1741 if (insert_result.second) {
1742 _editor->session()->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1748 if (left_direction) {
1749 frame_delta = (last_pointer_frame() - pf);
1751 frame_delta = (pf - last_pointer_frame());
1754 bool non_overlap_trim = false;
1756 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1757 non_overlap_trim = true;
1760 switch (_operation) {
1762 if ((left_direction == false) && (pf <= rv->region()->first_frame()/speed)) {
1766 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1767 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1773 if ((left_direction == true) && (pf > (nframes64_t) (rv->region()->last_frame()/speed))) {
1777 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1778 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1785 bool swap_direction = false;
1787 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1788 swap_direction = true;
1791 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1792 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1798 switch (_operation) {
1800 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1803 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1806 _editor->show_verbose_time_cursor (pf, 10);
1813 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1815 if (movement_occurred) {
1816 motion (event, false);
1818 if (!_editor->selection->selected (_primary)) {
1819 _editor->thaw_region_after_trim (*_primary);
1822 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1823 _editor->thaw_region_after_trim (**i);
1824 (*i)->fake_set_opaque (true);
1827 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1829 if (_have_transaction) {
1830 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1834 _editor->motion_frozen_playlists.clear ();
1836 if (_have_transaction) {
1837 _editor->commit_reversible_command();
1841 /* no mouse movement */
1842 _editor->point_trim (event, adjusted_current_frame (event));
1847 TrimDrag::aborted ()
1849 /* Our motion method is changing model state, so use the Undo system
1850 to cancel. Perhaps not ideal, as this will leave an Undo point
1851 behind which may be slightly odd from the user's point of view.
1856 if (_have_transaction) {
1861 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1865 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1870 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1873 // create a dummy marker for visual representation of moving the copy.
1874 // The actual copying is not done before we reach the finish callback.
1876 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1877 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1878 *new MeterSection (_marker->meter()));
1880 _item = &new_marker->the_item ();
1881 _marker = new_marker;
1885 MetricSection& section (_marker->meter());
1887 if (!section.movable()) {
1893 Drag::start_grab (event, cursor);
1895 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1897 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1901 MeterMarkerDrag::motion (GdkEvent* event, bool)
1903 nframes64_t const pf = adjusted_current_frame (event);
1905 _marker->set_position (pf);
1907 _editor->show_verbose_time_cursor (pf, 10);
1911 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1913 if (!movement_occurred) {
1917 motion (event, false);
1921 TempoMap& map (_editor->session()->tempo_map());
1922 map.bbt_time (last_pointer_frame(), when);
1924 if (_copy == true) {
1925 _editor->begin_reversible_command (_("copy meter mark"));
1926 XMLNode &before = map.get_state();
1927 map.add_meter (_marker->meter(), when);
1928 XMLNode &after = map.get_state();
1929 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1930 _editor->commit_reversible_command ();
1932 // delete the dummy marker we used for visual representation of copying.
1933 // a new visual marker will show up automatically.
1936 _editor->begin_reversible_command (_("move meter mark"));
1937 XMLNode &before = map.get_state();
1938 map.move_meter (_marker->meter(), when);
1939 XMLNode &after = map.get_state();
1940 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1941 _editor->commit_reversible_command ();
1946 MeterMarkerDrag::aborted ()
1948 _marker->set_position (_marker->meter().frame ());
1951 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1955 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1960 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1965 // create a dummy marker for visual representation of moving the copy.
1966 // The actual copying is not done before we reach the finish callback.
1968 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1969 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1970 *new TempoSection (_marker->tempo()));
1972 _item = &new_marker->the_item ();
1973 _marker = new_marker;
1977 MetricSection& section (_marker->tempo());
1979 if (!section.movable()) {
1984 Drag::start_grab (event, cursor);
1986 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
1987 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
1991 TempoMarkerDrag::motion (GdkEvent* event, bool)
1993 nframes64_t const pf = adjusted_current_frame (event);
1994 _marker->set_position (pf);
1995 _editor->show_verbose_time_cursor (pf, 10);
1999 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2001 if (!movement_occurred) {
2005 motion (event, false);
2009 TempoMap& map (_editor->session()->tempo_map());
2010 map.bbt_time (last_pointer_frame(), when);
2012 if (_copy == true) {
2013 _editor->begin_reversible_command (_("copy tempo mark"));
2014 XMLNode &before = map.get_state();
2015 map.add_tempo (_marker->tempo(), when);
2016 XMLNode &after = map.get_state();
2017 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2018 _editor->commit_reversible_command ();
2020 // delete the dummy marker we used for visual representation of copying.
2021 // a new visual marker will show up automatically.
2024 _editor->begin_reversible_command (_("move tempo mark"));
2025 XMLNode &before = map.get_state();
2026 map.move_tempo (_marker->tempo(), when);
2027 XMLNode &after = map.get_state();
2028 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2029 _editor->commit_reversible_command ();
2034 TempoMarkerDrag::aborted ()
2036 _marker->set_position (_marker->tempo().frame());
2039 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2043 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2048 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2050 Drag::start_grab (event, c);
2054 nframes64_t where = _editor->event_frame (event, 0, 0);
2056 _editor->snap_to_with_modifier (where, event);
2057 _editor->playhead_cursor->set_position (where);
2061 if (_cursor == _editor->playhead_cursor) {
2062 _editor->_dragging_playhead = true;
2064 if (_editor->session() && _was_rolling && _stop) {
2065 _editor->session()->request_stop ();
2068 if (_editor->session() && _editor->session()->is_auditioning()) {
2069 _editor->session()->cancel_audition ();
2073 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2075 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2079 CursorDrag::motion (GdkEvent* event, bool)
2081 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2083 if (adjusted_frame == last_pointer_frame()) {
2087 _cursor->set_position (adjusted_frame);
2089 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2092 _editor->update_canvas_now ();
2094 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2098 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2100 _editor->_dragging_playhead = false;
2102 if (!movement_occurred && _stop) {
2106 motion (event, false);
2108 if (_item == &_editor->playhead_cursor->canvas_item) {
2109 if (_editor->session()) {
2110 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2111 _editor->_pending_locate_request = true;
2117 CursorDrag::aborted ()
2119 _editor->_dragging_playhead = false;
2120 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2123 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2124 : RegionDrag (e, i, p, v)
2130 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2132 Drag::start_grab (event, cursor);
2134 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2135 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2137 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2138 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2142 FadeInDrag::motion (GdkEvent* event, bool)
2144 nframes64_t fade_length;
2146 nframes64_t const pos = adjusted_current_frame (event);
2148 boost::shared_ptr<Region> region = _primary->region ();
2150 if (pos < (region->position() + 64)) {
2151 fade_length = 64; // this should be a minimum defined somewhere
2152 } else if (pos > region->last_frame()) {
2153 fade_length = region->length();
2155 fade_length = pos - region->position();
2158 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2160 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2166 tmp->reset_fade_in_shape_width (fade_length);
2169 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2173 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2175 if (!movement_occurred) {
2179 nframes64_t fade_length;
2181 nframes64_t const pos = adjusted_current_frame (event);
2183 boost::shared_ptr<Region> region = _primary->region ();
2185 if (pos < (region->position() + 64)) {
2186 fade_length = 64; // this should be a minimum defined somewhere
2187 } else if (pos > region->last_frame()) {
2188 fade_length = region->length();
2190 fade_length = pos - region->position();
2193 _editor->begin_reversible_command (_("change fade in length"));
2195 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2197 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2203 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2204 XMLNode &before = alist->get_state();
2206 tmp->audio_region()->set_fade_in_length (fade_length);
2207 tmp->audio_region()->set_fade_in_active (true);
2209 XMLNode &after = alist->get_state();
2210 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2213 _editor->commit_reversible_command ();
2217 FadeInDrag::aborted ()
2219 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2220 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2226 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2230 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2231 : RegionDrag (e, i, p, v)
2237 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2239 Drag::start_grab (event, cursor);
2241 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2242 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2244 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2245 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2249 FadeOutDrag::motion (GdkEvent* event, bool)
2251 nframes64_t fade_length;
2253 nframes64_t const pos = adjusted_current_frame (event);
2255 boost::shared_ptr<Region> region = _primary->region ();
2257 if (pos > (region->last_frame() - 64)) {
2258 fade_length = 64; // this should really be a minimum fade defined somewhere
2260 else if (pos < region->position()) {
2261 fade_length = region->length();
2264 fade_length = region->last_frame() - pos;
2267 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2269 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2275 tmp->reset_fade_out_shape_width (fade_length);
2278 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2282 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2284 if (!movement_occurred) {
2288 nframes64_t fade_length;
2290 nframes64_t const pos = adjusted_current_frame (event);
2292 boost::shared_ptr<Region> region = _primary->region ();
2294 if (pos > (region->last_frame() - 64)) {
2295 fade_length = 64; // this should really be a minimum fade defined somewhere
2297 else if (pos < region->position()) {
2298 fade_length = region->length();
2301 fade_length = region->last_frame() - pos;
2304 _editor->begin_reversible_command (_("change fade out length"));
2306 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2308 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2314 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2315 XMLNode &before = alist->get_state();
2317 tmp->audio_region()->set_fade_out_length (fade_length);
2318 tmp->audio_region()->set_fade_out_active (true);
2320 XMLNode &after = alist->get_state();
2321 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2324 _editor->commit_reversible_command ();
2328 FadeOutDrag::aborted ()
2330 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2331 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2337 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2341 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2344 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2347 _points.push_back (Gnome::Art::Point (0, 0));
2348 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2350 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2351 _line->property_width_pixels() = 1;
2352 _line->property_points () = _points;
2355 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2358 MarkerDrag::~MarkerDrag ()
2360 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2366 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2368 Drag::start_grab (event, cursor);
2372 Location *location = _editor->find_location_from_marker (_marker, is_start);
2373 _editor->_dragging_edit_point = true;
2375 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2377 update_item (location);
2379 // _drag_line->show();
2380 // _line->raise_to_top();
2383 _editor->show_verbose_time_cursor (location->start(), 10);
2385 _editor->show_verbose_time_cursor (location->end(), 10);
2388 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2391 case Selection::Toggle:
2392 _editor->selection->toggle (_marker);
2394 case Selection::Set:
2395 if (!_editor->selection->selected (_marker)) {
2396 _editor->selection->set (_marker);
2399 case Selection::Extend:
2401 Locations::LocationList ll;
2402 list<Marker*> to_add;
2404 _editor->selection->markers.range (s, e);
2405 s = min (_marker->position(), s);
2406 e = max (_marker->position(), e);
2409 if (e < max_frames) {
2412 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2413 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2414 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2417 to_add.push_back (lm->start);
2420 to_add.push_back (lm->end);
2424 if (!to_add.empty()) {
2425 _editor->selection->add (to_add);
2429 case Selection::Add:
2430 _editor->selection->add (_marker);
2434 /* set up copies for us to manipulate during the drag */
2436 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2437 Location *l = _editor->find_location_from_marker (*i, is_start);
2438 _copied_locations.push_back (new Location (*l));
2443 MarkerDrag::motion (GdkEvent* event, bool)
2445 nframes64_t f_delta = 0;
2447 bool move_both = false;
2449 Location *real_location;
2450 Location *copy_location = 0;
2452 nframes64_t const newframe = adjusted_current_frame (event);
2454 nframes64_t next = newframe;
2456 if (newframe == last_pointer_frame()) {
2460 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2464 MarkerSelection::iterator i;
2465 list<Location*>::iterator x;
2467 /* find the marker we're dragging, and compute the delta */
2469 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2470 x != _copied_locations.end() && i != _editor->selection->markers.end();
2476 if (marker == _marker) {
2478 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2483 if (real_location->is_mark()) {
2484 f_delta = newframe - copy_location->start();
2488 switch (marker->type()) {
2490 case Marker::LoopStart:
2491 case Marker::PunchIn:
2492 f_delta = newframe - copy_location->start();
2496 case Marker::LoopEnd:
2497 case Marker::PunchOut:
2498 f_delta = newframe - copy_location->end();
2501 /* what kind of marker is this ? */
2509 if (i == _editor->selection->markers.end()) {
2510 /* hmm, impossible - we didn't find the dragged marker */
2514 /* now move them all */
2516 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2517 x != _copied_locations.end() && i != _editor->selection->markers.end();
2523 /* call this to find out if its the start or end */
2525 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2529 if (real_location->locked()) {
2533 if (copy_location->is_mark()) {
2537 copy_location->set_start (copy_location->start() + f_delta);
2541 nframes64_t new_start = copy_location->start() + f_delta;
2542 nframes64_t new_end = copy_location->end() + f_delta;
2544 if (is_start) { // start-of-range marker
2547 copy_location->set_start (new_start);
2548 copy_location->set_end (new_end);
2549 } else if (new_start < copy_location->end()) {
2550 copy_location->set_start (new_start);
2552 _editor->snap_to (next, 1, true);
2553 copy_location->set_end (next);
2554 copy_location->set_start (newframe);
2557 } else { // end marker
2560 copy_location->set_end (new_end);
2561 copy_location->set_start (new_start);
2562 } else if (new_end > copy_location->start()) {
2563 copy_location->set_end (new_end);
2564 } else if (newframe > 0) {
2565 _editor->snap_to (next, -1, true);
2566 copy_location->set_start (next);
2567 copy_location->set_end (newframe);
2572 update_item (copy_location);
2574 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2577 lm->set_position (copy_location->start(), copy_location->end());
2581 assert (!_copied_locations.empty());
2583 _editor->show_verbose_time_cursor (newframe, 10);
2586 _editor->update_canvas_now ();
2591 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2593 if (!movement_occurred) {
2595 /* just a click, do nothing but finish
2596 off the selection process
2599 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2602 case Selection::Set:
2603 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2604 _editor->selection->set (_marker);
2608 case Selection::Toggle:
2609 case Selection::Extend:
2610 case Selection::Add:
2617 _editor->_dragging_edit_point = false;
2619 _editor->begin_reversible_command ( _("move marker") );
2620 XMLNode &before = _editor->session()->locations()->get_state();
2622 MarkerSelection::iterator i;
2623 list<Location*>::iterator x;
2626 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2627 x != _copied_locations.end() && i != _editor->selection->markers.end();
2630 Location * location = _editor->find_location_from_marker (*i, is_start);
2634 if (location->locked()) {
2638 if (location->is_mark()) {
2639 location->set_start ((*x)->start());
2641 location->set ((*x)->start(), (*x)->end());
2646 XMLNode &after = _editor->session()->locations()->get_state();
2647 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2648 _editor->commit_reversible_command ();
2654 MarkerDrag::aborted ()
2660 MarkerDrag::update_item (Location* location)
2662 double const x1 = _editor->frame_to_pixel (location->start());
2664 _points.front().set_x(x1);
2665 _points.back().set_x(x1);
2666 _line->property_points() = _points;
2669 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2671 _cumulative_x_drag (0),
2672 _cumulative_y_drag (0)
2674 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2680 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2682 Drag::start_grab (event, _editor->fader_cursor);
2684 // start the grab at the center of the control point so
2685 // the point doesn't 'jump' to the mouse after the first drag
2686 _time_axis_view_grab_x = _point->get_x();
2687 _time_axis_view_grab_y = _point->get_y();
2689 float const fraction = 1 - (_point->get_y() / _point->line().height());
2691 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2693 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2694 event->button.x + 10, event->button.y + 10);
2696 _editor->show_verbose_canvas_cursor ();
2700 ControlPointDrag::motion (GdkEvent* event, bool)
2702 double dx = _drags->current_pointer_x() - last_pointer_x();
2703 double dy = _drags->current_pointer_y() - last_pointer_y();
2705 if (event->button.state & Keyboard::SecondaryModifier) {
2710 /* coordinate in TimeAxisView's space */
2711 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2712 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2714 // calculate zero crossing point. back off by .01 to stay on the
2715 // positive side of zero
2716 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2718 // make sure we hit zero when passing through
2719 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2723 if (_x_constrained) {
2724 cx = _time_axis_view_grab_x;
2726 if (_y_constrained) {
2727 cy = _time_axis_view_grab_y;
2730 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2731 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2735 cy = min ((double) _point->line().height(), cy);
2737 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2739 if (!_x_constrained) {
2740 _editor->snap_to_with_modifier (cx_frames, event);
2743 float const fraction = 1.0 - (cy / _point->line().height());
2745 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2747 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2749 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2753 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2755 if (!movement_occurred) {
2759 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2760 _editor->reset_point_selection ();
2764 motion (event, false);
2766 _point->line().end_drag ();
2770 ControlPointDrag::aborted ()
2772 _point->line().reset ();
2776 ControlPointDrag::active (Editing::MouseMode m)
2778 if (m == Editing::MouseGain) {
2779 /* always active in mouse gain */
2783 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2784 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2787 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2790 _cumulative_y_drag (0)
2795 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2797 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2800 _item = &_line->grab_item ();
2802 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2803 origin, and ditto for y.
2806 double cx = event->button.x;
2807 double cy = event->button.y;
2809 _line->parent_group().w2i (cx, cy);
2811 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2816 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2817 /* no adjacent points */
2821 Drag::start_grab (event, _editor->fader_cursor);
2823 /* store grab start in parent frame */
2825 _time_axis_view_grab_x = cx;
2826 _time_axis_view_grab_y = cy;
2828 double fraction = 1.0 - (cy / _line->height());
2830 _line->start_drag_line (before, after, fraction);
2832 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2833 event->button.x + 10, event->button.y + 10);
2835 _editor->show_verbose_canvas_cursor ();
2839 LineDrag::motion (GdkEvent* event, bool)
2841 double dy = _drags->current_pointer_y() - last_pointer_y();
2843 if (event->button.state & Keyboard::SecondaryModifier) {
2847 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2849 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2852 cy = min ((double) _line->height(), cy);
2854 double const fraction = 1.0 - (cy / _line->height());
2858 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2864 /* we are ignoring x position for this drag, so we can just pass in anything */
2865 _line->drag_motion (0, fraction, true, push);
2867 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2871 LineDrag::finished (GdkEvent* event, bool)
2873 motion (event, false);
2878 LineDrag::aborted ()
2884 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2886 Drag::start_grab (event);
2887 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2891 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2898 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2900 nframes64_t grab = grab_frame ();
2901 if (Config->get_rubberbanding_snaps_to_grid ()) {
2902 _editor->snap_to_with_modifier (grab, event);
2905 /* base start and end on initial click position */
2915 if (_drags->current_pointer_y() < grab_y()) {
2916 y1 = _drags->current_pointer_y();
2919 y2 = _drags->current_pointer_y();
2924 if (start != end || y1 != y2) {
2926 double x1 = _editor->frame_to_pixel (start);
2927 double x2 = _editor->frame_to_pixel (end);
2929 _editor->rubberband_rect->property_x1() = x1;
2930 _editor->rubberband_rect->property_y1() = y1;
2931 _editor->rubberband_rect->property_x2() = x2;
2932 _editor->rubberband_rect->property_y2() = y2;
2934 _editor->rubberband_rect->show();
2935 _editor->rubberband_rect->raise_to_top();
2937 _editor->show_verbose_time_cursor (pf, 10);
2942 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2944 if (movement_occurred) {
2946 motion (event, false);
2949 if (_drags->current_pointer_y() < grab_y()) {
2950 y1 = _drags->current_pointer_y();
2953 y2 = _drags->current_pointer_y();
2958 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2961 _editor->begin_reversible_command (_("rubberband selection"));
2963 if (grab_frame() < last_pointer_frame()) {
2964 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
2966 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
2970 _editor->commit_reversible_command ();
2974 if (!getenv("ARDOUR_SAE")) {
2975 _editor->selection->clear_tracks();
2977 _editor->selection->clear_regions();
2978 _editor->selection->clear_points ();
2979 _editor->selection->clear_lines ();
2982 _editor->rubberband_rect->hide();
2986 RubberbandSelectDrag::aborted ()
2988 _editor->rubberband_rect->hide ();
2992 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2994 Drag::start_grab (event);
2996 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3000 TimeFXDrag::motion (GdkEvent* event, bool)
3002 RegionView* rv = _primary;
3004 nframes64_t const pf = adjusted_current_frame (event);
3006 if (pf > rv->region()->position()) {
3007 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3010 _editor->show_verbose_time_cursor (pf, 10);
3014 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3016 _primary->get_time_axis_view().hide_timestretch ();
3018 if (!movement_occurred) {
3022 if (last_pointer_frame() < _primary->region()->position()) {
3023 /* backwards drag of the left edge - not usable */
3027 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3029 float percentage = (double) newlen / (double) _primary->region()->length();
3031 #ifndef USE_RUBBERBAND
3032 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3033 if (_primary->region()->data_type() == DataType::AUDIO) {
3034 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3038 _editor->begin_reversible_command (_("timestretch"));
3040 // XXX how do timeFX on multiple regions ?
3045 if (!_editor->time_stretch (rs, percentage) == 0) {
3046 error << _("An error occurred while executing time stretch operation") << endmsg;
3051 TimeFXDrag::aborted ()
3053 _primary->get_time_axis_view().hide_timestretch ();
3058 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3060 Drag::start_grab (event);
3064 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3066 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3070 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3072 if (movement_occurred && _editor->session()) {
3073 /* make sure we stop */
3074 _editor->session()->request_transport_speed (0.0);
3079 ScrubDrag::aborted ()
3084 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3088 , _original_pointer_time_axis (-1)
3089 , _last_pointer_time_axis (-1)
3095 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3097 nframes64_t start = 0;
3098 nframes64_t end = 0;
3100 if (_editor->session() == 0) {
3104 Gdk::Cursor* cursor = 0;
3106 switch (_operation) {
3107 case CreateSelection:
3108 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3113 cursor = _editor->selector_cursor;
3114 Drag::start_grab (event, cursor);
3117 case SelectionStartTrim:
3118 if (_editor->clicked_axisview) {
3119 _editor->clicked_axisview->order_selection_trims (_item, true);
3121 Drag::start_grab (event, _editor->trimmer_cursor);
3122 start = _editor->selection->time[_editor->clicked_selection].start;
3123 _pointer_frame_offset = grab_frame() - start;
3126 case SelectionEndTrim:
3127 if (_editor->clicked_axisview) {
3128 _editor->clicked_axisview->order_selection_trims (_item, false);
3130 Drag::start_grab (event, _editor->trimmer_cursor);
3131 end = _editor->selection->time[_editor->clicked_selection].end;
3132 _pointer_frame_offset = grab_frame() - end;
3136 start = _editor->selection->time[_editor->clicked_selection].start;
3137 Drag::start_grab (event, cursor);
3138 _pointer_frame_offset = grab_frame() - start;
3142 if (_operation == SelectionMove) {
3143 _editor->show_verbose_time_cursor (start, 10);
3145 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3148 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3152 SelectionDrag::motion (GdkEvent* event, bool first_move)
3154 nframes64_t start = 0;
3155 nframes64_t end = 0;
3158 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3159 if (pending_time_axis.first == 0) {
3163 nframes64_t const pending_position = adjusted_current_frame (event);
3165 /* only alter selection if things have changed */
3167 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3171 switch (_operation) {
3172 case CreateSelection:
3174 nframes64_t grab = grab_frame ();
3177 _editor->snap_to (grab);
3180 if (pending_position < grab_frame()) {
3181 start = pending_position;
3184 end = pending_position;
3188 /* first drag: Either add to the selection
3189 or create a new selection
3195 /* adding to the selection */
3196 _editor->selection->add (_editor->clicked_axisview);
3197 _editor->clicked_selection = _editor->selection->add (start, end);
3202 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3203 _editor->selection->set (_editor->clicked_axisview);
3206 _editor->clicked_selection = _editor->selection->set (start, end);
3210 /* select the track that we're in */
3211 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3212 _editor->selection->add (pending_time_axis.first);
3213 _added_time_axes.push_back (pending_time_axis.first);
3216 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3217 tracks that we selected in the first place.
3220 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3221 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3223 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3224 while (i != _added_time_axes.end()) {
3226 list<TimeAxisView*>::iterator tmp = i;
3229 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3230 _editor->selection->remove (*i);
3231 _added_time_axes.remove (*i);
3240 case SelectionStartTrim:
3242 start = _editor->selection->time[_editor->clicked_selection].start;
3243 end = _editor->selection->time[_editor->clicked_selection].end;
3245 if (pending_position > end) {
3248 start = pending_position;
3252 case SelectionEndTrim:
3254 start = _editor->selection->time[_editor->clicked_selection].start;
3255 end = _editor->selection->time[_editor->clicked_selection].end;
3257 if (pending_position < start) {
3260 end = pending_position;
3267 start = _editor->selection->time[_editor->clicked_selection].start;
3268 end = _editor->selection->time[_editor->clicked_selection].end;
3270 length = end - start;
3272 start = pending_position;
3273 _editor->snap_to (start);
3275 end = start + length;
3280 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3281 _editor->start_canvas_autoscroll (1, 0);
3285 _editor->selection->replace (_editor->clicked_selection, start, end);
3288 if (_operation == SelectionMove) {
3289 _editor->show_verbose_time_cursor(start, 10);
3291 _editor->show_verbose_time_cursor(pending_position, 10);
3296 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3298 Session* s = _editor->session();
3300 if (movement_occurred) {
3301 motion (event, false);
3302 /* XXX this is not object-oriented programming at all. ick */
3303 if (_editor->selection->time.consolidate()) {
3304 _editor->selection->TimeChanged ();
3307 /* XXX what if its a music time selection? */
3308 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3309 s->request_play_range (&_editor->selection->time, true);
3314 /* just a click, no pointer movement.*/
3316 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3317 _editor->selection->clear_time();
3320 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3321 _editor->selection->set (_editor->clicked_axisview);
3324 if (s && s->get_play_range () && s->transport_rolling()) {
3325 s->request_stop (false, false);
3330 _editor->stop_canvas_autoscroll ();
3334 SelectionDrag::aborted ()
3339 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3344 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3345 _drag_rect->hide ();
3347 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3348 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3352 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3354 if (_editor->session() == 0) {
3358 Gdk::Cursor* cursor = 0;
3360 if (!_editor->temp_location) {
3361 _editor->temp_location = new Location;
3364 switch (_operation) {
3365 case CreateRangeMarker:
3366 case CreateTransportMarker:
3367 case CreateCDMarker:
3369 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3374 cursor = _editor->selector_cursor;
3378 Drag::start_grab (event, cursor);
3380 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3384 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3386 nframes64_t start = 0;
3387 nframes64_t end = 0;
3388 ArdourCanvas::SimpleRect *crect;
3390 switch (_operation) {
3391 case CreateRangeMarker:
3392 crect = _editor->range_bar_drag_rect;
3394 case CreateTransportMarker:
3395 crect = _editor->transport_bar_drag_rect;
3397 case CreateCDMarker:
3398 crect = _editor->cd_marker_bar_drag_rect;
3401 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3406 nframes64_t const pf = adjusted_current_frame (event);
3408 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3409 nframes64_t grab = grab_frame ();
3410 _editor->snap_to (grab);
3412 if (pf < grab_frame()) {
3420 /* first drag: Either add to the selection
3421 or create a new selection.
3426 _editor->temp_location->set (start, end);
3430 update_item (_editor->temp_location);
3432 //_drag_rect->raise_to_top();
3437 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3438 _editor->start_canvas_autoscroll (1, 0);
3442 _editor->temp_location->set (start, end);
3444 double x1 = _editor->frame_to_pixel (start);
3445 double x2 = _editor->frame_to_pixel (end);
3446 crect->property_x1() = x1;
3447 crect->property_x2() = x2;
3449 update_item (_editor->temp_location);
3452 _editor->show_verbose_time_cursor (pf, 10);
3457 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3459 Location * newloc = 0;
3463 if (movement_occurred) {
3464 motion (event, false);
3467 switch (_operation) {
3468 case CreateRangeMarker:
3469 case CreateCDMarker:
3471 _editor->begin_reversible_command (_("new range marker"));
3472 XMLNode &before = _editor->session()->locations()->get_state();
3473 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3474 if (_operation == CreateCDMarker) {
3475 flags = Location::IsRangeMarker | Location::IsCDMarker;
3476 _editor->cd_marker_bar_drag_rect->hide();
3479 flags = Location::IsRangeMarker;
3480 _editor->range_bar_drag_rect->hide();
3482 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3483 _editor->session()->locations()->add (newloc, true);
3484 XMLNode &after = _editor->session()->locations()->get_state();
3485 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3486 _editor->commit_reversible_command ();
3490 case CreateTransportMarker:
3491 // popup menu to pick loop or punch
3492 _editor->new_transport_marker_context_menu (&event->button, _item);
3496 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3498 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3503 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3505 if (end == max_frames) {
3506 end = _editor->session()->current_end_frame ();
3509 if (start == max_frames) {
3510 start = _editor->session()->current_start_frame ();
3513 switch (_editor->mouse_mode) {
3515 /* find the two markers on either side and then make the selection from it */
3516 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3520 /* find the two markers on either side of the click and make the range out of it */
3521 _editor->selection->set (start, end);
3530 _editor->stop_canvas_autoscroll ();
3534 RangeMarkerBarDrag::aborted ()
3540 RangeMarkerBarDrag::update_item (Location* location)
3542 double const x1 = _editor->frame_to_pixel (location->start());
3543 double const x2 = _editor->frame_to_pixel (location->end());
3545 _drag_rect->property_x1() = x1;
3546 _drag_rect->property_x2() = x2;
3550 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3552 Drag::start_grab (event, _editor->zoom_cursor);
3553 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3557 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3562 nframes64_t const pf = adjusted_current_frame (event);
3564 nframes64_t grab = grab_frame ();
3565 _editor->snap_to_with_modifier (grab, event);
3567 /* base start and end on initial click position */
3579 _editor->zoom_rect->show();
3580 _editor->zoom_rect->raise_to_top();
3583 _editor->reposition_zoom_rect(start, end);
3585 _editor->show_verbose_time_cursor (pf, 10);
3590 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3592 if (movement_occurred) {
3593 motion (event, false);
3595 if (grab_frame() < last_pointer_frame()) {
3596 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3598 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3601 _editor->temporal_zoom_to_frame (false, grab_frame());
3603 temporal_zoom_step (false);
3604 center_screen (grab_frame());
3608 _editor->zoom_rect->hide();
3612 MouseZoomDrag::aborted ()
3614 _editor->zoom_rect->hide ();
3617 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3620 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3621 region = &cnote->region_view();
3625 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3627 Drag::start_grab (event);
3630 drag_delta_note = 0;
3635 event_x = _drags->current_pointer_x();
3636 event_y = _drags->current_pointer_y();
3638 _item->property_parent().get_value()->w2i(event_x, event_y);
3640 last_x = region->snap_to_pixel(event_x);
3643 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3645 if (!(was_selected = cnote->selected())) {
3647 /* tertiary-click means extend selection - we'll do that on button release,
3648 so don't add it here, because otherwise we make it hard to figure
3649 out the "extend-to" range.
3652 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3655 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3658 region->note_selected (cnote, true);
3660 region->unique_select (cnote);
3667 NoteDrag::motion (GdkEvent*, bool)
3669 MidiStreamView* streamview = region->midi_stream_view();
3673 event_x = _drags->current_pointer_x();
3674 event_y = _drags->current_pointer_y();
3676 _item->property_parent().get_value()->w2i(event_x, event_y);
3678 event_x = region->snap_to_pixel(event_x);
3680 double dx = event_x - last_x;
3681 double dy = event_y - last_y;
3686 // Snap to note rows
3688 if (abs (dy) < streamview->note_height()) {
3691 int8_t this_delta_note;
3693 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3695 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3697 drag_delta_note -= this_delta_note;
3698 dy = streamview->note_height() * this_delta_note;
3699 last_y = last_y + dy;
3703 region->move_selection (dx, dy);
3705 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3707 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3708 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3709 _editor->show_verbose_canvas_cursor_with (buf);
3714 NoteDrag::finished (GdkEvent* ev, bool moved)
3716 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3719 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3722 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3724 region->note_deselected (cnote);
3727 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3728 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3730 if (!extend && !add && region->selection_size() > 1) {
3731 region->unique_select(cnote);
3732 } else if (extend) {
3733 region->note_selected (cnote, true, true);
3735 /* it was added during button press */
3740 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3745 NoteDrag::aborted ()
3750 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3753 , _nothing_to_drag (false)
3755 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3758 _line = _atav->line ();
3762 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3764 Drag::start_grab (event, cursor);
3766 list<ControlPoint*> points;
3768 XMLNode* state = &_line->get_state ();
3770 if (_ranges.empty()) {
3772 uint32_t const N = _line->npoints ();
3773 for (uint32_t i = 0; i < N; ++i) {
3774 points.push_back (_line->nth (i));
3779 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3780 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3782 /* fade into and out of the region that we're dragging;
3783 64 samples length plucked out of thin air.
3785 nframes64_t const h = (j->start + j->end) / 2;
3786 nframes64_t a = j->start + 64;
3790 nframes64_t b = j->end - 64;
3795 the_list->add (j->start, the_list->eval (j->start));
3796 _line->add_always_in_view (j->start);
3797 the_list->add (a, the_list->eval (a));
3798 _line->add_always_in_view (a);
3799 the_list->add (b, the_list->eval (b));
3800 _line->add_always_in_view (b);
3801 the_list->add (j->end, the_list->eval (j->end));
3802 _line->add_always_in_view (j->end);
3805 uint32_t const N = _line->npoints ();
3806 for (uint32_t i = 0; i < N; ++i) {
3808 ControlPoint* p = _line->nth (i);
3810 list<AudioRange>::const_iterator j = _ranges.begin ();
3811 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3815 if (j != _ranges.end()) {
3816 points.push_back (p);
3821 if (points.empty()) {
3822 _nothing_to_drag = true;
3826 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3830 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3832 if (_nothing_to_drag) {
3836 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3838 /* we are ignoring x position for this drag, so we can just pass in anything */
3839 _line->drag_motion (0, f, true, false);
3843 AutomationRangeDrag::finished (GdkEvent* event, bool)
3845 if (_nothing_to_drag) {
3849 motion (event, false);
3851 _line->clear_always_in_view ();
3855 AutomationRangeDrag::aborted ()
3857 _line->clear_always_in_view ();