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 #include "pbd/memento_command.h"
21 #include "pbd/basename.h"
22 #include "ardour/diskstream.h"
23 #include "ardour/dB.h"
24 #include "ardour/region_factory.h"
25 #include "ardour/midi_diskstream.h"
29 #include "audio_region_view.h"
30 #include "midi_region_view.h"
31 #include "ardour_ui.h"
32 #include "control_point.h"
34 #include "region_gain_line.h"
35 #include "editor_drag.h"
36 #include "audio_time_axis.h"
37 #include "midi_time_axis.h"
40 using namespace ARDOUR;
44 using namespace Editing;
46 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
48 Drag::Drag (Editor* e, ArdourCanvas::Item* i) :
51 _pointer_frame_offset (0),
53 _last_pointer_frame (0),
54 _current_pointer_frame (0),
55 _had_movement (false),
56 _move_threshold_passed (false)
62 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
68 cursor = _editor->which_grabber_cursor ();
71 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
75 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
78 cursor = _editor->which_grabber_cursor ();
81 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
83 if (Keyboard::is_button2_event (&event->button)) {
84 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
85 _y_constrained = true;
86 _x_constrained = false;
88 _y_constrained = false;
89 _x_constrained = true;
92 _x_constrained = false;
93 _y_constrained = false;
96 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
97 _last_pointer_frame = _grab_frame;
98 _current_pointer_frame = _grab_frame;
99 _current_pointer_x = _grab_x;
100 _current_pointer_y = _grab_y;
101 _last_pointer_x = _current_pointer_x;
102 _last_pointer_y = _current_pointer_y;
106 _item->i2w (_original_x, _original_y);
108 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
112 if (_editor->session && _editor->session->transport_rolling()) {
115 _was_rolling = false;
118 switch (_editor->snap_type) {
119 case SnapToRegionStart:
120 case SnapToRegionEnd:
121 case SnapToRegionSync:
122 case SnapToRegionBoundary:
123 _editor->build_region_boundary_cache ();
130 /** @param event GDK event, or 0.
131 * @return true if some movement occurred, otherwise false.
134 Drag::end_grab (GdkEvent* event)
138 _editor->stop_canvas_autoscroll ();
140 _item->ungrab (event ? event->button.time : 0);
142 _last_pointer_x = _current_pointer_x;
143 _last_pointer_y = _current_pointer_y;
144 finished (event, _had_movement);
146 _editor->hide_verbose_canvas_cursor();
150 return _had_movement;
154 Drag::adjusted_current_frame (GdkEvent* event) const
158 if (_current_pointer_frame > _pointer_frame_offset) {
159 pos = _current_pointer_frame - _pointer_frame_offset;
162 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
163 _editor->snap_to (pos);
170 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
172 _last_pointer_x = _current_pointer_x;
173 _last_pointer_y = _current_pointer_y;
174 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
176 if (!from_autoscroll && !_move_threshold_passed) {
178 bool const xp = (::llabs ((nframes64_t) (_current_pointer_x - _grab_x)) > 4LL);
179 bool const yp = (::llabs ((nframes64_t) (_current_pointer_y - _grab_y)) > 4LL);
181 _move_threshold_passed = (xp || yp);
183 if (apply_move_threshold() && _move_threshold_passed) {
185 _grab_frame = _current_pointer_frame;
186 _grab_x = _current_pointer_x;
187 _grab_y = _current_pointer_y;
188 _last_pointer_frame = _grab_frame;
189 _pointer_frame_offset = _grab_frame - _last_frame_position;
194 bool old_had_movement = _had_movement;
196 /* a motion event has happened, so we've had movement... */
197 _had_movement = true;
199 /* ... unless we're using a move threshold and we've not yet passed it */
200 if (apply_move_threshold() && !_move_threshold_passed) {
201 _had_movement = false;
204 if (active (_editor->mouse_mode)) {
206 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
207 if (!from_autoscroll) {
208 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
211 motion (event, _had_movement != old_had_movement);
223 _editor->stop_canvas_autoscroll ();
224 _editor->hide_verbose_canvas_cursor ();
229 /* put it back where it came from */
234 _item->i2w (cxw, cyw);
235 _item->move (_original_x - cxw, _original_y - cyw);
240 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
245 RegionView::RegionViewGoingAway.connect (mem_fun (*this, &RegionDrag::region_going_away));
249 RegionDrag::region_going_away (RegionView* v)
254 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
255 : RegionDrag (e, i, p, v),
265 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
267 Drag::start_grab (event);
269 _editor->show_verbose_time_cursor (_last_frame_position, 10);
272 RegionMotionDrag::TimeAxisViewSummary
273 RegionMotionDrag::get_time_axis_view_summary ()
275 int32_t children = 0;
276 TimeAxisViewSummary sum;
278 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
280 /* get a bitmask representing the visible tracks */
282 for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
283 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
284 TimeAxisView::Children children_list;
286 /* zeroes are audio/MIDI tracks. ones are other types. */
288 if (!rtv->hidden()) {
290 if (!rtv->is_track()) {
291 /* not an audio nor MIDI track */
292 sum.tracks = sum.tracks |= (0x01 << rtv->order());
295 sum.height_list[rtv->order()] = (*i)->current_height();
298 if ((children_list = rtv->get_child_list()).size() > 0) {
299 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
300 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
301 sum.height_list[rtv->order() + children] = (*j)->current_height();
312 RegionMotionDrag::compute_y_delta (
313 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
314 int32_t last_pointer_layer, int32_t current_pointer_layer,
315 TimeAxisViewSummary const & tavs,
316 int32_t* pointer_order_span, int32_t* pointer_layer_span,
317 int32_t* canvas_pointer_order_span
321 *pointer_order_span = 0;
322 *pointer_layer_span = 0;
326 bool clamp_y_axis = false;
328 /* the change in track order between this callback and the last */
329 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
330 /* the change in layer between this callback and the last;
331 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
332 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
334 if (*pointer_order_span != 0) {
336 /* find the actual pointer span, in terms of the number of visible tracks;
337 to do this, we reduce |pointer_order_span| by the number of hidden tracks
340 *canvas_pointer_order_span = *pointer_order_span;
341 if (last_pointer_view->order() >= current_pointer_view->order()) {
342 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
343 if (tavs.height_list[y] == 0) {
344 *canvas_pointer_order_span--;
348 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
349 if (tavs.height_list[y] == 0) {
350 *canvas_pointer_order_span++;
355 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
357 RegionView* rv = (*i);
359 if (rv->region()->locked()) {
363 double ix1, ix2, iy1, iy2;
364 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
365 rv->get_canvas_frame()->i2w (ix1, iy1);
366 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
368 /* get the new trackview for this particular region */
369 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
371 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
373 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
374 as surely this is a per-region thing... */
376 clamp_y_axis = y_movement_disallowed (
377 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
385 } else if (_dest_trackview == current_pointer_view) {
387 if (current_pointer_layer == last_pointer_layer) {
388 /* No movement; clamp */
394 _dest_trackview = current_pointer_view;
395 _dest_layer = current_pointer_layer;
403 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
405 *pending_region_position = 0;
407 /* compute the amount of pointer motion in frames, and where
408 the region would be if we moved it by that much.
410 if (_current_pointer_frame >= _pointer_frame_offset) {
412 nframes64_t sync_frame;
413 nframes64_t sync_offset;
416 *pending_region_position = _current_pointer_frame - _pointer_frame_offset;
418 sync_offset = _primary->region()->sync_offset (sync_dir);
420 /* we don't handle a sync point that lies before zero.
422 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
424 sync_frame = *pending_region_position + (sync_dir*sync_offset);
426 /* we snap if the snap modifier is not enabled.
429 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
430 _editor->snap_to (sync_frame);
433 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
436 *pending_region_position = _last_frame_position;
441 if (*pending_region_position > max_frames - _primary->region()->length()) {
442 *pending_region_position = _last_frame_position;
447 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
449 /* now compute the canvas unit distance we need to move the regionview
450 to make it appear at the new location.
453 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
455 if (*pending_region_position <= _last_frame_position) {
457 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
459 RegionView* rv = (*i);
461 // If any regionview is at zero, we need to know so we can stop further leftward motion.
463 double ix1, ix2, iy1, iy2;
464 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
465 rv->get_canvas_frame()->i2w (ix1, iy1);
467 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
469 *pending_region_position = _last_frame_position;
476 _last_frame_position = *pending_region_position;
483 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
487 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
489 vector<int32_t>::iterator j;
491 /* *pointer* variables reflect things about the pointer; as we may be moving
492 multiple regions, much detail must be computed per-region */
494 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
495 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
496 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
497 is always 0 regardless of what the region's "real" layer is */
498 RouteTimeAxisView* current_pointer_view;
499 layer_t current_pointer_layer;
500 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
504 /* TimeAxisView that we were pointing at last time we entered this method */
505 TimeAxisView const * const last_pointer_view = _dest_trackview;
506 /* the order of the track that we were pointing at last time we entered this method */
507 int32_t const last_pointer_order = last_pointer_view->order ();
508 /* the layer that we were pointing at last time we entered this method */
509 layer_t const last_pointer_layer = _dest_layer;
511 int32_t pointer_order_span;
512 int32_t pointer_layer_span;
513 int32_t canvas_pointer_order_span;
515 bool const clamp_y_axis = compute_y_delta (
516 last_pointer_view, current_pointer_view,
517 last_pointer_layer, current_pointer_layer, tavs,
518 &pointer_order_span, &pointer_layer_span,
519 &canvas_pointer_order_span
522 nframes64_t pending_region_position;
523 double const x_delta = compute_x_delta (event, &pending_region_position);
525 /*************************************************************
527 ************************************************************/
529 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0) {
530 /* haven't reached next snap point, and we're not switching
531 trackviews nor layers. nothing to do.
536 /*************************************************************
538 ************************************************************/
540 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
542 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
544 RegionView* rv = (*i);
546 if (rv->region()->locked()) {
550 /* here we are calculating the y distance from the
551 top of the first track view to the top of the region
552 area of the track view that we're working on */
554 /* this x value is just a dummy value so that we have something
559 /* distance from the top of this track view to the region area
560 of our track view is always 1 */
564 /* convert to world coordinates, ie distance from the top of
567 rv->get_canvas_frame()->i2w (ix1, iy1);
569 /* compensate for the ruler section and the vertical scrollbar position */
570 iy1 += _editor->get_trackview_group_vertical_offset ();
574 // hide any dependent views
576 rv->get_time_axis_view().hide_dependent_views (*rv);
579 reparent to a non scrolling group so that we can keep the
580 region selection above all time axis views.
581 reparenting means we have to move the rv as the two
582 parent groups have different coordinates.
585 rv->get_canvas_group()->property_y() = iy1 - 1;
586 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
588 rv->fake_set_opaque (true);
591 /* current view for this particular region */
592 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
593 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
595 if (pointer_order_span != 0 && !clamp_y_axis) {
597 /* INTER-TRACK MOVEMENT */
599 /* move through the height list to the track that the region is currently on */
600 vector<int32_t>::iterator j = tavs.height_list.begin ();
602 while (j != tavs.height_list.end () && x != rtv->order ()) {
608 int32_t temp_pointer_order_span = canvas_pointer_order_span;
610 if (j != tavs.height_list.end ()) {
612 /* Account for layers in the original and
613 destination tracks. If we're moving around in layers we assume
614 that only one track is involved, so it's ok to use *pointer*
617 StreamView* lv = last_pointer_view->view ();
620 /* move to the top of the last trackview */
621 if (lv->layer_display () == Stacked) {
622 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
625 StreamView* cv = current_pointer_view->view ();
628 /* move to the right layer on the current trackview */
629 if (cv->layer_display () == Stacked) {
630 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
633 /* And for being on a non-topmost layer on the new
636 while (temp_pointer_order_span > 0) {
637 /* we're moving up canvas-wise,
638 so we need to find the next track height
640 if (j != tavs.height_list.begin()) {
644 if (x != last_pointer_order) {
646 ++temp_pointer_order_span;
651 temp_pointer_order_span--;
654 while (temp_pointer_order_span < 0) {
658 if (x != last_pointer_order) {
660 --temp_pointer_order_span;
664 if (j != tavs.height_list.end()) {
668 temp_pointer_order_span++;
672 /* find out where we'll be when we move and set height accordingly */
674 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
675 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
676 rv->set_height (temp_rtv->view()->child_height());
678 /* if you un-comment the following, the region colours will follow
679 the track colours whilst dragging; personally
680 i think this can confuse things, but never mind.
683 //const GdkColor& col (temp_rtv->view->get_region_color());
684 //rv->set_color (const_cast<GdkColor&>(col));
688 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
690 /* INTER-LAYER MOVEMENT in the same track */
691 y_delta = rtv->view()->child_height () * pointer_layer_span;
696 _editor->mouse_brush_insert_region (rv, pending_region_position);
698 rv->move (x_delta, y_delta);
701 } /* foreach region */
704 _editor->cursor_group->raise_to_top();
707 if (x_delta != 0 && !_brushing) {
708 _editor->show_verbose_time_cursor (_last_frame_position, 10);
713 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
715 if (_copy && first_move) {
716 copy_regions (event);
719 RegionMotionDrag::motion (event, first_move);
723 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
725 bool nocommit = true;
726 vector<RegionView*> copies;
727 boost::shared_ptr<Diskstream> ds;
728 boost::shared_ptr<Playlist> from_playlist;
729 list<RegionView*> new_views;
730 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
731 PlaylistSet modified_playlists;
732 PlaylistSet frozen_playlists;
733 list <sigc::connection> modified_playlist_connections;
734 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
735 nframes64_t drag_delta;
736 bool changed_tracks, changed_position;
737 map<RegionView*, RouteTimeAxisView*> final;
738 RouteTimeAxisView* source_tv;
740 if (!movement_occurred) {
747 if (Config->get_edit_mode() == Splice && !_editor->pre_drag_region_selection.empty()) {
748 _editor->selection->set (_editor->pre_drag_region_selection);
749 _editor->pre_drag_region_selection.clear ();
753 /* all changes were made during motion event handlers */
756 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
757 copies.push_back (*i);
764 /* reverse this here so that we have the correct logic to finalize
768 if (Config->get_edit_mode() == Lock && !_copy) {
769 _x_constrained = !_x_constrained;
773 if (_x_constrained) {
774 _editor->begin_reversible_command (_("fixed time region copy"));
776 _editor->begin_reversible_command (_("region copy"));
779 if (_x_constrained) {
780 _editor->begin_reversible_command (_("fixed time region drag"));
782 _editor->begin_reversible_command (_("region drag"));
786 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
787 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
789 drag_delta = _primary->region()->position() - _last_frame_position;
791 _editor->update_canvas_now ();
793 /* make a list of where each region ended up */
794 final = find_time_axis_views ();
796 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
798 RegionView* rv = (*i);
799 RouteTimeAxisView* dest_rtv = final[*i];
803 if (rv->region()->locked()) {
808 if (changed_position && !_x_constrained) {
809 where = rv->region()->position() - drag_delta;
811 where = rv->region()->position();
814 boost::shared_ptr<Region> new_region;
817 /* we already made a copy */
818 new_region = rv->region();
820 /* undo the previous hide_dependent_views so that xfades don't
821 disappear on copying regions
824 //rv->get_time_axis_view().reveal_dependent_views (*rv);
826 } else if (changed_tracks && dest_rtv->playlist()) {
827 new_region = RegionFactory::create (rv->region());
830 if (changed_tracks || _copy) {
832 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
839 _editor->latest_regionviews.clear ();
841 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
843 insert_result = modified_playlists.insert (to_playlist);
845 if (insert_result.second) {
846 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
849 to_playlist->add_region (new_region, where);
853 if (!_editor->latest_regionviews.empty()) {
854 // XXX why just the first one ? we only expect one
855 // commented out in nick_m's canvas reworking. is that intended?
856 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
857 new_views.push_back (_editor->latest_regionviews.front());
862 motion on the same track. plonk the previously reparented region
863 back to its original canvas group (its streamview).
864 No need to do anything for copies as they are fake regions which will be deleted.
867 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
868 rv->get_canvas_group()->property_y() = 0;
870 /* just change the model */
872 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
874 insert_result = modified_playlists.insert (playlist);
876 if (insert_result.second) {
877 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
879 /* freeze to avoid lots of relayering in the case of a multi-region drag */
880 frozen_insert_result = frozen_playlists.insert(playlist);
882 if (frozen_insert_result.second) {
886 rv->region()->set_position (where, (void*) this);
889 if (changed_tracks && !_copy) {
891 /* get the playlist where this drag started. we can't use rv->region()->playlist()
892 because we may have copied the region and it has not been attached to a playlist.
895 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
896 ds = source_tv->get_diskstream();
897 from_playlist = ds->playlist();
901 assert (from_playlist);
903 /* moved to a different audio track, without copying */
905 /* the region that used to be in the old playlist is not
906 moved to the new one - we use a copy of it. as a result,
907 any existing editor for the region should no longer be
911 rv->hide_region_editor();
912 rv->fake_set_opaque (false);
914 /* remove the region from the old playlist */
916 insert_result = modified_playlists.insert (from_playlist);
918 if (insert_result.second) {
919 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
922 from_playlist->remove_region (rv->region());
924 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
925 was selected in all of them, then removing it from a playlist will have removed all
926 trace of it from the selection (i.e. there were N regions selected, we removed 1,
927 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
928 corresponding regionview, and the selection is now empty).
930 this could have invalidated any and all iterators into the region selection.
932 the heuristic we use here is: if the region selection is empty, break out of the loop
933 here. if the region selection is not empty, then restart the loop because we know that
934 we must have removed at least the region(view) we've just been working on as well as any
935 that we processed on previous iterations.
937 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
941 if (_views.empty()) {
952 copies.push_back (rv);
956 if (new_views.empty()) {
958 /* the region(view)s that are being dragged around are copies and do not
959 belong to any track. remove them from our list
965 _primary = _views.front ();
968 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
974 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
975 _editor->session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
978 _editor->commit_reversible_command ();
981 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
988 RegionMoveDrag::x_move_allowed () const
990 if (Config->get_edit_mode() == Lock) {
992 return !_x_constrained;
994 /* in locked edit mode, reverse the usual meaning of _x_constrained */
995 return _x_constrained;
999 return !_x_constrained;
1003 RegionInsertDrag::x_move_allowed () const
1005 if (Config->get_edit_mode() == Lock) {
1006 return _x_constrained;
1009 return !_x_constrained;
1013 RegionMotionDrag::copy_regions (GdkEvent* event)
1015 /* duplicate the regionview(s) and region(s) */
1017 list<RegionView*> new_regionviews;
1019 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1021 RegionView* rv = (*i);
1022 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1023 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1025 const boost::shared_ptr<const Region> original = rv->region();
1026 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1030 boost::shared_ptr<AudioRegion> audioregion_copy
1031 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1032 nrv = new AudioRegionView (*arv, audioregion_copy);
1034 boost::shared_ptr<MidiRegion> midiregion_copy
1035 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1036 nrv = new MidiRegionView (*mrv, midiregion_copy);
1041 nrv->get_canvas_group()->show ();
1042 new_regionviews.push_back (nrv);
1045 if (new_regionviews.empty()) {
1049 /* reflect the fact that we are dragging the copies */
1051 _primary = new_regionviews.front();
1052 _views = new_regionviews;
1054 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1057 sync the canvas to what we think is its current state
1058 without it, the canvas seems to
1059 "forget" to update properly after the upcoming reparent()
1060 ..only if the mouse is in rapid motion at the time of the grab.
1061 something to do with regionview creation raking so long?
1063 _editor->update_canvas_now();
1067 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1069 /* Which trackview is this ? */
1071 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1072 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1073 (*layer) = tvp.second;
1075 if (*tv && (*tv)->layer_display() == Overlaid) {
1079 /* The region motion is only processed if the pointer is over
1083 if (!(*tv) || !(*tv)->is_track()) {
1084 /* To make sure we hide the verbose canvas cursor when the mouse is
1085 not held over and audiotrack.
1087 _editor->hide_verbose_canvas_cursor ();
1094 /** @param new_order New track order.
1095 * @param old_order Old track order.
1096 * @param visible_y_low Lowest visible order.
1097 * @return true if y movement should not happen, otherwise false.
1100 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1102 if (new_order != old_order) {
1104 /* this isn't the pointer track */
1108 /* moving up the canvas */
1109 if ( (new_order - y_span) >= tavs.visible_y_low) {
1113 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1114 int32_t visible_tracks = 0;
1115 while (visible_tracks < y_span ) {
1117 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1118 /* passing through a hidden track */
1123 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1124 /* moving to a non-track; disallow */
1130 /* moving beyond the lowest visible track; disallow */
1134 } else if (y_span < 0) {
1136 /* moving down the canvas */
1137 if ((new_order - y_span) <= tavs.visible_y_high) {
1139 int32_t visible_tracks = 0;
1141 while (visible_tracks > y_span ) {
1144 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1145 /* passing through a hidden track */
1150 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1151 /* moving to a non-track; disallow */
1158 /* moving beyond the highest visible track; disallow */
1165 /* this is the pointer's track */
1167 if ((new_order - y_span) > tavs.visible_y_high) {
1168 /* we will overflow */
1170 } else if ((new_order - y_span) < tavs.visible_y_low) {
1171 /* we will overflow */
1180 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1181 : RegionMotionDrag (e, i, p, v, b),
1184 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1186 _dest_trackview = tv;
1187 if (tv->layer_display() == Overlaid) {
1190 _dest_layer = _primary->region()->layer ();
1194 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1195 if (rtv && rtv->is_track()) {
1196 speed = rtv->get_diskstream()->speed ();
1199 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1203 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1205 RegionMotionDrag::start_grab (event, c);
1207 _pointer_frame_offset = _grab_frame - _last_frame_position;
1210 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1211 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1213 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1214 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1216 _primary = v->view()->create_region_view (r, false, false);
1218 _primary->get_canvas_group()->show ();
1219 _primary->set_position (pos, 0);
1220 _views.push_back (_primary);
1222 _last_frame_position = pos;
1224 _item = _primary->get_canvas_group ();
1225 _dest_trackview = v;
1226 _dest_layer = _primary->region()->layer ();
1229 map<RegionView*, RouteTimeAxisView*>
1230 RegionMotionDrag::find_time_axis_views ()
1232 map<RegionView*, RouteTimeAxisView*> tav;
1234 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1236 double ix1, ix2, iy1, iy2;
1237 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1238 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1239 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1241 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1242 tav[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
1250 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1252 _editor->update_canvas_now ();
1254 map<RegionView*, RouteTimeAxisView*> final = find_time_axis_views ();
1256 RouteTimeAxisView* dest_rtv = final[_primary];
1258 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1259 _primary->get_canvas_group()->property_y() = 0;
1261 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1263 _editor->begin_reversible_command (_("insert region"));
1264 XMLNode& before = playlist->get_state ();
1265 playlist->add_region (_primary->region (), _last_frame_position);
1266 _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1267 _editor->commit_reversible_command ();
1274 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1275 : RegionMoveDrag (e, i, p, v, false, false)
1280 struct RegionSelectionByPosition {
1281 bool operator() (RegionView*a, RegionView* b) {
1282 return a->region()->position () < b->region()->position();
1287 RegionSpliceDrag::motion (GdkEvent* /*event*/, bool)
1289 RouteTimeAxisView* tv;
1292 if (!check_possible (&tv, &layer)) {
1298 if (_current_pointer_x - _grab_x > 0) {
1304 RegionSelection copy (_editor->selection->regions);
1306 RegionSelectionByPosition cmp;
1309 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1311 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1317 boost::shared_ptr<Playlist> playlist;
1319 if ((playlist = atv->playlist()) == 0) {
1323 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1328 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1332 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1338 playlist->shuffle ((*i)->region(), dir);
1340 _grab_x = _current_pointer_x;
1345 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1351 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1359 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1361 _dest_trackview = _view;
1363 Drag::start_grab (event);
1368 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1371 // TODO: create region-create-drag region view here
1374 // TODO: resize region-create-drag region view here
1378 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1380 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1385 const boost::shared_ptr<MidiDiskstream> diskstream =
1386 boost::dynamic_pointer_cast<MidiDiskstream>(mtv->view()->trackview().track()->diskstream());
1389 warning << "Cannot create non-MIDI region" << endl;
1393 if (!movement_occurred) {
1394 _editor->begin_reversible_command (_("create region"));
1395 XMLNode &before = mtv->playlist()->get_state();
1397 nframes64_t start = _grab_frame;
1398 _editor->snap_to (start, -1);
1399 const Meter& m = _editor->session->tempo_map().meter_at(start);
1400 const Tempo& t = _editor->session->tempo_map().tempo_at(start);
1401 double length = floor (m.frames_per_bar(t, _editor->session->frame_rate()));
1403 boost::shared_ptr<Source> src = _editor->session->create_midi_source_for_session(*diskstream.get());
1405 mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>
1406 (RegionFactory::create(src, 0, (nframes_t) length,
1407 PBD::basename_nosuffix(src->name()))), start);
1408 XMLNode &after = mtv->playlist()->get_state();
1409 _editor->session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
1410 _editor->commit_reversible_command();
1413 motion (event, false);
1414 // TODO: create region-create-drag region here
1422 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1428 RegionGainDrag::finished (GdkEvent *, bool)
1433 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1434 : RegionDrag (e, i, p, v)
1440 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1443 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1444 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1446 if (tv && tv->is_track()) {
1447 speed = tv->get_diskstream()->speed();
1450 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1451 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1452 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1454 Drag::start_grab (event, _editor->trimmer_cursor);
1456 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1457 _operation = ContentsTrim;
1459 /* These will get overridden for a point trim.*/
1460 if (_current_pointer_frame < (region_start + region_length/2)) {
1461 /* closer to start */
1462 _operation = StartTrim;
1463 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1465 _operation = EndTrim;
1469 switch (_operation) {
1471 _editor->show_verbose_time_cursor (region_start, 10);
1474 _editor->show_verbose_time_cursor (region_end, 10);
1477 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1483 TrimDrag::motion (GdkEvent* event, bool first_move)
1485 RegionView* rv = _primary;
1486 nframes64_t frame_delta = 0;
1488 bool left_direction;
1489 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1491 /* snap modifier works differently here..
1492 its' current state has to be passed to the
1493 various trim functions in order to work properly
1497 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1498 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1499 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1501 if (tv && tv->is_track()) {
1502 speed = tv->get_diskstream()->speed();
1505 if (_last_pointer_frame > _current_pointer_frame) {
1506 left_direction = true;
1508 left_direction = false;
1512 _editor->snap_to (_current_pointer_frame);
1519 switch (_operation) {
1521 trim_type = "Region start trim";
1524 trim_type = "Region end trim";
1527 trim_type = "Region content trim";
1531 _editor->begin_reversible_command (trim_type);
1533 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1534 (*i)->fake_set_opaque(false);
1535 (*i)->region()->freeze ();
1537 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1540 arv->temporarily_hide_envelope ();
1543 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1544 insert_result = _editor->motion_frozen_playlists.insert (pl);
1546 if (insert_result.second) {
1547 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1553 if (_current_pointer_frame == _last_pointer_frame) {
1557 if (left_direction) {
1558 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1560 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1563 bool non_overlap_trim = false;
1565 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1566 non_overlap_trim = true;
1569 switch (_operation) {
1571 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1575 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1576 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1582 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1586 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1587 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1594 bool swap_direction = false;
1596 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1597 swap_direction = true;
1600 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1602 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1608 switch (_operation) {
1610 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1613 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1616 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1620 _last_pointer_frame = _current_pointer_frame;
1625 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1627 if (movement_occurred) {
1628 motion (event, false);
1630 if (!_editor->selection->selected (_primary)) {
1631 _editor->thaw_region_after_trim (*_primary);
1634 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1635 _editor->thaw_region_after_trim (**i);
1636 (*i)->fake_set_opaque (true);
1640 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1642 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1645 _editor->motion_frozen_playlists.clear ();
1647 _editor->commit_reversible_command();
1649 /* no mouse movement */
1650 _editor->point_trim (event);
1654 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1658 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1663 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1666 // create a dummy marker for visual representation of moving the copy.
1667 // The actual copying is not done before we reach the finish callback.
1669 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1670 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1671 *new MeterSection (_marker->meter()));
1673 _item = &new_marker->the_item ();
1674 _marker = new_marker;
1678 MetricSection& section (_marker->meter());
1680 if (!section.movable()) {
1686 Drag::start_grab (event, cursor);
1688 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1690 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1694 MeterMarkerDrag::motion (GdkEvent* event, bool)
1696 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1698 if (adjusted_frame == _last_pointer_frame) {
1702 _marker->set_position (adjusted_frame);
1704 _last_pointer_frame = adjusted_frame;
1706 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1710 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1712 if (!movement_occurred) {
1716 motion (event, false);
1720 TempoMap& map (_editor->session->tempo_map());
1721 map.bbt_time (_last_pointer_frame, when);
1723 if (_copy == true) {
1724 _editor->begin_reversible_command (_("copy meter mark"));
1725 XMLNode &before = map.get_state();
1726 map.add_meter (_marker->meter(), when);
1727 XMLNode &after = map.get_state();
1728 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1729 _editor->commit_reversible_command ();
1731 // delete the dummy marker we used for visual representation of copying.
1732 // a new visual marker will show up automatically.
1735 _editor->begin_reversible_command (_("move meter mark"));
1736 XMLNode &before = map.get_state();
1737 map.move_meter (_marker->meter(), when);
1738 XMLNode &after = map.get_state();
1739 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1740 _editor->commit_reversible_command ();
1744 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1748 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1753 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1758 // create a dummy marker for visual representation of moving the copy.
1759 // The actual copying is not done before we reach the finish callback.
1761 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1762 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1763 *new TempoSection (_marker->tempo()));
1765 _item = &new_marker->the_item ();
1766 _marker = new_marker;
1770 MetricSection& section (_marker->tempo());
1772 if (!section.movable()) {
1777 Drag::start_grab (event, cursor);
1779 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1780 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1784 TempoMarkerDrag::motion (GdkEvent* event, bool)
1786 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1788 if (adjusted_frame == _last_pointer_frame) {
1792 /* OK, we've moved far enough to make it worth actually move the thing. */
1794 _marker->set_position (adjusted_frame);
1796 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1798 _last_pointer_frame = adjusted_frame;
1802 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1804 if (!movement_occurred) {
1808 motion (event, false);
1812 TempoMap& map (_editor->session->tempo_map());
1813 map.bbt_time (_last_pointer_frame, when);
1815 if (_copy == true) {
1816 _editor->begin_reversible_command (_("copy tempo mark"));
1817 XMLNode &before = map.get_state();
1818 map.add_tempo (_marker->tempo(), when);
1819 XMLNode &after = map.get_state();
1820 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1821 _editor->commit_reversible_command ();
1823 // delete the dummy marker we used for visual representation of copying.
1824 // a new visual marker will show up automatically.
1827 _editor->begin_reversible_command (_("move tempo mark"));
1828 XMLNode &before = map.get_state();
1829 map.move_tempo (_marker->tempo(), when);
1830 XMLNode &after = map.get_state();
1831 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1832 _editor->commit_reversible_command ();
1837 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1841 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1846 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1848 Drag::start_grab (event, c);
1852 nframes64_t where = _editor->event_frame (event, 0, 0);
1854 _editor->snap_to (where);
1855 _editor->playhead_cursor->set_position (where);
1859 if (_cursor == _editor->playhead_cursor) {
1860 _editor->_dragging_playhead = true;
1862 if (_editor->session && _was_rolling && _stop) {
1863 _editor->session->request_stop ();
1866 if (_editor->session && _editor->session->is_auditioning()) {
1867 _editor->session->cancel_audition ();
1871 _pointer_frame_offset = _grab_frame - _cursor->current_frame;
1873 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1877 CursorDrag::motion (GdkEvent* event, bool)
1879 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1881 if (adjusted_frame == _last_pointer_frame) {
1885 _cursor->set_position (adjusted_frame);
1887 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1890 _editor->update_canvas_now ();
1892 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1894 _last_pointer_frame = adjusted_frame;
1898 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1900 _editor->_dragging_playhead = false;
1902 if (!movement_occurred && _stop) {
1906 motion (event, false);
1908 if (_item == &_editor->playhead_cursor->canvas_item) {
1909 if (_editor->session) {
1910 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1911 _editor->_pending_locate_request = true;
1916 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1917 : RegionDrag (e, i, p, v)
1923 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1925 Drag::start_grab (event, cursor);
1927 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1928 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1930 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1934 FadeInDrag::motion (GdkEvent* event, bool)
1936 nframes64_t fade_length;
1938 nframes64_t const pos = adjusted_current_frame (event);
1940 boost::shared_ptr<Region> region = _primary->region ();
1942 if (pos < (region->position() + 64)) {
1943 fade_length = 64; // this should be a minimum defined somewhere
1944 } else if (pos > region->last_frame()) {
1945 fade_length = region->length();
1947 fade_length = pos - region->position();
1950 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1952 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1958 tmp->reset_fade_in_shape_width (fade_length);
1961 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1965 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1967 if (!movement_occurred) {
1971 nframes64_t fade_length;
1973 nframes64_t const pos = adjusted_current_frame (event);
1975 boost::shared_ptr<Region> region = _primary->region ();
1977 if (pos < (region->position() + 64)) {
1978 fade_length = 64; // this should be a minimum defined somewhere
1979 } else if (pos > region->last_frame()) {
1980 fade_length = region->length();
1982 fade_length = pos - region->position();
1985 _editor->begin_reversible_command (_("change fade in length"));
1987 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1989 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1995 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
1996 XMLNode &before = alist->get_state();
1998 tmp->audio_region()->set_fade_in_length (fade_length);
1999 tmp->audio_region()->set_fade_in_active (true);
2001 XMLNode &after = alist->get_state();
2002 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2005 _editor->commit_reversible_command ();
2008 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2009 : RegionDrag (e, i, p, v)
2015 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2017 Drag::start_grab (event, cursor);
2019 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2020 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2022 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2026 FadeOutDrag::motion (GdkEvent* event, bool)
2028 nframes64_t fade_length;
2030 nframes64_t const pos = adjusted_current_frame (event);
2032 boost::shared_ptr<Region> region = _primary->region ();
2034 if (pos > (region->last_frame() - 64)) {
2035 fade_length = 64; // this should really be a minimum fade defined somewhere
2037 else if (pos < region->position()) {
2038 fade_length = region->length();
2041 fade_length = region->last_frame() - pos;
2044 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2046 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2052 tmp->reset_fade_out_shape_width (fade_length);
2055 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2059 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2061 if (!movement_occurred) {
2065 nframes64_t fade_length;
2067 nframes64_t const pos = adjusted_current_frame (event);
2069 boost::shared_ptr<Region> region = _primary->region ();
2071 if (pos > (region->last_frame() - 64)) {
2072 fade_length = 64; // this should really be a minimum fade defined somewhere
2074 else if (pos < region->position()) {
2075 fade_length = region->length();
2078 fade_length = region->last_frame() - pos;
2081 _editor->begin_reversible_command (_("change fade out length"));
2083 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2085 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2091 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2092 XMLNode &before = alist->get_state();
2094 tmp->audio_region()->set_fade_out_length (fade_length);
2095 tmp->audio_region()->set_fade_out_active (true);
2097 XMLNode &after = alist->get_state();
2098 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2101 _editor->commit_reversible_command ();
2104 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2107 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2110 _points.push_back (Gnome::Art::Point (0, 0));
2111 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2113 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2114 _line->property_width_pixels() = 1;
2115 _line->property_points () = _points;
2118 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2121 MarkerDrag::~MarkerDrag ()
2123 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2129 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2131 Drag::start_grab (event, cursor);
2135 Location *location = _editor->find_location_from_marker (_marker, is_start);
2136 _editor->_dragging_edit_point = true;
2138 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2140 update_item (location);
2142 // _drag_line->show();
2143 // _line->raise_to_top();
2146 _editor->show_verbose_time_cursor (location->start(), 10);
2148 _editor->show_verbose_time_cursor (location->end(), 10);
2151 Selection::Operation op = Keyboard::selection_type (event->button.state);
2154 case Selection::Toggle:
2155 _editor->selection->toggle (_marker);
2157 case Selection::Set:
2158 if (!_editor->selection->selected (_marker)) {
2159 _editor->selection->set (_marker);
2162 case Selection::Extend:
2164 Locations::LocationList ll;
2165 list<Marker*> to_add;
2167 _editor->selection->markers.range (s, e);
2168 s = min (_marker->position(), s);
2169 e = max (_marker->position(), e);
2172 if (e < max_frames) {
2175 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2176 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2177 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2180 to_add.push_back (lm->start);
2183 to_add.push_back (lm->end);
2187 if (!to_add.empty()) {
2188 _editor->selection->add (to_add);
2192 case Selection::Add:
2193 _editor->selection->add (_marker);
2197 /* set up copies for us to manipulate during the drag */
2199 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2200 Location *l = _editor->find_location_from_marker (*i, is_start);
2201 _copied_locations.push_back (new Location (*l));
2206 MarkerDrag::motion (GdkEvent* event, bool)
2208 nframes64_t f_delta = 0;
2210 bool move_both = false;
2212 Location *real_location;
2213 Location *copy_location = 0;
2215 nframes64_t const newframe = adjusted_current_frame (event);
2217 nframes64_t next = newframe;
2219 if (_current_pointer_frame == _last_pointer_frame) {
2223 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2227 MarkerSelection::iterator i;
2228 list<Location*>::iterator x;
2230 /* find the marker we're dragging, and compute the delta */
2232 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2233 x != _copied_locations.end() && i != _editor->selection->markers.end();
2239 if (marker == _marker) {
2241 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2246 if (real_location->is_mark()) {
2247 f_delta = newframe - copy_location->start();
2251 switch (marker->type()) {
2253 case Marker::LoopStart:
2254 case Marker::PunchIn:
2255 f_delta = newframe - copy_location->start();
2259 case Marker::LoopEnd:
2260 case Marker::PunchOut:
2261 f_delta = newframe - copy_location->end();
2264 /* what kind of marker is this ? */
2272 if (i == _editor->selection->markers.end()) {
2273 /* hmm, impossible - we didn't find the dragged marker */
2277 /* now move them all */
2279 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2280 x != _copied_locations.end() && i != _editor->selection->markers.end();
2286 /* call this to find out if its the start or end */
2288 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2292 if (real_location->locked()) {
2296 if (copy_location->is_mark()) {
2300 copy_location->set_start (copy_location->start() + f_delta);
2304 nframes64_t new_start = copy_location->start() + f_delta;
2305 nframes64_t new_end = copy_location->end() + f_delta;
2307 if (is_start) { // start-of-range marker
2310 copy_location->set_start (new_start);
2311 copy_location->set_end (new_end);
2312 } else if (new_start < copy_location->end()) {
2313 copy_location->set_start (new_start);
2315 _editor->snap_to (next, 1, true);
2316 copy_location->set_end (next);
2317 copy_location->set_start (newframe);
2320 } else { // end marker
2323 copy_location->set_end (new_end);
2324 copy_location->set_start (new_start);
2325 } else if (new_end > copy_location->start()) {
2326 copy_location->set_end (new_end);
2327 } else if (newframe > 0) {
2328 _editor->snap_to (next, -1, true);
2329 copy_location->set_start (next);
2330 copy_location->set_end (newframe);
2335 update_item (copy_location);
2337 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2340 lm->set_position (copy_location->start(), copy_location->end());
2344 _last_pointer_frame = _current_pointer_frame;
2346 assert (!_copied_locations.empty());
2348 _editor->edit_point_clock.set (_copied_locations.front()->start());
2349 _editor->show_verbose_time_cursor (newframe, 10);
2352 _editor->update_canvas_now ();
2354 _editor->edit_point_clock.set (copy_location->start());
2358 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2360 if (!movement_occurred) {
2362 /* just a click, do nothing but finish
2363 off the selection process
2366 Selection::Operation op = Keyboard::selection_type (event->button.state);
2369 case Selection::Set:
2370 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2371 _editor->selection->set (_marker);
2375 case Selection::Toggle:
2376 case Selection::Extend:
2377 case Selection::Add:
2384 _editor->_dragging_edit_point = false;
2386 _editor->begin_reversible_command ( _("move marker") );
2387 XMLNode &before = _editor->session->locations()->get_state();
2389 MarkerSelection::iterator i;
2390 list<Location*>::iterator x;
2393 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2394 x != _copied_locations.end() && i != _editor->selection->markers.end();
2397 Location * location = _editor->find_location_from_marker (*i, is_start);
2401 if (location->locked()) {
2405 if (location->is_mark()) {
2406 location->set_start ((*x)->start());
2408 location->set ((*x)->start(), (*x)->end());
2413 XMLNode &after = _editor->session->locations()->get_state();
2414 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
2415 _editor->commit_reversible_command ();
2421 MarkerDrag::update_item (Location* location)
2423 double const x1 = _editor->frame_to_pixel (location->start());
2425 _points.front().set_x(x1);
2426 _points.back().set_x(x1);
2427 _line->property_points() = _points;
2430 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2432 _cumulative_x_drag (0),
2433 _cumulative_y_drag (0)
2435 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2441 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2443 Drag::start_grab (event, _editor->fader_cursor);
2445 // start the grab at the center of the control point so
2446 // the point doesn't 'jump' to the mouse after the first drag
2447 _grab_x = _point->get_x();
2448 _grab_y = _point->get_y();
2450 _point->line().parent_group().i2w (_grab_x, _grab_y);
2451 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2453 _grab_frame = _editor->pixel_to_frame (_grab_x);
2455 _point->line().start_drag (_point, _grab_frame, 0);
2457 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2458 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2459 _current_pointer_x + 10, _current_pointer_y + 10);
2461 _editor->show_verbose_canvas_cursor ();
2465 ControlPointDrag::motion (GdkEvent* event, bool)
2467 double dx = _current_pointer_x - _last_pointer_x;
2468 double dy = _current_pointer_y - _last_pointer_y;
2470 if (event->button.state & Keyboard::SecondaryModifier) {
2475 double cx = _grab_x + _cumulative_x_drag + dx;
2476 double cy = _grab_y + _cumulative_y_drag + dy;
2478 // calculate zero crossing point. back off by .01 to stay on the
2479 // positive side of zero
2481 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2482 _point->line().parent_group().i2w(_unused, zero_gain_y);
2484 // make sure we hit zero when passing through
2485 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2486 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2490 if (_x_constrained) {
2493 if (_y_constrained) {
2497 _cumulative_x_drag = cx - _grab_x;
2498 _cumulative_y_drag = cy - _grab_y;
2500 _point->line().parent_group().w2i (cx, cy);
2504 cy = min ((double) _point->line().height(), cy);
2506 //translate cx to frames
2507 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2509 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !_x_constrained) {
2510 _editor->snap_to (cx_frames);
2513 float const fraction = 1.0 - (cy / _point->line().height());
2515 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2517 _point->line().point_drag (*_point, cx_frames, fraction, push);
2519 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2523 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2525 if (!movement_occurred) {
2529 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2530 _editor->reset_point_selection ();
2534 motion (event, false);
2536 _point->line().end_drag (_point);
2540 ControlPointDrag::active (Editing::MouseMode m)
2542 if (m == Editing::MouseGain) {
2543 /* always active in mouse gain */
2547 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2548 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2551 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2554 _cumulative_y_drag (0)
2559 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2561 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2564 _item = &_line->grab_item ();
2566 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2567 origin, and ditto for y.
2570 double cx = event->button.x;
2571 double cy = event->button.y;
2573 _line->parent_group().w2i (cx, cy);
2575 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2577 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2578 /* no adjacent points */
2582 Drag::start_grab (event, _editor->fader_cursor);
2584 /* store grab start in parent frame */
2589 double fraction = 1.0 - (cy / _line->height());
2591 _line->start_drag (0, _grab_frame, fraction);
2593 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2594 _current_pointer_x + 10, _current_pointer_y + 10);
2596 _editor->show_verbose_canvas_cursor ();
2600 LineDrag::motion (GdkEvent* event, bool)
2602 double dy = _current_pointer_y - _last_pointer_y;
2604 if (event->button.state & Keyboard::SecondaryModifier) {
2608 double cy = _grab_y + _cumulative_y_drag + dy;
2610 _cumulative_y_drag = cy - _grab_y;
2613 cy = min ((double) _line->height(), cy);
2615 double const fraction = 1.0 - (cy / _line->height());
2619 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2625 _line->line_drag (_before, _after, fraction, push);
2627 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2631 LineDrag::finished (GdkEvent* event, bool)
2633 motion (event, false);
2634 _line->end_drag (0);
2638 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2640 Drag::start_grab (event);
2641 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2645 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2652 /* use a bigger drag threshold than the default */
2654 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2658 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && Config->get_rubberbanding_snaps_to_grid()) {
2660 _editor->snap_to (_grab_frame);
2662 _editor->snap_to (_current_pointer_frame);
2665 /* base start and end on initial click position */
2667 if (_current_pointer_frame < _grab_frame) {
2668 start = _current_pointer_frame;
2671 end = _current_pointer_frame;
2672 start = _grab_frame;
2675 if (_current_pointer_y < _grab_y) {
2676 y1 = _current_pointer_y;
2679 y2 = _current_pointer_y;
2684 if (start != end || y1 != y2) {
2686 double x1 = _editor->frame_to_pixel (start);
2687 double x2 = _editor->frame_to_pixel (end);
2689 _editor->rubberband_rect->property_x1() = x1;
2690 _editor->rubberband_rect->property_y1() = y1;
2691 _editor->rubberband_rect->property_x2() = x2;
2692 _editor->rubberband_rect->property_y2() = y2;
2694 _editor->rubberband_rect->show();
2695 _editor->rubberband_rect->raise_to_top();
2697 _last_pointer_frame = _current_pointer_frame;
2699 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2704 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2706 if (movement_occurred) {
2708 motion (event, false);
2711 if (_current_pointer_y < _grab_y) {
2712 y1 = _current_pointer_y;
2715 y2 = _current_pointer_y;
2720 Selection::Operation op = Keyboard::selection_type (event->button.state);
2723 _editor->begin_reversible_command (_("rubberband selection"));
2725 if (_grab_frame < _last_pointer_frame) {
2726 commit = _editor->select_all_within (_grab_frame, _last_pointer_frame, y1, y2, _editor->track_views, op);
2728 commit = _editor->select_all_within (_last_pointer_frame, _grab_frame, y1, y2, _editor->track_views, op);
2732 _editor->commit_reversible_command ();
2736 if (!getenv("ARDOUR_SAE")) {
2737 _editor->selection->clear_tracks();
2739 _editor->selection->clear_regions();
2740 _editor->selection->clear_points ();
2741 _editor->selection->clear_lines ();
2744 _editor->rubberband_rect->hide();
2748 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2750 Drag::start_grab (event);
2752 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2756 TimeFXDrag::motion (GdkEvent* event, bool)
2758 RegionView* rv = _primary;
2760 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2761 _editor->snap_to (_current_pointer_frame);
2764 if (_current_pointer_frame == _last_pointer_frame) {
2768 if (_current_pointer_frame > rv->region()->position()) {
2769 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2772 _last_pointer_frame = _current_pointer_frame;
2774 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2778 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2780 _primary->get_time_axis_view().hide_timestretch ();
2782 if (!movement_occurred) {
2786 if (_last_pointer_frame < _primary->region()->position()) {
2787 /* backwards drag of the left edge - not usable */
2791 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2793 float percentage = (double) newlen / (double) _primary->region()->length();
2795 #ifndef USE_RUBBERBAND
2796 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2797 if (_primary->region()->data_type() == DataType::AUDIO) {
2798 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2802 _editor->begin_reversible_command (_("timestretch"));
2804 // XXX how do timeFX on multiple regions ?
2809 if (_editor->time_stretch (rs, percentage) == 0) {
2810 _editor->session->commit_reversible_command ();
2815 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2817 Drag::start_grab (event);
2821 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2827 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2829 if (movement_occurred && _editor->session) {
2830 /* make sure we stop */
2831 _editor->session->request_transport_speed (0.0);
2835 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2844 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2846 nframes64_t start = 0;
2847 nframes64_t end = 0;
2849 if (_editor->session == 0) {
2853 Gdk::Cursor* cursor = 0;
2855 switch (_operation) {
2856 case CreateSelection:
2857 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2862 cursor = _editor->selector_cursor;
2863 Drag::start_grab (event, cursor);
2866 case SelectionStartTrim:
2867 if (_editor->clicked_axisview) {
2868 _editor->clicked_axisview->order_selection_trims (_item, true);
2870 Drag::start_grab (event, cursor);
2871 cursor = _editor->trimmer_cursor;
2872 start = _editor->selection->time[_editor->clicked_selection].start;
2873 _pointer_frame_offset = _grab_frame - start;
2876 case SelectionEndTrim:
2877 if (_editor->clicked_axisview) {
2878 _editor->clicked_axisview->order_selection_trims (_item, false);
2880 Drag::start_grab (event, cursor);
2881 cursor = _editor->trimmer_cursor;
2882 end = _editor->selection->time[_editor->clicked_selection].end;
2883 _pointer_frame_offset = _grab_frame - end;
2887 start = _editor->selection->time[_editor->clicked_selection].start;
2888 Drag::start_grab (event, cursor);
2889 _pointer_frame_offset = _grab_frame - start;
2893 if (_operation == SelectionMove) {
2894 _editor->show_verbose_time_cursor (start, 10);
2896 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2901 SelectionDrag::motion (GdkEvent* event, bool first_move)
2903 nframes64_t start = 0;
2904 nframes64_t end = 0;
2907 nframes64_t const pending_position = adjusted_current_frame (event);
2909 /* only alter selection if the current frame is
2910 different from the last frame position (adjusted)
2913 if (pending_position == _last_pointer_frame) {
2917 switch (_operation) {
2918 case CreateSelection:
2921 _editor->snap_to (_grab_frame);
2924 if (pending_position < _grab_frame) {
2925 start = pending_position;
2928 end = pending_position;
2929 start = _grab_frame;
2932 /* first drag: Either add to the selection
2933 or create a new selection->
2938 _editor->begin_reversible_command (_("range selection"));
2941 /* adding to the selection */
2942 _editor->clicked_selection = _editor->selection->add (start, end);
2945 /* new selection-> */
2946 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2951 case SelectionStartTrim:
2954 _editor->begin_reversible_command (_("trim selection start"));
2957 start = _editor->selection->time[_editor->clicked_selection].start;
2958 end = _editor->selection->time[_editor->clicked_selection].end;
2960 if (pending_position > end) {
2963 start = pending_position;
2967 case SelectionEndTrim:
2970 _editor->begin_reversible_command (_("trim selection end"));
2973 start = _editor->selection->time[_editor->clicked_selection].start;
2974 end = _editor->selection->time[_editor->clicked_selection].end;
2976 if (pending_position < start) {
2979 end = pending_position;
2987 _editor->begin_reversible_command (_("move selection"));
2990 start = _editor->selection->time[_editor->clicked_selection].start;
2991 end = _editor->selection->time[_editor->clicked_selection].end;
2993 length = end - start;
2995 start = pending_position;
2996 _editor->snap_to (start);
2998 end = start + length;
3003 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3004 _editor->start_canvas_autoscroll (1, 0);
3008 _editor->selection->replace (_editor->clicked_selection, start, end);
3011 _last_pointer_frame = pending_position;
3013 if (_operation == SelectionMove) {
3014 _editor->show_verbose_time_cursor(start, 10);
3016 _editor->show_verbose_time_cursor(pending_position, 10);
3021 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3023 if (movement_occurred) {
3024 motion (event, false);
3025 /* XXX this is not object-oriented programming at all. ick */
3026 if (_editor->selection->time.consolidate()) {
3027 _editor->selection->TimeChanged ();
3029 _editor->commit_reversible_command ();
3031 /* just a click, no pointer movement.*/
3033 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3035 _editor->selection->clear_time();
3040 /* XXX what happens if its a music selection? */
3041 _editor->session->set_audio_range (_editor->selection->time);
3042 _editor->stop_canvas_autoscroll ();
3045 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3050 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3051 _drag_rect->hide ();
3053 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3054 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3058 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3060 if (_editor->session == 0) {
3064 Gdk::Cursor* cursor = 0;
3066 if (!_editor->temp_location) {
3067 _editor->temp_location = new Location;
3070 switch (_operation) {
3071 case CreateRangeMarker:
3072 case CreateTransportMarker:
3073 case CreateCDMarker:
3075 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3080 cursor = _editor->selector_cursor;
3084 Drag::start_grab (event, cursor);
3086 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3090 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3092 nframes64_t start = 0;
3093 nframes64_t end = 0;
3094 ArdourCanvas::SimpleRect *crect;
3096 switch (_operation) {
3097 case CreateRangeMarker:
3098 crect = _editor->range_bar_drag_rect;
3100 case CreateTransportMarker:
3101 crect = _editor->transport_bar_drag_rect;
3103 case CreateCDMarker:
3104 crect = _editor->cd_marker_bar_drag_rect;
3107 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3112 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3113 _editor->snap_to (_current_pointer_frame);
3116 /* only alter selection if the current frame is
3117 different from the last frame position.
3120 if (_current_pointer_frame == _last_pointer_frame) {
3124 switch (_operation) {
3125 case CreateRangeMarker:
3126 case CreateTransportMarker:
3127 case CreateCDMarker:
3129 _editor->snap_to (_grab_frame);
3132 if (_current_pointer_frame < _grab_frame) {
3133 start = _current_pointer_frame;
3136 end = _current_pointer_frame;
3137 start = _grab_frame;
3140 /* first drag: Either add to the selection
3141 or create a new selection.
3146 _editor->temp_location->set (start, end);
3150 update_item (_editor->temp_location);
3152 //_drag_rect->raise_to_top();
3158 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3159 _editor->start_canvas_autoscroll (1, 0);
3163 _editor->temp_location->set (start, end);
3165 double x1 = _editor->frame_to_pixel (start);
3166 double x2 = _editor->frame_to_pixel (end);
3167 crect->property_x1() = x1;
3168 crect->property_x2() = x2;
3170 update_item (_editor->temp_location);
3173 _last_pointer_frame = _current_pointer_frame;
3175 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3180 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3182 Location * newloc = 0;
3186 if (movement_occurred) {
3187 motion (event, false);
3190 switch (_operation) {
3191 case CreateRangeMarker:
3192 case CreateCDMarker:
3194 _editor->begin_reversible_command (_("new range marker"));
3195 XMLNode &before = _editor->session->locations()->get_state();
3196 _editor->session->locations()->next_available_name(rangename,"unnamed");
3197 if (_operation == CreateCDMarker) {
3198 flags = Location::IsRangeMarker | Location::IsCDMarker;
3199 _editor->cd_marker_bar_drag_rect->hide();
3202 flags = Location::IsRangeMarker;
3203 _editor->range_bar_drag_rect->hide();
3205 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3206 _editor->session->locations()->add (newloc, true);
3207 XMLNode &after = _editor->session->locations()->get_state();
3208 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3209 _editor->commit_reversible_command ();
3213 case CreateTransportMarker:
3214 // popup menu to pick loop or punch
3215 _editor->new_transport_marker_context_menu (&event->button, _item);
3219 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3221 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3226 start = _editor->session->locations()->first_mark_before (_grab_frame);
3227 end = _editor->session->locations()->first_mark_after (_grab_frame);
3229 if (end == max_frames) {
3230 end = _editor->session->current_end_frame ();
3234 start = _editor->session->current_start_frame ();
3237 switch (_editor->mouse_mode) {
3239 /* find the two markers on either side and then make the selection from it */
3240 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3244 /* find the two markers on either side of the click and make the range out of it */
3245 _editor->selection->set (0, start, end);
3254 _editor->stop_canvas_autoscroll ();
3260 RangeMarkerBarDrag::update_item (Location* location)
3262 double const x1 = _editor->frame_to_pixel (location->start());
3263 double const x2 = _editor->frame_to_pixel (location->end());
3265 _drag_rect->property_x1() = x1;
3266 _drag_rect->property_x2() = x2;
3270 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3272 Drag::start_grab (event, _editor->zoom_cursor);
3273 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3277 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3282 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3283 _editor->snap_to (_current_pointer_frame);
3286 _editor->snap_to (_grab_frame);
3290 if (_current_pointer_frame == _last_pointer_frame) {
3294 /* base start and end on initial click position */
3295 if (_current_pointer_frame < _grab_frame) {
3296 start = _current_pointer_frame;
3299 end = _current_pointer_frame;
3300 start = _grab_frame;
3306 _editor->zoom_rect->show();
3307 _editor->zoom_rect->raise_to_top();
3310 _editor->reposition_zoom_rect(start, end);
3312 _last_pointer_frame = _current_pointer_frame;
3314 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3319 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3321 if (movement_occurred) {
3322 motion (event, false);
3324 if (_grab_frame < _last_pointer_frame) {
3325 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3327 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3330 _editor->temporal_zoom_to_frame (false, _grab_frame);
3332 temporal_zoom_step (false);
3333 center_screen (_grab_frame);
3337 _editor->zoom_rect->hide();