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;
549 if (regions_came_from_canvas()) {
550 total_dx = total_dx - grab_frame () + _pointer_frame_offset;
553 /* check that no regions have gone off the start of the session */
554 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
555 if ((i->view->region()->position() + total_dx) < 0) {
557 *pending_region_position = _last_frame_position;
562 _last_frame_position = *pending_region_position;
569 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
573 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
575 vector<int32_t>::iterator j;
577 /* *pointer* variables reflect things about the pointer; as we may be moving
578 multiple regions, much detail must be computed per-region */
580 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
581 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
582 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
583 is always 0 regardless of what the region's "real" layer is */
584 RouteTimeAxisView* current_pointer_view;
585 layer_t current_pointer_layer;
586 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
590 /* TimeAxisView that we were pointing at last time we entered this method */
591 TimeAxisView const * const last_pointer_view = _dest_trackview;
592 /* the order of the track that we were pointing at last time we entered this method */
593 int32_t const last_pointer_order = last_pointer_view->order ();
594 /* the layer that we were pointing at last time we entered this method */
595 layer_t const last_pointer_layer = _dest_layer;
597 int32_t pointer_order_span;
598 int32_t pointer_layer_span;
599 int32_t canvas_pointer_order_span;
601 bool const clamp_y_axis = compute_y_delta (
602 last_pointer_view, current_pointer_view,
603 last_pointer_layer, current_pointer_layer, tavs,
604 &pointer_order_span, &pointer_layer_span,
605 &canvas_pointer_order_span
608 nframes64_t pending_region_position;
609 double const x_delta = compute_x_delta (event, &pending_region_position);
611 /*************************************************************
613 ************************************************************/
615 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
616 /* haven't reached next snap point, and we're not switching
617 trackviews nor layers. nothing to do.
622 /*************************************************************
624 ************************************************************/
626 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
628 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
630 RegionView* rv = i->view;
632 if (rv->region()->locked()) {
636 /* here we are calculating the y distance from the
637 top of the first track view to the top of the region
638 area of the track view that we're working on */
640 /* this x value is just a dummy value so that we have something
645 /* distance from the top of this track view to the region area
646 of our track view is always 1 */
650 /* convert to world coordinates, ie distance from the top of
653 rv->get_canvas_frame()->i2w (ix1, iy1);
655 /* compensate for the ruler section and the vertical scrollbar position */
656 iy1 += _editor->get_trackview_group_vertical_offset ();
660 // hide any dependent views
662 rv->get_time_axis_view().hide_dependent_views (*rv);
665 reparent to a non scrolling group so that we can keep the
666 region selection above all time axis views.
667 reparenting means we have to move the rv as the two
668 parent groups have different coordinates.
671 rv->get_canvas_group()->property_y() = iy1 - 1;
672 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
674 rv->fake_set_opaque (true);
677 /* current view for this particular region */
678 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
679 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
681 if (pointer_order_span != 0 && !clamp_y_axis) {
683 /* INTER-TRACK MOVEMENT */
685 /* move through the height list to the track that the region is currently on */
686 vector<int32_t>::iterator j = tavs.height_list.begin ();
688 while (j != tavs.height_list.end () && x != rtv->order ()) {
694 int32_t temp_pointer_order_span = canvas_pointer_order_span;
696 if (j != tavs.height_list.end ()) {
698 /* Account for layers in the original and
699 destination tracks. If we're moving around in layers we assume
700 that only one track is involved, so it's ok to use *pointer*
703 StreamView* lv = last_pointer_view->view ();
706 /* move to the top of the last trackview */
707 if (lv->layer_display () == Stacked) {
708 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
711 StreamView* cv = current_pointer_view->view ();
714 /* move to the right layer on the current trackview */
715 if (cv->layer_display () == Stacked) {
716 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
719 /* And for being on a non-topmost layer on the new
722 while (temp_pointer_order_span > 0) {
723 /* we're moving up canvas-wise,
724 so we need to find the next track height
726 if (j != tavs.height_list.begin()) {
730 if (x != last_pointer_order) {
732 ++temp_pointer_order_span;
737 temp_pointer_order_span--;
740 while (temp_pointer_order_span < 0) {
744 if (x != last_pointer_order) {
746 --temp_pointer_order_span;
750 if (j != tavs.height_list.end()) {
754 temp_pointer_order_span++;
758 /* find out where we'll be when we move and set height accordingly */
760 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
761 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
762 rv->set_height (temp_rtv->view()->child_height());
764 /* if you un-comment the following, the region colours will follow
765 the track colours whilst dragging; personally
766 i think this can confuse things, but never mind.
769 //const GdkColor& col (temp_rtv->view->get_region_color());
770 //rv->set_color (const_cast<GdkColor&>(col));
774 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
776 /* INTER-LAYER MOVEMENT in the same track */
777 y_delta = rtv->view()->child_height () * pointer_layer_span;
781 _editor->mouse_brush_insert_region (rv, pending_region_position);
783 rv->move (x_delta, y_delta);
786 } /* foreach region */
788 _total_x_delta += x_delta;
791 _editor->cursor_group->raise_to_top();
794 if (x_delta != 0 && !_brushing) {
795 _editor->show_verbose_time_cursor (_last_frame_position, 10);
800 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
802 if (_copy && first_move) {
803 copy_regions (event);
806 RegionMotionDrag::motion (event, first_move);
810 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
812 vector<RegionView*> copies;
813 boost::shared_ptr<Track> tr;
814 boost::shared_ptr<Playlist> from_playlist;
815 boost::shared_ptr<Playlist> to_playlist;
816 RegionSelection new_views;
817 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
818 PlaylistSet modified_playlists;
819 PlaylistSet frozen_playlists;
820 list <sigc::connection> modified_playlist_connections;
821 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
822 nframes64_t drag_delta;
823 bool changed_tracks, changed_position;
824 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
825 RouteTimeAxisView* source_tv;
826 vector<StatefulDiffCommand*> sdc;
828 if (!movement_occurred) {
834 /* all changes were made during motion event handlers */
837 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
838 copies.push_back (i->view);
845 /* reverse this here so that we have the correct logic to finalize
849 if (Config->get_edit_mode() == Lock) {
850 _x_constrained = !_x_constrained;
854 if (_x_constrained) {
855 _editor->begin_reversible_command (_("fixed time region copy"));
857 _editor->begin_reversible_command (_("region copy"));
860 if (_x_constrained) {
861 _editor->begin_reversible_command (_("fixed time region drag"));
863 _editor->begin_reversible_command (_("region drag"));
867 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
868 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
870 drag_delta = _primary->region()->position() - _last_frame_position;
872 _editor->update_canvas_now ();
874 /* make a list of where each region ended up */
875 final = find_time_axis_views_and_layers ();
877 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
879 RegionView* rv = i->view;
880 RouteTimeAxisView* dest_rtv = final[rv].first;
881 layer_t dest_layer = final[rv].second;
885 from_playlist.reset ();
886 to_playlist.reset ();
888 if (rv->region()->locked()) {
893 if (changed_position && !_x_constrained) {
894 where = rv->region()->position() - drag_delta;
896 where = rv->region()->position();
899 boost::shared_ptr<Region> new_region;
902 /* we already made a copy */
903 new_region = rv->region();
905 /* undo the previous hide_dependent_views so that xfades don't
906 disappear on copying regions
909 //rv->get_time_axis_view().reveal_dependent_views (*rv);
911 } else if (changed_tracks && dest_rtv->playlist()) {
912 new_region = RegionFactory::create (rv->region());
915 if (changed_tracks || _copy) {
917 to_playlist = dest_rtv->playlist();
924 _editor->latest_regionviews.clear ();
926 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
928 insert_result = modified_playlists.insert (to_playlist);
930 if (insert_result.second) {
931 to_playlist->clear_history ();
934 cerr << "To playlist " << to_playlist->name() << " region history contains "
935 << to_playlist->region_list().change().added.size() << " adds and "
936 << to_playlist->region_list().change().removed.size() << " removes\n";
938 cerr << "Adding new region " << new_region->id() << " based on "
939 << rv->region()->id() << endl;
941 to_playlist->add_region (new_region, where);
943 if (dest_rtv->view()->layer_display() == Stacked) {
944 new_region->set_layer (dest_layer);
945 new_region->set_pending_explicit_relayer (true);
950 if (!_editor->latest_regionviews.empty()) {
951 // XXX why just the first one ? we only expect one
952 // commented out in nick_m's canvas reworking. is that intended?
953 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
954 new_views.push_back (_editor->latest_regionviews.front());
958 rv->region()->clear_history ();
961 motion on the same track. plonk the previously reparented region
962 back to its original canvas group (its streamview).
963 No need to do anything for copies as they are fake regions which will be deleted.
966 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
967 rv->get_canvas_group()->property_y() = i->initial_y;
968 rv->get_time_axis_view().reveal_dependent_views (*rv);
970 /* just change the model */
972 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
974 if (dest_rtv->view()->layer_display() == Stacked) {
975 rv->region()->set_layer (dest_layer);
976 rv->region()->set_pending_explicit_relayer (true);
979 /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
981 frozen_insert_result = frozen_playlists.insert(playlist);
983 if (frozen_insert_result.second) {
987 cerr << "Moving region " << rv->region()->id() << endl;
989 rv->region()->set_position (where, (void*) this);
991 sdc.push_back (new StatefulDiffCommand (rv->region()));
994 if (changed_tracks && !_copy) {
996 /* get the playlist where this drag started. we can't use rv->region()->playlist()
997 because we may have copied the region and it has not been attached to a playlist.
1000 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
1001 tr = source_tv->track();
1002 from_playlist = tr->playlist();
1006 assert (from_playlist);
1008 /* moved to a different audio track, without copying */
1010 /* the region that used to be in the old playlist is not
1011 moved to the new one - we use a copy of it. as a result,
1012 any existing editor for the region should no longer be
1016 rv->hide_region_editor();
1017 rv->fake_set_opaque (false);
1019 /* remove the region from the old playlist */
1021 insert_result = modified_playlists.insert (from_playlist);
1023 if (insert_result.second) {
1024 from_playlist->clear_history ();
1027 cerr << "From playlist " << from_playlist->name() << " region history contains "
1028 << from_playlist->region_list().change().added.size() << " adds and "
1029 << from_playlist->region_list().change().removed.size() << " removes\n";
1031 cerr << "removing region " << rv->region() << endl;
1033 from_playlist->remove_region (rv->region());
1035 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1036 was selected in all of them, then removing it from a playlist will have removed all
1037 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1038 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1039 corresponding regionview, and the selection is now empty).
1041 this could have invalidated any and all iterators into the region selection.
1043 the heuristic we use here is: if the region selection is empty, break out of the loop
1044 here. if the region selection is not empty, then restart the loop because we know that
1045 we must have removed at least the region(view) we've just been working on as well as any
1046 that we processed on previous iterations.
1048 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1049 we can just iterate.
1052 if (_views.empty()) {
1054 sdc.push_back (new StatefulDiffCommand (to_playlist));
1055 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1058 if (from_playlist && (from_playlist != to_playlist)) {
1059 sdc.push_back (new StatefulDiffCommand (from_playlist));
1060 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1072 copies.push_back (rv);
1075 cerr << "Done with TV, top = " << to_playlist << " from = " << from_playlist << endl;
1078 sdc.push_back (new StatefulDiffCommand (to_playlist));
1079 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1082 if (from_playlist && (from_playlist != to_playlist)) {
1083 sdc.push_back (new StatefulDiffCommand (from_playlist));
1084 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1089 if we've created new regions either by copying or moving
1090 to a new track, we want to replace the old selection with the new ones
1093 if (new_views.size() > 0) {
1094 _editor->selection->set (new_views);
1097 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1102 for (vector<StatefulDiffCommand*>::iterator i = sdc.begin(); i != sdc.end(); ++i) {
1103 _editor->session()->add_command (*i);
1106 _editor->commit_reversible_command ();
1108 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1114 RegionMoveDrag::aborted ()
1118 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1125 RegionMotionDrag::aborted ();
1130 RegionMotionDrag::aborted ()
1132 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1133 RegionView* rv = i->view;
1134 TimeAxisView* tv = &(rv->get_time_axis_view ());
1135 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1137 rv->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1138 rv->get_canvas_group()->property_y() = 0;
1139 rv->get_time_axis_view().reveal_dependent_views (*rv);
1140 rv->fake_set_opaque (false);
1141 rv->move (-_total_x_delta, 0);
1142 rv->set_height (rtv->view()->child_height ());
1145 _editor->update_canvas_now ();
1150 RegionMotionDrag::x_move_allowed () const
1152 if (Config->get_edit_mode() == Lock) {
1153 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1154 return _x_constrained;
1157 return !_x_constrained;
1161 RegionMotionDrag::copy_regions (GdkEvent* event)
1163 /* duplicate the regionview(s) and region(s) */
1165 list<DraggingView> new_regionviews;
1167 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1169 RegionView* rv = i->view;
1170 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1171 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1173 const boost::shared_ptr<const Region> original = rv->region();
1174 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1175 region_copy->set_position (original->position(), this);
1179 boost::shared_ptr<AudioRegion> audioregion_copy
1180 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1182 nrv = new AudioRegionView (*arv, audioregion_copy);
1184 boost::shared_ptr<MidiRegion> midiregion_copy
1185 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1186 nrv = new MidiRegionView (*mrv, midiregion_copy);
1191 nrv->get_canvas_group()->show ();
1192 new_regionviews.push_back (DraggingView (nrv));
1194 /* swap _primary to the copy */
1196 if (rv == _primary) {
1200 /* ..and deselect the one we copied */
1202 rv->set_selected (false);
1205 if (new_regionviews.empty()) {
1209 /* reflect the fact that we are dragging the copies */
1211 _views = new_regionviews;
1213 swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0);
1216 sync the canvas to what we think is its current state
1217 without it, the canvas seems to
1218 "forget" to update properly after the upcoming reparent()
1219 ..only if the mouse is in rapid motion at the time of the grab.
1220 something to do with regionview creation taking so long?
1222 _editor->update_canvas_now();
1226 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1228 /* Which trackview is this ? */
1230 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1231 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1232 (*layer) = tvp.second;
1234 if (*tv && (*tv)->layer_display() == Overlaid) {
1238 /* The region motion is only processed if the pointer is over
1242 if (!(*tv) || !(*tv)->is_track()) {
1243 /* To make sure we hide the verbose canvas cursor when the mouse is
1244 not held over and audiotrack.
1246 _editor->hide_verbose_canvas_cursor ();
1253 /** @param new_order New track order.
1254 * @param old_order Old track order.
1255 * @param visible_y_low Lowest visible order.
1256 * @return true if y movement should not happen, otherwise false.
1259 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1261 if (new_order != old_order) {
1263 /* this isn't the pointer track */
1267 /* moving up the canvas */
1268 if ( (new_order - y_span) >= tavs.visible_y_low) {
1272 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1273 int32_t visible_tracks = 0;
1274 while (visible_tracks < y_span ) {
1276 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1277 /* passing through a hidden track */
1282 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1283 /* moving to a non-track; disallow */
1289 /* moving beyond the lowest visible track; disallow */
1293 } else if (y_span < 0) {
1295 /* moving down the canvas */
1296 if ((new_order - y_span) <= tavs.visible_y_high) {
1298 int32_t visible_tracks = 0;
1300 while (visible_tracks > y_span ) {
1303 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1304 /* passing through a hidden track */
1309 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1310 /* moving to a non-track; disallow */
1317 /* moving beyond the highest visible track; disallow */
1324 /* this is the pointer's track */
1326 if ((new_order - y_span) > tavs.visible_y_high) {
1327 /* we will overflow */
1329 } else if ((new_order - y_span) < tavs.visible_y_low) {
1330 /* we will overflow */
1339 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1340 : RegionMotionDrag (e, i, p, v, b),
1343 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1345 _dest_trackview = tv;
1346 if (tv->layer_display() == Overlaid) {
1349 _dest_layer = _primary->region()->layer ();
1353 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1354 if (rtv && rtv->is_track()) {
1355 speed = rtv->track()->speed ();
1358 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1362 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1364 RegionMotionDrag::start_grab (event, c);
1366 _pointer_frame_offset = grab_frame() - _last_frame_position;
1369 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1370 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1372 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1373 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1375 _primary = v->view()->create_region_view (r, false, false);
1377 _primary->get_canvas_group()->show ();
1378 _primary->set_position (pos, 0);
1379 _views.push_back (DraggingView (_primary));
1381 _last_frame_position = pos;
1383 _item = _primary->get_canvas_group ();
1384 _dest_trackview = v;
1385 _dest_layer = _primary->region()->layer ();
1388 map<RegionView*, pair<RouteTimeAxisView*, int> >
1389 RegionMotionDrag::find_time_axis_views_and_layers ()
1391 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1393 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1395 double ix1, ix2, iy1, iy2;
1396 RegionView* rv = i->view;
1397 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1398 rv->get_canvas_frame()->i2w (ix1, iy1);
1399 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1401 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1402 tav[rv] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1410 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1412 _editor->update_canvas_now ();
1414 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1416 RouteTimeAxisView* dest_rtv = final[_primary].first;
1418 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1419 _primary->get_canvas_group()->property_y() = 0;
1421 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1423 _editor->begin_reversible_command (_("insert region"));
1424 playlist->clear_history ();
1425 playlist->add_region (_primary->region (), _last_frame_position);
1426 _editor->session()->add_command (new StatefulDiffCommand (playlist));
1427 _editor->commit_reversible_command ();
1435 RegionInsertDrag::aborted ()
1442 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1443 : RegionMoveDrag (e, i, p, v, false, false)
1448 struct RegionSelectionByPosition {
1449 bool operator() (RegionView*a, RegionView* b) {
1450 return a->region()->position () < b->region()->position();
1455 RegionSpliceDrag::motion (GdkEvent* event, bool)
1457 RouteTimeAxisView* tv;
1460 if (!check_possible (&tv, &layer)) {
1466 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1472 RegionSelection copy (_editor->selection->regions);
1474 RegionSelectionByPosition cmp;
1477 nframes64_t const pf = adjusted_current_frame (event);
1479 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1481 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1487 boost::shared_ptr<Playlist> playlist;
1489 if ((playlist = atv->playlist()) == 0) {
1493 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1498 if (pf < (*i)->region()->last_frame() + 1) {
1502 if (pf > (*i)->region()->first_frame()) {
1508 playlist->shuffle ((*i)->region(), dir);
1513 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1519 RegionSpliceDrag::aborted ()
1524 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1526 _view (dynamic_cast<MidiTimeAxisView*> (v))
1532 RegionCreateDrag::motion (GdkEvent *, bool first_move)
1535 /* don't use a zero-length region otherwise its region view will be hidden when it is created */
1536 _region = _view->add_region (grab_frame(), 1, false);
1538 if (_drags->current_pointer_frame() < grab_frame()) {
1539 _region->set_position (_drags->current_pointer_frame(), this);
1542 /* again, don't use a zero-length region (see above) */
1543 framecnt_t const len = abs (_drags->current_pointer_frame() - grab_frame ());
1544 _region->set_length (len < 1 ? 1 : len, this);
1549 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1551 if (movement_occurred) {
1552 _editor->commit_reversible_command ();
1557 RegionCreateDrag::aborted ()
1562 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1570 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/)
1572 Gdk::Cursor* cursor;
1573 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1575 Drag::start_grab (event);
1577 region = &cnote->region_view();
1579 double const region_start = region->get_position_pixels();
1580 double const middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1582 if (grab_x() <= middle_point) {
1583 cursor = _editor->left_side_trim_cursor;
1586 cursor = _editor->right_side_trim_cursor;
1590 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, *cursor, event->motion.time);
1592 if (event->motion.state & Keyboard::PrimaryModifier) {
1598 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1600 if (ms.size() > 1) {
1601 /* has to be relative, may make no sense otherwise */
1605 /* select this note; if it is already selected, preserve the existing selection,
1606 otherwise make this note the only one selected.
1608 region->note_selected (cnote, cnote->selected ());
1610 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1611 MidiRegionSelection::iterator next;
1614 (*r)->begin_resizing (at_front);
1620 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1622 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1623 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1624 (*r)->update_resizing (dynamic_cast<ArdourCanvas::CanvasNote*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
1629 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1631 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1632 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1633 (*r)->commit_resizing (dynamic_cast<ArdourCanvas::CanvasNote*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
1638 NoteResizeDrag::aborted ()
1644 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1650 RegionGainDrag::finished (GdkEvent *, bool)
1656 RegionGainDrag::aborted ()
1661 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1662 : RegionDrag (e, i, p, v)
1663 , _have_transaction (false)
1669 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1672 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1673 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1675 if (tv && tv->is_track()) {
1676 speed = tv->track()->speed();
1679 nframes64_t const region_start = (nframes64_t) (_primary->region()->position() / speed);
1680 nframes64_t const region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1681 nframes64_t const region_length = (nframes64_t) (_primary->region()->length() / speed);
1683 nframes64_t const pf = adjusted_current_frame (event);
1685 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1686 _operation = ContentsTrim;
1687 Drag::start_grab (event, _editor->trimmer_cursor);
1689 /* These will get overridden for a point trim.*/
1690 if (pf < (region_start + region_length/2)) {
1691 /* closer to start */
1692 _operation = StartTrim;
1693 Drag::start_grab (event, _editor->left_side_trim_cursor);
1696 _operation = EndTrim;
1697 Drag::start_grab (event, _editor->right_side_trim_cursor);
1701 switch (_operation) {
1703 _editor->show_verbose_time_cursor (region_start, 10);
1706 _editor->show_verbose_time_cursor (region_end, 10);
1709 _editor->show_verbose_time_cursor (pf, 10);
1715 TrimDrag::motion (GdkEvent* event, bool first_move)
1717 RegionView* rv = _primary;
1719 /* snap modifier works differently here..
1720 its current state has to be passed to the
1721 various trim functions in order to work properly
1725 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1726 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1727 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1729 if (tv && tv->is_track()) {
1730 speed = tv->track()->speed();
1733 nframes64_t const pf = adjusted_current_frame (event);
1739 switch (_operation) {
1741 trim_type = "Region start trim";
1744 trim_type = "Region end trim";
1747 trim_type = "Region content trim";
1751 _editor->begin_reversible_command (trim_type);
1752 _have_transaction = true;
1754 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1755 RegionView* rv = i->view;
1756 rv->fake_set_opaque(false);
1757 rv->enable_display (false);
1758 rv->region()->clear_history ();
1759 rv->region()->suspend_property_changes ();
1761 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
1764 arv->temporarily_hide_envelope ();
1767 boost::shared_ptr<Playlist> pl = rv->region()->playlist();
1768 insert_result = _editor->motion_frozen_playlists.insert (pl);
1770 if (insert_result.second) {
1776 bool non_overlap_trim = false;
1778 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1779 non_overlap_trim = true;
1782 switch (_operation) {
1784 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1785 _editor->single_start_trim (*i->view, pf, non_overlap_trim);
1790 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1791 _editor->single_end_trim (*i->view, pf, non_overlap_trim);
1797 bool swap_direction = false;
1799 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1800 swap_direction = true;
1803 nframes64_t frame_delta = 0;
1805 bool left_direction = false;
1806 if (last_pointer_frame() > pf) {
1807 left_direction = true;
1810 if (left_direction) {
1811 frame_delta = (last_pointer_frame() - pf);
1813 frame_delta = (pf - last_pointer_frame());
1816 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1817 _editor->single_contents_trim (*i->view, frame_delta, left_direction, swap_direction);
1823 switch (_operation) {
1825 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1828 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1831 _editor->show_verbose_time_cursor (pf, 10);
1838 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1840 if (movement_occurred) {
1841 motion (event, false);
1843 if (!_editor->selection->selected (_primary)) {
1844 _editor->thaw_region_after_trim (*_primary);
1847 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1848 _editor->thaw_region_after_trim (*i->view);
1849 i->view->enable_display (true);
1850 i->view->fake_set_opaque (true);
1851 if (_have_transaction) {
1852 _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
1856 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1860 _editor->motion_frozen_playlists.clear ();
1862 if (_have_transaction) {
1863 _editor->commit_reversible_command();
1867 /* no mouse movement */
1868 _editor->point_trim (event, adjusted_current_frame (event));
1873 TrimDrag::aborted ()
1875 /* Our motion method is changing model state, so use the Undo system
1876 to cancel. Perhaps not ideal, as this will leave an Undo point
1877 behind which may be slightly odd from the user's point of view.
1882 if (_have_transaction) {
1887 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1891 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1896 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1899 // create a dummy marker for visual representation of moving the copy.
1900 // The actual copying is not done before we reach the finish callback.
1902 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1903 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1904 *new MeterSection (_marker->meter()));
1906 _item = &new_marker->the_item ();
1907 _marker = new_marker;
1911 MetricSection& section (_marker->meter());
1913 if (!section.movable()) {
1919 Drag::start_grab (event, cursor);
1921 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1923 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1927 MeterMarkerDrag::motion (GdkEvent* event, bool)
1929 nframes64_t const pf = adjusted_current_frame (event);
1931 _marker->set_position (pf);
1933 _editor->show_verbose_time_cursor (pf, 10);
1937 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1939 if (!movement_occurred) {
1943 motion (event, false);
1947 TempoMap& map (_editor->session()->tempo_map());
1948 map.bbt_time (last_pointer_frame(), when);
1950 if (_copy == true) {
1951 _editor->begin_reversible_command (_("copy meter mark"));
1952 XMLNode &before = map.get_state();
1953 map.add_meter (_marker->meter(), when);
1954 XMLNode &after = map.get_state();
1955 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1956 _editor->commit_reversible_command ();
1958 // delete the dummy marker we used for visual representation of copying.
1959 // a new visual marker will show up automatically.
1962 _editor->begin_reversible_command (_("move meter mark"));
1963 XMLNode &before = map.get_state();
1964 map.move_meter (_marker->meter(), when);
1965 XMLNode &after = map.get_state();
1966 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1967 _editor->commit_reversible_command ();
1972 MeterMarkerDrag::aborted ()
1974 _marker->set_position (_marker->meter().frame ());
1977 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1981 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1986 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1991 // create a dummy marker for visual representation of moving the copy.
1992 // The actual copying is not done before we reach the finish callback.
1994 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1995 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1996 *new TempoSection (_marker->tempo()));
1998 _item = &new_marker->the_item ();
1999 _marker = new_marker;
2003 MetricSection& section (_marker->tempo());
2005 if (!section.movable()) {
2010 Drag::start_grab (event, cursor);
2012 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
2013 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2017 TempoMarkerDrag::motion (GdkEvent* event, bool)
2019 nframes64_t const pf = adjusted_current_frame (event);
2020 _marker->set_position (pf);
2021 _editor->show_verbose_time_cursor (pf, 10);
2025 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2027 if (!movement_occurred) {
2031 motion (event, false);
2035 TempoMap& map (_editor->session()->tempo_map());
2036 map.bbt_time (last_pointer_frame(), when);
2038 if (_copy == true) {
2039 _editor->begin_reversible_command (_("copy tempo mark"));
2040 XMLNode &before = map.get_state();
2041 map.add_tempo (_marker->tempo(), when);
2042 XMLNode &after = map.get_state();
2043 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2044 _editor->commit_reversible_command ();
2046 // delete the dummy marker we used for visual representation of copying.
2047 // a new visual marker will show up automatically.
2050 _editor->begin_reversible_command (_("move tempo mark"));
2051 XMLNode &before = map.get_state();
2052 map.move_tempo (_marker->tempo(), when);
2053 XMLNode &after = map.get_state();
2054 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2055 _editor->commit_reversible_command ();
2060 TempoMarkerDrag::aborted ()
2062 _marker->set_position (_marker->tempo().frame());
2065 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2069 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2074 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2076 Drag::start_grab (event, c);
2080 nframes64_t where = _editor->event_frame (event, 0, 0);
2082 _editor->snap_to_with_modifier (where, event);
2083 _editor->playhead_cursor->set_position (where);
2087 if (_cursor == _editor->playhead_cursor) {
2088 _editor->_dragging_playhead = true;
2090 Session* s = _editor->session ();
2093 if (_was_rolling && _stop) {
2097 if (s->is_auditioning()) {
2098 s->cancel_audition ();
2101 s->request_suspend_timecode_transmission ();
2103 if (s->timecode_transmission_suspended ()) {
2104 nframes64_t const f = _editor->playhead_cursor->current_frame;
2105 s->send_mmc_locate (f);
2106 s->send_full_time_code (f);
2111 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2113 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2117 CursorDrag::motion (GdkEvent* event, bool)
2119 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2121 if (adjusted_frame == last_pointer_frame()) {
2125 _cursor->set_position (adjusted_frame);
2127 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2129 Session* s = _editor->session ();
2130 if (s && _item == &_editor->playhead_cursor->canvas_item && s->timecode_transmission_suspended ()) {
2131 nframes64_t const f = _editor->playhead_cursor->current_frame;
2132 s->send_mmc_locate (f);
2133 s->send_full_time_code (f);
2138 _editor->update_canvas_now ();
2140 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2144 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2146 _editor->_dragging_playhead = false;
2148 if (!movement_occurred && _stop) {
2152 motion (event, false);
2154 if (_item == &_editor->playhead_cursor->canvas_item) {
2155 Session* s = _editor->session ();
2157 s->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2158 _editor->_pending_locate_request = true;
2159 s->request_resume_timecode_transmission ();
2165 CursorDrag::aborted ()
2167 if (_editor->_dragging_playhead) {
2168 _editor->session()->request_resume_timecode_transmission ();
2169 _editor->_dragging_playhead = false;
2172 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2175 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2176 : RegionDrag (e, i, p, v)
2182 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2184 Drag::start_grab (event, cursor);
2186 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2187 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2189 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2190 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2195 FadeInDrag::motion (GdkEvent* event, bool)
2197 nframes64_t fade_length;
2199 nframes64_t const pos = adjusted_current_frame (event);
2201 boost::shared_ptr<Region> region = _primary->region ();
2203 if (pos < (region->position() + 64)) {
2204 fade_length = 64; // this should be a minimum defined somewhere
2205 } else if (pos > region->last_frame()) {
2206 fade_length = region->length();
2208 fade_length = pos - region->position();
2211 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2213 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2219 tmp->reset_fade_in_shape_width (fade_length);
2222 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2226 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2228 if (!movement_occurred) {
2232 nframes64_t fade_length;
2234 nframes64_t const pos = adjusted_current_frame (event);
2236 boost::shared_ptr<Region> region = _primary->region ();
2238 if (pos < (region->position() + 64)) {
2239 fade_length = 64; // this should be a minimum defined somewhere
2240 } else if (pos > region->last_frame()) {
2241 fade_length = region->length();
2243 fade_length = pos - region->position();
2246 _editor->begin_reversible_command (_("change fade in length"));
2248 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2250 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2256 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2257 XMLNode &before = alist->get_state();
2259 tmp->audio_region()->set_fade_in_length (fade_length);
2260 tmp->audio_region()->set_fade_in_active (true);
2262 XMLNode &after = alist->get_state();
2263 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2266 _editor->commit_reversible_command ();
2270 FadeInDrag::aborted ()
2272 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2273 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2279 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2283 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2284 : RegionDrag (e, i, p, v)
2290 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2292 Drag::start_grab (event, cursor);
2294 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2295 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2297 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2298 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2302 FadeOutDrag::motion (GdkEvent* event, bool)
2304 nframes64_t fade_length;
2306 nframes64_t const pos = adjusted_current_frame (event);
2308 boost::shared_ptr<Region> region = _primary->region ();
2310 if (pos > (region->last_frame() - 64)) {
2311 fade_length = 64; // this should really be a minimum fade defined somewhere
2313 else if (pos < region->position()) {
2314 fade_length = region->length();
2317 fade_length = region->last_frame() - pos;
2320 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2322 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2328 tmp->reset_fade_out_shape_width (fade_length);
2331 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2335 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2337 if (!movement_occurred) {
2341 nframes64_t fade_length;
2343 nframes64_t const pos = adjusted_current_frame (event);
2345 boost::shared_ptr<Region> region = _primary->region ();
2347 if (pos > (region->last_frame() - 64)) {
2348 fade_length = 64; // this should really be a minimum fade defined somewhere
2350 else if (pos < region->position()) {
2351 fade_length = region->length();
2354 fade_length = region->last_frame() - pos;
2357 _editor->begin_reversible_command (_("change fade out length"));
2359 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2361 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2367 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2368 XMLNode &before = alist->get_state();
2370 tmp->audio_region()->set_fade_out_length (fade_length);
2371 tmp->audio_region()->set_fade_out_active (true);
2373 XMLNode &after = alist->get_state();
2374 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2377 _editor->commit_reversible_command ();
2381 FadeOutDrag::aborted ()
2383 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2384 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2390 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2394 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2397 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2400 _points.push_back (Gnome::Art::Point (0, 0));
2401 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2403 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2404 _line->property_width_pixels() = 1;
2405 _line->property_points () = _points;
2408 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2411 MarkerDrag::~MarkerDrag ()
2413 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2419 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2421 Drag::start_grab (event, cursor);
2425 Location *location = _editor->find_location_from_marker (_marker, is_start);
2426 _editor->_dragging_edit_point = true;
2428 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2430 update_item (location);
2432 // _drag_line->show();
2433 // _line->raise_to_top();
2436 _editor->show_verbose_time_cursor (location->start(), 10);
2438 _editor->show_verbose_time_cursor (location->end(), 10);
2441 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2444 case Selection::Toggle:
2445 _editor->selection->toggle (_marker);
2447 case Selection::Set:
2448 if (!_editor->selection->selected (_marker)) {
2449 _editor->selection->set (_marker);
2452 case Selection::Extend:
2454 Locations::LocationList ll;
2455 list<Marker*> to_add;
2457 _editor->selection->markers.range (s, e);
2458 s = min (_marker->position(), s);
2459 e = max (_marker->position(), e);
2462 if (e < max_frames) {
2465 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2466 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2467 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2470 to_add.push_back (lm->start);
2473 to_add.push_back (lm->end);
2477 if (!to_add.empty()) {
2478 _editor->selection->add (to_add);
2482 case Selection::Add:
2483 _editor->selection->add (_marker);
2487 /* Set up copies for us to manipulate during the drag */
2489 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2490 Location* l = _editor->find_location_from_marker (*i, is_start);
2491 _copied_locations.push_back (new Location (*l));
2496 MarkerDrag::motion (GdkEvent* event, bool)
2498 nframes64_t f_delta = 0;
2500 bool move_both = false;
2502 Location *real_location;
2503 Location *copy_location = 0;
2505 nframes64_t const newframe = adjusted_current_frame (event);
2507 nframes64_t next = newframe;
2509 if (newframe == last_pointer_frame()) {
2513 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2517 MarkerSelection::iterator i;
2518 list<Location*>::iterator x;
2520 /* find the marker we're dragging, and compute the delta */
2522 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2523 x != _copied_locations.end() && i != _editor->selection->markers.end();
2529 if (marker == _marker) {
2531 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2536 if (real_location->is_mark()) {
2537 f_delta = newframe - copy_location->start();
2541 switch (marker->type()) {
2543 case Marker::LoopStart:
2544 case Marker::PunchIn:
2545 f_delta = newframe - copy_location->start();
2549 case Marker::LoopEnd:
2550 case Marker::PunchOut:
2551 f_delta = newframe - copy_location->end();
2554 /* what kind of marker is this ? */
2562 if (i == _editor->selection->markers.end()) {
2563 /* hmm, impossible - we didn't find the dragged marker */
2567 /* now move them all */
2569 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2570 x != _copied_locations.end() && i != _editor->selection->markers.end();
2576 /* call this to find out if its the start or end */
2578 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2582 if (real_location->locked()) {
2586 if (copy_location->is_mark()) {
2590 copy_location->set_start (copy_location->start() + f_delta);
2594 nframes64_t new_start = copy_location->start() + f_delta;
2595 nframes64_t new_end = copy_location->end() + f_delta;
2597 if (is_start) { // start-of-range marker
2600 copy_location->set_start (new_start);
2601 copy_location->set_end (new_end);
2602 } else if (new_start < copy_location->end()) {
2603 copy_location->set_start (new_start);
2605 _editor->snap_to (next, 1, true);
2606 copy_location->set_end (next);
2607 copy_location->set_start (newframe);
2610 } else { // end marker
2613 copy_location->set_end (new_end);
2614 copy_location->set_start (new_start);
2615 } else if (new_end > copy_location->start()) {
2616 copy_location->set_end (new_end);
2617 } else if (newframe > 0) {
2618 _editor->snap_to (next, -1, true);
2619 copy_location->set_start (next);
2620 copy_location->set_end (newframe);
2625 update_item (copy_location);
2627 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2630 lm->set_position (copy_location->start(), copy_location->end());
2634 assert (!_copied_locations.empty());
2636 _editor->show_verbose_time_cursor (newframe, 10);
2639 _editor->update_canvas_now ();
2644 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2646 if (!movement_occurred) {
2648 /* just a click, do nothing but finish
2649 off the selection process
2652 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2655 case Selection::Set:
2656 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2657 _editor->selection->set (_marker);
2661 case Selection::Toggle:
2662 case Selection::Extend:
2663 case Selection::Add:
2670 _editor->_dragging_edit_point = false;
2672 _editor->begin_reversible_command ( _("move marker") );
2673 XMLNode &before = _editor->session()->locations()->get_state();
2675 MarkerSelection::iterator i;
2676 list<Location*>::iterator x;
2679 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2680 x != _copied_locations.end() && i != _editor->selection->markers.end();
2683 Location * location = _editor->find_location_from_marker (*i, is_start);
2687 if (location->locked()) {
2691 if (location->is_mark()) {
2692 location->set_start ((*x)->start());
2694 location->set ((*x)->start(), (*x)->end());
2699 XMLNode &after = _editor->session()->locations()->get_state();
2700 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2701 _editor->commit_reversible_command ();
2707 MarkerDrag::aborted ()
2713 MarkerDrag::update_item (Location* location)
2715 double const x1 = _editor->frame_to_pixel (location->start());
2717 _points.front().set_x(x1);
2718 _points.back().set_x(x1);
2719 _line->property_points() = _points;
2722 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2724 _cumulative_x_drag (0),
2725 _cumulative_y_drag (0)
2727 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2733 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2735 Drag::start_grab (event, _editor->fader_cursor);
2737 // start the grab at the center of the control point so
2738 // the point doesn't 'jump' to the mouse after the first drag
2739 _fixed_grab_x = _point->get_x();
2740 _fixed_grab_y = _point->get_y();
2742 float const fraction = 1 - (_point->get_y() / _point->line().height());
2744 _point->line().start_drag_single (_point, _fixed_grab_x, fraction);
2746 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2747 event->button.x + 10, event->button.y + 10);
2749 _editor->show_verbose_canvas_cursor ();
2753 ControlPointDrag::motion (GdkEvent* event, bool)
2755 double dx = _drags->current_pointer_x() - last_pointer_x();
2756 double dy = _drags->current_pointer_y() - last_pointer_y();
2758 if (event->button.state & Keyboard::SecondaryModifier) {
2763 /* coordinate in pixels relative to the start of the region (for region-based automation)
2764 or track (for track-based automation) */
2765 double cx = _fixed_grab_x + _cumulative_x_drag + dx;
2766 double cy = _fixed_grab_y + _cumulative_y_drag + dy;
2768 // calculate zero crossing point. back off by .01 to stay on the
2769 // positive side of zero
2770 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2772 // make sure we hit zero when passing through
2773 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2777 if (_x_constrained) {
2780 if (_y_constrained) {
2784 _cumulative_x_drag = cx - _fixed_grab_x;
2785 _cumulative_y_drag = cy - _fixed_grab_y;
2789 cy = min ((double) _point->line().height(), cy);
2791 framepos_t cx_frames = _editor->unit_to_frame (cx);
2793 if (!_x_constrained) {
2794 _editor->snap_to_with_modifier (cx_frames, event);
2797 cx_frames = min (cx_frames, _point->line().maximum_time());
2799 float const fraction = 1.0 - (cy / _point->line().height());
2801 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2803 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2805 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2809 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2811 if (!movement_occurred) {
2815 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2816 _editor->reset_point_selection ();
2820 motion (event, false);
2822 _point->line().end_drag ();
2826 ControlPointDrag::aborted ()
2828 _point->line().reset ();
2832 ControlPointDrag::active (Editing::MouseMode m)
2834 if (m == Editing::MouseGain) {
2835 /* always active in mouse gain */
2839 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2840 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2843 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2846 _cumulative_y_drag (0)
2851 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2853 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2856 _item = &_line->grab_item ();
2858 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2859 origin, and ditto for y.
2862 double cx = event->button.x;
2863 double cy = event->button.y;
2865 _line->parent_group().w2i (cx, cy);
2867 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2872 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2873 /* no adjacent points */
2877 Drag::start_grab (event, _editor->fader_cursor);
2879 /* store grab start in parent frame */
2884 double fraction = 1.0 - (cy / _line->height());
2886 _line->start_drag_line (before, after, fraction);
2888 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2889 event->button.x + 10, event->button.y + 10);
2891 _editor->show_verbose_canvas_cursor ();
2895 LineDrag::motion (GdkEvent* event, bool)
2897 double dy = _drags->current_pointer_y() - last_pointer_y();
2899 if (event->button.state & Keyboard::SecondaryModifier) {
2903 double cy = _fixed_grab_y + _cumulative_y_drag + dy;
2905 _cumulative_y_drag = cy - _fixed_grab_y;
2908 cy = min ((double) _line->height(), cy);
2910 double const fraction = 1.0 - (cy / _line->height());
2914 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2920 /* we are ignoring x position for this drag, so we can just pass in anything */
2921 _line->drag_motion (0, fraction, true, push);
2923 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2927 LineDrag::finished (GdkEvent* event, bool)
2929 motion (event, false);
2934 LineDrag::aborted ()
2939 FeatureLineDrag::FeatureLineDrag (Editor* e, ArdourCanvas::Item* i)
2942 _cumulative_x_drag (0)
2947 FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2950 Drag::start_grab (event);
2952 _line = reinterpret_cast<SimpleLine*> (_item);
2955 /* need to get x coordinate in terms of parent (AudioRegionView) origin. */
2957 double cx = event->button.x;
2958 double cy = event->button.y;
2960 _item->property_parent().get_value()->w2i(cx, cy);
2962 /* store grab start in parent frame */
2963 _region_view_grab_x = cx;
2965 _before = _line->property_x1();
2967 _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
2969 _max_x = _editor->frame_to_pixel(_arv->get_duration());
2973 FeatureLineDrag::motion (GdkEvent* event, bool)
2975 double dx = _drags->current_pointer_x() - last_pointer_x();
2977 double cx = _region_view_grab_x + _cumulative_x_drag + dx;
2979 _cumulative_x_drag += dx;
2981 /* Clamp the min and max extent of the drag to keep it within the region view bounds */
2990 _line->property_x1() = cx;
2991 _line->property_x2() = cx;
2993 _before = _line->property_x1();
2997 FeatureLineDrag::finished (GdkEvent* event, bool)
2999 _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
3000 _arv->update_transient(_before, _line->property_x1());
3004 FeatureLineDrag::aborted ()
3010 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3012 Drag::start_grab (event);
3013 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3017 RubberbandSelectDrag::motion (GdkEvent* event, bool)
3024 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
3026 nframes64_t grab = grab_frame ();
3027 if (Config->get_rubberbanding_snaps_to_grid ()) {
3028 _editor->snap_to_with_modifier (grab, event);
3031 /* base start and end on initial click position */
3041 if (_drags->current_pointer_y() < grab_y()) {
3042 y1 = _drags->current_pointer_y();
3045 y2 = _drags->current_pointer_y();
3050 if (start != end || y1 != y2) {
3052 double x1 = _editor->frame_to_pixel (start);
3053 double x2 = _editor->frame_to_pixel (end);
3055 _editor->rubberband_rect->property_x1() = x1;
3056 _editor->rubberband_rect->property_y1() = y1;
3057 _editor->rubberband_rect->property_x2() = x2;
3058 _editor->rubberband_rect->property_y2() = y2;
3060 _editor->rubberband_rect->show();
3061 _editor->rubberband_rect->raise_to_top();
3063 _editor->show_verbose_time_cursor (pf, 10);
3068 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
3070 if (movement_occurred) {
3072 motion (event, false);
3075 if (_drags->current_pointer_y() < grab_y()) {
3076 y1 = _drags->current_pointer_y();
3079 y2 = _drags->current_pointer_y();
3084 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
3087 _editor->begin_reversible_command (_("rubberband selection"));
3089 if (grab_frame() < last_pointer_frame()) {
3090 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op, false);
3092 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op, false);
3096 _editor->commit_reversible_command ();
3100 if (!getenv("ARDOUR_SAE")) {
3101 _editor->selection->clear_tracks();
3103 _editor->selection->clear_regions();
3104 _editor->selection->clear_points ();
3105 _editor->selection->clear_lines ();
3108 _editor->rubberband_rect->hide();
3112 RubberbandSelectDrag::aborted ()
3114 _editor->rubberband_rect->hide ();
3118 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3120 Drag::start_grab (event);
3122 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3126 TimeFXDrag::motion (GdkEvent* event, bool)
3128 RegionView* rv = _primary;
3130 nframes64_t const pf = adjusted_current_frame (event);
3132 if (pf > rv->region()->position()) {
3133 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3136 _editor->show_verbose_time_cursor (pf, 10);
3140 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3142 _primary->get_time_axis_view().hide_timestretch ();
3144 if (!movement_occurred) {
3148 if (last_pointer_frame() < _primary->region()->position()) {
3149 /* backwards drag of the left edge - not usable */
3153 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3155 float percentage = (double) newlen / (double) _primary->region()->length();
3157 #ifndef USE_RUBBERBAND
3158 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3159 if (_primary->region()->data_type() == DataType::AUDIO) {
3160 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3164 _editor->begin_reversible_command (_("timestretch"));
3166 // XXX how do timeFX on multiple regions ?
3171 if (_editor->time_stretch (rs, percentage) == -1) {
3172 error << _("An error occurred while executing time stretch operation") << endmsg;
3177 TimeFXDrag::aborted ()
3179 _primary->get_time_axis_view().hide_timestretch ();
3184 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3186 Drag::start_grab (event);
3190 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3192 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3196 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3198 if (movement_occurred && _editor->session()) {
3199 /* make sure we stop */
3200 _editor->session()->request_transport_speed (0.0);
3205 ScrubDrag::aborted ()
3210 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3214 , _original_pointer_time_axis (-1)
3215 , _last_pointer_time_axis (-1)
3221 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3223 nframes64_t start = 0;
3224 nframes64_t end = 0;
3226 if (_editor->session() == 0) {
3230 Gdk::Cursor* cursor = 0;
3232 switch (_operation) {
3233 case CreateSelection:
3234 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3239 cursor = _editor->selector_cursor;
3240 Drag::start_grab (event, cursor);
3243 case SelectionStartTrim:
3244 if (_editor->clicked_axisview) {
3245 _editor->clicked_axisview->order_selection_trims (_item, true);
3247 Drag::start_grab (event, _editor->left_side_trim_cursor);
3248 start = _editor->selection->time[_editor->clicked_selection].start;
3249 _pointer_frame_offset = grab_frame() - start;
3252 case SelectionEndTrim:
3253 if (_editor->clicked_axisview) {
3254 _editor->clicked_axisview->order_selection_trims (_item, false);
3256 Drag::start_grab (event, _editor->right_side_trim_cursor);
3257 end = _editor->selection->time[_editor->clicked_selection].end;
3258 _pointer_frame_offset = grab_frame() - end;
3262 start = _editor->selection->time[_editor->clicked_selection].start;
3263 Drag::start_grab (event, cursor);
3264 _pointer_frame_offset = grab_frame() - start;
3268 if (_operation == SelectionMove) {
3269 _editor->show_verbose_time_cursor (start, 10);
3271 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3274 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3278 SelectionDrag::motion (GdkEvent* event, bool first_move)
3280 nframes64_t start = 0;
3281 nframes64_t end = 0;
3284 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3285 if (pending_time_axis.first == 0) {
3289 nframes64_t const pending_position = adjusted_current_frame (event);
3291 /* only alter selection if things have changed */
3293 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3297 switch (_operation) {
3298 case CreateSelection:
3300 nframes64_t grab = grab_frame ();
3303 _editor->snap_to (grab);
3306 if (pending_position < grab_frame()) {
3307 start = pending_position;
3310 end = pending_position;
3314 /* first drag: Either add to the selection
3315 or create a new selection
3321 /* adding to the selection */
3322 _editor->selection->add (_editor->clicked_axisview);
3323 _editor->clicked_selection = _editor->selection->add (start, end);
3328 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
3329 _editor->selection->set (_editor->clicked_axisview);
3332 _editor->clicked_selection = _editor->selection->set (start, end);
3336 /* select the track that we're in */
3337 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3338 _editor->selection->add (pending_time_axis.first);
3339 _added_time_axes.push_back (pending_time_axis.first);
3342 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3343 tracks that we selected in the first place.
3346 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3347 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3349 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3350 while (i != _added_time_axes.end()) {
3352 list<TimeAxisView*>::iterator tmp = i;
3355 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3356 _editor->selection->remove (*i);
3357 _added_time_axes.remove (*i);
3366 case SelectionStartTrim:
3368 start = _editor->selection->time[_editor->clicked_selection].start;
3369 end = _editor->selection->time[_editor->clicked_selection].end;
3371 if (pending_position > end) {
3374 start = pending_position;
3378 case SelectionEndTrim:
3380 start = _editor->selection->time[_editor->clicked_selection].start;
3381 end = _editor->selection->time[_editor->clicked_selection].end;
3383 if (pending_position < start) {
3386 end = pending_position;
3393 start = _editor->selection->time[_editor->clicked_selection].start;
3394 end = _editor->selection->time[_editor->clicked_selection].end;
3396 length = end - start;
3398 start = pending_position;
3399 _editor->snap_to (start);
3401 end = start + length;
3406 if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
3407 _editor->start_canvas_autoscroll (1, 0);
3411 _editor->selection->replace (_editor->clicked_selection, start, end);
3414 if (_operation == SelectionMove) {
3415 _editor->show_verbose_time_cursor(start, 10);
3417 _editor->show_verbose_time_cursor(pending_position, 10);
3422 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3424 Session* s = _editor->session();
3426 if (movement_occurred) {
3427 motion (event, false);
3428 /* XXX this is not object-oriented programming at all. ick */
3429 if (_editor->selection->time.consolidate()) {
3430 _editor->selection->TimeChanged ();
3433 /* XXX what if its a music time selection? */
3434 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3435 s->request_play_range (&_editor->selection->time, true);
3440 /* just a click, no pointer movement.*/
3442 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3443 _editor->selection->clear_time();
3446 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
3447 _editor->selection->set (_editor->clicked_axisview);
3450 if (s && s->get_play_range () && s->transport_rolling()) {
3451 s->request_stop (false, false);
3456 _editor->stop_canvas_autoscroll ();
3460 SelectionDrag::aborted ()
3465 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3470 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3471 _drag_rect->hide ();
3473 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3474 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3478 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3480 if (_editor->session() == 0) {
3484 Gdk::Cursor* cursor = 0;
3486 if (!_editor->temp_location) {
3487 _editor->temp_location = new Location (*_editor->session());
3490 switch (_operation) {
3491 case CreateRangeMarker:
3492 case CreateTransportMarker:
3493 case CreateCDMarker:
3495 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3500 cursor = _editor->selector_cursor;
3504 Drag::start_grab (event, cursor);
3506 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3510 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3512 nframes64_t start = 0;
3513 nframes64_t end = 0;
3514 ArdourCanvas::SimpleRect *crect;
3516 switch (_operation) {
3517 case CreateRangeMarker:
3518 crect = _editor->range_bar_drag_rect;
3520 case CreateTransportMarker:
3521 crect = _editor->transport_bar_drag_rect;
3523 case CreateCDMarker:
3524 crect = _editor->cd_marker_bar_drag_rect;
3527 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3532 nframes64_t const pf = adjusted_current_frame (event);
3534 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3535 nframes64_t grab = grab_frame ();
3536 _editor->snap_to (grab);
3538 if (pf < grab_frame()) {
3546 /* first drag: Either add to the selection
3547 or create a new selection.
3552 _editor->temp_location->set (start, end);
3556 update_item (_editor->temp_location);
3558 //_drag_rect->raise_to_top();
3563 if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
3564 _editor->start_canvas_autoscroll (1, 0);
3568 _editor->temp_location->set (start, end);
3570 double x1 = _editor->frame_to_pixel (start);
3571 double x2 = _editor->frame_to_pixel (end);
3572 crect->property_x1() = x1;
3573 crect->property_x2() = x2;
3575 update_item (_editor->temp_location);
3578 _editor->show_verbose_time_cursor (pf, 10);
3583 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3585 Location * newloc = 0;
3589 if (movement_occurred) {
3590 motion (event, false);
3593 switch (_operation) {
3594 case CreateRangeMarker:
3595 case CreateCDMarker:
3597 _editor->begin_reversible_command (_("new range marker"));
3598 XMLNode &before = _editor->session()->locations()->get_state();
3599 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3600 if (_operation == CreateCDMarker) {
3601 flags = Location::IsRangeMarker | Location::IsCDMarker;
3602 _editor->cd_marker_bar_drag_rect->hide();
3605 flags = Location::IsRangeMarker;
3606 _editor->range_bar_drag_rect->hide();
3608 newloc = new Location (
3609 *_editor->session(), _editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags
3612 _editor->session()->locations()->add (newloc, true);
3613 XMLNode &after = _editor->session()->locations()->get_state();
3614 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3615 _editor->commit_reversible_command ();
3619 case CreateTransportMarker:
3620 // popup menu to pick loop or punch
3621 _editor->new_transport_marker_context_menu (&event->button, _item);
3625 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3627 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3632 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3634 if (end == max_frames) {
3635 end = _editor->session()->current_end_frame ();
3638 if (start == max_frames) {
3639 start = _editor->session()->current_start_frame ();
3642 switch (_editor->mouse_mode) {
3644 /* find the two markers on either side and then make the selection from it */
3645 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set, false);
3649 /* find the two markers on either side of the click and make the range out of it */
3650 _editor->selection->set (start, end);
3659 _editor->stop_canvas_autoscroll ();
3663 RangeMarkerBarDrag::aborted ()
3669 RangeMarkerBarDrag::update_item (Location* location)
3671 double const x1 = _editor->frame_to_pixel (location->start());
3672 double const x2 = _editor->frame_to_pixel (location->end());
3674 _drag_rect->property_x1() = x1;
3675 _drag_rect->property_x2() = x2;
3679 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3681 Drag::start_grab (event, _editor->zoom_cursor);
3682 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3686 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3691 nframes64_t const pf = adjusted_current_frame (event);
3693 nframes64_t grab = grab_frame ();
3694 _editor->snap_to_with_modifier (grab, event);
3696 /* base start and end on initial click position */
3708 _editor->zoom_rect->show();
3709 _editor->zoom_rect->raise_to_top();
3712 _editor->reposition_zoom_rect(start, end);
3714 _editor->show_verbose_time_cursor (pf, 10);
3719 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3721 if (movement_occurred) {
3722 motion (event, false);
3724 if (grab_frame() < last_pointer_frame()) {
3725 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3727 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3730 _editor->temporal_zoom_to_frame (false, grab_frame());
3732 temporal_zoom_step (false);
3733 center_screen (grab_frame());
3737 _editor->zoom_rect->hide();
3741 MouseZoomDrag::aborted ()
3743 _editor->zoom_rect->hide ();
3746 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3748 , _cumulative_dx (0)
3749 , _cumulative_dy (0)
3751 _primary = dynamic_cast<CanvasNoteEvent*> (_item);
3752 _region = &_primary->region_view ();
3753 _note_height = _region->midi_stream_view()->note_height ();
3757 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3759 Drag::start_grab (event);
3761 if (!(_was_selected = _primary->selected())) {
3763 /* tertiary-click means extend selection - we'll do that on button release,
3764 so don't add it here, because otherwise we make it hard to figure
3765 out the "extend-to" range.
3768 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3771 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3774 _region->note_selected (_primary, true);
3776 _region->unique_select (_primary);
3782 /** @return Current total drag x change in frames */
3784 NoteDrag::total_dx () const
3787 frameoffset_t const dx = _editor->unit_to_frame (_drags->current_pointer_x() - grab_x());
3789 /* primary note time */
3790 frameoffset_t const n = _region->beats_to_frames (_primary->note()->time ());
3792 /* new time of the primary note relative to the region position */
3793 frameoffset_t const st = n + dx;
3795 /* snap and return corresponding delta */
3796 return _region->snap_frame_to_frame (st) - n;
3799 /** @return Current total drag y change in notes */
3801 NoteDrag::total_dy () const
3803 /* this is `backwards' to make increasing note number go in the right direction */
3804 double const dy = _drags->current_pointer_y() - grab_y();
3809 if (abs (dy) >= _note_height) {
3811 ndy = (int8_t) ceil (dy / _note_height / 2.0);
3813 ndy = (int8_t) floor (dy / _note_height / 2.0);
3822 NoteDrag::motion (GdkEvent *, bool)
3824 /* Total change in x and y since the start of the drag */
3825 frameoffset_t const dx = total_dx ();
3826 int8_t const dy = total_dy ();
3828 /* Now work out what we have to do to the note canvas items to set this new drag delta */
3829 double const tdx = _editor->frame_to_unit (dx) - _cumulative_dx;
3830 double const tdy = dy * _note_height - _cumulative_dy;
3833 _region->move_selection (tdx, tdy);
3834 _cumulative_dx += tdx;
3835 _cumulative_dy += tdy;
3838 snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (_primary->note()->note() + dy).c_str(),
3839 (int) floor (_primary->note()->note() + dy));
3841 _editor->show_verbose_canvas_cursor_with (buf);
3846 NoteDrag::finished (GdkEvent* ev, bool moved)
3849 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3851 if (_was_selected) {
3852 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3854 _region->note_deselected (_primary);
3857 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3858 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3860 if (!extend && !add && _region->selection_size() > 1) {
3861 _region->unique_select (_primary);
3862 } else if (extend) {
3863 _region->note_selected (_primary, true, true);
3865 /* it was added during button press */
3870 _region->note_dropped (_primary, total_dx(), - total_dy());
3875 NoteDrag::aborted ()
3880 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3883 , _nothing_to_drag (false)
3885 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3888 _line = _atav->line ();
3892 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3894 Drag::start_grab (event, cursor);
3896 list<ControlPoint*> points;
3898 XMLNode* state = &_line->get_state ();
3900 if (_ranges.empty()) {
3902 uint32_t const N = _line->npoints ();
3903 for (uint32_t i = 0; i < N; ++i) {
3904 points.push_back (_line->nth (i));
3909 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3910 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3912 /* fade into and out of the region that we're dragging;
3913 64 samples length plucked out of thin air.
3915 nframes64_t const h = (j->start + j->end) / 2;
3916 nframes64_t a = j->start + 64;
3920 nframes64_t b = j->end - 64;
3925 the_list->add (j->start, the_list->eval (j->start));
3926 _line->add_always_in_view (j->start);
3927 the_list->add (a, the_list->eval (a));
3928 _line->add_always_in_view (a);
3929 the_list->add (b, the_list->eval (b));
3930 _line->add_always_in_view (b);
3931 the_list->add (j->end, the_list->eval (j->end));
3932 _line->add_always_in_view (j->end);
3935 uint32_t const N = _line->npoints ();
3936 for (uint32_t i = 0; i < N; ++i) {
3938 ControlPoint* p = _line->nth (i);
3940 list<AudioRange>::const_iterator j = _ranges.begin ();
3941 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3945 if (j != _ranges.end()) {
3946 points.push_back (p);
3951 if (points.empty()) {
3952 _nothing_to_drag = true;
3956 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3960 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3962 if (_nothing_to_drag) {
3966 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3968 /* we are ignoring x position for this drag, so we can just pass in anything */
3969 _line->drag_motion (0, f, true, false);
3973 AutomationRangeDrag::finished (GdkEvent* event, bool)
3975 if (_nothing_to_drag) {
3979 motion (event, false);
3981 _line->clear_always_in_view ();
3985 AutomationRangeDrag::aborted ()
3987 _line->clear_always_in_view ();
3991 DraggingView::DraggingView (RegionView* v)
3994 initial_y = v->get_canvas_group()->property_y ();