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, Gdk::Cursor* c)
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, c);
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 /* x movement since last time */
545 dx = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
547 /* total x movement */
548 framecnt_t total_dx = *pending_region_position - grab_frame () + _pointer_frame_offset;
550 /* check that no regions have gone off the start of the session */
551 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
552 if ((i->view->region()->position() + total_dx) < 0) {
554 *pending_region_position = _last_frame_position;
559 _last_frame_position = *pending_region_position;
566 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
570 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
572 vector<int32_t>::iterator j;
574 /* *pointer* variables reflect things about the pointer; as we may be moving
575 multiple regions, much detail must be computed per-region */
577 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
578 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
579 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
580 is always 0 regardless of what the region's "real" layer is */
581 RouteTimeAxisView* current_pointer_view;
582 layer_t current_pointer_layer;
583 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
587 /* TimeAxisView that we were pointing at last time we entered this method */
588 TimeAxisView const * const last_pointer_view = _dest_trackview;
589 /* the order of the track that we were pointing at last time we entered this method */
590 int32_t const last_pointer_order = last_pointer_view->order ();
591 /* the layer that we were pointing at last time we entered this method */
592 layer_t const last_pointer_layer = _dest_layer;
594 int32_t pointer_order_span;
595 int32_t pointer_layer_span;
596 int32_t canvas_pointer_order_span;
598 bool const clamp_y_axis = compute_y_delta (
599 last_pointer_view, current_pointer_view,
600 last_pointer_layer, current_pointer_layer, tavs,
601 &pointer_order_span, &pointer_layer_span,
602 &canvas_pointer_order_span
605 nframes64_t pending_region_position;
606 double const x_delta = compute_x_delta (event, &pending_region_position);
608 /*************************************************************
610 ************************************************************/
612 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
613 /* haven't reached next snap point, and we're not switching
614 trackviews nor layers. nothing to do.
619 /*************************************************************
621 ************************************************************/
623 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
625 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
627 RegionView* rv = i->view;
629 if (rv->region()->locked()) {
633 /* here we are calculating the y distance from the
634 top of the first track view to the top of the region
635 area of the track view that we're working on */
637 /* this x value is just a dummy value so that we have something
642 /* distance from the top of this track view to the region area
643 of our track view is always 1 */
647 /* convert to world coordinates, ie distance from the top of
650 rv->get_canvas_frame()->i2w (ix1, iy1);
652 /* compensate for the ruler section and the vertical scrollbar position */
653 iy1 += _editor->get_trackview_group_vertical_offset ();
657 // hide any dependent views
659 rv->get_time_axis_view().hide_dependent_views (*rv);
662 reparent to a non scrolling group so that we can keep the
663 region selection above all time axis views.
664 reparenting means we have to move the rv as the two
665 parent groups have different coordinates.
668 rv->get_canvas_group()->property_y() = iy1 - 1;
669 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
671 rv->fake_set_opaque (true);
674 /* current view for this particular region */
675 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
676 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
678 if (pointer_order_span != 0 && !clamp_y_axis) {
680 /* INTER-TRACK MOVEMENT */
682 /* move through the height list to the track that the region is currently on */
683 vector<int32_t>::iterator j = tavs.height_list.begin ();
685 while (j != tavs.height_list.end () && x != rtv->order ()) {
691 int32_t temp_pointer_order_span = canvas_pointer_order_span;
693 if (j != tavs.height_list.end ()) {
695 /* Account for layers in the original and
696 destination tracks. If we're moving around in layers we assume
697 that only one track is involved, so it's ok to use *pointer*
700 StreamView* lv = last_pointer_view->view ();
703 /* move to the top of the last trackview */
704 if (lv->layer_display () == Stacked) {
705 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
708 StreamView* cv = current_pointer_view->view ();
711 /* move to the right layer on the current trackview */
712 if (cv->layer_display () == Stacked) {
713 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
716 /* And for being on a non-topmost layer on the new
719 while (temp_pointer_order_span > 0) {
720 /* we're moving up canvas-wise,
721 so we need to find the next track height
723 if (j != tavs.height_list.begin()) {
727 if (x != last_pointer_order) {
729 ++temp_pointer_order_span;
734 temp_pointer_order_span--;
737 while (temp_pointer_order_span < 0) {
741 if (x != last_pointer_order) {
743 --temp_pointer_order_span;
747 if (j != tavs.height_list.end()) {
751 temp_pointer_order_span++;
755 /* find out where we'll be when we move and set height accordingly */
757 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
758 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
759 rv->set_height (temp_rtv->view()->child_height());
761 /* if you un-comment the following, the region colours will follow
762 the track colours whilst dragging; personally
763 i think this can confuse things, but never mind.
766 //const GdkColor& col (temp_rtv->view->get_region_color());
767 //rv->set_color (const_cast<GdkColor&>(col));
771 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
773 /* INTER-LAYER MOVEMENT in the same track */
774 y_delta = rtv->view()->child_height () * pointer_layer_span;
779 _editor->mouse_brush_insert_region (rv, pending_region_position);
781 rv->move (x_delta, y_delta);
784 } /* foreach region */
786 _total_x_delta += x_delta;
789 _editor->cursor_group->raise_to_top();
792 if (x_delta != 0 && !_brushing) {
793 _editor->show_verbose_time_cursor (_last_frame_position, 10);
798 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
800 if (_copy && first_move) {
801 copy_regions (event);
804 RegionMotionDrag::motion (event, first_move);
808 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
810 vector<RegionView*> copies;
811 boost::shared_ptr<Track> tr;
812 boost::shared_ptr<Playlist> from_playlist;
813 boost::shared_ptr<Playlist> to_playlist;
814 RegionSelection new_views;
815 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
816 PlaylistSet modified_playlists;
817 PlaylistSet frozen_playlists;
818 list <sigc::connection> modified_playlist_connections;
819 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
820 nframes64_t drag_delta;
821 bool changed_tracks, changed_position;
822 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
823 RouteTimeAxisView* source_tv;
824 vector<StatefulDiffCommand*> sdc;
826 if (!movement_occurred) {
832 /* all changes were made during motion event handlers */
835 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
836 copies.push_back (i->view);
843 /* reverse this here so that we have the correct logic to finalize
847 if (Config->get_edit_mode() == Lock) {
848 _x_constrained = !_x_constrained;
852 if (_x_constrained) {
853 _editor->begin_reversible_command (_("fixed time region copy"));
855 _editor->begin_reversible_command (_("region copy"));
858 if (_x_constrained) {
859 _editor->begin_reversible_command (_("fixed time region drag"));
861 _editor->begin_reversible_command (_("region drag"));
865 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
866 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
868 drag_delta = _primary->region()->position() - _last_frame_position;
870 _editor->update_canvas_now ();
872 /* make a list of where each region ended up */
873 final = find_time_axis_views_and_layers ();
875 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
877 RegionView* rv = i->view;
878 RouteTimeAxisView* dest_rtv = final[rv].first;
879 layer_t dest_layer = final[rv].second;
883 from_playlist.reset ();
884 to_playlist.reset ();
886 if (rv->region()->locked()) {
891 if (changed_position && !_x_constrained) {
892 where = rv->region()->position() - drag_delta;
894 where = rv->region()->position();
897 boost::shared_ptr<Region> new_region;
900 /* we already made a copy */
901 new_region = rv->region();
903 /* undo the previous hide_dependent_views so that xfades don't
904 disappear on copying regions
907 //rv->get_time_axis_view().reveal_dependent_views (*rv);
909 } else if (changed_tracks && dest_rtv->playlist()) {
910 new_region = RegionFactory::create (rv->region());
913 if (changed_tracks || _copy) {
915 to_playlist = dest_rtv->playlist();
922 _editor->latest_regionviews.clear ();
924 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
926 insert_result = modified_playlists.insert (to_playlist);
928 if (insert_result.second) {
929 to_playlist->clear_history ();
932 cerr << "To playlist " << to_playlist->name() << " region history contains "
933 << to_playlist->region_list().change().added.size() << " adds and "
934 << to_playlist->region_list().change().removed.size() << " removes\n";
936 cerr << "Adding new region " << new_region->id() << " based on "
937 << rv->region()->id() << endl;
939 to_playlist->add_region (new_region, where);
941 if (dest_rtv->view()->layer_display() == Stacked) {
942 new_region->set_layer (dest_layer);
943 new_region->set_pending_explicit_relayer (true);
948 if (!_editor->latest_regionviews.empty()) {
949 // XXX why just the first one ? we only expect one
950 // commented out in nick_m's canvas reworking. is that intended?
951 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
952 new_views.push_back (_editor->latest_regionviews.front());
956 rv->region()->clear_history ();
959 motion on the same track. plonk the previously reparented region
960 back to its original canvas group (its streamview).
961 No need to do anything for copies as they are fake regions which will be deleted.
964 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
965 rv->get_canvas_group()->property_y() = i->initial_y;
966 rv->get_time_axis_view().reveal_dependent_views (*rv);
968 /* just change the model */
970 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
972 if (dest_rtv->view()->layer_display() == Stacked) {
973 rv->region()->set_layer (dest_layer);
974 rv->region()->set_pending_explicit_relayer (true);
977 /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
979 frozen_insert_result = frozen_playlists.insert(playlist);
981 if (frozen_insert_result.second) {
985 cerr << "Moving region " << rv->region()->id() << endl;
987 rv->region()->set_position (where, (void*) this);
989 sdc.push_back (new StatefulDiffCommand (rv->region()));
992 if (changed_tracks && !_copy) {
994 /* get the playlist where this drag started. we can't use rv->region()->playlist()
995 because we may have copied the region and it has not been attached to a playlist.
998 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
999 tr = source_tv->track();
1000 from_playlist = tr->playlist();
1004 assert (from_playlist);
1006 /* moved to a different audio track, without copying */
1008 /* the region that used to be in the old playlist is not
1009 moved to the new one - we use a copy of it. as a result,
1010 any existing editor for the region should no longer be
1014 rv->hide_region_editor();
1015 rv->fake_set_opaque (false);
1017 /* remove the region from the old playlist */
1019 insert_result = modified_playlists.insert (from_playlist);
1021 if (insert_result.second) {
1022 from_playlist->clear_history ();
1025 cerr << "From playlist " << from_playlist->name() << " region history contains "
1026 << from_playlist->region_list().change().added.size() << " adds and "
1027 << from_playlist->region_list().change().removed.size() << " removes\n";
1029 cerr << "removing region " << rv->region() << endl;
1031 from_playlist->remove_region (rv->region());
1033 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1034 was selected in all of them, then removing it from a playlist will have removed all
1035 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1036 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1037 corresponding regionview, and the selection is now empty).
1039 this could have invalidated any and all iterators into the region selection.
1041 the heuristic we use here is: if the region selection is empty, break out of the loop
1042 here. if the region selection is not empty, then restart the loop because we know that
1043 we must have removed at least the region(view) we've just been working on as well as any
1044 that we processed on previous iterations.
1046 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1047 we can just iterate.
1050 if (_views.empty()) {
1052 sdc.push_back (new StatefulDiffCommand (to_playlist));
1053 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1056 if (from_playlist && (from_playlist != to_playlist)) {
1057 sdc.push_back (new StatefulDiffCommand (from_playlist));
1058 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1070 copies.push_back (rv);
1073 cerr << "Done with TV, top = " << to_playlist << " from = " << from_playlist << endl;
1076 sdc.push_back (new StatefulDiffCommand (to_playlist));
1077 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1080 if (from_playlist && (from_playlist != to_playlist)) {
1081 sdc.push_back (new StatefulDiffCommand (from_playlist));
1082 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1087 if we've created new regions either by copying or moving
1088 to a new track, we want to replace the old selection with the new ones
1091 if (new_views.size() > 0) {
1092 _editor->selection->set (new_views);
1095 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1100 for (vector<StatefulDiffCommand*>::iterator i = sdc.begin(); i != sdc.end(); ++i) {
1101 _editor->session()->add_command (*i);
1104 _editor->commit_reversible_command ();
1106 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1112 RegionMoveDrag::aborted ()
1116 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1123 RegionMotionDrag::aborted ();
1128 RegionMotionDrag::aborted ()
1130 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1131 RegionView* rv = i->view;
1132 TimeAxisView* tv = &(rv->get_time_axis_view ());
1133 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1135 rv->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1136 rv->get_canvas_group()->property_y() = 0;
1137 rv->get_time_axis_view().reveal_dependent_views (*rv);
1138 rv->fake_set_opaque (false);
1139 rv->move (-_total_x_delta, 0);
1140 rv->set_height (rtv->view()->child_height ());
1143 _editor->update_canvas_now ();
1148 RegionMotionDrag::x_move_allowed () const
1150 if (Config->get_edit_mode() == Lock) {
1151 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1152 return _x_constrained;
1155 return !_x_constrained;
1159 RegionMotionDrag::copy_regions (GdkEvent* event)
1161 /* duplicate the regionview(s) and region(s) */
1163 list<DraggingView> new_regionviews;
1165 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1167 RegionView* rv = i->view;
1168 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1169 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1171 const boost::shared_ptr<const Region> original = rv->region();
1172 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1173 region_copy->set_position (original->position(), this);
1177 boost::shared_ptr<AudioRegion> audioregion_copy
1178 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1180 nrv = new AudioRegionView (*arv, audioregion_copy);
1182 boost::shared_ptr<MidiRegion> midiregion_copy
1183 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1184 nrv = new MidiRegionView (*mrv, midiregion_copy);
1189 nrv->get_canvas_group()->show ();
1190 new_regionviews.push_back (DraggingView (nrv));
1192 /* swap _primary to the copy */
1194 if (rv == _primary) {
1198 /* ..and deselect the one we copied */
1200 rv->set_selected (false);
1203 if (new_regionviews.empty()) {
1207 /* reflect the fact that we are dragging the copies */
1209 _views = new_regionviews;
1211 swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0);
1214 sync the canvas to what we think is its current state
1215 without it, the canvas seems to
1216 "forget" to update properly after the upcoming reparent()
1217 ..only if the mouse is in rapid motion at the time of the grab.
1218 something to do with regionview creation taking so long?
1220 _editor->update_canvas_now();
1224 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1226 /* Which trackview is this ? */
1228 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1229 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1230 (*layer) = tvp.second;
1232 if (*tv && (*tv)->layer_display() == Overlaid) {
1236 /* The region motion is only processed if the pointer is over
1240 if (!(*tv) || !(*tv)->is_track()) {
1241 /* To make sure we hide the verbose canvas cursor when the mouse is
1242 not held over and audiotrack.
1244 _editor->hide_verbose_canvas_cursor ();
1251 /** @param new_order New track order.
1252 * @param old_order Old track order.
1253 * @param visible_y_low Lowest visible order.
1254 * @return true if y movement should not happen, otherwise false.
1257 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1259 if (new_order != old_order) {
1261 /* this isn't the pointer track */
1265 /* moving up the canvas */
1266 if ( (new_order - y_span) >= tavs.visible_y_low) {
1270 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1271 int32_t visible_tracks = 0;
1272 while (visible_tracks < y_span ) {
1274 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1275 /* passing through a hidden track */
1280 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1281 /* moving to a non-track; disallow */
1287 /* moving beyond the lowest visible track; disallow */
1291 } else if (y_span < 0) {
1293 /* moving down the canvas */
1294 if ((new_order - y_span) <= tavs.visible_y_high) {
1296 int32_t visible_tracks = 0;
1298 while (visible_tracks > y_span ) {
1301 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1302 /* passing through a hidden track */
1307 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1308 /* moving to a non-track; disallow */
1315 /* moving beyond the highest visible track; disallow */
1322 /* this is the pointer's track */
1324 if ((new_order - y_span) > tavs.visible_y_high) {
1325 /* we will overflow */
1327 } else if ((new_order - y_span) < tavs.visible_y_low) {
1328 /* we will overflow */
1337 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1338 : RegionMotionDrag (e, i, p, v, b),
1341 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1343 _dest_trackview = tv;
1344 if (tv->layer_display() == Overlaid) {
1347 _dest_layer = _primary->region()->layer ();
1351 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1352 if (rtv && rtv->is_track()) {
1353 speed = rtv->track()->speed ();
1356 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1360 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1362 RegionMotionDrag::start_grab (event, c);
1364 _pointer_frame_offset = grab_frame() - _last_frame_position;
1367 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1368 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1370 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1371 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1373 _primary = v->view()->create_region_view (r, false, false);
1375 _primary->get_canvas_group()->show ();
1376 _primary->set_position (pos, 0);
1377 _views.push_back (DraggingView (_primary));
1379 _last_frame_position = pos;
1381 _item = _primary->get_canvas_group ();
1382 _dest_trackview = v;
1383 _dest_layer = _primary->region()->layer ();
1386 map<RegionView*, pair<RouteTimeAxisView*, int> >
1387 RegionMotionDrag::find_time_axis_views_and_layers ()
1389 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1391 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1393 double ix1, ix2, iy1, iy2;
1394 RegionView* rv = i->view;
1395 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1396 rv->get_canvas_frame()->i2w (ix1, iy1);
1397 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1399 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1400 tav[rv] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1408 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1410 _editor->update_canvas_now ();
1412 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1414 RouteTimeAxisView* dest_rtv = final[_primary].first;
1416 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1417 _primary->get_canvas_group()->property_y() = 0;
1419 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1421 _editor->begin_reversible_command (_("insert region"));
1422 playlist->clear_history ();
1423 playlist->add_region (_primary->region (), _last_frame_position);
1424 _editor->session()->add_command (new StatefulDiffCommand (playlist));
1425 _editor->commit_reversible_command ();
1433 RegionInsertDrag::aborted ()
1440 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1441 : RegionMoveDrag (e, i, p, v, false, false)
1446 struct RegionSelectionByPosition {
1447 bool operator() (RegionView*a, RegionView* b) {
1448 return a->region()->position () < b->region()->position();
1453 RegionSpliceDrag::motion (GdkEvent* event, bool)
1455 RouteTimeAxisView* tv;
1458 if (!check_possible (&tv, &layer)) {
1464 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1470 RegionSelection copy (_editor->selection->regions);
1472 RegionSelectionByPosition cmp;
1475 nframes64_t const pf = adjusted_current_frame (event);
1477 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1479 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1485 boost::shared_ptr<Playlist> playlist;
1487 if ((playlist = atv->playlist()) == 0) {
1491 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1496 if (pf < (*i)->region()->last_frame() + 1) {
1500 if (pf > (*i)->region()->first_frame()) {
1506 playlist->shuffle ((*i)->region(), dir);
1511 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1517 RegionSpliceDrag::aborted ()
1522 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1530 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1532 _dest_trackview = _view;
1534 Drag::start_grab (event);
1539 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1542 // TODO: create region-create-drag region view here
1545 // TODO: resize region-create-drag region view here
1549 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1551 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1557 if (!movement_occurred) {
1558 mtv->add_region (grab_frame ());
1560 motion (event, false);
1561 // TODO: create region-create-drag region here
1566 RegionCreateDrag::aborted ()
1571 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1579 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/)
1581 Gdk::Cursor* cursor;
1582 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1584 Drag::start_grab (event);
1586 region = &cnote->region_view();
1588 double const region_start = region->get_position_pixels();
1589 double const middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1591 if (grab_x() <= middle_point) {
1592 cursor = _editor->left_side_trim_cursor;
1595 cursor = _editor->right_side_trim_cursor;
1599 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, *cursor, event->motion.time);
1601 if (event->motion.state & Keyboard::PrimaryModifier) {
1607 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1609 if (ms.size() > 1) {
1610 /* has to be relative, may make no sense otherwise */
1614 /* select this note; if it is already selected, preserve the existing selection,
1615 otherwise make this note the only one selected.
1617 region->note_selected (cnote, cnote->selected ());
1619 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1620 MidiRegionSelection::iterator next;
1623 (*r)->begin_resizing (at_front);
1629 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1631 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1632 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1633 (*r)->update_resizing (dynamic_cast<ArdourCanvas::CanvasNote*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
1638 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1640 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1641 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1642 (*r)->commit_resizing (dynamic_cast<ArdourCanvas::CanvasNote*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
1647 NoteResizeDrag::aborted ()
1653 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1659 RegionGainDrag::finished (GdkEvent *, bool)
1665 RegionGainDrag::aborted ()
1670 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1671 : RegionDrag (e, i, p, v)
1672 , _have_transaction (false)
1678 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1681 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1682 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1684 if (tv && tv->is_track()) {
1685 speed = tv->track()->speed();
1688 nframes64_t const region_start = (nframes64_t) (_primary->region()->position() / speed);
1689 nframes64_t const region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1690 nframes64_t const region_length = (nframes64_t) (_primary->region()->length() / speed);
1692 nframes64_t const pf = adjusted_current_frame (event);
1694 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1695 _operation = ContentsTrim;
1696 Drag::start_grab (event, _editor->trimmer_cursor);
1698 /* These will get overridden for a point trim.*/
1699 if (pf < (region_start + region_length/2)) {
1700 /* closer to start */
1701 _operation = StartTrim;
1702 Drag::start_grab (event, _editor->left_side_trim_cursor);
1705 _operation = EndTrim;
1706 Drag::start_grab (event, _editor->right_side_trim_cursor);
1710 switch (_operation) {
1712 _editor->show_verbose_time_cursor (region_start, 10);
1715 _editor->show_verbose_time_cursor (region_end, 10);
1718 _editor->show_verbose_time_cursor (pf, 10);
1724 TrimDrag::motion (GdkEvent* event, bool first_move)
1726 RegionView* rv = _primary;
1728 /* snap modifier works differently here..
1729 its current state has to be passed to the
1730 various trim functions in order to work properly
1734 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1735 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1736 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1738 if (tv && tv->is_track()) {
1739 speed = tv->track()->speed();
1742 nframes64_t const pf = adjusted_current_frame (event);
1748 switch (_operation) {
1750 trim_type = "Region start trim";
1753 trim_type = "Region end trim";
1756 trim_type = "Region content trim";
1760 _editor->begin_reversible_command (trim_type);
1761 _have_transaction = true;
1763 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1764 RegionView* rv = i->view;
1765 rv->fake_set_opaque(false);
1766 rv->enable_display (false);
1767 rv->region()->clear_history ();
1768 rv->region()->suspend_property_changes ();
1770 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
1773 arv->temporarily_hide_envelope ();
1776 boost::shared_ptr<Playlist> pl = rv->region()->playlist();
1777 insert_result = _editor->motion_frozen_playlists.insert (pl);
1779 if (insert_result.second) {
1785 bool non_overlap_trim = false;
1787 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1788 non_overlap_trim = true;
1791 switch (_operation) {
1793 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1794 _editor->single_start_trim (*i->view, pf, non_overlap_trim);
1799 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1800 _editor->single_end_trim (*i->view, pf, non_overlap_trim);
1806 bool swap_direction = false;
1808 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1809 swap_direction = true;
1812 nframes64_t frame_delta = 0;
1814 bool left_direction = false;
1815 if (last_pointer_frame() > pf) {
1816 left_direction = true;
1819 if (left_direction) {
1820 frame_delta = (last_pointer_frame() - pf);
1822 frame_delta = (pf - last_pointer_frame());
1825 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1826 _editor->single_contents_trim (*i->view, frame_delta, left_direction, swap_direction);
1832 switch (_operation) {
1834 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1837 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1840 _editor->show_verbose_time_cursor (pf, 10);
1847 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1849 if (movement_occurred) {
1850 motion (event, false);
1852 if (!_editor->selection->selected (_primary)) {
1853 _editor->thaw_region_after_trim (*_primary);
1856 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1857 _editor->thaw_region_after_trim (*i->view);
1858 i->view->enable_display (true);
1859 i->view->fake_set_opaque (true);
1860 if (_have_transaction) {
1861 _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
1865 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1869 _editor->motion_frozen_playlists.clear ();
1871 if (_have_transaction) {
1872 _editor->commit_reversible_command();
1876 /* no mouse movement */
1877 _editor->point_trim (event, adjusted_current_frame (event));
1882 TrimDrag::aborted ()
1884 /* Our motion method is changing model state, so use the Undo system
1885 to cancel. Perhaps not ideal, as this will leave an Undo point
1886 behind which may be slightly odd from the user's point of view.
1891 if (_have_transaction) {
1896 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1900 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1905 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1908 // create a dummy marker for visual representation of moving the copy.
1909 // The actual copying is not done before we reach the finish callback.
1911 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1912 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1913 *new MeterSection (_marker->meter()));
1915 _item = &new_marker->the_item ();
1916 _marker = new_marker;
1920 MetricSection& section (_marker->meter());
1922 if (!section.movable()) {
1928 Drag::start_grab (event, cursor);
1930 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1932 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1936 MeterMarkerDrag::motion (GdkEvent* event, bool)
1938 nframes64_t const pf = adjusted_current_frame (event);
1940 _marker->set_position (pf);
1942 _editor->show_verbose_time_cursor (pf, 10);
1946 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1948 if (!movement_occurred) {
1952 motion (event, false);
1956 TempoMap& map (_editor->session()->tempo_map());
1957 map.bbt_time (last_pointer_frame(), when);
1959 if (_copy == true) {
1960 _editor->begin_reversible_command (_("copy meter mark"));
1961 XMLNode &before = map.get_state();
1962 map.add_meter (_marker->meter(), when);
1963 XMLNode &after = map.get_state();
1964 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1965 _editor->commit_reversible_command ();
1967 // delete the dummy marker we used for visual representation of copying.
1968 // a new visual marker will show up automatically.
1971 _editor->begin_reversible_command (_("move meter mark"));
1972 XMLNode &before = map.get_state();
1973 map.move_meter (_marker->meter(), when);
1974 XMLNode &after = map.get_state();
1975 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1976 _editor->commit_reversible_command ();
1981 MeterMarkerDrag::aborted ()
1983 _marker->set_position (_marker->meter().frame ());
1986 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1990 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1995 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2000 // create a dummy marker for visual representation of moving the copy.
2001 // The actual copying is not done before we reach the finish callback.
2003 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
2004 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
2005 *new TempoSection (_marker->tempo()));
2007 _item = &new_marker->the_item ();
2008 _marker = new_marker;
2012 MetricSection& section (_marker->tempo());
2014 if (!section.movable()) {
2019 Drag::start_grab (event, cursor);
2021 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
2022 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2026 TempoMarkerDrag::motion (GdkEvent* event, bool)
2028 nframes64_t const pf = adjusted_current_frame (event);
2029 _marker->set_position (pf);
2030 _editor->show_verbose_time_cursor (pf, 10);
2034 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2036 if (!movement_occurred) {
2040 motion (event, false);
2044 TempoMap& map (_editor->session()->tempo_map());
2045 map.bbt_time (last_pointer_frame(), when);
2047 if (_copy == true) {
2048 _editor->begin_reversible_command (_("copy tempo mark"));
2049 XMLNode &before = map.get_state();
2050 map.add_tempo (_marker->tempo(), when);
2051 XMLNode &after = map.get_state();
2052 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2053 _editor->commit_reversible_command ();
2055 // delete the dummy marker we used for visual representation of copying.
2056 // a new visual marker will show up automatically.
2059 _editor->begin_reversible_command (_("move tempo mark"));
2060 XMLNode &before = map.get_state();
2061 map.move_tempo (_marker->tempo(), when);
2062 XMLNode &after = map.get_state();
2063 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2064 _editor->commit_reversible_command ();
2069 TempoMarkerDrag::aborted ()
2071 _marker->set_position (_marker->tempo().frame());
2074 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2078 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2083 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2085 Drag::start_grab (event, c);
2089 nframes64_t where = _editor->event_frame (event, 0, 0);
2091 _editor->snap_to_with_modifier (where, event);
2092 _editor->playhead_cursor->set_position (where);
2096 if (_cursor == _editor->playhead_cursor) {
2097 _editor->_dragging_playhead = true;
2099 Session* s = _editor->session ();
2102 if (_was_rolling && _stop) {
2106 if (s->is_auditioning()) {
2107 s->cancel_audition ();
2110 s->request_suspend_timecode_transmission ();
2112 if (s->timecode_transmission_suspended ()) {
2113 nframes64_t const f = _editor->playhead_cursor->current_frame;
2114 s->send_mmc_locate (f);
2115 s->send_full_time_code (f);
2120 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2122 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2126 CursorDrag::motion (GdkEvent* event, bool)
2128 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2130 if (adjusted_frame == last_pointer_frame()) {
2134 _cursor->set_position (adjusted_frame);
2136 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2138 Session* s = _editor->session ();
2139 if (s && _item == &_editor->playhead_cursor->canvas_item && s->timecode_transmission_suspended ()) {
2140 nframes64_t const f = _editor->playhead_cursor->current_frame;
2141 s->send_mmc_locate (f);
2142 s->send_full_time_code (f);
2147 _editor->update_canvas_now ();
2149 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2153 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2155 _editor->_dragging_playhead = false;
2157 if (!movement_occurred && _stop) {
2161 motion (event, false);
2163 if (_item == &_editor->playhead_cursor->canvas_item) {
2164 Session* s = _editor->session ();
2166 s->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2167 _editor->_pending_locate_request = true;
2168 s->request_resume_timecode_transmission ();
2174 CursorDrag::aborted ()
2176 if (_editor->_dragging_playhead) {
2177 _editor->session()->request_resume_timecode_transmission ();
2178 _editor->_dragging_playhead = false;
2181 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2184 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2185 : RegionDrag (e, i, p, v)
2191 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2193 Drag::start_grab (event, cursor);
2195 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2196 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2198 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2199 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2204 FadeInDrag::motion (GdkEvent* event, bool)
2206 nframes64_t fade_length;
2208 nframes64_t const pos = adjusted_current_frame (event);
2210 boost::shared_ptr<Region> region = _primary->region ();
2212 if (pos < (region->position() + 64)) {
2213 fade_length = 64; // this should be a minimum defined somewhere
2214 } else if (pos > region->last_frame()) {
2215 fade_length = region->length();
2217 fade_length = pos - region->position();
2220 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2222 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2228 tmp->reset_fade_in_shape_width (fade_length);
2231 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2235 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2237 if (!movement_occurred) {
2241 nframes64_t fade_length;
2243 nframes64_t const pos = adjusted_current_frame (event);
2245 boost::shared_ptr<Region> region = _primary->region ();
2247 if (pos < (region->position() + 64)) {
2248 fade_length = 64; // this should be a minimum defined somewhere
2249 } else if (pos > region->last_frame()) {
2250 fade_length = region->length();
2252 fade_length = pos - region->position();
2255 _editor->begin_reversible_command (_("change fade in length"));
2257 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2259 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2265 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2266 XMLNode &before = alist->get_state();
2268 tmp->audio_region()->set_fade_in_length (fade_length);
2269 tmp->audio_region()->set_fade_in_active (true);
2271 XMLNode &after = alist->get_state();
2272 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2275 _editor->commit_reversible_command ();
2279 FadeInDrag::aborted ()
2281 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2282 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2288 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2292 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2293 : RegionDrag (e, i, p, v)
2299 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2301 Drag::start_grab (event, cursor);
2303 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2304 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2306 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2307 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2311 FadeOutDrag::motion (GdkEvent* event, bool)
2313 nframes64_t fade_length;
2315 nframes64_t const pos = adjusted_current_frame (event);
2317 boost::shared_ptr<Region> region = _primary->region ();
2319 if (pos > (region->last_frame() - 64)) {
2320 fade_length = 64; // this should really be a minimum fade defined somewhere
2322 else if (pos < region->position()) {
2323 fade_length = region->length();
2326 fade_length = region->last_frame() - pos;
2329 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2331 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2337 tmp->reset_fade_out_shape_width (fade_length);
2340 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2344 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2346 if (!movement_occurred) {
2350 nframes64_t fade_length;
2352 nframes64_t const pos = adjusted_current_frame (event);
2354 boost::shared_ptr<Region> region = _primary->region ();
2356 if (pos > (region->last_frame() - 64)) {
2357 fade_length = 64; // this should really be a minimum fade defined somewhere
2359 else if (pos < region->position()) {
2360 fade_length = region->length();
2363 fade_length = region->last_frame() - pos;
2366 _editor->begin_reversible_command (_("change fade out length"));
2368 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2370 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2376 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2377 XMLNode &before = alist->get_state();
2379 tmp->audio_region()->set_fade_out_length (fade_length);
2380 tmp->audio_region()->set_fade_out_active (true);
2382 XMLNode &after = alist->get_state();
2383 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2386 _editor->commit_reversible_command ();
2390 FadeOutDrag::aborted ()
2392 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2393 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2399 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2403 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2406 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2409 _points.push_back (Gnome::Art::Point (0, 0));
2410 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2412 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2413 _line->property_width_pixels() = 1;
2414 _line->property_points () = _points;
2417 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2420 MarkerDrag::~MarkerDrag ()
2422 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2428 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2430 Drag::start_grab (event, cursor);
2434 Location *location = _editor->find_location_from_marker (_marker, is_start);
2435 _editor->_dragging_edit_point = true;
2437 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2439 update_item (location);
2441 // _drag_line->show();
2442 // _line->raise_to_top();
2445 _editor->show_verbose_time_cursor (location->start(), 10);
2447 _editor->show_verbose_time_cursor (location->end(), 10);
2450 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2453 case Selection::Toggle:
2454 _editor->selection->toggle (_marker);
2456 case Selection::Set:
2457 if (!_editor->selection->selected (_marker)) {
2458 _editor->selection->set (_marker);
2461 case Selection::Extend:
2463 Locations::LocationList ll;
2464 list<Marker*> to_add;
2466 _editor->selection->markers.range (s, e);
2467 s = min (_marker->position(), s);
2468 e = max (_marker->position(), e);
2471 if (e < max_frames) {
2474 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2475 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2476 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2479 to_add.push_back (lm->start);
2482 to_add.push_back (lm->end);
2486 if (!to_add.empty()) {
2487 _editor->selection->add (to_add);
2491 case Selection::Add:
2492 _editor->selection->add (_marker);
2496 /* Set up copies for us to manipulate during the drag */
2498 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2499 Location* l = _editor->find_location_from_marker (*i, is_start);
2500 _copied_locations.push_back (new Location (*l));
2505 MarkerDrag::motion (GdkEvent* event, bool)
2507 nframes64_t f_delta = 0;
2509 bool move_both = false;
2511 Location *real_location;
2512 Location *copy_location = 0;
2514 nframes64_t const newframe = adjusted_current_frame (event);
2516 nframes64_t next = newframe;
2518 if (newframe == last_pointer_frame()) {
2522 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2526 MarkerSelection::iterator i;
2527 list<Location*>::iterator x;
2529 /* find the marker we're dragging, and compute the delta */
2531 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2532 x != _copied_locations.end() && i != _editor->selection->markers.end();
2538 if (marker == _marker) {
2540 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2545 if (real_location->is_mark()) {
2546 f_delta = newframe - copy_location->start();
2550 switch (marker->type()) {
2552 case Marker::LoopStart:
2553 case Marker::PunchIn:
2554 f_delta = newframe - copy_location->start();
2558 case Marker::LoopEnd:
2559 case Marker::PunchOut:
2560 f_delta = newframe - copy_location->end();
2563 /* what kind of marker is this ? */
2571 if (i == _editor->selection->markers.end()) {
2572 /* hmm, impossible - we didn't find the dragged marker */
2576 /* now move them all */
2578 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2579 x != _copied_locations.end() && i != _editor->selection->markers.end();
2585 /* call this to find out if its the start or end */
2587 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2591 if (real_location->locked()) {
2595 if (copy_location->is_mark()) {
2599 copy_location->set_start (copy_location->start() + f_delta);
2603 nframes64_t new_start = copy_location->start() + f_delta;
2604 nframes64_t new_end = copy_location->end() + f_delta;
2606 if (is_start) { // start-of-range marker
2609 copy_location->set_start (new_start);
2610 copy_location->set_end (new_end);
2611 } else if (new_start < copy_location->end()) {
2612 copy_location->set_start (new_start);
2614 _editor->snap_to (next, 1, true);
2615 copy_location->set_end (next);
2616 copy_location->set_start (newframe);
2619 } else { // end marker
2622 copy_location->set_end (new_end);
2623 copy_location->set_start (new_start);
2624 } else if (new_end > copy_location->start()) {
2625 copy_location->set_end (new_end);
2626 } else if (newframe > 0) {
2627 _editor->snap_to (next, -1, true);
2628 copy_location->set_start (next);
2629 copy_location->set_end (newframe);
2634 update_item (copy_location);
2636 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2639 lm->set_position (copy_location->start(), copy_location->end());
2643 assert (!_copied_locations.empty());
2645 _editor->show_verbose_time_cursor (newframe, 10);
2648 _editor->update_canvas_now ();
2653 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2655 if (!movement_occurred) {
2657 /* just a click, do nothing but finish
2658 off the selection process
2661 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2664 case Selection::Set:
2665 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2666 _editor->selection->set (_marker);
2670 case Selection::Toggle:
2671 case Selection::Extend:
2672 case Selection::Add:
2679 _editor->_dragging_edit_point = false;
2681 _editor->begin_reversible_command ( _("move marker") );
2682 XMLNode &before = _editor->session()->locations()->get_state();
2684 MarkerSelection::iterator i;
2685 list<Location*>::iterator x;
2688 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2689 x != _copied_locations.end() && i != _editor->selection->markers.end();
2692 Location * location = _editor->find_location_from_marker (*i, is_start);
2696 if (location->locked()) {
2700 if (location->is_mark()) {
2701 location->set_start ((*x)->start());
2703 location->set ((*x)->start(), (*x)->end());
2708 XMLNode &after = _editor->session()->locations()->get_state();
2709 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2710 _editor->commit_reversible_command ();
2716 MarkerDrag::aborted ()
2722 MarkerDrag::update_item (Location* location)
2724 double const x1 = _editor->frame_to_pixel (location->start());
2726 _points.front().set_x(x1);
2727 _points.back().set_x(x1);
2728 _line->property_points() = _points;
2731 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2733 _cumulative_x_drag (0),
2734 _cumulative_y_drag (0)
2736 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2742 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2744 Drag::start_grab (event, _editor->fader_cursor);
2746 // start the grab at the center of the control point so
2747 // the point doesn't 'jump' to the mouse after the first drag
2748 _time_axis_view_grab_x = _point->get_x();
2749 _time_axis_view_grab_y = _point->get_y();
2751 float const fraction = 1 - (_point->get_y() / _point->line().height());
2753 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2755 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2756 event->button.x + 10, event->button.y + 10);
2758 _editor->show_verbose_canvas_cursor ();
2762 ControlPointDrag::motion (GdkEvent* event, bool)
2764 double dx = _drags->current_pointer_x() - last_pointer_x();
2765 double dy = _drags->current_pointer_y() - last_pointer_y();
2767 if (event->button.state & Keyboard::SecondaryModifier) {
2772 /* coordinate in TimeAxisView's space */
2773 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2774 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2776 // calculate zero crossing point. back off by .01 to stay on the
2777 // positive side of zero
2778 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2780 // make sure we hit zero when passing through
2781 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2785 if (_x_constrained) {
2786 cx = _time_axis_view_grab_x;
2788 if (_y_constrained) {
2789 cy = _time_axis_view_grab_y;
2792 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2793 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2797 cy = min ((double) _point->line().height(), cy);
2799 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2801 if (!_x_constrained) {
2802 _editor->snap_to_with_modifier (cx_frames, event);
2805 float const fraction = 1.0 - (cy / _point->line().height());
2807 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2809 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2811 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2815 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2817 if (!movement_occurred) {
2821 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2822 _editor->reset_point_selection ();
2826 motion (event, false);
2828 _point->line().end_drag ();
2832 ControlPointDrag::aborted ()
2834 _point->line().reset ();
2838 ControlPointDrag::active (Editing::MouseMode m)
2840 if (m == Editing::MouseGain) {
2841 /* always active in mouse gain */
2845 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2846 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2849 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2852 _cumulative_y_drag (0)
2857 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2859 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2862 _item = &_line->grab_item ();
2864 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2865 origin, and ditto for y.
2868 double cx = event->button.x;
2869 double cy = event->button.y;
2871 _line->parent_group().w2i (cx, cy);
2873 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2878 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2879 /* no adjacent points */
2883 Drag::start_grab (event, _editor->fader_cursor);
2885 /* store grab start in parent frame */
2887 _time_axis_view_grab_x = cx;
2888 _time_axis_view_grab_y = cy;
2890 double fraction = 1.0 - (cy / _line->height());
2892 _line->start_drag_line (before, after, fraction);
2894 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2895 event->button.x + 10, event->button.y + 10);
2897 _editor->show_verbose_canvas_cursor ();
2901 LineDrag::motion (GdkEvent* event, bool)
2903 double dy = _drags->current_pointer_y() - last_pointer_y();
2905 if (event->button.state & Keyboard::SecondaryModifier) {
2909 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2911 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2914 cy = min ((double) _line->height(), cy);
2916 double const fraction = 1.0 - (cy / _line->height());
2920 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2926 /* we are ignoring x position for this drag, so we can just pass in anything */
2927 _line->drag_motion (0, fraction, true, push);
2929 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2933 LineDrag::finished (GdkEvent* event, bool)
2935 motion (event, false);
2940 LineDrag::aborted ()
2945 FeatureLineDrag::FeatureLineDrag (Editor* e, ArdourCanvas::Item* i)
2948 _cumulative_x_drag (0)
2953 FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2956 Drag::start_grab (event);
2958 _line = reinterpret_cast<SimpleLine*> (_item);
2961 /* need to get x coordinate in terms of parent (AudioRegionView) origin. */
2963 double cx = event->button.x;
2964 double cy = event->button.y;
2966 _item->property_parent().get_value()->w2i(cx, cy);
2968 /* store grab start in parent frame */
2969 _region_view_grab_x = cx;
2971 _before = _line->property_x1();
2973 _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
2975 _max_x = _editor->frame_to_pixel(_arv->get_duration());
2979 FeatureLineDrag::motion (GdkEvent* event, bool)
2981 double dx = _drags->current_pointer_x() - last_pointer_x();
2983 double cx = _region_view_grab_x + _cumulative_x_drag + dx;
2985 _cumulative_x_drag += dx;
2987 /* Clamp the min and max extent of the drag to keep it within the region view bounds */
2996 _line->property_x1() = cx;
2997 _line->property_x2() = cx;
2999 _before = _line->property_x1();
3003 FeatureLineDrag::finished (GdkEvent* event, bool)
3005 _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
3006 _arv->update_transient(_before, _line->property_x1());
3010 FeatureLineDrag::aborted ()
3016 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3018 Drag::start_grab (event);
3019 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3023 RubberbandSelectDrag::motion (GdkEvent* event, bool)
3030 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
3032 nframes64_t grab = grab_frame ();
3033 if (Config->get_rubberbanding_snaps_to_grid ()) {
3034 _editor->snap_to_with_modifier (grab, event);
3037 /* base start and end on initial click position */
3047 if (_drags->current_pointer_y() < grab_y()) {
3048 y1 = _drags->current_pointer_y();
3051 y2 = _drags->current_pointer_y();
3056 if (start != end || y1 != y2) {
3058 double x1 = _editor->frame_to_pixel (start);
3059 double x2 = _editor->frame_to_pixel (end);
3061 _editor->rubberband_rect->property_x1() = x1;
3062 _editor->rubberband_rect->property_y1() = y1;
3063 _editor->rubberband_rect->property_x2() = x2;
3064 _editor->rubberband_rect->property_y2() = y2;
3066 _editor->rubberband_rect->show();
3067 _editor->rubberband_rect->raise_to_top();
3069 _editor->show_verbose_time_cursor (pf, 10);
3074 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
3076 if (movement_occurred) {
3078 motion (event, false);
3081 if (_drags->current_pointer_y() < grab_y()) {
3082 y1 = _drags->current_pointer_y();
3085 y2 = _drags->current_pointer_y();
3090 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
3093 _editor->begin_reversible_command (_("rubberband selection"));
3095 if (grab_frame() < last_pointer_frame()) {
3096 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op, false);
3098 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op, false);
3102 _editor->commit_reversible_command ();
3106 if (!getenv("ARDOUR_SAE")) {
3107 _editor->selection->clear_tracks();
3109 _editor->selection->clear_regions();
3110 _editor->selection->clear_points ();
3111 _editor->selection->clear_lines ();
3114 _editor->rubberband_rect->hide();
3118 RubberbandSelectDrag::aborted ()
3120 _editor->rubberband_rect->hide ();
3124 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3126 Drag::start_grab (event);
3128 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3132 TimeFXDrag::motion (GdkEvent* event, bool)
3134 RegionView* rv = _primary;
3136 nframes64_t const pf = adjusted_current_frame (event);
3138 if (pf > rv->region()->position()) {
3139 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3142 _editor->show_verbose_time_cursor (pf, 10);
3146 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3148 _primary->get_time_axis_view().hide_timestretch ();
3150 if (!movement_occurred) {
3154 if (last_pointer_frame() < _primary->region()->position()) {
3155 /* backwards drag of the left edge - not usable */
3159 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3161 float percentage = (double) newlen / (double) _primary->region()->length();
3163 #ifndef USE_RUBBERBAND
3164 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3165 if (_primary->region()->data_type() == DataType::AUDIO) {
3166 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3170 _editor->begin_reversible_command (_("timestretch"));
3172 // XXX how do timeFX on multiple regions ?
3177 if (_editor->time_stretch (rs, percentage) == -1) {
3178 error << _("An error occurred while executing time stretch operation") << endmsg;
3183 TimeFXDrag::aborted ()
3185 _primary->get_time_axis_view().hide_timestretch ();
3190 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3192 Drag::start_grab (event);
3196 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3198 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3202 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3204 if (movement_occurred && _editor->session()) {
3205 /* make sure we stop */
3206 _editor->session()->request_transport_speed (0.0);
3211 ScrubDrag::aborted ()
3216 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3220 , _original_pointer_time_axis (-1)
3221 , _last_pointer_time_axis (-1)
3227 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3229 nframes64_t start = 0;
3230 nframes64_t end = 0;
3232 if (_editor->session() == 0) {
3236 Gdk::Cursor* cursor = 0;
3238 switch (_operation) {
3239 case CreateSelection:
3240 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3245 cursor = _editor->selector_cursor;
3246 Drag::start_grab (event, cursor);
3249 case SelectionStartTrim:
3250 if (_editor->clicked_axisview) {
3251 _editor->clicked_axisview->order_selection_trims (_item, true);
3253 Drag::start_grab (event, _editor->left_side_trim_cursor);
3254 start = _editor->selection->time[_editor->clicked_selection].start;
3255 _pointer_frame_offset = grab_frame() - start;
3258 case SelectionEndTrim:
3259 if (_editor->clicked_axisview) {
3260 _editor->clicked_axisview->order_selection_trims (_item, false);
3262 Drag::start_grab (event, _editor->right_side_trim_cursor);
3263 end = _editor->selection->time[_editor->clicked_selection].end;
3264 _pointer_frame_offset = grab_frame() - end;
3268 start = _editor->selection->time[_editor->clicked_selection].start;
3269 Drag::start_grab (event, cursor);
3270 _pointer_frame_offset = grab_frame() - start;
3274 if (_operation == SelectionMove) {
3275 _editor->show_verbose_time_cursor (start, 10);
3277 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3280 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3284 SelectionDrag::motion (GdkEvent* event, bool first_move)
3286 nframes64_t start = 0;
3287 nframes64_t end = 0;
3290 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3291 if (pending_time_axis.first == 0) {
3295 nframes64_t const pending_position = adjusted_current_frame (event);
3297 /* only alter selection if things have changed */
3299 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3303 switch (_operation) {
3304 case CreateSelection:
3306 nframes64_t grab = grab_frame ();
3309 _editor->snap_to (grab);
3312 if (pending_position < grab_frame()) {
3313 start = pending_position;
3316 end = pending_position;
3320 /* first drag: Either add to the selection
3321 or create a new selection
3327 /* adding to the selection */
3328 _editor->selection->add (_editor->clicked_axisview);
3329 _editor->clicked_selection = _editor->selection->add (start, end);
3334 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
3335 _editor->selection->set (_editor->clicked_axisview);
3338 _editor->clicked_selection = _editor->selection->set (start, end);
3342 /* select the track that we're in */
3343 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3344 _editor->selection->add (pending_time_axis.first);
3345 _added_time_axes.push_back (pending_time_axis.first);
3348 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3349 tracks that we selected in the first place.
3352 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3353 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3355 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3356 while (i != _added_time_axes.end()) {
3358 list<TimeAxisView*>::iterator tmp = i;
3361 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3362 _editor->selection->remove (*i);
3363 _added_time_axes.remove (*i);
3372 case SelectionStartTrim:
3374 start = _editor->selection->time[_editor->clicked_selection].start;
3375 end = _editor->selection->time[_editor->clicked_selection].end;
3377 if (pending_position > end) {
3380 start = pending_position;
3384 case SelectionEndTrim:
3386 start = _editor->selection->time[_editor->clicked_selection].start;
3387 end = _editor->selection->time[_editor->clicked_selection].end;
3389 if (pending_position < start) {
3392 end = pending_position;
3399 start = _editor->selection->time[_editor->clicked_selection].start;
3400 end = _editor->selection->time[_editor->clicked_selection].end;
3402 length = end - start;
3404 start = pending_position;
3405 _editor->snap_to (start);
3407 end = start + length;
3412 if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
3413 _editor->start_canvas_autoscroll (1, 0);
3417 _editor->selection->replace (_editor->clicked_selection, start, end);
3420 if (_operation == SelectionMove) {
3421 _editor->show_verbose_time_cursor(start, 10);
3423 _editor->show_verbose_time_cursor(pending_position, 10);
3428 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3430 Session* s = _editor->session();
3432 if (movement_occurred) {
3433 motion (event, false);
3434 /* XXX this is not object-oriented programming at all. ick */
3435 if (_editor->selection->time.consolidate()) {
3436 _editor->selection->TimeChanged ();
3439 /* XXX what if its a music time selection? */
3440 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3441 s->request_play_range (&_editor->selection->time, true);
3446 /* just a click, no pointer movement.*/
3448 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3449 _editor->selection->clear_time();
3452 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
3453 _editor->selection->set (_editor->clicked_axisview);
3456 if (s && s->get_play_range () && s->transport_rolling()) {
3457 s->request_stop (false, false);
3462 _editor->stop_canvas_autoscroll ();
3466 SelectionDrag::aborted ()
3471 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3476 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3477 _drag_rect->hide ();
3479 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3480 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3484 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3486 if (_editor->session() == 0) {
3490 Gdk::Cursor* cursor = 0;
3492 if (!_editor->temp_location) {
3493 _editor->temp_location = new Location (*_editor->session());
3496 switch (_operation) {
3497 case CreateRangeMarker:
3498 case CreateTransportMarker:
3499 case CreateCDMarker:
3501 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3506 cursor = _editor->selector_cursor;
3510 Drag::start_grab (event, cursor);
3512 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3516 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3518 nframes64_t start = 0;
3519 nframes64_t end = 0;
3520 ArdourCanvas::SimpleRect *crect;
3522 switch (_operation) {
3523 case CreateRangeMarker:
3524 crect = _editor->range_bar_drag_rect;
3526 case CreateTransportMarker:
3527 crect = _editor->transport_bar_drag_rect;
3529 case CreateCDMarker:
3530 crect = _editor->cd_marker_bar_drag_rect;
3533 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3538 nframes64_t const pf = adjusted_current_frame (event);
3540 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3541 nframes64_t grab = grab_frame ();
3542 _editor->snap_to (grab);
3544 if (pf < grab_frame()) {
3552 /* first drag: Either add to the selection
3553 or create a new selection.
3558 _editor->temp_location->set (start, end);
3562 update_item (_editor->temp_location);
3564 //_drag_rect->raise_to_top();
3569 if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
3570 _editor->start_canvas_autoscroll (1, 0);
3574 _editor->temp_location->set (start, end);
3576 double x1 = _editor->frame_to_pixel (start);
3577 double x2 = _editor->frame_to_pixel (end);
3578 crect->property_x1() = x1;
3579 crect->property_x2() = x2;
3581 update_item (_editor->temp_location);
3584 _editor->show_verbose_time_cursor (pf, 10);
3589 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3591 Location * newloc = 0;
3595 if (movement_occurred) {
3596 motion (event, false);
3599 switch (_operation) {
3600 case CreateRangeMarker:
3601 case CreateCDMarker:
3603 _editor->begin_reversible_command (_("new range marker"));
3604 XMLNode &before = _editor->session()->locations()->get_state();
3605 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3606 if (_operation == CreateCDMarker) {
3607 flags = Location::IsRangeMarker | Location::IsCDMarker;
3608 _editor->cd_marker_bar_drag_rect->hide();
3611 flags = Location::IsRangeMarker;
3612 _editor->range_bar_drag_rect->hide();
3614 newloc = new Location (
3615 *_editor->session(), _editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags
3618 _editor->session()->locations()->add (newloc, true);
3619 XMLNode &after = _editor->session()->locations()->get_state();
3620 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3621 _editor->commit_reversible_command ();
3625 case CreateTransportMarker:
3626 // popup menu to pick loop or punch
3627 _editor->new_transport_marker_context_menu (&event->button, _item);
3631 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3633 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3638 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3640 if (end == max_frames) {
3641 end = _editor->session()->current_end_frame ();
3644 if (start == max_frames) {
3645 start = _editor->session()->current_start_frame ();
3648 switch (_editor->mouse_mode) {
3650 /* find the two markers on either side and then make the selection from it */
3651 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set, false);
3655 /* find the two markers on either side of the click and make the range out of it */
3656 _editor->selection->set (start, end);
3665 _editor->stop_canvas_autoscroll ();
3669 RangeMarkerBarDrag::aborted ()
3675 RangeMarkerBarDrag::update_item (Location* location)
3677 double const x1 = _editor->frame_to_pixel (location->start());
3678 double const x2 = _editor->frame_to_pixel (location->end());
3680 _drag_rect->property_x1() = x1;
3681 _drag_rect->property_x2() = x2;
3685 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3687 Drag::start_grab (event, _editor->zoom_cursor);
3688 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3692 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3697 nframes64_t const pf = adjusted_current_frame (event);
3699 nframes64_t grab = grab_frame ();
3700 _editor->snap_to_with_modifier (grab, event);
3702 /* base start and end on initial click position */
3714 _editor->zoom_rect->show();
3715 _editor->zoom_rect->raise_to_top();
3718 _editor->reposition_zoom_rect(start, end);
3720 _editor->show_verbose_time_cursor (pf, 10);
3725 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3727 if (movement_occurred) {
3728 motion (event, false);
3730 if (grab_frame() < last_pointer_frame()) {
3731 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3733 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3736 _editor->temporal_zoom_to_frame (false, grab_frame());
3738 temporal_zoom_step (false);
3739 center_screen (grab_frame());
3743 _editor->zoom_rect->hide();
3747 MouseZoomDrag::aborted ()
3749 _editor->zoom_rect->hide ();
3752 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3755 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3756 region = &cnote->region_view();
3760 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3762 Drag::start_grab (event);
3765 drag_delta_note = 0;
3770 event_x = _drags->current_pointer_x();
3771 event_y = _drags->current_pointer_y();
3773 _item->property_parent().get_value()->w2i(event_x, event_y);
3775 last_x = region->snap_to_pixel(event_x);
3778 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3780 if (!(was_selected = cnote->selected())) {
3782 /* tertiary-click means extend selection - we'll do that on button release,
3783 so don't add it here, because otherwise we make it hard to figure
3784 out the "extend-to" range.
3787 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3790 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3793 region->note_selected (cnote, true);
3795 region->unique_select (cnote);
3802 NoteDrag::motion (GdkEvent*, bool)
3804 MidiStreamView* streamview = region->midi_stream_view();
3808 event_x = _drags->current_pointer_x();
3809 event_y = _drags->current_pointer_y();
3811 _item->property_parent().get_value()->w2i(event_x, event_y);
3813 event_x = region->snap_to_pixel(event_x);
3815 double dx = event_x - last_x;
3816 double dy = event_y - last_y;
3821 // Snap to note rows
3823 if (abs (dy) < streamview->note_height()) {
3826 int8_t this_delta_note;
3828 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3830 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3832 drag_delta_note -= this_delta_note;
3833 dy = streamview->note_height() * this_delta_note;
3834 last_y = last_y + dy;
3839 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3840 Evoral::MusicalTime new_time;
3843 nframes64_t start_frames = region->beats_to_frames(cnote->note()->time());
3844 if (drag_delta_x >= 0) {
3845 start_frames += region->snap_frame_to_frame(_editor->pixel_to_frame(drag_delta_x));
3847 start_frames -= region->snap_frame_to_frame(_editor->pixel_to_frame(-drag_delta_x));
3849 new_time = region->frames_to_beats(start_frames);
3851 new_time = cnote->note()->time();
3854 boost::shared_ptr<Evoral::Note<Evoral::MusicalTime> > check_note (
3855 new Evoral::Note<Evoral::MusicalTime> (cnote->note()->channel(),
3857 cnote->note()->length(),
3858 cnote->note()->note() + drag_delta_note,
3859 cnote->note()->velocity()));
3861 region->move_selection (dx, dy);
3864 snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (cnote->note()->note() + drag_delta_note).c_str(),
3865 (int) floor ((cnote->note()->note() + drag_delta_note)));
3866 _editor->show_verbose_canvas_cursor_with (buf);
3871 NoteDrag::finished (GdkEvent* ev, bool moved)
3873 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3876 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3879 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3881 region->note_deselected (cnote);
3884 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3885 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3887 if (!extend && !add && region->selection_size() > 1) {
3888 region->unique_select(cnote);
3889 } else if (extend) {
3890 region->note_selected (cnote, true, true);
3892 /* it was added during button press */
3897 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3902 NoteDrag::aborted ()
3907 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3910 , _nothing_to_drag (false)
3912 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3915 _line = _atav->line ();
3919 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3921 Drag::start_grab (event, cursor);
3923 list<ControlPoint*> points;
3925 XMLNode* state = &_line->get_state ();
3927 if (_ranges.empty()) {
3929 uint32_t const N = _line->npoints ();
3930 for (uint32_t i = 0; i < N; ++i) {
3931 points.push_back (_line->nth (i));
3936 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3937 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3939 /* fade into and out of the region that we're dragging;
3940 64 samples length plucked out of thin air.
3942 nframes64_t const h = (j->start + j->end) / 2;
3943 nframes64_t a = j->start + 64;
3947 nframes64_t b = j->end - 64;
3952 the_list->add (j->start, the_list->eval (j->start));
3953 _line->add_always_in_view (j->start);
3954 the_list->add (a, the_list->eval (a));
3955 _line->add_always_in_view (a);
3956 the_list->add (b, the_list->eval (b));
3957 _line->add_always_in_view (b);
3958 the_list->add (j->end, the_list->eval (j->end));
3959 _line->add_always_in_view (j->end);
3962 uint32_t const N = _line->npoints ();
3963 for (uint32_t i = 0; i < N; ++i) {
3965 ControlPoint* p = _line->nth (i);
3967 list<AudioRange>::const_iterator j = _ranges.begin ();
3968 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3972 if (j != _ranges.end()) {
3973 points.push_back (p);
3978 if (points.empty()) {
3979 _nothing_to_drag = true;
3983 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3987 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3989 if (_nothing_to_drag) {
3993 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3995 /* we are ignoring x position for this drag, so we can just pass in anything */
3996 _line->drag_motion (0, f, true, false);
4000 AutomationRangeDrag::finished (GdkEvent* event, bool)
4002 if (_nothing_to_drag) {
4006 motion (event, false);
4008 _line->clear_always_in_view ();
4012 AutomationRangeDrag::aborted ()
4014 _line->clear_always_in_view ();
4018 DraggingView::DraggingView (RegionView* v)
4021 initial_y = v->get_canvas_group()->property_y ();