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 vector<RegionView*> copies;
726 boost::shared_ptr<Diskstream> ds;
727 boost::shared_ptr<Playlist> from_playlist;
728 list<RegionView*> new_views;
729 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
730 PlaylistSet modified_playlists;
731 PlaylistSet frozen_playlists;
732 list <sigc::connection> modified_playlist_connections;
733 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
734 nframes64_t drag_delta;
735 bool changed_tracks, changed_position;
736 map<RegionView*, RouteTimeAxisView*> final;
737 RouteTimeAxisView* source_tv;
739 if (!movement_occurred) {
744 if (Config->get_edit_mode() == Splice && !_editor->pre_drag_region_selection.empty()) {
745 _editor->selection->set (_editor->pre_drag_region_selection);
746 _editor->pre_drag_region_selection.clear ();
750 /* all changes were made during motion event handlers */
753 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
754 copies.push_back (*i);
761 /* reverse this here so that we have the correct logic to finalize
765 if (Config->get_edit_mode() == Lock && !_copy) {
766 _x_constrained = !_x_constrained;
770 if (_x_constrained) {
771 _editor->begin_reversible_command (_("fixed time region copy"));
773 _editor->begin_reversible_command (_("region copy"));
776 if (_x_constrained) {
777 _editor->begin_reversible_command (_("fixed time region drag"));
779 _editor->begin_reversible_command (_("region drag"));
783 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
784 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
786 drag_delta = _primary->region()->position() - _last_frame_position;
788 _editor->update_canvas_now ();
790 /* make a list of where each region ended up */
791 final = find_time_axis_views ();
793 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
795 RegionView* rv = (*i);
796 RouteTimeAxisView* dest_rtv = final[*i];
800 if (rv->region()->locked()) {
805 if (changed_position && !_x_constrained) {
806 where = rv->region()->position() - drag_delta;
808 where = rv->region()->position();
811 boost::shared_ptr<Region> new_region;
814 /* we already made a copy */
815 new_region = rv->region();
817 /* undo the previous hide_dependent_views so that xfades don't
818 disappear on copying regions
821 //rv->get_time_axis_view().reveal_dependent_views (*rv);
823 } else if (changed_tracks && dest_rtv->playlist()) {
824 new_region = RegionFactory::create (rv->region());
827 if (changed_tracks || _copy) {
829 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
836 _editor->latest_regionviews.clear ();
838 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
840 insert_result = modified_playlists.insert (to_playlist);
842 if (insert_result.second) {
843 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
846 to_playlist->add_region (new_region, where);
850 if (!_editor->latest_regionviews.empty()) {
851 // XXX why just the first one ? we only expect one
852 // commented out in nick_m's canvas reworking. is that intended?
853 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
854 new_views.push_back (_editor->latest_regionviews.front());
859 motion on the same track. plonk the previously reparented region
860 back to its original canvas group (its streamview).
861 No need to do anything for copies as they are fake regions which will be deleted.
864 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
865 rv->get_canvas_group()->property_y() = 0;
867 /* just change the model */
869 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
871 insert_result = modified_playlists.insert (playlist);
873 if (insert_result.second) {
874 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
876 /* freeze to avoid lots of relayering in the case of a multi-region drag */
877 frozen_insert_result = frozen_playlists.insert(playlist);
879 if (frozen_insert_result.second) {
883 rv->region()->set_position (where, (void*) this);
886 if (changed_tracks && !_copy) {
888 /* get the playlist where this drag started. we can't use rv->region()->playlist()
889 because we may have copied the region and it has not been attached to a playlist.
892 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
893 ds = source_tv->get_diskstream();
894 from_playlist = ds->playlist();
898 assert (from_playlist);
900 /* moved to a different audio track, without copying */
902 /* the region that used to be in the old playlist is not
903 moved to the new one - we use a copy of it. as a result,
904 any existing editor for the region should no longer be
908 rv->hide_region_editor();
909 rv->fake_set_opaque (false);
911 /* remove the region from the old playlist */
913 insert_result = modified_playlists.insert (from_playlist);
915 if (insert_result.second) {
916 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
919 from_playlist->remove_region (rv->region());
921 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
922 was selected in all of them, then removing it from a playlist will have removed all
923 trace of it from the selection (i.e. there were N regions selected, we removed 1,
924 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
925 corresponding regionview, and the selection is now empty).
927 this could have invalidated any and all iterators into the region selection.
929 the heuristic we use here is: if the region selection is empty, break out of the loop
930 here. if the region selection is not empty, then restart the loop because we know that
931 we must have removed at least the region(view) we've just been working on as well as any
932 that we processed on previous iterations.
934 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
938 if (_views.empty()) {
949 copies.push_back (rv);
953 if (new_views.empty()) {
955 /* the region(view)s that are being dragged around are copies and do not
956 belong to any track. remove them from our list
962 _primary = _views.front ();
965 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
970 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
971 _editor->session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
974 _editor->commit_reversible_command ();
976 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
983 RegionMoveDrag::x_move_allowed () const
985 if (Config->get_edit_mode() == Lock) {
987 return !_x_constrained;
989 /* in locked edit mode, reverse the usual meaning of _x_constrained */
990 return _x_constrained;
994 return !_x_constrained;
998 RegionInsertDrag::x_move_allowed () const
1000 if (Config->get_edit_mode() == Lock) {
1001 return _x_constrained;
1004 return !_x_constrained;
1008 RegionMotionDrag::copy_regions (GdkEvent* event)
1010 /* duplicate the regionview(s) and region(s) */
1012 list<RegionView*> new_regionviews;
1014 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1016 RegionView* rv = (*i);
1017 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1018 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1020 const boost::shared_ptr<const Region> original = rv->region();
1021 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1025 boost::shared_ptr<AudioRegion> audioregion_copy
1026 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1027 nrv = new AudioRegionView (*arv, audioregion_copy);
1029 boost::shared_ptr<MidiRegion> midiregion_copy
1030 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1031 nrv = new MidiRegionView (*mrv, midiregion_copy);
1036 nrv->get_canvas_group()->show ();
1037 new_regionviews.push_back (nrv);
1040 if (new_regionviews.empty()) {
1044 /* reflect the fact that we are dragging the copies */
1046 _primary = new_regionviews.front();
1047 _views = new_regionviews;
1049 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1052 sync the canvas to what we think is its current state
1053 without it, the canvas seems to
1054 "forget" to update properly after the upcoming reparent()
1055 ..only if the mouse is in rapid motion at the time of the grab.
1056 something to do with regionview creation raking so long?
1058 _editor->update_canvas_now();
1062 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1064 /* Which trackview is this ? */
1066 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1067 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1068 (*layer) = tvp.second;
1070 if (*tv && (*tv)->layer_display() == Overlaid) {
1074 /* The region motion is only processed if the pointer is over
1078 if (!(*tv) || !(*tv)->is_track()) {
1079 /* To make sure we hide the verbose canvas cursor when the mouse is
1080 not held over and audiotrack.
1082 _editor->hide_verbose_canvas_cursor ();
1089 /** @param new_order New track order.
1090 * @param old_order Old track order.
1091 * @param visible_y_low Lowest visible order.
1092 * @return true if y movement should not happen, otherwise false.
1095 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1097 if (new_order != old_order) {
1099 /* this isn't the pointer track */
1103 /* moving up the canvas */
1104 if ( (new_order - y_span) >= tavs.visible_y_low) {
1108 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1109 int32_t visible_tracks = 0;
1110 while (visible_tracks < y_span ) {
1112 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1113 /* passing through a hidden track */
1118 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1119 /* moving to a non-track; disallow */
1125 /* moving beyond the lowest visible track; disallow */
1129 } else if (y_span < 0) {
1131 /* moving down the canvas */
1132 if ((new_order - y_span) <= tavs.visible_y_high) {
1134 int32_t visible_tracks = 0;
1136 while (visible_tracks > y_span ) {
1139 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1140 /* passing through a hidden track */
1145 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1146 /* moving to a non-track; disallow */
1153 /* moving beyond the highest visible track; disallow */
1160 /* this is the pointer's track */
1162 if ((new_order - y_span) > tavs.visible_y_high) {
1163 /* we will overflow */
1165 } else if ((new_order - y_span) < tavs.visible_y_low) {
1166 /* we will overflow */
1175 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1176 : RegionMotionDrag (e, i, p, v, b),
1179 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1181 _dest_trackview = tv;
1182 if (tv->layer_display() == Overlaid) {
1185 _dest_layer = _primary->region()->layer ();
1189 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1190 if (rtv && rtv->is_track()) {
1191 speed = rtv->get_diskstream()->speed ();
1194 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1198 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1200 RegionMotionDrag::start_grab (event, c);
1202 _pointer_frame_offset = _grab_frame - _last_frame_position;
1205 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1206 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1208 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1209 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1211 _primary = v->view()->create_region_view (r, false, false);
1213 _primary->get_canvas_group()->show ();
1214 _primary->set_position (pos, 0);
1215 _views.push_back (_primary);
1217 _last_frame_position = pos;
1219 _item = _primary->get_canvas_group ();
1220 _dest_trackview = v;
1221 _dest_layer = _primary->region()->layer ();
1224 map<RegionView*, RouteTimeAxisView*>
1225 RegionMotionDrag::find_time_axis_views ()
1227 map<RegionView*, RouteTimeAxisView*> tav;
1229 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1231 double ix1, ix2, iy1, iy2;
1232 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1233 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1234 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1236 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1237 tav[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
1245 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1247 _editor->update_canvas_now ();
1249 map<RegionView*, RouteTimeAxisView*> final = find_time_axis_views ();
1251 RouteTimeAxisView* dest_rtv = final[_primary];
1253 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1254 _primary->get_canvas_group()->property_y() = 0;
1256 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1258 _editor->begin_reversible_command (_("insert region"));
1259 XMLNode& before = playlist->get_state ();
1260 playlist->add_region (_primary->region (), _last_frame_position);
1261 _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1262 _editor->commit_reversible_command ();
1269 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1270 : RegionMoveDrag (e, i, p, v, false, false)
1275 struct RegionSelectionByPosition {
1276 bool operator() (RegionView*a, RegionView* b) {
1277 return a->region()->position () < b->region()->position();
1282 RegionSpliceDrag::motion (GdkEvent* /*event*/, bool)
1284 RouteTimeAxisView* tv;
1287 if (!check_possible (&tv, &layer)) {
1293 if (_current_pointer_x - _grab_x > 0) {
1299 RegionSelection copy (_editor->selection->regions);
1301 RegionSelectionByPosition cmp;
1304 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1306 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1312 boost::shared_ptr<Playlist> playlist;
1314 if ((playlist = atv->playlist()) == 0) {
1318 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1323 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1327 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1333 playlist->shuffle ((*i)->region(), dir);
1335 _grab_x = _current_pointer_x;
1340 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1346 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1354 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1356 _dest_trackview = _view;
1358 Drag::start_grab (event);
1363 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1366 // TODO: create region-create-drag region view here
1369 // TODO: resize region-create-drag region view here
1373 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1375 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1380 const boost::shared_ptr<MidiDiskstream> diskstream =
1381 boost::dynamic_pointer_cast<MidiDiskstream>(mtv->view()->trackview().track()->diskstream());
1384 warning << "Cannot create non-MIDI region" << endl;
1388 if (!movement_occurred) {
1389 _editor->begin_reversible_command (_("create region"));
1390 XMLNode &before = mtv->playlist()->get_state();
1392 nframes64_t start = _grab_frame;
1393 _editor->snap_to (start, -1);
1394 const Meter& m = _editor->session->tempo_map().meter_at(start);
1395 const Tempo& t = _editor->session->tempo_map().tempo_at(start);
1396 double length = floor (m.frames_per_bar(t, _editor->session->frame_rate()));
1398 boost::shared_ptr<Source> src = _editor->session->create_midi_source_for_session(*diskstream.get());
1400 mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>
1401 (RegionFactory::create(src, 0, (nframes_t) length,
1402 PBD::basename_nosuffix(src->name()))), start);
1403 XMLNode &after = mtv->playlist()->get_state();
1404 _editor->session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
1405 _editor->commit_reversible_command();
1408 motion (event, false);
1409 // TODO: create region-create-drag region here
1417 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1423 RegionGainDrag::finished (GdkEvent *, bool)
1428 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1429 : RegionDrag (e, i, p, v)
1435 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1438 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1439 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1441 if (tv && tv->is_track()) {
1442 speed = tv->get_diskstream()->speed();
1445 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1446 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1447 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1449 Drag::start_grab (event, _editor->trimmer_cursor);
1451 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1452 _operation = ContentsTrim;
1454 /* These will get overridden for a point trim.*/
1455 if (_current_pointer_frame < (region_start + region_length/2)) {
1456 /* closer to start */
1457 _operation = StartTrim;
1458 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1460 _operation = EndTrim;
1464 switch (_operation) {
1466 _editor->show_verbose_time_cursor (region_start, 10);
1469 _editor->show_verbose_time_cursor (region_end, 10);
1472 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1478 TrimDrag::motion (GdkEvent* event, bool first_move)
1480 RegionView* rv = _primary;
1481 nframes64_t frame_delta = 0;
1483 bool left_direction;
1484 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1486 /* snap modifier works differently here..
1487 its' current state has to be passed to the
1488 various trim functions in order to work properly
1492 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1493 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1494 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1496 if (tv && tv->is_track()) {
1497 speed = tv->get_diskstream()->speed();
1500 if (_last_pointer_frame > _current_pointer_frame) {
1501 left_direction = true;
1503 left_direction = false;
1507 _editor->snap_to (_current_pointer_frame);
1514 switch (_operation) {
1516 trim_type = "Region start trim";
1519 trim_type = "Region end trim";
1522 trim_type = "Region content trim";
1526 _editor->begin_reversible_command (trim_type);
1528 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1529 (*i)->fake_set_opaque(false);
1530 (*i)->region()->freeze ();
1532 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1535 arv->temporarily_hide_envelope ();
1538 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1539 insert_result = _editor->motion_frozen_playlists.insert (pl);
1541 if (insert_result.second) {
1542 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1548 if (_current_pointer_frame == _last_pointer_frame) {
1552 if (left_direction) {
1553 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1555 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1558 bool non_overlap_trim = false;
1560 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1561 non_overlap_trim = true;
1564 switch (_operation) {
1566 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1570 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1571 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1577 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1581 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1582 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1589 bool swap_direction = false;
1591 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1592 swap_direction = true;
1595 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1597 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1603 switch (_operation) {
1605 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1608 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1611 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1615 _last_pointer_frame = _current_pointer_frame;
1620 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1622 if (movement_occurred) {
1623 motion (event, false);
1625 if (!_editor->selection->selected (_primary)) {
1626 _editor->thaw_region_after_trim (*_primary);
1629 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1630 _editor->thaw_region_after_trim (**i);
1631 (*i)->fake_set_opaque (true);
1635 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1637 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1640 _editor->motion_frozen_playlists.clear ();
1642 _editor->commit_reversible_command();
1644 /* no mouse movement */
1645 _editor->point_trim (event);
1649 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1653 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1658 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1661 // create a dummy marker for visual representation of moving the copy.
1662 // The actual copying is not done before we reach the finish callback.
1664 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1665 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1666 *new MeterSection (_marker->meter()));
1668 _item = &new_marker->the_item ();
1669 _marker = new_marker;
1673 MetricSection& section (_marker->meter());
1675 if (!section.movable()) {
1681 Drag::start_grab (event, cursor);
1683 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1685 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1689 MeterMarkerDrag::motion (GdkEvent* event, bool)
1691 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1693 if (adjusted_frame == _last_pointer_frame) {
1697 _marker->set_position (adjusted_frame);
1699 _last_pointer_frame = adjusted_frame;
1701 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1705 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1707 if (!movement_occurred) {
1711 motion (event, false);
1715 TempoMap& map (_editor->session->tempo_map());
1716 map.bbt_time (_last_pointer_frame, when);
1718 if (_copy == true) {
1719 _editor->begin_reversible_command (_("copy meter mark"));
1720 XMLNode &before = map.get_state();
1721 map.add_meter (_marker->meter(), when);
1722 XMLNode &after = map.get_state();
1723 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1724 _editor->commit_reversible_command ();
1726 // delete the dummy marker we used for visual representation of copying.
1727 // a new visual marker will show up automatically.
1730 _editor->begin_reversible_command (_("move meter mark"));
1731 XMLNode &before = map.get_state();
1732 map.move_meter (_marker->meter(), when);
1733 XMLNode &after = map.get_state();
1734 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1735 _editor->commit_reversible_command ();
1739 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1743 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1748 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1753 // create a dummy marker for visual representation of moving the copy.
1754 // The actual copying is not done before we reach the finish callback.
1756 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1757 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1758 *new TempoSection (_marker->tempo()));
1760 _item = &new_marker->the_item ();
1761 _marker = new_marker;
1765 MetricSection& section (_marker->tempo());
1767 if (!section.movable()) {
1772 Drag::start_grab (event, cursor);
1774 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1775 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1779 TempoMarkerDrag::motion (GdkEvent* event, bool)
1781 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1783 if (adjusted_frame == _last_pointer_frame) {
1787 /* OK, we've moved far enough to make it worth actually move the thing. */
1789 _marker->set_position (adjusted_frame);
1791 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1793 _last_pointer_frame = adjusted_frame;
1797 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1799 if (!movement_occurred) {
1803 motion (event, false);
1807 TempoMap& map (_editor->session->tempo_map());
1808 map.bbt_time (_last_pointer_frame, when);
1810 if (_copy == true) {
1811 _editor->begin_reversible_command (_("copy tempo mark"));
1812 XMLNode &before = map.get_state();
1813 map.add_tempo (_marker->tempo(), when);
1814 XMLNode &after = map.get_state();
1815 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1816 _editor->commit_reversible_command ();
1818 // delete the dummy marker we used for visual representation of copying.
1819 // a new visual marker will show up automatically.
1822 _editor->begin_reversible_command (_("move tempo mark"));
1823 XMLNode &before = map.get_state();
1824 map.move_tempo (_marker->tempo(), when);
1825 XMLNode &after = map.get_state();
1826 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1827 _editor->commit_reversible_command ();
1832 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1836 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1841 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1843 Drag::start_grab (event, c);
1847 nframes64_t where = _editor->event_frame (event, 0, 0);
1849 _editor->snap_to (where);
1850 _editor->playhead_cursor->set_position (where);
1854 if (_cursor == _editor->playhead_cursor) {
1855 _editor->_dragging_playhead = true;
1857 if (_editor->session && _was_rolling && _stop) {
1858 _editor->session->request_stop ();
1861 if (_editor->session && _editor->session->is_auditioning()) {
1862 _editor->session->cancel_audition ();
1866 _pointer_frame_offset = _grab_frame - _cursor->current_frame;
1868 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1872 CursorDrag::motion (GdkEvent* event, bool)
1874 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1876 if (adjusted_frame == _last_pointer_frame) {
1880 _cursor->set_position (adjusted_frame);
1882 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1885 _editor->update_canvas_now ();
1887 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1889 _last_pointer_frame = adjusted_frame;
1893 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1895 _editor->_dragging_playhead = false;
1897 if (!movement_occurred && _stop) {
1901 motion (event, false);
1903 if (_item == &_editor->playhead_cursor->canvas_item) {
1904 if (_editor->session) {
1905 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1906 _editor->_pending_locate_request = true;
1911 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1912 : RegionDrag (e, i, p, v)
1918 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1920 Drag::start_grab (event, cursor);
1922 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1923 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1925 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1929 FadeInDrag::motion (GdkEvent* event, bool)
1931 nframes64_t fade_length;
1933 nframes64_t const pos = adjusted_current_frame (event);
1935 boost::shared_ptr<Region> region = _primary->region ();
1937 if (pos < (region->position() + 64)) {
1938 fade_length = 64; // this should be a minimum defined somewhere
1939 } else if (pos > region->last_frame()) {
1940 fade_length = region->length();
1942 fade_length = pos - region->position();
1945 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1947 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1953 tmp->reset_fade_in_shape_width (fade_length);
1956 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1960 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1962 if (!movement_occurred) {
1966 nframes64_t fade_length;
1968 nframes64_t const pos = adjusted_current_frame (event);
1970 boost::shared_ptr<Region> region = _primary->region ();
1972 if (pos < (region->position() + 64)) {
1973 fade_length = 64; // this should be a minimum defined somewhere
1974 } else if (pos > region->last_frame()) {
1975 fade_length = region->length();
1977 fade_length = pos - region->position();
1980 _editor->begin_reversible_command (_("change fade in length"));
1982 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1984 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1990 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
1991 XMLNode &before = alist->get_state();
1993 tmp->audio_region()->set_fade_in_length (fade_length);
1994 tmp->audio_region()->set_fade_in_active (true);
1996 XMLNode &after = alist->get_state();
1997 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2000 _editor->commit_reversible_command ();
2003 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2004 : RegionDrag (e, i, p, v)
2010 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2012 Drag::start_grab (event, cursor);
2014 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2015 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2017 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2021 FadeOutDrag::motion (GdkEvent* event, bool)
2023 nframes64_t fade_length;
2025 nframes64_t const pos = adjusted_current_frame (event);
2027 boost::shared_ptr<Region> region = _primary->region ();
2029 if (pos > (region->last_frame() - 64)) {
2030 fade_length = 64; // this should really be a minimum fade defined somewhere
2032 else if (pos < region->position()) {
2033 fade_length = region->length();
2036 fade_length = region->last_frame() - pos;
2039 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2041 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2047 tmp->reset_fade_out_shape_width (fade_length);
2050 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2054 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2056 if (!movement_occurred) {
2060 nframes64_t fade_length;
2062 nframes64_t const pos = adjusted_current_frame (event);
2064 boost::shared_ptr<Region> region = _primary->region ();
2066 if (pos > (region->last_frame() - 64)) {
2067 fade_length = 64; // this should really be a minimum fade defined somewhere
2069 else if (pos < region->position()) {
2070 fade_length = region->length();
2073 fade_length = region->last_frame() - pos;
2076 _editor->begin_reversible_command (_("change fade out length"));
2078 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2080 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2086 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2087 XMLNode &before = alist->get_state();
2089 tmp->audio_region()->set_fade_out_length (fade_length);
2090 tmp->audio_region()->set_fade_out_active (true);
2092 XMLNode &after = alist->get_state();
2093 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2096 _editor->commit_reversible_command ();
2099 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2102 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2105 _points.push_back (Gnome::Art::Point (0, 0));
2106 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2108 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2109 _line->property_width_pixels() = 1;
2110 _line->property_points () = _points;
2113 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2116 MarkerDrag::~MarkerDrag ()
2118 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2124 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2126 Drag::start_grab (event, cursor);
2130 Location *location = _editor->find_location_from_marker (_marker, is_start);
2131 _editor->_dragging_edit_point = true;
2133 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2135 update_item (location);
2137 // _drag_line->show();
2138 // _line->raise_to_top();
2141 _editor->show_verbose_time_cursor (location->start(), 10);
2143 _editor->show_verbose_time_cursor (location->end(), 10);
2146 Selection::Operation op = Keyboard::selection_type (event->button.state);
2149 case Selection::Toggle:
2150 _editor->selection->toggle (_marker);
2152 case Selection::Set:
2153 if (!_editor->selection->selected (_marker)) {
2154 _editor->selection->set (_marker);
2157 case Selection::Extend:
2159 Locations::LocationList ll;
2160 list<Marker*> to_add;
2162 _editor->selection->markers.range (s, e);
2163 s = min (_marker->position(), s);
2164 e = max (_marker->position(), e);
2167 if (e < max_frames) {
2170 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2171 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2172 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2175 to_add.push_back (lm->start);
2178 to_add.push_back (lm->end);
2182 if (!to_add.empty()) {
2183 _editor->selection->add (to_add);
2187 case Selection::Add:
2188 _editor->selection->add (_marker);
2192 /* set up copies for us to manipulate during the drag */
2194 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2195 Location *l = _editor->find_location_from_marker (*i, is_start);
2196 _copied_locations.push_back (new Location (*l));
2201 MarkerDrag::motion (GdkEvent* event, bool)
2203 nframes64_t f_delta = 0;
2205 bool move_both = false;
2207 Location *real_location;
2208 Location *copy_location = 0;
2210 nframes64_t const newframe = adjusted_current_frame (event);
2212 nframes64_t next = newframe;
2214 if (_current_pointer_frame == _last_pointer_frame) {
2218 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2222 MarkerSelection::iterator i;
2223 list<Location*>::iterator x;
2225 /* find the marker we're dragging, and compute the delta */
2227 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2228 x != _copied_locations.end() && i != _editor->selection->markers.end();
2234 if (marker == _marker) {
2236 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2241 if (real_location->is_mark()) {
2242 f_delta = newframe - copy_location->start();
2246 switch (marker->type()) {
2248 case Marker::LoopStart:
2249 case Marker::PunchIn:
2250 f_delta = newframe - copy_location->start();
2254 case Marker::LoopEnd:
2255 case Marker::PunchOut:
2256 f_delta = newframe - copy_location->end();
2259 /* what kind of marker is this ? */
2267 if (i == _editor->selection->markers.end()) {
2268 /* hmm, impossible - we didn't find the dragged marker */
2272 /* now move them all */
2274 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2275 x != _copied_locations.end() && i != _editor->selection->markers.end();
2281 /* call this to find out if its the start or end */
2283 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2287 if (real_location->locked()) {
2291 if (copy_location->is_mark()) {
2295 copy_location->set_start (copy_location->start() + f_delta);
2299 nframes64_t new_start = copy_location->start() + f_delta;
2300 nframes64_t new_end = copy_location->end() + f_delta;
2302 if (is_start) { // start-of-range marker
2305 copy_location->set_start (new_start);
2306 copy_location->set_end (new_end);
2307 } else if (new_start < copy_location->end()) {
2308 copy_location->set_start (new_start);
2310 _editor->snap_to (next, 1, true);
2311 copy_location->set_end (next);
2312 copy_location->set_start (newframe);
2315 } else { // end marker
2318 copy_location->set_end (new_end);
2319 copy_location->set_start (new_start);
2320 } else if (new_end > copy_location->start()) {
2321 copy_location->set_end (new_end);
2322 } else if (newframe > 0) {
2323 _editor->snap_to (next, -1, true);
2324 copy_location->set_start (next);
2325 copy_location->set_end (newframe);
2330 update_item (copy_location);
2332 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2335 lm->set_position (copy_location->start(), copy_location->end());
2339 _last_pointer_frame = _current_pointer_frame;
2341 assert (!_copied_locations.empty());
2343 _editor->edit_point_clock.set (_copied_locations.front()->start());
2344 _editor->show_verbose_time_cursor (newframe, 10);
2347 _editor->update_canvas_now ();
2349 _editor->edit_point_clock.set (copy_location->start());
2353 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2355 if (!movement_occurred) {
2357 /* just a click, do nothing but finish
2358 off the selection process
2361 Selection::Operation op = Keyboard::selection_type (event->button.state);
2364 case Selection::Set:
2365 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2366 _editor->selection->set (_marker);
2370 case Selection::Toggle:
2371 case Selection::Extend:
2372 case Selection::Add:
2379 _editor->_dragging_edit_point = false;
2381 _editor->begin_reversible_command ( _("move marker") );
2382 XMLNode &before = _editor->session->locations()->get_state();
2384 MarkerSelection::iterator i;
2385 list<Location*>::iterator x;
2388 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2389 x != _copied_locations.end() && i != _editor->selection->markers.end();
2392 Location * location = _editor->find_location_from_marker (*i, is_start);
2396 if (location->locked()) {
2400 if (location->is_mark()) {
2401 location->set_start ((*x)->start());
2403 location->set ((*x)->start(), (*x)->end());
2408 XMLNode &after = _editor->session->locations()->get_state();
2409 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
2410 _editor->commit_reversible_command ();
2416 MarkerDrag::update_item (Location* location)
2418 double const x1 = _editor->frame_to_pixel (location->start());
2420 _points.front().set_x(x1);
2421 _points.back().set_x(x1);
2422 _line->property_points() = _points;
2425 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2427 _cumulative_x_drag (0),
2428 _cumulative_y_drag (0)
2430 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2436 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2438 Drag::start_grab (event, _editor->fader_cursor);
2440 // start the grab at the center of the control point so
2441 // the point doesn't 'jump' to the mouse after the first drag
2442 _grab_x = _point->get_x();
2443 _grab_y = _point->get_y();
2445 _point->line().parent_group().i2w (_grab_x, _grab_y);
2446 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2448 _grab_frame = _editor->pixel_to_frame (_grab_x);
2450 _point->line().start_drag (_point, _grab_frame, 0);
2452 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2453 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2454 _current_pointer_x + 10, _current_pointer_y + 10);
2456 _editor->show_verbose_canvas_cursor ();
2460 ControlPointDrag::motion (GdkEvent* event, bool)
2462 double dx = _current_pointer_x - _last_pointer_x;
2463 double dy = _current_pointer_y - _last_pointer_y;
2465 if (event->button.state & Keyboard::SecondaryModifier) {
2470 double cx = _grab_x + _cumulative_x_drag + dx;
2471 double cy = _grab_y + _cumulative_y_drag + dy;
2473 // calculate zero crossing point. back off by .01 to stay on the
2474 // positive side of zero
2476 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2477 _point->line().parent_group().i2w(_unused, zero_gain_y);
2479 // make sure we hit zero when passing through
2480 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2481 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2485 if (_x_constrained) {
2488 if (_y_constrained) {
2492 _cumulative_x_drag = cx - _grab_x;
2493 _cumulative_y_drag = cy - _grab_y;
2495 _point->line().parent_group().w2i (cx, cy);
2499 cy = min ((double) _point->line().height(), cy);
2501 //translate cx to frames
2502 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2504 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !_x_constrained) {
2505 _editor->snap_to (cx_frames);
2508 float const fraction = 1.0 - (cy / _point->line().height());
2510 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2512 _point->line().point_drag (*_point, cx_frames, fraction, push);
2514 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2518 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2520 if (!movement_occurred) {
2524 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2525 _editor->reset_point_selection ();
2529 motion (event, false);
2531 _point->line().end_drag (_point);
2535 ControlPointDrag::active (Editing::MouseMode m)
2537 if (m == Editing::MouseGain) {
2538 /* always active in mouse gain */
2542 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2543 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2546 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2549 _cumulative_y_drag (0)
2554 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2556 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2559 _item = &_line->grab_item ();
2561 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2562 origin, and ditto for y.
2565 double cx = event->button.x;
2566 double cy = event->button.y;
2568 _line->parent_group().w2i (cx, cy);
2570 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2572 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2573 /* no adjacent points */
2577 Drag::start_grab (event, _editor->fader_cursor);
2579 /* store grab start in parent frame */
2584 double fraction = 1.0 - (cy / _line->height());
2586 _line->start_drag (0, _grab_frame, fraction);
2588 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2589 _current_pointer_x + 10, _current_pointer_y + 10);
2591 _editor->show_verbose_canvas_cursor ();
2595 LineDrag::motion (GdkEvent* event, bool)
2597 double dy = _current_pointer_y - _last_pointer_y;
2599 if (event->button.state & Keyboard::SecondaryModifier) {
2603 double cy = _grab_y + _cumulative_y_drag + dy;
2605 _cumulative_y_drag = cy - _grab_y;
2608 cy = min ((double) _line->height(), cy);
2610 double const fraction = 1.0 - (cy / _line->height());
2614 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2620 _line->line_drag (_before, _after, fraction, push);
2622 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2626 LineDrag::finished (GdkEvent* event, bool)
2628 motion (event, false);
2629 _line->end_drag (0);
2633 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2635 Drag::start_grab (event);
2636 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2640 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2647 /* use a bigger drag threshold than the default */
2649 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2653 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && Config->get_rubberbanding_snaps_to_grid()) {
2655 _editor->snap_to (_grab_frame);
2657 _editor->snap_to (_current_pointer_frame);
2660 /* base start and end on initial click position */
2662 if (_current_pointer_frame < _grab_frame) {
2663 start = _current_pointer_frame;
2666 end = _current_pointer_frame;
2667 start = _grab_frame;
2670 if (_current_pointer_y < _grab_y) {
2671 y1 = _current_pointer_y;
2674 y2 = _current_pointer_y;
2679 if (start != end || y1 != y2) {
2681 double x1 = _editor->frame_to_pixel (start);
2682 double x2 = _editor->frame_to_pixel (end);
2684 _editor->rubberband_rect->property_x1() = x1;
2685 _editor->rubberband_rect->property_y1() = y1;
2686 _editor->rubberband_rect->property_x2() = x2;
2687 _editor->rubberband_rect->property_y2() = y2;
2689 _editor->rubberband_rect->show();
2690 _editor->rubberband_rect->raise_to_top();
2692 _last_pointer_frame = _current_pointer_frame;
2694 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2699 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2701 if (movement_occurred) {
2703 motion (event, false);
2706 if (_current_pointer_y < _grab_y) {
2707 y1 = _current_pointer_y;
2710 y2 = _current_pointer_y;
2715 Selection::Operation op = Keyboard::selection_type (event->button.state);
2718 _editor->begin_reversible_command (_("rubberband selection"));
2720 if (_grab_frame < _last_pointer_frame) {
2721 committed = _editor->select_all_within (_grab_frame, _last_pointer_frame, y1, y2, _editor->track_views, op);
2723 committed = _editor->select_all_within (_last_pointer_frame, _grab_frame, y1, y2, _editor->track_views, op);
2727 _editor->commit_reversible_command ();
2731 if (!getenv("ARDOUR_SAE")) {
2732 _editor->selection->clear_tracks();
2734 _editor->selection->clear_regions();
2735 _editor->selection->clear_points ();
2736 _editor->selection->clear_lines ();
2739 _editor->rubberband_rect->hide();
2743 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2745 Drag::start_grab (event);
2747 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2751 TimeFXDrag::motion (GdkEvent* event, bool)
2753 RegionView* rv = _primary;
2755 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2756 _editor->snap_to (_current_pointer_frame);
2759 if (_current_pointer_frame == _last_pointer_frame) {
2763 if (_current_pointer_frame > rv->region()->position()) {
2764 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2767 _last_pointer_frame = _current_pointer_frame;
2769 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2773 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2775 _primary->get_time_axis_view().hide_timestretch ();
2777 if (!movement_occurred) {
2781 if (_last_pointer_frame < _primary->region()->position()) {
2782 /* backwards drag of the left edge - not usable */
2786 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2788 float percentage = (double) newlen / (double) _primary->region()->length();
2790 #ifndef USE_RUBBERBAND
2791 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2792 if (_primary->region()->data_type() == DataType::AUDIO) {
2793 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2797 _editor->begin_reversible_command (_("timestretch"));
2799 // XXX how do timeFX on multiple regions ?
2804 if (_editor->time_stretch (rs, percentage) == 0) {
2805 _editor->session->commit_reversible_command ();
2810 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2812 Drag::start_grab (event);
2816 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2822 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2824 if (movement_occurred && _editor->session) {
2825 /* make sure we stop */
2826 _editor->session->request_transport_speed (0.0);
2830 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2839 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2841 nframes64_t start = 0;
2842 nframes64_t end = 0;
2844 if (_editor->session == 0) {
2848 Gdk::Cursor* cursor = 0;
2850 switch (_operation) {
2851 case CreateSelection:
2852 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2857 cursor = _editor->selector_cursor;
2858 Drag::start_grab (event, cursor);
2861 case SelectionStartTrim:
2862 if (_editor->clicked_axisview) {
2863 _editor->clicked_axisview->order_selection_trims (_item, true);
2865 Drag::start_grab (event, cursor);
2866 cursor = _editor->trimmer_cursor;
2867 start = _editor->selection->time[_editor->clicked_selection].start;
2868 _pointer_frame_offset = _grab_frame - start;
2871 case SelectionEndTrim:
2872 if (_editor->clicked_axisview) {
2873 _editor->clicked_axisview->order_selection_trims (_item, false);
2875 Drag::start_grab (event, cursor);
2876 cursor = _editor->trimmer_cursor;
2877 end = _editor->selection->time[_editor->clicked_selection].end;
2878 _pointer_frame_offset = _grab_frame - end;
2882 start = _editor->selection->time[_editor->clicked_selection].start;
2883 Drag::start_grab (event, cursor);
2884 _pointer_frame_offset = _grab_frame - start;
2888 if (_operation == SelectionMove) {
2889 _editor->show_verbose_time_cursor (start, 10);
2891 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2896 SelectionDrag::motion (GdkEvent* event, bool first_move)
2898 nframes64_t start = 0;
2899 nframes64_t end = 0;
2902 nframes64_t const pending_position = adjusted_current_frame (event);
2904 /* only alter selection if the current frame is
2905 different from the last frame position (adjusted)
2908 if (pending_position == _last_pointer_frame) {
2912 switch (_operation) {
2913 case CreateSelection:
2916 _editor->snap_to (_grab_frame);
2919 if (pending_position < _grab_frame) {
2920 start = pending_position;
2923 end = pending_position;
2924 start = _grab_frame;
2927 /* first drag: Either add to the selection
2928 or create a new selection->
2933 _editor->begin_reversible_command (_("range selection"));
2936 /* adding to the selection */
2937 _editor->clicked_selection = _editor->selection->add (start, end);
2940 /* new selection-> */
2941 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2946 case SelectionStartTrim:
2949 _editor->begin_reversible_command (_("trim selection start"));
2952 start = _editor->selection->time[_editor->clicked_selection].start;
2953 end = _editor->selection->time[_editor->clicked_selection].end;
2955 if (pending_position > end) {
2958 start = pending_position;
2962 case SelectionEndTrim:
2965 _editor->begin_reversible_command (_("trim selection end"));
2968 start = _editor->selection->time[_editor->clicked_selection].start;
2969 end = _editor->selection->time[_editor->clicked_selection].end;
2971 if (pending_position < start) {
2974 end = pending_position;
2982 _editor->begin_reversible_command (_("move selection"));
2985 start = _editor->selection->time[_editor->clicked_selection].start;
2986 end = _editor->selection->time[_editor->clicked_selection].end;
2988 length = end - start;
2990 start = pending_position;
2991 _editor->snap_to (start);
2993 end = start + length;
2998 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
2999 _editor->start_canvas_autoscroll (1, 0);
3003 _editor->selection->replace (_editor->clicked_selection, start, end);
3006 _last_pointer_frame = pending_position;
3008 if (_operation == SelectionMove) {
3009 _editor->show_verbose_time_cursor(start, 10);
3011 _editor->show_verbose_time_cursor(pending_position, 10);
3016 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3018 if (movement_occurred) {
3019 motion (event, false);
3020 /* XXX this is not object-oriented programming at all. ick */
3021 if (_editor->selection->time.consolidate()) {
3022 _editor->selection->TimeChanged ();
3024 _editor->commit_reversible_command ();
3026 /* just a click, no pointer movement.*/
3028 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3030 _editor->selection->clear_time();
3035 /* XXX what happens if its a music selection? */
3036 _editor->session->set_audio_range (_editor->selection->time);
3037 _editor->stop_canvas_autoscroll ();
3040 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3045 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3046 _drag_rect->hide ();
3048 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3049 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3053 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3055 if (_editor->session == 0) {
3059 Gdk::Cursor* cursor = 0;
3061 if (!_editor->temp_location) {
3062 _editor->temp_location = new Location;
3065 switch (_operation) {
3066 case CreateRangeMarker:
3067 case CreateTransportMarker:
3068 case CreateCDMarker:
3070 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3075 cursor = _editor->selector_cursor;
3079 Drag::start_grab (event, cursor);
3081 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3085 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3087 nframes64_t start = 0;
3088 nframes64_t end = 0;
3089 ArdourCanvas::SimpleRect *crect;
3091 switch (_operation) {
3092 case CreateRangeMarker:
3093 crect = _editor->range_bar_drag_rect;
3095 case CreateTransportMarker:
3096 crect = _editor->transport_bar_drag_rect;
3098 case CreateCDMarker:
3099 crect = _editor->cd_marker_bar_drag_rect;
3102 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3107 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3108 _editor->snap_to (_current_pointer_frame);
3111 /* only alter selection if the current frame is
3112 different from the last frame position.
3115 if (_current_pointer_frame == _last_pointer_frame) {
3119 switch (_operation) {
3120 case CreateRangeMarker:
3121 case CreateTransportMarker:
3122 case CreateCDMarker:
3124 _editor->snap_to (_grab_frame);
3127 if (_current_pointer_frame < _grab_frame) {
3128 start = _current_pointer_frame;
3131 end = _current_pointer_frame;
3132 start = _grab_frame;
3135 /* first drag: Either add to the selection
3136 or create a new selection.
3141 _editor->temp_location->set (start, end);
3145 update_item (_editor->temp_location);
3147 //_drag_rect->raise_to_top();
3153 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3154 _editor->start_canvas_autoscroll (1, 0);
3158 _editor->temp_location->set (start, end);
3160 double x1 = _editor->frame_to_pixel (start);
3161 double x2 = _editor->frame_to_pixel (end);
3162 crect->property_x1() = x1;
3163 crect->property_x2() = x2;
3165 update_item (_editor->temp_location);
3168 _last_pointer_frame = _current_pointer_frame;
3170 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3175 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3177 Location * newloc = 0;
3181 if (movement_occurred) {
3182 motion (event, false);
3185 switch (_operation) {
3186 case CreateRangeMarker:
3187 case CreateCDMarker:
3189 _editor->begin_reversible_command (_("new range marker"));
3190 XMLNode &before = _editor->session->locations()->get_state();
3191 _editor->session->locations()->next_available_name(rangename,"unnamed");
3192 if (_operation == CreateCDMarker) {
3193 flags = Location::IsRangeMarker | Location::IsCDMarker;
3194 _editor->cd_marker_bar_drag_rect->hide();
3197 flags = Location::IsRangeMarker;
3198 _editor->range_bar_drag_rect->hide();
3200 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3201 _editor->session->locations()->add (newloc, true);
3202 XMLNode &after = _editor->session->locations()->get_state();
3203 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3204 _editor->commit_reversible_command ();
3208 case CreateTransportMarker:
3209 // popup menu to pick loop or punch
3210 _editor->new_transport_marker_context_menu (&event->button, _item);
3214 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3216 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3221 start = _editor->session->locations()->first_mark_before (_grab_frame);
3222 end = _editor->session->locations()->first_mark_after (_grab_frame);
3224 if (end == max_frames) {
3225 end = _editor->session->current_end_frame ();
3229 start = _editor->session->current_start_frame ();
3232 switch (_editor->mouse_mode) {
3234 /* find the two markers on either side and then make the selection from it */
3235 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3239 /* find the two markers on either side of the click and make the range out of it */
3240 _editor->selection->set (0, start, end);
3249 _editor->stop_canvas_autoscroll ();
3255 RangeMarkerBarDrag::update_item (Location* location)
3257 double const x1 = _editor->frame_to_pixel (location->start());
3258 double const x2 = _editor->frame_to_pixel (location->end());
3260 _drag_rect->property_x1() = x1;
3261 _drag_rect->property_x2() = x2;
3265 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3267 Drag::start_grab (event, _editor->zoom_cursor);
3268 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3272 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3277 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3278 _editor->snap_to (_current_pointer_frame);
3281 _editor->snap_to (_grab_frame);
3285 if (_current_pointer_frame == _last_pointer_frame) {
3289 /* base start and end on initial click position */
3290 if (_current_pointer_frame < _grab_frame) {
3291 start = _current_pointer_frame;
3294 end = _current_pointer_frame;
3295 start = _grab_frame;
3301 _editor->zoom_rect->show();
3302 _editor->zoom_rect->raise_to_top();
3305 _editor->reposition_zoom_rect(start, end);
3307 _last_pointer_frame = _current_pointer_frame;
3309 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3314 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3316 if (movement_occurred) {
3317 motion (event, false);
3319 if (_grab_frame < _last_pointer_frame) {
3320 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3322 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3325 _editor->temporal_zoom_to_frame (false, _grab_frame);
3327 temporal_zoom_step (false);
3328 center_screen (_grab_frame);
3332 _editor->zoom_rect->hide();