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 "ardour/diskstream.h"
25 #include "ardour/session.h"
26 #include "ardour/dB.h"
27 #include "ardour/region_factory.h"
28 #include "ardour/midi_diskstream.h"
32 #include "audio_region_view.h"
33 #include "midi_region_view.h"
34 #include "ardour_ui.h"
35 #include "gui_thread.h"
36 #include "control_point.h"
38 #include "region_gain_line.h"
39 #include "editor_drag.h"
40 #include "audio_time_axis.h"
41 #include "midi_time_axis.h"
42 #include "canvas-note.h"
43 #include "selection.h"
44 #include "midi_selection.h"
45 #include "automation_time_axis.h"
48 using namespace ARDOUR;
51 using namespace Editing;
52 using namespace ArdourCanvas;
54 using Gtkmm2ext::Keyboard;
56 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
58 DragManager::DragManager (Editor* e)
61 , _current_pointer_frame (0)
66 DragManager::~DragManager ()
74 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
83 DragManager::break_drag ()
87 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
98 DragManager::add (Drag* d)
100 d->set_manager (this);
101 _drags.push_back (d);
105 DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
107 assert (_drags.empty ());
108 d->set_manager (this);
109 _drags.push_back (d);
114 DragManager::start_grab (GdkEvent* e)
116 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
118 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
119 (*i)->start_grab (e);
124 DragManager::end_grab (GdkEvent* e)
129 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
130 bool const t = (*i)->end_grab (e);
145 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
149 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
151 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
152 bool const t = (*i)->motion_handler (e, from_autoscroll);
163 DragManager::have_item (ArdourCanvas::Item* i) const
165 list<Drag*>::const_iterator j = _drags.begin ();
166 while (j != _drags.end() && (*j)->item () != i) {
170 return j != _drags.end ();
173 pair<nframes64_t, nframes64_t>
174 DragManager::extent () const
176 if (_drags.empty()) {
177 return make_pair (0, 0);
180 list<Drag*>::const_iterator i = _drags.begin ();
181 pair<nframes64_t, nframes64_t> e = (*i)->extent ();
184 while (i != _drags.end()) {
185 pair<nframes64_t, nframes64_t> const t = (*i)->extent ();
186 e.first = min (e.first, t.first);
187 e.second = max (e.second, t.second);
194 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
197 , _pointer_frame_offset (0)
198 , _move_threshold_passed (false)
200 , _last_pointer_frame (0)
206 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
212 cursor = _editor->which_grabber_cursor ();
215 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
219 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
222 cursor = _editor->which_grabber_cursor ();
225 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
227 if (Keyboard::is_button2_event (&event->button)) {
228 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
229 _y_constrained = true;
230 _x_constrained = false;
232 _y_constrained = false;
233 _x_constrained = true;
236 _x_constrained = false;
237 _y_constrained = false;
240 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
241 _grab_frame = adjusted_frame (_grab_frame, event);
242 _last_pointer_frame = _grab_frame;
243 _last_pointer_x = _grab_x;
244 _last_pointer_y = _grab_y;
246 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
250 if (_editor->session() && _editor->session()->transport_rolling()) {
253 _was_rolling = false;
256 switch (_editor->snap_type()) {
257 case SnapToRegionStart:
258 case SnapToRegionEnd:
259 case SnapToRegionSync:
260 case SnapToRegionBoundary:
261 _editor->build_region_boundary_cache ();
268 /** @param event GDK event, or 0.
269 * @return true if some movement occurred, otherwise false.
272 Drag::end_grab (GdkEvent* event)
274 _editor->stop_canvas_autoscroll ();
276 _item->ungrab (event ? event->button.time : 0);
278 finished (event, _move_threshold_passed);
280 _editor->hide_verbose_canvas_cursor();
282 return _move_threshold_passed;
286 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
290 if (f > _pointer_frame_offset) {
291 pos = f - _pointer_frame_offset;
295 _editor->snap_to_with_modifier (pos, event);
302 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
304 return adjusted_frame (_drags->current_pointer_frame (), event, snap);
308 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
310 /* check to see if we have moved in any way that matters since the last motion event */
311 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
312 (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
316 pair<nframes64_t, int> const threshold = move_threshold ();
318 bool const old_move_threshold_passed = _move_threshold_passed;
320 if (!from_autoscroll && !_move_threshold_passed) {
322 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
323 bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
325 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
328 if (active (_editor->mouse_mode) && _move_threshold_passed) {
330 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
331 if (!from_autoscroll) {
332 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
335 motion (event, _move_threshold_passed != old_move_threshold_passed);
337 _last_pointer_x = _drags->current_pointer_x ();
338 _last_pointer_y = _drags->current_pointer_y ();
339 _last_pointer_frame = adjusted_current_frame (event);
357 _editor->stop_canvas_autoscroll ();
358 _editor->hide_verbose_canvas_cursor ();
361 pair<nframes64_t, nframes64_t>
362 Drag::extent () const
364 nframes64_t const f = adjusted_current_frame (0);
365 return make_pair (f, f);
368 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
373 RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
377 RegionDrag::region_going_away (RegionView* v)
379 if (!_drags->ending ()) {
384 pair<nframes64_t, nframes64_t>
385 RegionDrag::extent () const
387 nframes64_t const f = adjusted_current_frame (0);
388 return make_pair (f, f + _primary->region()->length ());
392 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
393 : RegionDrag (e, i, p, v),
404 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
406 Drag::start_grab (event);
408 _editor->show_verbose_time_cursor (_last_frame_position, 10);
411 RegionMotionDrag::TimeAxisViewSummary
412 RegionMotionDrag::get_time_axis_view_summary ()
414 int32_t children = 0;
415 TimeAxisViewSummary sum;
417 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
419 /* get a bitmask representing the visible tracks */
421 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
422 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
423 TimeAxisView::Children children_list;
425 /* zeroes are audio/MIDI tracks. ones are other types. */
427 if (!rtv->hidden()) {
429 if (!rtv->is_track()) {
430 /* not an audio nor MIDI track */
431 sum.tracks = sum.tracks |= (0x01 << rtv->order());
434 sum.height_list[rtv->order()] = (*i)->current_height();
437 if ((children_list = rtv->get_child_list()).size() > 0) {
438 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
439 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
440 sum.height_list[rtv->order() + children] = (*j)->current_height();
451 RegionMotionDrag::compute_y_delta (
452 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
453 int32_t last_pointer_layer, int32_t current_pointer_layer,
454 TimeAxisViewSummary const & tavs,
455 int32_t* pointer_order_span, int32_t* pointer_layer_span,
456 int32_t* canvas_pointer_order_span
460 *pointer_order_span = 0;
461 *pointer_layer_span = 0;
465 bool clamp_y_axis = false;
467 /* the change in track order between this callback and the last */
468 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
469 /* the change in layer between this callback and the last;
470 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
471 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
473 if (*pointer_order_span != 0) {
475 /* find the actual pointer span, in terms of the number of visible tracks;
476 to do this, we reduce |pointer_order_span| by the number of hidden tracks
479 *canvas_pointer_order_span = *pointer_order_span;
480 if (last_pointer_view->order() >= current_pointer_view->order()) {
481 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
482 if (tavs.height_list[y] == 0) {
483 *canvas_pointer_order_span--;
487 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
488 if (tavs.height_list[y] == 0) {
489 *canvas_pointer_order_span++;
494 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
496 RegionView* rv = (*i);
498 if (rv->region()->locked()) {
502 double ix1, ix2, iy1, iy2;
503 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
504 rv->get_canvas_frame()->i2w (ix1, iy1);
505 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
507 /* get the new trackview for this particular region */
508 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
510 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
512 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
513 as surely this is a per-region thing... */
515 clamp_y_axis = y_movement_disallowed (
516 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
524 } else if (_dest_trackview == current_pointer_view) {
526 if (current_pointer_layer == last_pointer_layer) {
527 /* No movement; clamp */
533 _dest_trackview = current_pointer_view;
534 _dest_layer = current_pointer_layer;
542 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
544 /* compute the amount of pointer motion in frames, and where
545 the region would be if we moved it by that much.
547 *pending_region_position = adjusted_current_frame (event);
549 nframes64_t sync_frame;
550 nframes64_t sync_offset;
553 sync_offset = _primary->region()->sync_offset (sync_dir);
555 /* we don't handle a sync point that lies before zero.
557 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
559 sync_frame = *pending_region_position + (sync_dir*sync_offset);
561 _editor->snap_to_with_modifier (sync_frame, event);
563 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
566 *pending_region_position = _last_frame_position;
569 if (*pending_region_position > max_frames - _primary->region()->length()) {
570 *pending_region_position = _last_frame_position;
575 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
577 /* now compute the canvas unit distance we need to move the regionview
578 to make it appear at the new location.
581 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
583 if (*pending_region_position <= _last_frame_position) {
585 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
587 RegionView* rv = (*i);
589 // If any regionview is at zero, we need to know so we can stop further leftward motion.
591 double ix1, ix2, iy1, iy2;
592 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
593 rv->get_canvas_frame()->i2w (ix1, iy1);
595 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
597 *pending_region_position = _last_frame_position;
604 _last_frame_position = *pending_region_position;
611 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
615 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
617 vector<int32_t>::iterator j;
619 /* *pointer* variables reflect things about the pointer; as we may be moving
620 multiple regions, much detail must be computed per-region */
622 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
623 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
624 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
625 is always 0 regardless of what the region's "real" layer is */
626 RouteTimeAxisView* current_pointer_view;
627 layer_t current_pointer_layer;
628 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
632 /* TimeAxisView that we were pointing at last time we entered this method */
633 TimeAxisView const * const last_pointer_view = _dest_trackview;
634 /* the order of the track that we were pointing at last time we entered this method */
635 int32_t const last_pointer_order = last_pointer_view->order ();
636 /* the layer that we were pointing at last time we entered this method */
637 layer_t const last_pointer_layer = _dest_layer;
639 int32_t pointer_order_span;
640 int32_t pointer_layer_span;
641 int32_t canvas_pointer_order_span;
643 bool const clamp_y_axis = compute_y_delta (
644 last_pointer_view, current_pointer_view,
645 last_pointer_layer, current_pointer_layer, tavs,
646 &pointer_order_span, &pointer_layer_span,
647 &canvas_pointer_order_span
650 nframes64_t pending_region_position;
651 double const x_delta = compute_x_delta (event, &pending_region_position);
653 /*************************************************************
655 ************************************************************/
657 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
658 /* haven't reached next snap point, and we're not switching
659 trackviews nor layers. nothing to do.
664 /*************************************************************
666 ************************************************************/
668 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
670 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
672 RegionView* rv = (*i);
674 if (rv->region()->locked()) {
678 /* here we are calculating the y distance from the
679 top of the first track view to the top of the region
680 area of the track view that we're working on */
682 /* this x value is just a dummy value so that we have something
687 /* distance from the top of this track view to the region area
688 of our track view is always 1 */
692 /* convert to world coordinates, ie distance from the top of
695 rv->get_canvas_frame()->i2w (ix1, iy1);
697 /* compensate for the ruler section and the vertical scrollbar position */
698 iy1 += _editor->get_trackview_group_vertical_offset ();
702 // hide any dependent views
704 rv->get_time_axis_view().hide_dependent_views (*rv);
707 reparent to a non scrolling group so that we can keep the
708 region selection above all time axis views.
709 reparenting means we have to move the rv as the two
710 parent groups have different coordinates.
713 rv->get_canvas_group()->property_y() = iy1 - 1;
714 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
716 rv->fake_set_opaque (true);
719 /* current view for this particular region */
720 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
721 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
723 if (pointer_order_span != 0 && !clamp_y_axis) {
725 /* INTER-TRACK MOVEMENT */
727 /* move through the height list to the track that the region is currently on */
728 vector<int32_t>::iterator j = tavs.height_list.begin ();
730 while (j != tavs.height_list.end () && x != rtv->order ()) {
736 int32_t temp_pointer_order_span = canvas_pointer_order_span;
738 if (j != tavs.height_list.end ()) {
740 /* Account for layers in the original and
741 destination tracks. If we're moving around in layers we assume
742 that only one track is involved, so it's ok to use *pointer*
745 StreamView* lv = last_pointer_view->view ();
748 /* move to the top of the last trackview */
749 if (lv->layer_display () == Stacked) {
750 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
753 StreamView* cv = current_pointer_view->view ();
756 /* move to the right layer on the current trackview */
757 if (cv->layer_display () == Stacked) {
758 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
761 /* And for being on a non-topmost layer on the new
764 while (temp_pointer_order_span > 0) {
765 /* we're moving up canvas-wise,
766 so we need to find the next track height
768 if (j != tavs.height_list.begin()) {
772 if (x != last_pointer_order) {
774 ++temp_pointer_order_span;
779 temp_pointer_order_span--;
782 while (temp_pointer_order_span < 0) {
786 if (x != last_pointer_order) {
788 --temp_pointer_order_span;
792 if (j != tavs.height_list.end()) {
796 temp_pointer_order_span++;
800 /* find out where we'll be when we move and set height accordingly */
802 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
803 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
804 rv->set_height (temp_rtv->view()->child_height());
806 /* if you un-comment the following, the region colours will follow
807 the track colours whilst dragging; personally
808 i think this can confuse things, but never mind.
811 //const GdkColor& col (temp_rtv->view->get_region_color());
812 //rv->set_color (const_cast<GdkColor&>(col));
816 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
818 /* INTER-LAYER MOVEMENT in the same track */
819 y_delta = rtv->view()->child_height () * pointer_layer_span;
824 _editor->mouse_brush_insert_region (rv, pending_region_position);
826 rv->move (x_delta, y_delta);
829 } /* foreach region */
831 _total_x_delta += x_delta;
834 _editor->cursor_group->raise_to_top();
837 if (x_delta != 0 && !_brushing) {
838 _editor->show_verbose_time_cursor (_last_frame_position, 10);
843 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
845 if (_copy && first_move) {
846 copy_regions (event);
849 RegionMotionDrag::motion (event, first_move);
853 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
855 vector<RegionView*> copies;
856 boost::shared_ptr<Diskstream> ds;
857 boost::shared_ptr<Playlist> from_playlist;
858 RegionSelection new_views;
859 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
860 PlaylistSet modified_playlists;
861 PlaylistSet frozen_playlists;
862 list <sigc::connection> modified_playlist_connections;
863 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
864 nframes64_t drag_delta;
865 bool changed_tracks, changed_position;
866 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
867 RouteTimeAxisView* source_tv;
869 if (!movement_occurred) {
875 /* all changes were made during motion event handlers */
878 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
879 copies.push_back (*i);
886 /* reverse this here so that we have the correct logic to finalize
890 if (Config->get_edit_mode() == Lock) {
891 _x_constrained = !_x_constrained;
895 if (_x_constrained) {
896 _editor->begin_reversible_command (_("fixed time region copy"));
898 _editor->begin_reversible_command (_("region copy"));
901 if (_x_constrained) {
902 _editor->begin_reversible_command (_("fixed time region drag"));
904 _editor->begin_reversible_command (_("region drag"));
908 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
909 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
911 drag_delta = _primary->region()->position() - _last_frame_position;
913 _editor->update_canvas_now ();
915 /* make a list of where each region ended up */
916 final = find_time_axis_views_and_layers ();
918 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
920 RegionView* rv = (*i);
921 RouteTimeAxisView* dest_rtv = final[*i].first;
922 layer_t dest_layer = final[*i].second;
926 if (rv->region()->locked()) {
931 if (changed_position && !_x_constrained) {
932 where = rv->region()->position() - drag_delta;
934 where = rv->region()->position();
937 boost::shared_ptr<Region> new_region;
940 /* we already made a copy */
941 new_region = rv->region();
943 /* undo the previous hide_dependent_views so that xfades don't
944 disappear on copying regions
947 //rv->get_time_axis_view().reveal_dependent_views (*rv);
949 } else if (changed_tracks && dest_rtv->playlist()) {
950 new_region = RegionFactory::create (rv->region());
953 if (changed_tracks || _copy) {
955 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
962 _editor->latest_regionviews.clear ();
964 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
966 insert_result = modified_playlists.insert (to_playlist);
968 if (insert_result.second) {
969 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
972 to_playlist->add_region (new_region, where);
973 if (dest_rtv->view()->layer_display() == Stacked) {
974 new_region->set_layer (dest_layer);
975 new_region->set_pending_explicit_relayer (true);
980 if (!_editor->latest_regionviews.empty()) {
981 // XXX why just the first one ? we only expect one
982 // commented out in nick_m's canvas reworking. is that intended?
983 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
984 new_views.push_back (_editor->latest_regionviews.front());
989 motion on the same track. plonk the previously reparented region
990 back to its original canvas group (its streamview).
991 No need to do anything for copies as they are fake regions which will be deleted.
994 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
995 rv->get_canvas_group()->property_y() = 0;
996 rv->get_time_axis_view().reveal_dependent_views (*rv);
998 /* just change the model */
1000 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1002 if (dest_rtv->view()->layer_display() == Stacked) {
1003 rv->region()->set_layer (dest_layer);
1004 rv->region()->set_pending_explicit_relayer (true);
1007 insert_result = modified_playlists.insert (playlist);
1009 if (insert_result.second) {
1010 _editor->session()->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
1012 /* freeze to avoid lots of relayering in the case of a multi-region drag */
1013 frozen_insert_result = frozen_playlists.insert(playlist);
1015 if (frozen_insert_result.second) {
1019 rv->region()->set_position (where, (void*) this);
1022 if (changed_tracks && !_copy) {
1024 /* get the playlist where this drag started. we can't use rv->region()->playlist()
1025 because we may have copied the region and it has not been attached to a playlist.
1028 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
1029 ds = source_tv->get_diskstream();
1030 from_playlist = ds->playlist();
1034 assert (from_playlist);
1036 /* moved to a different audio track, without copying */
1038 /* the region that used to be in the old playlist is not
1039 moved to the new one - we use a copy of it. as a result,
1040 any existing editor for the region should no longer be
1044 rv->hide_region_editor();
1045 rv->fake_set_opaque (false);
1047 /* remove the region from the old playlist */
1049 insert_result = modified_playlists.insert (from_playlist);
1051 if (insert_result.second) {
1052 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
1055 from_playlist->remove_region (rv->region());
1057 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1058 was selected in all of them, then removing it from a playlist will have removed all
1059 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1060 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1061 corresponding regionview, and the selection is now empty).
1063 this could have invalidated any and all iterators into the region selection.
1065 the heuristic we use here is: if the region selection is empty, break out of the loop
1066 here. if the region selection is not empty, then restart the loop because we know that
1067 we must have removed at least the region(view) we've just been working on as well as any
1068 that we processed on previous iterations.
1070 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1071 we can just iterate.
1074 if (_views.empty()) {
1085 copies.push_back (rv);
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
1092 if (new_views.size() > 0) {
1093 _editor->selection->set (new_views);
1096 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1101 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
1102 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
1105 _editor->commit_reversible_command ();
1107 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1113 RegionMoveDrag::aborted ()
1117 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1124 RegionMotionDrag::aborted ();
1129 RegionMotionDrag::aborted ()
1131 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1132 TimeAxisView* tv = &(*i)->get_time_axis_view ();
1133 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1135 (*i)->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1136 (*i)->get_canvas_group()->property_y() = 0;
1137 (*i)->get_time_axis_view().reveal_dependent_views (**i);
1138 (*i)->fake_set_opaque (false);
1139 (*i)->move (-_total_x_delta, 0);
1140 (*i)->set_height (rtv->view()->child_height ());
1143 _editor->update_canvas_now ();
1148 RegionMotionDrag::x_move_allowed () const
1150 if (Config->get_edit_mode() == Lock) {
1151 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1152 return _x_constrained;
1155 return !_x_constrained;
1159 RegionMotionDrag::copy_regions (GdkEvent* event)
1161 /* duplicate the regionview(s) and region(s) */
1163 list<RegionView*> new_regionviews;
1165 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1167 RegionView* rv = (*i);
1168 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1169 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1171 const boost::shared_ptr<const Region> original = rv->region();
1172 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1176 boost::shared_ptr<AudioRegion> audioregion_copy
1177 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1178 nrv = new AudioRegionView (*arv, audioregion_copy);
1180 boost::shared_ptr<MidiRegion> midiregion_copy
1181 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1182 nrv = new MidiRegionView (*mrv, midiregion_copy);
1187 nrv->get_canvas_group()->show ();
1188 new_regionviews.push_back (nrv);
1190 /* swap _primary to the copy */
1192 if (rv == _primary) {
1196 /* ..and deselect the one we copied */
1198 rv->set_selected (false);
1201 if (new_regionviews.empty()) {
1205 /* reflect the fact that we are dragging the copies */
1207 _views = new_regionviews;
1209 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1212 sync the canvas to what we think is its current state
1213 without it, the canvas seems to
1214 "forget" to update properly after the upcoming reparent()
1215 ..only if the mouse is in rapid motion at the time of the grab.
1216 something to do with regionview creation taking so long?
1218 _editor->update_canvas_now();
1222 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1224 /* Which trackview is this ? */
1226 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1227 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1228 (*layer) = tvp.second;
1230 if (*tv && (*tv)->layer_display() == Overlaid) {
1234 /* The region motion is only processed if the pointer is over
1238 if (!(*tv) || !(*tv)->is_track()) {
1239 /* To make sure we hide the verbose canvas cursor when the mouse is
1240 not held over and audiotrack.
1242 _editor->hide_verbose_canvas_cursor ();
1249 /** @param new_order New track order.
1250 * @param old_order Old track order.
1251 * @param visible_y_low Lowest visible order.
1252 * @return true if y movement should not happen, otherwise false.
1255 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1257 if (new_order != old_order) {
1259 /* this isn't the pointer track */
1263 /* moving up the canvas */
1264 if ( (new_order - y_span) >= tavs.visible_y_low) {
1268 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1269 int32_t visible_tracks = 0;
1270 while (visible_tracks < y_span ) {
1272 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1273 /* passing through a hidden track */
1278 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1279 /* moving to a non-track; disallow */
1285 /* moving beyond the lowest visible track; disallow */
1289 } else if (y_span < 0) {
1291 /* moving down the canvas */
1292 if ((new_order - y_span) <= tavs.visible_y_high) {
1294 int32_t visible_tracks = 0;
1296 while (visible_tracks > y_span ) {
1299 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1300 /* passing through a hidden track */
1305 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1306 /* moving to a non-track; disallow */
1313 /* moving beyond the highest visible track; disallow */
1320 /* this is the pointer's track */
1322 if ((new_order - y_span) > tavs.visible_y_high) {
1323 /* we will overflow */
1325 } else if ((new_order - y_span) < tavs.visible_y_low) {
1326 /* we will overflow */
1335 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1336 : RegionMotionDrag (e, i, p, v, b),
1339 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1341 _dest_trackview = tv;
1342 if (tv->layer_display() == Overlaid) {
1345 _dest_layer = _primary->region()->layer ();
1349 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1350 if (rtv && rtv->is_track()) {
1351 speed = rtv->get_diskstream()->speed ();
1354 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1358 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1360 RegionMotionDrag::start_grab (event, c);
1362 _pointer_frame_offset = grab_frame() - _last_frame_position;
1365 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1366 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1368 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1369 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1371 _primary = v->view()->create_region_view (r, false, false);
1373 _primary->get_canvas_group()->show ();
1374 _primary->set_position (pos, 0);
1375 _views.push_back (_primary);
1377 _last_frame_position = pos;
1379 _item = _primary->get_canvas_group ();
1380 _dest_trackview = v;
1381 _dest_layer = _primary->region()->layer ();
1384 map<RegionView*, pair<RouteTimeAxisView*, int> >
1385 RegionMotionDrag::find_time_axis_views_and_layers ()
1387 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1389 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1391 double ix1, ix2, iy1, iy2;
1392 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1393 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1394 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1396 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1397 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1405 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1407 _editor->update_canvas_now ();
1409 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1411 RouteTimeAxisView* dest_rtv = final[_primary].first;
1413 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1414 _primary->get_canvas_group()->property_y() = 0;
1416 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1418 _editor->begin_reversible_command (_("insert region"));
1419 XMLNode& before = playlist->get_state ();
1420 playlist->add_region (_primary->region (), _last_frame_position);
1421 _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1422 _editor->commit_reversible_command ();
1430 RegionInsertDrag::aborted ()
1435 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1436 : RegionMoveDrag (e, i, p, v, false, false)
1441 struct RegionSelectionByPosition {
1442 bool operator() (RegionView*a, RegionView* b) {
1443 return a->region()->position () < b->region()->position();
1448 RegionSpliceDrag::motion (GdkEvent* event, bool)
1450 RouteTimeAxisView* tv;
1453 if (!check_possible (&tv, &layer)) {
1459 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1465 RegionSelection copy (_editor->selection->regions);
1467 RegionSelectionByPosition cmp;
1470 nframes64_t const pf = adjusted_current_frame (event);
1472 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1474 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1480 boost::shared_ptr<Playlist> playlist;
1482 if ((playlist = atv->playlist()) == 0) {
1486 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1491 if (pf < (*i)->region()->last_frame() + 1) {
1495 if (pf > (*i)->region()->first_frame()) {
1501 playlist->shuffle ((*i)->region(), dir);
1506 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1512 RegionSpliceDrag::aborted ()
1517 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1525 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1527 _dest_trackview = _view;
1529 Drag::start_grab (event);
1534 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1537 // TODO: create region-create-drag region view here
1540 // TODO: resize region-create-drag region view here
1544 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1546 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1552 if (!movement_occurred) {
1553 mtv->add_region (grab_frame ());
1555 motion (event, false);
1556 // TODO: create region-create-drag region here
1561 RegionCreateDrag::aborted ()
1566 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1574 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1577 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1579 Drag::start_grab (event);
1581 region = &cnote->region_view();
1583 double region_start = region->get_position_pixels();
1584 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1586 if (grab_x() <= middle_point) {
1587 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1590 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1594 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1596 if (event->motion.state & Keyboard::PrimaryModifier) {
1602 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1604 if (ms.size() > 1) {
1605 /* has to be relative, may make no sense otherwise */
1609 region->note_selected (cnote, true);
1611 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1612 MidiRegionSelection::iterator next;
1615 (*r)->begin_resizing (at_front);
1621 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1623 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1624 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1625 (*r)->update_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1630 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1632 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1633 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1634 (*r)->commit_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1639 NoteResizeDrag::aborted ()
1645 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1651 RegionGainDrag::finished (GdkEvent *, bool)
1657 RegionGainDrag::aborted ()
1662 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1663 : RegionDrag (e, i, p, v)
1664 , _have_transaction (false)
1670 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1673 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1674 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1676 if (tv && tv->is_track()) {
1677 speed = tv->get_diskstream()->speed();
1680 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1681 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1682 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1684 Drag::start_grab (event, _editor->trimmer_cursor);
1686 nframes64_t const pf = adjusted_current_frame (event);
1688 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1689 _operation = ContentsTrim;
1691 /* These will get overridden for a point trim.*/
1692 if (pf < (region_start + region_length/2)) {
1693 /* closer to start */
1694 _operation = StartTrim;
1695 } else if (pf > (region_end - region_length/2)) {
1697 _operation = EndTrim;
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;
1718 nframes64_t frame_delta = 0;
1720 bool left_direction;
1721 bool obey_snap = event ? !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) : false;
1723 /* snap modifier works differently here..
1724 its current state has to be passed to the
1725 various trim functions in order to work properly
1729 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1730 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1731 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1733 if (tv && tv->is_track()) {
1734 speed = tv->get_diskstream()->speed();
1737 nframes64_t const pf = adjusted_current_frame (event);
1739 if (last_pointer_frame() > pf) {
1740 left_direction = true;
1742 left_direction = false;
1749 switch (_operation) {
1751 trim_type = "Region start trim";
1754 trim_type = "Region end trim";
1757 trim_type = "Region content trim";
1761 _editor->begin_reversible_command (trim_type);
1762 _have_transaction = true;
1764 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1765 (*i)->fake_set_opaque(false);
1766 (*i)->region()->freeze ();
1768 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1771 arv->temporarily_hide_envelope ();
1774 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1775 insert_result = _editor->motion_frozen_playlists.insert (pl);
1777 if (insert_result.second) {
1778 _editor->session()->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1784 if (left_direction) {
1785 frame_delta = (last_pointer_frame() - pf);
1787 frame_delta = (pf - last_pointer_frame());
1790 bool non_overlap_trim = false;
1792 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1793 non_overlap_trim = true;
1796 switch (_operation) {
1798 if ((left_direction == false) && (pf <= rv->region()->first_frame()/speed)) {
1802 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1803 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1809 if ((left_direction == true) && (pf > (nframes64_t) (rv->region()->last_frame()/speed))) {
1813 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1814 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1821 bool swap_direction = false;
1823 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1824 swap_direction = true;
1827 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1828 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1834 switch (_operation) {
1836 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1839 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1842 _editor->show_verbose_time_cursor (pf, 10);
1849 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1851 if (movement_occurred) {
1852 motion (event, false);
1854 if (!_editor->selection->selected (_primary)) {
1855 _editor->thaw_region_after_trim (*_primary);
1858 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1859 _editor->thaw_region_after_trim (**i);
1860 (*i)->fake_set_opaque (true);
1863 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1865 if (_have_transaction) {
1866 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1870 _editor->motion_frozen_playlists.clear ();
1872 if (_have_transaction) {
1873 _editor->commit_reversible_command();
1877 /* no mouse movement */
1878 _editor->point_trim (event, adjusted_current_frame (event));
1883 TrimDrag::aborted ()
1885 /* Our motion method is changing model state, so use the Undo system
1886 to cancel. Perhaps not ideal, as this will leave an Undo point
1887 behind which may be slightly odd from the user's point of view.
1892 if (_have_transaction) {
1897 pair<nframes64_t, nframes64_t>
1898 TrimDrag::extent () const
1900 pair<nframes64_t, nframes64_t> e = make_pair (INT64_MAX, 0);
1902 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1903 boost::shared_ptr<Region> r = (*i)->region ();
1904 pair<nframes64_t, nframes64_t> const t = make_pair (r->position(), r->position() + r->length ());
1905 e.first = min (e.first, t.first);
1906 e.second = max (e.second, t.second);
1913 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1917 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1922 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1925 // create a dummy marker for visual representation of moving the copy.
1926 // The actual copying is not done before we reach the finish callback.
1928 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1929 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1930 *new MeterSection (_marker->meter()));
1932 _item = &new_marker->the_item ();
1933 _marker = new_marker;
1937 MetricSection& section (_marker->meter());
1939 if (!section.movable()) {
1945 Drag::start_grab (event, cursor);
1947 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1949 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1953 MeterMarkerDrag::motion (GdkEvent* event, bool)
1955 nframes64_t const pf = adjusted_current_frame (event);
1957 _marker->set_position (pf);
1959 _editor->show_verbose_time_cursor (pf, 10);
1963 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1965 if (!movement_occurred) {
1969 motion (event, false);
1973 TempoMap& map (_editor->session()->tempo_map());
1974 map.bbt_time (last_pointer_frame(), when);
1976 if (_copy == true) {
1977 _editor->begin_reversible_command (_("copy meter mark"));
1978 XMLNode &before = map.get_state();
1979 map.add_meter (_marker->meter(), when);
1980 XMLNode &after = map.get_state();
1981 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1982 _editor->commit_reversible_command ();
1984 // delete the dummy marker we used for visual representation of copying.
1985 // a new visual marker will show up automatically.
1988 _editor->begin_reversible_command (_("move meter mark"));
1989 XMLNode &before = map.get_state();
1990 map.move_meter (_marker->meter(), when);
1991 XMLNode &after = map.get_state();
1992 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1993 _editor->commit_reversible_command ();
1998 MeterMarkerDrag::aborted ()
2000 _marker->set_position (_marker->meter().frame ());
2003 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
2007 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
2012 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2017 // create a dummy marker for visual representation of moving the copy.
2018 // The actual copying is not done before we reach the finish callback.
2020 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
2021 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
2022 *new TempoSection (_marker->tempo()));
2024 _item = &new_marker->the_item ();
2025 _marker = new_marker;
2029 MetricSection& section (_marker->tempo());
2031 if (!section.movable()) {
2036 Drag::start_grab (event, cursor);
2038 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
2039 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2043 TempoMarkerDrag::motion (GdkEvent* event, bool)
2045 nframes64_t const pf = adjusted_current_frame (event);
2046 _marker->set_position (pf);
2047 _editor->show_verbose_time_cursor (pf, 10);
2051 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2053 if (!movement_occurred) {
2057 motion (event, false);
2061 TempoMap& map (_editor->session()->tempo_map());
2062 map.bbt_time (last_pointer_frame(), when);
2064 if (_copy == true) {
2065 _editor->begin_reversible_command (_("copy tempo mark"));
2066 XMLNode &before = map.get_state();
2067 map.add_tempo (_marker->tempo(), when);
2068 XMLNode &after = map.get_state();
2069 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2070 _editor->commit_reversible_command ();
2072 // delete the dummy marker we used for visual representation of copying.
2073 // a new visual marker will show up automatically.
2076 _editor->begin_reversible_command (_("move tempo mark"));
2077 XMLNode &before = map.get_state();
2078 map.move_tempo (_marker->tempo(), when);
2079 XMLNode &after = map.get_state();
2080 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2081 _editor->commit_reversible_command ();
2086 TempoMarkerDrag::aborted ()
2088 _marker->set_position (_marker->tempo().frame());
2091 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2095 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2100 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2102 Drag::start_grab (event, c);
2106 nframes64_t where = _editor->event_frame (event, 0, 0);
2108 _editor->snap_to_with_modifier (where, event);
2109 _editor->playhead_cursor->set_position (where);
2113 if (_cursor == _editor->playhead_cursor) {
2114 _editor->_dragging_playhead = true;
2116 if (_editor->session() && _was_rolling && _stop) {
2117 _editor->session()->request_stop ();
2120 if (_editor->session() && _editor->session()->is_auditioning()) {
2121 _editor->session()->cancel_audition ();
2125 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2127 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2131 CursorDrag::motion (GdkEvent* event, bool)
2133 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2135 if (adjusted_frame == last_pointer_frame()) {
2139 _cursor->set_position (adjusted_frame);
2141 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2144 _editor->update_canvas_now ();
2146 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2150 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2152 _editor->_dragging_playhead = false;
2154 if (!movement_occurred && _stop) {
2158 motion (event, false);
2160 if (_item == &_editor->playhead_cursor->canvas_item) {
2161 if (_editor->session()) {
2162 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2163 _editor->_pending_locate_request = true;
2169 CursorDrag::aborted ()
2171 _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);
2194 FadeInDrag::motion (GdkEvent* event, bool)
2196 nframes64_t fade_length;
2198 nframes64_t const pos = adjusted_current_frame (event);
2200 boost::shared_ptr<Region> region = _primary->region ();
2202 if (pos < (region->position() + 64)) {
2203 fade_length = 64; // this should be a minimum defined somewhere
2204 } else if (pos > region->last_frame()) {
2205 fade_length = region->length();
2207 fade_length = pos - region->position();
2210 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2212 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2218 tmp->reset_fade_in_shape_width (fade_length);
2221 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2225 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2227 if (!movement_occurred) {
2231 nframes64_t fade_length;
2233 nframes64_t const pos = adjusted_current_frame (event);
2235 boost::shared_ptr<Region> region = _primary->region ();
2237 if (pos < (region->position() + 64)) {
2238 fade_length = 64; // this should be a minimum defined somewhere
2239 } else if (pos > region->last_frame()) {
2240 fade_length = region->length();
2242 fade_length = pos - region->position();
2245 _editor->begin_reversible_command (_("change fade in length"));
2247 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2249 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2255 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2256 XMLNode &before = alist->get_state();
2258 tmp->audio_region()->set_fade_in_length (fade_length);
2259 tmp->audio_region()->set_fade_in_active (true);
2261 XMLNode &after = alist->get_state();
2262 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2265 _editor->commit_reversible_command ();
2269 FadeInDrag::aborted ()
2271 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2272 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2278 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2282 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2283 : RegionDrag (e, i, p, v)
2289 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2291 Drag::start_grab (event, cursor);
2293 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2294 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2296 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2297 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2301 FadeOutDrag::motion (GdkEvent* event, bool)
2303 nframes64_t fade_length;
2305 nframes64_t const pos = adjusted_current_frame (event);
2307 boost::shared_ptr<Region> region = _primary->region ();
2309 if (pos > (region->last_frame() - 64)) {
2310 fade_length = 64; // this should really be a minimum fade defined somewhere
2312 else if (pos < region->position()) {
2313 fade_length = region->length();
2316 fade_length = region->last_frame() - pos;
2319 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2321 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2327 tmp->reset_fade_out_shape_width (fade_length);
2330 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2334 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2336 if (!movement_occurred) {
2340 nframes64_t fade_length;
2342 nframes64_t const pos = adjusted_current_frame (event);
2344 boost::shared_ptr<Region> region = _primary->region ();
2346 if (pos > (region->last_frame() - 64)) {
2347 fade_length = 64; // this should really be a minimum fade defined somewhere
2349 else if (pos < region->position()) {
2350 fade_length = region->length();
2353 fade_length = region->last_frame() - pos;
2356 _editor->begin_reversible_command (_("change fade out length"));
2358 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2360 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2366 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2367 XMLNode &before = alist->get_state();
2369 tmp->audio_region()->set_fade_out_length (fade_length);
2370 tmp->audio_region()->set_fade_out_active (true);
2372 XMLNode &after = alist->get_state();
2373 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2376 _editor->commit_reversible_command ();
2380 FadeOutDrag::aborted ()
2382 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2383 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2389 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2393 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2396 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2399 _points.push_back (Gnome::Art::Point (0, 0));
2400 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2402 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2403 _line->property_width_pixels() = 1;
2404 _line->property_points () = _points;
2407 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2410 MarkerDrag::~MarkerDrag ()
2412 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2418 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2420 Drag::start_grab (event, cursor);
2424 Location *location = _editor->find_location_from_marker (_marker, is_start);
2425 _editor->_dragging_edit_point = true;
2427 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2429 update_item (location);
2431 // _drag_line->show();
2432 // _line->raise_to_top();
2435 _editor->show_verbose_time_cursor (location->start(), 10);
2437 _editor->show_verbose_time_cursor (location->end(), 10);
2440 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2443 case Selection::Toggle:
2444 _editor->selection->toggle (_marker);
2446 case Selection::Set:
2447 if (!_editor->selection->selected (_marker)) {
2448 _editor->selection->set (_marker);
2451 case Selection::Extend:
2453 Locations::LocationList ll;
2454 list<Marker*> to_add;
2456 _editor->selection->markers.range (s, e);
2457 s = min (_marker->position(), s);
2458 e = max (_marker->position(), e);
2461 if (e < max_frames) {
2464 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2465 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2466 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2469 to_add.push_back (lm->start);
2472 to_add.push_back (lm->end);
2476 if (!to_add.empty()) {
2477 _editor->selection->add (to_add);
2481 case Selection::Add:
2482 _editor->selection->add (_marker);
2486 /* set up copies for us to manipulate during the drag */
2488 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2489 Location *l = _editor->find_location_from_marker (*i, is_start);
2490 _copied_locations.push_back (new Location (*l));
2495 MarkerDrag::motion (GdkEvent* event, bool)
2497 nframes64_t f_delta = 0;
2499 bool move_both = false;
2501 Location *real_location;
2502 Location *copy_location = 0;
2504 nframes64_t const newframe = adjusted_current_frame (event);
2506 nframes64_t next = newframe;
2508 if (newframe == last_pointer_frame()) {
2512 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2516 MarkerSelection::iterator i;
2517 list<Location*>::iterator x;
2519 /* find the marker we're dragging, and compute the delta */
2521 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2522 x != _copied_locations.end() && i != _editor->selection->markers.end();
2528 if (marker == _marker) {
2530 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2535 if (real_location->is_mark()) {
2536 f_delta = newframe - copy_location->start();
2540 switch (marker->type()) {
2542 case Marker::LoopStart:
2543 case Marker::PunchIn:
2544 f_delta = newframe - copy_location->start();
2548 case Marker::LoopEnd:
2549 case Marker::PunchOut:
2550 f_delta = newframe - copy_location->end();
2553 /* what kind of marker is this ? */
2561 if (i == _editor->selection->markers.end()) {
2562 /* hmm, impossible - we didn't find the dragged marker */
2566 /* now move them all */
2568 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2569 x != _copied_locations.end() && i != _editor->selection->markers.end();
2575 /* call this to find out if its the start or end */
2577 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2581 if (real_location->locked()) {
2585 if (copy_location->is_mark()) {
2589 copy_location->set_start (copy_location->start() + f_delta);
2593 nframes64_t new_start = copy_location->start() + f_delta;
2594 nframes64_t new_end = copy_location->end() + f_delta;
2596 if (is_start) { // start-of-range marker
2599 copy_location->set_start (new_start);
2600 copy_location->set_end (new_end);
2601 } else if (new_start < copy_location->end()) {
2602 copy_location->set_start (new_start);
2604 _editor->snap_to (next, 1, true);
2605 copy_location->set_end (next);
2606 copy_location->set_start (newframe);
2609 } else { // end marker
2612 copy_location->set_end (new_end);
2613 copy_location->set_start (new_start);
2614 } else if (new_end > copy_location->start()) {
2615 copy_location->set_end (new_end);
2616 } else if (newframe > 0) {
2617 _editor->snap_to (next, -1, true);
2618 copy_location->set_start (next);
2619 copy_location->set_end (newframe);
2624 update_item (copy_location);
2626 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2629 lm->set_position (copy_location->start(), copy_location->end());
2633 assert (!_copied_locations.empty());
2635 _editor->show_verbose_time_cursor (newframe, 10);
2638 _editor->update_canvas_now ();
2643 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2645 if (!movement_occurred) {
2647 /* just a click, do nothing but finish
2648 off the selection process
2651 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2654 case Selection::Set:
2655 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2656 _editor->selection->set (_marker);
2660 case Selection::Toggle:
2661 case Selection::Extend:
2662 case Selection::Add:
2669 _editor->_dragging_edit_point = false;
2671 _editor->begin_reversible_command ( _("move marker") );
2672 XMLNode &before = _editor->session()->locations()->get_state();
2674 MarkerSelection::iterator i;
2675 list<Location*>::iterator x;
2678 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2679 x != _copied_locations.end() && i != _editor->selection->markers.end();
2682 Location * location = _editor->find_location_from_marker (*i, is_start);
2686 if (location->locked()) {
2690 if (location->is_mark()) {
2691 location->set_start ((*x)->start());
2693 location->set ((*x)->start(), (*x)->end());
2698 XMLNode &after = _editor->session()->locations()->get_state();
2699 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2700 _editor->commit_reversible_command ();
2706 MarkerDrag::aborted ()
2712 MarkerDrag::update_item (Location* location)
2714 double const x1 = _editor->frame_to_pixel (location->start());
2716 _points.front().set_x(x1);
2717 _points.back().set_x(x1);
2718 _line->property_points() = _points;
2721 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2723 _cumulative_x_drag (0),
2724 _cumulative_y_drag (0)
2726 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2732 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2734 Drag::start_grab (event, _editor->fader_cursor);
2736 // start the grab at the center of the control point so
2737 // the point doesn't 'jump' to the mouse after the first drag
2738 _time_axis_view_grab_x = _point->get_x();
2739 _time_axis_view_grab_y = _point->get_y();
2741 float const fraction = 1 - (_point->get_y() / _point->line().height());
2743 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2745 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2746 event->button.x + 10, event->button.y + 10);
2748 _editor->show_verbose_canvas_cursor ();
2752 ControlPointDrag::motion (GdkEvent* event, bool)
2754 double dx = _drags->current_pointer_x() - last_pointer_x();
2755 double dy = _drags->current_pointer_y() - last_pointer_y();
2757 if (event->button.state & Keyboard::SecondaryModifier) {
2762 /* coordinate in TimeAxisView's space */
2763 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2764 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2766 // calculate zero crossing point. back off by .01 to stay on the
2767 // positive side of zero
2768 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2770 // make sure we hit zero when passing through
2771 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2775 if (_x_constrained) {
2776 cx = _time_axis_view_grab_x;
2778 if (_y_constrained) {
2779 cy = _time_axis_view_grab_y;
2782 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2783 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2787 cy = min ((double) _point->line().height(), cy);
2789 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2791 if (!_x_constrained) {
2792 _editor->snap_to_with_modifier (cx_frames, event);
2795 float const fraction = 1.0 - (cy / _point->line().height());
2797 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2799 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2801 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2805 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2807 if (!movement_occurred) {
2811 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2812 _editor->reset_point_selection ();
2816 motion (event, false);
2818 _point->line().end_drag ();
2822 ControlPointDrag::aborted ()
2824 _point->line().reset ();
2828 ControlPointDrag::active (Editing::MouseMode m)
2830 if (m == Editing::MouseGain) {
2831 /* always active in mouse gain */
2835 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2836 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2839 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2842 _cumulative_y_drag (0)
2847 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2849 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2852 _item = &_line->grab_item ();
2854 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2855 origin, and ditto for y.
2858 double cx = event->button.x;
2859 double cy = event->button.y;
2861 _line->parent_group().w2i (cx, cy);
2863 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2868 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2869 /* no adjacent points */
2873 Drag::start_grab (event, _editor->fader_cursor);
2875 /* store grab start in parent frame */
2877 _time_axis_view_grab_x = cx;
2878 _time_axis_view_grab_y = cy;
2880 double fraction = 1.0 - (cy / _line->height());
2882 _line->start_drag_line (before, after, fraction);
2884 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2885 event->button.x + 10, event->button.y + 10);
2887 _editor->show_verbose_canvas_cursor ();
2891 LineDrag::motion (GdkEvent* event, bool)
2893 double dy = _drags->current_pointer_y() - last_pointer_y();
2895 if (event->button.state & Keyboard::SecondaryModifier) {
2899 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2901 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2904 cy = min ((double) _line->height(), cy);
2906 double const fraction = 1.0 - (cy / _line->height());
2910 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2916 /* we are ignoring x position for this drag, so we can just pass in anything */
2917 _line->drag_motion (0, fraction, true, push);
2919 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2923 LineDrag::finished (GdkEvent* event, bool)
2925 motion (event, false);
2930 LineDrag::aborted ()
2936 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2938 Drag::start_grab (event);
2939 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2943 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2950 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2952 nframes64_t grab = grab_frame ();
2953 if (Config->get_rubberbanding_snaps_to_grid ()) {
2954 _editor->snap_to_with_modifier (grab, event);
2957 /* base start and end on initial click position */
2967 if (_drags->current_pointer_y() < grab_y()) {
2968 y1 = _drags->current_pointer_y();
2971 y2 = _drags->current_pointer_y();
2976 if (start != end || y1 != y2) {
2978 double x1 = _editor->frame_to_pixel (start);
2979 double x2 = _editor->frame_to_pixel (end);
2981 _editor->rubberband_rect->property_x1() = x1;
2982 _editor->rubberband_rect->property_y1() = y1;
2983 _editor->rubberband_rect->property_x2() = x2;
2984 _editor->rubberband_rect->property_y2() = y2;
2986 _editor->rubberband_rect->show();
2987 _editor->rubberband_rect->raise_to_top();
2989 _editor->show_verbose_time_cursor (pf, 10);
2994 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2996 if (movement_occurred) {
2998 motion (event, false);
3001 if (_drags->current_pointer_y() < grab_y()) {
3002 y1 = _drags->current_pointer_y();
3005 y2 = _drags->current_pointer_y();
3010 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
3013 _editor->begin_reversible_command (_("rubberband selection"));
3015 if (grab_frame() < last_pointer_frame()) {
3016 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
3018 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
3022 _editor->commit_reversible_command ();
3026 if (!getenv("ARDOUR_SAE")) {
3027 _editor->selection->clear_tracks();
3029 _editor->selection->clear_regions();
3030 _editor->selection->clear_points ();
3031 _editor->selection->clear_lines ();
3034 _editor->rubberband_rect->hide();
3038 RubberbandSelectDrag::aborted ()
3040 _editor->rubberband_rect->hide ();
3044 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3046 Drag::start_grab (event);
3048 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3052 TimeFXDrag::motion (GdkEvent* event, bool)
3054 RegionView* rv = _primary;
3056 nframes64_t const pf = adjusted_current_frame (event);
3058 if (pf > rv->region()->position()) {
3059 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3062 _editor->show_verbose_time_cursor (pf, 10);
3066 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3068 _primary->get_time_axis_view().hide_timestretch ();
3070 if (!movement_occurred) {
3074 if (last_pointer_frame() < _primary->region()->position()) {
3075 /* backwards drag of the left edge - not usable */
3079 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3081 float percentage = (double) newlen / (double) _primary->region()->length();
3083 #ifndef USE_RUBBERBAND
3084 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3085 if (_primary->region()->data_type() == DataType::AUDIO) {
3086 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3090 _editor->begin_reversible_command (_("timestretch"));
3092 // XXX how do timeFX on multiple regions ?
3097 if (!_editor->time_stretch (rs, percentage) == 0) {
3098 error << _("An error occurred while executing time stretch operation") << endmsg;
3103 TimeFXDrag::aborted ()
3105 _primary->get_time_axis_view().hide_timestretch ();
3110 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3112 Drag::start_grab (event);
3116 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3118 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3122 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3124 if (movement_occurred && _editor->session()) {
3125 /* make sure we stop */
3126 _editor->session()->request_transport_speed (0.0);
3131 ScrubDrag::aborted ()
3136 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3140 , _original_pointer_time_axis (-1)
3141 , _last_pointer_time_axis (-1)
3147 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3149 nframes64_t start = 0;
3150 nframes64_t end = 0;
3152 if (_editor->session() == 0) {
3156 Gdk::Cursor* cursor = 0;
3158 switch (_operation) {
3159 case CreateSelection:
3160 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3165 cursor = _editor->selector_cursor;
3166 Drag::start_grab (event, cursor);
3169 case SelectionStartTrim:
3170 if (_editor->clicked_axisview) {
3171 _editor->clicked_axisview->order_selection_trims (_item, true);
3173 Drag::start_grab (event, _editor->trimmer_cursor);
3174 start = _editor->selection->time[_editor->clicked_selection].start;
3175 _pointer_frame_offset = grab_frame() - start;
3178 case SelectionEndTrim:
3179 if (_editor->clicked_axisview) {
3180 _editor->clicked_axisview->order_selection_trims (_item, false);
3182 Drag::start_grab (event, _editor->trimmer_cursor);
3183 end = _editor->selection->time[_editor->clicked_selection].end;
3184 _pointer_frame_offset = grab_frame() - end;
3188 start = _editor->selection->time[_editor->clicked_selection].start;
3189 Drag::start_grab (event, cursor);
3190 _pointer_frame_offset = grab_frame() - start;
3194 if (_operation == SelectionMove) {
3195 _editor->show_verbose_time_cursor (start, 10);
3197 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3200 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3204 SelectionDrag::motion (GdkEvent* event, bool first_move)
3206 nframes64_t start = 0;
3207 nframes64_t end = 0;
3210 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3211 if (pending_time_axis.first == 0) {
3215 nframes64_t const pending_position = adjusted_current_frame (event);
3217 /* only alter selection if things have changed */
3219 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3223 switch (_operation) {
3224 case CreateSelection:
3226 nframes64_t grab = grab_frame ();
3229 _editor->snap_to (grab);
3232 if (pending_position < grab_frame()) {
3233 start = pending_position;
3236 end = pending_position;
3240 /* first drag: Either add to the selection
3241 or create a new selection
3247 /* adding to the selection */
3248 _editor->selection->add (_editor->clicked_axisview);
3249 _editor->clicked_selection = _editor->selection->add (start, end);
3254 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3255 _editor->selection->set (_editor->clicked_axisview);
3258 _editor->clicked_selection = _editor->selection->set (start, end);
3262 /* select the track that we're in */
3263 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3264 _editor->selection->add (pending_time_axis.first);
3265 _added_time_axes.push_back (pending_time_axis.first);
3268 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3269 tracks that we selected in the first place.
3272 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3273 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3275 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3276 while (i != _added_time_axes.end()) {
3278 list<TimeAxisView*>::iterator tmp = i;
3281 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3282 _editor->selection->remove (*i);
3283 _added_time_axes.remove (*i);
3292 case SelectionStartTrim:
3294 start = _editor->selection->time[_editor->clicked_selection].start;
3295 end = _editor->selection->time[_editor->clicked_selection].end;
3297 if (pending_position > end) {
3300 start = pending_position;
3304 case SelectionEndTrim:
3306 start = _editor->selection->time[_editor->clicked_selection].start;
3307 end = _editor->selection->time[_editor->clicked_selection].end;
3309 if (pending_position < start) {
3312 end = pending_position;
3319 start = _editor->selection->time[_editor->clicked_selection].start;
3320 end = _editor->selection->time[_editor->clicked_selection].end;
3322 length = end - start;
3324 start = pending_position;
3325 _editor->snap_to (start);
3327 end = start + length;
3332 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3333 _editor->start_canvas_autoscroll (1, 0);
3337 _editor->selection->replace (_editor->clicked_selection, start, end);
3340 if (_operation == SelectionMove) {
3341 _editor->show_verbose_time_cursor(start, 10);
3343 _editor->show_verbose_time_cursor(pending_position, 10);
3348 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3350 Session* s = _editor->session();
3352 if (movement_occurred) {
3353 motion (event, false);
3354 /* XXX this is not object-oriented programming at all. ick */
3355 if (_editor->selection->time.consolidate()) {
3356 _editor->selection->TimeChanged ();
3359 /* XXX what if its a music time selection? */
3360 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3361 s->request_play_range (&_editor->selection->time, true);
3366 /* just a click, no pointer movement.*/
3368 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3369 _editor->selection->clear_time();
3372 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3373 _editor->selection->set (_editor->clicked_axisview);
3376 if (s && s->get_play_range () && s->transport_rolling()) {
3377 s->request_stop (false, false);
3382 _editor->stop_canvas_autoscroll ();
3386 SelectionDrag::aborted ()
3391 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3396 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3397 _drag_rect->hide ();
3399 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3400 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3404 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3406 if (_editor->session() == 0) {
3410 Gdk::Cursor* cursor = 0;
3412 if (!_editor->temp_location) {
3413 _editor->temp_location = new Location;
3416 switch (_operation) {
3417 case CreateRangeMarker:
3418 case CreateTransportMarker:
3419 case CreateCDMarker:
3421 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3426 cursor = _editor->selector_cursor;
3430 Drag::start_grab (event, cursor);
3432 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3436 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3438 nframes64_t start = 0;
3439 nframes64_t end = 0;
3440 ArdourCanvas::SimpleRect *crect;
3442 switch (_operation) {
3443 case CreateRangeMarker:
3444 crect = _editor->range_bar_drag_rect;
3446 case CreateTransportMarker:
3447 crect = _editor->transport_bar_drag_rect;
3449 case CreateCDMarker:
3450 crect = _editor->cd_marker_bar_drag_rect;
3453 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3458 nframes64_t const pf = adjusted_current_frame (event);
3460 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3461 nframes64_t grab = grab_frame ();
3462 _editor->snap_to (grab);
3464 if (pf < grab_frame()) {
3472 /* first drag: Either add to the selection
3473 or create a new selection.
3478 _editor->temp_location->set (start, end);
3482 update_item (_editor->temp_location);
3484 //_drag_rect->raise_to_top();
3489 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3490 _editor->start_canvas_autoscroll (1, 0);
3494 _editor->temp_location->set (start, end);
3496 double x1 = _editor->frame_to_pixel (start);
3497 double x2 = _editor->frame_to_pixel (end);
3498 crect->property_x1() = x1;
3499 crect->property_x2() = x2;
3501 update_item (_editor->temp_location);
3504 _editor->show_verbose_time_cursor (pf, 10);
3509 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3511 Location * newloc = 0;
3515 if (movement_occurred) {
3516 motion (event, false);
3519 switch (_operation) {
3520 case CreateRangeMarker:
3521 case CreateCDMarker:
3523 _editor->begin_reversible_command (_("new range marker"));
3524 XMLNode &before = _editor->session()->locations()->get_state();
3525 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3526 if (_operation == CreateCDMarker) {
3527 flags = Location::IsRangeMarker | Location::IsCDMarker;
3528 _editor->cd_marker_bar_drag_rect->hide();
3531 flags = Location::IsRangeMarker;
3532 _editor->range_bar_drag_rect->hide();
3534 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3535 _editor->session()->locations()->add (newloc, true);
3536 XMLNode &after = _editor->session()->locations()->get_state();
3537 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3538 _editor->commit_reversible_command ();
3542 case CreateTransportMarker:
3543 // popup menu to pick loop or punch
3544 _editor->new_transport_marker_context_menu (&event->button, _item);
3548 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3550 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3555 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3557 if (end == max_frames) {
3558 end = _editor->session()->current_end_frame ();
3561 if (start == max_frames) {
3562 start = _editor->session()->current_start_frame ();
3565 switch (_editor->mouse_mode) {
3567 /* find the two markers on either side and then make the selection from it */
3568 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3572 /* find the two markers on either side of the click and make the range out of it */
3573 _editor->selection->set (start, end);
3582 _editor->stop_canvas_autoscroll ();
3586 RangeMarkerBarDrag::aborted ()
3592 RangeMarkerBarDrag::update_item (Location* location)
3594 double const x1 = _editor->frame_to_pixel (location->start());
3595 double const x2 = _editor->frame_to_pixel (location->end());
3597 _drag_rect->property_x1() = x1;
3598 _drag_rect->property_x2() = x2;
3602 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3604 Drag::start_grab (event, _editor->zoom_cursor);
3605 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3609 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3614 nframes64_t const pf = adjusted_current_frame (event);
3616 nframes64_t grab = grab_frame ();
3617 _editor->snap_to_with_modifier (grab, event);
3619 /* base start and end on initial click position */
3631 _editor->zoom_rect->show();
3632 _editor->zoom_rect->raise_to_top();
3635 _editor->reposition_zoom_rect(start, end);
3637 _editor->show_verbose_time_cursor (pf, 10);
3642 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3644 if (movement_occurred) {
3645 motion (event, false);
3647 if (grab_frame() < last_pointer_frame()) {
3648 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3650 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3653 _editor->temporal_zoom_to_frame (false, grab_frame());
3655 temporal_zoom_step (false);
3656 center_screen (grab_frame());
3660 _editor->zoom_rect->hide();
3664 MouseZoomDrag::aborted ()
3666 _editor->zoom_rect->hide ();
3669 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3672 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3673 region = &cnote->region_view();
3677 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3679 Drag::start_grab (event);
3682 drag_delta_note = 0;
3687 event_x = _drags->current_pointer_x();
3688 event_y = _drags->current_pointer_y();
3690 _item->property_parent().get_value()->w2i(event_x, event_y);
3692 last_x = region->snap_to_pixel(event_x);
3695 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3697 if (!(was_selected = cnote->selected())) {
3699 /* tertiary-click means extend selection - we'll do that on button release,
3700 so don't add it here, because otherwise we make it hard to figure
3701 out the "extend-to" range.
3704 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3707 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3710 region->note_selected (cnote, true);
3712 region->unique_select (cnote);
3719 NoteDrag::motion (GdkEvent*, bool)
3721 MidiStreamView* streamview = region->midi_stream_view();
3725 event_x = _drags->current_pointer_x();
3726 event_y = _drags->current_pointer_y();
3728 _item->property_parent().get_value()->w2i(event_x, event_y);
3730 event_x = region->snap_to_pixel(event_x);
3732 double dx = event_x - last_x;
3733 double dy = event_y - last_y;
3738 // Snap to note rows
3740 if (abs (dy) < streamview->note_height()) {
3743 int8_t this_delta_note;
3745 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3747 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3749 drag_delta_note -= this_delta_note;
3750 dy = streamview->note_height() * this_delta_note;
3751 last_y = last_y + dy;
3755 region->move_selection (dx, dy);
3757 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3759 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3760 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3761 _editor->show_verbose_canvas_cursor_with (buf);
3766 NoteDrag::finished (GdkEvent* ev, bool moved)
3768 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3771 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3774 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3776 region->note_deselected (cnote);
3779 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3780 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3782 if (!extend && !add && region->selection_size() > 1) {
3783 region->unique_select(cnote);
3784 } else if (extend) {
3785 region->note_selected (cnote, true, true);
3787 /* it was added during button press */
3792 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3797 NoteDrag::aborted ()
3802 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3805 , _nothing_to_drag (false)
3807 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3810 _line = _atav->line ();
3814 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3816 Drag::start_grab (event, cursor);
3818 list<ControlPoint*> points;
3820 XMLNode* state = &_line->get_state ();
3822 if (_ranges.empty()) {
3824 uint32_t const N = _line->npoints ();
3825 for (uint32_t i = 0; i < N; ++i) {
3826 points.push_back (_line->nth (i));
3831 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3832 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3834 /* fade into and out of the region that we're dragging;
3835 64 samples length plucked out of thin air.
3837 nframes64_t const h = (j->start + j->end) / 2;
3838 nframes64_t a = j->start + 64;
3842 nframes64_t b = j->end - 64;
3847 the_list->add (j->start, the_list->eval (j->start));
3848 _line->add_always_in_view (j->start);
3849 the_list->add (a, the_list->eval (a));
3850 _line->add_always_in_view (a);
3851 the_list->add (b, the_list->eval (b));
3852 _line->add_always_in_view (b);
3853 the_list->add (j->end, the_list->eval (j->end));
3854 _line->add_always_in_view (j->end);
3857 uint32_t const N = _line->npoints ();
3858 for (uint32_t i = 0; i < N; ++i) {
3860 ControlPoint* p = _line->nth (i);
3862 list<AudioRange>::const_iterator j = _ranges.begin ();
3863 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3867 if (j != _ranges.end()) {
3868 points.push_back (p);
3873 if (points.empty()) {
3874 _nothing_to_drag = true;
3878 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3882 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3884 if (_nothing_to_drag) {
3888 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3890 /* we are ignoring x position for this drag, so we can just pass in anything */
3891 _line->drag_motion (0, f, true, false);
3895 AutomationRangeDrag::finished (GdkEvent* event, bool)
3897 if (_nothing_to_drag) {
3901 motion (event, false);
3903 _line->clear_always_in_view ();
3907 AutomationRangeDrag::aborted ()
3909 _line->clear_always_in_view ();