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/diskstream.h"
26 #include "ardour/session.h"
27 #include "ardour/dB.h"
28 #include "ardour/region_factory.h"
29 #include "ardour/midi_diskstream.h"
33 #include "audio_region_view.h"
34 #include "midi_region_view.h"
35 #include "ardour_ui.h"
36 #include "gui_thread.h"
37 #include "control_point.h"
39 #include "region_gain_line.h"
40 #include "editor_drag.h"
41 #include "audio_time_axis.h"
42 #include "midi_time_axis.h"
43 #include "canvas-note.h"
44 #include "selection.h"
45 #include "midi_selection.h"
46 #include "automation_time_axis.h"
49 using namespace ARDOUR;
52 using namespace Editing;
53 using namespace ArdourCanvas;
55 using Gtkmm2ext::Keyboard;
57 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
59 DragManager::DragManager (Editor* e)
62 , _current_pointer_frame (0)
67 DragManager::~DragManager ()
75 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
84 DragManager::break_drag ()
88 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
99 DragManager::add (Drag* d)
101 d->set_manager (this);
102 _drags.push_back (d);
106 DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
108 assert (_drags.empty ());
109 d->set_manager (this);
110 _drags.push_back (d);
115 DragManager::start_grab (GdkEvent* e)
117 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
119 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
120 (*i)->start_grab (e);
125 DragManager::end_grab (GdkEvent* e)
130 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
131 bool const t = (*i)->end_grab (e);
146 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
150 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
152 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
153 bool const t = (*i)->motion_handler (e, from_autoscroll);
164 DragManager::have_item (ArdourCanvas::Item* i) const
166 list<Drag*>::const_iterator j = _drags.begin ();
167 while (j != _drags.end() && (*j)->item () != i) {
171 return j != _drags.end ();
174 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
177 , _pointer_frame_offset (0)
178 , _move_threshold_passed (false)
180 , _last_pointer_frame (0)
186 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
192 cursor = _editor->which_grabber_cursor ();
195 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
199 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
202 cursor = _editor->which_grabber_cursor ();
205 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
207 if (Keyboard::is_button2_event (&event->button)) {
208 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
209 _y_constrained = true;
210 _x_constrained = false;
212 _y_constrained = false;
213 _x_constrained = true;
216 _x_constrained = false;
217 _y_constrained = false;
220 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
221 _grab_frame = adjusted_frame (_grab_frame, event);
222 _last_pointer_frame = _grab_frame;
223 _last_pointer_x = _grab_x;
224 _last_pointer_y = _grab_y;
226 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
230 if (_editor->session() && _editor->session()->transport_rolling()) {
233 _was_rolling = false;
236 switch (_editor->snap_type()) {
237 case SnapToRegionStart:
238 case SnapToRegionEnd:
239 case SnapToRegionSync:
240 case SnapToRegionBoundary:
241 _editor->build_region_boundary_cache ();
248 /** @param event GDK event, or 0.
249 * @return true if some movement occurred, otherwise false.
252 Drag::end_grab (GdkEvent* event)
254 _editor->stop_canvas_autoscroll ();
256 _item->ungrab (event ? event->button.time : 0);
258 finished (event, _move_threshold_passed);
260 _editor->hide_verbose_canvas_cursor();
262 return _move_threshold_passed;
266 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
270 if (f > _pointer_frame_offset) {
271 pos = f - _pointer_frame_offset;
275 _editor->snap_to_with_modifier (pos, event);
282 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
284 return adjusted_frame (_drags->current_pointer_frame (), event, snap);
288 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
290 /* check to see if we have moved in any way that matters since the last motion event */
291 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
292 (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
296 pair<nframes64_t, int> const threshold = move_threshold ();
298 bool const old_move_threshold_passed = _move_threshold_passed;
300 if (!from_autoscroll && !_move_threshold_passed) {
302 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
303 bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
305 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
308 if (active (_editor->mouse_mode) && _move_threshold_passed) {
310 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
311 if (!from_autoscroll) {
312 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
315 motion (event, _move_threshold_passed != old_move_threshold_passed);
317 _last_pointer_x = _drags->current_pointer_x ();
318 _last_pointer_y = _drags->current_pointer_y ();
319 _last_pointer_frame = adjusted_current_frame (event);
337 _editor->stop_canvas_autoscroll ();
338 _editor->hide_verbose_canvas_cursor ();
341 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
345 for (list<RegionView*>::const_iterator i = v.begin(); i != v.end(); ++i) {
346 _views.push_back (DraggingView (*i));
349 RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
353 RegionDrag::region_going_away (RegionView* v)
355 list<DraggingView>::iterator i = _views.begin ();
356 while (i != _views.end() && i->view != v) {
360 if (i != _views.end()) {
365 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
366 : RegionDrag (e, i, p, v),
377 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
379 Drag::start_grab (event);
381 _editor->show_verbose_time_cursor (_last_frame_position, 10);
384 RegionMotionDrag::TimeAxisViewSummary
385 RegionMotionDrag::get_time_axis_view_summary ()
387 int32_t children = 0;
388 TimeAxisViewSummary sum;
390 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
392 /* get a bitmask representing the visible tracks */
394 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
395 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
396 TimeAxisView::Children children_list;
398 /* zeroes are audio/MIDI tracks. ones are other types. */
400 if (!rtv->hidden()) {
402 if (!rtv->is_track()) {
403 /* not an audio nor MIDI track */
404 sum.tracks = sum.tracks |= (0x01 << rtv->order());
407 sum.height_list[rtv->order()] = (*i)->current_height();
410 if ((children_list = rtv->get_child_list()).size() > 0) {
411 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
412 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
413 sum.height_list[rtv->order() + children] = (*j)->current_height();
424 RegionMotionDrag::compute_y_delta (
425 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
426 int32_t last_pointer_layer, int32_t current_pointer_layer,
427 TimeAxisViewSummary const & tavs,
428 int32_t* pointer_order_span, int32_t* pointer_layer_span,
429 int32_t* canvas_pointer_order_span
433 *pointer_order_span = 0;
434 *pointer_layer_span = 0;
438 bool clamp_y_axis = false;
440 /* the change in track order between this callback and the last */
441 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
442 /* the change in layer between this callback and the last;
443 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
444 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
446 if (*pointer_order_span != 0) {
448 /* find the actual pointer span, in terms of the number of visible tracks;
449 to do this, we reduce |pointer_order_span| by the number of hidden tracks
452 *canvas_pointer_order_span = *pointer_order_span;
453 if (last_pointer_view->order() >= current_pointer_view->order()) {
454 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
455 if (tavs.height_list[y] == 0) {
456 *canvas_pointer_order_span--;
460 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
461 if (tavs.height_list[y] == 0) {
462 *canvas_pointer_order_span++;
467 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
469 RegionView* rv = i->view;
471 if (rv->region()->locked()) {
475 double ix1, ix2, iy1, iy2;
476 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
477 rv->get_canvas_frame()->i2w (ix1, iy1);
478 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
480 /* get the new trackview for this particular region */
481 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
483 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
485 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
486 as surely this is a per-region thing... */
488 clamp_y_axis = y_movement_disallowed (
489 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
497 } else if (_dest_trackview == current_pointer_view) {
499 if (current_pointer_layer == last_pointer_layer) {
500 /* No movement; clamp */
506 _dest_trackview = current_pointer_view;
507 _dest_layer = current_pointer_layer;
515 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
517 /* compute the amount of pointer motion in frames, and where
518 the region would be if we moved it by that much.
520 *pending_region_position = adjusted_current_frame (event);
522 nframes64_t sync_frame;
523 nframes64_t sync_offset;
526 sync_offset = _primary->region()->sync_offset (sync_dir);
528 /* we don't handle a sync point that lies before zero.
530 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
532 sync_frame = *pending_region_position + (sync_dir*sync_offset);
534 _editor->snap_to_with_modifier (sync_frame, event);
536 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
539 *pending_region_position = _last_frame_position;
542 if (*pending_region_position > max_frames - _primary->region()->length()) {
543 *pending_region_position = _last_frame_position;
548 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
550 /* now compute the canvas unit distance we need to move the regionview
551 to make it appear at the new location.
554 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
556 if (*pending_region_position <= _last_frame_position) {
558 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
560 RegionView* rv = i->view;
562 // If any regionview is at zero, we need to know so we can stop further leftward motion.
564 double ix1, ix2, iy1, iy2;
565 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
566 rv->get_canvas_frame()->i2w (ix1, iy1);
568 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
570 *pending_region_position = _last_frame_position;
577 _last_frame_position = *pending_region_position;
584 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
588 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
590 vector<int32_t>::iterator j;
592 /* *pointer* variables reflect things about the pointer; as we may be moving
593 multiple regions, much detail must be computed per-region */
595 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
596 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
597 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
598 is always 0 regardless of what the region's "real" layer is */
599 RouteTimeAxisView* current_pointer_view;
600 layer_t current_pointer_layer;
601 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
605 /* TimeAxisView that we were pointing at last time we entered this method */
606 TimeAxisView const * const last_pointer_view = _dest_trackview;
607 /* the order of the track that we were pointing at last time we entered this method */
608 int32_t const last_pointer_order = last_pointer_view->order ();
609 /* the layer that we were pointing at last time we entered this method */
610 layer_t const last_pointer_layer = _dest_layer;
612 int32_t pointer_order_span;
613 int32_t pointer_layer_span;
614 int32_t canvas_pointer_order_span;
616 bool const clamp_y_axis = compute_y_delta (
617 last_pointer_view, current_pointer_view,
618 last_pointer_layer, current_pointer_layer, tavs,
619 &pointer_order_span, &pointer_layer_span,
620 &canvas_pointer_order_span
623 nframes64_t pending_region_position;
624 double const x_delta = compute_x_delta (event, &pending_region_position);
626 /*************************************************************
628 ************************************************************/
630 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
631 /* haven't reached next snap point, and we're not switching
632 trackviews nor layers. nothing to do.
637 /*************************************************************
639 ************************************************************/
641 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
643 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
645 RegionView* rv = i->view;
647 if (rv->region()->locked()) {
651 /* here we are calculating the y distance from the
652 top of the first track view to the top of the region
653 area of the track view that we're working on */
655 /* this x value is just a dummy value so that we have something
660 /* distance from the top of this track view to the region area
661 of our track view is always 1 */
665 /* convert to world coordinates, ie distance from the top of
668 rv->get_canvas_frame()->i2w (ix1, iy1);
670 /* compensate for the ruler section and the vertical scrollbar position */
671 iy1 += _editor->get_trackview_group_vertical_offset ();
675 // hide any dependent views
677 rv->get_time_axis_view().hide_dependent_views (*rv);
680 reparent to a non scrolling group so that we can keep the
681 region selection above all time axis views.
682 reparenting means we have to move the rv as the two
683 parent groups have different coordinates.
686 rv->get_canvas_group()->property_y() = iy1 - 1;
687 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
689 rv->fake_set_opaque (true);
692 /* current view for this particular region */
693 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
694 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
696 if (pointer_order_span != 0 && !clamp_y_axis) {
698 /* INTER-TRACK MOVEMENT */
700 /* move through the height list to the track that the region is currently on */
701 vector<int32_t>::iterator j = tavs.height_list.begin ();
703 while (j != tavs.height_list.end () && x != rtv->order ()) {
709 int32_t temp_pointer_order_span = canvas_pointer_order_span;
711 if (j != tavs.height_list.end ()) {
713 /* Account for layers in the original and
714 destination tracks. If we're moving around in layers we assume
715 that only one track is involved, so it's ok to use *pointer*
718 StreamView* lv = last_pointer_view->view ();
721 /* move to the top of the last trackview */
722 if (lv->layer_display () == Stacked) {
723 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
726 StreamView* cv = current_pointer_view->view ();
729 /* move to the right layer on the current trackview */
730 if (cv->layer_display () == Stacked) {
731 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
734 /* And for being on a non-topmost layer on the new
737 while (temp_pointer_order_span > 0) {
738 /* we're moving up canvas-wise,
739 so we need to find the next track height
741 if (j != tavs.height_list.begin()) {
745 if (x != last_pointer_order) {
747 ++temp_pointer_order_span;
752 temp_pointer_order_span--;
755 while (temp_pointer_order_span < 0) {
759 if (x != last_pointer_order) {
761 --temp_pointer_order_span;
765 if (j != tavs.height_list.end()) {
769 temp_pointer_order_span++;
773 /* find out where we'll be when we move and set height accordingly */
775 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
776 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
777 rv->set_height (temp_rtv->view()->child_height());
779 /* if you un-comment the following, the region colours will follow
780 the track colours whilst dragging; personally
781 i think this can confuse things, but never mind.
784 //const GdkColor& col (temp_rtv->view->get_region_color());
785 //rv->set_color (const_cast<GdkColor&>(col));
789 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
791 /* INTER-LAYER MOVEMENT in the same track */
792 y_delta = rtv->view()->child_height () * pointer_layer_span;
797 _editor->mouse_brush_insert_region (rv, pending_region_position);
799 rv->move (x_delta, y_delta);
802 } /* foreach region */
804 _total_x_delta += x_delta;
807 _editor->cursor_group->raise_to_top();
810 if (x_delta != 0 && !_brushing) {
811 _editor->show_verbose_time_cursor (_last_frame_position, 10);
816 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
818 if (_copy && first_move) {
819 copy_regions (event);
822 RegionMotionDrag::motion (event, first_move);
826 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
828 vector<RegionView*> copies;
829 boost::shared_ptr<Diskstream> ds;
830 boost::shared_ptr<Playlist> from_playlist;
831 boost::shared_ptr<Playlist> to_playlist;
832 RegionSelection new_views;
833 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
834 PlaylistSet modified_playlists;
835 PlaylistSet frozen_playlists;
836 list <sigc::connection> modified_playlist_connections;
837 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
838 nframes64_t drag_delta;
839 bool changed_tracks, changed_position;
840 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
841 RouteTimeAxisView* source_tv;
842 vector<StatefulDiffCommand*> sdc;
844 if (!movement_occurred) {
850 /* all changes were made during motion event handlers */
853 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
854 copies.push_back (i->view);
861 /* reverse this here so that we have the correct logic to finalize
865 if (Config->get_edit_mode() == Lock) {
866 _x_constrained = !_x_constrained;
870 if (_x_constrained) {
871 _editor->begin_reversible_command (_("fixed time region copy"));
873 _editor->begin_reversible_command (_("region copy"));
876 if (_x_constrained) {
877 _editor->begin_reversible_command (_("fixed time region drag"));
879 _editor->begin_reversible_command (_("region drag"));
883 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
884 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
886 drag_delta = _primary->region()->position() - _last_frame_position;
888 _editor->update_canvas_now ();
890 /* make a list of where each region ended up */
891 final = find_time_axis_views_and_layers ();
893 cerr << "Iterate over " << _views.size() << " views\n";
895 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
897 RegionView* rv = i->view;
898 RouteTimeAxisView* dest_rtv = final[rv].first;
899 layer_t dest_layer = final[rv].second;
903 from_playlist.reset ();
904 to_playlist.reset ();
906 if (rv->region()->locked()) {
911 if (changed_position && !_x_constrained) {
912 where = rv->region()->position() - drag_delta;
914 where = rv->region()->position();
917 boost::shared_ptr<Region> new_region;
920 /* we already made a copy */
921 new_region = rv->region();
923 /* undo the previous hide_dependent_views so that xfades don't
924 disappear on copying regions
927 //rv->get_time_axis_view().reveal_dependent_views (*rv);
929 } else if (changed_tracks && dest_rtv->playlist()) {
930 new_region = RegionFactory::create (rv->region());
933 if (changed_tracks || _copy) {
935 to_playlist = dest_rtv->playlist();
942 _editor->latest_regionviews.clear ();
944 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
946 insert_result = modified_playlists.insert (to_playlist);
948 if (insert_result.second) {
949 to_playlist->clear_history ();
952 cerr << "To playlist " << to_playlist->name() << " region history contains "
953 << to_playlist->region_list().change().added.size() << " adds and "
954 << to_playlist->region_list().change().removed.size() << " removes\n";
956 cerr << "Adding new region " << new_region->id() << " based on "
957 << rv->region()->id() << endl;
959 to_playlist->add_region (new_region, where);
961 if (dest_rtv->view()->layer_display() == Stacked) {
962 new_region->set_layer (dest_layer);
963 new_region->set_pending_explicit_relayer (true);
968 if (!_editor->latest_regionviews.empty()) {
969 // XXX why just the first one ? we only expect one
970 // commented out in nick_m's canvas reworking. is that intended?
971 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
972 new_views.push_back (_editor->latest_regionviews.front());
976 rv->region()->clear_history ();
979 motion on the same track. plonk the previously reparented region
980 back to its original canvas group (its streamview).
981 No need to do anything for copies as they are fake regions which will be deleted.
984 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
985 rv->get_canvas_group()->property_y() = i->initial_y;
986 rv->get_time_axis_view().reveal_dependent_views (*rv);
988 /* just change the model */
990 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
992 if (dest_rtv->view()->layer_display() == Stacked) {
993 rv->region()->set_layer (dest_layer);
994 rv->region()->set_pending_explicit_relayer (true);
997 /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
999 frozen_insert_result = frozen_playlists.insert(playlist);
1001 if (frozen_insert_result.second) {
1005 cerr << "Moving region " << rv->region()->id() << endl;
1007 rv->region()->set_position (where, (void*) this);
1009 sdc.push_back (new StatefulDiffCommand (rv->region()));
1012 if (changed_tracks && !_copy) {
1014 /* get the playlist where this drag started. we can't use rv->region()->playlist()
1015 because we may have copied the region and it has not been attached to a playlist.
1018 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
1019 ds = source_tv->get_diskstream();
1020 from_playlist = ds->playlist();
1024 assert (from_playlist);
1026 /* moved to a different audio track, without copying */
1028 /* the region that used to be in the old playlist is not
1029 moved to the new one - we use a copy of it. as a result,
1030 any existing editor for the region should no longer be
1034 rv->hide_region_editor();
1035 rv->fake_set_opaque (false);
1037 /* remove the region from the old playlist */
1039 insert_result = modified_playlists.insert (from_playlist);
1041 if (insert_result.second) {
1042 from_playlist->clear_history ();
1045 cerr << "From playlist " << from_playlist->name() << " region history contains "
1046 << from_playlist->region_list().change().added.size() << " adds and "
1047 << from_playlist->region_list().change().removed.size() << " removes\n";
1049 cerr << "removing region " << rv->region() << endl;
1051 from_playlist->remove_region (rv->region());
1053 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1054 was selected in all of them, then removing it from a playlist will have removed all
1055 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1056 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1057 corresponding regionview, and the selection is now empty).
1059 this could have invalidated any and all iterators into the region selection.
1061 the heuristic we use here is: if the region selection is empty, break out of the loop
1062 here. if the region selection is not empty, then restart the loop because we know that
1063 we must have removed at least the region(view) we've just been working on as well as any
1064 that we processed on previous iterations.
1066 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1067 we can just iterate.
1070 if (_views.empty()) {
1072 sdc.push_back (new StatefulDiffCommand (to_playlist));
1073 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1076 if (from_playlist && (from_playlist != to_playlist)) {
1077 sdc.push_back (new StatefulDiffCommand (from_playlist));
1078 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1090 copies.push_back (rv);
1093 cerr << "Done with TV, top = " << to_playlist << " from = " << from_playlist << endl;
1096 sdc.push_back (new StatefulDiffCommand (to_playlist));
1097 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1100 if (from_playlist && (from_playlist != to_playlist)) {
1101 sdc.push_back (new StatefulDiffCommand (from_playlist));
1102 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1107 if we've created new regions either by copying or moving
1108 to a new track, we want to replace the old selection with the new ones
1111 if (new_views.size() > 0) {
1112 _editor->selection->set (new_views);
1115 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1120 for (vector<StatefulDiffCommand*>::iterator i = sdc.begin(); i != sdc.end(); ++i) {
1121 _editor->session()->add_command (*i);
1124 _editor->commit_reversible_command ();
1126 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1132 RegionMoveDrag::aborted ()
1136 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1143 RegionMotionDrag::aborted ();
1148 RegionMotionDrag::aborted ()
1150 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1151 RegionView* rv = i->view;
1152 TimeAxisView* tv = &(rv->get_time_axis_view ());
1153 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1155 rv->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1156 rv->get_canvas_group()->property_y() = 0;
1157 rv->get_time_axis_view().reveal_dependent_views (*rv);
1158 rv->fake_set_opaque (false);
1159 rv->move (-_total_x_delta, 0);
1160 rv->set_height (rtv->view()->child_height ());
1163 _editor->update_canvas_now ();
1168 RegionMotionDrag::x_move_allowed () const
1170 if (Config->get_edit_mode() == Lock) {
1171 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1172 return _x_constrained;
1175 return !_x_constrained;
1179 RegionMotionDrag::copy_regions (GdkEvent* event)
1181 /* duplicate the regionview(s) and region(s) */
1183 list<DraggingView> new_regionviews;
1185 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1187 RegionView* rv = i->view;
1188 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1189 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1191 const boost::shared_ptr<const Region> original = rv->region();
1192 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1193 region_copy->set_position (original->position(), this);
1197 boost::shared_ptr<AudioRegion> audioregion_copy
1198 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1200 nrv = new AudioRegionView (*arv, audioregion_copy);
1202 boost::shared_ptr<MidiRegion> midiregion_copy
1203 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1204 nrv = new MidiRegionView (*mrv, midiregion_copy);
1209 nrv->get_canvas_group()->show ();
1210 new_regionviews.push_back (DraggingView (nrv));
1212 /* swap _primary to the copy */
1214 if (rv == _primary) {
1218 /* ..and deselect the one we copied */
1220 rv->set_selected (false);
1223 if (new_regionviews.empty()) {
1227 /* reflect the fact that we are dragging the copies */
1229 _views = new_regionviews;
1231 swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0);
1234 sync the canvas to what we think is its current state
1235 without it, the canvas seems to
1236 "forget" to update properly after the upcoming reparent()
1237 ..only if the mouse is in rapid motion at the time of the grab.
1238 something to do with regionview creation taking so long?
1240 _editor->update_canvas_now();
1244 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1246 /* Which trackview is this ? */
1248 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1249 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1250 (*layer) = tvp.second;
1252 if (*tv && (*tv)->layer_display() == Overlaid) {
1256 /* The region motion is only processed if the pointer is over
1260 if (!(*tv) || !(*tv)->is_track()) {
1261 /* To make sure we hide the verbose canvas cursor when the mouse is
1262 not held over and audiotrack.
1264 _editor->hide_verbose_canvas_cursor ();
1271 /** @param new_order New track order.
1272 * @param old_order Old track order.
1273 * @param visible_y_low Lowest visible order.
1274 * @return true if y movement should not happen, otherwise false.
1277 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1279 if (new_order != old_order) {
1281 /* this isn't the pointer track */
1285 /* moving up the canvas */
1286 if ( (new_order - y_span) >= tavs.visible_y_low) {
1290 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1291 int32_t visible_tracks = 0;
1292 while (visible_tracks < y_span ) {
1294 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1295 /* passing through a hidden track */
1300 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1301 /* moving to a non-track; disallow */
1307 /* moving beyond the lowest visible track; disallow */
1311 } else if (y_span < 0) {
1313 /* moving down the canvas */
1314 if ((new_order - y_span) <= tavs.visible_y_high) {
1316 int32_t visible_tracks = 0;
1318 while (visible_tracks > y_span ) {
1321 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1322 /* passing through a hidden track */
1327 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1328 /* moving to a non-track; disallow */
1335 /* moving beyond the highest visible track; disallow */
1342 /* this is the pointer's track */
1344 if ((new_order - y_span) > tavs.visible_y_high) {
1345 /* we will overflow */
1347 } else if ((new_order - y_span) < tavs.visible_y_low) {
1348 /* we will overflow */
1357 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1358 : RegionMotionDrag (e, i, p, v, b),
1361 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1363 _dest_trackview = tv;
1364 if (tv->layer_display() == Overlaid) {
1367 _dest_layer = _primary->region()->layer ();
1371 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1372 if (rtv && rtv->is_track()) {
1373 speed = rtv->get_diskstream()->speed ();
1376 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1380 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1382 RegionMotionDrag::start_grab (event, c);
1384 _pointer_frame_offset = grab_frame() - _last_frame_position;
1387 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1388 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1390 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1391 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1393 _primary = v->view()->create_region_view (r, false, false);
1395 _primary->get_canvas_group()->show ();
1396 _primary->set_position (pos, 0);
1397 _views.push_back (DraggingView (_primary));
1399 _last_frame_position = pos;
1401 _item = _primary->get_canvas_group ();
1402 _dest_trackview = v;
1403 _dest_layer = _primary->region()->layer ();
1406 map<RegionView*, pair<RouteTimeAxisView*, int> >
1407 RegionMotionDrag::find_time_axis_views_and_layers ()
1409 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1411 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1413 double ix1, ix2, iy1, iy2;
1414 RegionView* rv = i->view;
1415 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1416 rv->get_canvas_frame()->i2w (ix1, iy1);
1417 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1419 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1420 tav[rv] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1428 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1430 _editor->update_canvas_now ();
1432 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1434 RouteTimeAxisView* dest_rtv = final[_primary].first;
1436 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1437 _primary->get_canvas_group()->property_y() = 0;
1439 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1441 _editor->begin_reversible_command (_("insert region"));
1442 playlist->clear_history ();
1443 playlist->add_region (_primary->region (), _last_frame_position);
1444 _editor->session()->add_command (new StatefulDiffCommand (playlist));
1445 _editor->commit_reversible_command ();
1453 RegionInsertDrag::aborted ()
1458 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1459 : RegionMoveDrag (e, i, p, v, false, false)
1464 struct RegionSelectionByPosition {
1465 bool operator() (RegionView*a, RegionView* b) {
1466 return a->region()->position () < b->region()->position();
1471 RegionSpliceDrag::motion (GdkEvent* event, bool)
1473 RouteTimeAxisView* tv;
1476 if (!check_possible (&tv, &layer)) {
1482 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1488 RegionSelection copy (_editor->selection->regions);
1490 RegionSelectionByPosition cmp;
1493 nframes64_t const pf = adjusted_current_frame (event);
1495 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1497 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1503 boost::shared_ptr<Playlist> playlist;
1505 if ((playlist = atv->playlist()) == 0) {
1509 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1514 if (pf < (*i)->region()->last_frame() + 1) {
1518 if (pf > (*i)->region()->first_frame()) {
1524 playlist->shuffle ((*i)->region(), dir);
1529 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1535 RegionSpliceDrag::aborted ()
1540 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1548 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1550 _dest_trackview = _view;
1552 Drag::start_grab (event);
1557 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1560 // TODO: create region-create-drag region view here
1563 // TODO: resize region-create-drag region view here
1567 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1569 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1575 if (!movement_occurred) {
1576 mtv->add_region (grab_frame ());
1578 motion (event, false);
1579 // TODO: create region-create-drag region here
1584 RegionCreateDrag::aborted ()
1589 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1597 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1600 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1602 Drag::start_grab (event);
1604 region = &cnote->region_view();
1606 double region_start = region->get_position_pixels();
1607 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1609 if (grab_x() <= middle_point) {
1610 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1613 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1617 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1619 if (event->motion.state & Keyboard::PrimaryModifier) {
1625 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1627 if (ms.size() > 1) {
1628 /* has to be relative, may make no sense otherwise */
1632 region->note_selected (cnote, true);
1634 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1635 MidiRegionSelection::iterator next;
1638 (*r)->begin_resizing (at_front);
1644 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1646 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1647 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1648 (*r)->update_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1653 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1655 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1656 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1657 (*r)->commit_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1662 NoteResizeDrag::aborted ()
1668 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1674 RegionGainDrag::finished (GdkEvent *, bool)
1680 RegionGainDrag::aborted ()
1685 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1686 : RegionDrag (e, i, p, v)
1687 , _have_transaction (false)
1693 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1696 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1697 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1699 if (tv && tv->is_track()) {
1700 speed = tv->get_diskstream()->speed();
1703 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1704 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1705 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1707 Drag::start_grab (event, _editor->trimmer_cursor);
1709 nframes64_t const pf = adjusted_current_frame (event);
1711 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1712 _operation = ContentsTrim;
1714 /* These will get overridden for a point trim.*/
1715 if (pf < (region_start + region_length/2)) {
1716 /* closer to start */
1717 _operation = StartTrim;
1718 } else if (pf > (region_end - region_length/2)) {
1720 _operation = EndTrim;
1724 switch (_operation) {
1726 _editor->show_verbose_time_cursor (region_start, 10);
1729 _editor->show_verbose_time_cursor (region_end, 10);
1732 _editor->show_verbose_time_cursor (pf, 10);
1738 TrimDrag::motion (GdkEvent* event, bool first_move)
1740 RegionView* rv = _primary;
1741 nframes64_t frame_delta = 0;
1743 bool left_direction;
1744 bool obey_snap = event ? !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) : false;
1746 /* snap modifier works differently here..
1747 its current state has to be passed to the
1748 various trim functions in order to work properly
1752 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1753 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1754 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1756 if (tv && tv->is_track()) {
1757 speed = tv->get_diskstream()->speed();
1760 nframes64_t const pf = adjusted_current_frame (event);
1762 if (last_pointer_frame() > pf) {
1763 left_direction = true;
1765 left_direction = false;
1772 switch (_operation) {
1774 trim_type = "Region start trim";
1777 trim_type = "Region end trim";
1780 trim_type = "Region content trim";
1784 _editor->begin_reversible_command (trim_type);
1785 _have_transaction = true;
1787 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1788 RegionView* rv = i->view;
1789 rv->fake_set_opaque(false);
1790 rv->region()->clear_history ();
1791 rv->region()->suspend_property_changes ();
1793 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
1796 arv->temporarily_hide_envelope ();
1799 boost::shared_ptr<Playlist> pl = rv->region()->playlist();
1800 insert_result = _editor->motion_frozen_playlists.insert (pl);
1802 if (insert_result.second) {
1808 if (left_direction) {
1809 frame_delta = (last_pointer_frame() - pf);
1811 frame_delta = (pf - last_pointer_frame());
1814 bool non_overlap_trim = false;
1816 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1817 non_overlap_trim = true;
1820 switch (_operation) {
1822 if ((left_direction == false) && (pf <= rv->region()->first_frame()/speed)) {
1826 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1827 _editor->single_start_trim (*i->view, frame_delta, left_direction, obey_snap, non_overlap_trim);
1833 if ((left_direction == true) && (pf > (nframes64_t) (rv->region()->last_frame()/speed))) {
1837 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1838 _editor->single_end_trim (*i->view, frame_delta, left_direction, obey_snap, non_overlap_trim);
1845 bool swap_direction = false;
1847 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1848 swap_direction = true;
1851 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1852 _editor->single_contents_trim (*i->view, frame_delta, left_direction, swap_direction, obey_snap);
1858 switch (_operation) {
1860 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1863 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1866 _editor->show_verbose_time_cursor (pf, 10);
1873 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1875 if (movement_occurred) {
1876 motion (event, false);
1878 if (!_editor->selection->selected (_primary)) {
1879 _editor->thaw_region_after_trim (*_primary);
1882 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1883 _editor->thaw_region_after_trim (*i->view);
1884 i->view->fake_set_opaque (true);
1885 if (_have_transaction) {
1886 _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
1890 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1894 _editor->motion_frozen_playlists.clear ();
1896 if (_have_transaction) {
1897 _editor->commit_reversible_command();
1901 /* no mouse movement */
1902 _editor->point_trim (event, adjusted_current_frame (event));
1907 TrimDrag::aborted ()
1909 /* Our motion method is changing model state, so use the Undo system
1910 to cancel. Perhaps not ideal, as this will leave an Undo point
1911 behind which may be slightly odd from the user's point of view.
1916 if (_have_transaction) {
1921 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1925 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1930 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1933 // create a dummy marker for visual representation of moving the copy.
1934 // The actual copying is not done before we reach the finish callback.
1936 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1937 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1938 *new MeterSection (_marker->meter()));
1940 _item = &new_marker->the_item ();
1941 _marker = new_marker;
1945 MetricSection& section (_marker->meter());
1947 if (!section.movable()) {
1953 Drag::start_grab (event, cursor);
1955 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1957 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1961 MeterMarkerDrag::motion (GdkEvent* event, bool)
1963 nframes64_t const pf = adjusted_current_frame (event);
1965 _marker->set_position (pf);
1967 _editor->show_verbose_time_cursor (pf, 10);
1971 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1973 if (!movement_occurred) {
1977 motion (event, false);
1981 TempoMap& map (_editor->session()->tempo_map());
1982 map.bbt_time (last_pointer_frame(), when);
1984 if (_copy == true) {
1985 _editor->begin_reversible_command (_("copy meter mark"));
1986 XMLNode &before = map.get_state();
1987 map.add_meter (_marker->meter(), when);
1988 XMLNode &after = map.get_state();
1989 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1990 _editor->commit_reversible_command ();
1992 // delete the dummy marker we used for visual representation of copying.
1993 // a new visual marker will show up automatically.
1996 _editor->begin_reversible_command (_("move meter mark"));
1997 XMLNode &before = map.get_state();
1998 map.move_meter (_marker->meter(), when);
1999 XMLNode &after = map.get_state();
2000 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
2001 _editor->commit_reversible_command ();
2006 MeterMarkerDrag::aborted ()
2008 _marker->set_position (_marker->meter().frame ());
2011 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
2015 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
2020 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2025 // create a dummy marker for visual representation of moving the copy.
2026 // The actual copying is not done before we reach the finish callback.
2028 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
2029 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
2030 *new TempoSection (_marker->tempo()));
2032 _item = &new_marker->the_item ();
2033 _marker = new_marker;
2037 MetricSection& section (_marker->tempo());
2039 if (!section.movable()) {
2044 Drag::start_grab (event, cursor);
2046 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
2047 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2051 TempoMarkerDrag::motion (GdkEvent* event, bool)
2053 nframes64_t const pf = adjusted_current_frame (event);
2054 _marker->set_position (pf);
2055 _editor->show_verbose_time_cursor (pf, 10);
2059 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2061 if (!movement_occurred) {
2065 motion (event, false);
2069 TempoMap& map (_editor->session()->tempo_map());
2070 map.bbt_time (last_pointer_frame(), when);
2072 if (_copy == true) {
2073 _editor->begin_reversible_command (_("copy tempo mark"));
2074 XMLNode &before = map.get_state();
2075 map.add_tempo (_marker->tempo(), when);
2076 XMLNode &after = map.get_state();
2077 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2078 _editor->commit_reversible_command ();
2080 // delete the dummy marker we used for visual representation of copying.
2081 // a new visual marker will show up automatically.
2084 _editor->begin_reversible_command (_("move tempo mark"));
2085 XMLNode &before = map.get_state();
2086 map.move_tempo (_marker->tempo(), when);
2087 XMLNode &after = map.get_state();
2088 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2089 _editor->commit_reversible_command ();
2094 TempoMarkerDrag::aborted ()
2096 _marker->set_position (_marker->tempo().frame());
2099 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2103 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2108 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2110 Drag::start_grab (event, c);
2114 nframes64_t where = _editor->event_frame (event, 0, 0);
2116 _editor->snap_to_with_modifier (where, event);
2117 _editor->playhead_cursor->set_position (where);
2121 if (_cursor == _editor->playhead_cursor) {
2122 _editor->_dragging_playhead = true;
2124 if (_editor->session() && _was_rolling && _stop) {
2125 _editor->session()->request_stop ();
2128 if (_editor->session() && _editor->session()->is_auditioning()) {
2129 _editor->session()->cancel_audition ();
2133 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2135 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2139 CursorDrag::motion (GdkEvent* event, bool)
2141 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2143 if (adjusted_frame == last_pointer_frame()) {
2147 _cursor->set_position (adjusted_frame);
2149 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2152 _editor->update_canvas_now ();
2154 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2158 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2160 _editor->_dragging_playhead = false;
2162 if (!movement_occurred && _stop) {
2166 motion (event, false);
2168 if (_item == &_editor->playhead_cursor->canvas_item) {
2169 if (_editor->session()) {
2170 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2171 _editor->_pending_locate_request = true;
2177 CursorDrag::aborted ()
2179 _editor->_dragging_playhead = false;
2180 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2183 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2184 : RegionDrag (e, i, p, v)
2190 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2192 Drag::start_grab (event, cursor);
2194 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2195 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2197 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2198 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2202 FadeInDrag::motion (GdkEvent* event, bool)
2204 nframes64_t fade_length;
2206 nframes64_t const pos = adjusted_current_frame (event);
2208 boost::shared_ptr<Region> region = _primary->region ();
2210 if (pos < (region->position() + 64)) {
2211 fade_length = 64; // this should be a minimum defined somewhere
2212 } else if (pos > region->last_frame()) {
2213 fade_length = region->length();
2215 fade_length = pos - region->position();
2218 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2220 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2226 tmp->reset_fade_in_shape_width (fade_length);
2229 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2233 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2235 if (!movement_occurred) {
2239 nframes64_t fade_length;
2241 nframes64_t const pos = adjusted_current_frame (event);
2243 boost::shared_ptr<Region> region = _primary->region ();
2245 if (pos < (region->position() + 64)) {
2246 fade_length = 64; // this should be a minimum defined somewhere
2247 } else if (pos > region->last_frame()) {
2248 fade_length = region->length();
2250 fade_length = pos - region->position();
2253 _editor->begin_reversible_command (_("change fade in length"));
2255 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2257 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2263 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2264 XMLNode &before = alist->get_state();
2266 tmp->audio_region()->set_fade_in_length (fade_length);
2267 tmp->audio_region()->set_fade_in_active (true);
2269 XMLNode &after = alist->get_state();
2270 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2273 _editor->commit_reversible_command ();
2277 FadeInDrag::aborted ()
2279 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2280 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2286 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2290 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2291 : RegionDrag (e, i, p, v)
2297 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2299 Drag::start_grab (event, cursor);
2301 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2302 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2304 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2305 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2309 FadeOutDrag::motion (GdkEvent* event, bool)
2311 nframes64_t fade_length;
2313 nframes64_t const pos = adjusted_current_frame (event);
2315 boost::shared_ptr<Region> region = _primary->region ();
2317 if (pos > (region->last_frame() - 64)) {
2318 fade_length = 64; // this should really be a minimum fade defined somewhere
2320 else if (pos < region->position()) {
2321 fade_length = region->length();
2324 fade_length = region->last_frame() - pos;
2327 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2329 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2335 tmp->reset_fade_out_shape_width (fade_length);
2338 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2342 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2344 if (!movement_occurred) {
2348 nframes64_t fade_length;
2350 nframes64_t const pos = adjusted_current_frame (event);
2352 boost::shared_ptr<Region> region = _primary->region ();
2354 if (pos > (region->last_frame() - 64)) {
2355 fade_length = 64; // this should really be a minimum fade defined somewhere
2357 else if (pos < region->position()) {
2358 fade_length = region->length();
2361 fade_length = region->last_frame() - pos;
2364 _editor->begin_reversible_command (_("change fade out length"));
2366 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2368 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2374 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2375 XMLNode &before = alist->get_state();
2377 tmp->audio_region()->set_fade_out_length (fade_length);
2378 tmp->audio_region()->set_fade_out_active (true);
2380 XMLNode &after = alist->get_state();
2381 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2384 _editor->commit_reversible_command ();
2388 FadeOutDrag::aborted ()
2390 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2391 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2397 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2401 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2404 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2407 _points.push_back (Gnome::Art::Point (0, 0));
2408 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2410 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2411 _line->property_width_pixels() = 1;
2412 _line->property_points () = _points;
2415 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2418 MarkerDrag::~MarkerDrag ()
2420 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2426 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2428 Drag::start_grab (event, cursor);
2432 Location *location = _editor->find_location_from_marker (_marker, is_start);
2433 _editor->_dragging_edit_point = true;
2435 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2437 update_item (location);
2439 // _drag_line->show();
2440 // _line->raise_to_top();
2443 _editor->show_verbose_time_cursor (location->start(), 10);
2445 _editor->show_verbose_time_cursor (location->end(), 10);
2448 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2451 case Selection::Toggle:
2452 _editor->selection->toggle (_marker);
2454 case Selection::Set:
2455 if (!_editor->selection->selected (_marker)) {
2456 _editor->selection->set (_marker);
2459 case Selection::Extend:
2461 Locations::LocationList ll;
2462 list<Marker*> to_add;
2464 _editor->selection->markers.range (s, e);
2465 s = min (_marker->position(), s);
2466 e = max (_marker->position(), e);
2469 if (e < max_frames) {
2472 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2473 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2474 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2477 to_add.push_back (lm->start);
2480 to_add.push_back (lm->end);
2484 if (!to_add.empty()) {
2485 _editor->selection->add (to_add);
2489 case Selection::Add:
2490 _editor->selection->add (_marker);
2494 /* Set up copies for us to manipulate during the drag */
2496 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2497 Location* l = _editor->find_location_from_marker (*i, is_start);
2498 _copied_locations.push_back (new Location (*l));
2503 MarkerDrag::motion (GdkEvent* event, bool)
2505 nframes64_t f_delta = 0;
2507 bool move_both = false;
2509 Location *real_location;
2510 Location *copy_location = 0;
2512 nframes64_t const newframe = adjusted_current_frame (event);
2514 nframes64_t next = newframe;
2516 if (newframe == last_pointer_frame()) {
2520 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2524 MarkerSelection::iterator i;
2525 list<Location*>::iterator x;
2527 /* find the marker we're dragging, and compute the delta */
2529 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2530 x != _copied_locations.end() && i != _editor->selection->markers.end();
2536 if (marker == _marker) {
2538 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2543 if (real_location->is_mark()) {
2544 f_delta = newframe - copy_location->start();
2548 switch (marker->type()) {
2550 case Marker::LoopStart:
2551 case Marker::PunchIn:
2552 f_delta = newframe - copy_location->start();
2556 case Marker::LoopEnd:
2557 case Marker::PunchOut:
2558 f_delta = newframe - copy_location->end();
2561 /* what kind of marker is this ? */
2569 if (i == _editor->selection->markers.end()) {
2570 /* hmm, impossible - we didn't find the dragged marker */
2574 /* now move them all */
2576 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2577 x != _copied_locations.end() && i != _editor->selection->markers.end();
2583 /* call this to find out if its the start or end */
2585 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2589 if (real_location->locked()) {
2593 if (copy_location->is_mark()) {
2597 copy_location->set_start (copy_location->start() + f_delta);
2601 nframes64_t new_start = copy_location->start() + f_delta;
2602 nframes64_t new_end = copy_location->end() + f_delta;
2604 if (is_start) { // start-of-range marker
2607 copy_location->set_start (new_start);
2608 copy_location->set_end (new_end);
2609 } else if (new_start < copy_location->end()) {
2610 copy_location->set_start (new_start);
2612 _editor->snap_to (next, 1, true);
2613 copy_location->set_end (next);
2614 copy_location->set_start (newframe);
2617 } else { // end marker
2620 copy_location->set_end (new_end);
2621 copy_location->set_start (new_start);
2622 } else if (new_end > copy_location->start()) {
2623 copy_location->set_end (new_end);
2624 } else if (newframe > 0) {
2625 _editor->snap_to (next, -1, true);
2626 copy_location->set_start (next);
2627 copy_location->set_end (newframe);
2632 update_item (copy_location);
2634 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2637 lm->set_position (copy_location->start(), copy_location->end());
2641 assert (!_copied_locations.empty());
2643 _editor->show_verbose_time_cursor (newframe, 10);
2646 _editor->update_canvas_now ();
2651 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2653 if (!movement_occurred) {
2655 /* just a click, do nothing but finish
2656 off the selection process
2659 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2662 case Selection::Set:
2663 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2664 _editor->selection->set (_marker);
2668 case Selection::Toggle:
2669 case Selection::Extend:
2670 case Selection::Add:
2677 _editor->_dragging_edit_point = false;
2679 _editor->begin_reversible_command ( _("move marker") );
2680 XMLNode &before = _editor->session()->locations()->get_state();
2682 MarkerSelection::iterator i;
2683 list<Location*>::iterator x;
2686 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2687 x != _copied_locations.end() && i != _editor->selection->markers.end();
2690 Location * location = _editor->find_location_from_marker (*i, is_start);
2694 if (location->locked()) {
2698 if (location->is_mark()) {
2699 location->set_start ((*x)->start());
2701 location->set ((*x)->start(), (*x)->end());
2706 XMLNode &after = _editor->session()->locations()->get_state();
2707 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2708 _editor->commit_reversible_command ();
2714 MarkerDrag::aborted ()
2720 MarkerDrag::update_item (Location* location)
2722 double const x1 = _editor->frame_to_pixel (location->start());
2724 _points.front().set_x(x1);
2725 _points.back().set_x(x1);
2726 _line->property_points() = _points;
2729 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2731 _cumulative_x_drag (0),
2732 _cumulative_y_drag (0)
2734 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2740 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2742 Drag::start_grab (event, _editor->fader_cursor);
2744 // start the grab at the center of the control point so
2745 // the point doesn't 'jump' to the mouse after the first drag
2746 _time_axis_view_grab_x = _point->get_x();
2747 _time_axis_view_grab_y = _point->get_y();
2749 float const fraction = 1 - (_point->get_y() / _point->line().height());
2751 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2753 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2754 event->button.x + 10, event->button.y + 10);
2756 _editor->show_verbose_canvas_cursor ();
2760 ControlPointDrag::motion (GdkEvent* event, bool)
2762 double dx = _drags->current_pointer_x() - last_pointer_x();
2763 double dy = _drags->current_pointer_y() - last_pointer_y();
2765 if (event->button.state & Keyboard::SecondaryModifier) {
2770 /* coordinate in TimeAxisView's space */
2771 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2772 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2774 // calculate zero crossing point. back off by .01 to stay on the
2775 // positive side of zero
2776 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2778 // make sure we hit zero when passing through
2779 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2783 if (_x_constrained) {
2784 cx = _time_axis_view_grab_x;
2786 if (_y_constrained) {
2787 cy = _time_axis_view_grab_y;
2790 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2791 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2795 cy = min ((double) _point->line().height(), cy);
2797 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2799 if (!_x_constrained) {
2800 _editor->snap_to_with_modifier (cx_frames, event);
2803 float const fraction = 1.0 - (cy / _point->line().height());
2805 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2807 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2809 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2813 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2815 if (!movement_occurred) {
2819 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2820 _editor->reset_point_selection ();
2824 motion (event, false);
2826 _point->line().end_drag ();
2830 ControlPointDrag::aborted ()
2832 _point->line().reset ();
2836 ControlPointDrag::active (Editing::MouseMode m)
2838 if (m == Editing::MouseGain) {
2839 /* always active in mouse gain */
2843 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2844 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2847 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2850 _cumulative_y_drag (0)
2855 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2857 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2860 _item = &_line->grab_item ();
2862 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2863 origin, and ditto for y.
2866 double cx = event->button.x;
2867 double cy = event->button.y;
2869 _line->parent_group().w2i (cx, cy);
2871 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2876 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2877 /* no adjacent points */
2881 Drag::start_grab (event, _editor->fader_cursor);
2883 /* store grab start in parent frame */
2885 _time_axis_view_grab_x = cx;
2886 _time_axis_view_grab_y = cy;
2888 double fraction = 1.0 - (cy / _line->height());
2890 _line->start_drag_line (before, after, fraction);
2892 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2893 event->button.x + 10, event->button.y + 10);
2895 _editor->show_verbose_canvas_cursor ();
2899 LineDrag::motion (GdkEvent* event, bool)
2901 double dy = _drags->current_pointer_y() - last_pointer_y();
2903 if (event->button.state & Keyboard::SecondaryModifier) {
2907 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2909 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2912 cy = min ((double) _line->height(), cy);
2914 double const fraction = 1.0 - (cy / _line->height());
2918 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2924 /* we are ignoring x position for this drag, so we can just pass in anything */
2925 _line->drag_motion (0, fraction, true, push);
2927 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2931 LineDrag::finished (GdkEvent* event, bool)
2933 motion (event, false);
2938 LineDrag::aborted ()
2944 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2946 Drag::start_grab (event);
2947 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2951 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2958 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2960 nframes64_t grab = grab_frame ();
2961 if (Config->get_rubberbanding_snaps_to_grid ()) {
2962 _editor->snap_to_with_modifier (grab, event);
2965 /* base start and end on initial click position */
2975 if (_drags->current_pointer_y() < grab_y()) {
2976 y1 = _drags->current_pointer_y();
2979 y2 = _drags->current_pointer_y();
2984 if (start != end || y1 != y2) {
2986 double x1 = _editor->frame_to_pixel (start);
2987 double x2 = _editor->frame_to_pixel (end);
2989 _editor->rubberband_rect->property_x1() = x1;
2990 _editor->rubberband_rect->property_y1() = y1;
2991 _editor->rubberband_rect->property_x2() = x2;
2992 _editor->rubberband_rect->property_y2() = y2;
2994 _editor->rubberband_rect->show();
2995 _editor->rubberband_rect->raise_to_top();
2997 _editor->show_verbose_time_cursor (pf, 10);
3002 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
3004 if (movement_occurred) {
3006 motion (event, false);
3009 if (_drags->current_pointer_y() < grab_y()) {
3010 y1 = _drags->current_pointer_y();
3013 y2 = _drags->current_pointer_y();
3018 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
3021 _editor->begin_reversible_command (_("rubberband selection"));
3023 if (grab_frame() < last_pointer_frame()) {
3024 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
3026 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
3030 _editor->commit_reversible_command ();
3034 if (!getenv("ARDOUR_SAE")) {
3035 _editor->selection->clear_tracks();
3037 _editor->selection->clear_regions();
3038 _editor->selection->clear_points ();
3039 _editor->selection->clear_lines ();
3042 _editor->rubberband_rect->hide();
3046 RubberbandSelectDrag::aborted ()
3048 _editor->rubberband_rect->hide ();
3052 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3054 Drag::start_grab (event);
3056 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3060 TimeFXDrag::motion (GdkEvent* event, bool)
3062 RegionView* rv = _primary;
3064 nframes64_t const pf = adjusted_current_frame (event);
3066 if (pf > rv->region()->position()) {
3067 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3070 _editor->show_verbose_time_cursor (pf, 10);
3074 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3076 _primary->get_time_axis_view().hide_timestretch ();
3078 if (!movement_occurred) {
3082 if (last_pointer_frame() < _primary->region()->position()) {
3083 /* backwards drag of the left edge - not usable */
3087 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3089 float percentage = (double) newlen / (double) _primary->region()->length();
3091 #ifndef USE_RUBBERBAND
3092 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3093 if (_primary->region()->data_type() == DataType::AUDIO) {
3094 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3098 _editor->begin_reversible_command (_("timestretch"));
3100 // XXX how do timeFX on multiple regions ?
3105 if (!_editor->time_stretch (rs, percentage) == 0) {
3106 error << _("An error occurred while executing time stretch operation") << endmsg;
3111 TimeFXDrag::aborted ()
3113 _primary->get_time_axis_view().hide_timestretch ();
3118 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3120 Drag::start_grab (event);
3124 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3126 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3130 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3132 if (movement_occurred && _editor->session()) {
3133 /* make sure we stop */
3134 _editor->session()->request_transport_speed (0.0);
3139 ScrubDrag::aborted ()
3144 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3148 , _original_pointer_time_axis (-1)
3149 , _last_pointer_time_axis (-1)
3155 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3157 nframes64_t start = 0;
3158 nframes64_t end = 0;
3160 if (_editor->session() == 0) {
3164 Gdk::Cursor* cursor = 0;
3166 switch (_operation) {
3167 case CreateSelection:
3168 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3173 cursor = _editor->selector_cursor;
3174 Drag::start_grab (event, cursor);
3177 case SelectionStartTrim:
3178 if (_editor->clicked_axisview) {
3179 _editor->clicked_axisview->order_selection_trims (_item, true);
3181 Drag::start_grab (event, _editor->trimmer_cursor);
3182 start = _editor->selection->time[_editor->clicked_selection].start;
3183 _pointer_frame_offset = grab_frame() - start;
3186 case SelectionEndTrim:
3187 if (_editor->clicked_axisview) {
3188 _editor->clicked_axisview->order_selection_trims (_item, false);
3190 Drag::start_grab (event, _editor->trimmer_cursor);
3191 end = _editor->selection->time[_editor->clicked_selection].end;
3192 _pointer_frame_offset = grab_frame() - end;
3196 start = _editor->selection->time[_editor->clicked_selection].start;
3197 Drag::start_grab (event, cursor);
3198 _pointer_frame_offset = grab_frame() - start;
3202 if (_operation == SelectionMove) {
3203 _editor->show_verbose_time_cursor (start, 10);
3205 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3208 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3212 SelectionDrag::motion (GdkEvent* event, bool first_move)
3214 nframes64_t start = 0;
3215 nframes64_t end = 0;
3218 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3219 if (pending_time_axis.first == 0) {
3223 nframes64_t const pending_position = adjusted_current_frame (event);
3225 /* only alter selection if things have changed */
3227 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3231 switch (_operation) {
3232 case CreateSelection:
3234 nframes64_t grab = grab_frame ();
3237 _editor->snap_to (grab);
3240 if (pending_position < grab_frame()) {
3241 start = pending_position;
3244 end = pending_position;
3248 /* first drag: Either add to the selection
3249 or create a new selection
3255 /* adding to the selection */
3256 _editor->selection->add (_editor->clicked_axisview);
3257 _editor->clicked_selection = _editor->selection->add (start, end);
3262 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3263 _editor->selection->set (_editor->clicked_axisview);
3266 _editor->clicked_selection = _editor->selection->set (start, end);
3270 /* select the track that we're in */
3271 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3272 _editor->selection->add (pending_time_axis.first);
3273 _added_time_axes.push_back (pending_time_axis.first);
3276 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3277 tracks that we selected in the first place.
3280 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3281 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3283 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3284 while (i != _added_time_axes.end()) {
3286 list<TimeAxisView*>::iterator tmp = i;
3289 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3290 _editor->selection->remove (*i);
3291 _added_time_axes.remove (*i);
3300 case SelectionStartTrim:
3302 start = _editor->selection->time[_editor->clicked_selection].start;
3303 end = _editor->selection->time[_editor->clicked_selection].end;
3305 if (pending_position > end) {
3308 start = pending_position;
3312 case SelectionEndTrim:
3314 start = _editor->selection->time[_editor->clicked_selection].start;
3315 end = _editor->selection->time[_editor->clicked_selection].end;
3317 if (pending_position < start) {
3320 end = pending_position;
3327 start = _editor->selection->time[_editor->clicked_selection].start;
3328 end = _editor->selection->time[_editor->clicked_selection].end;
3330 length = end - start;
3332 start = pending_position;
3333 _editor->snap_to (start);
3335 end = start + length;
3340 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3341 _editor->start_canvas_autoscroll (1, 0);
3345 _editor->selection->replace (_editor->clicked_selection, start, end);
3348 if (_operation == SelectionMove) {
3349 _editor->show_verbose_time_cursor(start, 10);
3351 _editor->show_verbose_time_cursor(pending_position, 10);
3356 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3358 Session* s = _editor->session();
3360 if (movement_occurred) {
3361 motion (event, false);
3362 /* XXX this is not object-oriented programming at all. ick */
3363 if (_editor->selection->time.consolidate()) {
3364 _editor->selection->TimeChanged ();
3367 /* XXX what if its a music time selection? */
3368 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3369 s->request_play_range (&_editor->selection->time, true);
3374 /* just a click, no pointer movement.*/
3376 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3377 _editor->selection->clear_time();
3380 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3381 _editor->selection->set (_editor->clicked_axisview);
3384 if (s && s->get_play_range () && s->transport_rolling()) {
3385 s->request_stop (false, false);
3390 _editor->stop_canvas_autoscroll ();
3394 SelectionDrag::aborted ()
3399 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3404 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3405 _drag_rect->hide ();
3407 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3408 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3412 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3414 if (_editor->session() == 0) {
3418 Gdk::Cursor* cursor = 0;
3420 if (!_editor->temp_location) {
3421 _editor->temp_location = new Location;
3424 switch (_operation) {
3425 case CreateRangeMarker:
3426 case CreateTransportMarker:
3427 case CreateCDMarker:
3429 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3434 cursor = _editor->selector_cursor;
3438 Drag::start_grab (event, cursor);
3440 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3444 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3446 nframes64_t start = 0;
3447 nframes64_t end = 0;
3448 ArdourCanvas::SimpleRect *crect;
3450 switch (_operation) {
3451 case CreateRangeMarker:
3452 crect = _editor->range_bar_drag_rect;
3454 case CreateTransportMarker:
3455 crect = _editor->transport_bar_drag_rect;
3457 case CreateCDMarker:
3458 crect = _editor->cd_marker_bar_drag_rect;
3461 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3466 nframes64_t const pf = adjusted_current_frame (event);
3468 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3469 nframes64_t grab = grab_frame ();
3470 _editor->snap_to (grab);
3472 if (pf < grab_frame()) {
3480 /* first drag: Either add to the selection
3481 or create a new selection.
3486 _editor->temp_location->set (start, end);
3490 update_item (_editor->temp_location);
3492 //_drag_rect->raise_to_top();
3497 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3498 _editor->start_canvas_autoscroll (1, 0);
3502 _editor->temp_location->set (start, end);
3504 double x1 = _editor->frame_to_pixel (start);
3505 double x2 = _editor->frame_to_pixel (end);
3506 crect->property_x1() = x1;
3507 crect->property_x2() = x2;
3509 update_item (_editor->temp_location);
3512 _editor->show_verbose_time_cursor (pf, 10);
3517 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3519 Location * newloc = 0;
3523 if (movement_occurred) {
3524 motion (event, false);
3527 switch (_operation) {
3528 case CreateRangeMarker:
3529 case CreateCDMarker:
3531 _editor->begin_reversible_command (_("new range marker"));
3532 XMLNode &before = _editor->session()->locations()->get_state();
3533 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3534 if (_operation == CreateCDMarker) {
3535 flags = Location::IsRangeMarker | Location::IsCDMarker;
3536 _editor->cd_marker_bar_drag_rect->hide();
3539 flags = Location::IsRangeMarker;
3540 _editor->range_bar_drag_rect->hide();
3542 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3543 _editor->session()->locations()->add (newloc, true);
3544 XMLNode &after = _editor->session()->locations()->get_state();
3545 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3546 _editor->commit_reversible_command ();
3550 case CreateTransportMarker:
3551 // popup menu to pick loop or punch
3552 _editor->new_transport_marker_context_menu (&event->button, _item);
3556 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3558 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3563 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3565 if (end == max_frames) {
3566 end = _editor->session()->current_end_frame ();
3569 if (start == max_frames) {
3570 start = _editor->session()->current_start_frame ();
3573 switch (_editor->mouse_mode) {
3575 /* find the two markers on either side and then make the selection from it */
3576 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3580 /* find the two markers on either side of the click and make the range out of it */
3581 _editor->selection->set (start, end);
3590 _editor->stop_canvas_autoscroll ();
3594 RangeMarkerBarDrag::aborted ()
3600 RangeMarkerBarDrag::update_item (Location* location)
3602 double const x1 = _editor->frame_to_pixel (location->start());
3603 double const x2 = _editor->frame_to_pixel (location->end());
3605 _drag_rect->property_x1() = x1;
3606 _drag_rect->property_x2() = x2;
3610 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3612 Drag::start_grab (event, _editor->zoom_cursor);
3613 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3617 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3622 nframes64_t const pf = adjusted_current_frame (event);
3624 nframes64_t grab = grab_frame ();
3625 _editor->snap_to_with_modifier (grab, event);
3627 /* base start and end on initial click position */
3639 _editor->zoom_rect->show();
3640 _editor->zoom_rect->raise_to_top();
3643 _editor->reposition_zoom_rect(start, end);
3645 _editor->show_verbose_time_cursor (pf, 10);
3650 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3652 if (movement_occurred) {
3653 motion (event, false);
3655 if (grab_frame() < last_pointer_frame()) {
3656 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3658 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3661 _editor->temporal_zoom_to_frame (false, grab_frame());
3663 temporal_zoom_step (false);
3664 center_screen (grab_frame());
3668 _editor->zoom_rect->hide();
3672 MouseZoomDrag::aborted ()
3674 _editor->zoom_rect->hide ();
3677 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3680 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3681 region = &cnote->region_view();
3685 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3687 Drag::start_grab (event);
3690 drag_delta_note = 0;
3695 event_x = _drags->current_pointer_x();
3696 event_y = _drags->current_pointer_y();
3698 _item->property_parent().get_value()->w2i(event_x, event_y);
3700 last_x = region->snap_to_pixel(event_x);
3703 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3705 if (!(was_selected = cnote->selected())) {
3707 /* tertiary-click means extend selection - we'll do that on button release,
3708 so don't add it here, because otherwise we make it hard to figure
3709 out the "extend-to" range.
3712 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3715 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3718 region->note_selected (cnote, true);
3720 region->unique_select (cnote);
3727 NoteDrag::motion (GdkEvent*, bool)
3729 MidiStreamView* streamview = region->midi_stream_view();
3733 event_x = _drags->current_pointer_x();
3734 event_y = _drags->current_pointer_y();
3736 _item->property_parent().get_value()->w2i(event_x, event_y);
3738 event_x = region->snap_to_pixel(event_x);
3740 double dx = event_x - last_x;
3741 double dy = event_y - last_y;
3746 // Snap to note rows
3748 if (abs (dy) < streamview->note_height()) {
3751 int8_t this_delta_note;
3753 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3755 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3757 drag_delta_note -= this_delta_note;
3758 dy = streamview->note_height() * this_delta_note;
3759 last_y = last_y + dy;
3763 region->move_selection (dx, dy);
3765 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3767 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3768 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3769 _editor->show_verbose_canvas_cursor_with (buf);
3774 NoteDrag::finished (GdkEvent* ev, bool moved)
3776 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3779 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3782 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3784 region->note_deselected (cnote);
3787 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3788 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3790 if (!extend && !add && region->selection_size() > 1) {
3791 region->unique_select(cnote);
3792 } else if (extend) {
3793 region->note_selected (cnote, true, true);
3795 /* it was added during button press */
3800 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3805 NoteDrag::aborted ()
3810 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3813 , _nothing_to_drag (false)
3815 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3818 _line = _atav->line ();
3822 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3824 Drag::start_grab (event, cursor);
3826 list<ControlPoint*> points;
3828 XMLNode* state = &_line->get_state ();
3830 if (_ranges.empty()) {
3832 uint32_t const N = _line->npoints ();
3833 for (uint32_t i = 0; i < N; ++i) {
3834 points.push_back (_line->nth (i));
3839 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3840 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3842 /* fade into and out of the region that we're dragging;
3843 64 samples length plucked out of thin air.
3845 nframes64_t const h = (j->start + j->end) / 2;
3846 nframes64_t a = j->start + 64;
3850 nframes64_t b = j->end - 64;
3855 the_list->add (j->start, the_list->eval (j->start));
3856 _line->add_always_in_view (j->start);
3857 the_list->add (a, the_list->eval (a));
3858 _line->add_always_in_view (a);
3859 the_list->add (b, the_list->eval (b));
3860 _line->add_always_in_view (b);
3861 the_list->add (j->end, the_list->eval (j->end));
3862 _line->add_always_in_view (j->end);
3865 uint32_t const N = _line->npoints ();
3866 for (uint32_t i = 0; i < N; ++i) {
3868 ControlPoint* p = _line->nth (i);
3870 list<AudioRange>::const_iterator j = _ranges.begin ();
3871 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3875 if (j != _ranges.end()) {
3876 points.push_back (p);
3881 if (points.empty()) {
3882 _nothing_to_drag = true;
3886 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3890 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3892 if (_nothing_to_drag) {
3896 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3898 /* we are ignoring x position for this drag, so we can just pass in anything */
3899 _line->drag_motion (0, f, true, false);
3903 AutomationRangeDrag::finished (GdkEvent* event, bool)
3905 if (_nothing_to_drag) {
3909 motion (event, false);
3911 _line->clear_always_in_view ();
3915 AutomationRangeDrag::aborted ()
3917 _line->clear_always_in_view ();
3921 DraggingView::DraggingView (RegionView* v)
3924 initial_y = v->get_canvas_group()->property_y ();