2 Copyright (C) 2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #define __STDC_LIMIT_MACROS 1
22 #include "pbd/memento_command.h"
23 #include "pbd/basename.h"
24 #include "pbd/stateful_diff_command.h"
25 #include "ardour/session.h"
26 #include "ardour/dB.h"
27 #include "ardour/region_factory.h"
31 #include "audio_region_view.h"
32 #include "midi_region_view.h"
33 #include "ardour_ui.h"
34 #include "gui_thread.h"
35 #include "control_point.h"
37 #include "region_gain_line.h"
38 #include "editor_drag.h"
39 #include "audio_time_axis.h"
40 #include "midi_time_axis.h"
41 #include "canvas-note.h"
42 #include "selection.h"
43 #include "midi_selection.h"
44 #include "automation_time_axis.h"
47 using namespace ARDOUR;
50 using namespace Editing;
51 using namespace ArdourCanvas;
53 using Gtkmm2ext::Keyboard;
55 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
57 DragManager::DragManager (Editor* e)
60 , _current_pointer_frame (0)
65 DragManager::~DragManager ()
70 /** Call abort for each active drag */
76 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
87 DragManager::add (Drag* d)
89 d->set_manager (this);
94 DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
96 assert (_drags.empty ());
97 d->set_manager (this);
103 DragManager::start_grab (GdkEvent* e)
105 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
107 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
108 (*i)->start_grab (e);
112 /** Call end_grab for each active drag.
113 * @return true if any drag reported movement having occurred.
116 DragManager::end_grab (GdkEvent* e)
121 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
122 bool const t = (*i)->end_grab (e);
137 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
141 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
143 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
144 bool const t = (*i)->motion_handler (e, from_autoscroll);
155 DragManager::have_item (ArdourCanvas::Item* i) const
157 list<Drag*>::const_iterator j = _drags.begin ();
158 while (j != _drags.end() && (*j)->item () != i) {
162 return j != _drags.end ();
165 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
168 , _pointer_frame_offset (0)
169 , _move_threshold_passed (false)
171 , _last_pointer_frame (0)
177 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
183 cursor = _editor->which_grabber_cursor ();
186 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
190 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
193 cursor = _editor->which_grabber_cursor ();
196 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
198 if (Keyboard::is_button2_event (&event->button)) {
199 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
200 _y_constrained = true;
201 _x_constrained = false;
203 _y_constrained = false;
204 _x_constrained = true;
207 _x_constrained = false;
208 _y_constrained = false;
211 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
212 _grab_frame = adjusted_frame (_grab_frame, event);
213 _last_pointer_frame = _grab_frame;
214 _last_pointer_x = _grab_x;
215 _last_pointer_y = _grab_y;
217 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
221 if (_editor->session() && _editor->session()->transport_rolling()) {
224 _was_rolling = false;
227 switch (_editor->snap_type()) {
228 case SnapToRegionStart:
229 case SnapToRegionEnd:
230 case SnapToRegionSync:
231 case SnapToRegionBoundary:
232 _editor->build_region_boundary_cache ();
239 /** Call to end a drag `successfully'. Ungrabs item and calls
240 * subclass' finished() method.
242 * @param event GDK event, or 0.
243 * @return true if some movement occurred, otherwise false.
246 Drag::end_grab (GdkEvent* event)
248 _editor->stop_canvas_autoscroll ();
250 _item->ungrab (event ? event->button.time : 0);
252 finished (event, _move_threshold_passed);
254 _editor->hide_verbose_canvas_cursor();
256 return _move_threshold_passed;
260 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
264 if (f > _pointer_frame_offset) {
265 pos = f - _pointer_frame_offset;
269 _editor->snap_to_with_modifier (pos, event);
276 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
278 return adjusted_frame (_drags->current_pointer_frame (), event, snap);
282 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
284 /* check to see if we have moved in any way that matters since the last motion event */
285 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
286 (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
290 pair<nframes64_t, int> const threshold = move_threshold ();
292 bool const old_move_threshold_passed = _move_threshold_passed;
294 if (!from_autoscroll && !_move_threshold_passed) {
296 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
297 bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
299 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
302 if (active (_editor->mouse_mode) && _move_threshold_passed) {
304 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
305 if (!from_autoscroll) {
306 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
309 motion (event, _move_threshold_passed != old_move_threshold_passed);
311 _last_pointer_x = _drags->current_pointer_x ();
312 _last_pointer_y = _drags->current_pointer_y ();
313 _last_pointer_frame = adjusted_current_frame (event);
322 /** Call to abort a drag. Ungrabs item and calls subclass's aborted () */
332 _editor->stop_canvas_autoscroll ();
333 _editor->hide_verbose_canvas_cursor ();
336 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
340 for (list<RegionView*>::const_iterator i = v.begin(); i != v.end(); ++i) {
341 _views.push_back (DraggingView (*i));
344 RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
348 RegionDrag::region_going_away (RegionView* v)
350 list<DraggingView>::iterator i = _views.begin ();
351 while (i != _views.end() && i->view != v) {
355 if (i != _views.end()) {
360 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
361 : RegionDrag (e, i, p, v),
372 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
374 Drag::start_grab (event);
376 _editor->show_verbose_time_cursor (_last_frame_position, 10);
379 RegionMotionDrag::TimeAxisViewSummary
380 RegionMotionDrag::get_time_axis_view_summary ()
382 int32_t children = 0;
383 TimeAxisViewSummary sum;
385 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
387 /* get a bitmask representing the visible tracks */
389 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
390 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
391 TimeAxisView::Children children_list;
393 /* zeroes are audio/MIDI tracks. ones are other types. */
395 if (!rtv->hidden()) {
397 if (!rtv->is_track()) {
398 /* not an audio nor MIDI track */
399 sum.tracks = sum.tracks |= (0x01 << rtv->order());
402 sum.height_list[rtv->order()] = (*i)->current_height();
405 if ((children_list = rtv->get_child_list()).size() > 0) {
406 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
407 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
408 sum.height_list[rtv->order() + children] = (*j)->current_height();
419 RegionMotionDrag::compute_y_delta (
420 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
421 int32_t last_pointer_layer, int32_t current_pointer_layer,
422 TimeAxisViewSummary const & tavs,
423 int32_t* pointer_order_span, int32_t* pointer_layer_span,
424 int32_t* canvas_pointer_order_span
428 *pointer_order_span = 0;
429 *pointer_layer_span = 0;
433 bool clamp_y_axis = false;
435 /* the change in track order between this callback and the last */
436 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
437 /* the change in layer between this callback and the last;
438 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
439 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
441 if (*pointer_order_span != 0) {
443 /* find the actual pointer span, in terms of the number of visible tracks;
444 to do this, we reduce |pointer_order_span| by the number of hidden tracks
447 *canvas_pointer_order_span = *pointer_order_span;
448 if (last_pointer_view->order() >= current_pointer_view->order()) {
449 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
450 if (tavs.height_list[y] == 0) {
451 *canvas_pointer_order_span--;
455 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
456 if (tavs.height_list[y] == 0) {
457 *canvas_pointer_order_span++;
462 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
464 RegionView* rv = i->view;
466 if (rv->region()->locked()) {
470 double ix1, ix2, iy1, iy2;
471 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
472 rv->get_canvas_frame()->i2w (ix1, iy1);
473 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
475 /* get the new trackview for this particular region */
476 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
478 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
480 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
481 as surely this is a per-region thing... */
483 clamp_y_axis = y_movement_disallowed (
484 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
492 } else if (_dest_trackview == current_pointer_view) {
494 if (current_pointer_layer == last_pointer_layer) {
495 /* No movement; clamp */
501 _dest_trackview = current_pointer_view;
502 _dest_layer = current_pointer_layer;
510 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
512 /* compute the amount of pointer motion in frames, and where
513 the region would be if we moved it by that much.
515 *pending_region_position = adjusted_current_frame (event);
517 nframes64_t sync_frame;
518 nframes64_t sync_offset;
521 sync_offset = _primary->region()->sync_offset (sync_dir);
523 /* we don't handle a sync point that lies before zero.
525 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
527 sync_frame = *pending_region_position + (sync_dir*sync_offset);
529 _editor->snap_to_with_modifier (sync_frame, event);
531 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
534 *pending_region_position = _last_frame_position;
537 if (*pending_region_position > max_frames - _primary->region()->length()) {
538 *pending_region_position = _last_frame_position;
543 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
545 /* now compute the canvas unit distance we need to move the regionview
546 to make it appear at the new location.
549 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
551 if (*pending_region_position <= _last_frame_position) {
553 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
555 RegionView* rv = i->view;
557 // If any regionview is at zero, we need to know so we can stop further leftward motion.
559 double ix1, ix2, iy1, iy2;
560 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
561 rv->get_canvas_frame()->i2w (ix1, iy1);
563 if (-x_delta > ix1 + _editor->horizontal_position()) {
565 *pending_region_position = _last_frame_position;
572 _last_frame_position = *pending_region_position;
579 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
583 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
585 vector<int32_t>::iterator j;
587 /* *pointer* variables reflect things about the pointer; as we may be moving
588 multiple regions, much detail must be computed per-region */
590 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
591 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
592 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
593 is always 0 regardless of what the region's "real" layer is */
594 RouteTimeAxisView* current_pointer_view;
595 layer_t current_pointer_layer;
596 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
600 /* TimeAxisView that we were pointing at last time we entered this method */
601 TimeAxisView const * const last_pointer_view = _dest_trackview;
602 /* the order of the track that we were pointing at last time we entered this method */
603 int32_t const last_pointer_order = last_pointer_view->order ();
604 /* the layer that we were pointing at last time we entered this method */
605 layer_t const last_pointer_layer = _dest_layer;
607 int32_t pointer_order_span;
608 int32_t pointer_layer_span;
609 int32_t canvas_pointer_order_span;
611 bool const clamp_y_axis = compute_y_delta (
612 last_pointer_view, current_pointer_view,
613 last_pointer_layer, current_pointer_layer, tavs,
614 &pointer_order_span, &pointer_layer_span,
615 &canvas_pointer_order_span
618 nframes64_t pending_region_position;
619 double const x_delta = compute_x_delta (event, &pending_region_position);
621 /*************************************************************
623 ************************************************************/
625 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
626 /* haven't reached next snap point, and we're not switching
627 trackviews nor layers. nothing to do.
632 /*************************************************************
634 ************************************************************/
636 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
638 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
640 RegionView* rv = i->view;
642 if (rv->region()->locked()) {
646 /* here we are calculating the y distance from the
647 top of the first track view to the top of the region
648 area of the track view that we're working on */
650 /* this x value is just a dummy value so that we have something
655 /* distance from the top of this track view to the region area
656 of our track view is always 1 */
660 /* convert to world coordinates, ie distance from the top of
663 rv->get_canvas_frame()->i2w (ix1, iy1);
665 /* compensate for the ruler section and the vertical scrollbar position */
666 iy1 += _editor->get_trackview_group_vertical_offset ();
670 // hide any dependent views
672 rv->get_time_axis_view().hide_dependent_views (*rv);
675 reparent to a non scrolling group so that we can keep the
676 region selection above all time axis views.
677 reparenting means we have to move the rv as the two
678 parent groups have different coordinates.
681 rv->get_canvas_group()->property_y() = iy1 - 1;
682 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
684 rv->fake_set_opaque (true);
687 /* current view for this particular region */
688 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
689 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
691 if (pointer_order_span != 0 && !clamp_y_axis) {
693 /* INTER-TRACK MOVEMENT */
695 /* move through the height list to the track that the region is currently on */
696 vector<int32_t>::iterator j = tavs.height_list.begin ();
698 while (j != tavs.height_list.end () && x != rtv->order ()) {
704 int32_t temp_pointer_order_span = canvas_pointer_order_span;
706 if (j != tavs.height_list.end ()) {
708 /* Account for layers in the original and
709 destination tracks. If we're moving around in layers we assume
710 that only one track is involved, so it's ok to use *pointer*
713 StreamView* lv = last_pointer_view->view ();
716 /* move to the top of the last trackview */
717 if (lv->layer_display () == Stacked) {
718 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
721 StreamView* cv = current_pointer_view->view ();
724 /* move to the right layer on the current trackview */
725 if (cv->layer_display () == Stacked) {
726 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
729 /* And for being on a non-topmost layer on the new
732 while (temp_pointer_order_span > 0) {
733 /* we're moving up canvas-wise,
734 so we need to find the next track height
736 if (j != tavs.height_list.begin()) {
740 if (x != last_pointer_order) {
742 ++temp_pointer_order_span;
747 temp_pointer_order_span--;
750 while (temp_pointer_order_span < 0) {
754 if (x != last_pointer_order) {
756 --temp_pointer_order_span;
760 if (j != tavs.height_list.end()) {
764 temp_pointer_order_span++;
768 /* find out where we'll be when we move and set height accordingly */
770 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
771 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
772 rv->set_height (temp_rtv->view()->child_height());
774 /* if you un-comment the following, the region colours will follow
775 the track colours whilst dragging; personally
776 i think this can confuse things, but never mind.
779 //const GdkColor& col (temp_rtv->view->get_region_color());
780 //rv->set_color (const_cast<GdkColor&>(col));
784 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
786 /* INTER-LAYER MOVEMENT in the same track */
787 y_delta = rtv->view()->child_height () * pointer_layer_span;
792 _editor->mouse_brush_insert_region (rv, pending_region_position);
794 rv->move (x_delta, y_delta);
797 } /* foreach region */
799 _total_x_delta += x_delta;
802 _editor->cursor_group->raise_to_top();
805 if (x_delta != 0 && !_brushing) {
806 _editor->show_verbose_time_cursor (_last_frame_position, 10);
811 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
813 if (_copy && first_move) {
814 copy_regions (event);
817 RegionMotionDrag::motion (event, first_move);
821 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
823 vector<RegionView*> copies;
824 boost::shared_ptr<Track> tr;
825 boost::shared_ptr<Playlist> from_playlist;
826 boost::shared_ptr<Playlist> to_playlist;
827 RegionSelection new_views;
828 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
829 PlaylistSet modified_playlists;
830 PlaylistSet frozen_playlists;
831 list <sigc::connection> modified_playlist_connections;
832 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
833 nframes64_t drag_delta;
834 bool changed_tracks, changed_position;
835 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
836 RouteTimeAxisView* source_tv;
837 vector<StatefulDiffCommand*> sdc;
839 if (!movement_occurred) {
845 /* all changes were made during motion event handlers */
848 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
849 copies.push_back (i->view);
856 /* reverse this here so that we have the correct logic to finalize
860 if (Config->get_edit_mode() == Lock) {
861 _x_constrained = !_x_constrained;
865 if (_x_constrained) {
866 _editor->begin_reversible_command (_("fixed time region copy"));
868 _editor->begin_reversible_command (_("region copy"));
871 if (_x_constrained) {
872 _editor->begin_reversible_command (_("fixed time region drag"));
874 _editor->begin_reversible_command (_("region drag"));
878 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
879 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
881 drag_delta = _primary->region()->position() - _last_frame_position;
883 _editor->update_canvas_now ();
885 /* make a list of where each region ended up */
886 final = find_time_axis_views_and_layers ();
888 cerr << "Iterate over " << _views.size() << " views\n";
890 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
892 RegionView* rv = i->view;
893 RouteTimeAxisView* dest_rtv = final[rv].first;
894 layer_t dest_layer = final[rv].second;
898 from_playlist.reset ();
899 to_playlist.reset ();
901 if (rv->region()->locked()) {
906 if (changed_position && !_x_constrained) {
907 where = rv->region()->position() - drag_delta;
909 where = rv->region()->position();
912 boost::shared_ptr<Region> new_region;
915 /* we already made a copy */
916 new_region = rv->region();
918 /* undo the previous hide_dependent_views so that xfades don't
919 disappear on copying regions
922 //rv->get_time_axis_view().reveal_dependent_views (*rv);
924 } else if (changed_tracks && dest_rtv->playlist()) {
925 new_region = RegionFactory::create (rv->region());
928 if (changed_tracks || _copy) {
930 to_playlist = dest_rtv->playlist();
937 _editor->latest_regionviews.clear ();
939 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
941 insert_result = modified_playlists.insert (to_playlist);
943 if (insert_result.second) {
944 to_playlist->clear_history ();
947 cerr << "To playlist " << to_playlist->name() << " region history contains "
948 << to_playlist->region_list().change().added.size() << " adds and "
949 << to_playlist->region_list().change().removed.size() << " removes\n";
951 cerr << "Adding new region " << new_region->id() << " based on "
952 << rv->region()->id() << endl;
954 to_playlist->add_region (new_region, where);
956 if (dest_rtv->view()->layer_display() == Stacked) {
957 new_region->set_layer (dest_layer);
958 new_region->set_pending_explicit_relayer (true);
963 if (!_editor->latest_regionviews.empty()) {
964 // XXX why just the first one ? we only expect one
965 // commented out in nick_m's canvas reworking. is that intended?
966 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
967 new_views.push_back (_editor->latest_regionviews.front());
971 rv->region()->clear_history ();
974 motion on the same track. plonk the previously reparented region
975 back to its original canvas group (its streamview).
976 No need to do anything for copies as they are fake regions which will be deleted.
979 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
980 rv->get_canvas_group()->property_y() = i->initial_y;
981 rv->get_time_axis_view().reveal_dependent_views (*rv);
983 /* just change the model */
985 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
987 if (dest_rtv->view()->layer_display() == Stacked) {
988 rv->region()->set_layer (dest_layer);
989 rv->region()->set_pending_explicit_relayer (true);
992 /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
994 frozen_insert_result = frozen_playlists.insert(playlist);
996 if (frozen_insert_result.second) {
1000 cerr << "Moving region " << rv->region()->id() << endl;
1002 rv->region()->set_position (where, (void*) this);
1004 sdc.push_back (new StatefulDiffCommand (rv->region()));
1007 if (changed_tracks && !_copy) {
1009 /* get the playlist where this drag started. we can't use rv->region()->playlist()
1010 because we may have copied the region and it has not been attached to a playlist.
1013 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
1014 tr = source_tv->track();
1015 from_playlist = tr->playlist();
1019 assert (from_playlist);
1021 /* moved to a different audio track, without copying */
1023 /* the region that used to be in the old playlist is not
1024 moved to the new one - we use a copy of it. as a result,
1025 any existing editor for the region should no longer be
1029 rv->hide_region_editor();
1030 rv->fake_set_opaque (false);
1032 /* remove the region from the old playlist */
1034 insert_result = modified_playlists.insert (from_playlist);
1036 if (insert_result.second) {
1037 from_playlist->clear_history ();
1040 cerr << "From playlist " << from_playlist->name() << " region history contains "
1041 << from_playlist->region_list().change().added.size() << " adds and "
1042 << from_playlist->region_list().change().removed.size() << " removes\n";
1044 cerr << "removing region " << rv->region() << endl;
1046 from_playlist->remove_region (rv->region());
1048 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1049 was selected in all of them, then removing it from a playlist will have removed all
1050 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1051 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1052 corresponding regionview, and the selection is now empty).
1054 this could have invalidated any and all iterators into the region selection.
1056 the heuristic we use here is: if the region selection is empty, break out of the loop
1057 here. if the region selection is not empty, then restart the loop because we know that
1058 we must have removed at least the region(view) we've just been working on as well as any
1059 that we processed on previous iterations.
1061 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1062 we can just iterate.
1065 if (_views.empty()) {
1067 sdc.push_back (new StatefulDiffCommand (to_playlist));
1068 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1071 if (from_playlist && (from_playlist != to_playlist)) {
1072 sdc.push_back (new StatefulDiffCommand (from_playlist));
1073 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1085 copies.push_back (rv);
1088 cerr << "Done with TV, top = " << to_playlist << " from = " << from_playlist << endl;
1091 sdc.push_back (new StatefulDiffCommand (to_playlist));
1092 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1095 if (from_playlist && (from_playlist != to_playlist)) {
1096 sdc.push_back (new StatefulDiffCommand (from_playlist));
1097 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1102 if we've created new regions either by copying or moving
1103 to a new track, we want to replace the old selection with the new ones
1106 if (new_views.size() > 0) {
1107 _editor->selection->set (new_views);
1110 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1115 for (vector<StatefulDiffCommand*>::iterator i = sdc.begin(); i != sdc.end(); ++i) {
1116 _editor->session()->add_command (*i);
1119 _editor->commit_reversible_command ();
1121 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1127 RegionMoveDrag::aborted ()
1131 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1138 RegionMotionDrag::aborted ();
1143 RegionMotionDrag::aborted ()
1145 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1146 RegionView* rv = i->view;
1147 TimeAxisView* tv = &(rv->get_time_axis_view ());
1148 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1150 rv->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1151 rv->get_canvas_group()->property_y() = 0;
1152 rv->get_time_axis_view().reveal_dependent_views (*rv);
1153 rv->fake_set_opaque (false);
1154 rv->move (-_total_x_delta, 0);
1155 rv->set_height (rtv->view()->child_height ());
1158 _editor->update_canvas_now ();
1163 RegionMotionDrag::x_move_allowed () const
1165 if (Config->get_edit_mode() == Lock) {
1166 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1167 return _x_constrained;
1170 return !_x_constrained;
1174 RegionMotionDrag::copy_regions (GdkEvent* event)
1176 /* duplicate the regionview(s) and region(s) */
1178 list<DraggingView> new_regionviews;
1180 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1182 RegionView* rv = i->view;
1183 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1184 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1186 const boost::shared_ptr<const Region> original = rv->region();
1187 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1188 region_copy->set_position (original->position(), this);
1192 boost::shared_ptr<AudioRegion> audioregion_copy
1193 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1195 nrv = new AudioRegionView (*arv, audioregion_copy);
1197 boost::shared_ptr<MidiRegion> midiregion_copy
1198 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1199 nrv = new MidiRegionView (*mrv, midiregion_copy);
1204 nrv->get_canvas_group()->show ();
1205 new_regionviews.push_back (DraggingView (nrv));
1207 /* swap _primary to the copy */
1209 if (rv == _primary) {
1213 /* ..and deselect the one we copied */
1215 rv->set_selected (false);
1218 if (new_regionviews.empty()) {
1222 /* reflect the fact that we are dragging the copies */
1224 _views = new_regionviews;
1226 swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0);
1229 sync the canvas to what we think is its current state
1230 without it, the canvas seems to
1231 "forget" to update properly after the upcoming reparent()
1232 ..only if the mouse is in rapid motion at the time of the grab.
1233 something to do with regionview creation taking so long?
1235 _editor->update_canvas_now();
1239 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1241 /* Which trackview is this ? */
1243 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1244 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1245 (*layer) = tvp.second;
1247 if (*tv && (*tv)->layer_display() == Overlaid) {
1251 /* The region motion is only processed if the pointer is over
1255 if (!(*tv) || !(*tv)->is_track()) {
1256 /* To make sure we hide the verbose canvas cursor when the mouse is
1257 not held over and audiotrack.
1259 _editor->hide_verbose_canvas_cursor ();
1266 /** @param new_order New track order.
1267 * @param old_order Old track order.
1268 * @param visible_y_low Lowest visible order.
1269 * @return true if y movement should not happen, otherwise false.
1272 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1274 if (new_order != old_order) {
1276 /* this isn't the pointer track */
1280 /* moving up the canvas */
1281 if ( (new_order - y_span) >= tavs.visible_y_low) {
1285 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1286 int32_t visible_tracks = 0;
1287 while (visible_tracks < y_span ) {
1289 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1290 /* passing through a hidden track */
1295 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1296 /* moving to a non-track; disallow */
1302 /* moving beyond the lowest visible track; disallow */
1306 } else if (y_span < 0) {
1308 /* moving down the canvas */
1309 if ((new_order - y_span) <= tavs.visible_y_high) {
1311 int32_t visible_tracks = 0;
1313 while (visible_tracks > y_span ) {
1316 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1317 /* passing through a hidden track */
1322 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1323 /* moving to a non-track; disallow */
1330 /* moving beyond the highest visible track; disallow */
1337 /* this is the pointer's track */
1339 if ((new_order - y_span) > tavs.visible_y_high) {
1340 /* we will overflow */
1342 } else if ((new_order - y_span) < tavs.visible_y_low) {
1343 /* we will overflow */
1352 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1353 : RegionMotionDrag (e, i, p, v, b),
1356 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1358 _dest_trackview = tv;
1359 if (tv->layer_display() == Overlaid) {
1362 _dest_layer = _primary->region()->layer ();
1366 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1367 if (rtv && rtv->is_track()) {
1368 speed = rtv->track()->speed ();
1371 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1375 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1377 RegionMotionDrag::start_grab (event, c);
1379 _pointer_frame_offset = grab_frame() - _last_frame_position;
1382 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1383 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1385 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1386 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1388 _primary = v->view()->create_region_view (r, false, false);
1390 _primary->get_canvas_group()->show ();
1391 _primary->set_position (pos, 0);
1392 _views.push_back (DraggingView (_primary));
1394 _last_frame_position = pos;
1396 _item = _primary->get_canvas_group ();
1397 _dest_trackview = v;
1398 _dest_layer = _primary->region()->layer ();
1401 map<RegionView*, pair<RouteTimeAxisView*, int> >
1402 RegionMotionDrag::find_time_axis_views_and_layers ()
1404 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1406 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1408 double ix1, ix2, iy1, iy2;
1409 RegionView* rv = i->view;
1410 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1411 rv->get_canvas_frame()->i2w (ix1, iy1);
1412 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1414 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1415 tav[rv] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1423 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1425 _editor->update_canvas_now ();
1427 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1429 RouteTimeAxisView* dest_rtv = final[_primary].first;
1431 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1432 _primary->get_canvas_group()->property_y() = 0;
1434 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1436 _editor->begin_reversible_command (_("insert region"));
1437 playlist->clear_history ();
1438 playlist->add_region (_primary->region (), _last_frame_position);
1439 _editor->session()->add_command (new StatefulDiffCommand (playlist));
1440 _editor->commit_reversible_command ();
1448 RegionInsertDrag::aborted ()
1455 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1456 : RegionMoveDrag (e, i, p, v, false, false)
1461 struct RegionSelectionByPosition {
1462 bool operator() (RegionView*a, RegionView* b) {
1463 return a->region()->position () < b->region()->position();
1468 RegionSpliceDrag::motion (GdkEvent* event, bool)
1470 RouteTimeAxisView* tv;
1473 if (!check_possible (&tv, &layer)) {
1479 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1485 RegionSelection copy (_editor->selection->regions);
1487 RegionSelectionByPosition cmp;
1490 nframes64_t const pf = adjusted_current_frame (event);
1492 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1494 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1500 boost::shared_ptr<Playlist> playlist;
1502 if ((playlist = atv->playlist()) == 0) {
1506 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1511 if (pf < (*i)->region()->last_frame() + 1) {
1515 if (pf > (*i)->region()->first_frame()) {
1521 playlist->shuffle ((*i)->region(), dir);
1526 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1532 RegionSpliceDrag::aborted ()
1537 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1545 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1547 _dest_trackview = _view;
1549 Drag::start_grab (event);
1554 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1557 // TODO: create region-create-drag region view here
1560 // TODO: resize region-create-drag region view here
1564 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1566 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1572 if (!movement_occurred) {
1573 mtv->add_region (grab_frame ());
1575 motion (event, false);
1576 // TODO: create region-create-drag region here
1581 RegionCreateDrag::aborted ()
1586 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1594 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1597 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1599 Drag::start_grab (event);
1601 region = &cnote->region_view();
1603 double region_start = region->get_position_pixels();
1604 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1606 if (grab_x() <= middle_point) {
1607 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1610 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1614 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1616 if (event->motion.state & Keyboard::PrimaryModifier) {
1622 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1624 if (ms.size() > 1) {
1625 /* has to be relative, may make no sense otherwise */
1629 /* select this note; if it is already selected, preserve the existing selection,
1630 otherwise make this note the only one selected.
1632 region->note_selected (cnote, cnote->selected ());
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->track()->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;
1742 /* snap modifier works differently here..
1743 its current state has to be passed to the
1744 various trim functions in order to work properly
1748 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1749 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1750 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1752 if (tv && tv->is_track()) {
1753 speed = tv->track()->speed();
1756 nframes64_t const pf = adjusted_current_frame (event);
1762 switch (_operation) {
1764 trim_type = "Region start trim";
1767 trim_type = "Region end trim";
1770 trim_type = "Region content trim";
1774 _editor->begin_reversible_command (trim_type);
1775 _have_transaction = true;
1777 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1778 RegionView* rv = i->view;
1779 rv->fake_set_opaque(false);
1780 rv->region()->clear_history ();
1781 rv->region()->suspend_property_changes ();
1783 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
1786 arv->temporarily_hide_envelope ();
1789 boost::shared_ptr<Playlist> pl = rv->region()->playlist();
1790 insert_result = _editor->motion_frozen_playlists.insert (pl);
1792 if (insert_result.second) {
1798 bool non_overlap_trim = false;
1800 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1801 non_overlap_trim = true;
1804 switch (_operation) {
1806 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1807 _editor->single_start_trim (*i->view, pf, non_overlap_trim);
1812 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1813 _editor->single_end_trim (*i->view, pf, non_overlap_trim);
1819 bool swap_direction = false;
1821 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1822 swap_direction = true;
1825 nframes64_t frame_delta = 0;
1827 bool left_direction = false;
1828 if (last_pointer_frame() > pf) {
1829 left_direction = true;
1832 if (left_direction) {
1833 frame_delta = (last_pointer_frame() - pf);
1835 frame_delta = (pf - last_pointer_frame());
1838 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1839 _editor->single_contents_trim (*i->view, frame_delta, left_direction, swap_direction);
1845 switch (_operation) {
1847 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1850 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1853 _editor->show_verbose_time_cursor (pf, 10);
1860 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1862 if (movement_occurred) {
1863 motion (event, false);
1865 if (!_editor->selection->selected (_primary)) {
1866 _editor->thaw_region_after_trim (*_primary);
1869 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1870 _editor->thaw_region_after_trim (*i->view);
1871 i->view->fake_set_opaque (true);
1872 if (_have_transaction) {
1873 _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
1877 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1881 _editor->motion_frozen_playlists.clear ();
1883 if (_have_transaction) {
1884 _editor->commit_reversible_command();
1888 /* no mouse movement */
1889 _editor->point_trim (event, adjusted_current_frame (event));
1894 TrimDrag::aborted ()
1896 /* Our motion method is changing model state, so use the Undo system
1897 to cancel. Perhaps not ideal, as this will leave an Undo point
1898 behind which may be slightly odd from the user's point of view.
1903 if (_have_transaction) {
1908 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1912 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1917 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1920 // create a dummy marker for visual representation of moving the copy.
1921 // The actual copying is not done before we reach the finish callback.
1923 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1924 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1925 *new MeterSection (_marker->meter()));
1927 _item = &new_marker->the_item ();
1928 _marker = new_marker;
1932 MetricSection& section (_marker->meter());
1934 if (!section.movable()) {
1940 Drag::start_grab (event, cursor);
1942 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1944 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1948 MeterMarkerDrag::motion (GdkEvent* event, bool)
1950 nframes64_t const pf = adjusted_current_frame (event);
1952 _marker->set_position (pf);
1954 _editor->show_verbose_time_cursor (pf, 10);
1958 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1960 if (!movement_occurred) {
1964 motion (event, false);
1968 TempoMap& map (_editor->session()->tempo_map());
1969 map.bbt_time (last_pointer_frame(), when);
1971 if (_copy == true) {
1972 _editor->begin_reversible_command (_("copy meter mark"));
1973 XMLNode &before = map.get_state();
1974 map.add_meter (_marker->meter(), when);
1975 XMLNode &after = map.get_state();
1976 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1977 _editor->commit_reversible_command ();
1979 // delete the dummy marker we used for visual representation of copying.
1980 // a new visual marker will show up automatically.
1983 _editor->begin_reversible_command (_("move meter mark"));
1984 XMLNode &before = map.get_state();
1985 map.move_meter (_marker->meter(), when);
1986 XMLNode &after = map.get_state();
1987 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1988 _editor->commit_reversible_command ();
1993 MeterMarkerDrag::aborted ()
1995 _marker->set_position (_marker->meter().frame ());
1998 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
2002 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
2007 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2012 // create a dummy marker for visual representation of moving the copy.
2013 // The actual copying is not done before we reach the finish callback.
2015 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
2016 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
2017 *new TempoSection (_marker->tempo()));
2019 _item = &new_marker->the_item ();
2020 _marker = new_marker;
2024 MetricSection& section (_marker->tempo());
2026 if (!section.movable()) {
2031 Drag::start_grab (event, cursor);
2033 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
2034 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2038 TempoMarkerDrag::motion (GdkEvent* event, bool)
2040 nframes64_t const pf = adjusted_current_frame (event);
2041 _marker->set_position (pf);
2042 _editor->show_verbose_time_cursor (pf, 10);
2046 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2048 if (!movement_occurred) {
2052 motion (event, false);
2056 TempoMap& map (_editor->session()->tempo_map());
2057 map.bbt_time (last_pointer_frame(), when);
2059 if (_copy == true) {
2060 _editor->begin_reversible_command (_("copy tempo mark"));
2061 XMLNode &before = map.get_state();
2062 map.add_tempo (_marker->tempo(), when);
2063 XMLNode &after = map.get_state();
2064 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2065 _editor->commit_reversible_command ();
2067 // delete the dummy marker we used for visual representation of copying.
2068 // a new visual marker will show up automatically.
2071 _editor->begin_reversible_command (_("move tempo mark"));
2072 XMLNode &before = map.get_state();
2073 map.move_tempo (_marker->tempo(), when);
2074 XMLNode &after = map.get_state();
2075 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2076 _editor->commit_reversible_command ();
2081 TempoMarkerDrag::aborted ()
2083 _marker->set_position (_marker->tempo().frame());
2086 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2090 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2095 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2097 Drag::start_grab (event, c);
2101 nframes64_t where = _editor->event_frame (event, 0, 0);
2103 _editor->snap_to_with_modifier (where, event);
2104 _editor->playhead_cursor->set_position (where);
2108 if (_cursor == _editor->playhead_cursor) {
2109 _editor->_dragging_playhead = true;
2111 if (_editor->session() && _was_rolling && _stop) {
2112 _editor->session()->request_stop ();
2115 if (_editor->session() && _editor->session()->is_auditioning()) {
2116 _editor->session()->cancel_audition ();
2120 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2122 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2126 CursorDrag::motion (GdkEvent* event, bool)
2128 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2130 if (adjusted_frame == last_pointer_frame()) {
2134 _cursor->set_position (adjusted_frame);
2136 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2139 _editor->update_canvas_now ();
2141 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2145 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2147 _editor->_dragging_playhead = false;
2149 if (!movement_occurred && _stop) {
2153 motion (event, false);
2155 if (_item == &_editor->playhead_cursor->canvas_item) {
2156 if (_editor->session()) {
2157 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2158 _editor->_pending_locate_request = true;
2164 CursorDrag::aborted ()
2166 _editor->_dragging_playhead = false;
2167 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2170 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2171 : RegionDrag (e, i, p, v)
2177 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2179 Drag::start_grab (event, cursor);
2181 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2182 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2184 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2185 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2189 FadeInDrag::motion (GdkEvent* event, bool)
2191 nframes64_t fade_length;
2193 nframes64_t const pos = adjusted_current_frame (event);
2195 boost::shared_ptr<Region> region = _primary->region ();
2197 if (pos < (region->position() + 64)) {
2198 fade_length = 64; // this should be a minimum defined somewhere
2199 } else if (pos > region->last_frame()) {
2200 fade_length = region->length();
2202 fade_length = pos - region->position();
2205 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2207 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2213 tmp->reset_fade_in_shape_width (fade_length);
2216 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2220 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2222 if (!movement_occurred) {
2226 nframes64_t fade_length;
2228 nframes64_t const pos = adjusted_current_frame (event);
2230 boost::shared_ptr<Region> region = _primary->region ();
2232 if (pos < (region->position() + 64)) {
2233 fade_length = 64; // this should be a minimum defined somewhere
2234 } else if (pos > region->last_frame()) {
2235 fade_length = region->length();
2237 fade_length = pos - region->position();
2240 _editor->begin_reversible_command (_("change fade in length"));
2242 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2244 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2250 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2251 XMLNode &before = alist->get_state();
2253 tmp->audio_region()->set_fade_in_length (fade_length);
2254 tmp->audio_region()->set_fade_in_active (true);
2256 XMLNode &after = alist->get_state();
2257 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2260 _editor->commit_reversible_command ();
2264 FadeInDrag::aborted ()
2266 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2267 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2273 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2277 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2278 : RegionDrag (e, i, p, v)
2284 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2286 Drag::start_grab (event, cursor);
2288 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2289 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2291 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2292 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2296 FadeOutDrag::motion (GdkEvent* event, bool)
2298 nframes64_t fade_length;
2300 nframes64_t const pos = adjusted_current_frame (event);
2302 boost::shared_ptr<Region> region = _primary->region ();
2304 if (pos > (region->last_frame() - 64)) {
2305 fade_length = 64; // this should really be a minimum fade defined somewhere
2307 else if (pos < region->position()) {
2308 fade_length = region->length();
2311 fade_length = region->last_frame() - pos;
2314 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2316 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2322 tmp->reset_fade_out_shape_width (fade_length);
2325 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2329 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2331 if (!movement_occurred) {
2335 nframes64_t fade_length;
2337 nframes64_t const pos = adjusted_current_frame (event);
2339 boost::shared_ptr<Region> region = _primary->region ();
2341 if (pos > (region->last_frame() - 64)) {
2342 fade_length = 64; // this should really be a minimum fade defined somewhere
2344 else if (pos < region->position()) {
2345 fade_length = region->length();
2348 fade_length = region->last_frame() - pos;
2351 _editor->begin_reversible_command (_("change fade out length"));
2353 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2355 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2361 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2362 XMLNode &before = alist->get_state();
2364 tmp->audio_region()->set_fade_out_length (fade_length);
2365 tmp->audio_region()->set_fade_out_active (true);
2367 XMLNode &after = alist->get_state();
2368 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2371 _editor->commit_reversible_command ();
2375 FadeOutDrag::aborted ()
2377 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2378 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2384 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2388 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2391 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2394 _points.push_back (Gnome::Art::Point (0, 0));
2395 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2397 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2398 _line->property_width_pixels() = 1;
2399 _line->property_points () = _points;
2402 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2405 MarkerDrag::~MarkerDrag ()
2407 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2413 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2415 Drag::start_grab (event, cursor);
2419 Location *location = _editor->find_location_from_marker (_marker, is_start);
2420 _editor->_dragging_edit_point = true;
2422 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2424 update_item (location);
2426 // _drag_line->show();
2427 // _line->raise_to_top();
2430 _editor->show_verbose_time_cursor (location->start(), 10);
2432 _editor->show_verbose_time_cursor (location->end(), 10);
2435 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2438 case Selection::Toggle:
2439 _editor->selection->toggle (_marker);
2441 case Selection::Set:
2442 if (!_editor->selection->selected (_marker)) {
2443 _editor->selection->set (_marker);
2446 case Selection::Extend:
2448 Locations::LocationList ll;
2449 list<Marker*> to_add;
2451 _editor->selection->markers.range (s, e);
2452 s = min (_marker->position(), s);
2453 e = max (_marker->position(), e);
2456 if (e < max_frames) {
2459 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2460 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2461 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2464 to_add.push_back (lm->start);
2467 to_add.push_back (lm->end);
2471 if (!to_add.empty()) {
2472 _editor->selection->add (to_add);
2476 case Selection::Add:
2477 _editor->selection->add (_marker);
2481 /* Set up copies for us to manipulate during the drag */
2483 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2484 Location* l = _editor->find_location_from_marker (*i, is_start);
2485 _copied_locations.push_back (new Location (*l));
2490 MarkerDrag::motion (GdkEvent* event, bool)
2492 nframes64_t f_delta = 0;
2494 bool move_both = false;
2496 Location *real_location;
2497 Location *copy_location = 0;
2499 nframes64_t const newframe = adjusted_current_frame (event);
2501 nframes64_t next = newframe;
2503 if (newframe == last_pointer_frame()) {
2507 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2511 MarkerSelection::iterator i;
2512 list<Location*>::iterator x;
2514 /* find the marker we're dragging, and compute the delta */
2516 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2517 x != _copied_locations.end() && i != _editor->selection->markers.end();
2523 if (marker == _marker) {
2525 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2530 if (real_location->is_mark()) {
2531 f_delta = newframe - copy_location->start();
2535 switch (marker->type()) {
2537 case Marker::LoopStart:
2538 case Marker::PunchIn:
2539 f_delta = newframe - copy_location->start();
2543 case Marker::LoopEnd:
2544 case Marker::PunchOut:
2545 f_delta = newframe - copy_location->end();
2548 /* what kind of marker is this ? */
2556 if (i == _editor->selection->markers.end()) {
2557 /* hmm, impossible - we didn't find the dragged marker */
2561 /* now move them all */
2563 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2564 x != _copied_locations.end() && i != _editor->selection->markers.end();
2570 /* call this to find out if its the start or end */
2572 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2576 if (real_location->locked()) {
2580 if (copy_location->is_mark()) {
2584 copy_location->set_start (copy_location->start() + f_delta);
2588 nframes64_t new_start = copy_location->start() + f_delta;
2589 nframes64_t new_end = copy_location->end() + f_delta;
2591 if (is_start) { // start-of-range marker
2594 copy_location->set_start (new_start);
2595 copy_location->set_end (new_end);
2596 } else if (new_start < copy_location->end()) {
2597 copy_location->set_start (new_start);
2599 _editor->snap_to (next, 1, true);
2600 copy_location->set_end (next);
2601 copy_location->set_start (newframe);
2604 } else { // end marker
2607 copy_location->set_end (new_end);
2608 copy_location->set_start (new_start);
2609 } else if (new_end > copy_location->start()) {
2610 copy_location->set_end (new_end);
2611 } else if (newframe > 0) {
2612 _editor->snap_to (next, -1, true);
2613 copy_location->set_start (next);
2614 copy_location->set_end (newframe);
2619 update_item (copy_location);
2621 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2624 lm->set_position (copy_location->start(), copy_location->end());
2628 assert (!_copied_locations.empty());
2630 _editor->show_verbose_time_cursor (newframe, 10);
2633 _editor->update_canvas_now ();
2638 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2640 if (!movement_occurred) {
2642 /* just a click, do nothing but finish
2643 off the selection process
2646 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2649 case Selection::Set:
2650 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2651 _editor->selection->set (_marker);
2655 case Selection::Toggle:
2656 case Selection::Extend:
2657 case Selection::Add:
2664 _editor->_dragging_edit_point = false;
2666 _editor->begin_reversible_command ( _("move marker") );
2667 XMLNode &before = _editor->session()->locations()->get_state();
2669 MarkerSelection::iterator i;
2670 list<Location*>::iterator x;
2673 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2674 x != _copied_locations.end() && i != _editor->selection->markers.end();
2677 Location * location = _editor->find_location_from_marker (*i, is_start);
2681 if (location->locked()) {
2685 if (location->is_mark()) {
2686 location->set_start ((*x)->start());
2688 location->set ((*x)->start(), (*x)->end());
2693 XMLNode &after = _editor->session()->locations()->get_state();
2694 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2695 _editor->commit_reversible_command ();
2701 MarkerDrag::aborted ()
2707 MarkerDrag::update_item (Location* location)
2709 double const x1 = _editor->frame_to_pixel (location->start());
2711 _points.front().set_x(x1);
2712 _points.back().set_x(x1);
2713 _line->property_points() = _points;
2716 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2718 _cumulative_x_drag (0),
2719 _cumulative_y_drag (0)
2721 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2727 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2729 Drag::start_grab (event, _editor->fader_cursor);
2731 // start the grab at the center of the control point so
2732 // the point doesn't 'jump' to the mouse after the first drag
2733 _time_axis_view_grab_x = _point->get_x();
2734 _time_axis_view_grab_y = _point->get_y();
2736 float const fraction = 1 - (_point->get_y() / _point->line().height());
2738 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2740 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2741 event->button.x + 10, event->button.y + 10);
2743 _editor->show_verbose_canvas_cursor ();
2747 ControlPointDrag::motion (GdkEvent* event, bool)
2749 double dx = _drags->current_pointer_x() - last_pointer_x();
2750 double dy = _drags->current_pointer_y() - last_pointer_y();
2752 if (event->button.state & Keyboard::SecondaryModifier) {
2757 /* coordinate in TimeAxisView's space */
2758 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2759 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2761 // calculate zero crossing point. back off by .01 to stay on the
2762 // positive side of zero
2763 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2765 // make sure we hit zero when passing through
2766 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2770 if (_x_constrained) {
2771 cx = _time_axis_view_grab_x;
2773 if (_y_constrained) {
2774 cy = _time_axis_view_grab_y;
2777 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2778 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2782 cy = min ((double) _point->line().height(), cy);
2784 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2786 if (!_x_constrained) {
2787 _editor->snap_to_with_modifier (cx_frames, event);
2790 float const fraction = 1.0 - (cy / _point->line().height());
2792 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2794 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2796 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2800 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2802 if (!movement_occurred) {
2806 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2807 _editor->reset_point_selection ();
2811 motion (event, false);
2813 _point->line().end_drag ();
2817 ControlPointDrag::aborted ()
2819 _point->line().reset ();
2823 ControlPointDrag::active (Editing::MouseMode m)
2825 if (m == Editing::MouseGain) {
2826 /* always active in mouse gain */
2830 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2831 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2834 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2837 _cumulative_y_drag (0)
2842 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2844 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2847 _item = &_line->grab_item ();
2849 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2850 origin, and ditto for y.
2853 double cx = event->button.x;
2854 double cy = event->button.y;
2856 _line->parent_group().w2i (cx, cy);
2858 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2863 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2864 /* no adjacent points */
2868 Drag::start_grab (event, _editor->fader_cursor);
2870 /* store grab start in parent frame */
2872 _time_axis_view_grab_x = cx;
2873 _time_axis_view_grab_y = cy;
2875 double fraction = 1.0 - (cy / _line->height());
2877 _line->start_drag_line (before, after, fraction);
2879 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2880 event->button.x + 10, event->button.y + 10);
2882 _editor->show_verbose_canvas_cursor ();
2886 LineDrag::motion (GdkEvent* event, bool)
2888 double dy = _drags->current_pointer_y() - last_pointer_y();
2890 if (event->button.state & Keyboard::SecondaryModifier) {
2894 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2896 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2899 cy = min ((double) _line->height(), cy);
2901 double const fraction = 1.0 - (cy / _line->height());
2905 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2911 /* we are ignoring x position for this drag, so we can just pass in anything */
2912 _line->drag_motion (0, fraction, true, push);
2914 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2918 LineDrag::finished (GdkEvent* event, bool)
2920 motion (event, false);
2925 LineDrag::aborted ()
2931 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2933 Drag::start_grab (event);
2934 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2938 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2945 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2947 nframes64_t grab = grab_frame ();
2948 if (Config->get_rubberbanding_snaps_to_grid ()) {
2949 _editor->snap_to_with_modifier (grab, event);
2952 /* base start and end on initial click position */
2962 if (_drags->current_pointer_y() < grab_y()) {
2963 y1 = _drags->current_pointer_y();
2966 y2 = _drags->current_pointer_y();
2971 if (start != end || y1 != y2) {
2973 double x1 = _editor->frame_to_pixel (start);
2974 double x2 = _editor->frame_to_pixel (end);
2976 _editor->rubberband_rect->property_x1() = x1;
2977 _editor->rubberband_rect->property_y1() = y1;
2978 _editor->rubberband_rect->property_x2() = x2;
2979 _editor->rubberband_rect->property_y2() = y2;
2981 _editor->rubberband_rect->show();
2982 _editor->rubberband_rect->raise_to_top();
2984 _editor->show_verbose_time_cursor (pf, 10);
2989 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2991 if (movement_occurred) {
2993 motion (event, false);
2996 if (_drags->current_pointer_y() < grab_y()) {
2997 y1 = _drags->current_pointer_y();
3000 y2 = _drags->current_pointer_y();
3005 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
3008 _editor->begin_reversible_command (_("rubberband selection"));
3010 if (grab_frame() < last_pointer_frame()) {
3011 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
3013 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
3017 _editor->commit_reversible_command ();
3021 if (!getenv("ARDOUR_SAE")) {
3022 _editor->selection->clear_tracks();
3024 _editor->selection->clear_regions();
3025 _editor->selection->clear_points ();
3026 _editor->selection->clear_lines ();
3029 _editor->rubberband_rect->hide();
3033 RubberbandSelectDrag::aborted ()
3035 _editor->rubberband_rect->hide ();
3039 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3041 Drag::start_grab (event);
3043 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3047 TimeFXDrag::motion (GdkEvent* event, bool)
3049 RegionView* rv = _primary;
3051 nframes64_t const pf = adjusted_current_frame (event);
3053 if (pf > rv->region()->position()) {
3054 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3057 _editor->show_verbose_time_cursor (pf, 10);
3061 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3063 _primary->get_time_axis_view().hide_timestretch ();
3065 if (!movement_occurred) {
3069 if (last_pointer_frame() < _primary->region()->position()) {
3070 /* backwards drag of the left edge - not usable */
3074 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3076 float percentage = (double) newlen / (double) _primary->region()->length();
3078 #ifndef USE_RUBBERBAND
3079 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3080 if (_primary->region()->data_type() == DataType::AUDIO) {
3081 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3085 _editor->begin_reversible_command (_("timestretch"));
3087 // XXX how do timeFX on multiple regions ?
3092 if (_editor->time_stretch (rs, percentage) == -1) {
3093 error << _("An error occurred while executing time stretch operation") << endmsg;
3098 TimeFXDrag::aborted ()
3100 _primary->get_time_axis_view().hide_timestretch ();
3105 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3107 Drag::start_grab (event);
3111 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3113 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3117 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3119 if (movement_occurred && _editor->session()) {
3120 /* make sure we stop */
3121 _editor->session()->request_transport_speed (0.0);
3126 ScrubDrag::aborted ()
3131 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3135 , _original_pointer_time_axis (-1)
3136 , _last_pointer_time_axis (-1)
3142 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3144 nframes64_t start = 0;
3145 nframes64_t end = 0;
3147 if (_editor->session() == 0) {
3151 Gdk::Cursor* cursor = 0;
3153 switch (_operation) {
3154 case CreateSelection:
3155 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3160 cursor = _editor->selector_cursor;
3161 Drag::start_grab (event, cursor);
3164 case SelectionStartTrim:
3165 if (_editor->clicked_axisview) {
3166 _editor->clicked_axisview->order_selection_trims (_item, true);
3168 Drag::start_grab (event, _editor->trimmer_cursor);
3169 start = _editor->selection->time[_editor->clicked_selection].start;
3170 _pointer_frame_offset = grab_frame() - start;
3173 case SelectionEndTrim:
3174 if (_editor->clicked_axisview) {
3175 _editor->clicked_axisview->order_selection_trims (_item, false);
3177 Drag::start_grab (event, _editor->trimmer_cursor);
3178 end = _editor->selection->time[_editor->clicked_selection].end;
3179 _pointer_frame_offset = grab_frame() - end;
3183 start = _editor->selection->time[_editor->clicked_selection].start;
3184 Drag::start_grab (event, cursor);
3185 _pointer_frame_offset = grab_frame() - start;
3189 if (_operation == SelectionMove) {
3190 _editor->show_verbose_time_cursor (start, 10);
3192 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3195 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3199 SelectionDrag::motion (GdkEvent* event, bool first_move)
3201 nframes64_t start = 0;
3202 nframes64_t end = 0;
3205 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3206 if (pending_time_axis.first == 0) {
3210 nframes64_t const pending_position = adjusted_current_frame (event);
3212 /* only alter selection if things have changed */
3214 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3218 switch (_operation) {
3219 case CreateSelection:
3221 nframes64_t grab = grab_frame ();
3224 _editor->snap_to (grab);
3227 if (pending_position < grab_frame()) {
3228 start = pending_position;
3231 end = pending_position;
3235 /* first drag: Either add to the selection
3236 or create a new selection
3242 /* adding to the selection */
3243 _editor->selection->add (_editor->clicked_axisview);
3244 _editor->clicked_selection = _editor->selection->add (start, end);
3249 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
3250 _editor->selection->set (_editor->clicked_axisview);
3253 _editor->clicked_selection = _editor->selection->set (start, end);
3257 /* select the track that we're in */
3258 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3259 _editor->selection->add (pending_time_axis.first);
3260 _added_time_axes.push_back (pending_time_axis.first);
3263 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3264 tracks that we selected in the first place.
3267 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3268 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3270 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3271 while (i != _added_time_axes.end()) {
3273 list<TimeAxisView*>::iterator tmp = i;
3276 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3277 _editor->selection->remove (*i);
3278 _added_time_axes.remove (*i);
3287 case SelectionStartTrim:
3289 start = _editor->selection->time[_editor->clicked_selection].start;
3290 end = _editor->selection->time[_editor->clicked_selection].end;
3292 if (pending_position > end) {
3295 start = pending_position;
3299 case SelectionEndTrim:
3301 start = _editor->selection->time[_editor->clicked_selection].start;
3302 end = _editor->selection->time[_editor->clicked_selection].end;
3304 if (pending_position < start) {
3307 end = pending_position;
3314 start = _editor->selection->time[_editor->clicked_selection].start;
3315 end = _editor->selection->time[_editor->clicked_selection].end;
3317 length = end - start;
3319 start = pending_position;
3320 _editor->snap_to (start);
3322 end = start + length;
3327 if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
3328 _editor->start_canvas_autoscroll (1, 0);
3332 _editor->selection->replace (_editor->clicked_selection, start, end);
3335 if (_operation == SelectionMove) {
3336 _editor->show_verbose_time_cursor(start, 10);
3338 _editor->show_verbose_time_cursor(pending_position, 10);
3343 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3345 Session* s = _editor->session();
3347 if (movement_occurred) {
3348 motion (event, false);
3349 /* XXX this is not object-oriented programming at all. ick */
3350 if (_editor->selection->time.consolidate()) {
3351 _editor->selection->TimeChanged ();
3354 /* XXX what if its a music time selection? */
3355 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3356 s->request_play_range (&_editor->selection->time, true);
3361 /* just a click, no pointer movement.*/
3363 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3364 _editor->selection->clear_time();
3367 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
3368 _editor->selection->set (_editor->clicked_axisview);
3371 if (s && s->get_play_range () && s->transport_rolling()) {
3372 s->request_stop (false, false);
3377 _editor->stop_canvas_autoscroll ();
3381 SelectionDrag::aborted ()
3386 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3391 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3392 _drag_rect->hide ();
3394 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3395 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3399 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3401 if (_editor->session() == 0) {
3405 Gdk::Cursor* cursor = 0;
3407 if (!_editor->temp_location) {
3408 _editor->temp_location = new Location;
3411 switch (_operation) {
3412 case CreateRangeMarker:
3413 case CreateTransportMarker:
3414 case CreateCDMarker:
3416 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3421 cursor = _editor->selector_cursor;
3425 Drag::start_grab (event, cursor);
3427 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3431 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3433 nframes64_t start = 0;
3434 nframes64_t end = 0;
3435 ArdourCanvas::SimpleRect *crect;
3437 switch (_operation) {
3438 case CreateRangeMarker:
3439 crect = _editor->range_bar_drag_rect;
3441 case CreateTransportMarker:
3442 crect = _editor->transport_bar_drag_rect;
3444 case CreateCDMarker:
3445 crect = _editor->cd_marker_bar_drag_rect;
3448 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3453 nframes64_t const pf = adjusted_current_frame (event);
3455 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3456 nframes64_t grab = grab_frame ();
3457 _editor->snap_to (grab);
3459 if (pf < grab_frame()) {
3467 /* first drag: Either add to the selection
3468 or create a new selection.
3473 _editor->temp_location->set (start, end);
3477 update_item (_editor->temp_location);
3479 //_drag_rect->raise_to_top();
3484 if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) {
3485 _editor->start_canvas_autoscroll (1, 0);
3489 _editor->temp_location->set (start, end);
3491 double x1 = _editor->frame_to_pixel (start);
3492 double x2 = _editor->frame_to_pixel (end);
3493 crect->property_x1() = x1;
3494 crect->property_x2() = x2;
3496 update_item (_editor->temp_location);
3499 _editor->show_verbose_time_cursor (pf, 10);
3504 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3506 Location * newloc = 0;
3510 if (movement_occurred) {
3511 motion (event, false);
3514 switch (_operation) {
3515 case CreateRangeMarker:
3516 case CreateCDMarker:
3518 _editor->begin_reversible_command (_("new range marker"));
3519 XMLNode &before = _editor->session()->locations()->get_state();
3520 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3521 if (_operation == CreateCDMarker) {
3522 flags = Location::IsRangeMarker | Location::IsCDMarker;
3523 _editor->cd_marker_bar_drag_rect->hide();
3526 flags = Location::IsRangeMarker;
3527 _editor->range_bar_drag_rect->hide();
3529 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3530 _editor->session()->locations()->add (newloc, true);
3531 XMLNode &after = _editor->session()->locations()->get_state();
3532 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3533 _editor->commit_reversible_command ();
3537 case CreateTransportMarker:
3538 // popup menu to pick loop or punch
3539 _editor->new_transport_marker_context_menu (&event->button, _item);
3543 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3545 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3550 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3552 if (end == max_frames) {
3553 end = _editor->session()->current_end_frame ();
3556 if (start == max_frames) {
3557 start = _editor->session()->current_start_frame ();
3560 switch (_editor->mouse_mode) {
3562 /* find the two markers on either side and then make the selection from it */
3563 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3567 /* find the two markers on either side of the click and make the range out of it */
3568 _editor->selection->set (start, end);
3577 _editor->stop_canvas_autoscroll ();
3581 RangeMarkerBarDrag::aborted ()
3587 RangeMarkerBarDrag::update_item (Location* location)
3589 double const x1 = _editor->frame_to_pixel (location->start());
3590 double const x2 = _editor->frame_to_pixel (location->end());
3592 _drag_rect->property_x1() = x1;
3593 _drag_rect->property_x2() = x2;
3597 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3599 Drag::start_grab (event, _editor->zoom_cursor);
3600 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3604 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3609 nframes64_t const pf = adjusted_current_frame (event);
3611 nframes64_t grab = grab_frame ();
3612 _editor->snap_to_with_modifier (grab, event);
3614 /* base start and end on initial click position */
3626 _editor->zoom_rect->show();
3627 _editor->zoom_rect->raise_to_top();
3630 _editor->reposition_zoom_rect(start, end);
3632 _editor->show_verbose_time_cursor (pf, 10);
3637 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3639 if (movement_occurred) {
3640 motion (event, false);
3642 if (grab_frame() < last_pointer_frame()) {
3643 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3645 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3648 _editor->temporal_zoom_to_frame (false, grab_frame());
3650 temporal_zoom_step (false);
3651 center_screen (grab_frame());
3655 _editor->zoom_rect->hide();
3659 MouseZoomDrag::aborted ()
3661 _editor->zoom_rect->hide ();
3664 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3667 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3668 region = &cnote->region_view();
3672 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3674 Drag::start_grab (event);
3677 drag_delta_note = 0;
3682 event_x = _drags->current_pointer_x();
3683 event_y = _drags->current_pointer_y();
3685 _item->property_parent().get_value()->w2i(event_x, event_y);
3687 last_x = region->snap_to_pixel(event_x);
3690 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3692 if (!(was_selected = cnote->selected())) {
3694 /* tertiary-click means extend selection - we'll do that on button release,
3695 so don't add it here, because otherwise we make it hard to figure
3696 out the "extend-to" range.
3699 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3702 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3705 region->note_selected (cnote, true);
3707 region->unique_select (cnote);
3714 NoteDrag::motion (GdkEvent*, bool)
3716 MidiStreamView* streamview = region->midi_stream_view();
3720 event_x = _drags->current_pointer_x();
3721 event_y = _drags->current_pointer_y();
3723 _item->property_parent().get_value()->w2i(event_x, event_y);
3725 event_x = region->snap_to_pixel(event_x);
3727 double dx = event_x - last_x;
3728 double dy = event_y - last_y;
3733 // Snap to note rows
3735 if (abs (dy) < streamview->note_height()) {
3738 int8_t this_delta_note;
3740 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3742 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3744 drag_delta_note -= this_delta_note;
3745 dy = streamview->note_height() * this_delta_note;
3746 last_y = last_y + dy;
3750 region->move_selection (dx, dy);
3752 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3755 snprintf (buf, sizeof (buf), "%s (%g)", Evoral::midi_note_name (cnote->note()->note()).c_str(),
3756 (int) cnote->note()->note() + drag_delta_note);
3757 _editor->show_verbose_canvas_cursor_with (buf);
3762 NoteDrag::finished (GdkEvent* ev, bool moved)
3764 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3767 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3770 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3772 region->note_deselected (cnote);
3775 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3776 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3778 if (!extend && !add && region->selection_size() > 1) {
3779 region->unique_select(cnote);
3780 } else if (extend) {
3781 region->note_selected (cnote, true, true);
3783 /* it was added during button press */
3788 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3793 NoteDrag::aborted ()
3798 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3801 , _nothing_to_drag (false)
3803 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3806 _line = _atav->line ();
3810 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3812 Drag::start_grab (event, cursor);
3814 list<ControlPoint*> points;
3816 XMLNode* state = &_line->get_state ();
3818 if (_ranges.empty()) {
3820 uint32_t const N = _line->npoints ();
3821 for (uint32_t i = 0; i < N; ++i) {
3822 points.push_back (_line->nth (i));
3827 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3828 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3830 /* fade into and out of the region that we're dragging;
3831 64 samples length plucked out of thin air.
3833 nframes64_t const h = (j->start + j->end) / 2;
3834 nframes64_t a = j->start + 64;
3838 nframes64_t b = j->end - 64;
3843 the_list->add (j->start, the_list->eval (j->start));
3844 _line->add_always_in_view (j->start);
3845 the_list->add (a, the_list->eval (a));
3846 _line->add_always_in_view (a);
3847 the_list->add (b, the_list->eval (b));
3848 _line->add_always_in_view (b);
3849 the_list->add (j->end, the_list->eval (j->end));
3850 _line->add_always_in_view (j->end);
3853 uint32_t const N = _line->npoints ();
3854 for (uint32_t i = 0; i < N; ++i) {
3856 ControlPoint* p = _line->nth (i);
3858 list<AudioRange>::const_iterator j = _ranges.begin ();
3859 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3863 if (j != _ranges.end()) {
3864 points.push_back (p);
3869 if (points.empty()) {
3870 _nothing_to_drag = true;
3874 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3878 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3880 if (_nothing_to_drag) {
3884 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3886 /* we are ignoring x position for this drag, so we can just pass in anything */
3887 _line->drag_motion (0, f, true, false);
3891 AutomationRangeDrag::finished (GdkEvent* event, bool)
3893 if (_nothing_to_drag) {
3897 motion (event, false);
3899 _line->clear_always_in_view ();
3903 AutomationRangeDrag::aborted ()
3905 _line->clear_always_in_view ();
3909 DraggingView::DraggingView (RegionView* v)
3912 initial_y = v->get_canvas_group()->property_y ();