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;
743 if (!movement_occurred) {
750 if (Config->get_edit_mode() == Splice && !_editor->pre_drag_region_selection.empty()) {
751 _editor->selection->set (_editor->pre_drag_region_selection);
752 _editor->pre_drag_region_selection.clear ();
756 /* all changes were made during motion event handlers */
759 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
760 copies.push_back (*i);
767 /* reverse this here so that we have the correct logic to finalize
771 if (Config->get_edit_mode() == Lock && !_copy) {
772 _x_constrained = !_x_constrained;
776 if (_x_constrained) {
777 _editor->begin_reversible_command (_("fixed time region copy"));
779 _editor->begin_reversible_command (_("region copy"));
782 if (_x_constrained) {
783 _editor->begin_reversible_command (_("fixed time region drag"));
785 _editor->begin_reversible_command (_("region drag"));
789 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
790 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
792 drag_delta = _primary->region()->position() - _last_frame_position;
794 _editor->track_canvas->update_now ();
796 /* make a list of where each region ended up */
797 final = find_time_axis_views ();
799 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
801 RegionView* rv = (*i);
802 RouteTimeAxisView* dest_rtv = final[*i];
806 if (rv->region()->locked()) {
811 if (changed_position && !_x_constrained) {
812 where = rv->region()->position() - drag_delta;
814 where = rv->region()->position();
817 boost::shared_ptr<Region> new_region;
820 /* we already made a copy */
821 new_region = rv->region();
823 /* undo the previous hide_dependent_views so that xfades don't
824 disappear on copying regions
827 //rv->get_time_axis_view().reveal_dependent_views (*rv);
829 } else if (changed_tracks && dest_rtv->playlist()) {
830 new_region = RegionFactory::create (rv->region());
833 if (changed_tracks || _copy) {
835 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
842 _editor->latest_regionviews.clear ();
844 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
846 insert_result = modified_playlists.insert (to_playlist);
848 if (insert_result.second) {
849 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
852 to_playlist->add_region (new_region, where);
856 if (!_editor->latest_regionviews.empty()) {
857 // XXX why just the first one ? we only expect one
858 // commented out in nick_m's canvas reworking. is that intended?
859 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
860 new_views.push_back (_editor->latest_regionviews.front());
865 motion on the same track. plonk the previously reparented region
866 back to its original canvas group (its streamview).
867 No need to do anything for copies as they are fake regions which will be deleted.
870 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
871 rv->get_canvas_group()->property_y() = 0;
873 /* just change the model */
875 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
877 insert_result = modified_playlists.insert (playlist);
879 if (insert_result.second) {
880 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
882 /* freeze to avoid lots of relayering in the case of a multi-region drag */
883 frozen_insert_result = frozen_playlists.insert(playlist);
885 if (frozen_insert_result.second) {
889 rv->region()->set_position (where, (void*) this);
892 if (changed_tracks && !_copy) {
894 /* get the playlist where this drag started. we can't use rv->region()->playlist()
895 because we may have copied the region and it has not been attached to a playlist.
898 assert ((source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view())));
899 assert ((ds = source_tv->get_diskstream()));
900 assert ((from_playlist = ds->playlist()));
902 /* moved to a different audio track, without copying */
904 /* the region that used to be in the old playlist is not
905 moved to the new one - we use a copy of it. as a result,
906 any existing editor for the region should no longer be
910 rv->hide_region_editor();
911 rv->fake_set_opaque (false);
913 /* remove the region from the old playlist */
915 insert_result = modified_playlists.insert (from_playlist);
917 if (insert_result.second) {
918 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
921 from_playlist->remove_region (rv->region());
923 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
924 was selected in all of them, then removing it from a playlist will have removed all
925 trace of it from the selection (i.e. there were N regions selected, we removed 1,
926 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
927 corresponding regionview, and the selection is now empty).
929 this could have invalidated any and all iterators into the region selection.
931 the heuristic we use here is: if the region selection is empty, break out of the loop
932 here. if the region selection is not empty, then restart the loop because we know that
933 we must have removed at least the region(view) we've just been working on as well as any
934 that we processed on previous iterations.
936 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
940 if (_views.empty()) {
951 copies.push_back (rv);
955 if (new_views.empty()) {
957 /* the region(view)s that are being dragged around are copies and do not
958 belong to any track. remove them from our list
964 _primary = _views.front ();
967 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
973 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
974 _editor->session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
977 _editor->commit_reversible_command ();
980 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
987 RegionMoveDrag::x_move_allowed () const
989 if (Config->get_edit_mode() == Lock) {
991 return !_x_constrained;
993 /* in locked edit mode, reverse the usual meaning of _x_constrained */
994 return _x_constrained;
998 return !_x_constrained;
1002 RegionInsertDrag::x_move_allowed () const
1004 if (Config->get_edit_mode() == Lock) {
1005 return _x_constrained;
1008 return !_x_constrained;
1012 RegionMotionDrag::copy_regions (GdkEvent* event)
1014 /* duplicate the regionview(s) and region(s) */
1016 list<RegionView*> new_regionviews;
1018 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1020 RegionView* rv = (*i);
1021 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1022 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1024 const boost::shared_ptr<const Region> original = rv->region();
1025 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1029 boost::shared_ptr<AudioRegion> audioregion_copy
1030 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1031 nrv = new AudioRegionView (*arv, audioregion_copy);
1033 boost::shared_ptr<MidiRegion> midiregion_copy
1034 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1035 nrv = new MidiRegionView (*mrv, midiregion_copy);
1040 nrv->get_canvas_group()->show ();
1041 new_regionviews.push_back (nrv);
1044 if (new_regionviews.empty()) {
1048 /* reflect the fact that we are dragging the copies */
1050 _primary = new_regionviews.front();
1051 _views = new_regionviews;
1053 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1056 sync the canvas to what we think is its current state
1057 without it, the canvas seems to
1058 "forget" to update properly after the upcoming reparent()
1059 ..only if the mouse is in rapid motion at the time of the grab.
1060 something to do with regionview creation raking so long?
1062 _editor->track_canvas->update_now();
1066 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1068 /* Which trackview is this ? */
1070 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1071 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1072 (*layer) = tvp.second;
1074 if (*tv && (*tv)->layer_display() == Overlaid) {
1078 /* The region motion is only processed if the pointer is over
1082 if (!(*tv) || !(*tv)->is_track()) {
1083 /* To make sure we hide the verbose canvas cursor when the mouse is
1084 not held over and audiotrack.
1086 _editor->hide_verbose_canvas_cursor ();
1093 /** @param new_order New track order.
1094 * @param old_order Old track order.
1095 * @param visible_y_low Lowest visible order.
1096 * @return true if y movement should not happen, otherwise false.
1099 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1101 if (new_order != old_order) {
1103 /* this isn't the pointer track */
1107 /* moving up the canvas */
1108 if ( (new_order - y_span) >= tavs.visible_y_low) {
1112 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1113 int32_t visible_tracks = 0;
1114 while (visible_tracks < y_span ) {
1116 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1117 /* passing through a hidden track */
1122 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1123 /* moving to a non-track; disallow */
1129 /* moving beyond the lowest visible track; disallow */
1133 } else if (y_span < 0) {
1135 /* moving down the canvas */
1136 if ((new_order - y_span) <= tavs.visible_y_high) {
1138 int32_t visible_tracks = 0;
1140 while (visible_tracks > y_span ) {
1143 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1144 /* passing through a hidden track */
1149 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1150 /* moving to a non-track; disallow */
1157 /* moving beyond the highest visible track; disallow */
1164 /* this is the pointer's track */
1166 if ((new_order - y_span) > tavs.visible_y_high) {
1167 /* we will overflow */
1169 } else if ((new_order - y_span) < tavs.visible_y_low) {
1170 /* we will overflow */
1179 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1180 : RegionMotionDrag (e, i, p, v, b),
1183 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1185 _dest_trackview = tv;
1186 if (tv->layer_display() == Overlaid) {
1189 _dest_layer = _primary->region()->layer ();
1193 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1194 if (rtv && rtv->is_track()) {
1195 speed = rtv->get_diskstream()->speed ();
1198 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1202 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1204 RegionMotionDrag::start_grab (event, c);
1206 _pointer_frame_offset = _grab_frame - _last_frame_position;
1209 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1210 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1212 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1213 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1215 _primary = v->view()->create_region_view (r, false, false);
1217 _primary->get_canvas_group()->show ();
1218 _primary->set_position (pos, 0);
1219 _views.push_back (_primary);
1221 _last_frame_position = pos;
1223 _item = _primary->get_canvas_group ();
1224 _dest_trackview = v;
1225 _dest_layer = _primary->region()->layer ();
1228 map<RegionView*, RouteTimeAxisView*>
1229 RegionMotionDrag::find_time_axis_views ()
1231 map<RegionView*, RouteTimeAxisView*> tav;
1233 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1235 double ix1, ix2, iy1, iy2;
1236 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1237 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1238 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1240 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1241 tav[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
1249 RegionInsertDrag::finished (GdkEvent* event, bool movement_occurred)
1251 _editor->track_canvas->update_now ();
1253 map<RegionView*, RouteTimeAxisView*> final = find_time_axis_views ();
1255 RouteTimeAxisView* dest_rtv = final[_primary];
1257 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1258 _primary->get_canvas_group()->property_y() = 0;
1260 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1262 _editor->begin_reversible_command (_("insert region"));
1263 XMLNode& before = playlist->get_state ();
1264 playlist->add_region (_primary->region (), _last_frame_position);
1265 _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1266 _editor->commit_reversible_command ();
1273 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1274 : RegionMoveDrag (e, i, p, v, false, false)
1279 struct RegionSelectionByPosition {
1280 bool operator() (RegionView*a, RegionView* b) {
1281 return a->region()->position () < b->region()->position();
1286 RegionSpliceDrag::motion (GdkEvent* event, bool)
1288 RouteTimeAxisView* tv;
1291 if (!check_possible (&tv, &layer)) {
1297 if (_current_pointer_x - _grab_x > 0) {
1303 RegionSelection copy (_editor->selection->regions);
1305 RegionSelectionByPosition cmp;
1308 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1310 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1316 boost::shared_ptr<Playlist> playlist;
1318 if ((playlist = atv->playlist()) == 0) {
1322 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1327 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1331 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1337 playlist->shuffle ((*i)->region(), dir);
1339 _grab_x = _current_pointer_x;
1344 RegionSpliceDrag::finished (GdkEvent* event, bool)
1350 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1358 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1360 _dest_trackview = _view;
1362 Drag::start_grab (event);
1367 RegionCreateDrag::motion (GdkEvent* event, bool first_move)
1370 // TODO: create region-create-drag region view here
1373 // TODO: resize region-create-drag region view here
1377 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1379 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1384 const boost::shared_ptr<MidiDiskstream> diskstream =
1385 boost::dynamic_pointer_cast<MidiDiskstream>(mtv->view()->trackview().track()->diskstream());
1388 warning << "Cannot create non-MIDI region" << endl;
1392 if (!movement_occurred) {
1393 _editor->begin_reversible_command (_("create region"));
1394 XMLNode &before = mtv->playlist()->get_state();
1396 nframes64_t start = _grab_frame;
1397 _editor->snap_to (start, -1);
1398 const Meter& m = _editor->session->tempo_map().meter_at(start);
1399 const Tempo& t = _editor->session->tempo_map().tempo_at(start);
1400 double length = floor (m.frames_per_bar(t, _editor->session->frame_rate()));
1402 boost::shared_ptr<Source> src = _editor->session->create_midi_source_for_session(*diskstream.get());
1404 mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>
1405 (RegionFactory::create(src, 0, (nframes_t) length,
1406 PBD::basename_nosuffix(src->name()))), start);
1407 XMLNode &after = mtv->playlist()->get_state();
1408 _editor->session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
1409 _editor->commit_reversible_command();
1412 motion (event, false);
1413 // TODO: create region-create-drag region here
1421 RegionGainDrag::motion (GdkEvent* event, bool)
1427 RegionGainDrag::finished (GdkEvent *, bool)
1432 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1433 : RegionDrag (e, i, p, v)
1439 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1442 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1443 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1445 if (tv && tv->is_track()) {
1446 speed = tv->get_diskstream()->speed();
1449 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1450 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1451 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1453 Drag::start_grab (event, _editor->trimmer_cursor);
1455 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1456 _operation = ContentsTrim;
1458 /* These will get overridden for a point trim.*/
1459 if (_current_pointer_frame < (region_start + region_length/2)) {
1460 /* closer to start */
1461 _operation = StartTrim;
1462 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1464 _operation = EndTrim;
1468 switch (_operation) {
1470 _editor->show_verbose_time_cursor (region_start, 10);
1473 _editor->show_verbose_time_cursor (region_end, 10);
1476 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1482 TrimDrag::motion (GdkEvent* event, bool first_move)
1484 RegionView* rv = _primary;
1485 nframes64_t frame_delta = 0;
1487 bool left_direction;
1488 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1490 /* snap modifier works differently here..
1491 its' current state has to be passed to the
1492 various trim functions in order to work properly
1496 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1497 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1498 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1500 if (tv && tv->is_track()) {
1501 speed = tv->get_diskstream()->speed();
1504 if (_last_pointer_frame > _current_pointer_frame) {
1505 left_direction = true;
1507 left_direction = false;
1511 _editor->snap_to (_current_pointer_frame);
1514 if (_current_pointer_frame == _last_pointer_frame) {
1522 switch (_operation) {
1524 trim_type = "Region start trim";
1527 trim_type = "Region end trim";
1530 trim_type = "Region content trim";
1534 _editor->begin_reversible_command (trim_type);
1536 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1537 (*i)->fake_set_opaque(false);
1538 (*i)->region()->freeze ();
1540 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1543 arv->temporarily_hide_envelope ();
1546 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1547 insert_result = _editor->motion_frozen_playlists.insert (pl);
1549 if (insert_result.second) {
1550 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1556 if (left_direction) {
1557 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1559 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1562 bool non_overlap_trim = false;
1564 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1565 non_overlap_trim = true;
1568 switch (_operation) {
1570 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1574 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1575 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1581 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1585 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1586 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1593 bool swap_direction = false;
1595 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1596 swap_direction = true;
1599 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1601 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1607 switch (_operation) {
1609 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1612 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1615 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1619 _last_pointer_frame = _current_pointer_frame;
1624 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1626 if (movement_occurred) {
1627 motion (event, false);
1629 if (!_editor->selection->selected (_primary)) {
1630 _editor->thaw_region_after_trim (*_primary);
1633 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1634 _editor->thaw_region_after_trim (**i);
1635 (*i)->fake_set_opaque (true);
1639 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1641 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1644 _editor->motion_frozen_playlists.clear ();
1646 _editor->commit_reversible_command();
1648 /* no mouse movement */
1649 _editor->point_trim (event);
1653 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1657 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1662 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1665 // create a dummy marker for visual representation of moving the copy.
1666 // The actual copying is not done before we reach the finish callback.
1668 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1669 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1670 *new MeterSection (_marker->meter()));
1672 _item = &new_marker->the_item ();
1673 _marker = new_marker;
1677 MetricSection& section (_marker->meter());
1679 if (!section.movable()) {
1685 Drag::start_grab (event, cursor);
1687 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1689 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1693 MeterMarkerDrag::motion (GdkEvent* event, bool)
1695 nframes64_t adjusted_frame = adjusted_current_frame ();
1697 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1698 _editor->snap_to (adjusted_frame);
1701 if (adjusted_frame == _last_pointer_frame) {
1705 _marker->set_position (adjusted_frame);
1707 _last_pointer_frame = adjusted_frame;
1709 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1713 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1715 if (!movement_occurred) {
1719 motion (event, false);
1723 TempoMap& map (_editor->session->tempo_map());
1724 map.bbt_time (_last_pointer_frame, when);
1726 if (_copy == true) {
1727 _editor->begin_reversible_command (_("copy meter mark"));
1728 XMLNode &before = map.get_state();
1729 map.add_meter (_marker->meter(), when);
1730 XMLNode &after = map.get_state();
1731 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1732 _editor->commit_reversible_command ();
1734 // delete the dummy marker we used for visual representation of copying.
1735 // a new visual marker will show up automatically.
1738 _editor->begin_reversible_command (_("move meter mark"));
1739 XMLNode &before = map.get_state();
1740 map.move_meter (_marker->meter(), when);
1741 XMLNode &after = map.get_state();
1742 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1743 _editor->commit_reversible_command ();
1747 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1751 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1756 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1761 // create a dummy marker for visual representation of moving the copy.
1762 // The actual copying is not done before we reach the finish callback.
1764 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1765 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1766 *new TempoSection (_marker->tempo()));
1768 _item = &new_marker->the_item ();
1769 _marker = new_marker;
1773 MetricSection& section (_marker->tempo());
1775 if (!section.movable()) {
1780 Drag::start_grab (event, cursor);
1782 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1783 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1787 TempoMarkerDrag::motion (GdkEvent* event, bool)
1789 nframes64_t adjusted_frame = adjusted_current_frame ();
1791 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1792 _editor->snap_to (adjusted_frame);
1795 if (adjusted_frame == _last_pointer_frame) {
1799 /* OK, we've moved far enough to make it worth actually move the thing. */
1801 _marker->set_position (adjusted_frame);
1803 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1805 _last_pointer_frame = adjusted_frame;
1809 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1811 if (!movement_occurred) {
1815 motion (event, false);
1819 TempoMap& map (_editor->session->tempo_map());
1820 map.bbt_time (_last_pointer_frame, when);
1822 if (_copy == true) {
1823 _editor->begin_reversible_command (_("copy tempo mark"));
1824 XMLNode &before = map.get_state();
1825 map.add_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 ();
1830 // delete the dummy marker we used for visual representation of copying.
1831 // a new visual marker will show up automatically.
1834 _editor->begin_reversible_command (_("move tempo mark"));
1835 XMLNode &before = map.get_state();
1836 map.move_tempo (_marker->tempo(), when);
1837 XMLNode &after = map.get_state();
1838 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1839 _editor->commit_reversible_command ();
1844 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1848 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1853 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1855 Drag::start_grab (event, c);
1859 nframes64_t where = _editor->event_frame (event, 0, 0);
1861 _editor->snap_to (where);
1862 _editor->playhead_cursor->set_position (where);
1866 if (_cursor == _editor->playhead_cursor) {
1867 _editor->_dragging_playhead = true;
1869 if (_editor->session && _was_rolling && _stop) {
1870 _editor->session->request_stop ();
1873 if (_editor->session && _editor->session->is_auditioning()) {
1874 _editor->session->cancel_audition ();
1878 _pointer_frame_offset = _grab_frame - _cursor->current_frame;
1880 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1884 CursorDrag::motion (GdkEvent* event, bool)
1886 nframes64_t adjusted_frame = adjusted_current_frame ();
1888 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1889 if (_cursor == _editor->playhead_cursor) {
1890 _editor->snap_to (adjusted_frame);
1894 if (adjusted_frame == _last_pointer_frame) {
1898 _cursor->set_position (adjusted_frame);
1900 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1903 _editor->track_canvas->update_now ();
1905 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1907 _last_pointer_frame = adjusted_frame;
1911 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1913 _editor->_dragging_playhead = false;
1915 if (!movement_occurred && _stop) {
1919 motion (event, false);
1921 if (_item == &_editor->playhead_cursor->canvas_item) {
1922 if (_editor->session) {
1923 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1924 _editor->_pending_locate_request = true;
1929 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1930 : RegionDrag (e, i, p, v)
1936 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1938 Drag::start_grab (event, cursor);
1940 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1941 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1943 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1947 FadeInDrag::motion (GdkEvent* event, bool)
1949 nframes64_t fade_length;
1951 nframes64_t pos = adjusted_current_frame ();
1953 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1954 _editor->snap_to (pos);
1957 boost::shared_ptr<Region> region = _primary->region ();
1959 if (pos < (region->position() + 64)) {
1960 fade_length = 64; // this should be a minimum defined somewhere
1961 } else if (pos > region->last_frame()) {
1962 fade_length = region->length();
1964 fade_length = pos - region->position();
1967 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1969 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1975 tmp->reset_fade_in_shape_width (fade_length);
1978 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1982 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1984 if (!movement_occurred) {
1988 nframes64_t fade_length;
1990 nframes64_t const pos = adjusted_current_frame ();
1992 boost::shared_ptr<Region> region = _primary->region ();
1994 if (pos < (region->position() + 64)) {
1995 fade_length = 64; // this should be a minimum defined somewhere
1996 } else if (pos > region->last_frame()) {
1997 fade_length = region->length();
1999 fade_length = pos - region->position();
2002 _editor->begin_reversible_command (_("change fade in length"));
2004 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2006 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2012 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2013 XMLNode &before = alist->get_state();
2015 tmp->audio_region()->set_fade_in_length (fade_length);
2016 tmp->audio_region()->set_fade_in_active (true);
2018 XMLNode &after = alist->get_state();
2019 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2022 _editor->commit_reversible_command ();
2025 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2026 : RegionDrag (e, i, p, v)
2032 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2034 Drag::start_grab (event, cursor);
2036 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2037 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2039 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2043 FadeOutDrag::motion (GdkEvent* event, bool)
2045 nframes64_t fade_length;
2047 nframes64_t pos = adjusted_current_frame ();
2049 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2050 _editor->snap_to (pos);
2053 boost::shared_ptr<Region> region = _primary->region ();
2055 if (pos > (region->last_frame() - 64)) {
2056 fade_length = 64; // this should really be a minimum fade defined somewhere
2058 else if (pos < region->position()) {
2059 fade_length = region->length();
2062 fade_length = region->last_frame() - pos;
2065 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2067 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2073 tmp->reset_fade_out_shape_width (fade_length);
2076 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2080 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2082 if (!movement_occurred) {
2086 nframes64_t fade_length;
2088 nframes64_t pos = adjusted_current_frame ();
2090 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2091 _editor->snap_to (pos);
2094 boost::shared_ptr<Region> region = _primary->region ();
2096 if (pos > (region->last_frame() - 64)) {
2097 fade_length = 64; // this should really be a minimum fade defined somewhere
2099 else if (pos < region->position()) {
2100 fade_length = region->length();
2103 fade_length = region->last_frame() - pos;
2106 _editor->begin_reversible_command (_("change fade out length"));
2108 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2110 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2116 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2117 XMLNode &before = alist->get_state();
2119 tmp->audio_region()->set_fade_out_length (fade_length);
2120 tmp->audio_region()->set_fade_out_active (true);
2122 XMLNode &after = alist->get_state();
2123 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2126 _editor->commit_reversible_command ();
2129 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2132 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2135 _points.push_back (Gnome::Art::Point (0, 0));
2136 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2138 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2139 _line->property_width_pixels() = 1;
2140 _line->property_points () = _points;
2143 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2146 MarkerDrag::~MarkerDrag ()
2148 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2154 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2156 Drag::start_grab (event, cursor);
2160 Location *location = _editor->find_location_from_marker (_marker, is_start);
2161 _editor->_dragging_edit_point = true;
2163 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2165 update_item (location);
2167 // _drag_line->show();
2168 // _line->raise_to_top();
2171 _editor->show_verbose_time_cursor (location->start(), 10);
2173 _editor->show_verbose_time_cursor (location->end(), 10);
2176 Selection::Operation op = Keyboard::selection_type (event->button.state);
2179 case Selection::Toggle:
2180 _editor->selection->toggle (_marker);
2182 case Selection::Set:
2183 if (!_editor->selection->selected (_marker)) {
2184 _editor->selection->set (_marker);
2187 case Selection::Extend:
2189 Locations::LocationList ll;
2190 list<Marker*> to_add;
2192 _editor->selection->markers.range (s, e);
2193 s = min (_marker->position(), s);
2194 e = max (_marker->position(), e);
2197 if (e < max_frames) {
2200 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2201 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2202 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2205 to_add.push_back (lm->start);
2208 to_add.push_back (lm->end);
2212 if (!to_add.empty()) {
2213 _editor->selection->add (to_add);
2217 case Selection::Add:
2218 _editor->selection->add (_marker);
2222 /* set up copies for us to manipulate during the drag */
2224 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2225 Location *l = _editor->find_location_from_marker (*i, is_start);
2226 _copied_locations.push_back (new Location (*l));
2231 MarkerDrag::motion (GdkEvent* event, bool)
2233 nframes64_t f_delta = 0;
2235 bool move_both = false;
2237 Location *real_location;
2238 Location *copy_location = 0;
2240 nframes64_t newframe = adjusted_current_frame ();
2242 nframes64_t next = newframe;
2244 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2245 _editor->snap_to (newframe, 0, true);
2248 if (_current_pointer_frame == _last_pointer_frame) {
2252 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2256 MarkerSelection::iterator i;
2257 list<Location*>::iterator x;
2259 /* find the marker we're dragging, and compute the delta */
2261 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2262 x != _copied_locations.end() && i != _editor->selection->markers.end();
2268 if (marker == _marker) {
2270 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2275 if (real_location->is_mark()) {
2276 f_delta = newframe - copy_location->start();
2280 switch (marker->type()) {
2282 case Marker::LoopStart:
2283 case Marker::PunchIn:
2284 f_delta = newframe - copy_location->start();
2288 case Marker::LoopEnd:
2289 case Marker::PunchOut:
2290 f_delta = newframe - copy_location->end();
2293 /* what kind of marker is this ? */
2301 if (i == _editor->selection->markers.end()) {
2302 /* hmm, impossible - we didn't find the dragged marker */
2306 /* now move them all */
2308 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2309 x != _copied_locations.end() && i != _editor->selection->markers.end();
2315 /* call this to find out if its the start or end */
2317 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2321 if (real_location->locked()) {
2325 if (copy_location->is_mark()) {
2329 copy_location->set_start (copy_location->start() + f_delta);
2333 nframes64_t new_start = copy_location->start() + f_delta;
2334 nframes64_t new_end = copy_location->end() + f_delta;
2336 if (is_start) { // start-of-range marker
2339 copy_location->set_start (new_start);
2340 copy_location->set_end (new_end);
2341 } else if (new_start < copy_location->end()) {
2342 copy_location->set_start (new_start);
2344 _editor->snap_to (next, 1, true);
2345 copy_location->set_end (next);
2346 copy_location->set_start (newframe);
2349 } else { // end marker
2352 copy_location->set_end (new_end);
2353 copy_location->set_start (new_start);
2354 } else if (new_end > copy_location->start()) {
2355 copy_location->set_end (new_end);
2356 } else if (newframe > 0) {
2357 _editor->snap_to (next, -1, true);
2358 copy_location->set_start (next);
2359 copy_location->set_end (newframe);
2364 update_item (copy_location);
2366 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2369 lm->set_position (copy_location->start(), copy_location->end());
2373 _last_pointer_frame = _current_pointer_frame;
2375 assert (!_copied_locations.empty());
2377 _editor->edit_point_clock.set (_copied_locations.front()->start());
2378 _editor->show_verbose_time_cursor (newframe, 10);
2381 _editor->track_canvas->update_now ();
2383 _editor->edit_point_clock.set (copy_location->start());
2387 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2389 if (!movement_occurred) {
2391 /* just a click, do nothing but finish
2392 off the selection process
2395 Selection::Operation op = Keyboard::selection_type (event->button.state);
2398 case Selection::Set:
2399 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2400 _editor->selection->set (_marker);
2404 case Selection::Toggle:
2405 case Selection::Extend:
2406 case Selection::Add:
2413 _editor->_dragging_edit_point = false;
2415 _editor->begin_reversible_command ( _("move marker") );
2416 XMLNode &before = _editor->session->locations()->get_state();
2418 MarkerSelection::iterator i;
2419 list<Location*>::iterator x;
2422 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2423 x != _copied_locations.end() && i != _editor->selection->markers.end();
2426 Location * location = _editor->find_location_from_marker (*i, is_start);
2430 if (location->locked()) {
2434 if (location->is_mark()) {
2435 location->set_start ((*x)->start());
2437 location->set ((*x)->start(), (*x)->end());
2442 XMLNode &after = _editor->session->locations()->get_state();
2443 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
2444 _editor->commit_reversible_command ();
2450 MarkerDrag::update_item (Location* location)
2452 double const x1 = _editor->frame_to_pixel (location->start());
2454 _points.front().set_x(x1);
2455 _points.back().set_x(x1);
2456 _line->property_points() = _points;
2459 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2461 _cumulative_x_drag (0),
2462 _cumulative_y_drag (0)
2464 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2470 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2472 Drag::start_grab (event, _editor->fader_cursor);
2474 // start the grab at the center of the control point so
2475 // the point doesn't 'jump' to the mouse after the first drag
2476 _grab_x = _point->get_x();
2477 _grab_y = _point->get_y();
2479 _point->line().parent_group().i2w (_grab_x, _grab_y);
2480 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2482 _grab_frame = _editor->pixel_to_frame (_grab_x);
2484 _point->line().start_drag (_point, _grab_frame, 0);
2486 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2487 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2488 _current_pointer_x + 10, _current_pointer_y + 10);
2490 _editor->show_verbose_canvas_cursor ();
2494 ControlPointDrag::motion (GdkEvent* event, bool)
2496 double dx = _current_pointer_x - _last_pointer_x;
2497 double dy = _current_pointer_y - _last_pointer_y;
2499 if (event->button.state & Keyboard::SecondaryModifier) {
2504 double cx = _grab_x + _cumulative_x_drag + dx;
2505 double cy = _grab_y + _cumulative_y_drag + dy;
2507 // calculate zero crossing point. back off by .01 to stay on the
2508 // positive side of zero
2510 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2511 _point->line().parent_group().i2w(_unused, zero_gain_y);
2513 // make sure we hit zero when passing through
2514 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2515 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2519 if (_x_constrained) {
2522 if (_y_constrained) {
2526 _cumulative_x_drag = cx - _grab_x;
2527 _cumulative_y_drag = cy - _grab_y;
2529 _point->line().parent_group().w2i (cx, cy);
2533 cy = min ((double) _point->line().height(), cy);
2535 //translate cx to frames
2536 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2538 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !_x_constrained) {
2539 _editor->snap_to (cx_frames);
2542 float const fraction = 1.0 - (cy / _point->line().height());
2544 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2546 _point->line().point_drag (*_point, cx_frames, fraction, push);
2548 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2552 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2554 if (!movement_occurred) {
2558 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2559 _editor->reset_point_selection ();
2563 motion (event, false);
2565 _point->line().end_drag (_point);
2568 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2571 _cumulative_y_drag (0)
2576 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2578 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2581 _item = &_line->grab_item ();
2583 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2584 origin, and ditto for y.
2587 double cx = event->button.x;
2588 double cy = event->button.y;
2590 _line->parent_group().w2i (cx, cy);
2592 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2594 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2595 /* no adjacent points */
2599 Drag::start_grab (event, _editor->fader_cursor);
2601 /* store grab start in parent frame */
2606 double fraction = 1.0 - (cy / _line->height());
2608 _line->start_drag (0, _grab_frame, fraction);
2610 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2611 _current_pointer_x + 10, _current_pointer_y + 10);
2613 _editor->show_verbose_canvas_cursor ();
2617 LineDrag::motion (GdkEvent* event, bool)
2619 double dy = _current_pointer_y - _last_pointer_y;
2621 if (event->button.state & Keyboard::SecondaryModifier) {
2625 double cy = _grab_y + _cumulative_y_drag + dy;
2627 _cumulative_y_drag = cy - _grab_y;
2630 cy = min ((double) _line->height(), cy);
2632 double const fraction = 1.0 - (cy / _line->height());
2636 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2642 _line->line_drag (_before, _after, fraction, push);
2644 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2648 LineDrag::finished (GdkEvent* event, bool)
2650 motion (event, false);
2651 _line->end_drag (0);
2655 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2657 Drag::start_grab (event);
2658 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2662 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2669 /* use a bigger drag threshold than the default */
2671 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2675 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && Config->get_rubberbanding_snaps_to_grid()) {
2677 _editor->snap_to (_grab_frame);
2679 _editor->snap_to (_current_pointer_frame);
2682 /* base start and end on initial click position */
2684 if (_current_pointer_frame < _grab_frame) {
2685 start = _current_pointer_frame;
2688 end = _current_pointer_frame;
2689 start = _grab_frame;
2692 if (_current_pointer_y < _grab_y) {
2693 y1 = _current_pointer_y;
2696 y2 = _current_pointer_y;
2701 if (start != end || y1 != y2) {
2703 double x1 = _editor->frame_to_pixel (start);
2704 double x2 = _editor->frame_to_pixel (end);
2706 _editor->rubberband_rect->property_x1() = x1;
2707 _editor->rubberband_rect->property_y1() = y1;
2708 _editor->rubberband_rect->property_x2() = x2;
2709 _editor->rubberband_rect->property_y2() = y2;
2711 _editor->rubberband_rect->show();
2712 _editor->rubberband_rect->raise_to_top();
2714 _last_pointer_frame = _current_pointer_frame;
2716 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2721 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2723 if (movement_occurred) {
2725 motion (event, false);
2728 if (_current_pointer_y < _grab_y) {
2729 y1 = _current_pointer_y;
2732 y2 = _current_pointer_y;
2737 Selection::Operation op = Keyboard::selection_type (event->button.state);
2740 _editor->begin_reversible_command (_("rubberband selection"));
2742 if (_grab_frame < _last_pointer_frame) {
2743 commit = _editor->select_all_within (_grab_frame, _last_pointer_frame, y1, y2, _editor->track_views, op);
2745 commit = _editor->select_all_within (_last_pointer_frame, _grab_frame, y1, y2, _editor->track_views, op);
2749 _editor->commit_reversible_command ();
2753 if (!getenv("ARDOUR_SAE")) {
2754 _editor->selection->clear_tracks();
2756 _editor->selection->clear_regions();
2757 _editor->selection->clear_points ();
2758 _editor->selection->clear_lines ();
2761 _editor->rubberband_rect->hide();
2765 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2767 Drag::start_grab (event);
2769 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2773 TimeFXDrag::motion (GdkEvent* event, bool)
2775 RegionView* rv = _primary;
2777 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2778 _editor->snap_to (_current_pointer_frame);
2781 if (_current_pointer_frame == _last_pointer_frame) {
2785 if (_current_pointer_frame > rv->region()->position()) {
2786 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2789 _last_pointer_frame = _current_pointer_frame;
2791 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2795 TimeFXDrag::finished (GdkEvent* event, bool movement_occurred)
2797 _primary->get_time_axis_view().hide_timestretch ();
2799 if (!movement_occurred) {
2803 if (_last_pointer_frame < _primary->region()->position()) {
2804 /* backwards drag of the left edge - not usable */
2808 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2810 float percentage = (double) newlen / (double) _primary->region()->length();
2812 #ifndef USE_RUBBERBAND
2813 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2814 if (_primary->region()->data_type() == DataType::AUDIO) {
2815 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2819 _editor->begin_reversible_command (_("timestretch"));
2821 // XXX how do timeFX on multiple regions ?
2826 if (_editor->time_stretch (rs, percentage) == 0) {
2827 _editor->session->commit_reversible_command ();
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 pending_position = adjusted_current_frame ();
2905 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2906 _editor->snap_to (pending_position);
2909 /* only alter selection if the current frame is
2910 different from the last frame position (adjusted)
2913 if (pending_position == _last_pointer_frame) {
2917 switch (_operation) {
2918 case CreateSelection:
2921 _editor->snap_to (_grab_frame);
2924 if (pending_position < _grab_frame) {
2925 start = pending_position;
2928 end = pending_position;
2929 start = _grab_frame;
2932 /* first drag: Either add to the selection
2933 or create a new selection->
2938 _editor->begin_reversible_command (_("range selection"));
2941 /* adding to the selection */
2942 _editor->clicked_selection = _editor->selection->add (start, end);
2945 /* new selection-> */
2946 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2951 case SelectionStartTrim:
2954 _editor->begin_reversible_command (_("trim selection start"));
2957 start = _editor->selection->time[_editor->clicked_selection].start;
2958 end = _editor->selection->time[_editor->clicked_selection].end;
2960 if (pending_position > end) {
2963 start = pending_position;
2967 case SelectionEndTrim:
2970 _editor->begin_reversible_command (_("trim selection end"));
2973 start = _editor->selection->time[_editor->clicked_selection].start;
2974 end = _editor->selection->time[_editor->clicked_selection].end;
2976 if (pending_position < start) {
2979 end = pending_position;
2987 _editor->begin_reversible_command (_("move selection"));
2990 start = _editor->selection->time[_editor->clicked_selection].start;
2991 end = _editor->selection->time[_editor->clicked_selection].end;
2993 length = end - start;
2995 start = pending_position;
2996 _editor->snap_to (start);
2998 end = start + length;
3003 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->canvas_width) {
3004 _editor->start_canvas_autoscroll (1, 0);
3008 _editor->selection->replace (_editor->clicked_selection, start, end);
3011 _last_pointer_frame = pending_position;
3013 if (_operation == SelectionMove) {
3014 _editor->show_verbose_time_cursor(start, 10);
3016 _editor->show_verbose_time_cursor(pending_position, 10);
3021 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3023 if (movement_occurred) {
3024 motion (event, false);
3025 /* XXX this is not object-oriented programming at all. ick */
3026 if (_editor->selection->time.consolidate()) {
3027 _editor->selection->TimeChanged ();
3029 _editor->commit_reversible_command ();
3031 /* just a click, no pointer movement.*/
3033 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3035 _editor->selection->clear_time();
3040 /* XXX what happens if its a music selection? */
3041 _editor->session->set_audio_range (_editor->selection->time);
3042 _editor->stop_canvas_autoscroll ();
3045 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3050 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3051 _drag_rect->hide ();
3053 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3054 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3058 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3060 if (_editor->session == 0) {
3064 Gdk::Cursor* cursor = 0;
3066 if (!_editor->temp_location) {
3067 _editor->temp_location = new Location;
3070 switch (_operation) {
3071 case CreateRangeMarker:
3072 case CreateTransportMarker:
3073 case CreateCDMarker:
3075 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3080 cursor = _editor->selector_cursor;
3084 Drag::start_grab (event, cursor);
3086 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3090 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3092 nframes64_t start = 0;
3093 nframes64_t end = 0;
3094 ArdourCanvas::SimpleRect *crect;
3096 switch (_operation) {
3097 case CreateRangeMarker:
3098 crect = _editor->range_bar_drag_rect;
3100 case CreateTransportMarker:
3101 crect = _editor->transport_bar_drag_rect;
3103 case CreateCDMarker:
3104 crect = _editor->cd_marker_bar_drag_rect;
3107 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3112 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3113 _editor->snap_to (_current_pointer_frame);
3116 /* only alter selection if the current frame is
3117 different from the last frame position.
3120 if (_current_pointer_frame == _last_pointer_frame) {
3124 switch (_operation) {
3125 case CreateRangeMarker:
3126 case CreateTransportMarker:
3127 case CreateCDMarker:
3129 _editor->snap_to (_grab_frame);
3132 if (_current_pointer_frame < _grab_frame) {
3133 start = _current_pointer_frame;
3136 end = _current_pointer_frame;
3137 start = _grab_frame;
3140 /* first drag: Either add to the selection
3141 or create a new selection.
3146 _editor->temp_location->set (start, end);
3150 update_item (_editor->temp_location);
3152 //_drag_rect->raise_to_top();
3158 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->canvas_width) {
3159 _editor->start_canvas_autoscroll (1, 0);
3163 _editor->temp_location->set (start, end);
3165 double x1 = _editor->frame_to_pixel (start);
3166 double x2 = _editor->frame_to_pixel (end);
3167 crect->property_x1() = x1;
3168 crect->property_x2() = x2;
3170 update_item (_editor->temp_location);
3173 _last_pointer_frame = _current_pointer_frame;
3175 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3180 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3182 Location * newloc = 0;
3186 if (movement_occurred) {
3187 motion (event, false);
3189 switch (_operation) {
3190 case CreateRangeMarker:
3191 case CreateCDMarker:
3193 _editor->begin_reversible_command (_("new range marker"));
3194 XMLNode &before = _editor->session->locations()->get_state();
3195 _editor->session->locations()->next_available_name(rangename,"unnamed");
3196 if (_operation == CreateCDMarker) {
3197 flags = Location::IsRangeMarker | Location::IsCDMarker;
3198 _editor->cd_marker_bar_drag_rect->hide();
3201 flags = Location::IsRangeMarker;
3202 _editor->range_bar_drag_rect->hide();
3204 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3205 _editor->session->locations()->add (newloc, true);
3206 XMLNode &after = _editor->session->locations()->get_state();
3207 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3208 _editor->commit_reversible_command ();
3214 case CreateTransportMarker:
3215 // popup menu to pick loop or punch
3216 _editor->new_transport_marker_context_menu (&event->button, _item);
3221 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3223 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3228 start = _editor->session->locations()->first_mark_before (_grab_frame);
3229 end = _editor->session->locations()->first_mark_after (_grab_frame);
3231 if (end == max_frames) {
3232 end = _editor->session->current_end_frame ();
3236 start = _editor->session->current_start_frame ();
3239 switch (_editor->mouse_mode) {
3241 /* find the two markers on either side and then make the selection from it */
3242 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3246 /* find the two markers on either side of the click and make the range out of it */
3247 _editor->selection->set (0, start, end);
3256 _editor->stop_canvas_autoscroll ();
3262 RangeMarkerBarDrag::update_item (Location* location)
3264 double const x1 = _editor->frame_to_pixel (location->start());
3265 double const x2 = _editor->frame_to_pixel (location->end());
3267 _drag_rect->property_x1() = x1;
3268 _drag_rect->property_x2() = x2;
3272 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3274 Drag::start_grab (event, _editor->zoom_cursor);
3275 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3279 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3284 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3285 _editor->snap_to (_current_pointer_frame);
3288 _editor->snap_to (_grab_frame);
3292 if (_current_pointer_frame == _last_pointer_frame) {
3296 /* base start and end on initial click position */
3297 if (_current_pointer_frame < _grab_frame) {
3298 start = _current_pointer_frame;
3301 end = _current_pointer_frame;
3302 start = _grab_frame;
3308 _editor->zoom_rect->show();
3309 _editor->zoom_rect->raise_to_top();
3312 _editor->reposition_zoom_rect(start, end);
3314 _last_pointer_frame = _current_pointer_frame;
3316 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3321 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3323 if (movement_occurred) {
3324 motion (event, false);
3326 if (_grab_frame < _last_pointer_frame) {
3327 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3329 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3332 _editor->temporal_zoom_to_frame (false, _grab_frame);
3334 temporal_zoom_step (false);
3335 center_screen (_grab_frame);
3339 _editor->zoom_rect->hide();