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/session.h"
27 #include "ardour/dB.h"
28 #include "ardour/region_factory.h"
29 #include "ardour/midi_diskstream.h"
33 #include "audio_region_view.h"
34 #include "midi_region_view.h"
35 #include "ardour_ui.h"
36 #include "gui_thread.h"
37 #include "control_point.h"
39 #include "region_gain_line.h"
40 #include "editor_drag.h"
41 #include "audio_time_axis.h"
42 #include "midi_time_axis.h"
43 #include "canvas-note.h"
44 #include "selection.h"
45 #include "midi_selection.h"
46 #include "automation_time_axis.h"
49 using namespace ARDOUR;
52 using namespace Editing;
53 using namespace ArdourCanvas;
55 using Gtkmm2ext::Keyboard;
57 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
59 DragManager::DragManager (Editor* e)
62 , _current_pointer_frame (0)
67 DragManager::~DragManager ()
75 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
84 DragManager::break_drag ()
88 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
99 DragManager::add (Drag* d)
101 d->set_manager (this);
102 _drags.push_back (d);
106 DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
108 assert (_drags.empty ());
109 d->set_manager (this);
110 _drags.push_back (d);
115 DragManager::start_grab (GdkEvent* e)
117 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
119 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
120 (*i)->start_grab (e);
125 DragManager::end_grab (GdkEvent* e)
130 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
131 bool const t = (*i)->end_grab (e);
146 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
150 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
152 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
153 bool const t = (*i)->motion_handler (e, from_autoscroll);
164 DragManager::have_item (ArdourCanvas::Item* i) const
166 list<Drag*>::const_iterator j = _drags.begin ();
167 while (j != _drags.end() && (*j)->item () != i) {
171 return j != _drags.end ();
174 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
177 , _pointer_frame_offset (0)
178 , _move_threshold_passed (false)
180 , _last_pointer_frame (0)
186 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
192 cursor = _editor->which_grabber_cursor ();
195 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
199 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
202 cursor = _editor->which_grabber_cursor ();
205 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
207 if (Keyboard::is_button2_event (&event->button)) {
208 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
209 _y_constrained = true;
210 _x_constrained = false;
212 _y_constrained = false;
213 _x_constrained = true;
216 _x_constrained = false;
217 _y_constrained = false;
220 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
221 _grab_frame = adjusted_frame (_grab_frame, event);
222 _last_pointer_frame = _grab_frame;
223 _last_pointer_x = _grab_x;
224 _last_pointer_y = _grab_y;
226 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
230 if (_editor->session() && _editor->session()->transport_rolling()) {
233 _was_rolling = false;
236 switch (_editor->snap_type()) {
237 case SnapToRegionStart:
238 case SnapToRegionEnd:
239 case SnapToRegionSync:
240 case SnapToRegionBoundary:
241 _editor->build_region_boundary_cache ();
248 /** @param event GDK event, or 0.
249 * @return true if some movement occurred, otherwise false.
252 Drag::end_grab (GdkEvent* event)
254 _editor->stop_canvas_autoscroll ();
256 _item->ungrab (event ? event->button.time : 0);
258 finished (event, _move_threshold_passed);
260 _editor->hide_verbose_canvas_cursor();
262 return _move_threshold_passed;
266 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
270 if (f > _pointer_frame_offset) {
271 pos = f - _pointer_frame_offset;
275 _editor->snap_to_with_modifier (pos, event);
282 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
284 return adjusted_frame (_drags->current_pointer_frame (), event, snap);
288 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
290 /* check to see if we have moved in any way that matters since the last motion event */
291 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
292 (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
296 pair<nframes64_t, int> const threshold = move_threshold ();
298 bool const old_move_threshold_passed = _move_threshold_passed;
300 if (!from_autoscroll && !_move_threshold_passed) {
302 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
303 bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
305 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
308 if (active (_editor->mouse_mode) && _move_threshold_passed) {
310 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
311 if (!from_autoscroll) {
312 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
315 motion (event, _move_threshold_passed != old_move_threshold_passed);
317 _last_pointer_x = _drags->current_pointer_x ();
318 _last_pointer_y = _drags->current_pointer_y ();
319 _last_pointer_frame = adjusted_current_frame (event);
337 _editor->stop_canvas_autoscroll ();
338 _editor->hide_verbose_canvas_cursor ();
341 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
346 RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
350 RegionDrag::region_going_away (RegionView* v)
355 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
356 : RegionDrag (e, i, p, v),
367 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
369 Drag::start_grab (event);
371 _editor->show_verbose_time_cursor (_last_frame_position, 10);
374 RegionMotionDrag::TimeAxisViewSummary
375 RegionMotionDrag::get_time_axis_view_summary ()
377 int32_t children = 0;
378 TimeAxisViewSummary sum;
380 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
382 /* get a bitmask representing the visible tracks */
384 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
385 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
386 TimeAxisView::Children children_list;
388 /* zeroes are audio/MIDI tracks. ones are other types. */
390 if (!rtv->hidden()) {
392 if (!rtv->is_track()) {
393 /* not an audio nor MIDI track */
394 sum.tracks = sum.tracks |= (0x01 << rtv->order());
397 sum.height_list[rtv->order()] = (*i)->current_height();
400 if ((children_list = rtv->get_child_list()).size() > 0) {
401 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
402 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
403 sum.height_list[rtv->order() + children] = (*j)->current_height();
414 RegionMotionDrag::compute_y_delta (
415 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
416 int32_t last_pointer_layer, int32_t current_pointer_layer,
417 TimeAxisViewSummary const & tavs,
418 int32_t* pointer_order_span, int32_t* pointer_layer_span,
419 int32_t* canvas_pointer_order_span
423 *pointer_order_span = 0;
424 *pointer_layer_span = 0;
428 bool clamp_y_axis = false;
430 /* the change in track order between this callback and the last */
431 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
432 /* the change in layer between this callback and the last;
433 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
434 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
436 if (*pointer_order_span != 0) {
438 /* find the actual pointer span, in terms of the number of visible tracks;
439 to do this, we reduce |pointer_order_span| by the number of hidden tracks
442 *canvas_pointer_order_span = *pointer_order_span;
443 if (last_pointer_view->order() >= current_pointer_view->order()) {
444 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
445 if (tavs.height_list[y] == 0) {
446 *canvas_pointer_order_span--;
450 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
451 if (tavs.height_list[y] == 0) {
452 *canvas_pointer_order_span++;
457 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
459 RegionView* rv = (*i);
461 if (rv->region()->locked()) {
465 double ix1, ix2, iy1, iy2;
466 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
467 rv->get_canvas_frame()->i2w (ix1, iy1);
468 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
470 /* get the new trackview for this particular region */
471 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
473 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
475 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
476 as surely this is a per-region thing... */
478 clamp_y_axis = y_movement_disallowed (
479 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
487 } else if (_dest_trackview == current_pointer_view) {
489 if (current_pointer_layer == last_pointer_layer) {
490 /* No movement; clamp */
496 _dest_trackview = current_pointer_view;
497 _dest_layer = current_pointer_layer;
505 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
507 /* compute the amount of pointer motion in frames, and where
508 the region would be if we moved it by that much.
510 *pending_region_position = adjusted_current_frame (event);
512 nframes64_t sync_frame;
513 nframes64_t sync_offset;
516 sync_offset = _primary->region()->sync_offset (sync_dir);
518 /* we don't handle a sync point that lies before zero.
520 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
522 sync_frame = *pending_region_position + (sync_dir*sync_offset);
524 _editor->snap_to_with_modifier (sync_frame, event);
526 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
529 *pending_region_position = _last_frame_position;
532 if (*pending_region_position > max_frames - _primary->region()->length()) {
533 *pending_region_position = _last_frame_position;
538 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
540 /* now compute the canvas unit distance we need to move the regionview
541 to make it appear at the new location.
544 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
546 if (*pending_region_position <= _last_frame_position) {
548 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
550 RegionView* rv = (*i);
552 // If any regionview is at zero, we need to know so we can stop further leftward motion.
554 double ix1, ix2, iy1, iy2;
555 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
556 rv->get_canvas_frame()->i2w (ix1, iy1);
558 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
560 *pending_region_position = _last_frame_position;
567 _last_frame_position = *pending_region_position;
574 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
578 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
580 vector<int32_t>::iterator j;
582 /* *pointer* variables reflect things about the pointer; as we may be moving
583 multiple regions, much detail must be computed per-region */
585 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
586 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
587 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
588 is always 0 regardless of what the region's "real" layer is */
589 RouteTimeAxisView* current_pointer_view;
590 layer_t current_pointer_layer;
591 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
595 /* TimeAxisView that we were pointing at last time we entered this method */
596 TimeAxisView const * const last_pointer_view = _dest_trackview;
597 /* the order of the track that we were pointing at last time we entered this method */
598 int32_t const last_pointer_order = last_pointer_view->order ();
599 /* the layer that we were pointing at last time we entered this method */
600 layer_t const last_pointer_layer = _dest_layer;
602 int32_t pointer_order_span;
603 int32_t pointer_layer_span;
604 int32_t canvas_pointer_order_span;
606 bool const clamp_y_axis = compute_y_delta (
607 last_pointer_view, current_pointer_view,
608 last_pointer_layer, current_pointer_layer, tavs,
609 &pointer_order_span, &pointer_layer_span,
610 &canvas_pointer_order_span
613 nframes64_t pending_region_position;
614 double const x_delta = compute_x_delta (event, &pending_region_position);
616 /*************************************************************
618 ************************************************************/
620 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
621 /* haven't reached next snap point, and we're not switching
622 trackviews nor layers. nothing to do.
627 /*************************************************************
629 ************************************************************/
631 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
633 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
635 RegionView* rv = (*i);
637 if (rv->region()->locked()) {
641 /* here we are calculating the y distance from the
642 top of the first track view to the top of the region
643 area of the track view that we're working on */
645 /* this x value is just a dummy value so that we have something
650 /* distance from the top of this track view to the region area
651 of our track view is always 1 */
655 /* convert to world coordinates, ie distance from the top of
658 rv->get_canvas_frame()->i2w (ix1, iy1);
660 /* compensate for the ruler section and the vertical scrollbar position */
661 iy1 += _editor->get_trackview_group_vertical_offset ();
665 // hide any dependent views
667 rv->get_time_axis_view().hide_dependent_views (*rv);
670 reparent to a non scrolling group so that we can keep the
671 region selection above all time axis views.
672 reparenting means we have to move the rv as the two
673 parent groups have different coordinates.
676 rv->get_canvas_group()->property_y() = iy1 - 1;
677 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
679 rv->fake_set_opaque (true);
682 /* current view for this particular region */
683 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
684 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
686 if (pointer_order_span != 0 && !clamp_y_axis) {
688 /* INTER-TRACK MOVEMENT */
690 /* move through the height list to the track that the region is currently on */
691 vector<int32_t>::iterator j = tavs.height_list.begin ();
693 while (j != tavs.height_list.end () && x != rtv->order ()) {
699 int32_t temp_pointer_order_span = canvas_pointer_order_span;
701 if (j != tavs.height_list.end ()) {
703 /* Account for layers in the original and
704 destination tracks. If we're moving around in layers we assume
705 that only one track is involved, so it's ok to use *pointer*
708 StreamView* lv = last_pointer_view->view ();
711 /* move to the top of the last trackview */
712 if (lv->layer_display () == Stacked) {
713 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
716 StreamView* cv = current_pointer_view->view ();
719 /* move to the right layer on the current trackview */
720 if (cv->layer_display () == Stacked) {
721 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
724 /* And for being on a non-topmost layer on the new
727 while (temp_pointer_order_span > 0) {
728 /* we're moving up canvas-wise,
729 so we need to find the next track height
731 if (j != tavs.height_list.begin()) {
735 if (x != last_pointer_order) {
737 ++temp_pointer_order_span;
742 temp_pointer_order_span--;
745 while (temp_pointer_order_span < 0) {
749 if (x != last_pointer_order) {
751 --temp_pointer_order_span;
755 if (j != tavs.height_list.end()) {
759 temp_pointer_order_span++;
763 /* find out where we'll be when we move and set height accordingly */
765 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
766 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
767 rv->set_height (temp_rtv->view()->child_height());
769 /* if you un-comment the following, the region colours will follow
770 the track colours whilst dragging; personally
771 i think this can confuse things, but never mind.
774 //const GdkColor& col (temp_rtv->view->get_region_color());
775 //rv->set_color (const_cast<GdkColor&>(col));
779 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
781 /* INTER-LAYER MOVEMENT in the same track */
782 y_delta = rtv->view()->child_height () * pointer_layer_span;
787 _editor->mouse_brush_insert_region (rv, pending_region_position);
789 rv->move (x_delta, y_delta);
792 } /* foreach region */
794 _total_x_delta += x_delta;
797 _editor->cursor_group->raise_to_top();
800 if (x_delta != 0 && !_brushing) {
801 _editor->show_verbose_time_cursor (_last_frame_position, 10);
806 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
808 if (_copy && first_move) {
809 copy_regions (event);
812 RegionMotionDrag::motion (event, first_move);
816 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
818 vector<RegionView*> copies;
819 boost::shared_ptr<Diskstream> ds;
820 boost::shared_ptr<Playlist> from_playlist;
821 RegionSelection new_views;
822 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
823 PlaylistSet modified_playlists;
824 PlaylistSet frozen_playlists;
825 list <sigc::connection> modified_playlist_connections;
826 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
827 nframes64_t drag_delta;
828 bool changed_tracks, changed_position;
829 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
830 RouteTimeAxisView* source_tv;
832 if (!movement_occurred) {
838 /* all changes were made during motion event handlers */
841 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
842 copies.push_back (*i);
849 /* reverse this here so that we have the correct logic to finalize
853 if (Config->get_edit_mode() == Lock) {
854 _x_constrained = !_x_constrained;
858 if (_x_constrained) {
859 _editor->begin_reversible_command (_("fixed time region copy"));
861 _editor->begin_reversible_command (_("region copy"));
864 if (_x_constrained) {
865 _editor->begin_reversible_command (_("fixed time region drag"));
867 _editor->begin_reversible_command (_("region drag"));
871 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
872 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
874 drag_delta = _primary->region()->position() - _last_frame_position;
876 _editor->update_canvas_now ();
878 /* make a list of where each region ended up */
879 final = find_time_axis_views_and_layers ();
881 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
883 RegionView* rv = (*i);
884 RouteTimeAxisView* dest_rtv = final[*i].first;
885 layer_t dest_layer = final[*i].second;
889 if (rv->region()->locked()) {
894 if (changed_position && !_x_constrained) {
895 where = rv->region()->position() - drag_delta;
897 where = rv->region()->position();
900 boost::shared_ptr<Region> new_region;
903 /* we already made a copy */
904 new_region = rv->region();
906 /* undo the previous hide_dependent_views so that xfades don't
907 disappear on copying regions
910 //rv->get_time_axis_view().reveal_dependent_views (*rv);
912 } else if (changed_tracks && dest_rtv->playlist()) {
913 new_region = RegionFactory::create (rv->region());
916 if (changed_tracks || _copy) {
918 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
925 _editor->latest_regionviews.clear ();
927 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
929 insert_result = modified_playlists.insert (to_playlist);
931 if (insert_result.second) {
932 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
935 to_playlist->add_region (new_region, where);
936 if (dest_rtv->view()->layer_display() == Stacked) {
937 new_region->set_layer (dest_layer);
938 new_region->set_pending_explicit_relayer (true);
943 if (!_editor->latest_regionviews.empty()) {
944 // XXX why just the first one ? we only expect one
945 // commented out in nick_m's canvas reworking. is that intended?
946 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
947 new_views.push_back (_editor->latest_regionviews.front());
951 rv->region()->clear_history ();
954 motion on the same track. plonk the previously reparented region
955 back to its original canvas group (its streamview).
956 No need to do anything for copies as they are fake regions which will be deleted.
959 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
960 rv->get_canvas_group()->property_y() = 0;
961 rv->get_time_axis_view().reveal_dependent_views (*rv);
963 /* just change the model */
965 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
967 if (dest_rtv->view()->layer_display() == Stacked) {
968 rv->region()->set_layer (dest_layer);
969 rv->region()->set_pending_explicit_relayer (true);
972 /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
974 frozen_insert_result = frozen_playlists.insert(playlist);
976 if (frozen_insert_result.second) {
980 rv->region()->set_position (where, (void*) this);
982 _editor->session()->add_command (new StatefulDiffCommand (rv->region()));
985 if (changed_tracks && !_copy) {
987 /* get the playlist where this drag started. we can't use rv->region()->playlist()
988 because we may have copied the region and it has not been attached to a playlist.
991 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
992 ds = source_tv->get_diskstream();
993 from_playlist = ds->playlist();
997 assert (from_playlist);
999 /* moved to a different audio track, without copying */
1001 /* the region that used to be in the old playlist is not
1002 moved to the new one - we use a copy of it. as a result,
1003 any existing editor for the region should no longer be
1007 rv->hide_region_editor();
1008 rv->fake_set_opaque (false);
1010 /* remove the region from the old playlist */
1012 insert_result = modified_playlists.insert (from_playlist);
1014 if (insert_result.second) {
1015 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
1018 from_playlist->remove_region (rv->region());
1020 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1021 was selected in all of them, then removing it from a playlist will have removed all
1022 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1023 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1024 corresponding regionview, and the selection is now empty).
1026 this could have invalidated any and all iterators into the region selection.
1028 the heuristic we use here is: if the region selection is empty, break out of the loop
1029 here. if the region selection is not empty, then restart the loop because we know that
1030 we must have removed at least the region(view) we've just been working on as well as any
1031 that we processed on previous iterations.
1033 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1034 we can just iterate.
1037 if (_views.empty()) {
1048 copies.push_back (rv);
1052 if we've created new regions either by copying or moving
1053 to a new track, we want to replace the old selection with the new ones
1055 if (new_views.size() > 0) {
1056 _editor->selection->set (new_views);
1059 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1064 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
1065 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
1068 _editor->commit_reversible_command ();
1070 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1076 RegionMoveDrag::aborted ()
1080 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1087 RegionMotionDrag::aborted ();
1092 RegionMotionDrag::aborted ()
1094 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1095 TimeAxisView* tv = &(*i)->get_time_axis_view ();
1096 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1098 (*i)->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1099 (*i)->get_canvas_group()->property_y() = 0;
1100 (*i)->get_time_axis_view().reveal_dependent_views (**i);
1101 (*i)->fake_set_opaque (false);
1102 (*i)->move (-_total_x_delta, 0);
1103 (*i)->set_height (rtv->view()->child_height ());
1106 _editor->update_canvas_now ();
1111 RegionMotionDrag::x_move_allowed () const
1113 if (Config->get_edit_mode() == Lock) {
1114 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1115 return _x_constrained;
1118 return !_x_constrained;
1122 RegionMotionDrag::copy_regions (GdkEvent* event)
1124 /* duplicate the regionview(s) and region(s) */
1126 list<RegionView*> new_regionviews;
1128 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1130 RegionView* rv = (*i);
1131 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1132 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1134 const boost::shared_ptr<const Region> original = rv->region();
1135 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1139 boost::shared_ptr<AudioRegion> audioregion_copy
1140 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1141 nrv = new AudioRegionView (*arv, audioregion_copy);
1143 boost::shared_ptr<MidiRegion> midiregion_copy
1144 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1145 nrv = new MidiRegionView (*mrv, midiregion_copy);
1150 nrv->get_canvas_group()->show ();
1151 new_regionviews.push_back (nrv);
1153 /* swap _primary to the copy */
1155 if (rv == _primary) {
1159 /* ..and deselect the one we copied */
1161 rv->set_selected (false);
1164 if (new_regionviews.empty()) {
1168 /* reflect the fact that we are dragging the copies */
1170 _views = new_regionviews;
1172 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1175 sync the canvas to what we think is its current state
1176 without it, the canvas seems to
1177 "forget" to update properly after the upcoming reparent()
1178 ..only if the mouse is in rapid motion at the time of the grab.
1179 something to do with regionview creation taking so long?
1181 _editor->update_canvas_now();
1185 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1187 /* Which trackview is this ? */
1189 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1190 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1191 (*layer) = tvp.second;
1193 if (*tv && (*tv)->layer_display() == Overlaid) {
1197 /* The region motion is only processed if the pointer is over
1201 if (!(*tv) || !(*tv)->is_track()) {
1202 /* To make sure we hide the verbose canvas cursor when the mouse is
1203 not held over and audiotrack.
1205 _editor->hide_verbose_canvas_cursor ();
1212 /** @param new_order New track order.
1213 * @param old_order Old track order.
1214 * @param visible_y_low Lowest visible order.
1215 * @return true if y movement should not happen, otherwise false.
1218 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1220 if (new_order != old_order) {
1222 /* this isn't the pointer track */
1226 /* moving up the canvas */
1227 if ( (new_order - y_span) >= tavs.visible_y_low) {
1231 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1232 int32_t visible_tracks = 0;
1233 while (visible_tracks < y_span ) {
1235 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1236 /* passing through a hidden track */
1241 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1242 /* moving to a non-track; disallow */
1248 /* moving beyond the lowest visible track; disallow */
1252 } else if (y_span < 0) {
1254 /* moving down the canvas */
1255 if ((new_order - y_span) <= tavs.visible_y_high) {
1257 int32_t visible_tracks = 0;
1259 while (visible_tracks > y_span ) {
1262 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1263 /* passing through a hidden track */
1268 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1269 /* moving to a non-track; disallow */
1276 /* moving beyond the highest visible track; disallow */
1283 /* this is the pointer's track */
1285 if ((new_order - y_span) > tavs.visible_y_high) {
1286 /* we will overflow */
1288 } else if ((new_order - y_span) < tavs.visible_y_low) {
1289 /* we will overflow */
1298 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1299 : RegionMotionDrag (e, i, p, v, b),
1302 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1304 _dest_trackview = tv;
1305 if (tv->layer_display() == Overlaid) {
1308 _dest_layer = _primary->region()->layer ();
1312 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1313 if (rtv && rtv->is_track()) {
1314 speed = rtv->get_diskstream()->speed ();
1317 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1321 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1323 RegionMotionDrag::start_grab (event, c);
1325 _pointer_frame_offset = grab_frame() - _last_frame_position;
1328 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1329 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1331 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1332 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1334 _primary = v->view()->create_region_view (r, false, false);
1336 _primary->get_canvas_group()->show ();
1337 _primary->set_position (pos, 0);
1338 _views.push_back (_primary);
1340 _last_frame_position = pos;
1342 _item = _primary->get_canvas_group ();
1343 _dest_trackview = v;
1344 _dest_layer = _primary->region()->layer ();
1347 map<RegionView*, pair<RouteTimeAxisView*, int> >
1348 RegionMotionDrag::find_time_axis_views_and_layers ()
1350 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1352 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1354 double ix1, ix2, iy1, iy2;
1355 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1356 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1357 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1359 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1360 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1368 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1370 _editor->update_canvas_now ();
1372 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1374 RouteTimeAxisView* dest_rtv = final[_primary].first;
1376 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1377 _primary->get_canvas_group()->property_y() = 0;
1379 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1381 _editor->begin_reversible_command (_("insert region"));
1382 XMLNode& before = playlist->get_state ();
1383 playlist->add_region (_primary->region (), _last_frame_position);
1384 _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1385 _editor->commit_reversible_command ();
1393 RegionInsertDrag::aborted ()
1398 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1399 : RegionMoveDrag (e, i, p, v, false, false)
1404 struct RegionSelectionByPosition {
1405 bool operator() (RegionView*a, RegionView* b) {
1406 return a->region()->position () < b->region()->position();
1411 RegionSpliceDrag::motion (GdkEvent* event, bool)
1413 RouteTimeAxisView* tv;
1416 if (!check_possible (&tv, &layer)) {
1422 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1428 RegionSelection copy (_editor->selection->regions);
1430 RegionSelectionByPosition cmp;
1433 nframes64_t const pf = adjusted_current_frame (event);
1435 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1437 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1443 boost::shared_ptr<Playlist> playlist;
1445 if ((playlist = atv->playlist()) == 0) {
1449 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1454 if (pf < (*i)->region()->last_frame() + 1) {
1458 if (pf > (*i)->region()->first_frame()) {
1464 playlist->shuffle ((*i)->region(), dir);
1469 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1475 RegionSpliceDrag::aborted ()
1480 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1488 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1490 _dest_trackview = _view;
1492 Drag::start_grab (event);
1497 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1500 // TODO: create region-create-drag region view here
1503 // TODO: resize region-create-drag region view here
1507 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1509 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1515 if (!movement_occurred) {
1516 mtv->add_region (grab_frame ());
1518 motion (event, false);
1519 // TODO: create region-create-drag region here
1524 RegionCreateDrag::aborted ()
1529 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1537 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1540 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1542 Drag::start_grab (event);
1544 region = &cnote->region_view();
1546 double region_start = region->get_position_pixels();
1547 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1549 if (grab_x() <= middle_point) {
1550 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1553 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1557 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1559 if (event->motion.state & Keyboard::PrimaryModifier) {
1565 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1567 if (ms.size() > 1) {
1568 /* has to be relative, may make no sense otherwise */
1572 region->note_selected (cnote, true);
1574 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1575 MidiRegionSelection::iterator next;
1578 (*r)->begin_resizing (at_front);
1584 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1586 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1587 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1588 (*r)->update_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1593 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1595 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1596 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1597 (*r)->commit_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1602 NoteResizeDrag::aborted ()
1608 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1614 RegionGainDrag::finished (GdkEvent *, bool)
1620 RegionGainDrag::aborted ()
1625 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1626 : RegionDrag (e, i, p, v)
1627 , _have_transaction (false)
1633 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1636 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1637 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1639 if (tv && tv->is_track()) {
1640 speed = tv->get_diskstream()->speed();
1643 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1644 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1645 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1647 Drag::start_grab (event, _editor->trimmer_cursor);
1649 nframes64_t const pf = adjusted_current_frame (event);
1651 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1652 _operation = ContentsTrim;
1654 /* These will get overridden for a point trim.*/
1655 if (pf < (region_start + region_length/2)) {
1656 /* closer to start */
1657 _operation = StartTrim;
1658 } else if (pf > (region_end - region_length/2)) {
1660 _operation = EndTrim;
1664 switch (_operation) {
1666 _editor->show_verbose_time_cursor (region_start, 10);
1669 _editor->show_verbose_time_cursor (region_end, 10);
1672 _editor->show_verbose_time_cursor (pf, 10);
1678 TrimDrag::motion (GdkEvent* event, bool first_move)
1680 RegionView* rv = _primary;
1681 nframes64_t frame_delta = 0;
1683 bool left_direction;
1684 bool obey_snap = event ? !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) : false;
1686 /* snap modifier works differently here..
1687 its current state has to be passed to the
1688 various trim functions in order to work properly
1692 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1693 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1694 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1696 if (tv && tv->is_track()) {
1697 speed = tv->get_diskstream()->speed();
1700 nframes64_t const pf = adjusted_current_frame (event);
1702 if (last_pointer_frame() > pf) {
1703 left_direction = true;
1705 left_direction = false;
1712 switch (_operation) {
1714 trim_type = "Region start trim";
1717 trim_type = "Region end trim";
1720 trim_type = "Region content trim";
1724 _editor->begin_reversible_command (trim_type);
1725 _have_transaction = true;
1727 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1728 (*i)->fake_set_opaque(false);
1729 (*i)->region()->freeze ();
1731 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1734 arv->temporarily_hide_envelope ();
1737 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1738 insert_result = _editor->motion_frozen_playlists.insert (pl);
1740 if (insert_result.second) {
1741 _editor->session()->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1747 if (left_direction) {
1748 frame_delta = (last_pointer_frame() - pf);
1750 frame_delta = (pf - last_pointer_frame());
1753 bool non_overlap_trim = false;
1755 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1756 non_overlap_trim = true;
1759 switch (_operation) {
1761 if ((left_direction == false) && (pf <= rv->region()->first_frame()/speed)) {
1765 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1766 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1772 if ((left_direction == true) && (pf > (nframes64_t) (rv->region()->last_frame()/speed))) {
1776 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1777 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1784 bool swap_direction = false;
1786 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1787 swap_direction = true;
1790 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1791 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1797 switch (_operation) {
1799 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1802 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1805 _editor->show_verbose_time_cursor (pf, 10);
1812 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1814 if (movement_occurred) {
1815 motion (event, false);
1817 if (!_editor->selection->selected (_primary)) {
1818 _editor->thaw_region_after_trim (*_primary);
1821 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1822 _editor->thaw_region_after_trim (**i);
1823 (*i)->fake_set_opaque (true);
1826 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1828 if (_have_transaction) {
1829 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1833 _editor->motion_frozen_playlists.clear ();
1835 if (_have_transaction) {
1836 _editor->commit_reversible_command();
1840 /* no mouse movement */
1841 _editor->point_trim (event, adjusted_current_frame (event));
1846 TrimDrag::aborted ()
1848 /* Our motion method is changing model state, so use the Undo system
1849 to cancel. Perhaps not ideal, as this will leave an Undo point
1850 behind which may be slightly odd from the user's point of view.
1855 if (_have_transaction) {
1860 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1864 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1869 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1872 // create a dummy marker for visual representation of moving the copy.
1873 // The actual copying is not done before we reach the finish callback.
1875 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1876 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1877 *new MeterSection (_marker->meter()));
1879 _item = &new_marker->the_item ();
1880 _marker = new_marker;
1884 MetricSection& section (_marker->meter());
1886 if (!section.movable()) {
1892 Drag::start_grab (event, cursor);
1894 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1896 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1900 MeterMarkerDrag::motion (GdkEvent* event, bool)
1902 nframes64_t const pf = adjusted_current_frame (event);
1904 _marker->set_position (pf);
1906 _editor->show_verbose_time_cursor (pf, 10);
1910 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1912 if (!movement_occurred) {
1916 motion (event, false);
1920 TempoMap& map (_editor->session()->tempo_map());
1921 map.bbt_time (last_pointer_frame(), when);
1923 if (_copy == true) {
1924 _editor->begin_reversible_command (_("copy meter mark"));
1925 XMLNode &before = map.get_state();
1926 map.add_meter (_marker->meter(), when);
1927 XMLNode &after = map.get_state();
1928 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1929 _editor->commit_reversible_command ();
1931 // delete the dummy marker we used for visual representation of copying.
1932 // a new visual marker will show up automatically.
1935 _editor->begin_reversible_command (_("move meter mark"));
1936 XMLNode &before = map.get_state();
1937 map.move_meter (_marker->meter(), when);
1938 XMLNode &after = map.get_state();
1939 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1940 _editor->commit_reversible_command ();
1945 MeterMarkerDrag::aborted ()
1947 _marker->set_position (_marker->meter().frame ());
1950 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1954 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1959 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1964 // create a dummy marker for visual representation of moving the copy.
1965 // The actual copying is not done before we reach the finish callback.
1967 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1968 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1969 *new TempoSection (_marker->tempo()));
1971 _item = &new_marker->the_item ();
1972 _marker = new_marker;
1976 MetricSection& section (_marker->tempo());
1978 if (!section.movable()) {
1983 Drag::start_grab (event, cursor);
1985 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
1986 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
1990 TempoMarkerDrag::motion (GdkEvent* event, bool)
1992 nframes64_t const pf = adjusted_current_frame (event);
1993 _marker->set_position (pf);
1994 _editor->show_verbose_time_cursor (pf, 10);
1998 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2000 if (!movement_occurred) {
2004 motion (event, false);
2008 TempoMap& map (_editor->session()->tempo_map());
2009 map.bbt_time (last_pointer_frame(), when);
2011 if (_copy == true) {
2012 _editor->begin_reversible_command (_("copy tempo mark"));
2013 XMLNode &before = map.get_state();
2014 map.add_tempo (_marker->tempo(), when);
2015 XMLNode &after = map.get_state();
2016 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2017 _editor->commit_reversible_command ();
2019 // delete the dummy marker we used for visual representation of copying.
2020 // a new visual marker will show up automatically.
2023 _editor->begin_reversible_command (_("move tempo mark"));
2024 XMLNode &before = map.get_state();
2025 map.move_tempo (_marker->tempo(), when);
2026 XMLNode &after = map.get_state();
2027 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2028 _editor->commit_reversible_command ();
2033 TempoMarkerDrag::aborted ()
2035 _marker->set_position (_marker->tempo().frame());
2038 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2042 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2047 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2049 Drag::start_grab (event, c);
2053 nframes64_t where = _editor->event_frame (event, 0, 0);
2055 _editor->snap_to_with_modifier (where, event);
2056 _editor->playhead_cursor->set_position (where);
2060 if (_cursor == _editor->playhead_cursor) {
2061 _editor->_dragging_playhead = true;
2063 if (_editor->session() && _was_rolling && _stop) {
2064 _editor->session()->request_stop ();
2067 if (_editor->session() && _editor->session()->is_auditioning()) {
2068 _editor->session()->cancel_audition ();
2072 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2074 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2078 CursorDrag::motion (GdkEvent* event, bool)
2080 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2082 if (adjusted_frame == last_pointer_frame()) {
2086 _cursor->set_position (adjusted_frame);
2088 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2091 _editor->update_canvas_now ();
2093 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2097 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2099 _editor->_dragging_playhead = false;
2101 if (!movement_occurred && _stop) {
2105 motion (event, false);
2107 if (_item == &_editor->playhead_cursor->canvas_item) {
2108 if (_editor->session()) {
2109 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2110 _editor->_pending_locate_request = true;
2116 CursorDrag::aborted ()
2118 _editor->_dragging_playhead = false;
2119 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2122 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2123 : RegionDrag (e, i, p, v)
2129 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2131 Drag::start_grab (event, cursor);
2133 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2134 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2136 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2137 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2141 FadeInDrag::motion (GdkEvent* event, bool)
2143 nframes64_t fade_length;
2145 nframes64_t const pos = adjusted_current_frame (event);
2147 boost::shared_ptr<Region> region = _primary->region ();
2149 if (pos < (region->position() + 64)) {
2150 fade_length = 64; // this should be a minimum defined somewhere
2151 } else if (pos > region->last_frame()) {
2152 fade_length = region->length();
2154 fade_length = pos - region->position();
2157 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2159 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2165 tmp->reset_fade_in_shape_width (fade_length);
2168 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2172 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2174 if (!movement_occurred) {
2178 nframes64_t fade_length;
2180 nframes64_t const pos = adjusted_current_frame (event);
2182 boost::shared_ptr<Region> region = _primary->region ();
2184 if (pos < (region->position() + 64)) {
2185 fade_length = 64; // this should be a minimum defined somewhere
2186 } else if (pos > region->last_frame()) {
2187 fade_length = region->length();
2189 fade_length = pos - region->position();
2192 _editor->begin_reversible_command (_("change fade in length"));
2194 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2196 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2202 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2203 XMLNode &before = alist->get_state();
2205 tmp->audio_region()->set_fade_in_length (fade_length);
2206 tmp->audio_region()->set_fade_in_active (true);
2208 XMLNode &after = alist->get_state();
2209 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2212 _editor->commit_reversible_command ();
2216 FadeInDrag::aborted ()
2218 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2219 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2225 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2229 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2230 : RegionDrag (e, i, p, v)
2236 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2238 Drag::start_grab (event, cursor);
2240 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2241 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2243 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2244 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2248 FadeOutDrag::motion (GdkEvent* event, bool)
2250 nframes64_t fade_length;
2252 nframes64_t const pos = adjusted_current_frame (event);
2254 boost::shared_ptr<Region> region = _primary->region ();
2256 if (pos > (region->last_frame() - 64)) {
2257 fade_length = 64; // this should really be a minimum fade defined somewhere
2259 else if (pos < region->position()) {
2260 fade_length = region->length();
2263 fade_length = region->last_frame() - pos;
2266 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2268 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2274 tmp->reset_fade_out_shape_width (fade_length);
2277 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2281 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2283 if (!movement_occurred) {
2287 nframes64_t fade_length;
2289 nframes64_t const pos = adjusted_current_frame (event);
2291 boost::shared_ptr<Region> region = _primary->region ();
2293 if (pos > (region->last_frame() - 64)) {
2294 fade_length = 64; // this should really be a minimum fade defined somewhere
2296 else if (pos < region->position()) {
2297 fade_length = region->length();
2300 fade_length = region->last_frame() - pos;
2303 _editor->begin_reversible_command (_("change fade out length"));
2305 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2307 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2313 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2314 XMLNode &before = alist->get_state();
2316 tmp->audio_region()->set_fade_out_length (fade_length);
2317 tmp->audio_region()->set_fade_out_active (true);
2319 XMLNode &after = alist->get_state();
2320 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2323 _editor->commit_reversible_command ();
2327 FadeOutDrag::aborted ()
2329 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2330 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2336 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2340 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2343 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2346 _points.push_back (Gnome::Art::Point (0, 0));
2347 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2349 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2350 _line->property_width_pixels() = 1;
2351 _line->property_points () = _points;
2354 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2357 MarkerDrag::~MarkerDrag ()
2359 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2365 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2367 Drag::start_grab (event, cursor);
2371 Location *location = _editor->find_location_from_marker (_marker, is_start);
2372 _editor->_dragging_edit_point = true;
2374 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2376 update_item (location);
2378 // _drag_line->show();
2379 // _line->raise_to_top();
2382 _editor->show_verbose_time_cursor (location->start(), 10);
2384 _editor->show_verbose_time_cursor (location->end(), 10);
2387 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2390 case Selection::Toggle:
2391 _editor->selection->toggle (_marker);
2393 case Selection::Set:
2394 if (!_editor->selection->selected (_marker)) {
2395 _editor->selection->set (_marker);
2398 case Selection::Extend:
2400 Locations::LocationList ll;
2401 list<Marker*> to_add;
2403 _editor->selection->markers.range (s, e);
2404 s = min (_marker->position(), s);
2405 e = max (_marker->position(), e);
2408 if (e < max_frames) {
2411 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2412 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2413 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2416 to_add.push_back (lm->start);
2419 to_add.push_back (lm->end);
2423 if (!to_add.empty()) {
2424 _editor->selection->add (to_add);
2428 case Selection::Add:
2429 _editor->selection->add (_marker);
2433 /* set up copies for us to manipulate during the drag */
2435 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2436 Location *l = _editor->find_location_from_marker (*i, is_start);
2437 _copied_locations.push_back (new Location (*l));
2442 MarkerDrag::motion (GdkEvent* event, bool)
2444 nframes64_t f_delta = 0;
2446 bool move_both = false;
2448 Location *real_location;
2449 Location *copy_location = 0;
2451 nframes64_t const newframe = adjusted_current_frame (event);
2453 nframes64_t next = newframe;
2455 if (newframe == last_pointer_frame()) {
2459 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2463 MarkerSelection::iterator i;
2464 list<Location*>::iterator x;
2466 /* find the marker we're dragging, and compute the delta */
2468 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2469 x != _copied_locations.end() && i != _editor->selection->markers.end();
2475 if (marker == _marker) {
2477 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2482 if (real_location->is_mark()) {
2483 f_delta = newframe - copy_location->start();
2487 switch (marker->type()) {
2489 case Marker::LoopStart:
2490 case Marker::PunchIn:
2491 f_delta = newframe - copy_location->start();
2495 case Marker::LoopEnd:
2496 case Marker::PunchOut:
2497 f_delta = newframe - copy_location->end();
2500 /* what kind of marker is this ? */
2508 if (i == _editor->selection->markers.end()) {
2509 /* hmm, impossible - we didn't find the dragged marker */
2513 /* now move them all */
2515 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2516 x != _copied_locations.end() && i != _editor->selection->markers.end();
2522 /* call this to find out if its the start or end */
2524 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2528 if (real_location->locked()) {
2532 if (copy_location->is_mark()) {
2536 copy_location->set_start (copy_location->start() + f_delta);
2540 nframes64_t new_start = copy_location->start() + f_delta;
2541 nframes64_t new_end = copy_location->end() + f_delta;
2543 if (is_start) { // start-of-range marker
2546 copy_location->set_start (new_start);
2547 copy_location->set_end (new_end);
2548 } else if (new_start < copy_location->end()) {
2549 copy_location->set_start (new_start);
2551 _editor->snap_to (next, 1, true);
2552 copy_location->set_end (next);
2553 copy_location->set_start (newframe);
2556 } else { // end marker
2559 copy_location->set_end (new_end);
2560 copy_location->set_start (new_start);
2561 } else if (new_end > copy_location->start()) {
2562 copy_location->set_end (new_end);
2563 } else if (newframe > 0) {
2564 _editor->snap_to (next, -1, true);
2565 copy_location->set_start (next);
2566 copy_location->set_end (newframe);
2571 update_item (copy_location);
2573 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2576 lm->set_position (copy_location->start(), copy_location->end());
2580 assert (!_copied_locations.empty());
2582 _editor->show_verbose_time_cursor (newframe, 10);
2585 _editor->update_canvas_now ();
2590 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2592 if (!movement_occurred) {
2594 /* just a click, do nothing but finish
2595 off the selection process
2598 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2601 case Selection::Set:
2602 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2603 _editor->selection->set (_marker);
2607 case Selection::Toggle:
2608 case Selection::Extend:
2609 case Selection::Add:
2616 _editor->_dragging_edit_point = false;
2618 _editor->begin_reversible_command ( _("move marker") );
2619 XMLNode &before = _editor->session()->locations()->get_state();
2621 MarkerSelection::iterator i;
2622 list<Location*>::iterator x;
2625 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2626 x != _copied_locations.end() && i != _editor->selection->markers.end();
2629 Location * location = _editor->find_location_from_marker (*i, is_start);
2633 if (location->locked()) {
2637 if (location->is_mark()) {
2638 location->set_start ((*x)->start());
2640 location->set ((*x)->start(), (*x)->end());
2645 XMLNode &after = _editor->session()->locations()->get_state();
2646 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2647 _editor->commit_reversible_command ();
2653 MarkerDrag::aborted ()
2659 MarkerDrag::update_item (Location* location)
2661 double const x1 = _editor->frame_to_pixel (location->start());
2663 _points.front().set_x(x1);
2664 _points.back().set_x(x1);
2665 _line->property_points() = _points;
2668 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2670 _cumulative_x_drag (0),
2671 _cumulative_y_drag (0)
2673 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2679 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2681 Drag::start_grab (event, _editor->fader_cursor);
2683 // start the grab at the center of the control point so
2684 // the point doesn't 'jump' to the mouse after the first drag
2685 _time_axis_view_grab_x = _point->get_x();
2686 _time_axis_view_grab_y = _point->get_y();
2688 float const fraction = 1 - (_point->get_y() / _point->line().height());
2690 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2692 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2693 event->button.x + 10, event->button.y + 10);
2695 _editor->show_verbose_canvas_cursor ();
2699 ControlPointDrag::motion (GdkEvent* event, bool)
2701 double dx = _drags->current_pointer_x() - last_pointer_x();
2702 double dy = _drags->current_pointer_y() - last_pointer_y();
2704 if (event->button.state & Keyboard::SecondaryModifier) {
2709 /* coordinate in TimeAxisView's space */
2710 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2711 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2713 // calculate zero crossing point. back off by .01 to stay on the
2714 // positive side of zero
2715 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2717 // make sure we hit zero when passing through
2718 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2722 if (_x_constrained) {
2723 cx = _time_axis_view_grab_x;
2725 if (_y_constrained) {
2726 cy = _time_axis_view_grab_y;
2729 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2730 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2734 cy = min ((double) _point->line().height(), cy);
2736 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2738 if (!_x_constrained) {
2739 _editor->snap_to_with_modifier (cx_frames, event);
2742 float const fraction = 1.0 - (cy / _point->line().height());
2744 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2746 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2748 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2752 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2754 if (!movement_occurred) {
2758 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2759 _editor->reset_point_selection ();
2763 motion (event, false);
2765 _point->line().end_drag ();
2769 ControlPointDrag::aborted ()
2771 _point->line().reset ();
2775 ControlPointDrag::active (Editing::MouseMode m)
2777 if (m == Editing::MouseGain) {
2778 /* always active in mouse gain */
2782 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2783 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2786 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2789 _cumulative_y_drag (0)
2794 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2796 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2799 _item = &_line->grab_item ();
2801 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2802 origin, and ditto for y.
2805 double cx = event->button.x;
2806 double cy = event->button.y;
2808 _line->parent_group().w2i (cx, cy);
2810 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2815 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2816 /* no adjacent points */
2820 Drag::start_grab (event, _editor->fader_cursor);
2822 /* store grab start in parent frame */
2824 _time_axis_view_grab_x = cx;
2825 _time_axis_view_grab_y = cy;
2827 double fraction = 1.0 - (cy / _line->height());
2829 _line->start_drag_line (before, after, fraction);
2831 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2832 event->button.x + 10, event->button.y + 10);
2834 _editor->show_verbose_canvas_cursor ();
2838 LineDrag::motion (GdkEvent* event, bool)
2840 double dy = _drags->current_pointer_y() - last_pointer_y();
2842 if (event->button.state & Keyboard::SecondaryModifier) {
2846 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2848 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2851 cy = min ((double) _line->height(), cy);
2853 double const fraction = 1.0 - (cy / _line->height());
2857 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2863 /* we are ignoring x position for this drag, so we can just pass in anything */
2864 _line->drag_motion (0, fraction, true, push);
2866 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2870 LineDrag::finished (GdkEvent* event, bool)
2872 motion (event, false);
2877 LineDrag::aborted ()
2883 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2885 Drag::start_grab (event);
2886 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2890 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2897 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2899 nframes64_t grab = grab_frame ();
2900 if (Config->get_rubberbanding_snaps_to_grid ()) {
2901 _editor->snap_to_with_modifier (grab, event);
2904 /* base start and end on initial click position */
2914 if (_drags->current_pointer_y() < grab_y()) {
2915 y1 = _drags->current_pointer_y();
2918 y2 = _drags->current_pointer_y();
2923 if (start != end || y1 != y2) {
2925 double x1 = _editor->frame_to_pixel (start);
2926 double x2 = _editor->frame_to_pixel (end);
2928 _editor->rubberband_rect->property_x1() = x1;
2929 _editor->rubberband_rect->property_y1() = y1;
2930 _editor->rubberband_rect->property_x2() = x2;
2931 _editor->rubberband_rect->property_y2() = y2;
2933 _editor->rubberband_rect->show();
2934 _editor->rubberband_rect->raise_to_top();
2936 _editor->show_verbose_time_cursor (pf, 10);
2941 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2943 if (movement_occurred) {
2945 motion (event, false);
2948 if (_drags->current_pointer_y() < grab_y()) {
2949 y1 = _drags->current_pointer_y();
2952 y2 = _drags->current_pointer_y();
2957 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2960 _editor->begin_reversible_command (_("rubberband selection"));
2962 if (grab_frame() < last_pointer_frame()) {
2963 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
2965 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
2969 _editor->commit_reversible_command ();
2973 if (!getenv("ARDOUR_SAE")) {
2974 _editor->selection->clear_tracks();
2976 _editor->selection->clear_regions();
2977 _editor->selection->clear_points ();
2978 _editor->selection->clear_lines ();
2981 _editor->rubberband_rect->hide();
2985 RubberbandSelectDrag::aborted ()
2987 _editor->rubberband_rect->hide ();
2991 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2993 Drag::start_grab (event);
2995 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2999 TimeFXDrag::motion (GdkEvent* event, bool)
3001 RegionView* rv = _primary;
3003 nframes64_t const pf = adjusted_current_frame (event);
3005 if (pf > rv->region()->position()) {
3006 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3009 _editor->show_verbose_time_cursor (pf, 10);
3013 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3015 _primary->get_time_axis_view().hide_timestretch ();
3017 if (!movement_occurred) {
3021 if (last_pointer_frame() < _primary->region()->position()) {
3022 /* backwards drag of the left edge - not usable */
3026 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3028 float percentage = (double) newlen / (double) _primary->region()->length();
3030 #ifndef USE_RUBBERBAND
3031 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3032 if (_primary->region()->data_type() == DataType::AUDIO) {
3033 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3037 _editor->begin_reversible_command (_("timestretch"));
3039 // XXX how do timeFX on multiple regions ?
3044 if (!_editor->time_stretch (rs, percentage) == 0) {
3045 error << _("An error occurred while executing time stretch operation") << endmsg;
3050 TimeFXDrag::aborted ()
3052 _primary->get_time_axis_view().hide_timestretch ();
3057 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3059 Drag::start_grab (event);
3063 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3065 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3069 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3071 if (movement_occurred && _editor->session()) {
3072 /* make sure we stop */
3073 _editor->session()->request_transport_speed (0.0);
3078 ScrubDrag::aborted ()
3083 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3087 , _original_pointer_time_axis (-1)
3088 , _last_pointer_time_axis (-1)
3094 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3096 nframes64_t start = 0;
3097 nframes64_t end = 0;
3099 if (_editor->session() == 0) {
3103 Gdk::Cursor* cursor = 0;
3105 switch (_operation) {
3106 case CreateSelection:
3107 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3112 cursor = _editor->selector_cursor;
3113 Drag::start_grab (event, cursor);
3116 case SelectionStartTrim:
3117 if (_editor->clicked_axisview) {
3118 _editor->clicked_axisview->order_selection_trims (_item, true);
3120 Drag::start_grab (event, _editor->trimmer_cursor);
3121 start = _editor->selection->time[_editor->clicked_selection].start;
3122 _pointer_frame_offset = grab_frame() - start;
3125 case SelectionEndTrim:
3126 if (_editor->clicked_axisview) {
3127 _editor->clicked_axisview->order_selection_trims (_item, false);
3129 Drag::start_grab (event, _editor->trimmer_cursor);
3130 end = _editor->selection->time[_editor->clicked_selection].end;
3131 _pointer_frame_offset = grab_frame() - end;
3135 start = _editor->selection->time[_editor->clicked_selection].start;
3136 Drag::start_grab (event, cursor);
3137 _pointer_frame_offset = grab_frame() - start;
3141 if (_operation == SelectionMove) {
3142 _editor->show_verbose_time_cursor (start, 10);
3144 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3147 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3151 SelectionDrag::motion (GdkEvent* event, bool first_move)
3153 nframes64_t start = 0;
3154 nframes64_t end = 0;
3157 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3158 if (pending_time_axis.first == 0) {
3162 nframes64_t const pending_position = adjusted_current_frame (event);
3164 /* only alter selection if things have changed */
3166 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3170 switch (_operation) {
3171 case CreateSelection:
3173 nframes64_t grab = grab_frame ();
3176 _editor->snap_to (grab);
3179 if (pending_position < grab_frame()) {
3180 start = pending_position;
3183 end = pending_position;
3187 /* first drag: Either add to the selection
3188 or create a new selection
3194 /* adding to the selection */
3195 _editor->selection->add (_editor->clicked_axisview);
3196 _editor->clicked_selection = _editor->selection->add (start, end);
3201 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3202 _editor->selection->set (_editor->clicked_axisview);
3205 _editor->clicked_selection = _editor->selection->set (start, end);
3209 /* select the track that we're in */
3210 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3211 _editor->selection->add (pending_time_axis.first);
3212 _added_time_axes.push_back (pending_time_axis.first);
3215 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3216 tracks that we selected in the first place.
3219 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3220 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3222 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3223 while (i != _added_time_axes.end()) {
3225 list<TimeAxisView*>::iterator tmp = i;
3228 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3229 _editor->selection->remove (*i);
3230 _added_time_axes.remove (*i);
3239 case SelectionStartTrim:
3241 start = _editor->selection->time[_editor->clicked_selection].start;
3242 end = _editor->selection->time[_editor->clicked_selection].end;
3244 if (pending_position > end) {
3247 start = pending_position;
3251 case SelectionEndTrim:
3253 start = _editor->selection->time[_editor->clicked_selection].start;
3254 end = _editor->selection->time[_editor->clicked_selection].end;
3256 if (pending_position < start) {
3259 end = pending_position;
3266 start = _editor->selection->time[_editor->clicked_selection].start;
3267 end = _editor->selection->time[_editor->clicked_selection].end;
3269 length = end - start;
3271 start = pending_position;
3272 _editor->snap_to (start);
3274 end = start + length;
3279 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3280 _editor->start_canvas_autoscroll (1, 0);
3284 _editor->selection->replace (_editor->clicked_selection, start, end);
3287 if (_operation == SelectionMove) {
3288 _editor->show_verbose_time_cursor(start, 10);
3290 _editor->show_verbose_time_cursor(pending_position, 10);
3295 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3297 Session* s = _editor->session();
3299 if (movement_occurred) {
3300 motion (event, false);
3301 /* XXX this is not object-oriented programming at all. ick */
3302 if (_editor->selection->time.consolidate()) {
3303 _editor->selection->TimeChanged ();
3306 /* XXX what if its a music time selection? */
3307 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3308 s->request_play_range (&_editor->selection->time, true);
3313 /* just a click, no pointer movement.*/
3315 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3316 _editor->selection->clear_time();
3319 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3320 _editor->selection->set (_editor->clicked_axisview);
3323 if (s && s->get_play_range () && s->transport_rolling()) {
3324 s->request_stop (false, false);
3329 _editor->stop_canvas_autoscroll ();
3333 SelectionDrag::aborted ()
3338 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3343 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3344 _drag_rect->hide ();
3346 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3347 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3351 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3353 if (_editor->session() == 0) {
3357 Gdk::Cursor* cursor = 0;
3359 if (!_editor->temp_location) {
3360 _editor->temp_location = new Location;
3363 switch (_operation) {
3364 case CreateRangeMarker:
3365 case CreateTransportMarker:
3366 case CreateCDMarker:
3368 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3373 cursor = _editor->selector_cursor;
3377 Drag::start_grab (event, cursor);
3379 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3383 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3385 nframes64_t start = 0;
3386 nframes64_t end = 0;
3387 ArdourCanvas::SimpleRect *crect;
3389 switch (_operation) {
3390 case CreateRangeMarker:
3391 crect = _editor->range_bar_drag_rect;
3393 case CreateTransportMarker:
3394 crect = _editor->transport_bar_drag_rect;
3396 case CreateCDMarker:
3397 crect = _editor->cd_marker_bar_drag_rect;
3400 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3405 nframes64_t const pf = adjusted_current_frame (event);
3407 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3408 nframes64_t grab = grab_frame ();
3409 _editor->snap_to (grab);
3411 if (pf < grab_frame()) {
3419 /* first drag: Either add to the selection
3420 or create a new selection.
3425 _editor->temp_location->set (start, end);
3429 update_item (_editor->temp_location);
3431 //_drag_rect->raise_to_top();
3436 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3437 _editor->start_canvas_autoscroll (1, 0);
3441 _editor->temp_location->set (start, end);
3443 double x1 = _editor->frame_to_pixel (start);
3444 double x2 = _editor->frame_to_pixel (end);
3445 crect->property_x1() = x1;
3446 crect->property_x2() = x2;
3448 update_item (_editor->temp_location);
3451 _editor->show_verbose_time_cursor (pf, 10);
3456 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3458 Location * newloc = 0;
3462 if (movement_occurred) {
3463 motion (event, false);
3466 switch (_operation) {
3467 case CreateRangeMarker:
3468 case CreateCDMarker:
3470 _editor->begin_reversible_command (_("new range marker"));
3471 XMLNode &before = _editor->session()->locations()->get_state();
3472 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3473 if (_operation == CreateCDMarker) {
3474 flags = Location::IsRangeMarker | Location::IsCDMarker;
3475 _editor->cd_marker_bar_drag_rect->hide();
3478 flags = Location::IsRangeMarker;
3479 _editor->range_bar_drag_rect->hide();
3481 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3482 _editor->session()->locations()->add (newloc, true);
3483 XMLNode &after = _editor->session()->locations()->get_state();
3484 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3485 _editor->commit_reversible_command ();
3489 case CreateTransportMarker:
3490 // popup menu to pick loop or punch
3491 _editor->new_transport_marker_context_menu (&event->button, _item);
3495 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3497 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3502 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3504 if (end == max_frames) {
3505 end = _editor->session()->current_end_frame ();
3508 if (start == max_frames) {
3509 start = _editor->session()->current_start_frame ();
3512 switch (_editor->mouse_mode) {
3514 /* find the two markers on either side and then make the selection from it */
3515 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3519 /* find the two markers on either side of the click and make the range out of it */
3520 _editor->selection->set (start, end);
3529 _editor->stop_canvas_autoscroll ();
3533 RangeMarkerBarDrag::aborted ()
3539 RangeMarkerBarDrag::update_item (Location* location)
3541 double const x1 = _editor->frame_to_pixel (location->start());
3542 double const x2 = _editor->frame_to_pixel (location->end());
3544 _drag_rect->property_x1() = x1;
3545 _drag_rect->property_x2() = x2;
3549 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3551 Drag::start_grab (event, _editor->zoom_cursor);
3552 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3556 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3561 nframes64_t const pf = adjusted_current_frame (event);
3563 nframes64_t grab = grab_frame ();
3564 _editor->snap_to_with_modifier (grab, event);
3566 /* base start and end on initial click position */
3578 _editor->zoom_rect->show();
3579 _editor->zoom_rect->raise_to_top();
3582 _editor->reposition_zoom_rect(start, end);
3584 _editor->show_verbose_time_cursor (pf, 10);
3589 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3591 if (movement_occurred) {
3592 motion (event, false);
3594 if (grab_frame() < last_pointer_frame()) {
3595 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3597 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3600 _editor->temporal_zoom_to_frame (false, grab_frame());
3602 temporal_zoom_step (false);
3603 center_screen (grab_frame());
3607 _editor->zoom_rect->hide();
3611 MouseZoomDrag::aborted ()
3613 _editor->zoom_rect->hide ();
3616 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3619 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3620 region = &cnote->region_view();
3624 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3626 Drag::start_grab (event);
3629 drag_delta_note = 0;
3634 event_x = _drags->current_pointer_x();
3635 event_y = _drags->current_pointer_y();
3637 _item->property_parent().get_value()->w2i(event_x, event_y);
3639 last_x = region->snap_to_pixel(event_x);
3642 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3644 if (!(was_selected = cnote->selected())) {
3646 /* tertiary-click means extend selection - we'll do that on button release,
3647 so don't add it here, because otherwise we make it hard to figure
3648 out the "extend-to" range.
3651 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3654 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3657 region->note_selected (cnote, true);
3659 region->unique_select (cnote);
3666 NoteDrag::motion (GdkEvent*, bool)
3668 MidiStreamView* streamview = region->midi_stream_view();
3672 event_x = _drags->current_pointer_x();
3673 event_y = _drags->current_pointer_y();
3675 _item->property_parent().get_value()->w2i(event_x, event_y);
3677 event_x = region->snap_to_pixel(event_x);
3679 double dx = event_x - last_x;
3680 double dy = event_y - last_y;
3685 // Snap to note rows
3687 if (abs (dy) < streamview->note_height()) {
3690 int8_t this_delta_note;
3692 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3694 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3696 drag_delta_note -= this_delta_note;
3697 dy = streamview->note_height() * this_delta_note;
3698 last_y = last_y + dy;
3702 region->move_selection (dx, dy);
3704 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3706 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3707 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3708 _editor->show_verbose_canvas_cursor_with (buf);
3713 NoteDrag::finished (GdkEvent* ev, bool moved)
3715 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3718 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3721 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3723 region->note_deselected (cnote);
3726 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3727 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3729 if (!extend && !add && region->selection_size() > 1) {
3730 region->unique_select(cnote);
3731 } else if (extend) {
3732 region->note_selected (cnote, true, true);
3734 /* it was added during button press */
3739 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3744 NoteDrag::aborted ()
3749 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3752 , _nothing_to_drag (false)
3754 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3757 _line = _atav->line ();
3761 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3763 Drag::start_grab (event, cursor);
3765 list<ControlPoint*> points;
3767 XMLNode* state = &_line->get_state ();
3769 if (_ranges.empty()) {
3771 uint32_t const N = _line->npoints ();
3772 for (uint32_t i = 0; i < N; ++i) {
3773 points.push_back (_line->nth (i));
3778 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3779 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3781 /* fade into and out of the region that we're dragging;
3782 64 samples length plucked out of thin air.
3784 nframes64_t const h = (j->start + j->end) / 2;
3785 nframes64_t a = j->start + 64;
3789 nframes64_t b = j->end - 64;
3794 the_list->add (j->start, the_list->eval (j->start));
3795 _line->add_always_in_view (j->start);
3796 the_list->add (a, the_list->eval (a));
3797 _line->add_always_in_view (a);
3798 the_list->add (b, the_list->eval (b));
3799 _line->add_always_in_view (b);
3800 the_list->add (j->end, the_list->eval (j->end));
3801 _line->add_always_in_view (j->end);
3804 uint32_t const N = _line->npoints ();
3805 for (uint32_t i = 0; i < N; ++i) {
3807 ControlPoint* p = _line->nth (i);
3809 list<AudioRange>::const_iterator j = _ranges.begin ();
3810 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3814 if (j != _ranges.end()) {
3815 points.push_back (p);
3820 if (points.empty()) {
3821 _nothing_to_drag = true;
3825 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3829 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3831 if (_nothing_to_drag) {
3835 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3837 /* we are ignoring x position for this drag, so we can just pass in anything */
3838 _line->drag_motion (0, f, true, false);
3842 AutomationRangeDrag::finished (GdkEvent* event, bool)
3844 if (_nothing_to_drag) {
3848 motion (event, false);
3850 _line->clear_always_in_view ();
3854 AutomationRangeDrag::aborted ()
3856 _line->clear_always_in_view ();