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 _time_axis_view_grab_x = _point->get_x();
2740 _time_axis_view_grab_y = _point->get_y();
2742 float const fraction = 1 - (_point->get_y() / _point->line().height());
2744 _point->line().start_drag_single (_point, _time_axis_view_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 TimeAxisView's space */
2764 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2765 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2767 // calculate zero crossing point. back off by .01 to stay on the
2768 // positive side of zero
2769 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2771 // make sure we hit zero when passing through
2772 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2776 if (_x_constrained) {
2777 cx = _time_axis_view_grab_x;
2779 if (_y_constrained) {
2780 cy = _time_axis_view_grab_y;
2783 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2784 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2788 cy = min ((double) _point->line().height(), cy);
2790 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2792 if (!_x_constrained) {
2793 _editor->snap_to_with_modifier (cx_frames, event);
2796 float const fraction = 1.0 - (cy / _point->line().height());
2798 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2800 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2802 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2806 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2808 if (!movement_occurred) {
2812 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2813 _editor->reset_point_selection ();
2817 motion (event, false);
2819 _point->line().end_drag ();
2823 ControlPointDrag::aborted ()
2825 _point->line().reset ();
2829 ControlPointDrag::active (Editing::MouseMode m)
2831 if (m == Editing::MouseGain) {
2832 /* always active in mouse gain */
2836 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2837 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2840 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2843 _cumulative_y_drag (0)
2848 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2850 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2853 _item = &_line->grab_item ();
2855 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2856 origin, and ditto for y.
2859 double cx = event->button.x;
2860 double cy = event->button.y;
2862 _line->parent_group().w2i (cx, cy);
2864 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2869 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2870 /* no adjacent points */
2874 Drag::start_grab (event, _editor->fader_cursor);
2876 /* store grab start in parent frame */
2878 _time_axis_view_grab_x = cx;
2879 _time_axis_view_grab_y = cy;
2881 double fraction = 1.0 - (cy / _line->height());
2883 _line->start_drag_line (before, after, fraction);
2885 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2886 event->button.x + 10, event->button.y + 10);
2888 _editor->show_verbose_canvas_cursor ();
2892 LineDrag::motion (GdkEvent* event, bool)
2894 double dy = _drags->current_pointer_y() - last_pointer_y();
2896 if (event->button.state & Keyboard::SecondaryModifier) {
2900 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2902 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2905 cy = min ((double) _line->height(), cy);
2907 double const fraction = 1.0 - (cy / _line->height());
2911 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2917 /* we are ignoring x position for this drag, so we can just pass in anything */
2918 _line->drag_motion (0, fraction, true, push);
2920 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2924 LineDrag::finished (GdkEvent* event, bool)
2926 motion (event, false);
2931 LineDrag::aborted ()
2936 FeatureLineDrag::FeatureLineDrag (Editor* e, ArdourCanvas::Item* i)
2939 _cumulative_x_drag (0)
2944 FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2947 Drag::start_grab (event);
2949 _line = reinterpret_cast<SimpleLine*> (_item);
2952 /* need to get x coordinate in terms of parent (AudioRegionView) origin. */
2954 double cx = event->button.x;
2955 double cy = event->button.y;
2957 _item->property_parent().get_value()->w2i(cx, cy);
2959 /* store grab start in parent frame */
2960 _region_view_grab_x = cx;
2962 _before = _line->property_x1();
2964 _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
2966 _max_x = _editor->frame_to_pixel(_arv->get_duration());
2970 FeatureLineDrag::motion (GdkEvent* event, bool)
2972 double dx = _drags->current_pointer_x() - last_pointer_x();
2974 double cx = _region_view_grab_x + _cumulative_x_drag + dx;
2976 _cumulative_x_drag += dx;
2978 /* Clamp the min and max extent of the drag to keep it within the region view bounds */
2987 _line->property_x1() = cx;
2988 _line->property_x2() = cx;
2990 _before = _line->property_x1();
2994 FeatureLineDrag::finished (GdkEvent* event, bool)
2996 _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
2997 _arv->update_transient(_before, _line->property_x1());
3001 FeatureLineDrag::aborted ()
3007 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3009 Drag::start_grab (event);
3010 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3014 RubberbandSelectDrag::motion (GdkEvent* event, bool)
3021 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
3023 nframes64_t grab = grab_frame ();
3024 if (Config->get_rubberbanding_snaps_to_grid ()) {
3025 _editor->snap_to_with_modifier (grab, event);
3028 /* base start and end on initial click position */
3038 if (_drags->current_pointer_y() < grab_y()) {
3039 y1 = _drags->current_pointer_y();
3042 y2 = _drags->current_pointer_y();
3047 if (start != end || y1 != y2) {
3049 double x1 = _editor->frame_to_pixel (start);
3050 double x2 = _editor->frame_to_pixel (end);
3052 _editor->rubberband_rect->property_x1() = x1;
3053 _editor->rubberband_rect->property_y1() = y1;
3054 _editor->rubberband_rect->property_x2() = x2;
3055 _editor->rubberband_rect->property_y2() = y2;
3057 _editor->rubberband_rect->show();
3058 _editor->rubberband_rect->raise_to_top();
3060 _editor->show_verbose_time_cursor (pf, 10);
3065 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
3067 if (movement_occurred) {
3069 motion (event, false);
3072 if (_drags->current_pointer_y() < grab_y()) {
3073 y1 = _drags->current_pointer_y();
3076 y2 = _drags->current_pointer_y();
3081 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
3084 _editor->begin_reversible_command (_("rubberband selection"));
3086 if (grab_frame() < last_pointer_frame()) {
3087 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op, false);
3089 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op, false);
3093 _editor->commit_reversible_command ();
3097 if (!getenv("ARDOUR_SAE")) {
3098 _editor->selection->clear_tracks();
3100 _editor->selection->clear_regions();
3101 _editor->selection->clear_points ();
3102 _editor->selection->clear_lines ();
3105 _editor->rubberband_rect->hide();
3109 RubberbandSelectDrag::aborted ()
3111 _editor->rubberband_rect->hide ();
3115 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3117 Drag::start_grab (event);
3119 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3123 TimeFXDrag::motion (GdkEvent* event, bool)
3125 RegionView* rv = _primary;
3127 nframes64_t const pf = adjusted_current_frame (event);
3129 if (pf > rv->region()->position()) {
3130 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3133 _editor->show_verbose_time_cursor (pf, 10);
3137 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3139 _primary->get_time_axis_view().hide_timestretch ();
3141 if (!movement_occurred) {
3145 if (last_pointer_frame() < _primary->region()->position()) {
3146 /* backwards drag of the left edge - not usable */
3150 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3152 float percentage = (double) newlen / (double) _primary->region()->length();
3154 #ifndef USE_RUBBERBAND
3155 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3156 if (_primary->region()->data_type() == DataType::AUDIO) {
3157 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3161 _editor->begin_reversible_command (_("timestretch"));
3163 // XXX how do timeFX on multiple regions ?
3168 if (_editor->time_stretch (rs, percentage) == -1) {
3169 error << _("An error occurred while executing time stretch operation") << endmsg;
3174 TimeFXDrag::aborted ()
3176 _primary->get_time_axis_view().hide_timestretch ();
3181 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3183 Drag::start_grab (event);
3187 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3189 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3193 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3195 if (movement_occurred && _editor->session()) {
3196 /* make sure we stop */
3197 _editor->session()->request_transport_speed (0.0);
3202 ScrubDrag::aborted ()
3207 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3211 , _original_pointer_time_axis (-1)
3212 , _last_pointer_time_axis (-1)
3218 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3220 nframes64_t start = 0;
3221 nframes64_t end = 0;
3223 if (_editor->session() == 0) {
3227 Gdk::Cursor* cursor = 0;
3229 switch (_operation) {
3230 case CreateSelection:
3231 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3236 cursor = _editor->selector_cursor;
3237 Drag::start_grab (event, cursor);
3240 case SelectionStartTrim:
3241 if (_editor->clicked_axisview) {
3242 _editor->clicked_axisview->order_selection_trims (_item, true);
3244 Drag::start_grab (event, _editor->left_side_trim_cursor);
3245 start = _editor->selection->time[_editor->clicked_selection].start;
3246 _pointer_frame_offset = grab_frame() - start;
3249 case SelectionEndTrim:
3250 if (_editor->clicked_axisview) {
3251 _editor->clicked_axisview->order_selection_trims (_item, false);
3253 Drag::start_grab (event, _editor->right_side_trim_cursor);
3254 end = _editor->selection->time[_editor->clicked_selection].end;
3255 _pointer_frame_offset = grab_frame() - end;
3259 start = _editor->selection->time[_editor->clicked_selection].start;
3260 Drag::start_grab (event, cursor);
3261 _pointer_frame_offset = grab_frame() - start;
3265 if (_operation == SelectionMove) {
3266 _editor->show_verbose_time_cursor (start, 10);
3268 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3271 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3275 SelectionDrag::motion (GdkEvent* event, bool first_move)
3277 nframes64_t start = 0;
3278 nframes64_t end = 0;
3281 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3282 if (pending_time_axis.first == 0) {
3286 nframes64_t const pending_position = adjusted_current_frame (event);
3288 /* only alter selection if things have changed */
3290 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3294 switch (_operation) {
3295 case CreateSelection:
3297 nframes64_t grab = grab_frame ();
3300 _editor->snap_to (grab);
3303 if (pending_position < grab_frame()) {
3304 start = pending_position;
3307 end = pending_position;
3311 /* first drag: Either add to the selection
3312 or create a new selection
3318 /* adding to the selection */
3319 _editor->selection->add (_editor->clicked_axisview);
3320 _editor->clicked_selection = _editor->selection->add (start, end);
3325 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
3326 _editor->selection->set (_editor->clicked_axisview);
3329 _editor->clicked_selection = _editor->selection->set (start, end);
3333 /* select the track that we're in */
3334 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3335 _editor->selection->add (pending_time_axis.first);
3336 _added_time_axes.push_back (pending_time_axis.first);
3339 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3340 tracks that we selected in the first place.
3343 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3344 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3346 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3347 while (i != _added_time_axes.end()) {
3349 list<TimeAxisView*>::iterator tmp = i;
3352 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3353 _editor->selection->remove (*i);
3354 _added_time_axes.remove (*i);
3363 case SelectionStartTrim:
3365 start = _editor->selection->time[_editor->clicked_selection].start;
3366 end = _editor->selection->time[_editor->clicked_selection].end;
3368 if (pending_position > end) {
3371 start = pending_position;
3375 case SelectionEndTrim:
3377 start = _editor->selection->time[_editor->clicked_selection].start;
3378 end = _editor->selection->time[_editor->clicked_selection].end;
3380 if (pending_position < start) {
3383 end = pending_position;
3390 start = _editor->selection->time[_editor->clicked_selection].start;
3391 end = _editor->selection->time[_editor->clicked_selection].end;
3393 length = end - start;
3395 start = pending_position;
3396 _editor->snap_to (start);
3398 end = start + length;
3403 if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
3404 _editor->start_canvas_autoscroll (1, 0);
3408 _editor->selection->replace (_editor->clicked_selection, start, end);
3411 if (_operation == SelectionMove) {
3412 _editor->show_verbose_time_cursor(start, 10);
3414 _editor->show_verbose_time_cursor(pending_position, 10);
3419 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3421 Session* s = _editor->session();
3423 if (movement_occurred) {
3424 motion (event, false);
3425 /* XXX this is not object-oriented programming at all. ick */
3426 if (_editor->selection->time.consolidate()) {
3427 _editor->selection->TimeChanged ();
3430 /* XXX what if its a music time selection? */
3431 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3432 s->request_play_range (&_editor->selection->time, true);
3437 /* just a click, no pointer movement.*/
3439 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3440 _editor->selection->clear_time();
3443 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
3444 _editor->selection->set (_editor->clicked_axisview);
3447 if (s && s->get_play_range () && s->transport_rolling()) {
3448 s->request_stop (false, false);
3453 _editor->stop_canvas_autoscroll ();
3457 SelectionDrag::aborted ()
3462 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3467 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3468 _drag_rect->hide ();
3470 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3471 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3475 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3477 if (_editor->session() == 0) {
3481 Gdk::Cursor* cursor = 0;
3483 if (!_editor->temp_location) {
3484 _editor->temp_location = new Location (*_editor->session());
3487 switch (_operation) {
3488 case CreateRangeMarker:
3489 case CreateTransportMarker:
3490 case CreateCDMarker:
3492 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3497 cursor = _editor->selector_cursor;
3501 Drag::start_grab (event, cursor);
3503 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3507 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3509 nframes64_t start = 0;
3510 nframes64_t end = 0;
3511 ArdourCanvas::SimpleRect *crect;
3513 switch (_operation) {
3514 case CreateRangeMarker:
3515 crect = _editor->range_bar_drag_rect;
3517 case CreateTransportMarker:
3518 crect = _editor->transport_bar_drag_rect;
3520 case CreateCDMarker:
3521 crect = _editor->cd_marker_bar_drag_rect;
3524 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3529 nframes64_t const pf = adjusted_current_frame (event);
3531 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3532 nframes64_t grab = grab_frame ();
3533 _editor->snap_to (grab);
3535 if (pf < grab_frame()) {
3543 /* first drag: Either add to the selection
3544 or create a new selection.
3549 _editor->temp_location->set (start, end);
3553 update_item (_editor->temp_location);
3555 //_drag_rect->raise_to_top();
3560 if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
3561 _editor->start_canvas_autoscroll (1, 0);
3565 _editor->temp_location->set (start, end);
3567 double x1 = _editor->frame_to_pixel (start);
3568 double x2 = _editor->frame_to_pixel (end);
3569 crect->property_x1() = x1;
3570 crect->property_x2() = x2;
3572 update_item (_editor->temp_location);
3575 _editor->show_verbose_time_cursor (pf, 10);
3580 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3582 Location * newloc = 0;
3586 if (movement_occurred) {
3587 motion (event, false);
3590 switch (_operation) {
3591 case CreateRangeMarker:
3592 case CreateCDMarker:
3594 _editor->begin_reversible_command (_("new range marker"));
3595 XMLNode &before = _editor->session()->locations()->get_state();
3596 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3597 if (_operation == CreateCDMarker) {
3598 flags = Location::IsRangeMarker | Location::IsCDMarker;
3599 _editor->cd_marker_bar_drag_rect->hide();
3602 flags = Location::IsRangeMarker;
3603 _editor->range_bar_drag_rect->hide();
3605 newloc = new Location (
3606 *_editor->session(), _editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags
3609 _editor->session()->locations()->add (newloc, true);
3610 XMLNode &after = _editor->session()->locations()->get_state();
3611 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3612 _editor->commit_reversible_command ();
3616 case CreateTransportMarker:
3617 // popup menu to pick loop or punch
3618 _editor->new_transport_marker_context_menu (&event->button, _item);
3622 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3624 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3629 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3631 if (end == max_frames) {
3632 end = _editor->session()->current_end_frame ();
3635 if (start == max_frames) {
3636 start = _editor->session()->current_start_frame ();
3639 switch (_editor->mouse_mode) {
3641 /* find the two markers on either side and then make the selection from it */
3642 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set, false);
3646 /* find the two markers on either side of the click and make the range out of it */
3647 _editor->selection->set (start, end);
3656 _editor->stop_canvas_autoscroll ();
3660 RangeMarkerBarDrag::aborted ()
3666 RangeMarkerBarDrag::update_item (Location* location)
3668 double const x1 = _editor->frame_to_pixel (location->start());
3669 double const x2 = _editor->frame_to_pixel (location->end());
3671 _drag_rect->property_x1() = x1;
3672 _drag_rect->property_x2() = x2;
3676 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3678 Drag::start_grab (event, _editor->zoom_cursor);
3679 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3683 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3688 nframes64_t const pf = adjusted_current_frame (event);
3690 nframes64_t grab = grab_frame ();
3691 _editor->snap_to_with_modifier (grab, event);
3693 /* base start and end on initial click position */
3705 _editor->zoom_rect->show();
3706 _editor->zoom_rect->raise_to_top();
3709 _editor->reposition_zoom_rect(start, end);
3711 _editor->show_verbose_time_cursor (pf, 10);
3716 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3718 if (movement_occurred) {
3719 motion (event, false);
3721 if (grab_frame() < last_pointer_frame()) {
3722 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3724 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3727 _editor->temporal_zoom_to_frame (false, grab_frame());
3729 temporal_zoom_step (false);
3730 center_screen (grab_frame());
3734 _editor->zoom_rect->hide();
3738 MouseZoomDrag::aborted ()
3740 _editor->zoom_rect->hide ();
3743 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3745 , _cumulative_dx (0)
3746 , _cumulative_dy (0)
3748 _primary = dynamic_cast<CanvasNoteEvent*> (_item);
3749 _region = &_primary->region_view ();
3750 _note_height = _region->midi_stream_view()->note_height ();
3754 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3756 Drag::start_grab (event);
3758 if (!(_was_selected = _primary->selected())) {
3760 /* tertiary-click means extend selection - we'll do that on button release,
3761 so don't add it here, because otherwise we make it hard to figure
3762 out the "extend-to" range.
3765 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3768 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3771 _region->note_selected (_primary, true);
3773 _region->unique_select (_primary);
3779 /** @return Current total drag x change in frames */
3781 NoteDrag::total_dx () const
3784 frameoffset_t const dx = _editor->unit_to_frame (_drags->current_pointer_x() - grab_x());
3786 /* primary note time */
3787 frameoffset_t const n = _region->beats_to_frames (_primary->note()->time ());
3789 /* new time of the primary note relative to the region position */
3790 frameoffset_t const st = n + dx;
3792 /* snap and return corresponding delta */
3793 return _region->snap_frame_to_frame (st) - n;
3796 /** @return Current total drag y change in notes */
3798 NoteDrag::total_dy () const
3800 /* this is `backwards' to make increasing note number go in the right direction */
3801 double const dy = _drags->current_pointer_y() - grab_y();
3806 if (abs (dy) >= _note_height) {
3808 ndy = (int8_t) ceil (dy / _note_height / 2.0);
3810 ndy = (int8_t) floor (dy / _note_height / 2.0);
3819 NoteDrag::motion (GdkEvent *, bool)
3821 /* Total change in x and y since the start of the drag */
3822 frameoffset_t const dx = total_dx ();
3823 int8_t const dy = total_dy ();
3825 /* Now work out what we have to do to the note canvas items to set this new drag delta */
3826 double const tdx = _editor->frame_to_unit (dx) - _cumulative_dx;
3827 double const tdy = dy * _note_height - _cumulative_dy;
3830 _region->move_selection (tdx, tdy);
3831 _cumulative_dx += tdx;
3832 _cumulative_dy += tdy;
3835 snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (_primary->note()->note() + dy).c_str(),
3836 (int) floor (_primary->note()->note() + dy));
3838 _editor->show_verbose_canvas_cursor_with (buf);
3843 NoteDrag::finished (GdkEvent* ev, bool moved)
3846 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3848 if (_was_selected) {
3849 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3851 _region->note_deselected (_primary);
3854 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3855 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3857 if (!extend && !add && _region->selection_size() > 1) {
3858 _region->unique_select (_primary);
3859 } else if (extend) {
3860 _region->note_selected (_primary, true, true);
3862 /* it was added during button press */
3867 _region->note_dropped (_primary, total_dx(), - total_dy());
3872 NoteDrag::aborted ()
3877 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3880 , _nothing_to_drag (false)
3882 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3885 _line = _atav->line ();
3889 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3891 Drag::start_grab (event, cursor);
3893 list<ControlPoint*> points;
3895 XMLNode* state = &_line->get_state ();
3897 if (_ranges.empty()) {
3899 uint32_t const N = _line->npoints ();
3900 for (uint32_t i = 0; i < N; ++i) {
3901 points.push_back (_line->nth (i));
3906 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3907 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3909 /* fade into and out of the region that we're dragging;
3910 64 samples length plucked out of thin air.
3912 nframes64_t const h = (j->start + j->end) / 2;
3913 nframes64_t a = j->start + 64;
3917 nframes64_t b = j->end - 64;
3922 the_list->add (j->start, the_list->eval (j->start));
3923 _line->add_always_in_view (j->start);
3924 the_list->add (a, the_list->eval (a));
3925 _line->add_always_in_view (a);
3926 the_list->add (b, the_list->eval (b));
3927 _line->add_always_in_view (b);
3928 the_list->add (j->end, the_list->eval (j->end));
3929 _line->add_always_in_view (j->end);
3932 uint32_t const N = _line->npoints ();
3933 for (uint32_t i = 0; i < N; ++i) {
3935 ControlPoint* p = _line->nth (i);
3937 list<AudioRange>::const_iterator j = _ranges.begin ();
3938 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3942 if (j != _ranges.end()) {
3943 points.push_back (p);
3948 if (points.empty()) {
3949 _nothing_to_drag = true;
3953 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3957 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3959 if (_nothing_to_drag) {
3963 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3965 /* we are ignoring x position for this drag, so we can just pass in anything */
3966 _line->drag_motion (0, f, true, false);
3970 AutomationRangeDrag::finished (GdkEvent* event, bool)
3972 if (_nothing_to_drag) {
3976 motion (event, false);
3978 _line->clear_always_in_view ();
3982 AutomationRangeDrag::aborted ()
3984 _line->clear_always_in_view ();
3988 DraggingView::DraggingView (RegionView* v)
3991 initial_y = v->get_canvas_group()->property_y ();