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 (GdkEvent* event) const
160 if (_current_pointer_frame > _pointer_frame_offset) {
161 pos = _current_pointer_frame - _pointer_frame_offset;
164 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
165 _editor->snap_to (pos);
172 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
174 _last_pointer_x = _current_pointer_x;
175 _last_pointer_y = _current_pointer_y;
176 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
178 if (!from_autoscroll && !_move_threshold_passed) {
180 bool const xp = (::llabs ((nframes64_t) (_current_pointer_x - _grab_x)) > 4LL);
181 bool const yp = (::llabs ((nframes64_t) (_current_pointer_y - _grab_y)) > 4LL);
183 _move_threshold_passed = (xp || yp);
185 if (apply_move_threshold() && _move_threshold_passed) {
187 _grab_frame = _current_pointer_frame;
188 _grab_x = _current_pointer_x;
189 _grab_y = _current_pointer_y;
190 _last_pointer_frame = _grab_frame;
191 _pointer_frame_offset = _grab_frame - _last_frame_position;
196 bool old_had_movement = _had_movement;
198 /* a motion event has happened, so we've had movement... */
199 _had_movement = true;
201 /* ... unless we're using a move threshold and we've not yet passed it */
202 if (apply_move_threshold() && !_move_threshold_passed) {
203 _had_movement = false;
206 if (active (_editor->mouse_mode)) {
208 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
209 if (!from_autoscroll) {
210 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
213 motion (event, _had_movement != old_had_movement);
225 _editor->stop_canvas_autoscroll ();
226 _editor->hide_verbose_canvas_cursor ();
231 /* put it back where it came from */
236 _item->i2w (cxw, cyw);
237 _item->move (_original_x - cxw, _original_y - cyw);
242 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
247 RegionView::RegionViewGoingAway.connect (mem_fun (*this, &RegionDrag::region_going_away));
251 RegionDrag::region_going_away (RegionView* v)
257 RegionDrag::update_selection ()
260 copy (_views.begin(), _views.end(), back_inserter (s));
261 _editor->selection->set (s);
264 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
265 : RegionDrag (e, i, p, v),
275 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
277 Drag::start_grab (event);
279 _editor->show_verbose_time_cursor (_last_frame_position, 10);
282 RegionMotionDrag::TimeAxisViewSummary
283 RegionMotionDrag::get_time_axis_view_summary ()
285 int32_t children = 0;
286 TimeAxisViewSummary sum;
288 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
290 /* get a bitmask representing the visible tracks */
292 for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
293 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
294 TimeAxisView::Children children_list;
296 /* zeroes are audio/MIDI tracks. ones are other types. */
298 if (!rtv->hidden()) {
300 if (!rtv->is_track()) {
301 /* not an audio nor MIDI track */
302 sum.tracks = sum.tracks |= (0x01 << rtv->order());
305 sum.height_list[rtv->order()] = (*i)->current_height();
308 if ((children_list = rtv->get_child_list()).size() > 0) {
309 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
310 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
311 sum.height_list[rtv->order() + children] = (*j)->current_height();
322 RegionMotionDrag::compute_y_delta (
323 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
324 int32_t last_pointer_layer, int32_t current_pointer_layer,
325 TimeAxisViewSummary const & tavs,
326 int32_t* pointer_order_span, int32_t* pointer_layer_span,
327 int32_t* canvas_pointer_order_span
331 *pointer_order_span = 0;
332 *pointer_layer_span = 0;
336 bool clamp_y_axis = false;
338 /* the change in track order between this callback and the last */
339 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
340 /* the change in layer between this callback and the last;
341 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
342 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
344 if (*pointer_order_span != 0) {
346 /* find the actual pointer span, in terms of the number of visible tracks;
347 to do this, we reduce |pointer_order_span| by the number of hidden tracks
350 *canvas_pointer_order_span = *pointer_order_span;
351 if (last_pointer_view->order() >= current_pointer_view->order()) {
352 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
353 if (tavs.height_list[y] == 0) {
354 *canvas_pointer_order_span--;
358 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
359 if (tavs.height_list[y] == 0) {
360 *canvas_pointer_order_span++;
365 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
367 RegionView* rv = (*i);
369 if (rv->region()->locked()) {
373 double ix1, ix2, iy1, iy2;
374 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
375 rv->get_canvas_frame()->i2w (ix1, iy1);
376 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
378 /* get the new trackview for this particular region */
379 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
381 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
383 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
384 as surely this is a per-region thing... */
386 clamp_y_axis = y_movement_disallowed (
387 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
395 } else if (_dest_trackview == current_pointer_view) {
397 if (current_pointer_layer == last_pointer_layer) {
398 /* No movement; clamp */
404 _dest_trackview = current_pointer_view;
405 _dest_layer = current_pointer_layer;
413 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
415 *pending_region_position = 0;
417 /* compute the amount of pointer motion in frames, and where
418 the region would be if we moved it by that much.
420 if (_current_pointer_frame >= _pointer_frame_offset) {
422 nframes64_t sync_frame;
423 nframes64_t sync_offset;
426 *pending_region_position = _current_pointer_frame - _pointer_frame_offset;
428 sync_offset = _primary->region()->sync_offset (sync_dir);
430 /* we don't handle a sync point that lies before zero.
432 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
434 sync_frame = *pending_region_position + (sync_dir*sync_offset);
436 /* we snap if the snap modifier is not enabled.
439 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
440 _editor->snap_to (sync_frame);
443 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
446 *pending_region_position = _last_frame_position;
451 if (*pending_region_position > max_frames - _primary->region()->length()) {
452 *pending_region_position = _last_frame_position;
457 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
459 /* now compute the canvas unit distance we need to move the regionview
460 to make it appear at the new location.
463 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
465 if (*pending_region_position <= _last_frame_position) {
467 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
469 RegionView* rv = (*i);
471 // If any regionview is at zero, we need to know so we can stop further leftward motion.
473 double ix1, ix2, iy1, iy2;
474 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
475 rv->get_canvas_frame()->i2w (ix1, iy1);
477 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
479 *pending_region_position = _last_frame_position;
486 _last_frame_position = *pending_region_position;
493 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
497 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
499 vector<int32_t>::iterator j;
501 /* *pointer* variables reflect things about the pointer; as we may be moving
502 multiple regions, much detail must be computed per-region */
504 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
505 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
506 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
507 is always 0 regardless of what the region's "real" layer is */
508 RouteTimeAxisView* current_pointer_view;
509 layer_t current_pointer_layer;
510 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
514 /* TimeAxisView that we were pointing at last time we entered this method */
515 TimeAxisView const * const last_pointer_view = _dest_trackview;
516 /* the order of the track that we were pointing at last time we entered this method */
517 int32_t const last_pointer_order = last_pointer_view->order ();
518 /* the layer that we were pointing at last time we entered this method */
519 layer_t const last_pointer_layer = _dest_layer;
521 int32_t pointer_order_span;
522 int32_t pointer_layer_span;
523 int32_t canvas_pointer_order_span;
525 bool const clamp_y_axis = compute_y_delta (
526 last_pointer_view, current_pointer_view,
527 last_pointer_layer, current_pointer_layer, tavs,
528 &pointer_order_span, &pointer_layer_span,
529 &canvas_pointer_order_span
532 nframes64_t pending_region_position;
533 double const x_delta = compute_x_delta (event, &pending_region_position);
535 /*************************************************************
537 ************************************************************/
539 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0) {
540 /* haven't reached next snap point, and we're not switching
541 trackviews nor layers. nothing to do.
546 /*************************************************************
548 ************************************************************/
550 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
552 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
554 RegionView* rv = (*i);
556 if (rv->region()->locked()) {
560 /* here we are calculating the y distance from the
561 top of the first track view to the top of the region
562 area of the track view that we're working on */
564 /* this x value is just a dummy value so that we have something
569 /* distance from the top of this track view to the region area
570 of our track view is always 1 */
574 /* convert to world coordinates, ie distance from the top of
577 rv->get_canvas_frame()->i2w (ix1, iy1);
579 /* compensate for the ruler section and the vertical scrollbar position */
580 iy1 += _editor->get_trackview_group_vertical_offset ();
584 // hide any dependent views
586 rv->get_time_axis_view().hide_dependent_views (*rv);
589 reparent to a non scrolling group so that we can keep the
590 region selection above all time axis views.
591 reparenting means we have to move the rv as the two
592 parent groups have different coordinates.
595 rv->get_canvas_group()->property_y() = iy1 - 1;
596 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
598 rv->fake_set_opaque (true);
601 /* current view for this particular region */
602 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
603 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
605 if (pointer_order_span != 0 && !clamp_y_axis) {
607 /* INTER-TRACK MOVEMENT */
609 /* move through the height list to the track that the region is currently on */
610 vector<int32_t>::iterator j = tavs.height_list.begin ();
612 while (j != tavs.height_list.end () && x != rtv->order ()) {
618 int32_t temp_pointer_order_span = canvas_pointer_order_span;
620 if (j != tavs.height_list.end ()) {
622 /* Account for layers in the original and
623 destination tracks. If we're moving around in layers we assume
624 that only one track is involved, so it's ok to use *pointer*
627 StreamView* lv = last_pointer_view->view ();
630 /* move to the top of the last trackview */
631 if (lv->layer_display () == Stacked) {
632 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
635 StreamView* cv = current_pointer_view->view ();
638 /* move to the right layer on the current trackview */
639 if (cv->layer_display () == Stacked) {
640 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
643 /* And for being on a non-topmost layer on the new
646 while (temp_pointer_order_span > 0) {
647 /* we're moving up canvas-wise,
648 so we need to find the next track height
650 if (j != tavs.height_list.begin()) {
654 if (x != last_pointer_order) {
656 ++temp_pointer_order_span;
661 temp_pointer_order_span--;
664 while (temp_pointer_order_span < 0) {
668 if (x != last_pointer_order) {
670 --temp_pointer_order_span;
674 if (j != tavs.height_list.end()) {
678 temp_pointer_order_span++;
682 /* find out where we'll be when we move and set height accordingly */
684 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
685 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
686 rv->set_height (temp_rtv->view()->child_height());
688 /* if you un-comment the following, the region colours will follow
689 the track colours whilst dragging; personally
690 i think this can confuse things, but never mind.
693 //const GdkColor& col (temp_rtv->view->get_region_color());
694 //rv->set_color (const_cast<GdkColor&>(col));
698 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
700 /* INTER-LAYER MOVEMENT in the same track */
701 y_delta = rtv->view()->child_height () * pointer_layer_span;
706 _editor->mouse_brush_insert_region (rv, pending_region_position);
708 rv->move (x_delta, y_delta);
711 } /* foreach region */
714 _editor->cursor_group->raise_to_top();
717 if (x_delta != 0 && !_brushing) {
718 _editor->show_verbose_time_cursor (_last_frame_position, 10);
723 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
725 if (_copy && first_move) {
726 copy_regions (event);
729 RegionMotionDrag::motion (event, first_move);
733 RegionMoveDrag::finished (GdkEvent* event, bool movement_occurred)
735 bool nocommit = true;
736 vector<RegionView*> copies;
737 boost::shared_ptr<Diskstream> ds;
738 boost::shared_ptr<Playlist> from_playlist;
739 list<RegionView*> new_views;
740 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
741 PlaylistSet modified_playlists;
742 PlaylistSet frozen_playlists;
743 list <sigc::connection> modified_playlist_connections;
744 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
745 nframes64_t drag_delta;
746 bool changed_tracks, changed_position;
747 map<RegionView*, RouteTimeAxisView*> final;
748 RouteTimeAxisView* source_tv;
750 if (!movement_occurred) {
757 if (Config->get_edit_mode() == Splice && !_editor->pre_drag_region_selection.empty()) {
758 _editor->selection->set (_editor->pre_drag_region_selection);
759 _editor->pre_drag_region_selection.clear ();
763 /* all changes were made during motion event handlers */
766 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
767 copies.push_back (*i);
774 /* reverse this here so that we have the correct logic to finalize
778 if (Config->get_edit_mode() == Lock && !_copy) {
779 _x_constrained = !_x_constrained;
783 if (_x_constrained) {
784 _editor->begin_reversible_command (_("fixed time region copy"));
786 _editor->begin_reversible_command (_("region copy"));
789 if (_x_constrained) {
790 _editor->begin_reversible_command (_("fixed time region drag"));
792 _editor->begin_reversible_command (_("region drag"));
796 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
797 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
799 drag_delta = _primary->region()->position() - _last_frame_position;
801 _editor->update_canvas_now ();
803 /* make a list of where each region ended up */
804 final = find_time_axis_views ();
806 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
808 RegionView* rv = (*i);
809 RouteTimeAxisView* dest_rtv = final[*i];
813 if (rv->region()->locked()) {
818 if (changed_position && !_x_constrained) {
819 where = rv->region()->position() - drag_delta;
821 where = rv->region()->position();
824 boost::shared_ptr<Region> new_region;
827 /* we already made a copy */
828 new_region = rv->region();
830 /* undo the previous hide_dependent_views so that xfades don't
831 disappear on copying regions
834 //rv->get_time_axis_view().reveal_dependent_views (*rv);
836 } else if (changed_tracks && dest_rtv->playlist()) {
837 new_region = RegionFactory::create (rv->region());
840 if (changed_tracks || _copy) {
842 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
849 _editor->latest_regionviews.clear ();
851 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
853 insert_result = modified_playlists.insert (to_playlist);
855 if (insert_result.second) {
856 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
859 to_playlist->add_region (new_region, where);
863 if (!_editor->latest_regionviews.empty()) {
864 // XXX why just the first one ? we only expect one
865 // commented out in nick_m's canvas reworking. is that intended?
866 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
867 new_views.push_back (_editor->latest_regionviews.front());
872 motion on the same track. plonk the previously reparented region
873 back to its original canvas group (its streamview).
874 No need to do anything for copies as they are fake regions which will be deleted.
877 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
878 rv->get_canvas_group()->property_y() = 0;
880 /* just change the model */
882 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
884 insert_result = modified_playlists.insert (playlist);
886 if (insert_result.second) {
887 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
889 /* freeze to avoid lots of relayering in the case of a multi-region drag */
890 frozen_insert_result = frozen_playlists.insert(playlist);
892 if (frozen_insert_result.second) {
896 rv->region()->set_position (where, (void*) this);
899 if (changed_tracks && !_copy) {
901 /* get the playlist where this drag started. we can't use rv->region()->playlist()
902 because we may have copied the region and it has not been attached to a playlist.
905 assert ((source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view())));
906 assert ((ds = source_tv->get_diskstream()));
907 assert ((from_playlist = ds->playlist()));
909 /* moved to a different audio track, without copying */
911 /* the region that used to be in the old playlist is not
912 moved to the new one - we use a copy of it. as a result,
913 any existing editor for the region should no longer be
917 rv->hide_region_editor();
918 rv->fake_set_opaque (false);
920 /* remove the region from the old playlist */
922 insert_result = modified_playlists.insert (from_playlist);
924 if (insert_result.second) {
925 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
928 from_playlist->remove_region (rv->region());
930 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
931 was selected in all of them, then removing it from a playlist will have removed all
932 trace of it from the selection (i.e. there were N regions selected, we removed 1,
933 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
934 corresponding regionview, and the selection is now empty).
936 this could have invalidated any and all iterators into the region selection.
938 the heuristic we use here is: if the region selection is empty, break out of the loop
939 here. if the region selection is not empty, then restart the loop because we know that
940 we must have removed at least the region(view) we've just been working on as well as any
941 that we processed on previous iterations.
943 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
947 if (_views.empty()) {
958 copies.push_back (rv);
962 if (new_views.empty()) {
964 /* the region(view)s that are being dragged around are copies and do not
965 belong to any track. remove them from our list
971 _primary = _views.front ();
974 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 ();
987 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
994 RegionMoveDrag::x_move_allowed () const
996 if (Config->get_edit_mode() == Lock) {
998 return !_x_constrained;
1000 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1001 return _x_constrained;
1005 return !_x_constrained;
1009 RegionInsertDrag::x_move_allowed () const
1011 if (Config->get_edit_mode() == Lock) {
1012 return _x_constrained;
1015 return !_x_constrained;
1019 RegionMotionDrag::copy_regions (GdkEvent* event)
1021 /* duplicate the regionview(s) and region(s) */
1023 list<RegionView*> new_regionviews;
1025 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1027 RegionView* rv = (*i);
1028 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1029 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1031 const boost::shared_ptr<const Region> original = rv->region();
1032 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1036 boost::shared_ptr<AudioRegion> audioregion_copy
1037 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1038 nrv = new AudioRegionView (*arv, audioregion_copy);
1040 boost::shared_ptr<MidiRegion> midiregion_copy
1041 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1042 nrv = new MidiRegionView (*mrv, midiregion_copy);
1047 nrv->get_canvas_group()->show ();
1048 new_regionviews.push_back (nrv);
1051 if (new_regionviews.empty()) {
1055 /* reflect the fact that we are dragging the copies */
1057 _primary = new_regionviews.front();
1058 _views = new_regionviews;
1060 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1063 sync the canvas to what we think is its current state
1064 without it, the canvas seems to
1065 "forget" to update properly after the upcoming reparent()
1066 ..only if the mouse is in rapid motion at the time of the grab.
1067 something to do with regionview creation raking so long?
1069 _editor->update_canvas_now();
1073 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1075 /* Which trackview is this ? */
1077 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1078 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1079 (*layer) = tvp.second;
1081 if (*tv && (*tv)->layer_display() == Overlaid) {
1085 /* The region motion is only processed if the pointer is over
1089 if (!(*tv) || !(*tv)->is_track()) {
1090 /* To make sure we hide the verbose canvas cursor when the mouse is
1091 not held over and audiotrack.
1093 _editor->hide_verbose_canvas_cursor ();
1100 /** @param new_order New track order.
1101 * @param old_order Old track order.
1102 * @param visible_y_low Lowest visible order.
1103 * @return true if y movement should not happen, otherwise false.
1106 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1108 if (new_order != old_order) {
1110 /* this isn't the pointer track */
1114 /* moving up the canvas */
1115 if ( (new_order - y_span) >= tavs.visible_y_low) {
1119 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1120 int32_t visible_tracks = 0;
1121 while (visible_tracks < y_span ) {
1123 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1124 /* passing through a hidden track */
1129 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1130 /* moving to a non-track; disallow */
1136 /* moving beyond the lowest visible track; disallow */
1140 } else if (y_span < 0) {
1142 /* moving down the canvas */
1143 if ((new_order - y_span) <= tavs.visible_y_high) {
1145 int32_t visible_tracks = 0;
1147 while (visible_tracks > y_span ) {
1150 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1151 /* passing through a hidden track */
1156 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1157 /* moving to a non-track; disallow */
1164 /* moving beyond the highest visible track; disallow */
1171 /* this is the pointer's track */
1173 if ((new_order - y_span) > tavs.visible_y_high) {
1174 /* we will overflow */
1176 } else if ((new_order - y_span) < tavs.visible_y_low) {
1177 /* we will overflow */
1186 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1187 : RegionMotionDrag (e, i, p, v, b),
1190 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1192 _dest_trackview = tv;
1193 if (tv->layer_display() == Overlaid) {
1196 _dest_layer = _primary->region()->layer ();
1200 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1201 if (rtv && rtv->is_track()) {
1202 speed = rtv->get_diskstream()->speed ();
1205 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1209 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1211 RegionMotionDrag::start_grab (event, c);
1213 _pointer_frame_offset = _grab_frame - _last_frame_position;
1216 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1217 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1219 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1220 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1222 _primary = v->view()->create_region_view (r, false, false);
1224 _primary->get_canvas_group()->show ();
1225 _primary->set_position (pos, 0);
1226 _views.push_back (_primary);
1228 _last_frame_position = pos;
1230 _item = _primary->get_canvas_group ();
1231 _dest_trackview = v;
1232 _dest_layer = _primary->region()->layer ();
1235 map<RegionView*, RouteTimeAxisView*>
1236 RegionMotionDrag::find_time_axis_views ()
1238 map<RegionView*, RouteTimeAxisView*> tav;
1240 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1242 double ix1, ix2, iy1, iy2;
1243 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1244 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1245 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1247 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1248 tav[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
1256 RegionInsertDrag::finished (GdkEvent* event, bool movement_occurred)
1258 _editor->update_canvas_now ();
1260 map<RegionView*, RouteTimeAxisView*> final = find_time_axis_views ();
1262 RouteTimeAxisView* dest_rtv = final[_primary];
1264 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1265 _primary->get_canvas_group()->property_y() = 0;
1267 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1269 _editor->begin_reversible_command (_("insert region"));
1270 XMLNode& before = playlist->get_state ();
1271 playlist->add_region (_primary->region (), _last_frame_position);
1272 _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1273 _editor->commit_reversible_command ();
1280 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1281 : RegionMoveDrag (e, i, p, v, false, false)
1286 struct RegionSelectionByPosition {
1287 bool operator() (RegionView*a, RegionView* b) {
1288 return a->region()->position () < b->region()->position();
1293 RegionSpliceDrag::motion (GdkEvent* event, bool)
1295 RouteTimeAxisView* tv;
1298 if (!check_possible (&tv, &layer)) {
1304 if (_current_pointer_x - _grab_x > 0) {
1310 RegionSelection copy (_editor->selection->regions);
1312 RegionSelectionByPosition cmp;
1315 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1317 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1323 boost::shared_ptr<Playlist> playlist;
1325 if ((playlist = atv->playlist()) == 0) {
1329 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1334 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1338 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1344 playlist->shuffle ((*i)->region(), dir);
1346 _grab_x = _current_pointer_x;
1351 RegionSpliceDrag::finished (GdkEvent* event, bool)
1357 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1365 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1367 _dest_trackview = _view;
1369 Drag::start_grab (event);
1374 RegionCreateDrag::motion (GdkEvent* event, bool first_move)
1377 // TODO: create region-create-drag region view here
1380 // TODO: resize region-create-drag region view here
1384 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1386 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1391 const boost::shared_ptr<MidiDiskstream> diskstream =
1392 boost::dynamic_pointer_cast<MidiDiskstream>(mtv->view()->trackview().track()->diskstream());
1395 warning << "Cannot create non-MIDI region" << endl;
1399 if (!movement_occurred) {
1400 _editor->begin_reversible_command (_("create region"));
1401 XMLNode &before = mtv->playlist()->get_state();
1403 nframes64_t start = _grab_frame;
1404 _editor->snap_to (start, -1);
1405 const Meter& m = _editor->session->tempo_map().meter_at(start);
1406 const Tempo& t = _editor->session->tempo_map().tempo_at(start);
1407 double length = floor (m.frames_per_bar(t, _editor->session->frame_rate()));
1409 boost::shared_ptr<Source> src = _editor->session->create_midi_source_for_session(*diskstream.get());
1411 mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>
1412 (RegionFactory::create(src, 0, (nframes_t) length,
1413 PBD::basename_nosuffix(src->name()))), start);
1414 XMLNode &after = mtv->playlist()->get_state();
1415 _editor->session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
1416 _editor->commit_reversible_command();
1419 motion (event, false);
1420 // TODO: create region-create-drag region here
1428 RegionGainDrag::motion (GdkEvent* event, bool)
1434 RegionGainDrag::finished (GdkEvent *, bool)
1439 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1440 : RegionDrag (e, i, p, v)
1446 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1449 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1450 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1452 if (tv && tv->is_track()) {
1453 speed = tv->get_diskstream()->speed();
1456 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1457 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1458 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1460 Drag::start_grab (event, _editor->trimmer_cursor);
1462 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1463 _operation = ContentsTrim;
1465 /* These will get overridden for a point trim.*/
1466 if (_current_pointer_frame < (region_start + region_length/2)) {
1467 /* closer to start */
1468 _operation = StartTrim;
1469 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1471 _operation = EndTrim;
1475 switch (_operation) {
1477 _editor->show_verbose_time_cursor (region_start, 10);
1480 _editor->show_verbose_time_cursor (region_end, 10);
1483 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1489 TrimDrag::motion (GdkEvent* event, bool first_move)
1491 RegionView* rv = _primary;
1492 nframes64_t frame_delta = 0;
1494 bool left_direction;
1495 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1497 /* snap modifier works differently here..
1498 its' current state has to be passed to the
1499 various trim functions in order to work properly
1503 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1504 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1505 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1507 if (tv && tv->is_track()) {
1508 speed = tv->get_diskstream()->speed();
1511 if (_last_pointer_frame > _current_pointer_frame) {
1512 left_direction = true;
1514 left_direction = false;
1518 _editor->snap_to (_current_pointer_frame);
1521 if (_current_pointer_frame == _last_pointer_frame) {
1529 switch (_operation) {
1531 trim_type = "Region start trim";
1534 trim_type = "Region end trim";
1537 trim_type = "Region content trim";
1541 _editor->begin_reversible_command (trim_type);
1543 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1544 (*i)->fake_set_opaque(false);
1545 (*i)->region()->freeze ();
1547 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1550 arv->temporarily_hide_envelope ();
1553 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1554 insert_result = _editor->motion_frozen_playlists.insert (pl);
1556 if (insert_result.second) {
1557 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1563 if (left_direction) {
1564 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1566 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1569 bool non_overlap_trim = false;
1571 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1572 non_overlap_trim = true;
1575 switch (_operation) {
1577 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1581 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1582 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1588 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1592 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1593 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1600 bool swap_direction = false;
1602 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1603 swap_direction = true;
1606 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1608 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1614 switch (_operation) {
1616 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1619 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1622 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1626 _last_pointer_frame = _current_pointer_frame;
1631 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1633 if (movement_occurred) {
1634 motion (event, false);
1636 if (!_editor->selection->selected (_primary)) {
1637 _editor->thaw_region_after_trim (*_primary);
1640 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1641 _editor->thaw_region_after_trim (**i);
1642 (*i)->fake_set_opaque (true);
1646 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1648 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1651 _editor->motion_frozen_playlists.clear ();
1653 _editor->commit_reversible_command();
1655 /* no mouse movement */
1656 _editor->point_trim (event);
1660 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1664 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1669 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1672 // create a dummy marker for visual representation of moving the copy.
1673 // The actual copying is not done before we reach the finish callback.
1675 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1676 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1677 *new MeterSection (_marker->meter()));
1679 _item = &new_marker->the_item ();
1680 _marker = new_marker;
1684 MetricSection& section (_marker->meter());
1686 if (!section.movable()) {
1692 Drag::start_grab (event, cursor);
1694 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1696 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1700 MeterMarkerDrag::motion (GdkEvent* event, bool)
1702 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1704 if (adjusted_frame == _last_pointer_frame) {
1708 _marker->set_position (adjusted_frame);
1710 _last_pointer_frame = adjusted_frame;
1712 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1716 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1718 if (!movement_occurred) {
1722 motion (event, false);
1726 TempoMap& map (_editor->session->tempo_map());
1727 map.bbt_time (_last_pointer_frame, when);
1729 if (_copy == true) {
1730 _editor->begin_reversible_command (_("copy meter mark"));
1731 XMLNode &before = map.get_state();
1732 map.add_meter (_marker->meter(), when);
1733 XMLNode &after = map.get_state();
1734 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1735 _editor->commit_reversible_command ();
1737 // delete the dummy marker we used for visual representation of copying.
1738 // a new visual marker will show up automatically.
1741 _editor->begin_reversible_command (_("move meter mark"));
1742 XMLNode &before = map.get_state();
1743 map.move_meter (_marker->meter(), when);
1744 XMLNode &after = map.get_state();
1745 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1746 _editor->commit_reversible_command ();
1750 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1754 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1759 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1764 // create a dummy marker for visual representation of moving the copy.
1765 // The actual copying is not done before we reach the finish callback.
1767 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1768 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1769 *new TempoSection (_marker->tempo()));
1771 _item = &new_marker->the_item ();
1772 _marker = new_marker;
1776 MetricSection& section (_marker->tempo());
1778 if (!section.movable()) {
1783 Drag::start_grab (event, cursor);
1785 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1786 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1790 TempoMarkerDrag::motion (GdkEvent* event, bool)
1792 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1794 if (adjusted_frame == _last_pointer_frame) {
1798 /* OK, we've moved far enough to make it worth actually move the thing. */
1800 _marker->set_position (adjusted_frame);
1802 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1804 _last_pointer_frame = adjusted_frame;
1808 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1810 if (!movement_occurred) {
1814 motion (event, false);
1818 TempoMap& map (_editor->session->tempo_map());
1819 map.bbt_time (_last_pointer_frame, when);
1821 if (_copy == true) {
1822 _editor->begin_reversible_command (_("copy tempo mark"));
1823 XMLNode &before = map.get_state();
1824 map.add_tempo (_marker->tempo(), when);
1825 XMLNode &after = map.get_state();
1826 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1827 _editor->commit_reversible_command ();
1829 // delete the dummy marker we used for visual representation of copying.
1830 // a new visual marker will show up automatically.
1833 _editor->begin_reversible_command (_("move tempo mark"));
1834 XMLNode &before = map.get_state();
1835 map.move_tempo (_marker->tempo(), when);
1836 XMLNode &after = map.get_state();
1837 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1838 _editor->commit_reversible_command ();
1843 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1847 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1852 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1854 Drag::start_grab (event, c);
1858 nframes64_t where = _editor->event_frame (event, 0, 0);
1860 _editor->snap_to (where);
1861 _editor->playhead_cursor->set_position (where);
1865 if (_cursor == _editor->playhead_cursor) {
1866 _editor->_dragging_playhead = true;
1868 if (_editor->session && _was_rolling && _stop) {
1869 _editor->session->request_stop ();
1872 if (_editor->session && _editor->session->is_auditioning()) {
1873 _editor->session->cancel_audition ();
1877 _pointer_frame_offset = _grab_frame - _cursor->current_frame;
1879 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1883 CursorDrag::motion (GdkEvent* event, bool)
1885 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1887 if (adjusted_frame == _last_pointer_frame) {
1891 _cursor->set_position (adjusted_frame);
1893 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1896 _editor->update_canvas_now ();
1898 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1900 _last_pointer_frame = adjusted_frame;
1904 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1906 _editor->_dragging_playhead = false;
1908 if (!movement_occurred && _stop) {
1912 motion (event, false);
1914 if (_item == &_editor->playhead_cursor->canvas_item) {
1915 if (_editor->session) {
1916 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1917 _editor->_pending_locate_request = true;
1922 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1923 : RegionDrag (e, i, p, v)
1929 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1931 Drag::start_grab (event, cursor);
1933 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1934 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1936 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1940 FadeInDrag::motion (GdkEvent* event, bool)
1942 nframes64_t fade_length;
1944 nframes64_t const pos = adjusted_current_frame (event);
1946 boost::shared_ptr<Region> region = _primary->region ();
1948 if (pos < (region->position() + 64)) {
1949 fade_length = 64; // this should be a minimum defined somewhere
1950 } else if (pos > region->last_frame()) {
1951 fade_length = region->length();
1953 fade_length = pos - region->position();
1956 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1958 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1964 tmp->reset_fade_in_shape_width (fade_length);
1967 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1971 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1973 if (!movement_occurred) {
1977 nframes64_t fade_length;
1979 nframes64_t const pos = adjusted_current_frame (event);
1981 boost::shared_ptr<Region> region = _primary->region ();
1983 if (pos < (region->position() + 64)) {
1984 fade_length = 64; // this should be a minimum defined somewhere
1985 } else if (pos > region->last_frame()) {
1986 fade_length = region->length();
1988 fade_length = pos - region->position();
1991 _editor->begin_reversible_command (_("change fade in length"));
1993 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1995 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2001 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2002 XMLNode &before = alist->get_state();
2004 tmp->audio_region()->set_fade_in_length (fade_length);
2005 tmp->audio_region()->set_fade_in_active (true);
2007 XMLNode &after = alist->get_state();
2008 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2011 _editor->commit_reversible_command ();
2014 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2015 : RegionDrag (e, i, p, v)
2021 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2023 Drag::start_grab (event, cursor);
2025 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2026 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2028 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2032 FadeOutDrag::motion (GdkEvent* event, bool)
2034 nframes64_t fade_length;
2036 nframes64_t const pos = adjusted_current_frame (event);
2038 boost::shared_ptr<Region> region = _primary->region ();
2040 if (pos > (region->last_frame() - 64)) {
2041 fade_length = 64; // this should really be a minimum fade defined somewhere
2043 else if (pos < region->position()) {
2044 fade_length = region->length();
2047 fade_length = region->last_frame() - pos;
2050 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2052 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2058 tmp->reset_fade_out_shape_width (fade_length);
2061 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2065 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2067 if (!movement_occurred) {
2071 nframes64_t fade_length;
2073 nframes64_t const pos = adjusted_current_frame (event);
2075 boost::shared_ptr<Region> region = _primary->region ();
2077 if (pos > (region->last_frame() - 64)) {
2078 fade_length = 64; // this should really be a minimum fade defined somewhere
2080 else if (pos < region->position()) {
2081 fade_length = region->length();
2084 fade_length = region->last_frame() - pos;
2087 _editor->begin_reversible_command (_("change fade out length"));
2089 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2091 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2097 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2098 XMLNode &before = alist->get_state();
2100 tmp->audio_region()->set_fade_out_length (fade_length);
2101 tmp->audio_region()->set_fade_out_active (true);
2103 XMLNode &after = alist->get_state();
2104 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2107 _editor->commit_reversible_command ();
2110 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2113 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2116 _points.push_back (Gnome::Art::Point (0, 0));
2117 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2119 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2120 _line->property_width_pixels() = 1;
2121 _line->property_points () = _points;
2124 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2127 MarkerDrag::~MarkerDrag ()
2129 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2135 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2137 Drag::start_grab (event, cursor);
2141 Location *location = _editor->find_location_from_marker (_marker, is_start);
2142 _editor->_dragging_edit_point = true;
2144 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2146 update_item (location);
2148 // _drag_line->show();
2149 // _line->raise_to_top();
2152 _editor->show_verbose_time_cursor (location->start(), 10);
2154 _editor->show_verbose_time_cursor (location->end(), 10);
2157 Selection::Operation op = Keyboard::selection_type (event->button.state);
2160 case Selection::Toggle:
2161 _editor->selection->toggle (_marker);
2163 case Selection::Set:
2164 if (!_editor->selection->selected (_marker)) {
2165 _editor->selection->set (_marker);
2168 case Selection::Extend:
2170 Locations::LocationList ll;
2171 list<Marker*> to_add;
2173 _editor->selection->markers.range (s, e);
2174 s = min (_marker->position(), s);
2175 e = max (_marker->position(), e);
2178 if (e < max_frames) {
2181 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2182 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2183 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2186 to_add.push_back (lm->start);
2189 to_add.push_back (lm->end);
2193 if (!to_add.empty()) {
2194 _editor->selection->add (to_add);
2198 case Selection::Add:
2199 _editor->selection->add (_marker);
2203 /* set up copies for us to manipulate during the drag */
2205 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2206 Location *l = _editor->find_location_from_marker (*i, is_start);
2207 _copied_locations.push_back (new Location (*l));
2212 MarkerDrag::motion (GdkEvent* event, bool)
2214 nframes64_t f_delta = 0;
2216 bool move_both = false;
2218 Location *real_location;
2219 Location *copy_location = 0;
2221 nframes64_t const newframe = adjusted_current_frame (event);
2223 nframes64_t next = newframe;
2225 if (_current_pointer_frame == _last_pointer_frame) {
2229 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2233 MarkerSelection::iterator i;
2234 list<Location*>::iterator x;
2236 /* find the marker we're dragging, and compute the delta */
2238 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2239 x != _copied_locations.end() && i != _editor->selection->markers.end();
2245 if (marker == _marker) {
2247 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2252 if (real_location->is_mark()) {
2253 f_delta = newframe - copy_location->start();
2257 switch (marker->type()) {
2259 case Marker::LoopStart:
2260 case Marker::PunchIn:
2261 f_delta = newframe - copy_location->start();
2265 case Marker::LoopEnd:
2266 case Marker::PunchOut:
2267 f_delta = newframe - copy_location->end();
2270 /* what kind of marker is this ? */
2278 if (i == _editor->selection->markers.end()) {
2279 /* hmm, impossible - we didn't find the dragged marker */
2283 /* now move them all */
2285 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2286 x != _copied_locations.end() && i != _editor->selection->markers.end();
2292 /* call this to find out if its the start or end */
2294 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2298 if (real_location->locked()) {
2302 if (copy_location->is_mark()) {
2306 copy_location->set_start (copy_location->start() + f_delta);
2310 nframes64_t new_start = copy_location->start() + f_delta;
2311 nframes64_t new_end = copy_location->end() + f_delta;
2313 if (is_start) { // start-of-range marker
2316 copy_location->set_start (new_start);
2317 copy_location->set_end (new_end);
2318 } else if (new_start < copy_location->end()) {
2319 copy_location->set_start (new_start);
2321 _editor->snap_to (next, 1, true);
2322 copy_location->set_end (next);
2323 copy_location->set_start (newframe);
2326 } else { // end marker
2329 copy_location->set_end (new_end);
2330 copy_location->set_start (new_start);
2331 } else if (new_end > copy_location->start()) {
2332 copy_location->set_end (new_end);
2333 } else if (newframe > 0) {
2334 _editor->snap_to (next, -1, true);
2335 copy_location->set_start (next);
2336 copy_location->set_end (newframe);
2341 update_item (copy_location);
2343 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2346 lm->set_position (copy_location->start(), copy_location->end());
2350 _last_pointer_frame = _current_pointer_frame;
2352 assert (!_copied_locations.empty());
2354 _editor->edit_point_clock.set (_copied_locations.front()->start());
2355 _editor->show_verbose_time_cursor (newframe, 10);
2358 _editor->update_canvas_now ();
2360 _editor->edit_point_clock.set (copy_location->start());
2364 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2366 if (!movement_occurred) {
2368 /* just a click, do nothing but finish
2369 off the selection process
2372 Selection::Operation op = Keyboard::selection_type (event->button.state);
2375 case Selection::Set:
2376 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2377 _editor->selection->set (_marker);
2381 case Selection::Toggle:
2382 case Selection::Extend:
2383 case Selection::Add:
2390 _editor->_dragging_edit_point = false;
2392 _editor->begin_reversible_command ( _("move marker") );
2393 XMLNode &before = _editor->session->locations()->get_state();
2395 MarkerSelection::iterator i;
2396 list<Location*>::iterator x;
2399 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2400 x != _copied_locations.end() && i != _editor->selection->markers.end();
2403 Location * location = _editor->find_location_from_marker (*i, is_start);
2407 if (location->locked()) {
2411 if (location->is_mark()) {
2412 location->set_start ((*x)->start());
2414 location->set ((*x)->start(), (*x)->end());
2419 XMLNode &after = _editor->session->locations()->get_state();
2420 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
2421 _editor->commit_reversible_command ();
2427 MarkerDrag::update_item (Location* location)
2429 double const x1 = _editor->frame_to_pixel (location->start());
2431 _points.front().set_x(x1);
2432 _points.back().set_x(x1);
2433 _line->property_points() = _points;
2436 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2438 _cumulative_x_drag (0),
2439 _cumulative_y_drag (0)
2441 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2447 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2449 Drag::start_grab (event, _editor->fader_cursor);
2451 // start the grab at the center of the control point so
2452 // the point doesn't 'jump' to the mouse after the first drag
2453 _grab_x = _point->get_x();
2454 _grab_y = _point->get_y();
2456 _point->line().parent_group().i2w (_grab_x, _grab_y);
2457 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2459 _grab_frame = _editor->pixel_to_frame (_grab_x);
2461 _point->line().start_drag (_point, _grab_frame, 0);
2463 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2464 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2465 _current_pointer_x + 10, _current_pointer_y + 10);
2467 _editor->show_verbose_canvas_cursor ();
2471 ControlPointDrag::motion (GdkEvent* event, bool)
2473 double dx = _current_pointer_x - _last_pointer_x;
2474 double dy = _current_pointer_y - _last_pointer_y;
2476 if (event->button.state & Keyboard::SecondaryModifier) {
2481 double cx = _grab_x + _cumulative_x_drag + dx;
2482 double cy = _grab_y + _cumulative_y_drag + dy;
2484 // calculate zero crossing point. back off by .01 to stay on the
2485 // positive side of zero
2487 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2488 _point->line().parent_group().i2w(_unused, zero_gain_y);
2490 // make sure we hit zero when passing through
2491 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2492 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2496 if (_x_constrained) {
2499 if (_y_constrained) {
2503 _cumulative_x_drag = cx - _grab_x;
2504 _cumulative_y_drag = cy - _grab_y;
2506 _point->line().parent_group().w2i (cx, cy);
2510 cy = min ((double) _point->line().height(), cy);
2512 //translate cx to frames
2513 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2515 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !_x_constrained) {
2516 _editor->snap_to (cx_frames);
2519 float const fraction = 1.0 - (cy / _point->line().height());
2521 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2523 _point->line().point_drag (*_point, cx_frames, fraction, push);
2525 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2529 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2531 if (!movement_occurred) {
2535 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2536 _editor->reset_point_selection ();
2540 motion (event, false);
2542 _point->line().end_drag (_point);
2545 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2548 _cumulative_y_drag (0)
2553 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2555 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2558 _item = &_line->grab_item ();
2560 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2561 origin, and ditto for y.
2564 double cx = event->button.x;
2565 double cy = event->button.y;
2567 _line->parent_group().w2i (cx, cy);
2569 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2571 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2572 /* no adjacent points */
2576 Drag::start_grab (event, _editor->fader_cursor);
2578 /* store grab start in parent frame */
2583 double fraction = 1.0 - (cy / _line->height());
2585 _line->start_drag (0, _grab_frame, fraction);
2587 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2588 _current_pointer_x + 10, _current_pointer_y + 10);
2590 _editor->show_verbose_canvas_cursor ();
2594 LineDrag::motion (GdkEvent* event, bool)
2596 double dy = _current_pointer_y - _last_pointer_y;
2598 if (event->button.state & Keyboard::SecondaryModifier) {
2602 double cy = _grab_y + _cumulative_y_drag + dy;
2604 _cumulative_y_drag = cy - _grab_y;
2607 cy = min ((double) _line->height(), cy);
2609 double const fraction = 1.0 - (cy / _line->height());
2613 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2619 _line->line_drag (_before, _after, fraction, push);
2621 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2625 LineDrag::finished (GdkEvent* event, bool)
2627 motion (event, false);
2628 _line->end_drag (0);
2632 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2634 Drag::start_grab (event);
2635 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2639 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2646 /* use a bigger drag threshold than the default */
2648 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2652 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && Config->get_rubberbanding_snaps_to_grid()) {
2654 _editor->snap_to (_grab_frame);
2656 _editor->snap_to (_current_pointer_frame);
2659 /* base start and end on initial click position */
2661 if (_current_pointer_frame < _grab_frame) {
2662 start = _current_pointer_frame;
2665 end = _current_pointer_frame;
2666 start = _grab_frame;
2669 if (_current_pointer_y < _grab_y) {
2670 y1 = _current_pointer_y;
2673 y2 = _current_pointer_y;
2678 if (start != end || y1 != y2) {
2680 double x1 = _editor->frame_to_pixel (start);
2681 double x2 = _editor->frame_to_pixel (end);
2683 _editor->rubberband_rect->property_x1() = x1;
2684 _editor->rubberband_rect->property_y1() = y1;
2685 _editor->rubberband_rect->property_x2() = x2;
2686 _editor->rubberband_rect->property_y2() = y2;
2688 _editor->rubberband_rect->show();
2689 _editor->rubberband_rect->raise_to_top();
2691 _last_pointer_frame = _current_pointer_frame;
2693 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2698 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2700 if (movement_occurred) {
2702 motion (event, false);
2705 if (_current_pointer_y < _grab_y) {
2706 y1 = _current_pointer_y;
2709 y2 = _current_pointer_y;
2714 Selection::Operation op = Keyboard::selection_type (event->button.state);
2717 _editor->begin_reversible_command (_("rubberband selection"));
2719 if (_grab_frame < _last_pointer_frame) {
2720 commit = _editor->select_all_within (_grab_frame, _last_pointer_frame, y1, y2, _editor->track_views, op);
2722 commit = _editor->select_all_within (_last_pointer_frame, _grab_frame, y1, y2, _editor->track_views, op);
2726 _editor->commit_reversible_command ();
2730 if (!getenv("ARDOUR_SAE")) {
2731 _editor->selection->clear_tracks();
2733 _editor->selection->clear_regions();
2734 _editor->selection->clear_points ();
2735 _editor->selection->clear_lines ();
2738 _editor->rubberband_rect->hide();
2742 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2744 Drag::start_grab (event);
2746 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2750 TimeFXDrag::motion (GdkEvent* event, bool)
2752 RegionView* rv = _primary;
2754 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2755 _editor->snap_to (_current_pointer_frame);
2758 if (_current_pointer_frame == _last_pointer_frame) {
2762 if (_current_pointer_frame > rv->region()->position()) {
2763 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2766 _last_pointer_frame = _current_pointer_frame;
2768 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2772 TimeFXDrag::finished (GdkEvent* event, bool movement_occurred)
2774 _primary->get_time_axis_view().hide_timestretch ();
2776 if (!movement_occurred) {
2780 if (_last_pointer_frame < _primary->region()->position()) {
2781 /* backwards drag of the left edge - not usable */
2785 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2787 float percentage = (double) newlen / (double) _primary->region()->length();
2789 #ifndef USE_RUBBERBAND
2790 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2791 if (_primary->region()->data_type() == DataType::AUDIO) {
2792 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2796 _editor->begin_reversible_command (_("timestretch"));
2798 // XXX how do timeFX on multiple regions ?
2803 if (_editor->time_stretch (rs, percentage) == 0) {
2804 _editor->session->commit_reversible_command ();
2809 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2811 Drag::start_grab (event);
2815 ScrubDrag::motion (GdkEvent* event, bool)
2821 ScrubDrag::finished (GdkEvent* event, bool movement_occurred)
2823 if (movement_occurred && _editor->session) {
2824 /* make sure we stop */
2825 _editor->session->request_transport_speed (0.0);
2829 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2838 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2840 nframes64_t start = 0;
2841 nframes64_t end = 0;
2843 if (_editor->session == 0) {
2847 Gdk::Cursor* cursor = 0;
2849 switch (_operation) {
2850 case CreateSelection:
2851 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2856 cursor = _editor->selector_cursor;
2857 Drag::start_grab (event, cursor);
2860 case SelectionStartTrim:
2861 if (_editor->clicked_axisview) {
2862 _editor->clicked_axisview->order_selection_trims (_item, true);
2864 Drag::start_grab (event, cursor);
2865 cursor = _editor->trimmer_cursor;
2866 start = _editor->selection->time[_editor->clicked_selection].start;
2867 _pointer_frame_offset = _grab_frame - start;
2870 case SelectionEndTrim:
2871 if (_editor->clicked_axisview) {
2872 _editor->clicked_axisview->order_selection_trims (_item, false);
2874 Drag::start_grab (event, cursor);
2875 cursor = _editor->trimmer_cursor;
2876 end = _editor->selection->time[_editor->clicked_selection].end;
2877 _pointer_frame_offset = _grab_frame - end;
2881 start = _editor->selection->time[_editor->clicked_selection].start;
2882 Drag::start_grab (event, cursor);
2883 _pointer_frame_offset = _grab_frame - start;
2887 if (_operation == SelectionMove) {
2888 _editor->show_verbose_time_cursor (start, 10);
2890 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2895 SelectionDrag::motion (GdkEvent* event, bool first_move)
2897 nframes64_t start = 0;
2898 nframes64_t end = 0;
2901 nframes64_t const pending_position = adjusted_current_frame (event);
2903 /* only alter selection if the current frame is
2904 different from the last frame position (adjusted)
2907 if (pending_position == _last_pointer_frame) {
2911 switch (_operation) {
2912 case CreateSelection:
2915 _editor->snap_to (_grab_frame);
2918 if (pending_position < _grab_frame) {
2919 start = pending_position;
2922 end = pending_position;
2923 start = _grab_frame;
2926 /* first drag: Either add to the selection
2927 or create a new selection->
2932 _editor->begin_reversible_command (_("range selection"));
2935 /* adding to the selection */
2936 _editor->clicked_selection = _editor->selection->add (start, end);
2939 /* new selection-> */
2940 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2945 case SelectionStartTrim:
2948 _editor->begin_reversible_command (_("trim selection start"));
2951 start = _editor->selection->time[_editor->clicked_selection].start;
2952 end = _editor->selection->time[_editor->clicked_selection].end;
2954 if (pending_position > end) {
2957 start = pending_position;
2961 case SelectionEndTrim:
2964 _editor->begin_reversible_command (_("trim selection end"));
2967 start = _editor->selection->time[_editor->clicked_selection].start;
2968 end = _editor->selection->time[_editor->clicked_selection].end;
2970 if (pending_position < start) {
2973 end = pending_position;
2981 _editor->begin_reversible_command (_("move selection"));
2984 start = _editor->selection->time[_editor->clicked_selection].start;
2985 end = _editor->selection->time[_editor->clicked_selection].end;
2987 length = end - start;
2989 start = pending_position;
2990 _editor->snap_to (start);
2992 end = start + length;
2997 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
2998 _editor->start_canvas_autoscroll (1, 0);
3002 _editor->selection->replace (_editor->clicked_selection, start, end);
3005 _last_pointer_frame = pending_position;
3007 if (_operation == SelectionMove) {
3008 _editor->show_verbose_time_cursor(start, 10);
3010 _editor->show_verbose_time_cursor(pending_position, 10);
3015 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3017 if (movement_occurred) {
3018 motion (event, false);
3019 /* XXX this is not object-oriented programming at all. ick */
3020 if (_editor->selection->time.consolidate()) {
3021 _editor->selection->TimeChanged ();
3023 _editor->commit_reversible_command ();
3025 /* just a click, no pointer movement.*/
3027 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3029 _editor->selection->clear_time();
3034 /* XXX what happens if its a music selection? */
3035 _editor->session->set_audio_range (_editor->selection->time);
3036 _editor->stop_canvas_autoscroll ();
3039 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3044 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3045 _drag_rect->hide ();
3047 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3048 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3052 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3054 if (_editor->session == 0) {
3058 Gdk::Cursor* cursor = 0;
3060 if (!_editor->temp_location) {
3061 _editor->temp_location = new Location;
3064 switch (_operation) {
3065 case CreateRangeMarker:
3066 case CreateTransportMarker:
3067 case CreateCDMarker:
3069 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3074 cursor = _editor->selector_cursor;
3078 Drag::start_grab (event, cursor);
3080 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3084 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3086 nframes64_t start = 0;
3087 nframes64_t end = 0;
3088 ArdourCanvas::SimpleRect *crect;
3090 switch (_operation) {
3091 case CreateRangeMarker:
3092 crect = _editor->range_bar_drag_rect;
3094 case CreateTransportMarker:
3095 crect = _editor->transport_bar_drag_rect;
3097 case CreateCDMarker:
3098 crect = _editor->cd_marker_bar_drag_rect;
3101 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3106 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3107 _editor->snap_to (_current_pointer_frame);
3110 /* only alter selection if the current frame is
3111 different from the last frame position.
3114 if (_current_pointer_frame == _last_pointer_frame) {
3118 switch (_operation) {
3119 case CreateRangeMarker:
3120 case CreateTransportMarker:
3121 case CreateCDMarker:
3123 _editor->snap_to (_grab_frame);
3126 if (_current_pointer_frame < _grab_frame) {
3127 start = _current_pointer_frame;
3130 end = _current_pointer_frame;
3131 start = _grab_frame;
3134 /* first drag: Either add to the selection
3135 or create a new selection.
3140 _editor->temp_location->set (start, end);
3144 update_item (_editor->temp_location);
3146 //_drag_rect->raise_to_top();
3152 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3153 _editor->start_canvas_autoscroll (1, 0);
3157 _editor->temp_location->set (start, end);
3159 double x1 = _editor->frame_to_pixel (start);
3160 double x2 = _editor->frame_to_pixel (end);
3161 crect->property_x1() = x1;
3162 crect->property_x2() = x2;
3164 update_item (_editor->temp_location);
3167 _last_pointer_frame = _current_pointer_frame;
3169 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3174 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3176 Location * newloc = 0;
3180 if (movement_occurred) {
3181 motion (event, false);
3183 switch (_operation) {
3184 case CreateRangeMarker:
3185 case CreateCDMarker:
3187 _editor->begin_reversible_command (_("new range marker"));
3188 XMLNode &before = _editor->session->locations()->get_state();
3189 _editor->session->locations()->next_available_name(rangename,"unnamed");
3190 if (_operation == CreateCDMarker) {
3191 flags = Location::IsRangeMarker | Location::IsCDMarker;
3192 _editor->cd_marker_bar_drag_rect->hide();
3195 flags = Location::IsRangeMarker;
3196 _editor->range_bar_drag_rect->hide();
3198 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3199 _editor->session->locations()->add (newloc, true);
3200 XMLNode &after = _editor->session->locations()->get_state();
3201 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3202 _editor->commit_reversible_command ();
3208 case CreateTransportMarker:
3209 // popup menu to pick loop or punch
3210 _editor->new_transport_marker_context_menu (&event->button, _item);
3215 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3217 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3222 start = _editor->session->locations()->first_mark_before (_grab_frame);
3223 end = _editor->session->locations()->first_mark_after (_grab_frame);
3225 if (end == max_frames) {
3226 end = _editor->session->current_end_frame ();
3230 start = _editor->session->current_start_frame ();
3233 switch (_editor->mouse_mode) {
3235 /* find the two markers on either side and then make the selection from it */
3236 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3240 /* find the two markers on either side of the click and make the range out of it */
3241 _editor->selection->set (0, start, end);
3250 _editor->stop_canvas_autoscroll ();
3256 RangeMarkerBarDrag::update_item (Location* location)
3258 double const x1 = _editor->frame_to_pixel (location->start());
3259 double const x2 = _editor->frame_to_pixel (location->end());
3261 _drag_rect->property_x1() = x1;
3262 _drag_rect->property_x2() = x2;
3266 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3268 Drag::start_grab (event, _editor->zoom_cursor);
3269 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3273 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3278 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3279 _editor->snap_to (_current_pointer_frame);
3282 _editor->snap_to (_grab_frame);
3286 if (_current_pointer_frame == _last_pointer_frame) {
3290 /* base start and end on initial click position */
3291 if (_current_pointer_frame < _grab_frame) {
3292 start = _current_pointer_frame;
3295 end = _current_pointer_frame;
3296 start = _grab_frame;
3302 _editor->zoom_rect->show();
3303 _editor->zoom_rect->raise_to_top();
3306 _editor->reposition_zoom_rect(start, end);
3308 _last_pointer_frame = _current_pointer_frame;
3310 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3315 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3317 if (movement_occurred) {
3318 motion (event, false);
3320 if (_grab_frame < _last_pointer_frame) {
3321 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3323 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3326 _editor->temporal_zoom_to_frame (false, _grab_frame);
3328 temporal_zoom_step (false);
3329 center_screen (_grab_frame);
3333 _editor->zoom_rect->hide();