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();
152 return _had_movement;
156 Drag::adjusted_current_frame () const
158 if (_current_pointer_frame > _pointer_frame_offset) {
159 return _current_pointer_frame - _pointer_frame_offset;
166 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
168 _last_pointer_x = _current_pointer_x;
169 _last_pointer_y = _current_pointer_y;
170 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
172 if (!from_autoscroll && !_move_threshold_passed) {
174 bool const xp = (::llabs ((nframes64_t) (_current_pointer_x - _grab_x)) > 4LL);
175 bool const yp = (::llabs ((nframes64_t) (_current_pointer_y - _grab_y)) > 4LL);
177 _move_threshold_passed = (xp || yp);
179 if (apply_move_threshold() && _move_threshold_passed) {
181 _grab_frame = _current_pointer_frame;
182 _grab_x = _current_pointer_x;
183 _grab_y = _current_pointer_y;
184 _last_pointer_frame = _grab_frame;
185 _pointer_frame_offset = _grab_frame - _last_frame_position;
190 bool old_had_movement = _had_movement;
192 /* a motion event has happened, so we've had movement... */
193 _had_movement = true;
195 /* ... unless we're using a move threshold and we've not yet passed it */
196 if (apply_move_threshold() && !_move_threshold_passed) {
197 _had_movement = false;
200 if (active (_editor->mouse_mode)) {
202 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
203 if (!from_autoscroll) {
204 _editor->maybe_autoscroll (&event->motion);
207 motion (event, _had_movement != old_had_movement);
219 _editor->stop_canvas_autoscroll ();
220 _editor->hide_verbose_canvas_cursor ();
225 /* put it back where it came from */
230 _item->i2w (cxw, cyw);
231 _item->move (_original_x - cxw, _original_y - cyw);
236 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
241 RegionView::RegionViewGoingAway.connect (mem_fun (*this, &RegionDrag::region_going_away));
245 RegionDrag::region_going_away (RegionView* v)
251 RegionDrag::update_selection ()
254 copy (_views.begin(), _views.end(), back_inserter (s));
255 _editor->selection->set (s);
258 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
259 : RegionDrag (e, i, p, v),
269 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
271 Drag::start_grab (event);
273 _editor->show_verbose_time_cursor (_last_frame_position, 10);
276 RegionMotionDrag::TimeAxisViewSummary
277 RegionMotionDrag::get_time_axis_view_summary ()
279 int32_t children = 0;
280 TimeAxisViewSummary sum;
282 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
284 /* get a bitmask representing the visible tracks */
286 for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
287 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
288 TimeAxisView::Children children_list;
290 /* zeroes are audio/MIDI tracks. ones are other types. */
292 if (!rtv->hidden()) {
294 if (!rtv->is_track()) {
295 /* not an audio nor MIDI track */
296 sum.tracks = sum.tracks |= (0x01 << rtv->order());
299 sum.height_list[rtv->order()] = (*i)->current_height();
302 if ((children_list = rtv->get_child_list()).size() > 0) {
303 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
304 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
305 sum.height_list[rtv->order() + children] = (*j)->current_height();
316 RegionMotionDrag::compute_y_delta (
317 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
318 int32_t last_pointer_layer, int32_t current_pointer_layer,
319 TimeAxisViewSummary const & tavs,
320 int32_t* pointer_order_span, int32_t* pointer_layer_span,
321 int32_t* canvas_pointer_order_span
325 *pointer_order_span = 0;
326 *pointer_layer_span = 0;
330 bool clamp_y_axis = false;
332 /* the change in track order between this callback and the last */
333 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
334 /* the change in layer between this callback and the last;
335 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
336 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
338 if (*pointer_order_span != 0) {
340 /* find the actual pointer span, in terms of the number of visible tracks;
341 to do this, we reduce |pointer_order_span| by the number of hidden tracks
344 *canvas_pointer_order_span = *pointer_order_span;
345 if (last_pointer_view->order() >= current_pointer_view->order()) {
346 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
347 if (tavs.height_list[y] == 0) {
348 *canvas_pointer_order_span--;
352 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
353 if (tavs.height_list[y] == 0) {
354 *canvas_pointer_order_span++;
359 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
361 RegionView* rv = (*i);
363 if (rv->region()->locked()) {
367 double ix1, ix2, iy1, iy2;
368 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
369 rv->get_canvas_frame()->i2w (ix1, iy1);
370 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
372 /* get the new trackview for this particular region */
373 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
375 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
377 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
378 as surely this is a per-region thing... */
380 clamp_y_axis = y_movement_disallowed (
381 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
389 } else if (_dest_trackview == current_pointer_view) {
391 if (current_pointer_layer == last_pointer_layer) {
392 /* No movement; clamp */
398 _dest_trackview = current_pointer_view;
399 _dest_layer = current_pointer_layer;
407 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
409 *pending_region_position = 0;
411 /* compute the amount of pointer motion in frames, and where
412 the region would be if we moved it by that much.
414 if (_current_pointer_frame >= _pointer_frame_offset) {
416 nframes64_t sync_frame;
417 nframes64_t sync_offset;
420 *pending_region_position = _current_pointer_frame - _pointer_frame_offset;
422 sync_offset = _primary->region()->sync_offset (sync_dir);
424 /* we don't handle a sync point that lies before zero.
426 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
428 sync_frame = *pending_region_position + (sync_dir*sync_offset);
430 /* we snap if the snap modifier is not enabled.
433 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
434 _editor->snap_to (sync_frame);
437 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
440 *pending_region_position = _last_frame_position;
445 if (*pending_region_position > max_frames - _primary->region()->length()) {
446 *pending_region_position = _last_frame_position;
451 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
453 /* now compute the canvas unit distance we need to move the regionview
454 to make it appear at the new location.
457 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
459 if (*pending_region_position <= _last_frame_position) {
461 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
463 RegionView* rv = (*i);
465 // If any regionview is at zero, we need to know so we can stop further leftward motion.
467 double ix1, ix2, iy1, iy2;
468 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
469 rv->get_canvas_frame()->i2w (ix1, iy1);
471 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
473 *pending_region_position = _last_frame_position;
480 _last_frame_position = *pending_region_position;
487 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
491 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
493 vector<int32_t>::iterator j;
495 /* *pointer* variables reflect things about the pointer; as we may be moving
496 multiple regions, much detail must be computed per-region */
498 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
499 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
500 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
501 is always 0 regardless of what the region's "real" layer is */
502 RouteTimeAxisView* current_pointer_view;
503 layer_t current_pointer_layer;
504 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
508 /* TimeAxisView that we were pointing at last time we entered this method */
509 TimeAxisView const * const last_pointer_view = _dest_trackview;
510 /* the order of the track that we were pointing at last time we entered this method */
511 int32_t const last_pointer_order = last_pointer_view->order ();
512 /* the layer that we were pointing at last time we entered this method */
513 layer_t const last_pointer_layer = _dest_layer;
515 int32_t pointer_order_span;
516 int32_t pointer_layer_span;
517 int32_t canvas_pointer_order_span;
519 bool const clamp_y_axis = compute_y_delta (
520 last_pointer_view, current_pointer_view,
521 last_pointer_layer, current_pointer_layer, tavs,
522 &pointer_order_span, &pointer_layer_span,
523 &canvas_pointer_order_span
526 nframes64_t pending_region_position;
527 double const x_delta = compute_x_delta (event, &pending_region_position);
529 /*************************************************************
531 ************************************************************/
533 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0) {
534 /* haven't reached next snap point, and we're not switching
535 trackviews nor layers. nothing to do.
540 /*************************************************************
542 ************************************************************/
544 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
546 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
548 RegionView* rv = (*i);
550 if (rv->region()->locked()) {
554 /* here we are calculating the y distance from the
555 top of the first track view to the top of the region
556 area of the track view that we're working on */
558 /* this x value is just a dummy value so that we have something
563 /* distance from the top of this track view to the region area
564 of our track view is always 1 */
568 /* convert to world coordinates, ie distance from the top of
571 rv->get_canvas_frame()->i2w (ix1, iy1);
573 /* compensate for the ruler section and the vertical scrollbar position */
574 iy1 += _editor->get_trackview_group_vertical_offset ();
578 // hide any dependent views
580 rv->get_time_axis_view().hide_dependent_views (*rv);
583 reparent to a non scrolling group so that we can keep the
584 region selection above all time axis views.
585 reparenting means we have to move the rv as the two
586 parent groups have different coordinates.
589 rv->get_canvas_group()->property_y() = iy1 - 1;
590 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
592 rv->fake_set_opaque (true);
595 /* current view for this particular region */
596 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
597 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
599 if (pointer_order_span != 0 && !clamp_y_axis) {
601 /* INTER-TRACK MOVEMENT */
603 /* move through the height list to the track that the region is currently on */
604 vector<int32_t>::iterator j = tavs.height_list.begin ();
606 while (j != tavs.height_list.end () && x != rtv->order ()) {
612 int32_t temp_pointer_order_span = canvas_pointer_order_span;
614 if (j != tavs.height_list.end ()) {
616 /* Account for layers in the original and
617 destination tracks. If we're moving around in layers we assume
618 that only one track is involved, so it's ok to use *pointer*
621 StreamView* lv = last_pointer_view->view ();
624 /* move to the top of the last trackview */
625 if (lv->layer_display () == Stacked) {
626 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
629 StreamView* cv = current_pointer_view->view ();
632 /* move to the right layer on the current trackview */
633 if (cv->layer_display () == Stacked) {
634 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
637 /* And for being on a non-topmost layer on the new
640 while (temp_pointer_order_span > 0) {
641 /* we're moving up canvas-wise,
642 so we need to find the next track height
644 if (j != tavs.height_list.begin()) {
648 if (x != last_pointer_order) {
650 ++temp_pointer_order_span;
655 temp_pointer_order_span--;
658 while (temp_pointer_order_span < 0) {
662 if (x != last_pointer_order) {
664 --temp_pointer_order_span;
668 if (j != tavs.height_list.end()) {
672 temp_pointer_order_span++;
676 /* find out where we'll be when we move and set height accordingly */
678 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
679 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
680 rv->set_height (temp_rtv->view()->child_height());
682 /* if you un-comment the following, the region colours will follow
683 the track colours whilst dragging; personally
684 i think this can confuse things, but never mind.
687 //const GdkColor& col (temp_rtv->view->get_region_color());
688 //rv->set_color (const_cast<GdkColor&>(col));
692 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
694 /* INTER-LAYER MOVEMENT in the same track */
695 y_delta = rtv->view()->child_height () * pointer_layer_span;
700 _editor->mouse_brush_insert_region (rv, pending_region_position);
702 rv->move (x_delta, y_delta);
705 } /* foreach region */
708 _editor->cursor_group->raise_to_top();
711 if (x_delta != 0 && !_brushing) {
712 _editor->show_verbose_time_cursor (_last_frame_position, 10);
717 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
719 if (_copy && first_move) {
720 copy_regions (event);
723 RegionMotionDrag::motion (event, first_move);
727 RegionMoveDrag::finished (GdkEvent* event, bool movement_occurred)
729 bool nocommit = true;
730 vector<RegionView*> copies;
731 boost::shared_ptr<Diskstream> ds;
732 boost::shared_ptr<Playlist> from_playlist;
733 list<RegionView*> new_views;
734 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
735 PlaylistSet modified_playlists;
736 PlaylistSet frozen_playlists;
737 list <sigc::connection> modified_playlist_connections;
738 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
739 nframes64_t drag_delta;
740 bool changed_tracks, changed_position;
741 map<RegionView*, RouteTimeAxisView*> final;
742 RouteTimeAxisView* source_tv;
744 if (!movement_occurred) {
751 if (Config->get_edit_mode() == Splice && !_editor->pre_drag_region_selection.empty()) {
752 _editor->selection->set (_editor->pre_drag_region_selection);
753 _editor->pre_drag_region_selection.clear ();
757 /* all changes were made during motion event handlers */
760 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
761 copies.push_back (*i);
768 /* reverse this here so that we have the correct logic to finalize
772 if (Config->get_edit_mode() == Lock && !_copy) {
773 _x_constrained = !_x_constrained;
777 if (_x_constrained) {
778 _editor->begin_reversible_command (_("fixed time region copy"));
780 _editor->begin_reversible_command (_("region copy"));
783 if (_x_constrained) {
784 _editor->begin_reversible_command (_("fixed time region drag"));
786 _editor->begin_reversible_command (_("region drag"));
790 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
791 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
793 drag_delta = _primary->region()->position() - _last_frame_position;
795 _editor->track_canvas->update_now ();
797 /* make a list of where each region ended up */
798 final = find_time_axis_views ();
800 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
802 RegionView* rv = (*i);
803 RouteTimeAxisView* dest_rtv = final[*i];
807 if (rv->region()->locked()) {
812 if (changed_position && !_x_constrained) {
813 where = rv->region()->position() - drag_delta;
815 where = rv->region()->position();
818 boost::shared_ptr<Region> new_region;
821 /* we already made a copy */
822 new_region = rv->region();
824 /* undo the previous hide_dependent_views so that xfades don't
825 disappear on copying regions
828 //rv->get_time_axis_view().reveal_dependent_views (*rv);
830 } else if (changed_tracks && dest_rtv->playlist()) {
831 new_region = RegionFactory::create (rv->region());
834 if (changed_tracks || _copy) {
836 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
843 _editor->latest_regionviews.clear ();
845 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
847 insert_result = modified_playlists.insert (to_playlist);
849 if (insert_result.second) {
850 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
853 to_playlist->add_region (new_region, where);
857 if (!_editor->latest_regionviews.empty()) {
858 // XXX why just the first one ? we only expect one
859 // commented out in nick_m's canvas reworking. is that intended?
860 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
861 new_views.push_back (_editor->latest_regionviews.front());
866 motion on the same track. plonk the previously reparented region
867 back to its original canvas group (its streamview).
868 No need to do anything for copies as they are fake regions which will be deleted.
871 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
872 rv->get_canvas_group()->property_y() = 0;
874 /* just change the model */
876 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
878 insert_result = modified_playlists.insert (playlist);
880 if (insert_result.second) {
881 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
883 /* freeze to avoid lots of relayering in the case of a multi-region drag */
884 frozen_insert_result = frozen_playlists.insert(playlist);
886 if (frozen_insert_result.second) {
890 rv->region()->set_position (where, (void*) this);
893 if (changed_tracks && !_copy) {
895 /* get the playlist where this drag started. we can't use rv->region()->playlist()
896 because we may have copied the region and it has not been attached to a playlist.
899 assert ((source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view())));
900 assert ((ds = source_tv->get_diskstream()));
901 assert ((from_playlist = ds->playlist()));
903 /* moved to a different audio track, without copying */
905 /* the region that used to be in the old playlist is not
906 moved to the new one - we use a copy of it. as a result,
907 any existing editor for the region should no longer be
911 rv->hide_region_editor();
912 rv->fake_set_opaque (false);
914 /* remove the region from the old playlist */
916 insert_result = modified_playlists.insert (from_playlist);
918 if (insert_result.second) {
919 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
922 from_playlist->remove_region (rv->region());
924 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
925 was selected in all of them, then removing it from a playlist will have removed all
926 trace of it from the selection (i.e. there were N regions selected, we removed 1,
927 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
928 corresponding regionview, and the selection is now empty).
930 this could have invalidated any and all iterators into the region selection.
932 the heuristic we use here is: if the region selection is empty, break out of the loop
933 here. if the region selection is not empty, then restart the loop because we know that
934 we must have removed at least the region(view) we've just been working on as well as any
935 that we processed on previous iterations.
937 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
941 if (_views.empty()) {
952 copies.push_back (rv);
956 if (new_views.empty()) {
958 /* the region(view)s that are being dragged around are copies and do not
959 belong to any track. remove them from our list
965 _primary = _views.front ();
968 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
974 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
975 _editor->session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
978 _editor->commit_reversible_command ();
981 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
988 RegionMoveDrag::x_move_allowed () const
990 if (Config->get_edit_mode() == Lock) {
992 return !_x_constrained;
994 /* in locked edit mode, reverse the usual meaning of _x_constrained */
995 return _x_constrained;
999 return !_x_constrained;
1003 RegionInsertDrag::x_move_allowed () const
1005 if (Config->get_edit_mode() == Lock) {
1006 return _x_constrained;
1009 return !_x_constrained;
1013 RegionMotionDrag::copy_regions (GdkEvent* event)
1015 /* duplicate the regionview(s) and region(s) */
1017 list<RegionView*> new_regionviews;
1019 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1021 RegionView* rv = (*i);
1022 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1023 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1025 const boost::shared_ptr<const Region> original = rv->region();
1026 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1030 boost::shared_ptr<AudioRegion> audioregion_copy
1031 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1032 nrv = new AudioRegionView (*arv, audioregion_copy);
1034 boost::shared_ptr<MidiRegion> midiregion_copy
1035 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1036 nrv = new MidiRegionView (*mrv, midiregion_copy);
1041 nrv->get_canvas_group()->show ();
1042 new_regionviews.push_back (nrv);
1045 if (new_regionviews.empty()) {
1049 /* reflect the fact that we are dragging the copies */
1051 _primary = new_regionviews.front();
1052 _views = new_regionviews;
1054 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1057 sync the canvas to what we think is its current state
1058 without it, the canvas seems to
1059 "forget" to update properly after the upcoming reparent()
1060 ..only if the mouse is in rapid motion at the time of the grab.
1061 something to do with regionview creation raking so long?
1063 _editor->track_canvas->update_now();
1067 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1069 /* Which trackview is this ? */
1071 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1072 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1073 (*layer) = tvp.second;
1075 if (*tv && (*tv)->layer_display() == Overlaid) {
1079 /* The region motion is only processed if the pointer is over
1083 if (!(*tv) || !(*tv)->is_track()) {
1084 /* To make sure we hide the verbose canvas cursor when the mouse is
1085 not held over and audiotrack.
1087 _editor->hide_verbose_canvas_cursor ();
1094 /** @param new_order New track order.
1095 * @param old_order Old track order.
1096 * @param visible_y_low Lowest visible order.
1097 * @return true if y movement should not happen, otherwise false.
1100 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1102 if (new_order != old_order) {
1104 /* this isn't the pointer track */
1108 /* moving up the canvas */
1109 if ( (new_order - y_span) >= tavs.visible_y_low) {
1113 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1114 int32_t visible_tracks = 0;
1115 while (visible_tracks < y_span ) {
1117 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1118 /* passing through a hidden track */
1123 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1124 /* moving to a non-track; disallow */
1130 /* moving beyond the lowest visible track; disallow */
1134 } else if (y_span < 0) {
1136 /* moving down the canvas */
1137 if ((new_order - y_span) <= tavs.visible_y_high) {
1139 int32_t visible_tracks = 0;
1141 while (visible_tracks > y_span ) {
1144 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1145 /* passing through a hidden track */
1150 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1151 /* moving to a non-track; disallow */
1158 /* moving beyond the highest visible track; disallow */
1165 /* this is the pointer's track */
1167 if ((new_order - y_span) > tavs.visible_y_high) {
1168 /* we will overflow */
1170 } else if ((new_order - y_span) < tavs.visible_y_low) {
1171 /* we will overflow */
1180 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1181 : RegionMotionDrag (e, i, p, v, b),
1184 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1186 _dest_trackview = tv;
1187 if (tv->layer_display() == Overlaid) {
1190 _dest_layer = _primary->region()->layer ();
1194 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1195 if (rtv && rtv->is_track()) {
1196 speed = rtv->get_diskstream()->speed ();
1199 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1203 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1205 RegionMotionDrag::start_grab (event, c);
1207 _pointer_frame_offset = _grab_frame - _last_frame_position;
1210 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1211 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1213 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1214 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1216 _primary = v->view()->create_region_view (r, false, false);
1218 _primary->get_canvas_group()->show ();
1219 _primary->set_position (pos, 0);
1220 _views.push_back (_primary);
1222 _last_frame_position = pos;
1224 _item = _primary->get_canvas_group ();
1225 _dest_trackview = v;
1226 _dest_layer = _primary->region()->layer ();
1229 map<RegionView*, RouteTimeAxisView*>
1230 RegionMotionDrag::find_time_axis_views ()
1232 map<RegionView*, RouteTimeAxisView*> tav;
1234 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1236 double ix1, ix2, iy1, iy2;
1237 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1238 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1239 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1241 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1242 tav[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
1250 RegionInsertDrag::finished (GdkEvent* event, bool movement_occurred)
1252 _editor->track_canvas->update_now ();
1254 map<RegionView*, RouteTimeAxisView*> final = find_time_axis_views ();
1256 RouteTimeAxisView* dest_rtv = final[_primary];
1258 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1259 _primary->get_canvas_group()->property_y() = 0;
1261 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1263 _editor->begin_reversible_command (_("insert region"));
1264 XMLNode& before = playlist->get_state ();
1265 playlist->add_region (_primary->region (), _last_frame_position);
1266 _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1267 _editor->commit_reversible_command ();
1274 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1275 : RegionMoveDrag (e, i, p, v, false, false)
1280 struct RegionSelectionByPosition {
1281 bool operator() (RegionView*a, RegionView* b) {
1282 return a->region()->position () < b->region()->position();
1287 RegionSpliceDrag::motion (GdkEvent* event, bool)
1289 RouteTimeAxisView* tv;
1292 if (!check_possible (&tv, &layer)) {
1298 if (_current_pointer_x - _grab_x > 0) {
1304 RegionSelection copy (_editor->selection->regions);
1306 RegionSelectionByPosition cmp;
1309 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1311 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1317 boost::shared_ptr<Playlist> playlist;
1319 if ((playlist = atv->playlist()) == 0) {
1323 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1328 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1332 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1338 playlist->shuffle ((*i)->region(), dir);
1340 _grab_x = _current_pointer_x;
1345 RegionSpliceDrag::finished (GdkEvent* event, bool)
1351 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1359 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1361 _dest_trackview = _view;
1363 Drag::start_grab (event);
1368 RegionCreateDrag::motion (GdkEvent* event, bool first_move)
1371 // TODO: create region-create-drag region view here
1374 // TODO: resize region-create-drag region view here
1378 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1380 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1385 const boost::shared_ptr<MidiDiskstream> diskstream =
1386 boost::dynamic_pointer_cast<MidiDiskstream>(mtv->view()->trackview().track()->diskstream());
1389 warning << "Cannot create non-MIDI region" << endl;
1393 if (!movement_occurred) {
1394 _editor->begin_reversible_command (_("create region"));
1395 XMLNode &before = mtv->playlist()->get_state();
1397 nframes64_t start = _grab_frame;
1398 _editor->snap_to (start, -1);
1399 const Meter& m = _editor->session->tempo_map().meter_at(start);
1400 const Tempo& t = _editor->session->tempo_map().tempo_at(start);
1401 double length = floor (m.frames_per_bar(t, _editor->session->frame_rate()));
1403 boost::shared_ptr<Source> src = _editor->session->create_midi_source_for_session(*diskstream.get());
1405 mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>
1406 (RegionFactory::create(src, 0, (nframes_t) length,
1407 PBD::basename_nosuffix(src->name()))), start);
1408 XMLNode &after = mtv->playlist()->get_state();
1409 _editor->session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
1410 _editor->commit_reversible_command();
1413 motion (event, false);
1414 // TODO: create region-create-drag region here
1422 RegionGainDrag::motion (GdkEvent* event, bool)
1428 RegionGainDrag::finished (GdkEvent *, bool)
1433 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1434 : RegionDrag (e, i, p, v)
1440 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1443 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1444 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1446 if (tv && tv->is_track()) {
1447 speed = tv->get_diskstream()->speed();
1450 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1451 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1452 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1454 Drag::start_grab (event, _editor->trimmer_cursor);
1456 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1457 _operation = ContentsTrim;
1459 /* These will get overridden for a point trim.*/
1460 if (_current_pointer_frame < (region_start + region_length/2)) {
1461 /* closer to start */
1462 _operation = StartTrim;
1463 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1465 _operation = EndTrim;
1469 switch (_operation) {
1471 _editor->show_verbose_time_cursor (region_start, 10);
1474 _editor->show_verbose_time_cursor (region_end, 10);
1477 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1483 TrimDrag::motion (GdkEvent* event, bool first_move)
1485 RegionView* rv = _primary;
1486 nframes64_t frame_delta = 0;
1488 bool left_direction;
1489 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1491 /* snap modifier works differently here..
1492 its' current state has to be passed to the
1493 various trim functions in order to work properly
1497 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1498 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1499 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1501 if (tv && tv->is_track()) {
1502 speed = tv->get_diskstream()->speed();
1505 if (_last_pointer_frame > _current_pointer_frame) {
1506 left_direction = true;
1508 left_direction = false;
1512 _editor->snap_to (_current_pointer_frame);
1515 if (_current_pointer_frame == _last_pointer_frame) {
1523 switch (_operation) {
1525 trim_type = "Region start trim";
1528 trim_type = "Region end trim";
1531 trim_type = "Region content trim";
1535 _editor->begin_reversible_command (trim_type);
1537 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1538 (*i)->fake_set_opaque(false);
1539 (*i)->region()->freeze ();
1541 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1544 arv->temporarily_hide_envelope ();
1547 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1548 insert_result = _editor->motion_frozen_playlists.insert (pl);
1550 if (insert_result.second) {
1551 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1557 if (left_direction) {
1558 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1560 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1563 bool non_overlap_trim = false;
1565 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1566 non_overlap_trim = true;
1569 switch (_operation) {
1571 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1575 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1576 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1582 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1586 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1587 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1594 bool swap_direction = false;
1596 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1597 swap_direction = true;
1600 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1602 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1608 switch (_operation) {
1610 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1613 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1616 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1620 _last_pointer_frame = _current_pointer_frame;
1625 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1627 if (movement_occurred) {
1628 motion (event, false);
1630 if (!_editor->selection->selected (_primary)) {
1631 _editor->thaw_region_after_trim (*_primary);
1634 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1635 _editor->thaw_region_after_trim (**i);
1636 (*i)->fake_set_opaque (true);
1640 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1642 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1645 _editor->motion_frozen_playlists.clear ();
1647 _editor->commit_reversible_command();
1649 /* no mouse movement */
1650 _editor->point_trim (event);
1654 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1658 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1663 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1666 // create a dummy marker for visual representation of moving the copy.
1667 // The actual copying is not done before we reach the finish callback.
1669 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1670 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1671 *new MeterSection (_marker->meter()));
1673 _item = &new_marker->the_item ();
1674 _marker = new_marker;
1678 MetricSection& section (_marker->meter());
1680 if (!section.movable()) {
1686 Drag::start_grab (event, cursor);
1688 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1690 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1694 MeterMarkerDrag::motion (GdkEvent* event, bool)
1696 nframes64_t adjusted_frame = adjusted_current_frame ();
1698 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1699 _editor->snap_to (adjusted_frame);
1702 if (adjusted_frame == _last_pointer_frame) {
1706 _marker->set_position (adjusted_frame);
1708 _last_pointer_frame = adjusted_frame;
1710 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1714 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1716 if (!movement_occurred) {
1720 motion (event, false);
1724 TempoMap& map (_editor->session->tempo_map());
1725 map.bbt_time (_last_pointer_frame, when);
1727 if (_copy == true) {
1728 _editor->begin_reversible_command (_("copy meter mark"));
1729 XMLNode &before = map.get_state();
1730 map.add_meter (_marker->meter(), when);
1731 XMLNode &after = map.get_state();
1732 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1733 _editor->commit_reversible_command ();
1735 // delete the dummy marker we used for visual representation of copying.
1736 // a new visual marker will show up automatically.
1739 _editor->begin_reversible_command (_("move meter mark"));
1740 XMLNode &before = map.get_state();
1741 map.move_meter (_marker->meter(), when);
1742 XMLNode &after = map.get_state();
1743 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1744 _editor->commit_reversible_command ();
1748 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1752 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1757 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1762 // create a dummy marker for visual representation of moving the copy.
1763 // The actual copying is not done before we reach the finish callback.
1765 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1766 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1767 *new TempoSection (_marker->tempo()));
1769 _item = &new_marker->the_item ();
1770 _marker = new_marker;
1774 MetricSection& section (_marker->tempo());
1776 if (!section.movable()) {
1781 Drag::start_grab (event, cursor);
1783 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1784 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1788 TempoMarkerDrag::motion (GdkEvent* event, bool)
1790 nframes64_t adjusted_frame = adjusted_current_frame ();
1792 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1793 _editor->snap_to (adjusted_frame);
1796 if (adjusted_frame == _last_pointer_frame) {
1800 /* OK, we've moved far enough to make it worth actually move the thing. */
1802 _marker->set_position (adjusted_frame);
1804 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1806 _last_pointer_frame = adjusted_frame;
1810 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1812 if (!movement_occurred) {
1816 motion (event, false);
1820 TempoMap& map (_editor->session->tempo_map());
1821 map.bbt_time (_last_pointer_frame, when);
1823 if (_copy == true) {
1824 _editor->begin_reversible_command (_("copy tempo mark"));
1825 XMLNode &before = map.get_state();
1826 map.add_tempo (_marker->tempo(), when);
1827 XMLNode &after = map.get_state();
1828 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1829 _editor->commit_reversible_command ();
1831 // delete the dummy marker we used for visual representation of copying.
1832 // a new visual marker will show up automatically.
1835 _editor->begin_reversible_command (_("move tempo mark"));
1836 XMLNode &before = map.get_state();
1837 map.move_tempo (_marker->tempo(), when);
1838 XMLNode &after = map.get_state();
1839 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1840 _editor->commit_reversible_command ();
1845 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1849 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1854 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1856 Drag::start_grab (event, c);
1860 nframes64_t where = _editor->event_frame (event, 0, 0);
1862 _editor->snap_to (where);
1863 _editor->playhead_cursor->set_position (where);
1867 if (_cursor == _editor->playhead_cursor) {
1868 _editor->_dragging_playhead = true;
1870 if (_editor->session && _was_rolling && _stop) {
1871 _editor->session->request_stop ();
1874 if (_editor->session && _editor->session->is_auditioning()) {
1875 _editor->session->cancel_audition ();
1879 _pointer_frame_offset = _grab_frame - _cursor->current_frame;
1881 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1885 CursorDrag::motion (GdkEvent* event, bool)
1887 nframes64_t adjusted_frame = adjusted_current_frame ();
1889 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1890 if (_cursor == _editor->playhead_cursor) {
1891 _editor->snap_to (adjusted_frame);
1895 if (adjusted_frame == _last_pointer_frame) {
1899 _cursor->set_position (adjusted_frame);
1901 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1904 _editor->track_canvas->update_now ();
1906 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1908 _last_pointer_frame = adjusted_frame;
1912 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1914 _editor->_dragging_playhead = false;
1916 if (!movement_occurred && _stop) {
1920 motion (event, false);
1922 if (_item == &_editor->playhead_cursor->canvas_item) {
1923 if (_editor->session) {
1924 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1925 _editor->_pending_locate_request = true;
1930 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1931 : RegionDrag (e, i, p, v)
1937 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1939 Drag::start_grab (event, cursor);
1941 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1942 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1944 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1948 FadeInDrag::motion (GdkEvent* event, bool)
1950 nframes64_t fade_length;
1952 nframes64_t pos = adjusted_current_frame ();
1954 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1955 _editor->snap_to (pos);
1958 boost::shared_ptr<Region> region = _primary->region ();
1960 if (pos < (region->position() + 64)) {
1961 fade_length = 64; // this should be a minimum defined somewhere
1962 } else if (pos > region->last_frame()) {
1963 fade_length = region->length();
1965 fade_length = pos - region->position();
1968 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1970 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1976 tmp->reset_fade_in_shape_width (fade_length);
1979 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1983 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1985 if (!movement_occurred) {
1989 nframes64_t fade_length;
1991 nframes64_t const pos = adjusted_current_frame ();
1993 boost::shared_ptr<Region> region = _primary->region ();
1995 if (pos < (region->position() + 64)) {
1996 fade_length = 64; // this should be a minimum defined somewhere
1997 } else if (pos > region->last_frame()) {
1998 fade_length = region->length();
2000 fade_length = pos - region->position();
2003 _editor->begin_reversible_command (_("change fade in length"));
2005 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2007 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2013 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2014 XMLNode &before = alist->get_state();
2016 tmp->audio_region()->set_fade_in_length (fade_length);
2017 tmp->audio_region()->set_fade_in_active (true);
2019 XMLNode &after = alist->get_state();
2020 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2023 _editor->commit_reversible_command ();
2026 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2027 : RegionDrag (e, i, p, v)
2033 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2035 Drag::start_grab (event, cursor);
2037 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2038 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2040 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2044 FadeOutDrag::motion (GdkEvent* event, bool)
2046 nframes64_t fade_length;
2048 nframes64_t pos = adjusted_current_frame ();
2050 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2051 _editor->snap_to (pos);
2054 boost::shared_ptr<Region> region = _primary->region ();
2056 if (pos > (region->last_frame() - 64)) {
2057 fade_length = 64; // this should really be a minimum fade defined somewhere
2059 else if (pos < region->position()) {
2060 fade_length = region->length();
2063 fade_length = region->last_frame() - pos;
2066 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2068 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2074 tmp->reset_fade_out_shape_width (fade_length);
2077 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2081 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2083 if (!movement_occurred) {
2087 nframes64_t fade_length;
2089 nframes64_t pos = adjusted_current_frame ();
2091 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2092 _editor->snap_to (pos);
2095 boost::shared_ptr<Region> region = _primary->region ();
2097 if (pos > (region->last_frame() - 64)) {
2098 fade_length = 64; // this should really be a minimum fade defined somewhere
2100 else if (pos < region->position()) {
2101 fade_length = region->length();
2104 fade_length = region->last_frame() - pos;
2107 _editor->begin_reversible_command (_("change fade out length"));
2109 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2111 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2117 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2118 XMLNode &before = alist->get_state();
2120 tmp->audio_region()->set_fade_out_length (fade_length);
2121 tmp->audio_region()->set_fade_out_active (true);
2123 XMLNode &after = alist->get_state();
2124 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2127 _editor->commit_reversible_command ();
2130 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2133 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2136 _points.push_back (Gnome::Art::Point (0, 0));
2137 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2139 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2140 _line->property_width_pixels() = 1;
2141 _line->property_points () = _points;
2144 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2147 MarkerDrag::~MarkerDrag ()
2149 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2155 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2157 Drag::start_grab (event, cursor);
2161 Location *location = _editor->find_location_from_marker (_marker, is_start);
2162 _editor->_dragging_edit_point = true;
2164 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2166 update_item (location);
2168 // _drag_line->show();
2169 // _line->raise_to_top();
2172 _editor->show_verbose_time_cursor (location->start(), 10);
2174 _editor->show_verbose_time_cursor (location->end(), 10);
2177 Selection::Operation op = Keyboard::selection_type (event->button.state);
2180 case Selection::Toggle:
2181 _editor->selection->toggle (_marker);
2183 case Selection::Set:
2184 if (!_editor->selection->selected (_marker)) {
2185 _editor->selection->set (_marker);
2188 case Selection::Extend:
2190 Locations::LocationList ll;
2191 list<Marker*> to_add;
2193 _editor->selection->markers.range (s, e);
2194 s = min (_marker->position(), s);
2195 e = max (_marker->position(), e);
2198 if (e < max_frames) {
2201 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2202 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2203 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2206 to_add.push_back (lm->start);
2209 to_add.push_back (lm->end);
2213 if (!to_add.empty()) {
2214 _editor->selection->add (to_add);
2218 case Selection::Add:
2219 _editor->selection->add (_marker);
2223 /* set up copies for us to manipulate during the drag */
2225 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2226 Location *l = _editor->find_location_from_marker (*i, is_start);
2227 _copied_locations.push_back (new Location (*l));
2232 MarkerDrag::motion (GdkEvent* event, bool)
2234 nframes64_t f_delta = 0;
2236 bool move_both = false;
2238 Location *real_location;
2239 Location *copy_location = 0;
2241 nframes64_t newframe = adjusted_current_frame ();
2243 nframes64_t next = newframe;
2245 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2246 _editor->snap_to (newframe, 0, true);
2249 if (_current_pointer_frame == _last_pointer_frame) {
2253 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2257 MarkerSelection::iterator i;
2258 list<Location*>::iterator x;
2260 /* find the marker we're dragging, and compute the delta */
2262 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2263 x != _copied_locations.end() && i != _editor->selection->markers.end();
2269 if (marker == _marker) {
2271 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2276 if (real_location->is_mark()) {
2277 f_delta = newframe - copy_location->start();
2281 switch (marker->type()) {
2283 case Marker::LoopStart:
2284 case Marker::PunchIn:
2285 f_delta = newframe - copy_location->start();
2289 case Marker::LoopEnd:
2290 case Marker::PunchOut:
2291 f_delta = newframe - copy_location->end();
2294 /* what kind of marker is this ? */
2302 if (i == _editor->selection->markers.end()) {
2303 /* hmm, impossible - we didn't find the dragged marker */
2307 /* now move them all */
2309 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2310 x != _copied_locations.end() && i != _editor->selection->markers.end();
2316 /* call this to find out if its the start or end */
2318 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2322 if (real_location->locked()) {
2326 if (copy_location->is_mark()) {
2330 copy_location->set_start (copy_location->start() + f_delta);
2334 nframes64_t new_start = copy_location->start() + f_delta;
2335 nframes64_t new_end = copy_location->end() + f_delta;
2337 if (is_start) { // start-of-range marker
2340 copy_location->set_start (new_start);
2341 copy_location->set_end (new_end);
2342 } else if (new_start < copy_location->end()) {
2343 copy_location->set_start (new_start);
2345 _editor->snap_to (next, 1, true);
2346 copy_location->set_end (next);
2347 copy_location->set_start (newframe);
2350 } else { // end marker
2353 copy_location->set_end (new_end);
2354 copy_location->set_start (new_start);
2355 } else if (new_end > copy_location->start()) {
2356 copy_location->set_end (new_end);
2357 } else if (newframe > 0) {
2358 _editor->snap_to (next, -1, true);
2359 copy_location->set_start (next);
2360 copy_location->set_end (newframe);
2365 update_item (copy_location);
2367 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2370 lm->set_position (copy_location->start(), copy_location->end());
2374 _last_pointer_frame = _current_pointer_frame;
2376 assert (!_copied_locations.empty());
2378 _editor->edit_point_clock.set (_copied_locations.front()->start());
2379 _editor->show_verbose_time_cursor (newframe, 10);
2382 _editor->track_canvas->update_now ();
2384 _editor->edit_point_clock.set (copy_location->start());
2388 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2390 if (!movement_occurred) {
2392 /* just a click, do nothing but finish
2393 off the selection process
2396 Selection::Operation op = Keyboard::selection_type (event->button.state);
2399 case Selection::Set:
2400 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2401 _editor->selection->set (_marker);
2405 case Selection::Toggle:
2406 case Selection::Extend:
2407 case Selection::Add:
2414 _editor->_dragging_edit_point = false;
2416 _editor->begin_reversible_command ( _("move marker") );
2417 XMLNode &before = _editor->session->locations()->get_state();
2419 MarkerSelection::iterator i;
2420 list<Location*>::iterator x;
2423 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2424 x != _copied_locations.end() && i != _editor->selection->markers.end();
2427 Location * location = _editor->find_location_from_marker (*i, is_start);
2431 if (location->locked()) {
2435 if (location->is_mark()) {
2436 location->set_start ((*x)->start());
2438 location->set ((*x)->start(), (*x)->end());
2443 XMLNode &after = _editor->session->locations()->get_state();
2444 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
2445 _editor->commit_reversible_command ();
2451 MarkerDrag::update_item (Location* location)
2453 double const x1 = _editor->frame_to_pixel (location->start());
2455 _points.front().set_x(x1);
2456 _points.back().set_x(x1);
2457 _line->property_points() = _points;
2460 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2462 _cumulative_x_drag (0),
2463 _cumulative_y_drag (0)
2465 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2471 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2473 Drag::start_grab (event, _editor->fader_cursor);
2475 // start the grab at the center of the control point so
2476 // the point doesn't 'jump' to the mouse after the first drag
2477 _grab_x = _point->get_x();
2478 _grab_y = _point->get_y();
2480 _point->line().parent_group().i2w (_grab_x, _grab_y);
2481 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2483 _grab_frame = _editor->pixel_to_frame (_grab_x);
2485 _point->line().start_drag (_point, _grab_frame, 0);
2487 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2488 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2489 _current_pointer_x + 10, _current_pointer_y + 10);
2491 _editor->show_verbose_canvas_cursor ();
2495 ControlPointDrag::motion (GdkEvent* event, bool)
2497 double dx = _current_pointer_x - _last_pointer_x;
2498 double dy = _current_pointer_y - _last_pointer_y;
2500 if (event->button.state & Keyboard::SecondaryModifier) {
2505 double cx = _grab_x + _cumulative_x_drag + dx;
2506 double cy = _grab_y + _cumulative_y_drag + dy;
2508 // calculate zero crossing point. back off by .01 to stay on the
2509 // positive side of zero
2511 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2512 _point->line().parent_group().i2w(_unused, zero_gain_y);
2514 // make sure we hit zero when passing through
2515 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2516 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2520 if (_x_constrained) {
2523 if (_y_constrained) {
2527 _cumulative_x_drag = cx - _grab_x;
2528 _cumulative_y_drag = cy - _grab_y;
2530 _point->line().parent_group().w2i (cx, cy);
2534 cy = min ((double) _point->line().height(), cy);
2536 //translate cx to frames
2537 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2539 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !_x_constrained) {
2540 _editor->snap_to (cx_frames);
2543 float const fraction = 1.0 - (cy / _point->line().height());
2545 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2547 _point->line().point_drag (*_point, cx_frames, fraction, push);
2549 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2553 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2555 if (!movement_occurred) {
2559 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2560 _editor->reset_point_selection ();
2564 motion (event, false);
2566 _point->line().end_drag (_point);
2569 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2572 _cumulative_y_drag (0)
2577 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2579 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2582 _item = &_line->grab_item ();
2584 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2585 origin, and ditto for y.
2588 double cx = event->button.x;
2589 double cy = event->button.y;
2591 _line->parent_group().w2i (cx, cy);
2593 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2595 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2596 /* no adjacent points */
2600 Drag::start_grab (event, _editor->fader_cursor);
2602 /* store grab start in parent frame */
2607 double fraction = 1.0 - (cy / _line->height());
2609 _line->start_drag (0, _grab_frame, fraction);
2611 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2612 _current_pointer_x + 10, _current_pointer_y + 10);
2614 _editor->show_verbose_canvas_cursor ();
2618 LineDrag::motion (GdkEvent* event, bool)
2620 double dy = _current_pointer_y - _last_pointer_y;
2622 if (event->button.state & Keyboard::SecondaryModifier) {
2626 double cy = _grab_y + _cumulative_y_drag + dy;
2628 _cumulative_y_drag = cy - _grab_y;
2631 cy = min ((double) _line->height(), cy);
2633 double const fraction = 1.0 - (cy / _line->height());
2637 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2643 _line->line_drag (_before, _after, fraction, push);
2645 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2649 LineDrag::finished (GdkEvent* event, bool)
2651 motion (event, false);
2652 _line->end_drag (0);
2656 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2658 Drag::start_grab (event);
2659 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2663 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2670 /* use a bigger drag threshold than the default */
2672 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2676 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && Config->get_rubberbanding_snaps_to_grid()) {
2678 _editor->snap_to (_grab_frame);
2680 _editor->snap_to (_current_pointer_frame);
2683 /* base start and end on initial click position */
2685 if (_current_pointer_frame < _grab_frame) {
2686 start = _current_pointer_frame;
2689 end = _current_pointer_frame;
2690 start = _grab_frame;
2693 if (_current_pointer_y < _grab_y) {
2694 y1 = _current_pointer_y;
2697 y2 = _current_pointer_y;
2702 if (start != end || y1 != y2) {
2704 double x1 = _editor->frame_to_pixel (start);
2705 double x2 = _editor->frame_to_pixel (end);
2707 _editor->rubberband_rect->property_x1() = x1;
2708 _editor->rubberband_rect->property_y1() = y1;
2709 _editor->rubberband_rect->property_x2() = x2;
2710 _editor->rubberband_rect->property_y2() = y2;
2712 _editor->rubberband_rect->show();
2713 _editor->rubberband_rect->raise_to_top();
2715 _last_pointer_frame = _current_pointer_frame;
2717 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2722 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2724 if (movement_occurred) {
2726 motion (event, false);
2729 if (_current_pointer_y < _grab_y) {
2730 y1 = _current_pointer_y;
2733 y2 = _current_pointer_y;
2738 Selection::Operation op = Keyboard::selection_type (event->button.state);
2741 _editor->begin_reversible_command (_("rubberband selection"));
2743 if (_grab_frame < _last_pointer_frame) {
2744 commit = _editor->select_all_within (_grab_frame, _last_pointer_frame, y1, y2, _editor->track_views, op);
2746 commit = _editor->select_all_within (_last_pointer_frame, _grab_frame, y1, y2, _editor->track_views, op);
2750 _editor->commit_reversible_command ();
2754 if (!getenv("ARDOUR_SAE")) {
2755 _editor->selection->clear_tracks();
2757 _editor->selection->clear_regions();
2758 _editor->selection->clear_points ();
2759 _editor->selection->clear_lines ();
2762 _editor->rubberband_rect->hide();
2766 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2768 Drag::start_grab (event);
2770 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2774 TimeFXDrag::motion (GdkEvent* event, bool)
2776 RegionView* rv = _primary;
2778 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2779 _editor->snap_to (_current_pointer_frame);
2782 if (_current_pointer_frame == _last_pointer_frame) {
2786 if (_current_pointer_frame > rv->region()->position()) {
2787 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2790 _last_pointer_frame = _current_pointer_frame;
2792 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2796 TimeFXDrag::finished (GdkEvent* event, bool movement_occurred)
2798 _primary->get_time_axis_view().hide_timestretch ();
2800 if (!movement_occurred) {
2804 if (_last_pointer_frame < _primary->region()->position()) {
2805 /* backwards drag of the left edge - not usable */
2809 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2811 float percentage = (double) newlen / (double) _primary->region()->length();
2813 #ifndef USE_RUBBERBAND
2814 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2815 if (_primary->region()->data_type() == DataType::AUDIO) {
2816 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2820 _editor->begin_reversible_command (_("timestretch"));
2822 // XXX how do timeFX on multiple regions ?
2827 if (_editor->time_stretch (rs, percentage) == 0) {
2828 _editor->session->commit_reversible_command ();
2833 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2835 Drag::start_grab (event);
2839 ScrubDrag::motion (GdkEvent* event, bool)
2845 ScrubDrag::finished (GdkEvent* event, bool movement_occurred)
2847 if (movement_occurred && _editor->session) {
2848 /* make sure we stop */
2849 _editor->session->request_transport_speed (0.0);
2853 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2862 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2864 nframes64_t start = 0;
2865 nframes64_t end = 0;
2867 if (_editor->session == 0) {
2871 Gdk::Cursor* cursor = 0;
2873 switch (_operation) {
2874 case CreateSelection:
2875 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2880 cursor = _editor->selector_cursor;
2881 Drag::start_grab (event, cursor);
2884 case SelectionStartTrim:
2885 if (_editor->clicked_axisview) {
2886 _editor->clicked_axisview->order_selection_trims (_item, true);
2888 Drag::start_grab (event, cursor);
2889 cursor = _editor->trimmer_cursor;
2890 start = _editor->selection->time[_editor->clicked_selection].start;
2891 _pointer_frame_offset = _grab_frame - start;
2894 case SelectionEndTrim:
2895 if (_editor->clicked_axisview) {
2896 _editor->clicked_axisview->order_selection_trims (_item, false);
2898 Drag::start_grab (event, cursor);
2899 cursor = _editor->trimmer_cursor;
2900 end = _editor->selection->time[_editor->clicked_selection].end;
2901 _pointer_frame_offset = _grab_frame - end;
2905 start = _editor->selection->time[_editor->clicked_selection].start;
2906 Drag::start_grab (event, cursor);
2907 _pointer_frame_offset = _grab_frame - start;
2911 if (_operation == SelectionMove) {
2912 _editor->show_verbose_time_cursor (start, 10);
2914 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2919 SelectionDrag::motion (GdkEvent* event, bool first_move)
2921 nframes64_t start = 0;
2922 nframes64_t end = 0;
2925 nframes64_t pending_position = adjusted_current_frame ();
2927 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2928 _editor->snap_to (pending_position);
2931 /* only alter selection if the current frame is
2932 different from the last frame position (adjusted)
2935 if (pending_position == _last_pointer_frame) {
2939 switch (_operation) {
2940 case CreateSelection:
2943 _editor->snap_to (_grab_frame);
2946 if (pending_position < _grab_frame) {
2947 start = pending_position;
2950 end = pending_position;
2951 start = _grab_frame;
2954 /* first drag: Either add to the selection
2955 or create a new selection->
2960 _editor->begin_reversible_command (_("range selection"));
2963 /* adding to the selection */
2964 _editor->clicked_selection = _editor->selection->add (start, end);
2967 /* new selection-> */
2968 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2973 case SelectionStartTrim:
2976 _editor->begin_reversible_command (_("trim selection start"));
2979 start = _editor->selection->time[_editor->clicked_selection].start;
2980 end = _editor->selection->time[_editor->clicked_selection].end;
2982 if (pending_position > end) {
2985 start = pending_position;
2989 case SelectionEndTrim:
2992 _editor->begin_reversible_command (_("trim selection end"));
2995 start = _editor->selection->time[_editor->clicked_selection].start;
2996 end = _editor->selection->time[_editor->clicked_selection].end;
2998 if (pending_position < start) {
3001 end = pending_position;
3009 _editor->begin_reversible_command (_("move selection"));
3012 start = _editor->selection->time[_editor->clicked_selection].start;
3013 end = _editor->selection->time[_editor->clicked_selection].end;
3015 length = end - start;
3017 start = pending_position;
3018 _editor->snap_to (start);
3020 end = start + length;
3025 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->canvas_width) {
3026 _editor->start_canvas_autoscroll (1, 0);
3030 _editor->selection->replace (_editor->clicked_selection, start, end);
3033 _last_pointer_frame = pending_position;
3035 if (_operation == SelectionMove) {
3036 _editor->show_verbose_time_cursor(start, 10);
3038 _editor->show_verbose_time_cursor(pending_position, 10);
3043 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3045 if (movement_occurred) {
3046 motion (event, false);
3047 /* XXX this is not object-oriented programming at all. ick */
3048 if (_editor->selection->time.consolidate()) {
3049 _editor->selection->TimeChanged ();
3051 _editor->commit_reversible_command ();
3053 /* just a click, no pointer movement.*/
3055 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3057 _editor->selection->clear_time();
3062 /* XXX what happens if its a music selection? */
3063 _editor->session->set_audio_range (_editor->selection->time);
3064 _editor->stop_canvas_autoscroll ();
3067 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3072 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3073 _drag_rect->hide ();
3075 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3076 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3080 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3082 if (_editor->session == 0) {
3086 Gdk::Cursor* cursor = 0;
3088 if (!_editor->temp_location) {
3089 _editor->temp_location = new Location;
3092 switch (_operation) {
3093 case CreateRangeMarker:
3094 case CreateTransportMarker:
3095 case CreateCDMarker:
3097 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3102 cursor = _editor->selector_cursor;
3106 Drag::start_grab (event, cursor);
3108 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3112 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3114 nframes64_t start = 0;
3115 nframes64_t end = 0;
3116 ArdourCanvas::SimpleRect *crect;
3118 switch (_operation) {
3119 case CreateRangeMarker:
3120 crect = _editor->range_bar_drag_rect;
3122 case CreateTransportMarker:
3123 crect = _editor->transport_bar_drag_rect;
3125 case CreateCDMarker:
3126 crect = _editor->cd_marker_bar_drag_rect;
3129 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3134 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3135 _editor->snap_to (_current_pointer_frame);
3138 /* only alter selection if the current frame is
3139 different from the last frame position.
3142 if (_current_pointer_frame == _last_pointer_frame) {
3146 switch (_operation) {
3147 case CreateRangeMarker:
3148 case CreateTransportMarker:
3149 case CreateCDMarker:
3151 _editor->snap_to (_grab_frame);
3154 if (_current_pointer_frame < _grab_frame) {
3155 start = _current_pointer_frame;
3158 end = _current_pointer_frame;
3159 start = _grab_frame;
3162 /* first drag: Either add to the selection
3163 or create a new selection.
3168 _editor->temp_location->set (start, end);
3172 update_item (_editor->temp_location);
3174 //_drag_rect->raise_to_top();
3180 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->canvas_width) {
3181 _editor->start_canvas_autoscroll (1, 0);
3185 _editor->temp_location->set (start, end);
3187 double x1 = _editor->frame_to_pixel (start);
3188 double x2 = _editor->frame_to_pixel (end);
3189 crect->property_x1() = x1;
3190 crect->property_x2() = x2;
3192 update_item (_editor->temp_location);
3195 _last_pointer_frame = _current_pointer_frame;
3197 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3202 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3204 Location * newloc = 0;
3208 if (movement_occurred) {
3209 motion (event, false);
3211 switch (_operation) {
3212 case CreateRangeMarker:
3213 case CreateCDMarker:
3215 _editor->begin_reversible_command (_("new range marker"));
3216 XMLNode &before = _editor->session->locations()->get_state();
3217 _editor->session->locations()->next_available_name(rangename,"unnamed");
3218 if (_operation == CreateCDMarker) {
3219 flags = Location::IsRangeMarker | Location::IsCDMarker;
3220 _editor->cd_marker_bar_drag_rect->hide();
3223 flags = Location::IsRangeMarker;
3224 _editor->range_bar_drag_rect->hide();
3226 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3227 _editor->session->locations()->add (newloc, true);
3228 XMLNode &after = _editor->session->locations()->get_state();
3229 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3230 _editor->commit_reversible_command ();
3236 case CreateTransportMarker:
3237 // popup menu to pick loop or punch
3238 _editor->new_transport_marker_context_menu (&event->button, _item);
3243 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3245 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3250 start = _editor->session->locations()->first_mark_before (_grab_frame);
3251 end = _editor->session->locations()->first_mark_after (_grab_frame);
3253 if (end == max_frames) {
3254 end = _editor->session->current_end_frame ();
3258 start = _editor->session->current_start_frame ();
3261 switch (_editor->mouse_mode) {
3263 /* find the two markers on either side and then make the selection from it */
3264 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3268 /* find the two markers on either side of the click and make the range out of it */
3269 _editor->selection->set (0, start, end);
3278 _editor->stop_canvas_autoscroll ();
3284 RangeMarkerBarDrag::update_item (Location* location)
3286 double const x1 = _editor->frame_to_pixel (location->start());
3287 double const x2 = _editor->frame_to_pixel (location->end());
3289 _drag_rect->property_x1() = x1;
3290 _drag_rect->property_x2() = x2;
3294 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3296 Drag::start_grab (event, _editor->zoom_cursor);
3297 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3301 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3306 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3307 _editor->snap_to (_current_pointer_frame);
3310 _editor->snap_to (_grab_frame);
3314 if (_current_pointer_frame == _last_pointer_frame) {
3318 /* base start and end on initial click position */
3319 if (_current_pointer_frame < _grab_frame) {
3320 start = _current_pointer_frame;
3323 end = _current_pointer_frame;
3324 start = _grab_frame;
3330 _editor->zoom_rect->show();
3331 _editor->zoom_rect->raise_to_top();
3334 _editor->reposition_zoom_rect(start, end);
3336 _last_pointer_frame = _current_pointer_frame;
3338 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3343 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3345 if (movement_occurred) {
3346 motion (event, false);
3348 if (_grab_frame < _last_pointer_frame) {
3349 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3351 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3354 _editor->temporal_zoom_to_frame (false, _grab_frame);
3356 temporal_zoom_step (false);
3357 center_screen (_grab_frame);
3361 _editor->zoom_rect->hide();