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/session.h"
24 #include "ardour/dB.h"
25 #include "ardour/region_factory.h"
26 #include "ardour/midi_diskstream.h"
30 #include "audio_region_view.h"
31 #include "midi_region_view.h"
32 #include "ardour_ui.h"
33 #include "gui_thread.h"
34 #include "control_point.h"
36 #include "region_gain_line.h"
37 #include "editor_drag.h"
38 #include "audio_time_axis.h"
39 #include "midi_time_axis.h"
40 #include "canvas-note.h"
41 #include "selection.h"
42 #include "midi_selection.h"
43 #include "automation_time_axis.h"
46 using namespace ARDOUR;
49 using namespace Editing;
50 using namespace ArdourCanvas;
52 using Gtkmm2ext::Keyboard;
54 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
56 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
59 , _pointer_frame_offset (0)
61 , _move_threshold_passed (false)
63 , _last_pointer_frame (0)
64 , _current_pointer_frame (0)
70 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
76 cursor = _editor->which_grabber_cursor ();
79 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
83 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
86 cursor = _editor->which_grabber_cursor ();
89 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
91 if (Keyboard::is_button2_event (&event->button)) {
92 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
93 _y_constrained = true;
94 _x_constrained = false;
96 _y_constrained = false;
97 _x_constrained = true;
100 _x_constrained = false;
101 _y_constrained = false;
104 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
105 _grab_frame = adjusted_frame (_grab_frame, event);
106 _last_pointer_frame = _grab_frame;
107 _current_pointer_frame = _grab_frame;
108 _current_pointer_x = _grab_x;
109 _current_pointer_y = _grab_y;
110 _last_pointer_x = _current_pointer_x;
111 _last_pointer_y = _current_pointer_y;
113 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
117 if (_editor->session() && _editor->session()->transport_rolling()) {
120 _was_rolling = false;
123 switch (_editor->snap_type()) {
124 case SnapToRegionStart:
125 case SnapToRegionEnd:
126 case SnapToRegionSync:
127 case SnapToRegionBoundary:
128 _editor->build_region_boundary_cache ();
135 /** @param event GDK event, or 0.
136 * @return true if some movement occurred, otherwise false.
139 Drag::end_grab (GdkEvent* event)
143 _editor->stop_canvas_autoscroll ();
145 _item->ungrab (event ? event->button.time : 0);
147 _last_pointer_x = _current_pointer_x;
148 _last_pointer_y = _current_pointer_y;
149 finished (event, _move_threshold_passed);
151 _editor->hide_verbose_canvas_cursor();
155 return _move_threshold_passed;
159 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
163 if (f > _pointer_frame_offset) {
164 pos = f - _pointer_frame_offset;
168 _editor->snap_to_with_modifier (pos, event);
175 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
177 return adjusted_frame (_current_pointer_frame, event, snap);
181 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
183 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
185 /* check to see if we have moved in any way that matters since the last motion event */
186 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
187 (!y_movement_matters() || _last_pointer_y == _current_pointer_y) ) {
191 pair<nframes64_t, int> const threshold = move_threshold ();
193 bool const old_move_threshold_passed = _move_threshold_passed;
195 if (!from_autoscroll && !_move_threshold_passed) {
197 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
198 bool const yp = (::fabs ((_current_pointer_y - _grab_y)) >= threshold.second);
200 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
203 if (active (_editor->mouse_mode) && _move_threshold_passed) {
205 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
206 if (!from_autoscroll) {
207 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
210 motion (event, _move_threshold_passed != old_move_threshold_passed);
212 _last_pointer_x = _current_pointer_x;
213 _last_pointer_y = _current_pointer_y;
214 _last_pointer_frame = adjusted_current_frame (event);
234 _editor->stop_canvas_autoscroll ();
235 _editor->hide_verbose_canvas_cursor ();
240 pair<nframes64_t, nframes64_t>
241 Drag::extent () const
243 nframes64_t const f = adjusted_current_frame (0);
244 return make_pair (f, f);
247 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
252 RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
256 RegionDrag::region_going_away (RegionView* v)
263 pair<nframes64_t, nframes64_t>
264 RegionDrag::extent () const
266 nframes64_t const f = adjusted_current_frame (0);
267 return make_pair (f, f + _primary->region()->length ());
271 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
272 : RegionDrag (e, i, p, v),
283 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
285 Drag::start_grab (event);
287 _editor->show_verbose_time_cursor (_last_frame_position, 10);
290 RegionMotionDrag::TimeAxisViewSummary
291 RegionMotionDrag::get_time_axis_view_summary ()
293 int32_t children = 0;
294 TimeAxisViewSummary sum;
296 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
298 /* get a bitmask representing the visible tracks */
300 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
301 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
302 TimeAxisView::Children children_list;
304 /* zeroes are audio/MIDI tracks. ones are other types. */
306 if (!rtv->hidden()) {
308 if (!rtv->is_track()) {
309 /* not an audio nor MIDI track */
310 sum.tracks = sum.tracks |= (0x01 << rtv->order());
313 sum.height_list[rtv->order()] = (*i)->current_height();
316 if ((children_list = rtv->get_child_list()).size() > 0) {
317 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
318 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
319 sum.height_list[rtv->order() + children] = (*j)->current_height();
330 RegionMotionDrag::compute_y_delta (
331 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
332 int32_t last_pointer_layer, int32_t current_pointer_layer,
333 TimeAxisViewSummary const & tavs,
334 int32_t* pointer_order_span, int32_t* pointer_layer_span,
335 int32_t* canvas_pointer_order_span
339 *pointer_order_span = 0;
340 *pointer_layer_span = 0;
344 bool clamp_y_axis = false;
346 /* the change in track order between this callback and the last */
347 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
348 /* the change in layer between this callback and the last;
349 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
350 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
352 if (*pointer_order_span != 0) {
354 /* find the actual pointer span, in terms of the number of visible tracks;
355 to do this, we reduce |pointer_order_span| by the number of hidden tracks
358 *canvas_pointer_order_span = *pointer_order_span;
359 if (last_pointer_view->order() >= current_pointer_view->order()) {
360 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
361 if (tavs.height_list[y] == 0) {
362 *canvas_pointer_order_span--;
366 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
367 if (tavs.height_list[y] == 0) {
368 *canvas_pointer_order_span++;
373 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
375 RegionView* rv = (*i);
377 if (rv->region()->locked()) {
381 double ix1, ix2, iy1, iy2;
382 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
383 rv->get_canvas_frame()->i2w (ix1, iy1);
384 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
386 /* get the new trackview for this particular region */
387 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
389 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
391 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
392 as surely this is a per-region thing... */
394 clamp_y_axis = y_movement_disallowed (
395 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
403 } else if (_dest_trackview == current_pointer_view) {
405 if (current_pointer_layer == last_pointer_layer) {
406 /* No movement; clamp */
412 _dest_trackview = current_pointer_view;
413 _dest_layer = current_pointer_layer;
421 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
423 /* compute the amount of pointer motion in frames, and where
424 the region would be if we moved it by that much.
426 *pending_region_position = adjusted_current_frame (event);
428 nframes64_t sync_frame;
429 nframes64_t sync_offset;
432 sync_offset = _primary->region()->sync_offset (sync_dir);
434 /* we don't handle a sync point that lies before zero.
436 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
438 sync_frame = *pending_region_position + (sync_dir*sync_offset);
440 _editor->snap_to_with_modifier (sync_frame, event);
442 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
445 *pending_region_position = _last_frame_position;
448 if (*pending_region_position > max_frames - _primary->region()->length()) {
449 *pending_region_position = _last_frame_position;
454 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
456 /* now compute the canvas unit distance we need to move the regionview
457 to make it appear at the new location.
460 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
462 if (*pending_region_position <= _last_frame_position) {
464 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
466 RegionView* rv = (*i);
468 // If any regionview is at zero, we need to know so we can stop further leftward motion.
470 double ix1, ix2, iy1, iy2;
471 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
472 rv->get_canvas_frame()->i2w (ix1, iy1);
474 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
476 *pending_region_position = _last_frame_position;
483 _last_frame_position = *pending_region_position;
490 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
494 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
496 vector<int32_t>::iterator j;
498 /* *pointer* variables reflect things about the pointer; as we may be moving
499 multiple regions, much detail must be computed per-region */
501 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
502 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
503 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
504 is always 0 regardless of what the region's "real" layer is */
505 RouteTimeAxisView* current_pointer_view;
506 layer_t current_pointer_layer;
507 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
511 /* TimeAxisView that we were pointing at last time we entered this method */
512 TimeAxisView const * const last_pointer_view = _dest_trackview;
513 /* the order of the track that we were pointing at last time we entered this method */
514 int32_t const last_pointer_order = last_pointer_view->order ();
515 /* the layer that we were pointing at last time we entered this method */
516 layer_t const last_pointer_layer = _dest_layer;
518 int32_t pointer_order_span;
519 int32_t pointer_layer_span;
520 int32_t canvas_pointer_order_span;
522 bool const clamp_y_axis = compute_y_delta (
523 last_pointer_view, current_pointer_view,
524 last_pointer_layer, current_pointer_layer, tavs,
525 &pointer_order_span, &pointer_layer_span,
526 &canvas_pointer_order_span
529 nframes64_t pending_region_position;
530 double const x_delta = compute_x_delta (event, &pending_region_position);
532 /*************************************************************
534 ************************************************************/
536 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
537 /* haven't reached next snap point, and we're not switching
538 trackviews nor layers. nothing to do.
543 /*************************************************************
545 ************************************************************/
547 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
549 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
551 RegionView* rv = (*i);
553 if (rv->region()->locked()) {
557 /* here we are calculating the y distance from the
558 top of the first track view to the top of the region
559 area of the track view that we're working on */
561 /* this x value is just a dummy value so that we have something
566 /* distance from the top of this track view to the region area
567 of our track view is always 1 */
571 /* convert to world coordinates, ie distance from the top of
574 rv->get_canvas_frame()->i2w (ix1, iy1);
576 /* compensate for the ruler section and the vertical scrollbar position */
577 iy1 += _editor->get_trackview_group_vertical_offset ();
581 // hide any dependent views
583 rv->get_time_axis_view().hide_dependent_views (*rv);
586 reparent to a non scrolling group so that we can keep the
587 region selection above all time axis views.
588 reparenting means we have to move the rv as the two
589 parent groups have different coordinates.
592 rv->get_canvas_group()->property_y() = iy1 - 1;
593 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
595 rv->fake_set_opaque (true);
598 /* current view for this particular region */
599 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
600 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
602 if (pointer_order_span != 0 && !clamp_y_axis) {
604 /* INTER-TRACK MOVEMENT */
606 /* move through the height list to the track that the region is currently on */
607 vector<int32_t>::iterator j = tavs.height_list.begin ();
609 while (j != tavs.height_list.end () && x != rtv->order ()) {
615 int32_t temp_pointer_order_span = canvas_pointer_order_span;
617 if (j != tavs.height_list.end ()) {
619 /* Account for layers in the original and
620 destination tracks. If we're moving around in layers we assume
621 that only one track is involved, so it's ok to use *pointer*
624 StreamView* lv = last_pointer_view->view ();
627 /* move to the top of the last trackview */
628 if (lv->layer_display () == Stacked) {
629 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
632 StreamView* cv = current_pointer_view->view ();
635 /* move to the right layer on the current trackview */
636 if (cv->layer_display () == Stacked) {
637 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
640 /* And for being on a non-topmost layer on the new
643 while (temp_pointer_order_span > 0) {
644 /* we're moving up canvas-wise,
645 so we need to find the next track height
647 if (j != tavs.height_list.begin()) {
651 if (x != last_pointer_order) {
653 ++temp_pointer_order_span;
658 temp_pointer_order_span--;
661 while (temp_pointer_order_span < 0) {
665 if (x != last_pointer_order) {
667 --temp_pointer_order_span;
671 if (j != tavs.height_list.end()) {
675 temp_pointer_order_span++;
679 /* find out where we'll be when we move and set height accordingly */
681 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
682 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
683 rv->set_height (temp_rtv->view()->child_height());
685 /* if you un-comment the following, the region colours will follow
686 the track colours whilst dragging; personally
687 i think this can confuse things, but never mind.
690 //const GdkColor& col (temp_rtv->view->get_region_color());
691 //rv->set_color (const_cast<GdkColor&>(col));
695 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
697 /* INTER-LAYER MOVEMENT in the same track */
698 y_delta = rtv->view()->child_height () * pointer_layer_span;
703 _editor->mouse_brush_insert_region (rv, pending_region_position);
705 rv->move (x_delta, y_delta);
708 } /* foreach region */
710 _total_x_delta += x_delta;
713 _editor->cursor_group->raise_to_top();
716 if (x_delta != 0 && !_brushing) {
717 _editor->show_verbose_time_cursor (_last_frame_position, 10);
722 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
724 if (_copy && first_move) {
725 copy_regions (event);
728 RegionMotionDrag::motion (event, first_move);
732 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
734 vector<RegionView*> copies;
735 boost::shared_ptr<Diskstream> ds;
736 boost::shared_ptr<Playlist> from_playlist;
737 RegionSelection new_views;
738 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
739 PlaylistSet modified_playlists;
740 PlaylistSet frozen_playlists;
741 list <sigc::connection> modified_playlist_connections;
742 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
743 nframes64_t drag_delta;
744 bool changed_tracks, changed_position;
745 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
746 RouteTimeAxisView* source_tv;
748 if (!movement_occurred) {
754 /* all changes were made during motion event handlers */
757 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
758 copies.push_back (*i);
765 /* reverse this here so that we have the correct logic to finalize
769 if (Config->get_edit_mode() == Lock) {
770 _x_constrained = !_x_constrained;
774 if (_x_constrained) {
775 _editor->begin_reversible_command (_("fixed time region copy"));
777 _editor->begin_reversible_command (_("region copy"));
780 if (_x_constrained) {
781 _editor->begin_reversible_command (_("fixed time region drag"));
783 _editor->begin_reversible_command (_("region drag"));
787 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
788 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
790 drag_delta = _primary->region()->position() - _last_frame_position;
792 _editor->update_canvas_now ();
794 /* make a list of where each region ended up */
795 final = find_time_axis_views_and_layers ();
797 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
799 RegionView* rv = (*i);
800 RouteTimeAxisView* dest_rtv = final[*i].first;
801 layer_t dest_layer = final[*i].second;
805 if (rv->region()->locked()) {
810 if (changed_position && !_x_constrained) {
811 where = rv->region()->position() - drag_delta;
813 where = rv->region()->position();
816 boost::shared_ptr<Region> new_region;
819 /* we already made a copy */
820 new_region = rv->region();
822 /* undo the previous hide_dependent_views so that xfades don't
823 disappear on copying regions
826 //rv->get_time_axis_view().reveal_dependent_views (*rv);
828 } else if (changed_tracks && dest_rtv->playlist()) {
829 new_region = RegionFactory::create (rv->region());
832 if (changed_tracks || _copy) {
834 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
841 _editor->latest_regionviews.clear ();
843 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
845 insert_result = modified_playlists.insert (to_playlist);
847 if (insert_result.second) {
848 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
851 to_playlist->add_region (new_region, where);
852 if (dest_rtv->view()->layer_display() == Stacked) {
853 new_region->set_layer (dest_layer);
854 new_region->set_pending_explicit_relayer (true);
859 if (!_editor->latest_regionviews.empty()) {
860 // XXX why just the first one ? we only expect one
861 // commented out in nick_m's canvas reworking. is that intended?
862 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
863 new_views.push_back (_editor->latest_regionviews.front());
868 motion on the same track. plonk the previously reparented region
869 back to its original canvas group (its streamview).
870 No need to do anything for copies as they are fake regions which will be deleted.
873 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
874 rv->get_canvas_group()->property_y() = 0;
875 rv->get_time_axis_view().reveal_dependent_views (*rv);
877 /* just change the model */
879 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
881 if (dest_rtv->view()->layer_display() == Stacked) {
882 rv->region()->set_layer (dest_layer);
883 rv->region()->set_pending_explicit_relayer (true);
886 insert_result = modified_playlists.insert (playlist);
888 if (insert_result.second) {
889 _editor->session()->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
891 /* freeze to avoid lots of relayering in the case of a multi-region drag */
892 frozen_insert_result = frozen_playlists.insert(playlist);
894 if (frozen_insert_result.second) {
898 rv->region()->set_position (where, (void*) this);
901 if (changed_tracks && !_copy) {
903 /* get the playlist where this drag started. we can't use rv->region()->playlist()
904 because we may have copied the region and it has not been attached to a playlist.
907 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
908 ds = source_tv->get_diskstream();
909 from_playlist = ds->playlist();
913 assert (from_playlist);
915 /* moved to a different audio track, without copying */
917 /* the region that used to be in the old playlist is not
918 moved to the new one - we use a copy of it. as a result,
919 any existing editor for the region should no longer be
923 rv->hide_region_editor();
924 rv->fake_set_opaque (false);
926 /* remove the region from the old playlist */
928 insert_result = modified_playlists.insert (from_playlist);
930 if (insert_result.second) {
931 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
934 from_playlist->remove_region (rv->region());
936 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
937 was selected in all of them, then removing it from a playlist will have removed all
938 trace of it from the selection (i.e. there were N regions selected, we removed 1,
939 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
940 corresponding regionview, and the selection is now empty).
942 this could have invalidated any and all iterators into the region selection.
944 the heuristic we use here is: if the region selection is empty, break out of the loop
945 here. if the region selection is not empty, then restart the loop because we know that
946 we must have removed at least the region(view) we've just been working on as well as any
947 that we processed on previous iterations.
949 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
953 if (_views.empty()) {
964 copies.push_back (rv);
968 if we've created new regions either by copying or moving
969 to a new track, we want to replace the old selection with the new ones
971 if (new_views.size() > 0) {
972 _editor->selection->set (new_views);
975 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
980 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
981 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
984 _editor->commit_reversible_command ();
986 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
992 RegionMoveDrag::aborted ()
996 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1003 RegionMotionDrag::aborted ();
1008 RegionMotionDrag::aborted ()
1010 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1011 TimeAxisView* tv = &(*i)->get_time_axis_view ();
1012 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1014 (*i)->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1015 (*i)->get_canvas_group()->property_y() = 0;
1016 (*i)->get_time_axis_view().reveal_dependent_views (**i);
1017 (*i)->fake_set_opaque (false);
1018 (*i)->move (-_total_x_delta, 0);
1019 (*i)->set_height (rtv->view()->child_height ());
1022 _editor->update_canvas_now ();
1027 RegionMotionDrag::x_move_allowed () const
1029 if (Config->get_edit_mode() == Lock) {
1030 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1031 return _x_constrained;
1034 return !_x_constrained;
1038 RegionMotionDrag::copy_regions (GdkEvent* event)
1040 /* duplicate the regionview(s) and region(s) */
1042 list<RegionView*> new_regionviews;
1044 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1046 RegionView* rv = (*i);
1047 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1048 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1050 const boost::shared_ptr<const Region> original = rv->region();
1051 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1055 boost::shared_ptr<AudioRegion> audioregion_copy
1056 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1057 nrv = new AudioRegionView (*arv, audioregion_copy);
1059 boost::shared_ptr<MidiRegion> midiregion_copy
1060 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1061 nrv = new MidiRegionView (*mrv, midiregion_copy);
1066 nrv->get_canvas_group()->show ();
1067 new_regionviews.push_back (nrv);
1069 /* swap _primary to the copy */
1071 if (rv == _primary) {
1075 /* ..and deselect the one we copied */
1077 rv->set_selected (false);
1080 if (new_regionviews.empty()) {
1084 /* reflect the fact that we are dragging the copies */
1086 _views = new_regionviews;
1088 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1091 sync the canvas to what we think is its current state
1092 without it, the canvas seems to
1093 "forget" to update properly after the upcoming reparent()
1094 ..only if the mouse is in rapid motion at the time of the grab.
1095 something to do with regionview creation taking so long?
1097 _editor->update_canvas_now();
1101 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1103 /* Which trackview is this ? */
1105 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1106 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1107 (*layer) = tvp.second;
1109 if (*tv && (*tv)->layer_display() == Overlaid) {
1113 /* The region motion is only processed if the pointer is over
1117 if (!(*tv) || !(*tv)->is_track()) {
1118 /* To make sure we hide the verbose canvas cursor when the mouse is
1119 not held over and audiotrack.
1121 _editor->hide_verbose_canvas_cursor ();
1128 /** @param new_order New track order.
1129 * @param old_order Old track order.
1130 * @param visible_y_low Lowest visible order.
1131 * @return true if y movement should not happen, otherwise false.
1134 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1136 if (new_order != old_order) {
1138 /* this isn't the pointer track */
1142 /* moving up the canvas */
1143 if ( (new_order - y_span) >= tavs.visible_y_low) {
1147 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1148 int32_t visible_tracks = 0;
1149 while (visible_tracks < y_span ) {
1151 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1152 /* passing through a hidden track */
1157 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1158 /* moving to a non-track; disallow */
1164 /* moving beyond the lowest visible track; disallow */
1168 } else if (y_span < 0) {
1170 /* moving down the canvas */
1171 if ((new_order - y_span) <= tavs.visible_y_high) {
1173 int32_t visible_tracks = 0;
1175 while (visible_tracks > y_span ) {
1178 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1179 /* passing through a hidden track */
1184 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1185 /* moving to a non-track; disallow */
1192 /* moving beyond the highest visible track; disallow */
1199 /* this is the pointer's track */
1201 if ((new_order - y_span) > tavs.visible_y_high) {
1202 /* we will overflow */
1204 } else if ((new_order - y_span) < tavs.visible_y_low) {
1205 /* we will overflow */
1214 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1215 : RegionMotionDrag (e, i, p, v, b),
1218 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1220 _dest_trackview = tv;
1221 if (tv->layer_display() == Overlaid) {
1224 _dest_layer = _primary->region()->layer ();
1228 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1229 if (rtv && rtv->is_track()) {
1230 speed = rtv->get_diskstream()->speed ();
1233 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1237 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1239 RegionMotionDrag::start_grab (event, c);
1241 _pointer_frame_offset = grab_frame() - _last_frame_position;
1244 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1245 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1247 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1248 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1250 _primary = v->view()->create_region_view (r, false, false);
1252 _primary->get_canvas_group()->show ();
1253 _primary->set_position (pos, 0);
1254 _views.push_back (_primary);
1256 _last_frame_position = pos;
1258 _item = _primary->get_canvas_group ();
1259 _dest_trackview = v;
1260 _dest_layer = _primary->region()->layer ();
1263 map<RegionView*, pair<RouteTimeAxisView*, int> >
1264 RegionMotionDrag::find_time_axis_views_and_layers ()
1266 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1268 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1270 double ix1, ix2, iy1, iy2;
1271 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1272 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1273 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1275 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1276 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1284 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1286 _editor->update_canvas_now ();
1288 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1290 RouteTimeAxisView* dest_rtv = final[_primary].first;
1292 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1293 _primary->get_canvas_group()->property_y() = 0;
1295 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1297 _editor->begin_reversible_command (_("insert region"));
1298 XMLNode& before = playlist->get_state ();
1299 playlist->add_region (_primary->region (), _last_frame_position);
1300 _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1301 _editor->commit_reversible_command ();
1309 RegionInsertDrag::aborted ()
1314 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1315 : RegionMoveDrag (e, i, p, v, false, false)
1320 struct RegionSelectionByPosition {
1321 bool operator() (RegionView*a, RegionView* b) {
1322 return a->region()->position () < b->region()->position();
1327 RegionSpliceDrag::motion (GdkEvent* event, bool)
1329 RouteTimeAxisView* tv;
1332 if (!check_possible (&tv, &layer)) {
1338 if ((current_pointer_x() - last_pointer_x()) > 0) {
1344 RegionSelection copy (_editor->selection->regions);
1346 RegionSelectionByPosition cmp;
1349 nframes64_t const pf = adjusted_current_frame (event);
1351 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1353 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1359 boost::shared_ptr<Playlist> playlist;
1361 if ((playlist = atv->playlist()) == 0) {
1365 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1370 if (pf < (*i)->region()->last_frame() + 1) {
1374 if (pf > (*i)->region()->first_frame()) {
1380 playlist->shuffle ((*i)->region(), dir);
1385 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1391 RegionSpliceDrag::aborted ()
1396 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1404 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1406 _dest_trackview = _view;
1408 Drag::start_grab (event);
1413 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1416 // TODO: create region-create-drag region view here
1419 // TODO: resize region-create-drag region view here
1423 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1425 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1431 if (!movement_occurred) {
1432 mtv->add_region (grab_frame ());
1434 motion (event, false);
1435 // TODO: create region-create-drag region here
1440 RegionCreateDrag::aborted ()
1445 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1453 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1456 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1458 Drag::start_grab (event);
1460 region = &cnote->region_view();
1462 double region_start = region->get_position_pixels();
1463 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1465 if (grab_x() <= middle_point) {
1466 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1469 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1473 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1475 if (event->motion.state & Keyboard::PrimaryModifier) {
1481 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1483 if (ms.size() > 1) {
1484 /* has to be relative, may make no sense otherwise */
1488 region->note_selected (cnote, true);
1490 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1491 MidiRegionSelection::iterator next;
1494 (*r)->begin_resizing (at_front);
1500 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1502 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1503 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1504 (*r)->update_resizing (at_front, current_pointer_x() - grab_x(), relative);
1509 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1511 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1512 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1513 (*r)->commit_resizing (at_front, current_pointer_x() - grab_x(), relative);
1518 NoteResizeDrag::aborted ()
1524 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1530 RegionGainDrag::finished (GdkEvent *, bool)
1536 RegionGainDrag::aborted ()
1541 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1542 : RegionDrag (e, i, p, v)
1543 , _have_transaction (false)
1549 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1552 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1553 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1555 if (tv && tv->is_track()) {
1556 speed = tv->get_diskstream()->speed();
1559 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1560 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1561 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1563 Drag::start_grab (event, _editor->trimmer_cursor);
1565 nframes64_t const pf = adjusted_current_frame (event);
1567 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1568 _operation = ContentsTrim;
1570 /* These will get overridden for a point trim.*/
1571 if (pf < (region_start + region_length/2)) {
1572 /* closer to start */
1573 _operation = StartTrim;
1574 } else if (pf > (region_end - region_length/2)) {
1576 _operation = EndTrim;
1580 switch (_operation) {
1582 _editor->show_verbose_time_cursor (region_start, 10);
1585 _editor->show_verbose_time_cursor (region_end, 10);
1588 _editor->show_verbose_time_cursor (pf, 10);
1594 TrimDrag::motion (GdkEvent* event, bool first_move)
1596 RegionView* rv = _primary;
1597 nframes64_t frame_delta = 0;
1599 bool left_direction;
1600 bool obey_snap = event ? !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) : false;
1602 /* snap modifier works differently here..
1603 its current state has to be passed to the
1604 various trim functions in order to work properly
1608 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1609 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1610 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1612 if (tv && tv->is_track()) {
1613 speed = tv->get_diskstream()->speed();
1616 nframes64_t const pf = adjusted_current_frame (event);
1618 if (last_pointer_frame() > pf) {
1619 left_direction = true;
1621 left_direction = false;
1628 switch (_operation) {
1630 trim_type = "Region start trim";
1633 trim_type = "Region end trim";
1636 trim_type = "Region content trim";
1640 _editor->begin_reversible_command (trim_type);
1641 _have_transaction = true;
1643 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1644 (*i)->fake_set_opaque(false);
1645 (*i)->region()->freeze ();
1647 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1650 arv->temporarily_hide_envelope ();
1653 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1654 insert_result = _editor->motion_frozen_playlists.insert (pl);
1656 if (insert_result.second) {
1657 _editor->session()->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1663 if (left_direction) {
1664 frame_delta = (last_pointer_frame() - pf);
1666 frame_delta = (pf - last_pointer_frame());
1669 bool non_overlap_trim = false;
1671 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1672 non_overlap_trim = true;
1675 switch (_operation) {
1677 if ((left_direction == false) && (pf <= rv->region()->first_frame()/speed)) {
1681 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1682 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1688 if ((left_direction == true) && (pf > (nframes64_t) (rv->region()->last_frame()/speed))) {
1692 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1693 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1700 bool swap_direction = false;
1702 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1703 swap_direction = true;
1706 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1707 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1713 switch (_operation) {
1715 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1718 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1721 _editor->show_verbose_time_cursor (pf, 10);
1728 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1730 if (movement_occurred) {
1731 motion (event, false);
1733 if (!_editor->selection->selected (_primary)) {
1734 _editor->thaw_region_after_trim (*_primary);
1737 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1738 _editor->thaw_region_after_trim (**i);
1739 (*i)->fake_set_opaque (true);
1742 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1744 if (_have_transaction) {
1745 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1749 _editor->motion_frozen_playlists.clear ();
1751 if (_have_transaction) {
1752 _editor->commit_reversible_command();
1756 /* no mouse movement */
1757 _editor->point_trim (event);
1762 TrimDrag::aborted ()
1764 /* Our motion method is changing model state, so use the Undo system
1765 to cancel. Perhaps not ideal, as this will leave an Undo point
1766 behind which may be slightly odd from the user's point of view.
1771 if (_have_transaction) {
1776 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1780 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1785 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1788 // create a dummy marker for visual representation of moving the copy.
1789 // The actual copying is not done before we reach the finish callback.
1791 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1792 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1793 *new MeterSection (_marker->meter()));
1795 _item = &new_marker->the_item ();
1796 _marker = new_marker;
1800 MetricSection& section (_marker->meter());
1802 if (!section.movable()) {
1808 Drag::start_grab (event, cursor);
1810 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1812 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1816 MeterMarkerDrag::motion (GdkEvent* event, bool)
1818 nframes64_t const pf = adjusted_current_frame (event);
1820 _marker->set_position (pf);
1822 _editor->show_verbose_time_cursor (pf, 10);
1826 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1828 if (!movement_occurred) {
1832 motion (event, false);
1836 TempoMap& map (_editor->session()->tempo_map());
1837 map.bbt_time (last_pointer_frame(), when);
1839 if (_copy == true) {
1840 _editor->begin_reversible_command (_("copy meter mark"));
1841 XMLNode &before = map.get_state();
1842 map.add_meter (_marker->meter(), when);
1843 XMLNode &after = map.get_state();
1844 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1845 _editor->commit_reversible_command ();
1847 // delete the dummy marker we used for visual representation of copying.
1848 // a new visual marker will show up automatically.
1851 _editor->begin_reversible_command (_("move meter mark"));
1852 XMLNode &before = map.get_state();
1853 map.move_meter (_marker->meter(), when);
1854 XMLNode &after = map.get_state();
1855 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1856 _editor->commit_reversible_command ();
1861 MeterMarkerDrag::aborted ()
1863 _marker->set_position (_marker->meter().frame ());
1866 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1870 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1875 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1880 // create a dummy marker for visual representation of moving the copy.
1881 // The actual copying is not done before we reach the finish callback.
1883 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1884 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1885 *new TempoSection (_marker->tempo()));
1887 _item = &new_marker->the_item ();
1888 _marker = new_marker;
1892 MetricSection& section (_marker->tempo());
1894 if (!section.movable()) {
1899 Drag::start_grab (event, cursor);
1901 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
1902 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
1906 TempoMarkerDrag::motion (GdkEvent* event, bool)
1908 nframes64_t const pf = adjusted_current_frame (event);
1909 _marker->set_position (pf);
1910 _editor->show_verbose_time_cursor (pf, 10);
1914 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1916 if (!movement_occurred) {
1920 motion (event, false);
1924 TempoMap& map (_editor->session()->tempo_map());
1925 map.bbt_time (last_pointer_frame(), when);
1927 if (_copy == true) {
1928 _editor->begin_reversible_command (_("copy tempo mark"));
1929 XMLNode &before = map.get_state();
1930 map.add_tempo (_marker->tempo(), when);
1931 XMLNode &after = map.get_state();
1932 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1933 _editor->commit_reversible_command ();
1935 // delete the dummy marker we used for visual representation of copying.
1936 // a new visual marker will show up automatically.
1939 _editor->begin_reversible_command (_("move tempo mark"));
1940 XMLNode &before = map.get_state();
1941 map.move_tempo (_marker->tempo(), when);
1942 XMLNode &after = map.get_state();
1943 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1944 _editor->commit_reversible_command ();
1949 TempoMarkerDrag::aborted ()
1951 _marker->set_position (_marker->tempo().frame());
1954 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1958 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1963 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1965 Drag::start_grab (event, c);
1969 nframes64_t where = _editor->event_frame (event, 0, 0);
1971 _editor->snap_to_with_modifier (where, event);
1972 _editor->playhead_cursor->set_position (where);
1976 if (_cursor == _editor->playhead_cursor) {
1977 _editor->_dragging_playhead = true;
1979 if (_editor->session() && _was_rolling && _stop) {
1980 _editor->session()->request_stop ();
1983 if (_editor->session() && _editor->session()->is_auditioning()) {
1984 _editor->session()->cancel_audition ();
1988 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
1990 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1994 CursorDrag::motion (GdkEvent* event, bool)
1996 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1998 if (adjusted_frame == last_pointer_frame()) {
2002 _cursor->set_position (adjusted_frame);
2004 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2007 _editor->update_canvas_now ();
2009 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2013 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2015 _editor->_dragging_playhead = false;
2017 if (!movement_occurred && _stop) {
2021 motion (event, false);
2023 if (_item == &_editor->playhead_cursor->canvas_item) {
2024 if (_editor->session()) {
2025 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2026 _editor->_pending_locate_request = true;
2032 CursorDrag::aborted ()
2034 _editor->_dragging_playhead = false;
2035 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2038 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2039 : RegionDrag (e, i, p, v)
2045 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2047 Drag::start_grab (event, cursor);
2049 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2050 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2052 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2053 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2057 FadeInDrag::motion (GdkEvent* event, bool)
2059 nframes64_t fade_length;
2061 nframes64_t const pos = adjusted_current_frame (event);
2063 boost::shared_ptr<Region> region = _primary->region ();
2065 if (pos < (region->position() + 64)) {
2066 fade_length = 64; // this should be a minimum defined somewhere
2067 } else if (pos > region->last_frame()) {
2068 fade_length = region->length();
2070 fade_length = pos - region->position();
2073 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2075 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2081 tmp->reset_fade_in_shape_width (fade_length);
2084 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2088 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2090 if (!movement_occurred) {
2094 nframes64_t fade_length;
2096 nframes64_t const pos = adjusted_current_frame (event);
2098 boost::shared_ptr<Region> region = _primary->region ();
2100 if (pos < (region->position() + 64)) {
2101 fade_length = 64; // this should be a minimum defined somewhere
2102 } else if (pos > region->last_frame()) {
2103 fade_length = region->length();
2105 fade_length = pos - region->position();
2108 _editor->begin_reversible_command (_("change fade in length"));
2110 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2112 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2118 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2119 XMLNode &before = alist->get_state();
2121 tmp->audio_region()->set_fade_in_length (fade_length);
2122 tmp->audio_region()->set_fade_in_active (true);
2124 XMLNode &after = alist->get_state();
2125 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2128 _editor->commit_reversible_command ();
2132 FadeInDrag::aborted ()
2134 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2135 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2141 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2145 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2146 : RegionDrag (e, i, p, v)
2152 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2154 Drag::start_grab (event, cursor);
2156 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2157 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2159 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2160 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2164 FadeOutDrag::motion (GdkEvent* event, bool)
2166 nframes64_t fade_length;
2168 nframes64_t const pos = adjusted_current_frame (event);
2170 boost::shared_ptr<Region> region = _primary->region ();
2172 if (pos > (region->last_frame() - 64)) {
2173 fade_length = 64; // this should really be a minimum fade defined somewhere
2175 else if (pos < region->position()) {
2176 fade_length = region->length();
2179 fade_length = region->last_frame() - pos;
2182 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2184 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2190 tmp->reset_fade_out_shape_width (fade_length);
2193 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2197 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2199 if (!movement_occurred) {
2203 nframes64_t fade_length;
2205 nframes64_t const pos = adjusted_current_frame (event);
2207 boost::shared_ptr<Region> region = _primary->region ();
2209 if (pos > (region->last_frame() - 64)) {
2210 fade_length = 64; // this should really be a minimum fade defined somewhere
2212 else if (pos < region->position()) {
2213 fade_length = region->length();
2216 fade_length = region->last_frame() - pos;
2219 _editor->begin_reversible_command (_("change fade out length"));
2221 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2223 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2229 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2230 XMLNode &before = alist->get_state();
2232 tmp->audio_region()->set_fade_out_length (fade_length);
2233 tmp->audio_region()->set_fade_out_active (true);
2235 XMLNode &after = alist->get_state();
2236 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2239 _editor->commit_reversible_command ();
2243 FadeOutDrag::aborted ()
2245 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2246 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2252 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2256 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2259 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2262 _points.push_back (Gnome::Art::Point (0, 0));
2263 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2265 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2266 _line->property_width_pixels() = 1;
2267 _line->property_points () = _points;
2270 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2273 MarkerDrag::~MarkerDrag ()
2275 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2281 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2283 Drag::start_grab (event, cursor);
2287 Location *location = _editor->find_location_from_marker (_marker, is_start);
2288 _editor->_dragging_edit_point = true;
2290 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2292 update_item (location);
2294 // _drag_line->show();
2295 // _line->raise_to_top();
2298 _editor->show_verbose_time_cursor (location->start(), 10);
2300 _editor->show_verbose_time_cursor (location->end(), 10);
2303 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2306 case Selection::Toggle:
2307 _editor->selection->toggle (_marker);
2309 case Selection::Set:
2310 if (!_editor->selection->selected (_marker)) {
2311 _editor->selection->set (_marker);
2314 case Selection::Extend:
2316 Locations::LocationList ll;
2317 list<Marker*> to_add;
2319 _editor->selection->markers.range (s, e);
2320 s = min (_marker->position(), s);
2321 e = max (_marker->position(), e);
2324 if (e < max_frames) {
2327 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2328 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2329 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2332 to_add.push_back (lm->start);
2335 to_add.push_back (lm->end);
2339 if (!to_add.empty()) {
2340 _editor->selection->add (to_add);
2344 case Selection::Add:
2345 _editor->selection->add (_marker);
2349 /* set up copies for us to manipulate during the drag */
2351 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2352 Location *l = _editor->find_location_from_marker (*i, is_start);
2353 _copied_locations.push_back (new Location (*l));
2358 MarkerDrag::motion (GdkEvent* event, bool)
2360 nframes64_t f_delta = 0;
2362 bool move_both = false;
2364 Location *real_location;
2365 Location *copy_location = 0;
2367 nframes64_t const newframe = adjusted_current_frame (event);
2369 nframes64_t next = newframe;
2371 if (newframe == last_pointer_frame()) {
2375 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2379 MarkerSelection::iterator i;
2380 list<Location*>::iterator x;
2382 /* find the marker we're dragging, and compute the delta */
2384 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2385 x != _copied_locations.end() && i != _editor->selection->markers.end();
2391 if (marker == _marker) {
2393 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2398 if (real_location->is_mark()) {
2399 f_delta = newframe - copy_location->start();
2403 switch (marker->type()) {
2405 case Marker::LoopStart:
2406 case Marker::PunchIn:
2407 f_delta = newframe - copy_location->start();
2411 case Marker::LoopEnd:
2412 case Marker::PunchOut:
2413 f_delta = newframe - copy_location->end();
2416 /* what kind of marker is this ? */
2424 if (i == _editor->selection->markers.end()) {
2425 /* hmm, impossible - we didn't find the dragged marker */
2429 /* now move them all */
2431 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2432 x != _copied_locations.end() && i != _editor->selection->markers.end();
2438 /* call this to find out if its the start or end */
2440 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2444 if (real_location->locked()) {
2448 if (copy_location->is_mark()) {
2452 copy_location->set_start (copy_location->start() + f_delta);
2456 nframes64_t new_start = copy_location->start() + f_delta;
2457 nframes64_t new_end = copy_location->end() + f_delta;
2459 if (is_start) { // start-of-range marker
2462 copy_location->set_start (new_start);
2463 copy_location->set_end (new_end);
2464 } else if (new_start < copy_location->end()) {
2465 copy_location->set_start (new_start);
2467 _editor->snap_to (next, 1, true);
2468 copy_location->set_end (next);
2469 copy_location->set_start (newframe);
2472 } else { // end marker
2475 copy_location->set_end (new_end);
2476 copy_location->set_start (new_start);
2477 } else if (new_end > copy_location->start()) {
2478 copy_location->set_end (new_end);
2479 } else if (newframe > 0) {
2480 _editor->snap_to (next, -1, true);
2481 copy_location->set_start (next);
2482 copy_location->set_end (newframe);
2487 update_item (copy_location);
2489 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2492 lm->set_position (copy_location->start(), copy_location->end());
2496 assert (!_copied_locations.empty());
2498 _editor->show_verbose_time_cursor (newframe, 10);
2501 _editor->update_canvas_now ();
2506 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2508 if (!movement_occurred) {
2510 /* just a click, do nothing but finish
2511 off the selection process
2514 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2517 case Selection::Set:
2518 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2519 _editor->selection->set (_marker);
2523 case Selection::Toggle:
2524 case Selection::Extend:
2525 case Selection::Add:
2532 _editor->_dragging_edit_point = false;
2534 _editor->begin_reversible_command ( _("move marker") );
2535 XMLNode &before = _editor->session()->locations()->get_state();
2537 MarkerSelection::iterator i;
2538 list<Location*>::iterator x;
2541 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2542 x != _copied_locations.end() && i != _editor->selection->markers.end();
2545 Location * location = _editor->find_location_from_marker (*i, is_start);
2549 if (location->locked()) {
2553 if (location->is_mark()) {
2554 location->set_start ((*x)->start());
2556 location->set ((*x)->start(), (*x)->end());
2561 XMLNode &after = _editor->session()->locations()->get_state();
2562 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2563 _editor->commit_reversible_command ();
2569 MarkerDrag::aborted ()
2575 MarkerDrag::update_item (Location* location)
2577 double const x1 = _editor->frame_to_pixel (location->start());
2579 _points.front().set_x(x1);
2580 _points.back().set_x(x1);
2581 _line->property_points() = _points;
2584 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2586 _cumulative_x_drag (0),
2587 _cumulative_y_drag (0)
2589 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2595 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2597 Drag::start_grab (event, _editor->fader_cursor);
2599 // start the grab at the center of the control point so
2600 // the point doesn't 'jump' to the mouse after the first drag
2601 _time_axis_view_grab_x = _point->get_x();
2602 _time_axis_view_grab_y = _point->get_y();
2604 float const fraction = 1 - (_point->get_y() / _point->line().height());
2606 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2608 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2609 event->button.x + 10, event->button.y + 10);
2611 _editor->show_verbose_canvas_cursor ();
2615 ControlPointDrag::motion (GdkEvent* event, bool)
2617 double dx = current_pointer_x() - last_pointer_x();
2618 double dy = current_pointer_y() - last_pointer_y();
2620 if (event->button.state & Keyboard::SecondaryModifier) {
2625 /* coordinate in TimeAxisView's space */
2626 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2627 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2629 // calculate zero crossing point. back off by .01 to stay on the
2630 // positive side of zero
2631 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2633 // make sure we hit zero when passing through
2634 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2638 if (_x_constrained) {
2639 cx = _time_axis_view_grab_x;
2641 if (_y_constrained) {
2642 cy = _time_axis_view_grab_y;
2645 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2646 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2650 cy = min ((double) _point->line().height(), cy);
2652 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2654 if (!_x_constrained) {
2655 _editor->snap_to_with_modifier (cx_frames, event);
2658 float const fraction = 1.0 - (cy / _point->line().height());
2660 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2662 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2664 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2668 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2670 if (!movement_occurred) {
2674 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2675 _editor->reset_point_selection ();
2679 motion (event, false);
2681 _point->line().end_drag ();
2685 ControlPointDrag::aborted ()
2687 _point->line().reset ();
2691 ControlPointDrag::active (Editing::MouseMode m)
2693 if (m == Editing::MouseGain) {
2694 /* always active in mouse gain */
2698 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2699 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2702 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2705 _cumulative_y_drag (0)
2710 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2712 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2715 _item = &_line->grab_item ();
2717 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2718 origin, and ditto for y.
2721 double cx = event->button.x;
2722 double cy = event->button.y;
2724 _line->parent_group().w2i (cx, cy);
2726 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2731 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2732 /* no adjacent points */
2736 Drag::start_grab (event, _editor->fader_cursor);
2738 /* store grab start in parent frame */
2740 _time_axis_view_grab_x = cx;
2741 _time_axis_view_grab_y = cy;
2743 double fraction = 1.0 - (cy / _line->height());
2745 _line->start_drag_line (before, after, fraction);
2747 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2748 event->button.x + 10, event->button.y + 10);
2750 _editor->show_verbose_canvas_cursor ();
2754 LineDrag::motion (GdkEvent* event, bool)
2756 double dy = current_pointer_y() - last_pointer_y();
2758 if (event->button.state & Keyboard::SecondaryModifier) {
2762 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2764 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2767 cy = min ((double) _line->height(), cy);
2769 double const fraction = 1.0 - (cy / _line->height());
2773 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2779 /* we are ignoring x position for this drag, so we can just pass in anything */
2780 _line->drag_motion (0, fraction, true, push);
2782 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2786 LineDrag::finished (GdkEvent* event, bool)
2788 motion (event, false);
2793 LineDrag::aborted ()
2799 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2801 Drag::start_grab (event);
2802 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2806 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2813 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2815 nframes64_t grab = grab_frame ();
2816 if (Config->get_rubberbanding_snaps_to_grid ()) {
2817 _editor->snap_to_with_modifier (grab, event);
2820 /* base start and end on initial click position */
2830 if (current_pointer_y() < grab_y()) {
2831 y1 = current_pointer_y();
2834 y2 = current_pointer_y();
2839 if (start != end || y1 != y2) {
2841 double x1 = _editor->frame_to_pixel (start);
2842 double x2 = _editor->frame_to_pixel (end);
2844 _editor->rubberband_rect->property_x1() = x1;
2845 _editor->rubberband_rect->property_y1() = y1;
2846 _editor->rubberband_rect->property_x2() = x2;
2847 _editor->rubberband_rect->property_y2() = y2;
2849 _editor->rubberband_rect->show();
2850 _editor->rubberband_rect->raise_to_top();
2852 _editor->show_verbose_time_cursor (pf, 10);
2857 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2859 if (movement_occurred) {
2861 motion (event, false);
2864 if (current_pointer_y() < grab_y()) {
2865 y1 = current_pointer_y();
2868 y2 = current_pointer_y();
2873 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2876 _editor->begin_reversible_command (_("rubberband selection"));
2878 if (grab_frame() < last_pointer_frame()) {
2879 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
2881 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
2885 _editor->commit_reversible_command ();
2889 if (!getenv("ARDOUR_SAE")) {
2890 _editor->selection->clear_tracks();
2892 _editor->selection->clear_regions();
2893 _editor->selection->clear_points ();
2894 _editor->selection->clear_lines ();
2897 _editor->rubberband_rect->hide();
2901 RubberbandSelectDrag::aborted ()
2903 _editor->rubberband_rect->hide ();
2907 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2909 Drag::start_grab (event);
2911 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2915 TimeFXDrag::motion (GdkEvent* event, bool)
2917 RegionView* rv = _primary;
2919 nframes64_t const pf = adjusted_current_frame (event);
2921 if (pf > rv->region()->position()) {
2922 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
2925 _editor->show_verbose_time_cursor (pf, 10);
2929 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2931 _primary->get_time_axis_view().hide_timestretch ();
2933 if (!movement_occurred) {
2937 if (last_pointer_frame() < _primary->region()->position()) {
2938 /* backwards drag of the left edge - not usable */
2942 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
2944 float percentage = (double) newlen / (double) _primary->region()->length();
2946 #ifndef USE_RUBBERBAND
2947 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2948 if (_primary->region()->data_type() == DataType::AUDIO) {
2949 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2953 _editor->begin_reversible_command (_("timestretch"));
2955 // XXX how do timeFX on multiple regions ?
2960 if (!_editor->time_stretch (rs, percentage) == 0) {
2961 error << _("An error occurred while executing time stretch operation") << endmsg;
2966 TimeFXDrag::aborted ()
2968 _primary->get_time_axis_view().hide_timestretch ();
2973 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2975 Drag::start_grab (event);
2979 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2985 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2987 if (movement_occurred && _editor->session()) {
2988 /* make sure we stop */
2989 _editor->session()->request_transport_speed (0.0);
2994 ScrubDrag::aborted ()
2999 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3003 , _original_pointer_time_axis (-1)
3004 , _last_pointer_time_axis (-1)
3010 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3012 nframes64_t start = 0;
3013 nframes64_t end = 0;
3015 if (_editor->session() == 0) {
3019 Gdk::Cursor* cursor = 0;
3021 switch (_operation) {
3022 case CreateSelection:
3023 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3028 cursor = _editor->selector_cursor;
3029 Drag::start_grab (event, cursor);
3032 case SelectionStartTrim:
3033 if (_editor->clicked_axisview) {
3034 _editor->clicked_axisview->order_selection_trims (_item, true);
3036 Drag::start_grab (event, _editor->trimmer_cursor);
3037 start = _editor->selection->time[_editor->clicked_selection].start;
3038 _pointer_frame_offset = grab_frame() - start;
3041 case SelectionEndTrim:
3042 if (_editor->clicked_axisview) {
3043 _editor->clicked_axisview->order_selection_trims (_item, false);
3045 Drag::start_grab (event, _editor->trimmer_cursor);
3046 end = _editor->selection->time[_editor->clicked_selection].end;
3047 _pointer_frame_offset = grab_frame() - end;
3051 start = _editor->selection->time[_editor->clicked_selection].start;
3052 Drag::start_grab (event, cursor);
3053 _pointer_frame_offset = grab_frame() - start;
3057 if (_operation == SelectionMove) {
3058 _editor->show_verbose_time_cursor (start, 10);
3060 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3063 _original_pointer_time_axis = _editor->trackview_by_y_position (current_pointer_y ()).first->order ();
3067 SelectionDrag::motion (GdkEvent* event, bool first_move)
3069 nframes64_t start = 0;
3070 nframes64_t end = 0;
3073 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (current_pointer_y ());
3074 if (pending_time_axis.first == 0) {
3078 nframes64_t const pending_position = adjusted_current_frame (event);
3080 /* only alter selection if things have changed */
3082 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3086 switch (_operation) {
3087 case CreateSelection:
3089 nframes64_t grab = grab_frame ();
3092 _editor->snap_to (grab);
3095 if (pending_position < grab_frame()) {
3096 start = pending_position;
3099 end = pending_position;
3103 /* first drag: Either add to the selection
3104 or create a new selection
3110 /* adding to the selection */
3111 _editor->selection->add (_editor->clicked_axisview);
3112 _editor->clicked_selection = _editor->selection->add (start, end);
3117 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3118 _editor->selection->set (_editor->clicked_axisview);
3121 _editor->clicked_selection = _editor->selection->set (start, end);
3125 /* select the track that we're in */
3126 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3127 _editor->selection->add (pending_time_axis.first);
3128 _added_time_axes.push_back (pending_time_axis.first);
3131 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3132 tracks that we selected in the first place.
3135 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3136 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3138 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3139 while (i != _added_time_axes.end()) {
3141 list<TimeAxisView*>::iterator tmp = i;
3144 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3145 _editor->selection->remove (*i);
3146 _added_time_axes.remove (*i);
3155 case SelectionStartTrim:
3157 start = _editor->selection->time[_editor->clicked_selection].start;
3158 end = _editor->selection->time[_editor->clicked_selection].end;
3160 if (pending_position > end) {
3163 start = pending_position;
3167 case SelectionEndTrim:
3169 start = _editor->selection->time[_editor->clicked_selection].start;
3170 end = _editor->selection->time[_editor->clicked_selection].end;
3172 if (pending_position < start) {
3175 end = pending_position;
3182 start = _editor->selection->time[_editor->clicked_selection].start;
3183 end = _editor->selection->time[_editor->clicked_selection].end;
3185 length = end - start;
3187 start = pending_position;
3188 _editor->snap_to (start);
3190 end = start + length;
3195 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3196 _editor->start_canvas_autoscroll (1, 0);
3200 _editor->selection->replace (_editor->clicked_selection, start, end);
3203 if (_operation == SelectionMove) {
3204 _editor->show_verbose_time_cursor(start, 10);
3206 _editor->show_verbose_time_cursor(pending_position, 10);
3211 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3213 Session* s = _editor->session();
3215 if (movement_occurred) {
3216 motion (event, false);
3217 /* XXX this is not object-oriented programming at all. ick */
3218 if (_editor->selection->time.consolidate()) {
3219 _editor->selection->TimeChanged ();
3222 /* XXX what if its a music time selection? */
3223 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3224 s->request_play_range (&_editor->selection->time, true);
3229 /* just a click, no pointer movement.*/
3231 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3232 _editor->selection->clear_time();
3235 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3236 _editor->selection->set (_editor->clicked_axisview);
3239 if (s && s->get_play_range () && s->transport_rolling()) {
3240 s->request_stop (false, false);
3245 _editor->stop_canvas_autoscroll ();
3249 SelectionDrag::aborted ()
3254 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3259 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3260 _drag_rect->hide ();
3262 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3263 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3267 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3269 if (_editor->session() == 0) {
3273 Gdk::Cursor* cursor = 0;
3275 if (!_editor->temp_location) {
3276 _editor->temp_location = new Location;
3279 switch (_operation) {
3280 case CreateRangeMarker:
3281 case CreateTransportMarker:
3282 case CreateCDMarker:
3284 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3289 cursor = _editor->selector_cursor;
3293 Drag::start_grab (event, cursor);
3295 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3299 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3301 nframes64_t start = 0;
3302 nframes64_t end = 0;
3303 ArdourCanvas::SimpleRect *crect;
3305 switch (_operation) {
3306 case CreateRangeMarker:
3307 crect = _editor->range_bar_drag_rect;
3309 case CreateTransportMarker:
3310 crect = _editor->transport_bar_drag_rect;
3312 case CreateCDMarker:
3313 crect = _editor->cd_marker_bar_drag_rect;
3316 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3321 nframes64_t const pf = adjusted_current_frame (event);
3323 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3324 nframes64_t grab = grab_frame ();
3325 _editor->snap_to (grab);
3327 if (pf < grab_frame()) {
3335 /* first drag: Either add to the selection
3336 or create a new selection.
3341 _editor->temp_location->set (start, end);
3345 update_item (_editor->temp_location);
3347 //_drag_rect->raise_to_top();
3352 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3353 _editor->start_canvas_autoscroll (1, 0);
3357 _editor->temp_location->set (start, end);
3359 double x1 = _editor->frame_to_pixel (start);
3360 double x2 = _editor->frame_to_pixel (end);
3361 crect->property_x1() = x1;
3362 crect->property_x2() = x2;
3364 update_item (_editor->temp_location);
3367 _editor->show_verbose_time_cursor (pf, 10);
3372 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3374 Location * newloc = 0;
3378 if (movement_occurred) {
3379 motion (event, false);
3382 switch (_operation) {
3383 case CreateRangeMarker:
3384 case CreateCDMarker:
3386 _editor->begin_reversible_command (_("new range marker"));
3387 XMLNode &before = _editor->session()->locations()->get_state();
3388 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3389 if (_operation == CreateCDMarker) {
3390 flags = Location::IsRangeMarker | Location::IsCDMarker;
3391 _editor->cd_marker_bar_drag_rect->hide();
3394 flags = Location::IsRangeMarker;
3395 _editor->range_bar_drag_rect->hide();
3397 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3398 _editor->session()->locations()->add (newloc, true);
3399 XMLNode &after = _editor->session()->locations()->get_state();
3400 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3401 _editor->commit_reversible_command ();
3405 case CreateTransportMarker:
3406 // popup menu to pick loop or punch
3407 _editor->new_transport_marker_context_menu (&event->button, _item);
3411 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3413 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3418 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3420 if (end == max_frames) {
3421 end = _editor->session()->current_end_frame ();
3424 if (start == max_frames) {
3425 start = _editor->session()->current_start_frame ();
3428 switch (_editor->mouse_mode) {
3430 /* find the two markers on either side and then make the selection from it */
3431 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3435 /* find the two markers on either side of the click and make the range out of it */
3436 _editor->selection->set (start, end);
3445 _editor->stop_canvas_autoscroll ();
3449 RangeMarkerBarDrag::aborted ()
3455 RangeMarkerBarDrag::update_item (Location* location)
3457 double const x1 = _editor->frame_to_pixel (location->start());
3458 double const x2 = _editor->frame_to_pixel (location->end());
3460 _drag_rect->property_x1() = x1;
3461 _drag_rect->property_x2() = x2;
3465 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3467 Drag::start_grab (event, _editor->zoom_cursor);
3468 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3472 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3477 nframes64_t const pf = adjusted_current_frame (event);
3479 nframes64_t grab = grab_frame ();
3480 _editor->snap_to_with_modifier (grab, event);
3482 /* base start and end on initial click position */
3494 _editor->zoom_rect->show();
3495 _editor->zoom_rect->raise_to_top();
3498 _editor->reposition_zoom_rect(start, end);
3500 _editor->show_verbose_time_cursor (pf, 10);
3505 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3507 if (movement_occurred) {
3508 motion (event, false);
3510 if (grab_frame() < last_pointer_frame()) {
3511 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3513 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3516 _editor->temporal_zoom_to_frame (false, grab_frame());
3518 temporal_zoom_step (false);
3519 center_screen (grab_frame());
3523 _editor->zoom_rect->hide();
3527 MouseZoomDrag::aborted ()
3529 _editor->zoom_rect->hide ();
3532 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3535 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3536 region = &cnote->region_view();
3540 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3542 Drag::start_grab (event);
3545 drag_delta_note = 0;
3550 event_x = current_pointer_x();
3551 event_y = current_pointer_y();
3553 _item->property_parent().get_value()->w2i(event_x, event_y);
3555 last_x = region->snap_to_pixel(event_x);
3558 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3560 if (!(was_selected = cnote->selected())) {
3562 /* tertiary-click means extend selection - we'll do that on button release,
3563 so don't add it here, because otherwise we make it hard to figure
3564 out the "extend-to" range.
3567 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3570 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3573 region->note_selected (cnote, true);
3575 region->unique_select (cnote);
3582 NoteDrag::motion (GdkEvent*, bool)
3584 MidiStreamView* streamview = region->midi_stream_view();
3588 event_x = current_pointer_x();
3589 event_y = current_pointer_y();
3591 _item->property_parent().get_value()->w2i(event_x, event_y);
3593 event_x = region->snap_to_pixel(event_x);
3595 double dx = event_x - last_x;
3596 double dy = event_y - last_y;
3601 // Snap to note rows
3603 if (abs (dy) < streamview->note_height()) {
3606 int8_t this_delta_note;
3608 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3610 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3612 drag_delta_note -= this_delta_note;
3613 dy = streamview->note_height() * this_delta_note;
3614 last_y = last_y + dy;
3618 region->move_selection (dx, dy);
3620 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3622 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3623 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3624 _editor->show_verbose_canvas_cursor_with (buf);
3629 NoteDrag::finished (GdkEvent* ev, bool moved)
3631 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3634 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3637 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3639 region->note_deselected (cnote);
3642 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3643 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3645 if (!extend && !add && region->selection_size() > 1) {
3646 region->unique_select(cnote);
3647 } else if (extend) {
3648 region->note_selected (cnote, true, true);
3650 /* it was added during button press */
3655 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3660 NoteDrag::aborted ()
3665 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3668 , _nothing_to_drag (false)
3670 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3673 _line = _atav->line ();
3677 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3679 Drag::start_grab (event, cursor);
3681 list<ControlPoint*> points;
3683 XMLNode* state = &_line->get_state ();
3685 if (_ranges.empty()) {
3687 uint32_t const N = _line->npoints ();
3688 for (uint32_t i = 0; i < N; ++i) {
3689 points.push_back (_line->nth (i));
3694 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3695 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3697 /* fade into and out of the region that we're dragging;
3698 64 samples length plucked out of thin air.
3700 nframes64_t const h = (j->start + j->end) / 2;
3701 nframes64_t a = j->start + 64;
3705 nframes64_t b = j->end - 64;
3710 the_list->add (j->start, the_list->eval (j->start));
3711 _line->add_always_in_view (j->start);
3712 the_list->add (a, the_list->eval (a));
3713 _line->add_always_in_view (a);
3714 the_list->add (b, the_list->eval (b));
3715 _line->add_always_in_view (b);
3716 the_list->add (j->end, the_list->eval (j->end));
3717 _line->add_always_in_view (j->end);
3720 uint32_t const N = _line->npoints ();
3721 for (uint32_t i = 0; i < N; ++i) {
3723 ControlPoint* p = _line->nth (i);
3725 list<AudioRange>::const_iterator j = _ranges.begin ();
3726 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3730 if (j != _ranges.end()) {
3731 points.push_back (p);
3736 if (points.empty()) {
3737 _nothing_to_drag = true;
3741 _line->start_drag_multiple (points, 1 - (current_pointer_y() / _line->height ()), state);
3745 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3747 if (_nothing_to_drag) {
3751 float const f = 1 - (current_pointer_y() / _line->height());
3753 /* we are ignoring x position for this drag, so we can just pass in anything */
3754 _line->drag_motion (0, f, true, false);
3758 AutomationRangeDrag::finished (GdkEvent* event, bool)
3760 if (_nothing_to_drag) {
3764 motion (event, false);
3766 _line->clear_always_in_view ();
3770 AutomationRangeDrag::aborted ()
3772 _line->clear_always_in_view ();