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/session.h"
26 #include "ardour/dB.h"
27 #include "ardour/region_factory.h"
31 #include "audio_region_view.h"
32 #include "midi_region_view.h"
33 #include "ardour_ui.h"
34 #include "gui_thread.h"
35 #include "control_point.h"
37 #include "region_gain_line.h"
38 #include "editor_drag.h"
39 #include "audio_time_axis.h"
40 #include "midi_time_axis.h"
41 #include "canvas-note.h"
42 #include "selection.h"
43 #include "midi_selection.h"
44 #include "automation_time_axis.h"
47 using namespace ARDOUR;
50 using namespace Editing;
51 using namespace ArdourCanvas;
53 using Gtkmm2ext::Keyboard;
55 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
57 DragManager::DragManager (Editor* e)
60 , _current_pointer_frame (0)
65 DragManager::~DragManager ()
70 /** Call abort for each active drag */
76 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
87 DragManager::add (Drag* d)
89 d->set_manager (this);
94 DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
96 assert (_drags.empty ());
97 d->set_manager (this);
103 DragManager::start_grab (GdkEvent* e)
105 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
107 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
108 (*i)->start_grab (e);
112 /** Call end_grab for each active drag.
113 * @return true if any drag reported movement having occurred.
116 DragManager::end_grab (GdkEvent* e)
121 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
122 bool const t = (*i)->end_grab (e);
137 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
141 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
143 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
144 bool const t = (*i)->motion_handler (e, from_autoscroll);
155 DragManager::have_item (ArdourCanvas::Item* i) const
157 list<Drag*>::const_iterator j = _drags.begin ();
158 while (j != _drags.end() && (*j)->item () != i) {
162 return j != _drags.end ();
165 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
168 , _pointer_frame_offset (0)
169 , _move_threshold_passed (false)
171 , _last_pointer_frame (0)
177 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
183 cursor = _editor->which_grabber_cursor ();
186 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
190 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
193 cursor = _editor->which_grabber_cursor ();
196 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
198 if (Keyboard::is_button2_event (&event->button)) {
199 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
200 _y_constrained = true;
201 _x_constrained = false;
203 _y_constrained = false;
204 _x_constrained = true;
207 _x_constrained = false;
208 _y_constrained = false;
211 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
212 _grab_frame = adjusted_frame (_grab_frame, event);
213 _last_pointer_frame = _grab_frame;
214 _last_pointer_x = _grab_x;
215 _last_pointer_y = _grab_y;
217 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
221 if (_editor->session() && _editor->session()->transport_rolling()) {
224 _was_rolling = false;
227 switch (_editor->snap_type()) {
228 case SnapToRegionStart:
229 case SnapToRegionEnd:
230 case SnapToRegionSync:
231 case SnapToRegionBoundary:
232 _editor->build_region_boundary_cache ();
239 /** Call to end a drag `successfully'. Ungrabs item and calls
240 * subclass' finished() method.
242 * @param event GDK event, or 0.
243 * @return true if some movement occurred, otherwise false.
246 Drag::end_grab (GdkEvent* event)
248 _editor->stop_canvas_autoscroll ();
250 _item->ungrab (event ? event->button.time : 0);
252 finished (event, _move_threshold_passed);
254 _editor->hide_verbose_canvas_cursor();
256 return _move_threshold_passed;
260 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
264 if (f > _pointer_frame_offset) {
265 pos = f - _pointer_frame_offset;
269 _editor->snap_to_with_modifier (pos, event);
276 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
278 return adjusted_frame (_drags->current_pointer_frame (), event, snap);
282 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
284 /* check to see if we have moved in any way that matters since the last motion event */
285 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
286 (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
290 pair<nframes64_t, int> const threshold = move_threshold ();
292 bool const old_move_threshold_passed = _move_threshold_passed;
294 if (!from_autoscroll && !_move_threshold_passed) {
296 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
297 bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
299 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
302 if (active (_editor->mouse_mode) && _move_threshold_passed) {
304 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
305 if (!from_autoscroll) {
306 _editor->maybe_autoscroll (true, allow_vertical_autoscroll ());
309 motion (event, _move_threshold_passed != old_move_threshold_passed);
311 _last_pointer_x = _drags->current_pointer_x ();
312 _last_pointer_y = _drags->current_pointer_y ();
313 _last_pointer_frame = adjusted_current_frame (event);
321 /** Call to abort a drag. Ungrabs item and calls subclass's aborted () */
331 _editor->stop_canvas_autoscroll ();
332 _editor->hide_verbose_canvas_cursor ();
335 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
339 for (list<RegionView*>::const_iterator i = v.begin(); i != v.end(); ++i) {
340 _views.push_back (DraggingView (*i));
343 RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
347 RegionDrag::region_going_away (RegionView* v)
349 list<DraggingView>::iterator i = _views.begin ();
350 while (i != _views.end() && i->view != v) {
354 if (i != _views.end()) {
359 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
360 : RegionDrag (e, i, p, v),
371 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
373 Drag::start_grab (event);
375 _editor->show_verbose_time_cursor (_last_frame_position, 10);
378 RegionMotionDrag::TimeAxisViewSummary
379 RegionMotionDrag::get_time_axis_view_summary ()
381 int32_t children = 0;
382 TimeAxisViewSummary sum;
384 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
386 /* get a bitmask representing the visible tracks */
388 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
389 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
390 TimeAxisView::Children children_list;
392 /* zeroes are audio/MIDI tracks. ones are other types. */
394 if (!rtv->hidden()) {
396 if (!rtv->is_track()) {
397 /* not an audio nor MIDI track */
398 sum.tracks = sum.tracks |= (0x01 << rtv->order());
401 sum.height_list[rtv->order()] = (*i)->current_height();
404 if ((children_list = rtv->get_child_list()).size() > 0) {
405 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
406 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
407 sum.height_list[rtv->order() + children] = (*j)->current_height();
418 RegionMotionDrag::compute_y_delta (
419 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
420 int32_t last_pointer_layer, int32_t current_pointer_layer,
421 TimeAxisViewSummary const & tavs,
422 int32_t* pointer_order_span, int32_t* pointer_layer_span,
423 int32_t* canvas_pointer_order_span
427 *pointer_order_span = 0;
428 *pointer_layer_span = 0;
432 bool clamp_y_axis = false;
434 /* the change in track order between this callback and the last */
435 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
436 /* the change in layer between this callback and the last;
437 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
438 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
440 if (*pointer_order_span != 0) {
442 /* find the actual pointer span, in terms of the number of visible tracks;
443 to do this, we reduce |pointer_order_span| by the number of hidden tracks
446 *canvas_pointer_order_span = *pointer_order_span;
447 if (last_pointer_view->order() >= current_pointer_view->order()) {
448 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
449 if (tavs.height_list[y] == 0) {
450 *canvas_pointer_order_span--;
454 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
455 if (tavs.height_list[y] == 0) {
456 *canvas_pointer_order_span++;
461 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
463 RegionView* rv = i->view;
465 if (rv->region()->locked()) {
469 double ix1, ix2, iy1, iy2;
470 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
471 rv->get_canvas_frame()->i2w (ix1, iy1);
472 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
474 /* get the new trackview for this particular region */
475 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
477 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
479 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
480 as surely this is a per-region thing... */
482 clamp_y_axis = y_movement_disallowed (
483 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
491 } else if (_dest_trackview == current_pointer_view) {
493 if (current_pointer_layer == last_pointer_layer) {
494 /* No movement; clamp */
500 _dest_trackview = current_pointer_view;
501 _dest_layer = current_pointer_layer;
509 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
511 /* compute the amount of pointer motion in frames, and where
512 the region would be if we moved it by that much.
514 *pending_region_position = adjusted_current_frame (event);
516 nframes64_t sync_frame;
517 nframes64_t sync_offset;
520 sync_offset = _primary->region()->sync_offset (sync_dir);
522 /* we don't handle a sync point that lies before zero.
524 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
526 sync_frame = *pending_region_position + (sync_dir*sync_offset);
528 _editor->snap_to_with_modifier (sync_frame, event);
530 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
533 *pending_region_position = _last_frame_position;
536 if (*pending_region_position > max_frames - _primary->region()->length()) {
537 *pending_region_position = _last_frame_position;
542 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
544 /* now compute the canvas unit distance we need to move the regionview
545 to make it appear at the new location.
548 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
550 if (*pending_region_position <= _last_frame_position) {
552 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
554 RegionView* rv = i->view;
556 // If any regionview is at zero, we need to know so we can stop further leftward motion.
558 double ix1, ix2, iy1, iy2;
559 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
560 rv->get_canvas_frame()->i2w (ix1, iy1);
562 if (-x_delta > ix1 + _editor->horizontal_position()) {
564 *pending_region_position = _last_frame_position;
571 _last_frame_position = *pending_region_position;
578 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
582 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
584 vector<int32_t>::iterator j;
586 /* *pointer* variables reflect things about the pointer; as we may be moving
587 multiple regions, much detail must be computed per-region */
589 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
590 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
591 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
592 is always 0 regardless of what the region's "real" layer is */
593 RouteTimeAxisView* current_pointer_view;
594 layer_t current_pointer_layer;
595 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
599 /* TimeAxisView that we were pointing at last time we entered this method */
600 TimeAxisView const * const last_pointer_view = _dest_trackview;
601 /* the order of the track that we were pointing at last time we entered this method */
602 int32_t const last_pointer_order = last_pointer_view->order ();
603 /* the layer that we were pointing at last time we entered this method */
604 layer_t const last_pointer_layer = _dest_layer;
606 int32_t pointer_order_span;
607 int32_t pointer_layer_span;
608 int32_t canvas_pointer_order_span;
610 bool const clamp_y_axis = compute_y_delta (
611 last_pointer_view, current_pointer_view,
612 last_pointer_layer, current_pointer_layer, tavs,
613 &pointer_order_span, &pointer_layer_span,
614 &canvas_pointer_order_span
617 nframes64_t pending_region_position;
618 double const x_delta = compute_x_delta (event, &pending_region_position);
620 /*************************************************************
622 ************************************************************/
624 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
625 /* haven't reached next snap point, and we're not switching
626 trackviews nor layers. nothing to do.
631 /*************************************************************
633 ************************************************************/
635 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
637 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
639 RegionView* rv = i->view;
641 if (rv->region()->locked()) {
645 /* here we are calculating the y distance from the
646 top of the first track view to the top of the region
647 area of the track view that we're working on */
649 /* this x value is just a dummy value so that we have something
654 /* distance from the top of this track view to the region area
655 of our track view is always 1 */
659 /* convert to world coordinates, ie distance from the top of
662 rv->get_canvas_frame()->i2w (ix1, iy1);
664 /* compensate for the ruler section and the vertical scrollbar position */
665 iy1 += _editor->get_trackview_group_vertical_offset ();
669 // hide any dependent views
671 rv->get_time_axis_view().hide_dependent_views (*rv);
674 reparent to a non scrolling group so that we can keep the
675 region selection above all time axis views.
676 reparenting means we have to move the rv as the two
677 parent groups have different coordinates.
680 rv->get_canvas_group()->property_y() = iy1 - 1;
681 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
683 rv->fake_set_opaque (true);
686 /* current view for this particular region */
687 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
688 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
690 if (pointer_order_span != 0 && !clamp_y_axis) {
692 /* INTER-TRACK MOVEMENT */
694 /* move through the height list to the track that the region is currently on */
695 vector<int32_t>::iterator j = tavs.height_list.begin ();
697 while (j != tavs.height_list.end () && x != rtv->order ()) {
703 int32_t temp_pointer_order_span = canvas_pointer_order_span;
705 if (j != tavs.height_list.end ()) {
707 /* Account for layers in the original and
708 destination tracks. If we're moving around in layers we assume
709 that only one track is involved, so it's ok to use *pointer*
712 StreamView* lv = last_pointer_view->view ();
715 /* move to the top of the last trackview */
716 if (lv->layer_display () == Stacked) {
717 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
720 StreamView* cv = current_pointer_view->view ();
723 /* move to the right layer on the current trackview */
724 if (cv->layer_display () == Stacked) {
725 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
728 /* And for being on a non-topmost layer on the new
731 while (temp_pointer_order_span > 0) {
732 /* we're moving up canvas-wise,
733 so we need to find the next track height
735 if (j != tavs.height_list.begin()) {
739 if (x != last_pointer_order) {
741 ++temp_pointer_order_span;
746 temp_pointer_order_span--;
749 while (temp_pointer_order_span < 0) {
753 if (x != last_pointer_order) {
755 --temp_pointer_order_span;
759 if (j != tavs.height_list.end()) {
763 temp_pointer_order_span++;
767 /* find out where we'll be when we move and set height accordingly */
769 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
770 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
771 rv->set_height (temp_rtv->view()->child_height());
773 /* if you un-comment the following, the region colours will follow
774 the track colours whilst dragging; personally
775 i think this can confuse things, but never mind.
778 //const GdkColor& col (temp_rtv->view->get_region_color());
779 //rv->set_color (const_cast<GdkColor&>(col));
783 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
785 /* INTER-LAYER MOVEMENT in the same track */
786 y_delta = rtv->view()->child_height () * pointer_layer_span;
791 _editor->mouse_brush_insert_region (rv, pending_region_position);
793 rv->move (x_delta, y_delta);
796 } /* foreach region */
798 _total_x_delta += x_delta;
801 _editor->cursor_group->raise_to_top();
804 if (x_delta != 0 && !_brushing) {
805 _editor->show_verbose_time_cursor (_last_frame_position, 10);
810 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
812 if (_copy && first_move) {
813 copy_regions (event);
816 RegionMotionDrag::motion (event, first_move);
820 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
822 vector<RegionView*> copies;
823 boost::shared_ptr<Track> tr;
824 boost::shared_ptr<Playlist> from_playlist;
825 boost::shared_ptr<Playlist> to_playlist;
826 RegionSelection new_views;
827 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
828 PlaylistSet modified_playlists;
829 PlaylistSet frozen_playlists;
830 list <sigc::connection> modified_playlist_connections;
831 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
832 nframes64_t drag_delta;
833 bool changed_tracks, changed_position;
834 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
835 RouteTimeAxisView* source_tv;
836 vector<StatefulDiffCommand*> sdc;
838 if (!movement_occurred) {
844 /* all changes were made during motion event handlers */
847 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
848 copies.push_back (i->view);
855 /* reverse this here so that we have the correct logic to finalize
859 if (Config->get_edit_mode() == Lock) {
860 _x_constrained = !_x_constrained;
864 if (_x_constrained) {
865 _editor->begin_reversible_command (_("fixed time region copy"));
867 _editor->begin_reversible_command (_("region copy"));
870 if (_x_constrained) {
871 _editor->begin_reversible_command (_("fixed time region drag"));
873 _editor->begin_reversible_command (_("region drag"));
877 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
878 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
880 drag_delta = _primary->region()->position() - _last_frame_position;
882 _editor->update_canvas_now ();
884 /* make a list of where each region ended up */
885 final = find_time_axis_views_and_layers ();
887 cerr << "Iterate over " << _views.size() << " views\n";
889 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
891 RegionView* rv = i->view;
892 RouteTimeAxisView* dest_rtv = final[rv].first;
893 layer_t dest_layer = final[rv].second;
897 from_playlist.reset ();
898 to_playlist.reset ();
900 if (rv->region()->locked()) {
905 if (changed_position && !_x_constrained) {
906 where = rv->region()->position() - drag_delta;
908 where = rv->region()->position();
911 boost::shared_ptr<Region> new_region;
914 /* we already made a copy */
915 new_region = rv->region();
917 /* undo the previous hide_dependent_views so that xfades don't
918 disappear on copying regions
921 //rv->get_time_axis_view().reveal_dependent_views (*rv);
923 } else if (changed_tracks && dest_rtv->playlist()) {
924 new_region = RegionFactory::create (rv->region());
927 if (changed_tracks || _copy) {
929 to_playlist = dest_rtv->playlist();
936 _editor->latest_regionviews.clear ();
938 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
940 insert_result = modified_playlists.insert (to_playlist);
942 if (insert_result.second) {
943 to_playlist->clear_history ();
946 cerr << "To playlist " << to_playlist->name() << " region history contains "
947 << to_playlist->region_list().change().added.size() << " adds and "
948 << to_playlist->region_list().change().removed.size() << " removes\n";
950 cerr << "Adding new region " << new_region->id() << " based on "
951 << rv->region()->id() << endl;
953 to_playlist->add_region (new_region, where);
955 if (dest_rtv->view()->layer_display() == Stacked) {
956 new_region->set_layer (dest_layer);
957 new_region->set_pending_explicit_relayer (true);
962 if (!_editor->latest_regionviews.empty()) {
963 // XXX why just the first one ? we only expect one
964 // commented out in nick_m's canvas reworking. is that intended?
965 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
966 new_views.push_back (_editor->latest_regionviews.front());
970 rv->region()->clear_history ();
973 motion on the same track. plonk the previously reparented region
974 back to its original canvas group (its streamview).
975 No need to do anything for copies as they are fake regions which will be deleted.
978 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
979 rv->get_canvas_group()->property_y() = i->initial_y;
980 rv->get_time_axis_view().reveal_dependent_views (*rv);
982 /* just change the model */
984 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
986 if (dest_rtv->view()->layer_display() == Stacked) {
987 rv->region()->set_layer (dest_layer);
988 rv->region()->set_pending_explicit_relayer (true);
991 /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
993 frozen_insert_result = frozen_playlists.insert(playlist);
995 if (frozen_insert_result.second) {
999 cerr << "Moving region " << rv->region()->id() << endl;
1001 rv->region()->set_position (where, (void*) this);
1003 sdc.push_back (new StatefulDiffCommand (rv->region()));
1006 if (changed_tracks && !_copy) {
1008 /* get the playlist where this drag started. we can't use rv->region()->playlist()
1009 because we may have copied the region and it has not been attached to a playlist.
1012 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
1013 tr = source_tv->track();
1014 from_playlist = tr->playlist();
1018 assert (from_playlist);
1020 /* moved to a different audio track, without copying */
1022 /* the region that used to be in the old playlist is not
1023 moved to the new one - we use a copy of it. as a result,
1024 any existing editor for the region should no longer be
1028 rv->hide_region_editor();
1029 rv->fake_set_opaque (false);
1031 /* remove the region from the old playlist */
1033 insert_result = modified_playlists.insert (from_playlist);
1035 if (insert_result.second) {
1036 from_playlist->clear_history ();
1039 cerr << "From playlist " << from_playlist->name() << " region history contains "
1040 << from_playlist->region_list().change().added.size() << " adds and "
1041 << from_playlist->region_list().change().removed.size() << " removes\n";
1043 cerr << "removing region " << rv->region() << endl;
1045 from_playlist->remove_region (rv->region());
1047 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1048 was selected in all of them, then removing it from a playlist will have removed all
1049 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1050 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1051 corresponding regionview, and the selection is now empty).
1053 this could have invalidated any and all iterators into the region selection.
1055 the heuristic we use here is: if the region selection is empty, break out of the loop
1056 here. if the region selection is not empty, then restart the loop because we know that
1057 we must have removed at least the region(view) we've just been working on as well as any
1058 that we processed on previous iterations.
1060 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1061 we can just iterate.
1064 if (_views.empty()) {
1066 sdc.push_back (new StatefulDiffCommand (to_playlist));
1067 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1070 if (from_playlist && (from_playlist != to_playlist)) {
1071 sdc.push_back (new StatefulDiffCommand (from_playlist));
1072 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1084 copies.push_back (rv);
1087 cerr << "Done with TV, top = " << to_playlist << " from = " << from_playlist << endl;
1090 sdc.push_back (new StatefulDiffCommand (to_playlist));
1091 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1094 if (from_playlist && (from_playlist != to_playlist)) {
1095 sdc.push_back (new StatefulDiffCommand (from_playlist));
1096 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1101 if we've created new regions either by copying or moving
1102 to a new track, we want to replace the old selection with the new ones
1105 if (new_views.size() > 0) {
1106 _editor->selection->set (new_views);
1109 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1114 for (vector<StatefulDiffCommand*>::iterator i = sdc.begin(); i != sdc.end(); ++i) {
1115 _editor->session()->add_command (*i);
1118 _editor->commit_reversible_command ();
1120 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1126 RegionMoveDrag::aborted ()
1130 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1137 RegionMotionDrag::aborted ();
1142 RegionMotionDrag::aborted ()
1144 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1145 RegionView* rv = i->view;
1146 TimeAxisView* tv = &(rv->get_time_axis_view ());
1147 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1149 rv->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1150 rv->get_canvas_group()->property_y() = 0;
1151 rv->get_time_axis_view().reveal_dependent_views (*rv);
1152 rv->fake_set_opaque (false);
1153 rv->move (-_total_x_delta, 0);
1154 rv->set_height (rtv->view()->child_height ());
1157 _editor->update_canvas_now ();
1162 RegionMotionDrag::x_move_allowed () const
1164 if (Config->get_edit_mode() == Lock) {
1165 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1166 return _x_constrained;
1169 return !_x_constrained;
1173 RegionMotionDrag::copy_regions (GdkEvent* event)
1175 /* duplicate the regionview(s) and region(s) */
1177 list<DraggingView> new_regionviews;
1179 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1181 RegionView* rv = i->view;
1182 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1183 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1185 const boost::shared_ptr<const Region> original = rv->region();
1186 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1187 region_copy->set_position (original->position(), this);
1191 boost::shared_ptr<AudioRegion> audioregion_copy
1192 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1194 nrv = new AudioRegionView (*arv, audioregion_copy);
1196 boost::shared_ptr<MidiRegion> midiregion_copy
1197 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1198 nrv = new MidiRegionView (*mrv, midiregion_copy);
1203 nrv->get_canvas_group()->show ();
1204 new_regionviews.push_back (DraggingView (nrv));
1206 /* swap _primary to the copy */
1208 if (rv == _primary) {
1212 /* ..and deselect the one we copied */
1214 rv->set_selected (false);
1217 if (new_regionviews.empty()) {
1221 /* reflect the fact that we are dragging the copies */
1223 _views = new_regionviews;
1225 swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0);
1228 sync the canvas to what we think is its current state
1229 without it, the canvas seems to
1230 "forget" to update properly after the upcoming reparent()
1231 ..only if the mouse is in rapid motion at the time of the grab.
1232 something to do with regionview creation taking so long?
1234 _editor->update_canvas_now();
1238 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1240 /* Which trackview is this ? */
1242 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1243 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1244 (*layer) = tvp.second;
1246 if (*tv && (*tv)->layer_display() == Overlaid) {
1250 /* The region motion is only processed if the pointer is over
1254 if (!(*tv) || !(*tv)->is_track()) {
1255 /* To make sure we hide the verbose canvas cursor when the mouse is
1256 not held over and audiotrack.
1258 _editor->hide_verbose_canvas_cursor ();
1265 /** @param new_order New track order.
1266 * @param old_order Old track order.
1267 * @param visible_y_low Lowest visible order.
1268 * @return true if y movement should not happen, otherwise false.
1271 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1273 if (new_order != old_order) {
1275 /* this isn't the pointer track */
1279 /* moving up the canvas */
1280 if ( (new_order - y_span) >= tavs.visible_y_low) {
1284 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1285 int32_t visible_tracks = 0;
1286 while (visible_tracks < y_span ) {
1288 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1289 /* passing through a hidden track */
1294 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1295 /* moving to a non-track; disallow */
1301 /* moving beyond the lowest visible track; disallow */
1305 } else if (y_span < 0) {
1307 /* moving down the canvas */
1308 if ((new_order - y_span) <= tavs.visible_y_high) {
1310 int32_t visible_tracks = 0;
1312 while (visible_tracks > y_span ) {
1315 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1316 /* passing through a hidden track */
1321 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1322 /* moving to a non-track; disallow */
1329 /* moving beyond the highest visible track; disallow */
1336 /* this is the pointer's track */
1338 if ((new_order - y_span) > tavs.visible_y_high) {
1339 /* we will overflow */
1341 } else if ((new_order - y_span) < tavs.visible_y_low) {
1342 /* we will overflow */
1351 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1352 : RegionMotionDrag (e, i, p, v, b),
1355 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1357 _dest_trackview = tv;
1358 if (tv->layer_display() == Overlaid) {
1361 _dest_layer = _primary->region()->layer ();
1365 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1366 if (rtv && rtv->is_track()) {
1367 speed = rtv->track()->speed ();
1370 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1374 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1376 RegionMotionDrag::start_grab (event, c);
1378 _pointer_frame_offset = grab_frame() - _last_frame_position;
1381 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1382 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1384 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1385 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1387 _primary = v->view()->create_region_view (r, false, false);
1389 _primary->get_canvas_group()->show ();
1390 _primary->set_position (pos, 0);
1391 _views.push_back (DraggingView (_primary));
1393 _last_frame_position = pos;
1395 _item = _primary->get_canvas_group ();
1396 _dest_trackview = v;
1397 _dest_layer = _primary->region()->layer ();
1400 map<RegionView*, pair<RouteTimeAxisView*, int> >
1401 RegionMotionDrag::find_time_axis_views_and_layers ()
1403 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1405 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1407 double ix1, ix2, iy1, iy2;
1408 RegionView* rv = i->view;
1409 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1410 rv->get_canvas_frame()->i2w (ix1, iy1);
1411 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1413 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1414 tav[rv] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1422 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1424 _editor->update_canvas_now ();
1426 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1428 RouteTimeAxisView* dest_rtv = final[_primary].first;
1430 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1431 _primary->get_canvas_group()->property_y() = 0;
1433 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1435 _editor->begin_reversible_command (_("insert region"));
1436 playlist->clear_history ();
1437 playlist->add_region (_primary->region (), _last_frame_position);
1438 _editor->session()->add_command (new StatefulDiffCommand (playlist));
1439 _editor->commit_reversible_command ();
1447 RegionInsertDrag::aborted ()
1454 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1455 : RegionMoveDrag (e, i, p, v, false, false)
1460 struct RegionSelectionByPosition {
1461 bool operator() (RegionView*a, RegionView* b) {
1462 return a->region()->position () < b->region()->position();
1467 RegionSpliceDrag::motion (GdkEvent* event, bool)
1469 RouteTimeAxisView* tv;
1472 if (!check_possible (&tv, &layer)) {
1478 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1484 RegionSelection copy (_editor->selection->regions);
1486 RegionSelectionByPosition cmp;
1489 nframes64_t const pf = adjusted_current_frame (event);
1491 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1493 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1499 boost::shared_ptr<Playlist> playlist;
1501 if ((playlist = atv->playlist()) == 0) {
1505 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1510 if (pf < (*i)->region()->last_frame() + 1) {
1514 if (pf > (*i)->region()->first_frame()) {
1520 playlist->shuffle ((*i)->region(), dir);
1525 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1531 RegionSpliceDrag::aborted ()
1536 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1544 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1546 _dest_trackview = _view;
1548 Drag::start_grab (event);
1553 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1556 // TODO: create region-create-drag region view here
1559 // TODO: resize region-create-drag region view here
1563 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1565 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1571 if (!movement_occurred) {
1572 mtv->add_region (grab_frame ());
1574 motion (event, false);
1575 // TODO: create region-create-drag region here
1580 RegionCreateDrag::aborted ()
1585 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1593 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/)
1595 Gdk::Cursor* cursor;
1596 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1598 Drag::start_grab (event);
1600 region = &cnote->region_view();
1602 double const region_start = region->get_position_pixels();
1603 double const middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1605 if (grab_x() <= middle_point) {
1606 cursor = _editor->left_side_trim_cursor;
1609 cursor = _editor->right_side_trim_cursor;
1613 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, *cursor, event->motion.time);
1615 if (event->motion.state & Keyboard::PrimaryModifier) {
1621 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1623 if (ms.size() > 1) {
1624 /* has to be relative, may make no sense otherwise */
1628 /* select this note; if it is already selected, preserve the existing selection,
1629 otherwise make this note the only one selected.
1631 region->note_selected (cnote, cnote->selected ());
1633 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1634 MidiRegionSelection::iterator next;
1637 (*r)->begin_resizing (at_front);
1643 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1645 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1646 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1647 (*r)->update_resizing (dynamic_cast<ArdourCanvas::CanvasNote*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
1652 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1654 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1655 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1656 (*r)->commit_resizing (dynamic_cast<ArdourCanvas::CanvasNote*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
1661 NoteResizeDrag::aborted ()
1667 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1673 RegionGainDrag::finished (GdkEvent *, bool)
1679 RegionGainDrag::aborted ()
1684 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1685 : RegionDrag (e, i, p, v)
1686 , _have_transaction (false)
1692 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1695 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1696 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1698 if (tv && tv->is_track()) {
1699 speed = tv->track()->speed();
1702 nframes64_t const region_start = (nframes64_t) (_primary->region()->position() / speed);
1703 nframes64_t const region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1704 nframes64_t const region_length = (nframes64_t) (_primary->region()->length() / speed);
1706 nframes64_t const pf = adjusted_current_frame (event);
1708 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1709 _operation = ContentsTrim;
1710 Drag::start_grab (event, _editor->trimmer_cursor);
1712 /* These will get overridden for a point trim.*/
1713 if (pf < (region_start + region_length/2)) {
1714 /* closer to start */
1715 _operation = StartTrim;
1716 Drag::start_grab (event, _editor->left_side_trim_cursor);
1719 _operation = EndTrim;
1720 Drag::start_grab (event, _editor->right_side_trim_cursor);
1724 switch (_operation) {
1726 _editor->show_verbose_time_cursor (region_start, 10);
1729 _editor->show_verbose_time_cursor (region_end, 10);
1732 _editor->show_verbose_time_cursor (pf, 10);
1738 TrimDrag::motion (GdkEvent* event, bool first_move)
1740 RegionView* rv = _primary;
1742 /* snap modifier works differently here..
1743 its current state has to be passed to the
1744 various trim functions in order to work properly
1748 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1749 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1750 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1752 if (tv && tv->is_track()) {
1753 speed = tv->track()->speed();
1756 nframes64_t const pf = adjusted_current_frame (event);
1762 switch (_operation) {
1764 trim_type = "Region start trim";
1767 trim_type = "Region end trim";
1770 trim_type = "Region content trim";
1774 _editor->begin_reversible_command (trim_type);
1775 _have_transaction = true;
1777 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1778 RegionView* rv = i->view;
1779 rv->fake_set_opaque(false);
1780 rv->enable_display (false);
1781 rv->region()->clear_history ();
1782 rv->region()->suspend_property_changes ();
1784 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
1787 arv->temporarily_hide_envelope ();
1790 boost::shared_ptr<Playlist> pl = rv->region()->playlist();
1791 insert_result = _editor->motion_frozen_playlists.insert (pl);
1793 if (insert_result.second) {
1799 bool non_overlap_trim = false;
1801 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1802 non_overlap_trim = true;
1805 switch (_operation) {
1807 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1808 _editor->single_start_trim (*i->view, pf, non_overlap_trim);
1813 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1814 _editor->single_end_trim (*i->view, pf, non_overlap_trim);
1820 bool swap_direction = false;
1822 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1823 swap_direction = true;
1826 nframes64_t frame_delta = 0;
1828 bool left_direction = false;
1829 if (last_pointer_frame() > pf) {
1830 left_direction = true;
1833 if (left_direction) {
1834 frame_delta = (last_pointer_frame() - pf);
1836 frame_delta = (pf - last_pointer_frame());
1839 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1840 _editor->single_contents_trim (*i->view, frame_delta, left_direction, swap_direction);
1846 switch (_operation) {
1848 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1851 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1854 _editor->show_verbose_time_cursor (pf, 10);
1861 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1863 if (movement_occurred) {
1864 motion (event, false);
1866 if (!_editor->selection->selected (_primary)) {
1867 _editor->thaw_region_after_trim (*_primary);
1870 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1871 _editor->thaw_region_after_trim (*i->view);
1872 i->view->enable_display (true);
1873 i->view->fake_set_opaque (true);
1874 if (_have_transaction) {
1875 _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
1879 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1883 _editor->motion_frozen_playlists.clear ();
1885 if (_have_transaction) {
1886 _editor->commit_reversible_command();
1890 /* no mouse movement */
1891 _editor->point_trim (event, adjusted_current_frame (event));
1896 TrimDrag::aborted ()
1898 /* Our motion method is changing model state, so use the Undo system
1899 to cancel. Perhaps not ideal, as this will leave an Undo point
1900 behind which may be slightly odd from the user's point of view.
1905 if (_have_transaction) {
1910 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1914 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1919 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1922 // create a dummy marker for visual representation of moving the copy.
1923 // The actual copying is not done before we reach the finish callback.
1925 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1926 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1927 *new MeterSection (_marker->meter()));
1929 _item = &new_marker->the_item ();
1930 _marker = new_marker;
1934 MetricSection& section (_marker->meter());
1936 if (!section.movable()) {
1942 Drag::start_grab (event, cursor);
1944 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1946 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1950 MeterMarkerDrag::motion (GdkEvent* event, bool)
1952 nframes64_t const pf = adjusted_current_frame (event);
1954 _marker->set_position (pf);
1956 _editor->show_verbose_time_cursor (pf, 10);
1960 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1962 if (!movement_occurred) {
1966 motion (event, false);
1970 TempoMap& map (_editor->session()->tempo_map());
1971 map.bbt_time (last_pointer_frame(), when);
1973 if (_copy == true) {
1974 _editor->begin_reversible_command (_("copy meter mark"));
1975 XMLNode &before = map.get_state();
1976 map.add_meter (_marker->meter(), when);
1977 XMLNode &after = map.get_state();
1978 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1979 _editor->commit_reversible_command ();
1981 // delete the dummy marker we used for visual representation of copying.
1982 // a new visual marker will show up automatically.
1985 _editor->begin_reversible_command (_("move meter mark"));
1986 XMLNode &before = map.get_state();
1987 map.move_meter (_marker->meter(), when);
1988 XMLNode &after = map.get_state();
1989 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1990 _editor->commit_reversible_command ();
1995 MeterMarkerDrag::aborted ()
1997 _marker->set_position (_marker->meter().frame ());
2000 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
2004 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
2009 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2014 // create a dummy marker for visual representation of moving the copy.
2015 // The actual copying is not done before we reach the finish callback.
2017 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
2018 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
2019 *new TempoSection (_marker->tempo()));
2021 _item = &new_marker->the_item ();
2022 _marker = new_marker;
2026 MetricSection& section (_marker->tempo());
2028 if (!section.movable()) {
2033 Drag::start_grab (event, cursor);
2035 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
2036 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2040 TempoMarkerDrag::motion (GdkEvent* event, bool)
2042 nframes64_t const pf = adjusted_current_frame (event);
2043 _marker->set_position (pf);
2044 _editor->show_verbose_time_cursor (pf, 10);
2048 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2050 if (!movement_occurred) {
2054 motion (event, false);
2058 TempoMap& map (_editor->session()->tempo_map());
2059 map.bbt_time (last_pointer_frame(), when);
2061 if (_copy == true) {
2062 _editor->begin_reversible_command (_("copy tempo mark"));
2063 XMLNode &before = map.get_state();
2064 map.add_tempo (_marker->tempo(), when);
2065 XMLNode &after = map.get_state();
2066 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2067 _editor->commit_reversible_command ();
2069 // delete the dummy marker we used for visual representation of copying.
2070 // a new visual marker will show up automatically.
2073 _editor->begin_reversible_command (_("move tempo mark"));
2074 XMLNode &before = map.get_state();
2075 map.move_tempo (_marker->tempo(), when);
2076 XMLNode &after = map.get_state();
2077 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2078 _editor->commit_reversible_command ();
2083 TempoMarkerDrag::aborted ()
2085 _marker->set_position (_marker->tempo().frame());
2088 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2092 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2097 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2099 Drag::start_grab (event, c);
2103 nframes64_t where = _editor->event_frame (event, 0, 0);
2105 _editor->snap_to_with_modifier (where, event);
2106 _editor->playhead_cursor->set_position (where);
2110 if (_cursor == _editor->playhead_cursor) {
2111 _editor->_dragging_playhead = true;
2113 Session* s = _editor->session ();
2116 if (_was_rolling && _stop) {
2120 if (s->is_auditioning()) {
2121 s->cancel_audition ();
2124 s->request_suspend_timecode_transmission ();
2126 if (s->timecode_transmission_suspended ()) {
2127 nframes64_t const f = _editor->playhead_cursor->current_frame;
2128 s->send_mmc_locate (f);
2129 s->send_full_time_code (f);
2134 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2136 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2140 CursorDrag::motion (GdkEvent* event, bool)
2142 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2144 if (adjusted_frame == last_pointer_frame()) {
2148 _cursor->set_position (adjusted_frame);
2150 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2152 Session* s = _editor->session ();
2153 if (s && _item == &_editor->playhead_cursor->canvas_item && s->timecode_transmission_suspended ()) {
2154 nframes64_t const f = _editor->playhead_cursor->current_frame;
2155 s->send_mmc_locate (f);
2156 s->send_full_time_code (f);
2161 _editor->update_canvas_now ();
2163 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2167 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2169 _editor->_dragging_playhead = false;
2171 if (!movement_occurred && _stop) {
2175 motion (event, false);
2177 if (_item == &_editor->playhead_cursor->canvas_item) {
2178 Session* s = _editor->session ();
2180 s->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2181 _editor->_pending_locate_request = true;
2182 s->request_resume_timecode_transmission ();
2188 CursorDrag::aborted ()
2190 if (_editor->_dragging_playhead) {
2191 _editor->session()->request_resume_timecode_transmission ();
2192 _editor->_dragging_playhead = false;
2195 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2198 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2199 : RegionDrag (e, i, p, v)
2205 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2207 Drag::start_grab (event, cursor);
2209 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2210 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2212 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2213 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2218 FadeInDrag::motion (GdkEvent* event, bool)
2220 nframes64_t fade_length;
2222 nframes64_t const pos = adjusted_current_frame (event);
2224 boost::shared_ptr<Region> region = _primary->region ();
2226 if (pos < (region->position() + 64)) {
2227 fade_length = 64; // this should be a minimum defined somewhere
2228 } else if (pos > region->last_frame()) {
2229 fade_length = region->length();
2231 fade_length = pos - region->position();
2234 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2236 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2242 tmp->reset_fade_in_shape_width (fade_length);
2245 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2249 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2251 if (!movement_occurred) {
2255 nframes64_t fade_length;
2257 nframes64_t const pos = adjusted_current_frame (event);
2259 boost::shared_ptr<Region> region = _primary->region ();
2261 if (pos < (region->position() + 64)) {
2262 fade_length = 64; // this should be a minimum defined somewhere
2263 } else if (pos > region->last_frame()) {
2264 fade_length = region->length();
2266 fade_length = pos - region->position();
2269 _editor->begin_reversible_command (_("change fade in length"));
2271 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2273 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2279 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2280 XMLNode &before = alist->get_state();
2282 tmp->audio_region()->set_fade_in_length (fade_length);
2283 tmp->audio_region()->set_fade_in_active (true);
2285 XMLNode &after = alist->get_state();
2286 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2289 _editor->commit_reversible_command ();
2293 FadeInDrag::aborted ()
2295 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2296 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2302 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2306 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2307 : RegionDrag (e, i, p, v)
2313 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2315 Drag::start_grab (event, cursor);
2317 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2318 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2320 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2321 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2325 FadeOutDrag::motion (GdkEvent* event, bool)
2327 nframes64_t fade_length;
2329 nframes64_t const pos = adjusted_current_frame (event);
2331 boost::shared_ptr<Region> region = _primary->region ();
2333 if (pos > (region->last_frame() - 64)) {
2334 fade_length = 64; // this should really be a minimum fade defined somewhere
2336 else if (pos < region->position()) {
2337 fade_length = region->length();
2340 fade_length = region->last_frame() - pos;
2343 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2345 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2351 tmp->reset_fade_out_shape_width (fade_length);
2354 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2358 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2360 if (!movement_occurred) {
2364 nframes64_t fade_length;
2366 nframes64_t const pos = adjusted_current_frame (event);
2368 boost::shared_ptr<Region> region = _primary->region ();
2370 if (pos > (region->last_frame() - 64)) {
2371 fade_length = 64; // this should really be a minimum fade defined somewhere
2373 else if (pos < region->position()) {
2374 fade_length = region->length();
2377 fade_length = region->last_frame() - pos;
2380 _editor->begin_reversible_command (_("change fade out length"));
2382 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2384 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2390 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2391 XMLNode &before = alist->get_state();
2393 tmp->audio_region()->set_fade_out_length (fade_length);
2394 tmp->audio_region()->set_fade_out_active (true);
2396 XMLNode &after = alist->get_state();
2397 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2400 _editor->commit_reversible_command ();
2404 FadeOutDrag::aborted ()
2406 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2407 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2413 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2417 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2420 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2423 _points.push_back (Gnome::Art::Point (0, 0));
2424 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2426 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2427 _line->property_width_pixels() = 1;
2428 _line->property_points () = _points;
2431 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2434 MarkerDrag::~MarkerDrag ()
2436 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2442 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2444 Drag::start_grab (event, cursor);
2448 Location *location = _editor->find_location_from_marker (_marker, is_start);
2449 _editor->_dragging_edit_point = true;
2451 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2453 update_item (location);
2455 // _drag_line->show();
2456 // _line->raise_to_top();
2459 _editor->show_verbose_time_cursor (location->start(), 10);
2461 _editor->show_verbose_time_cursor (location->end(), 10);
2464 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2467 case Selection::Toggle:
2468 _editor->selection->toggle (_marker);
2470 case Selection::Set:
2471 if (!_editor->selection->selected (_marker)) {
2472 _editor->selection->set (_marker);
2475 case Selection::Extend:
2477 Locations::LocationList ll;
2478 list<Marker*> to_add;
2480 _editor->selection->markers.range (s, e);
2481 s = min (_marker->position(), s);
2482 e = max (_marker->position(), e);
2485 if (e < max_frames) {
2488 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2489 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2490 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2493 to_add.push_back (lm->start);
2496 to_add.push_back (lm->end);
2500 if (!to_add.empty()) {
2501 _editor->selection->add (to_add);
2505 case Selection::Add:
2506 _editor->selection->add (_marker);
2510 /* Set up copies for us to manipulate during the drag */
2512 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2513 Location* l = _editor->find_location_from_marker (*i, is_start);
2514 _copied_locations.push_back (new Location (*l));
2519 MarkerDrag::motion (GdkEvent* event, bool)
2521 nframes64_t f_delta = 0;
2523 bool move_both = false;
2525 Location *real_location;
2526 Location *copy_location = 0;
2528 nframes64_t const newframe = adjusted_current_frame (event);
2530 nframes64_t next = newframe;
2532 if (newframe == last_pointer_frame()) {
2536 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2540 MarkerSelection::iterator i;
2541 list<Location*>::iterator x;
2543 /* find the marker we're dragging, and compute the delta */
2545 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2546 x != _copied_locations.end() && i != _editor->selection->markers.end();
2552 if (marker == _marker) {
2554 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2559 if (real_location->is_mark()) {
2560 f_delta = newframe - copy_location->start();
2564 switch (marker->type()) {
2566 case Marker::LoopStart:
2567 case Marker::PunchIn:
2568 f_delta = newframe - copy_location->start();
2572 case Marker::LoopEnd:
2573 case Marker::PunchOut:
2574 f_delta = newframe - copy_location->end();
2577 /* what kind of marker is this ? */
2585 if (i == _editor->selection->markers.end()) {
2586 /* hmm, impossible - we didn't find the dragged marker */
2590 /* now move them all */
2592 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2593 x != _copied_locations.end() && i != _editor->selection->markers.end();
2599 /* call this to find out if its the start or end */
2601 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2605 if (real_location->locked()) {
2609 if (copy_location->is_mark()) {
2613 copy_location->set_start (copy_location->start() + f_delta);
2617 nframes64_t new_start = copy_location->start() + f_delta;
2618 nframes64_t new_end = copy_location->end() + f_delta;
2620 if (is_start) { // start-of-range marker
2623 copy_location->set_start (new_start);
2624 copy_location->set_end (new_end);
2625 } else if (new_start < copy_location->end()) {
2626 copy_location->set_start (new_start);
2628 _editor->snap_to (next, 1, true);
2629 copy_location->set_end (next);
2630 copy_location->set_start (newframe);
2633 } else { // end marker
2636 copy_location->set_end (new_end);
2637 copy_location->set_start (new_start);
2638 } else if (new_end > copy_location->start()) {
2639 copy_location->set_end (new_end);
2640 } else if (newframe > 0) {
2641 _editor->snap_to (next, -1, true);
2642 copy_location->set_start (next);
2643 copy_location->set_end (newframe);
2648 update_item (copy_location);
2650 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2653 lm->set_position (copy_location->start(), copy_location->end());
2657 assert (!_copied_locations.empty());
2659 _editor->show_verbose_time_cursor (newframe, 10);
2662 _editor->update_canvas_now ();
2667 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2669 if (!movement_occurred) {
2671 /* just a click, do nothing but finish
2672 off the selection process
2675 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2678 case Selection::Set:
2679 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2680 _editor->selection->set (_marker);
2684 case Selection::Toggle:
2685 case Selection::Extend:
2686 case Selection::Add:
2693 _editor->_dragging_edit_point = false;
2695 _editor->begin_reversible_command ( _("move marker") );
2696 XMLNode &before = _editor->session()->locations()->get_state();
2698 MarkerSelection::iterator i;
2699 list<Location*>::iterator x;
2702 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2703 x != _copied_locations.end() && i != _editor->selection->markers.end();
2706 Location * location = _editor->find_location_from_marker (*i, is_start);
2710 if (location->locked()) {
2714 if (location->is_mark()) {
2715 location->set_start ((*x)->start());
2717 location->set ((*x)->start(), (*x)->end());
2722 XMLNode &after = _editor->session()->locations()->get_state();
2723 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2724 _editor->commit_reversible_command ();
2730 MarkerDrag::aborted ()
2736 MarkerDrag::update_item (Location* location)
2738 double const x1 = _editor->frame_to_pixel (location->start());
2740 _points.front().set_x(x1);
2741 _points.back().set_x(x1);
2742 _line->property_points() = _points;
2745 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2747 _cumulative_x_drag (0),
2748 _cumulative_y_drag (0)
2750 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2756 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2758 Drag::start_grab (event, _editor->fader_cursor);
2760 // start the grab at the center of the control point so
2761 // the point doesn't 'jump' to the mouse after the first drag
2762 _time_axis_view_grab_x = _point->get_x();
2763 _time_axis_view_grab_y = _point->get_y();
2765 float const fraction = 1 - (_point->get_y() / _point->line().height());
2767 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2769 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2770 event->button.x + 10, event->button.y + 10);
2772 _editor->show_verbose_canvas_cursor ();
2776 ControlPointDrag::motion (GdkEvent* event, bool)
2778 double dx = _drags->current_pointer_x() - last_pointer_x();
2779 double dy = _drags->current_pointer_y() - last_pointer_y();
2781 if (event->button.state & Keyboard::SecondaryModifier) {
2786 /* coordinate in TimeAxisView's space */
2787 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2788 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2790 // calculate zero crossing point. back off by .01 to stay on the
2791 // positive side of zero
2792 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2794 // make sure we hit zero when passing through
2795 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2799 if (_x_constrained) {
2800 cx = _time_axis_view_grab_x;
2802 if (_y_constrained) {
2803 cy = _time_axis_view_grab_y;
2806 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2807 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2811 cy = min ((double) _point->line().height(), cy);
2813 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2815 if (!_x_constrained) {
2816 _editor->snap_to_with_modifier (cx_frames, event);
2819 float const fraction = 1.0 - (cy / _point->line().height());
2821 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2823 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2825 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2829 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2831 if (!movement_occurred) {
2835 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2836 _editor->reset_point_selection ();
2840 motion (event, false);
2842 _point->line().end_drag ();
2846 ControlPointDrag::aborted ()
2848 _point->line().reset ();
2852 ControlPointDrag::active (Editing::MouseMode m)
2854 if (m == Editing::MouseGain) {
2855 /* always active in mouse gain */
2859 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2860 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2863 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2866 _cumulative_y_drag (0)
2871 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2873 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2876 _item = &_line->grab_item ();
2878 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2879 origin, and ditto for y.
2882 double cx = event->button.x;
2883 double cy = event->button.y;
2885 _line->parent_group().w2i (cx, cy);
2887 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2892 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2893 /* no adjacent points */
2897 Drag::start_grab (event, _editor->fader_cursor);
2899 /* store grab start in parent frame */
2901 _time_axis_view_grab_x = cx;
2902 _time_axis_view_grab_y = cy;
2904 double fraction = 1.0 - (cy / _line->height());
2906 _line->start_drag_line (before, after, fraction);
2908 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2909 event->button.x + 10, event->button.y + 10);
2911 _editor->show_verbose_canvas_cursor ();
2915 LineDrag::motion (GdkEvent* event, bool)
2917 double dy = _drags->current_pointer_y() - last_pointer_y();
2919 if (event->button.state & Keyboard::SecondaryModifier) {
2923 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2925 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2928 cy = min ((double) _line->height(), cy);
2930 double const fraction = 1.0 - (cy / _line->height());
2934 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2940 /* we are ignoring x position for this drag, so we can just pass in anything */
2941 _line->drag_motion (0, fraction, true, push);
2943 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2947 LineDrag::finished (GdkEvent* event, bool)
2949 motion (event, false);
2954 LineDrag::aborted ()
2959 FeatureLineDrag::FeatureLineDrag (Editor* e, ArdourCanvas::Item* i)
2962 _cumulative_x_drag (0)
2967 FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2970 Drag::start_grab (event);
2972 _line = reinterpret_cast<SimpleLine*> (_item);
2975 /* need to get x coordinate in terms of parent (AudioRegionView) origin. */
2977 double cx = event->button.x;
2978 double cy = event->button.y;
2980 _item->property_parent().get_value()->w2i(cx, cy);
2982 /* store grab start in parent frame */
2983 _region_view_grab_x = cx;
2985 _before = _line->property_x1();
2987 _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
2989 _max_x = _editor->frame_to_pixel(_arv->get_duration());
2993 FeatureLineDrag::motion (GdkEvent* event, bool)
2995 double dx = _drags->current_pointer_x() - last_pointer_x();
2997 double cx = _region_view_grab_x + _cumulative_x_drag + dx;
2999 _cumulative_x_drag += dx;
3001 /* Clamp the min and max extent of the drag to keep it within the region view bounds */
3010 _line->property_x1() = cx;
3011 _line->property_x2() = cx;
3013 _before = _line->property_x1();
3017 FeatureLineDrag::finished (GdkEvent* event, bool)
3019 _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
3020 _arv->update_transient(_before, _line->property_x1());
3024 FeatureLineDrag::aborted ()
3030 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3032 Drag::start_grab (event);
3033 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3037 RubberbandSelectDrag::motion (GdkEvent* event, bool)
3044 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
3046 nframes64_t grab = grab_frame ();
3047 if (Config->get_rubberbanding_snaps_to_grid ()) {
3048 _editor->snap_to_with_modifier (grab, event);
3051 /* base start and end on initial click position */
3061 if (_drags->current_pointer_y() < grab_y()) {
3062 y1 = _drags->current_pointer_y();
3065 y2 = _drags->current_pointer_y();
3070 if (start != end || y1 != y2) {
3072 double x1 = _editor->frame_to_pixel (start);
3073 double x2 = _editor->frame_to_pixel (end);
3075 _editor->rubberband_rect->property_x1() = x1;
3076 _editor->rubberband_rect->property_y1() = y1;
3077 _editor->rubberband_rect->property_x2() = x2;
3078 _editor->rubberband_rect->property_y2() = y2;
3080 _editor->rubberband_rect->show();
3081 _editor->rubberband_rect->raise_to_top();
3083 _editor->show_verbose_time_cursor (pf, 10);
3088 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
3090 if (movement_occurred) {
3092 motion (event, false);
3095 if (_drags->current_pointer_y() < grab_y()) {
3096 y1 = _drags->current_pointer_y();
3099 y2 = _drags->current_pointer_y();
3104 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
3107 _editor->begin_reversible_command (_("rubberband selection"));
3109 if (grab_frame() < last_pointer_frame()) {
3110 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
3112 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
3116 _editor->commit_reversible_command ();
3120 if (!getenv("ARDOUR_SAE")) {
3121 _editor->selection->clear_tracks();
3123 _editor->selection->clear_regions();
3124 _editor->selection->clear_points ();
3125 _editor->selection->clear_lines ();
3128 _editor->rubberband_rect->hide();
3132 RubberbandSelectDrag::aborted ()
3134 _editor->rubberband_rect->hide ();
3138 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3140 Drag::start_grab (event);
3142 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3146 TimeFXDrag::motion (GdkEvent* event, bool)
3148 RegionView* rv = _primary;
3150 nframes64_t const pf = adjusted_current_frame (event);
3152 if (pf > rv->region()->position()) {
3153 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3156 _editor->show_verbose_time_cursor (pf, 10);
3160 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3162 _primary->get_time_axis_view().hide_timestretch ();
3164 if (!movement_occurred) {
3168 if (last_pointer_frame() < _primary->region()->position()) {
3169 /* backwards drag of the left edge - not usable */
3173 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3175 float percentage = (double) newlen / (double) _primary->region()->length();
3177 #ifndef USE_RUBBERBAND
3178 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3179 if (_primary->region()->data_type() == DataType::AUDIO) {
3180 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3184 _editor->begin_reversible_command (_("timestretch"));
3186 // XXX how do timeFX on multiple regions ?
3191 if (_editor->time_stretch (rs, percentage) == -1) {
3192 error << _("An error occurred while executing time stretch operation") << endmsg;
3197 TimeFXDrag::aborted ()
3199 _primary->get_time_axis_view().hide_timestretch ();
3204 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3206 Drag::start_grab (event);
3210 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3212 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3216 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3218 if (movement_occurred && _editor->session()) {
3219 /* make sure we stop */
3220 _editor->session()->request_transport_speed (0.0);
3225 ScrubDrag::aborted ()
3230 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3234 , _original_pointer_time_axis (-1)
3235 , _last_pointer_time_axis (-1)
3241 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3243 nframes64_t start = 0;
3244 nframes64_t end = 0;
3246 if (_editor->session() == 0) {
3250 Gdk::Cursor* cursor = 0;
3252 switch (_operation) {
3253 case CreateSelection:
3254 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3259 cursor = _editor->selector_cursor;
3260 Drag::start_grab (event, cursor);
3263 case SelectionStartTrim:
3264 if (_editor->clicked_axisview) {
3265 _editor->clicked_axisview->order_selection_trims (_item, true);
3267 Drag::start_grab (event, _editor->left_side_trim_cursor);
3268 start = _editor->selection->time[_editor->clicked_selection].start;
3269 _pointer_frame_offset = grab_frame() - start;
3272 case SelectionEndTrim:
3273 if (_editor->clicked_axisview) {
3274 _editor->clicked_axisview->order_selection_trims (_item, false);
3276 Drag::start_grab (event, _editor->right_side_trim_cursor);
3277 end = _editor->selection->time[_editor->clicked_selection].end;
3278 _pointer_frame_offset = grab_frame() - end;
3282 start = _editor->selection->time[_editor->clicked_selection].start;
3283 Drag::start_grab (event, cursor);
3284 _pointer_frame_offset = grab_frame() - start;
3288 if (_operation == SelectionMove) {
3289 _editor->show_verbose_time_cursor (start, 10);
3291 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3294 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3298 SelectionDrag::motion (GdkEvent* event, bool first_move)
3300 nframes64_t start = 0;
3301 nframes64_t end = 0;
3304 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3305 if (pending_time_axis.first == 0) {
3309 nframes64_t const pending_position = adjusted_current_frame (event);
3311 /* only alter selection if things have changed */
3313 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3317 switch (_operation) {
3318 case CreateSelection:
3320 nframes64_t grab = grab_frame ();
3323 _editor->snap_to (grab);
3326 if (pending_position < grab_frame()) {
3327 start = pending_position;
3330 end = pending_position;
3334 /* first drag: Either add to the selection
3335 or create a new selection
3341 /* adding to the selection */
3342 _editor->selection->add (_editor->clicked_axisview);
3343 _editor->clicked_selection = _editor->selection->add (start, end);
3348 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
3349 _editor->selection->set (_editor->clicked_axisview);
3352 _editor->clicked_selection = _editor->selection->set (start, end);
3356 /* select the track that we're in */
3357 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3358 _editor->selection->add (pending_time_axis.first);
3359 _added_time_axes.push_back (pending_time_axis.first);
3362 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3363 tracks that we selected in the first place.
3366 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3367 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3369 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3370 while (i != _added_time_axes.end()) {
3372 list<TimeAxisView*>::iterator tmp = i;
3375 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3376 _editor->selection->remove (*i);
3377 _added_time_axes.remove (*i);
3386 case SelectionStartTrim:
3388 start = _editor->selection->time[_editor->clicked_selection].start;
3389 end = _editor->selection->time[_editor->clicked_selection].end;
3391 if (pending_position > end) {
3394 start = pending_position;
3398 case SelectionEndTrim:
3400 start = _editor->selection->time[_editor->clicked_selection].start;
3401 end = _editor->selection->time[_editor->clicked_selection].end;
3403 if (pending_position < start) {
3406 end = pending_position;
3413 start = _editor->selection->time[_editor->clicked_selection].start;
3414 end = _editor->selection->time[_editor->clicked_selection].end;
3416 length = end - start;
3418 start = pending_position;
3419 _editor->snap_to (start);
3421 end = start + length;
3426 if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
3427 _editor->start_canvas_autoscroll (1, 0);
3431 _editor->selection->replace (_editor->clicked_selection, start, end);
3434 if (_operation == SelectionMove) {
3435 _editor->show_verbose_time_cursor(start, 10);
3437 _editor->show_verbose_time_cursor(pending_position, 10);
3442 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3444 Session* s = _editor->session();
3446 if (movement_occurred) {
3447 motion (event, false);
3448 /* XXX this is not object-oriented programming at all. ick */
3449 if (_editor->selection->time.consolidate()) {
3450 _editor->selection->TimeChanged ();
3453 /* XXX what if its a music time selection? */
3454 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3455 s->request_play_range (&_editor->selection->time, true);
3460 /* just a click, no pointer movement.*/
3462 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3463 _editor->selection->clear_time();
3466 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
3467 _editor->selection->set (_editor->clicked_axisview);
3470 if (s && s->get_play_range () && s->transport_rolling()) {
3471 s->request_stop (false, false);
3476 _editor->stop_canvas_autoscroll ();
3480 SelectionDrag::aborted ()
3485 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3490 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3491 _drag_rect->hide ();
3493 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3494 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3498 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3500 if (_editor->session() == 0) {
3504 Gdk::Cursor* cursor = 0;
3506 if (!_editor->temp_location) {
3507 _editor->temp_location = new Location;
3510 switch (_operation) {
3511 case CreateRangeMarker:
3512 case CreateTransportMarker:
3513 case CreateCDMarker:
3515 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3520 cursor = _editor->selector_cursor;
3524 Drag::start_grab (event, cursor);
3526 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3530 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3532 nframes64_t start = 0;
3533 nframes64_t end = 0;
3534 ArdourCanvas::SimpleRect *crect;
3536 switch (_operation) {
3537 case CreateRangeMarker:
3538 crect = _editor->range_bar_drag_rect;
3540 case CreateTransportMarker:
3541 crect = _editor->transport_bar_drag_rect;
3543 case CreateCDMarker:
3544 crect = _editor->cd_marker_bar_drag_rect;
3547 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3552 nframes64_t const pf = adjusted_current_frame (event);
3554 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3555 nframes64_t grab = grab_frame ();
3556 _editor->snap_to (grab);
3558 if (pf < grab_frame()) {
3566 /* first drag: Either add to the selection
3567 or create a new selection.
3572 _editor->temp_location->set (start, end);
3576 update_item (_editor->temp_location);
3578 //_drag_rect->raise_to_top();
3583 if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
3584 _editor->start_canvas_autoscroll (1, 0);
3588 _editor->temp_location->set (start, end);
3590 double x1 = _editor->frame_to_pixel (start);
3591 double x2 = _editor->frame_to_pixel (end);
3592 crect->property_x1() = x1;
3593 crect->property_x2() = x2;
3595 update_item (_editor->temp_location);
3598 _editor->show_verbose_time_cursor (pf, 10);
3603 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3605 Location * newloc = 0;
3609 if (movement_occurred) {
3610 motion (event, false);
3613 switch (_operation) {
3614 case CreateRangeMarker:
3615 case CreateCDMarker:
3617 _editor->begin_reversible_command (_("new range marker"));
3618 XMLNode &before = _editor->session()->locations()->get_state();
3619 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3620 if (_operation == CreateCDMarker) {
3621 flags = Location::IsRangeMarker | Location::IsCDMarker;
3622 _editor->cd_marker_bar_drag_rect->hide();
3625 flags = Location::IsRangeMarker;
3626 _editor->range_bar_drag_rect->hide();
3628 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3629 _editor->session()->locations()->add (newloc, true);
3630 XMLNode &after = _editor->session()->locations()->get_state();
3631 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3632 _editor->commit_reversible_command ();
3636 case CreateTransportMarker:
3637 // popup menu to pick loop or punch
3638 _editor->new_transport_marker_context_menu (&event->button, _item);
3642 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3644 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3649 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3651 if (end == max_frames) {
3652 end = _editor->session()->current_end_frame ();
3655 if (start == max_frames) {
3656 start = _editor->session()->current_start_frame ();
3659 switch (_editor->mouse_mode) {
3661 /* find the two markers on either side and then make the selection from it */
3662 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3666 /* find the two markers on either side of the click and make the range out of it */
3667 _editor->selection->set (start, end);
3676 _editor->stop_canvas_autoscroll ();
3680 RangeMarkerBarDrag::aborted ()
3686 RangeMarkerBarDrag::update_item (Location* location)
3688 double const x1 = _editor->frame_to_pixel (location->start());
3689 double const x2 = _editor->frame_to_pixel (location->end());
3691 _drag_rect->property_x1() = x1;
3692 _drag_rect->property_x2() = x2;
3696 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3698 Drag::start_grab (event, _editor->zoom_cursor);
3699 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3703 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3708 nframes64_t const pf = adjusted_current_frame (event);
3710 nframes64_t grab = grab_frame ();
3711 _editor->snap_to_with_modifier (grab, event);
3713 /* base start and end on initial click position */
3725 _editor->zoom_rect->show();
3726 _editor->zoom_rect->raise_to_top();
3729 _editor->reposition_zoom_rect(start, end);
3731 _editor->show_verbose_time_cursor (pf, 10);
3736 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3738 if (movement_occurred) {
3739 motion (event, false);
3741 if (grab_frame() < last_pointer_frame()) {
3742 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3744 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3747 _editor->temporal_zoom_to_frame (false, grab_frame());
3749 temporal_zoom_step (false);
3750 center_screen (grab_frame());
3754 _editor->zoom_rect->hide();
3758 MouseZoomDrag::aborted ()
3760 _editor->zoom_rect->hide ();
3763 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3766 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3767 region = &cnote->region_view();
3771 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3773 Drag::start_grab (event);
3776 drag_delta_note = 0;
3781 event_x = _drags->current_pointer_x();
3782 event_y = _drags->current_pointer_y();
3784 _item->property_parent().get_value()->w2i(event_x, event_y);
3786 last_x = region->snap_to_pixel(event_x);
3789 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3791 if (!(was_selected = cnote->selected())) {
3793 /* tertiary-click means extend selection - we'll do that on button release,
3794 so don't add it here, because otherwise we make it hard to figure
3795 out the "extend-to" range.
3798 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3801 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3804 region->note_selected (cnote, true);
3806 region->unique_select (cnote);
3813 NoteDrag::motion (GdkEvent*, bool)
3815 MidiStreamView* streamview = region->midi_stream_view();
3819 event_x = _drags->current_pointer_x();
3820 event_y = _drags->current_pointer_y();
3822 _item->property_parent().get_value()->w2i(event_x, event_y);
3824 event_x = region->snap_to_pixel(event_x);
3826 double dx = event_x - last_x;
3827 double dy = event_y - last_y;
3832 // Snap to note rows
3834 if (abs (dy) < streamview->note_height()) {
3837 int8_t this_delta_note;
3839 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3841 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3843 drag_delta_note -= this_delta_note;
3844 dy = streamview->note_height() * this_delta_note;
3845 last_y = last_y + dy;
3850 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3851 Evoral::MusicalTime new_time;
3854 nframes64_t start_frames = region->beats_to_frames(cnote->note()->time());
3855 if (drag_delta_x >= 0) {
3856 start_frames += region->snap_frame_to_frame(_editor->pixel_to_frame(drag_delta_x));
3858 start_frames -= region->snap_frame_to_frame(_editor->pixel_to_frame(-drag_delta_x));
3860 new_time = region->frames_to_beats(start_frames);
3862 new_time = cnote->note()->time();
3865 boost::shared_ptr<Evoral::Note<Evoral::MusicalTime> > check_note (
3866 new Evoral::Note<Evoral::MusicalTime> (cnote->note()->channel(),
3868 cnote->note()->length(),
3869 cnote->note()->note() + drag_delta_note,
3870 cnote->note()->velocity()));
3872 region->move_selection (dx, dy);
3875 snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (cnote->note()->note()).c_str(),
3876 (int) floor ((cnote->note()->note() + drag_delta_note)));
3877 _editor->show_verbose_canvas_cursor_with (buf);
3882 NoteDrag::finished (GdkEvent* ev, bool moved)
3884 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3887 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3890 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3892 region->note_deselected (cnote);
3895 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3896 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3898 if (!extend && !add && region->selection_size() > 1) {
3899 region->unique_select(cnote);
3900 } else if (extend) {
3901 region->note_selected (cnote, true, true);
3903 /* it was added during button press */
3908 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3913 NoteDrag::aborted ()
3918 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3921 , _nothing_to_drag (false)
3923 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3926 _line = _atav->line ();
3930 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3932 Drag::start_grab (event, cursor);
3934 list<ControlPoint*> points;
3936 XMLNode* state = &_line->get_state ();
3938 if (_ranges.empty()) {
3940 uint32_t const N = _line->npoints ();
3941 for (uint32_t i = 0; i < N; ++i) {
3942 points.push_back (_line->nth (i));
3947 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3948 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3950 /* fade into and out of the region that we're dragging;
3951 64 samples length plucked out of thin air.
3953 nframes64_t const h = (j->start + j->end) / 2;
3954 nframes64_t a = j->start + 64;
3958 nframes64_t b = j->end - 64;
3963 the_list->add (j->start, the_list->eval (j->start));
3964 _line->add_always_in_view (j->start);
3965 the_list->add (a, the_list->eval (a));
3966 _line->add_always_in_view (a);
3967 the_list->add (b, the_list->eval (b));
3968 _line->add_always_in_view (b);
3969 the_list->add (j->end, the_list->eval (j->end));
3970 _line->add_always_in_view (j->end);
3973 uint32_t const N = _line->npoints ();
3974 for (uint32_t i = 0; i < N; ++i) {
3976 ControlPoint* p = _line->nth (i);
3978 list<AudioRange>::const_iterator j = _ranges.begin ();
3979 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3983 if (j != _ranges.end()) {
3984 points.push_back (p);
3989 if (points.empty()) {
3990 _nothing_to_drag = true;
3994 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3998 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
4000 if (_nothing_to_drag) {
4004 float const f = 1 - (_drags->current_pointer_y() / _line->height());
4006 /* we are ignoring x position for this drag, so we can just pass in anything */
4007 _line->drag_motion (0, f, true, false);
4011 AutomationRangeDrag::finished (GdkEvent* event, bool)
4013 if (_nothing_to_drag) {
4017 motion (event, false);
4019 _line->clear_always_in_view ();
4023 AutomationRangeDrag::aborted ()
4025 _line->clear_always_in_view ();
4029 DraggingView::DraggingView (RegionView* v)
4032 initial_y = v->get_canvas_group()->property_y ();