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 assert ((source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view())));
896 assert ((ds = source_tv->get_diskstream()));
897 assert ((from_playlist = ds->playlist()));
899 /* moved to a different audio track, without copying */
901 /* the region that used to be in the old playlist is not
902 moved to the new one - we use a copy of it. as a result,
903 any existing editor for the region should no longer be
907 rv->hide_region_editor();
908 rv->fake_set_opaque (false);
910 /* remove the region from the old playlist */
912 insert_result = modified_playlists.insert (from_playlist);
914 if (insert_result.second) {
915 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
918 from_playlist->remove_region (rv->region());
920 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
921 was selected in all of them, then removing it from a playlist will have removed all
922 trace of it from the selection (i.e. there were N regions selected, we removed 1,
923 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
924 corresponding regionview, and the selection is now empty).
926 this could have invalidated any and all iterators into the region selection.
928 the heuristic we use here is: if the region selection is empty, break out of the loop
929 here. if the region selection is not empty, then restart the loop because we know that
930 we must have removed at least the region(view) we've just been working on as well as any
931 that we processed on previous iterations.
933 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
937 if (_views.empty()) {
948 copies.push_back (rv);
952 if (new_views.empty()) {
954 /* the region(view)s that are being dragged around are copies and do not
955 belong to any track. remove them from our list
961 _primary = _views.front ();
964 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 ();
977 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
984 RegionMoveDrag::x_move_allowed () const
986 if (Config->get_edit_mode() == Lock) {
988 return !_x_constrained;
990 /* in locked edit mode, reverse the usual meaning of _x_constrained */
991 return _x_constrained;
995 return !_x_constrained;
999 RegionInsertDrag::x_move_allowed () const
1001 if (Config->get_edit_mode() == Lock) {
1002 return _x_constrained;
1005 return !_x_constrained;
1009 RegionMotionDrag::copy_regions (GdkEvent* event)
1011 /* duplicate the regionview(s) and region(s) */
1013 list<RegionView*> new_regionviews;
1015 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1017 RegionView* rv = (*i);
1018 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1019 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1021 const boost::shared_ptr<const Region> original = rv->region();
1022 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1026 boost::shared_ptr<AudioRegion> audioregion_copy
1027 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1028 nrv = new AudioRegionView (*arv, audioregion_copy);
1030 boost::shared_ptr<MidiRegion> midiregion_copy
1031 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1032 nrv = new MidiRegionView (*mrv, midiregion_copy);
1037 nrv->get_canvas_group()->show ();
1038 new_regionviews.push_back (nrv);
1041 if (new_regionviews.empty()) {
1045 /* reflect the fact that we are dragging the copies */
1047 _primary = new_regionviews.front();
1048 _views = new_regionviews;
1050 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1053 sync the canvas to what we think is its current state
1054 without it, the canvas seems to
1055 "forget" to update properly after the upcoming reparent()
1056 ..only if the mouse is in rapid motion at the time of the grab.
1057 something to do with regionview creation raking so long?
1059 _editor->update_canvas_now();
1063 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1065 /* Which trackview is this ? */
1067 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1068 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1069 (*layer) = tvp.second;
1071 if (*tv && (*tv)->layer_display() == Overlaid) {
1075 /* The region motion is only processed if the pointer is over
1079 if (!(*tv) || !(*tv)->is_track()) {
1080 /* To make sure we hide the verbose canvas cursor when the mouse is
1081 not held over and audiotrack.
1083 _editor->hide_verbose_canvas_cursor ();
1090 /** @param new_order New track order.
1091 * @param old_order Old track order.
1092 * @param visible_y_low Lowest visible order.
1093 * @return true if y movement should not happen, otherwise false.
1096 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1098 if (new_order != old_order) {
1100 /* this isn't the pointer track */
1104 /* moving up the canvas */
1105 if ( (new_order - y_span) >= tavs.visible_y_low) {
1109 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1110 int32_t visible_tracks = 0;
1111 while (visible_tracks < y_span ) {
1113 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1114 /* passing through a hidden track */
1119 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1120 /* moving to a non-track; disallow */
1126 /* moving beyond the lowest visible track; disallow */
1130 } else if (y_span < 0) {
1132 /* moving down the canvas */
1133 if ((new_order - y_span) <= tavs.visible_y_high) {
1135 int32_t visible_tracks = 0;
1137 while (visible_tracks > y_span ) {
1140 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1141 /* passing through a hidden track */
1146 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1147 /* moving to a non-track; disallow */
1154 /* moving beyond the highest visible track; disallow */
1161 /* this is the pointer's track */
1163 if ((new_order - y_span) > tavs.visible_y_high) {
1164 /* we will overflow */
1166 } else if ((new_order - y_span) < tavs.visible_y_low) {
1167 /* we will overflow */
1176 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1177 : RegionMotionDrag (e, i, p, v, b),
1180 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1182 _dest_trackview = tv;
1183 if (tv->layer_display() == Overlaid) {
1186 _dest_layer = _primary->region()->layer ();
1190 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1191 if (rtv && rtv->is_track()) {
1192 speed = rtv->get_diskstream()->speed ();
1195 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1199 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1201 RegionMotionDrag::start_grab (event, c);
1203 _pointer_frame_offset = _grab_frame - _last_frame_position;
1206 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1207 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1209 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1210 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1212 _primary = v->view()->create_region_view (r, false, false);
1214 _primary->get_canvas_group()->show ();
1215 _primary->set_position (pos, 0);
1216 _views.push_back (_primary);
1218 _last_frame_position = pos;
1220 _item = _primary->get_canvas_group ();
1221 _dest_trackview = v;
1222 _dest_layer = _primary->region()->layer ();
1225 map<RegionView*, RouteTimeAxisView*>
1226 RegionMotionDrag::find_time_axis_views ()
1228 map<RegionView*, RouteTimeAxisView*> tav;
1230 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1232 double ix1, ix2, iy1, iy2;
1233 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1234 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1235 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1237 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1238 tav[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
1246 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1248 _editor->update_canvas_now ();
1250 map<RegionView*, RouteTimeAxisView*> final = find_time_axis_views ();
1252 RouteTimeAxisView* dest_rtv = final[_primary];
1254 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1255 _primary->get_canvas_group()->property_y() = 0;
1257 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1259 _editor->begin_reversible_command (_("insert region"));
1260 XMLNode& before = playlist->get_state ();
1261 playlist->add_region (_primary->region (), _last_frame_position);
1262 _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1263 _editor->commit_reversible_command ();
1270 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1271 : RegionMoveDrag (e, i, p, v, false, false)
1276 struct RegionSelectionByPosition {
1277 bool operator() (RegionView*a, RegionView* b) {
1278 return a->region()->position () < b->region()->position();
1283 RegionSpliceDrag::motion (GdkEvent* /*event*/, bool)
1285 RouteTimeAxisView* tv;
1288 if (!check_possible (&tv, &layer)) {
1294 if (_current_pointer_x - _grab_x > 0) {
1300 RegionSelection copy (_editor->selection->regions);
1302 RegionSelectionByPosition cmp;
1305 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1307 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1313 boost::shared_ptr<Playlist> playlist;
1315 if ((playlist = atv->playlist()) == 0) {
1319 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1324 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1328 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1334 playlist->shuffle ((*i)->region(), dir);
1336 _grab_x = _current_pointer_x;
1341 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1347 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1355 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1357 _dest_trackview = _view;
1359 Drag::start_grab (event);
1364 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1367 // TODO: create region-create-drag region view here
1370 // TODO: resize region-create-drag region view here
1374 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1376 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1381 const boost::shared_ptr<MidiDiskstream> diskstream =
1382 boost::dynamic_pointer_cast<MidiDiskstream>(mtv->view()->trackview().track()->diskstream());
1385 warning << "Cannot create non-MIDI region" << endl;
1389 if (!movement_occurred) {
1390 _editor->begin_reversible_command (_("create region"));
1391 XMLNode &before = mtv->playlist()->get_state();
1393 nframes64_t start = _grab_frame;
1394 _editor->snap_to (start, -1);
1395 const Meter& m = _editor->session->tempo_map().meter_at(start);
1396 const Tempo& t = _editor->session->tempo_map().tempo_at(start);
1397 double length = floor (m.frames_per_bar(t, _editor->session->frame_rate()));
1399 boost::shared_ptr<Source> src = _editor->session->create_midi_source_for_session(*diskstream.get());
1401 mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>
1402 (RegionFactory::create(src, 0, (nframes_t) length,
1403 PBD::basename_nosuffix(src->name()))), start);
1404 XMLNode &after = mtv->playlist()->get_state();
1405 _editor->session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
1406 _editor->commit_reversible_command();
1409 motion (event, false);
1410 // TODO: create region-create-drag region here
1418 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1424 RegionGainDrag::finished (GdkEvent *, bool)
1429 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1430 : RegionDrag (e, i, p, v)
1436 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1439 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1440 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1442 if (tv && tv->is_track()) {
1443 speed = tv->get_diskstream()->speed();
1446 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1447 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1448 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1450 Drag::start_grab (event, _editor->trimmer_cursor);
1452 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1453 _operation = ContentsTrim;
1455 /* These will get overridden for a point trim.*/
1456 if (_current_pointer_frame < (region_start + region_length/2)) {
1457 /* closer to start */
1458 _operation = StartTrim;
1459 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1461 _operation = EndTrim;
1465 switch (_operation) {
1467 _editor->show_verbose_time_cursor (region_start, 10);
1470 _editor->show_verbose_time_cursor (region_end, 10);
1473 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1479 TrimDrag::motion (GdkEvent* event, bool first_move)
1481 RegionView* rv = _primary;
1482 nframes64_t frame_delta = 0;
1484 bool left_direction;
1485 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1487 /* snap modifier works differently here..
1488 its' current state has to be passed to the
1489 various trim functions in order to work properly
1493 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1494 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1495 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1497 if (tv && tv->is_track()) {
1498 speed = tv->get_diskstream()->speed();
1501 if (_last_pointer_frame > _current_pointer_frame) {
1502 left_direction = true;
1504 left_direction = false;
1508 _editor->snap_to (_current_pointer_frame);
1515 switch (_operation) {
1517 trim_type = "Region start trim";
1520 trim_type = "Region end trim";
1523 trim_type = "Region content trim";
1527 _editor->begin_reversible_command (trim_type);
1529 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1530 (*i)->fake_set_opaque(false);
1531 (*i)->region()->freeze ();
1533 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1536 arv->temporarily_hide_envelope ();
1539 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1540 insert_result = _editor->motion_frozen_playlists.insert (pl);
1542 if (insert_result.second) {
1543 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1549 if (_current_pointer_frame == _last_pointer_frame) {
1553 if (left_direction) {
1554 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1556 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1559 bool non_overlap_trim = false;
1561 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1562 non_overlap_trim = true;
1565 switch (_operation) {
1567 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1571 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1572 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1578 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1582 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1583 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1590 bool swap_direction = false;
1592 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1593 swap_direction = true;
1596 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1598 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1604 switch (_operation) {
1606 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1609 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1612 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1616 _last_pointer_frame = _current_pointer_frame;
1621 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1623 if (movement_occurred) {
1624 motion (event, false);
1626 if (!_editor->selection->selected (_primary)) {
1627 _editor->thaw_region_after_trim (*_primary);
1630 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1631 _editor->thaw_region_after_trim (**i);
1632 (*i)->fake_set_opaque (true);
1636 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1638 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1641 _editor->motion_frozen_playlists.clear ();
1643 _editor->commit_reversible_command();
1645 /* no mouse movement */
1646 _editor->point_trim (event);
1650 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1654 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1659 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1662 // create a dummy marker for visual representation of moving the copy.
1663 // The actual copying is not done before we reach the finish callback.
1665 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1666 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1667 *new MeterSection (_marker->meter()));
1669 _item = &new_marker->the_item ();
1670 _marker = new_marker;
1674 MetricSection& section (_marker->meter());
1676 if (!section.movable()) {
1682 Drag::start_grab (event, cursor);
1684 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1686 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1690 MeterMarkerDrag::motion (GdkEvent* event, bool)
1692 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1694 if (adjusted_frame == _last_pointer_frame) {
1698 _marker->set_position (adjusted_frame);
1700 _last_pointer_frame = adjusted_frame;
1702 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1706 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1708 if (!movement_occurred) {
1712 motion (event, false);
1716 TempoMap& map (_editor->session->tempo_map());
1717 map.bbt_time (_last_pointer_frame, when);
1719 if (_copy == true) {
1720 _editor->begin_reversible_command (_("copy meter mark"));
1721 XMLNode &before = map.get_state();
1722 map.add_meter (_marker->meter(), when);
1723 XMLNode &after = map.get_state();
1724 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1725 _editor->commit_reversible_command ();
1727 // delete the dummy marker we used for visual representation of copying.
1728 // a new visual marker will show up automatically.
1731 _editor->begin_reversible_command (_("move meter mark"));
1732 XMLNode &before = map.get_state();
1733 map.move_meter (_marker->meter(), when);
1734 XMLNode &after = map.get_state();
1735 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1736 _editor->commit_reversible_command ();
1740 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1744 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1749 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1754 // create a dummy marker for visual representation of moving the copy.
1755 // The actual copying is not done before we reach the finish callback.
1757 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1758 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1759 *new TempoSection (_marker->tempo()));
1761 _item = &new_marker->the_item ();
1762 _marker = new_marker;
1766 MetricSection& section (_marker->tempo());
1768 if (!section.movable()) {
1773 Drag::start_grab (event, cursor);
1775 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1776 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1780 TempoMarkerDrag::motion (GdkEvent* event, bool)
1782 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1784 if (adjusted_frame == _last_pointer_frame) {
1788 /* OK, we've moved far enough to make it worth actually move the thing. */
1790 _marker->set_position (adjusted_frame);
1792 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1794 _last_pointer_frame = adjusted_frame;
1798 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1800 if (!movement_occurred) {
1804 motion (event, false);
1808 TempoMap& map (_editor->session->tempo_map());
1809 map.bbt_time (_last_pointer_frame, when);
1811 if (_copy == true) {
1812 _editor->begin_reversible_command (_("copy tempo mark"));
1813 XMLNode &before = map.get_state();
1814 map.add_tempo (_marker->tempo(), when);
1815 XMLNode &after = map.get_state();
1816 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1817 _editor->commit_reversible_command ();
1819 // delete the dummy marker we used for visual representation of copying.
1820 // a new visual marker will show up automatically.
1823 _editor->begin_reversible_command (_("move tempo mark"));
1824 XMLNode &before = map.get_state();
1825 map.move_tempo (_marker->tempo(), when);
1826 XMLNode &after = map.get_state();
1827 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1828 _editor->commit_reversible_command ();
1833 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1837 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1842 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1844 Drag::start_grab (event, c);
1848 nframes64_t where = _editor->event_frame (event, 0, 0);
1850 _editor->snap_to (where);
1851 _editor->playhead_cursor->set_position (where);
1855 if (_cursor == _editor->playhead_cursor) {
1856 _editor->_dragging_playhead = true;
1858 if (_editor->session && _was_rolling && _stop) {
1859 _editor->session->request_stop ();
1862 if (_editor->session && _editor->session->is_auditioning()) {
1863 _editor->session->cancel_audition ();
1867 _pointer_frame_offset = _grab_frame - _cursor->current_frame;
1869 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1873 CursorDrag::motion (GdkEvent* event, bool)
1875 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1877 if (adjusted_frame == _last_pointer_frame) {
1881 _cursor->set_position (adjusted_frame);
1883 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1886 _editor->update_canvas_now ();
1888 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1890 _last_pointer_frame = adjusted_frame;
1894 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1896 _editor->_dragging_playhead = false;
1898 if (!movement_occurred && _stop) {
1902 motion (event, false);
1904 if (_item == &_editor->playhead_cursor->canvas_item) {
1905 if (_editor->session) {
1906 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1907 _editor->_pending_locate_request = true;
1912 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1913 : RegionDrag (e, i, p, v)
1919 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1921 Drag::start_grab (event, cursor);
1923 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1924 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1926 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1930 FadeInDrag::motion (GdkEvent* event, bool)
1932 nframes64_t fade_length;
1934 nframes64_t const pos = adjusted_current_frame (event);
1936 boost::shared_ptr<Region> region = _primary->region ();
1938 if (pos < (region->position() + 64)) {
1939 fade_length = 64; // this should be a minimum defined somewhere
1940 } else if (pos > region->last_frame()) {
1941 fade_length = region->length();
1943 fade_length = pos - region->position();
1946 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1948 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1954 tmp->reset_fade_in_shape_width (fade_length);
1957 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1961 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1963 if (!movement_occurred) {
1967 nframes64_t fade_length;
1969 nframes64_t const pos = adjusted_current_frame (event);
1971 boost::shared_ptr<Region> region = _primary->region ();
1973 if (pos < (region->position() + 64)) {
1974 fade_length = 64; // this should be a minimum defined somewhere
1975 } else if (pos > region->last_frame()) {
1976 fade_length = region->length();
1978 fade_length = pos - region->position();
1981 _editor->begin_reversible_command (_("change fade in length"));
1983 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1985 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1991 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
1992 XMLNode &before = alist->get_state();
1994 tmp->audio_region()->set_fade_in_length (fade_length);
1995 tmp->audio_region()->set_fade_in_active (true);
1997 XMLNode &after = alist->get_state();
1998 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2001 _editor->commit_reversible_command ();
2004 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2005 : RegionDrag (e, i, p, v)
2011 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2013 Drag::start_grab (event, cursor);
2015 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2016 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2018 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2022 FadeOutDrag::motion (GdkEvent* event, bool)
2024 nframes64_t fade_length;
2026 nframes64_t const pos = adjusted_current_frame (event);
2028 boost::shared_ptr<Region> region = _primary->region ();
2030 if (pos > (region->last_frame() - 64)) {
2031 fade_length = 64; // this should really be a minimum fade defined somewhere
2033 else if (pos < region->position()) {
2034 fade_length = region->length();
2037 fade_length = region->last_frame() - pos;
2040 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2042 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2048 tmp->reset_fade_out_shape_width (fade_length);
2051 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2055 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2057 if (!movement_occurred) {
2061 nframes64_t fade_length;
2063 nframes64_t const pos = adjusted_current_frame (event);
2065 boost::shared_ptr<Region> region = _primary->region ();
2067 if (pos > (region->last_frame() - 64)) {
2068 fade_length = 64; // this should really be a minimum fade defined somewhere
2070 else if (pos < region->position()) {
2071 fade_length = region->length();
2074 fade_length = region->last_frame() - pos;
2077 _editor->begin_reversible_command (_("change fade out length"));
2079 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2081 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2087 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2088 XMLNode &before = alist->get_state();
2090 tmp->audio_region()->set_fade_out_length (fade_length);
2091 tmp->audio_region()->set_fade_out_active (true);
2093 XMLNode &after = alist->get_state();
2094 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2097 _editor->commit_reversible_command ();
2100 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2103 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2106 _points.push_back (Gnome::Art::Point (0, 0));
2107 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2109 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2110 _line->property_width_pixels() = 1;
2111 _line->property_points () = _points;
2114 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2117 MarkerDrag::~MarkerDrag ()
2119 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2125 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2127 Drag::start_grab (event, cursor);
2131 Location *location = _editor->find_location_from_marker (_marker, is_start);
2132 _editor->_dragging_edit_point = true;
2134 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2136 update_item (location);
2138 // _drag_line->show();
2139 // _line->raise_to_top();
2142 _editor->show_verbose_time_cursor (location->start(), 10);
2144 _editor->show_verbose_time_cursor (location->end(), 10);
2147 Selection::Operation op = Keyboard::selection_type (event->button.state);
2150 case Selection::Toggle:
2151 _editor->selection->toggle (_marker);
2153 case Selection::Set:
2154 if (!_editor->selection->selected (_marker)) {
2155 _editor->selection->set (_marker);
2158 case Selection::Extend:
2160 Locations::LocationList ll;
2161 list<Marker*> to_add;
2163 _editor->selection->markers.range (s, e);
2164 s = min (_marker->position(), s);
2165 e = max (_marker->position(), e);
2168 if (e < max_frames) {
2171 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2172 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2173 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2176 to_add.push_back (lm->start);
2179 to_add.push_back (lm->end);
2183 if (!to_add.empty()) {
2184 _editor->selection->add (to_add);
2188 case Selection::Add:
2189 _editor->selection->add (_marker);
2193 /* set up copies for us to manipulate during the drag */
2195 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2196 Location *l = _editor->find_location_from_marker (*i, is_start);
2197 _copied_locations.push_back (new Location (*l));
2202 MarkerDrag::motion (GdkEvent* event, bool)
2204 nframes64_t f_delta = 0;
2206 bool move_both = false;
2208 Location *real_location;
2209 Location *copy_location = 0;
2211 nframes64_t const newframe = adjusted_current_frame (event);
2213 nframes64_t next = newframe;
2215 if (_current_pointer_frame == _last_pointer_frame) {
2219 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2223 MarkerSelection::iterator i;
2224 list<Location*>::iterator x;
2226 /* find the marker we're dragging, and compute the delta */
2228 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2229 x != _copied_locations.end() && i != _editor->selection->markers.end();
2235 if (marker == _marker) {
2237 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2242 if (real_location->is_mark()) {
2243 f_delta = newframe - copy_location->start();
2247 switch (marker->type()) {
2249 case Marker::LoopStart:
2250 case Marker::PunchIn:
2251 f_delta = newframe - copy_location->start();
2255 case Marker::LoopEnd:
2256 case Marker::PunchOut:
2257 f_delta = newframe - copy_location->end();
2260 /* what kind of marker is this ? */
2268 if (i == _editor->selection->markers.end()) {
2269 /* hmm, impossible - we didn't find the dragged marker */
2273 /* now move them all */
2275 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2276 x != _copied_locations.end() && i != _editor->selection->markers.end();
2282 /* call this to find out if its the start or end */
2284 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2288 if (real_location->locked()) {
2292 if (copy_location->is_mark()) {
2296 copy_location->set_start (copy_location->start() + f_delta);
2300 nframes64_t new_start = copy_location->start() + f_delta;
2301 nframes64_t new_end = copy_location->end() + f_delta;
2303 if (is_start) { // start-of-range marker
2306 copy_location->set_start (new_start);
2307 copy_location->set_end (new_end);
2308 } else if (new_start < copy_location->end()) {
2309 copy_location->set_start (new_start);
2311 _editor->snap_to (next, 1, true);
2312 copy_location->set_end (next);
2313 copy_location->set_start (newframe);
2316 } else { // end marker
2319 copy_location->set_end (new_end);
2320 copy_location->set_start (new_start);
2321 } else if (new_end > copy_location->start()) {
2322 copy_location->set_end (new_end);
2323 } else if (newframe > 0) {
2324 _editor->snap_to (next, -1, true);
2325 copy_location->set_start (next);
2326 copy_location->set_end (newframe);
2331 update_item (copy_location);
2333 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2336 lm->set_position (copy_location->start(), copy_location->end());
2340 _last_pointer_frame = _current_pointer_frame;
2342 assert (!_copied_locations.empty());
2344 _editor->edit_point_clock.set (_copied_locations.front()->start());
2345 _editor->show_verbose_time_cursor (newframe, 10);
2348 _editor->update_canvas_now ();
2350 _editor->edit_point_clock.set (copy_location->start());
2354 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2356 if (!movement_occurred) {
2358 /* just a click, do nothing but finish
2359 off the selection process
2362 Selection::Operation op = Keyboard::selection_type (event->button.state);
2365 case Selection::Set:
2366 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2367 _editor->selection->set (_marker);
2371 case Selection::Toggle:
2372 case Selection::Extend:
2373 case Selection::Add:
2380 _editor->_dragging_edit_point = false;
2382 _editor->begin_reversible_command ( _("move marker") );
2383 XMLNode &before = _editor->session->locations()->get_state();
2385 MarkerSelection::iterator i;
2386 list<Location*>::iterator x;
2389 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2390 x != _copied_locations.end() && i != _editor->selection->markers.end();
2393 Location * location = _editor->find_location_from_marker (*i, is_start);
2397 if (location->locked()) {
2401 if (location->is_mark()) {
2402 location->set_start ((*x)->start());
2404 location->set ((*x)->start(), (*x)->end());
2409 XMLNode &after = _editor->session->locations()->get_state();
2410 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
2411 _editor->commit_reversible_command ();
2417 MarkerDrag::update_item (Location* location)
2419 double const x1 = _editor->frame_to_pixel (location->start());
2421 _points.front().set_x(x1);
2422 _points.back().set_x(x1);
2423 _line->property_points() = _points;
2426 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2428 _cumulative_x_drag (0),
2429 _cumulative_y_drag (0)
2431 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2437 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2439 Drag::start_grab (event, _editor->fader_cursor);
2441 // start the grab at the center of the control point so
2442 // the point doesn't 'jump' to the mouse after the first drag
2443 _grab_x = _point->get_x();
2444 _grab_y = _point->get_y();
2446 _point->line().parent_group().i2w (_grab_x, _grab_y);
2447 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2449 _grab_frame = _editor->pixel_to_frame (_grab_x);
2451 _point->line().start_drag (_point, _grab_frame, 0);
2453 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2454 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2455 _current_pointer_x + 10, _current_pointer_y + 10);
2457 _editor->show_verbose_canvas_cursor ();
2461 ControlPointDrag::motion (GdkEvent* event, bool)
2463 double dx = _current_pointer_x - _last_pointer_x;
2464 double dy = _current_pointer_y - _last_pointer_y;
2466 if (event->button.state & Keyboard::SecondaryModifier) {
2471 double cx = _grab_x + _cumulative_x_drag + dx;
2472 double cy = _grab_y + _cumulative_y_drag + dy;
2474 // calculate zero crossing point. back off by .01 to stay on the
2475 // positive side of zero
2477 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2478 _point->line().parent_group().i2w(_unused, zero_gain_y);
2480 // make sure we hit zero when passing through
2481 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2482 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2486 if (_x_constrained) {
2489 if (_y_constrained) {
2493 _cumulative_x_drag = cx - _grab_x;
2494 _cumulative_y_drag = cy - _grab_y;
2496 _point->line().parent_group().w2i (cx, cy);
2500 cy = min ((double) _point->line().height(), cy);
2502 //translate cx to frames
2503 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2505 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !_x_constrained) {
2506 _editor->snap_to (cx_frames);
2509 float const fraction = 1.0 - (cy / _point->line().height());
2511 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2513 _point->line().point_drag (*_point, cx_frames, fraction, push);
2515 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2519 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2521 if (!movement_occurred) {
2525 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2526 _editor->reset_point_selection ();
2530 motion (event, false);
2532 _point->line().end_drag (_point);
2536 ControlPointDrag::active (Editing::MouseMode m)
2538 if (m == Editing::MouseGain) {
2539 /* always active in mouse gain */
2543 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2544 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2547 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2550 _cumulative_y_drag (0)
2555 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2557 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2560 _item = &_line->grab_item ();
2562 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2563 origin, and ditto for y.
2566 double cx = event->button.x;
2567 double cy = event->button.y;
2569 _line->parent_group().w2i (cx, cy);
2571 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2573 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2574 /* no adjacent points */
2578 Drag::start_grab (event, _editor->fader_cursor);
2580 /* store grab start in parent frame */
2585 double fraction = 1.0 - (cy / _line->height());
2587 _line->start_drag (0, _grab_frame, fraction);
2589 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2590 _current_pointer_x + 10, _current_pointer_y + 10);
2592 _editor->show_verbose_canvas_cursor ();
2596 LineDrag::motion (GdkEvent* event, bool)
2598 double dy = _current_pointer_y - _last_pointer_y;
2600 if (event->button.state & Keyboard::SecondaryModifier) {
2604 double cy = _grab_y + _cumulative_y_drag + dy;
2606 _cumulative_y_drag = cy - _grab_y;
2609 cy = min ((double) _line->height(), cy);
2611 double const fraction = 1.0 - (cy / _line->height());
2615 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2621 _line->line_drag (_before, _after, fraction, push);
2623 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2627 LineDrag::finished (GdkEvent* event, bool)
2629 motion (event, false);
2630 _line->end_drag (0);
2634 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2636 Drag::start_grab (event);
2637 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2641 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2648 /* use a bigger drag threshold than the default */
2650 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2654 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && Config->get_rubberbanding_snaps_to_grid()) {
2656 _editor->snap_to (_grab_frame);
2658 _editor->snap_to (_current_pointer_frame);
2661 /* base start and end on initial click position */
2663 if (_current_pointer_frame < _grab_frame) {
2664 start = _current_pointer_frame;
2667 end = _current_pointer_frame;
2668 start = _grab_frame;
2671 if (_current_pointer_y < _grab_y) {
2672 y1 = _current_pointer_y;
2675 y2 = _current_pointer_y;
2680 if (start != end || y1 != y2) {
2682 double x1 = _editor->frame_to_pixel (start);
2683 double x2 = _editor->frame_to_pixel (end);
2685 _editor->rubberband_rect->property_x1() = x1;
2686 _editor->rubberband_rect->property_y1() = y1;
2687 _editor->rubberband_rect->property_x2() = x2;
2688 _editor->rubberband_rect->property_y2() = y2;
2690 _editor->rubberband_rect->show();
2691 _editor->rubberband_rect->raise_to_top();
2693 _last_pointer_frame = _current_pointer_frame;
2695 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2700 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2702 if (movement_occurred) {
2704 motion (event, false);
2707 if (_current_pointer_y < _grab_y) {
2708 y1 = _current_pointer_y;
2711 y2 = _current_pointer_y;
2716 Selection::Operation op = Keyboard::selection_type (event->button.state);
2719 _editor->begin_reversible_command (_("rubberband selection"));
2721 if (_grab_frame < _last_pointer_frame) {
2722 commit = _editor->select_all_within (_grab_frame, _last_pointer_frame, y1, y2, _editor->track_views, op);
2724 commit = _editor->select_all_within (_last_pointer_frame, _grab_frame, y1, y2, _editor->track_views, op);
2728 _editor->commit_reversible_command ();
2732 if (!getenv("ARDOUR_SAE")) {
2733 _editor->selection->clear_tracks();
2735 _editor->selection->clear_regions();
2736 _editor->selection->clear_points ();
2737 _editor->selection->clear_lines ();
2740 _editor->rubberband_rect->hide();
2744 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2746 Drag::start_grab (event);
2748 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2752 TimeFXDrag::motion (GdkEvent* event, bool)
2754 RegionView* rv = _primary;
2756 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2757 _editor->snap_to (_current_pointer_frame);
2760 if (_current_pointer_frame == _last_pointer_frame) {
2764 if (_current_pointer_frame > rv->region()->position()) {
2765 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2768 _last_pointer_frame = _current_pointer_frame;
2770 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2774 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2776 _primary->get_time_axis_view().hide_timestretch ();
2778 if (!movement_occurred) {
2782 if (_last_pointer_frame < _primary->region()->position()) {
2783 /* backwards drag of the left edge - not usable */
2787 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2789 float percentage = (double) newlen / (double) _primary->region()->length();
2791 #ifndef USE_RUBBERBAND
2792 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2793 if (_primary->region()->data_type() == DataType::AUDIO) {
2794 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2798 _editor->begin_reversible_command (_("timestretch"));
2800 // XXX how do timeFX on multiple regions ?
2805 if (_editor->time_stretch (rs, percentage) == 0) {
2806 _editor->session->commit_reversible_command ();
2811 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2813 Drag::start_grab (event);
2817 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2823 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2825 if (movement_occurred && _editor->session) {
2826 /* make sure we stop */
2827 _editor->session->request_transport_speed (0.0);
2831 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2840 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2842 nframes64_t start = 0;
2843 nframes64_t end = 0;
2845 if (_editor->session == 0) {
2849 Gdk::Cursor* cursor = 0;
2851 switch (_operation) {
2852 case CreateSelection:
2853 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2858 cursor = _editor->selector_cursor;
2859 Drag::start_grab (event, cursor);
2862 case SelectionStartTrim:
2863 if (_editor->clicked_axisview) {
2864 _editor->clicked_axisview->order_selection_trims (_item, true);
2866 Drag::start_grab (event, cursor);
2867 cursor = _editor->trimmer_cursor;
2868 start = _editor->selection->time[_editor->clicked_selection].start;
2869 _pointer_frame_offset = _grab_frame - start;
2872 case SelectionEndTrim:
2873 if (_editor->clicked_axisview) {
2874 _editor->clicked_axisview->order_selection_trims (_item, false);
2876 Drag::start_grab (event, cursor);
2877 cursor = _editor->trimmer_cursor;
2878 end = _editor->selection->time[_editor->clicked_selection].end;
2879 _pointer_frame_offset = _grab_frame - end;
2883 start = _editor->selection->time[_editor->clicked_selection].start;
2884 Drag::start_grab (event, cursor);
2885 _pointer_frame_offset = _grab_frame - start;
2889 if (_operation == SelectionMove) {
2890 _editor->show_verbose_time_cursor (start, 10);
2892 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2897 SelectionDrag::motion (GdkEvent* event, bool first_move)
2899 nframes64_t start = 0;
2900 nframes64_t end = 0;
2903 nframes64_t const pending_position = adjusted_current_frame (event);
2905 /* only alter selection if the current frame is
2906 different from the last frame position (adjusted)
2909 if (pending_position == _last_pointer_frame) {
2913 switch (_operation) {
2914 case CreateSelection:
2917 _editor->snap_to (_grab_frame);
2920 if (pending_position < _grab_frame) {
2921 start = pending_position;
2924 end = pending_position;
2925 start = _grab_frame;
2928 /* first drag: Either add to the selection
2929 or create a new selection->
2934 _editor->begin_reversible_command (_("range selection"));
2937 /* adding to the selection */
2938 _editor->clicked_selection = _editor->selection->add (start, end);
2941 /* new selection-> */
2942 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2947 case SelectionStartTrim:
2950 _editor->begin_reversible_command (_("trim selection start"));
2953 start = _editor->selection->time[_editor->clicked_selection].start;
2954 end = _editor->selection->time[_editor->clicked_selection].end;
2956 if (pending_position > end) {
2959 start = pending_position;
2963 case SelectionEndTrim:
2966 _editor->begin_reversible_command (_("trim selection end"));
2969 start = _editor->selection->time[_editor->clicked_selection].start;
2970 end = _editor->selection->time[_editor->clicked_selection].end;
2972 if (pending_position < start) {
2975 end = pending_position;
2983 _editor->begin_reversible_command (_("move selection"));
2986 start = _editor->selection->time[_editor->clicked_selection].start;
2987 end = _editor->selection->time[_editor->clicked_selection].end;
2989 length = end - start;
2991 start = pending_position;
2992 _editor->snap_to (start);
2994 end = start + length;
2999 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3000 _editor->start_canvas_autoscroll (1, 0);
3004 _editor->selection->replace (_editor->clicked_selection, start, end);
3007 _last_pointer_frame = pending_position;
3009 if (_operation == SelectionMove) {
3010 _editor->show_verbose_time_cursor(start, 10);
3012 _editor->show_verbose_time_cursor(pending_position, 10);
3017 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3019 if (movement_occurred) {
3020 motion (event, false);
3021 /* XXX this is not object-oriented programming at all. ick */
3022 if (_editor->selection->time.consolidate()) {
3023 _editor->selection->TimeChanged ();
3025 _editor->commit_reversible_command ();
3027 /* just a click, no pointer movement.*/
3029 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3031 _editor->selection->clear_time();
3036 /* XXX what happens if its a music selection? */
3037 _editor->session->set_audio_range (_editor->selection->time);
3038 _editor->stop_canvas_autoscroll ();
3041 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3046 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3047 _drag_rect->hide ();
3049 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3050 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3054 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3056 if (_editor->session == 0) {
3060 Gdk::Cursor* cursor = 0;
3062 if (!_editor->temp_location) {
3063 _editor->temp_location = new Location;
3066 switch (_operation) {
3067 case CreateRangeMarker:
3068 case CreateTransportMarker:
3069 case CreateCDMarker:
3071 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3076 cursor = _editor->selector_cursor;
3080 Drag::start_grab (event, cursor);
3082 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3086 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3088 nframes64_t start = 0;
3089 nframes64_t end = 0;
3090 ArdourCanvas::SimpleRect *crect;
3092 switch (_operation) {
3093 case CreateRangeMarker:
3094 crect = _editor->range_bar_drag_rect;
3096 case CreateTransportMarker:
3097 crect = _editor->transport_bar_drag_rect;
3099 case CreateCDMarker:
3100 crect = _editor->cd_marker_bar_drag_rect;
3103 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3108 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3109 _editor->snap_to (_current_pointer_frame);
3112 /* only alter selection if the current frame is
3113 different from the last frame position.
3116 if (_current_pointer_frame == _last_pointer_frame) {
3120 switch (_operation) {
3121 case CreateRangeMarker:
3122 case CreateTransportMarker:
3123 case CreateCDMarker:
3125 _editor->snap_to (_grab_frame);
3128 if (_current_pointer_frame < _grab_frame) {
3129 start = _current_pointer_frame;
3132 end = _current_pointer_frame;
3133 start = _grab_frame;
3136 /* first drag: Either add to the selection
3137 or create a new selection.
3142 _editor->temp_location->set (start, end);
3146 update_item (_editor->temp_location);
3148 //_drag_rect->raise_to_top();
3154 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3155 _editor->start_canvas_autoscroll (1, 0);
3159 _editor->temp_location->set (start, end);
3161 double x1 = _editor->frame_to_pixel (start);
3162 double x2 = _editor->frame_to_pixel (end);
3163 crect->property_x1() = x1;
3164 crect->property_x2() = x2;
3166 update_item (_editor->temp_location);
3169 _last_pointer_frame = _current_pointer_frame;
3171 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3176 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3178 Location * newloc = 0;
3182 if (movement_occurred) {
3183 motion (event, false);
3186 switch (_operation) {
3187 case CreateRangeMarker:
3188 case CreateCDMarker:
3190 _editor->begin_reversible_command (_("new range marker"));
3191 XMLNode &before = _editor->session->locations()->get_state();
3192 _editor->session->locations()->next_available_name(rangename,"unnamed");
3193 if (_operation == CreateCDMarker) {
3194 flags = Location::IsRangeMarker | Location::IsCDMarker;
3195 _editor->cd_marker_bar_drag_rect->hide();
3198 flags = Location::IsRangeMarker;
3199 _editor->range_bar_drag_rect->hide();
3201 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3202 _editor->session->locations()->add (newloc, true);
3203 XMLNode &after = _editor->session->locations()->get_state();
3204 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3205 _editor->commit_reversible_command ();
3209 case CreateTransportMarker:
3210 // popup menu to pick loop or punch
3211 _editor->new_transport_marker_context_menu (&event->button, _item);
3215 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3217 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3222 start = _editor->session->locations()->first_mark_before (_grab_frame);
3223 end = _editor->session->locations()->first_mark_after (_grab_frame);
3225 if (end == max_frames) {
3226 end = _editor->session->current_end_frame ();
3230 start = _editor->session->current_start_frame ();
3233 switch (_editor->mouse_mode) {
3235 /* find the two markers on either side and then make the selection from it */
3236 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3240 /* find the two markers on either side of the click and make the range out of it */
3241 _editor->selection->set (0, start, end);
3250 _editor->stop_canvas_autoscroll ();
3256 RangeMarkerBarDrag::update_item (Location* location)
3258 double const x1 = _editor->frame_to_pixel (location->start());
3259 double const x2 = _editor->frame_to_pixel (location->end());
3261 _drag_rect->property_x1() = x1;
3262 _drag_rect->property_x2() = x2;
3266 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3268 Drag::start_grab (event, _editor->zoom_cursor);
3269 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3273 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3278 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3279 _editor->snap_to (_current_pointer_frame);
3282 _editor->snap_to (_grab_frame);
3286 if (_current_pointer_frame == _last_pointer_frame) {
3290 /* base start and end on initial click position */
3291 if (_current_pointer_frame < _grab_frame) {
3292 start = _current_pointer_frame;
3295 end = _current_pointer_frame;
3296 start = _grab_frame;
3302 _editor->zoom_rect->show();
3303 _editor->zoom_rect->raise_to_top();
3306 _editor->reposition_zoom_rect(start, end);
3308 _last_pointer_frame = _current_pointer_frame;
3310 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3315 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3317 if (movement_occurred) {
3318 motion (event, false);
3320 if (_grab_frame < _last_pointer_frame) {
3321 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3323 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3326 _editor->temporal_zoom_to_frame (false, _grab_frame);
3328 temporal_zoom_step (false);
3329 center_screen (_grab_frame);
3333 _editor->zoom_rect->hide();