2 Copyright (C) 2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "pbd/memento_command.h"
21 #include "pbd/basename.h"
22 #include "ardour/diskstream.h"
23 #include "ardour/dB.h"
24 #include "ardour/region_factory.h"
25 #include "ardour/midi_diskstream.h"
29 #include "audio_region_view.h"
30 #include "midi_region_view.h"
31 #include "ardour_ui.h"
32 #include "control_point.h"
34 #include "region_gain_line.h"
35 #include "editor_drag.h"
36 #include "audio_time_axis.h"
37 #include "midi_time_axis.h"
40 using namespace ARDOUR;
44 using namespace Editing;
46 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
48 Drag::Drag (Editor* e, ArdourCanvas::Item* i) :
51 _pointer_frame_offset (0),
53 _last_pointer_frame (0),
54 _current_pointer_frame (0),
55 _had_movement (false),
56 _move_threshold_passed (false)
62 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
68 cursor = _editor->which_grabber_cursor ();
71 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
75 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
78 cursor = _editor->which_grabber_cursor ();
81 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
83 if (Keyboard::is_button2_event (&event->button)) {
84 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
85 _y_constrained = true;
86 _x_constrained = false;
88 _y_constrained = false;
89 _x_constrained = true;
92 _x_constrained = false;
93 _y_constrained = false;
96 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
97 _last_pointer_frame = _grab_frame;
98 _current_pointer_frame = _grab_frame;
99 _current_pointer_x = _grab_x;
100 _current_pointer_y = _grab_y;
101 _last_pointer_x = _current_pointer_x;
102 _last_pointer_y = _current_pointer_y;
106 _item->i2w (_original_x, _original_y);
108 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
112 if (_editor->session && _editor->session->transport_rolling()) {
115 _was_rolling = false;
118 switch (_editor->snap_type) {
119 case SnapToRegionStart:
120 case SnapToRegionEnd:
121 case SnapToRegionSync:
122 case SnapToRegionBoundary:
123 _editor->build_region_boundary_cache ();
130 /** @param event GDK event, or 0.
131 * @return true if some movement occurred, otherwise false.
134 Drag::end_grab (GdkEvent* event)
138 _editor->stop_canvas_autoscroll ();
140 _item->ungrab (event ? event->button.time : 0);
142 _last_pointer_x = _current_pointer_x;
143 _last_pointer_y = _current_pointer_y;
144 finished (event, _had_movement);
146 _editor->hide_verbose_canvas_cursor();
150 return _had_movement;
154 Drag::adjusted_current_frame (GdkEvent* event) const
158 if (_current_pointer_frame > _pointer_frame_offset) {
159 pos = _current_pointer_frame - _pointer_frame_offset;
162 _editor->snap_to_with_modifier (pos, event);
168 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
170 _last_pointer_x = _current_pointer_x;
171 _last_pointer_y = _current_pointer_y;
172 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
174 if (!from_autoscroll && !_move_threshold_passed) {
176 bool const xp = (::llabs ((nframes64_t) (_current_pointer_x - _grab_x)) > 4LL);
177 bool const yp = (::llabs ((nframes64_t) (_current_pointer_y - _grab_y)) > 4LL);
179 _move_threshold_passed = (xp || yp);
181 if (apply_move_threshold() && _move_threshold_passed) {
183 _grab_frame = _current_pointer_frame;
184 _grab_x = _current_pointer_x;
185 _grab_y = _current_pointer_y;
186 _last_pointer_frame = _grab_frame;
187 _pointer_frame_offset = _grab_frame - _last_frame_position;
192 bool old_had_movement = _had_movement;
194 /* a motion event has happened, so we've had movement... */
195 _had_movement = true;
197 /* ... unless we're using a move threshold and we've not yet passed it */
198 if (apply_move_threshold() && !_move_threshold_passed) {
199 _had_movement = false;
202 if (active (_editor->mouse_mode)) {
204 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
205 if (!from_autoscroll) {
206 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
209 motion (event, _had_movement != old_had_movement);
221 _editor->stop_canvas_autoscroll ();
222 _editor->hide_verbose_canvas_cursor ();
227 /* put it back where it came from */
232 _item->i2w (cxw, cyw);
233 _item->move (_original_x - cxw, _original_y - cyw);
238 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
243 RegionView::RegionViewGoingAway.connect (mem_fun (*this, &RegionDrag::region_going_away));
247 RegionDrag::region_going_away (RegionView* v)
252 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
253 : RegionDrag (e, i, p, v),
263 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
265 Drag::start_grab (event);
267 _editor->show_verbose_time_cursor (_last_frame_position, 10);
270 RegionMotionDrag::TimeAxisViewSummary
271 RegionMotionDrag::get_time_axis_view_summary ()
273 int32_t children = 0;
274 TimeAxisViewSummary sum;
276 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
278 /* get a bitmask representing the visible tracks */
280 for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
281 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
282 TimeAxisView::Children children_list;
284 /* zeroes are audio/MIDI tracks. ones are other types. */
286 if (!rtv->hidden()) {
288 if (!rtv->is_track()) {
289 /* not an audio nor MIDI track */
290 sum.tracks = sum.tracks |= (0x01 << rtv->order());
293 sum.height_list[rtv->order()] = (*i)->current_height();
296 if ((children_list = rtv->get_child_list()).size() > 0) {
297 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
298 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
299 sum.height_list[rtv->order() + children] = (*j)->current_height();
310 RegionMotionDrag::compute_y_delta (
311 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
312 int32_t last_pointer_layer, int32_t current_pointer_layer,
313 TimeAxisViewSummary const & tavs,
314 int32_t* pointer_order_span, int32_t* pointer_layer_span,
315 int32_t* canvas_pointer_order_span
319 *pointer_order_span = 0;
320 *pointer_layer_span = 0;
324 bool clamp_y_axis = false;
326 /* the change in track order between this callback and the last */
327 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
328 /* the change in layer between this callback and the last;
329 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
330 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
332 if (*pointer_order_span != 0) {
334 /* find the actual pointer span, in terms of the number of visible tracks;
335 to do this, we reduce |pointer_order_span| by the number of hidden tracks
338 *canvas_pointer_order_span = *pointer_order_span;
339 if (last_pointer_view->order() >= current_pointer_view->order()) {
340 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
341 if (tavs.height_list[y] == 0) {
342 *canvas_pointer_order_span--;
346 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
347 if (tavs.height_list[y] == 0) {
348 *canvas_pointer_order_span++;
353 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
355 RegionView* rv = (*i);
357 if (rv->region()->locked()) {
361 double ix1, ix2, iy1, iy2;
362 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
363 rv->get_canvas_frame()->i2w (ix1, iy1);
364 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
366 /* get the new trackview for this particular region */
367 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
369 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
371 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
372 as surely this is a per-region thing... */
374 clamp_y_axis = y_movement_disallowed (
375 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
383 } else if (_dest_trackview == current_pointer_view) {
385 if (current_pointer_layer == last_pointer_layer) {
386 /* No movement; clamp */
392 _dest_trackview = current_pointer_view;
393 _dest_layer = current_pointer_layer;
401 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
403 *pending_region_position = 0;
405 /* compute the amount of pointer motion in frames, and where
406 the region would be if we moved it by that much.
408 if (_current_pointer_frame >= _pointer_frame_offset) {
410 nframes64_t sync_frame;
411 nframes64_t sync_offset;
414 *pending_region_position = _current_pointer_frame - _pointer_frame_offset;
416 sync_offset = _primary->region()->sync_offset (sync_dir);
418 /* we don't handle a sync point that lies before zero.
420 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
422 sync_frame = *pending_region_position + (sync_dir*sync_offset);
424 _editor->snap_to_with_modifier (sync_frame, event);
426 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
429 *pending_region_position = _last_frame_position;
434 if (*pending_region_position > max_frames - _primary->region()->length()) {
435 *pending_region_position = _last_frame_position;
440 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
442 /* now compute the canvas unit distance we need to move the regionview
443 to make it appear at the new location.
446 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
448 if (*pending_region_position <= _last_frame_position) {
450 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
452 RegionView* rv = (*i);
454 // If any regionview is at zero, we need to know so we can stop further leftward motion.
456 double ix1, ix2, iy1, iy2;
457 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
458 rv->get_canvas_frame()->i2w (ix1, iy1);
460 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
462 *pending_region_position = _last_frame_position;
469 _last_frame_position = *pending_region_position;
476 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
480 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
482 vector<int32_t>::iterator j;
484 /* *pointer* variables reflect things about the pointer; as we may be moving
485 multiple regions, much detail must be computed per-region */
487 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
488 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
489 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
490 is always 0 regardless of what the region's "real" layer is */
491 RouteTimeAxisView* current_pointer_view;
492 layer_t current_pointer_layer;
493 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
497 /* TimeAxisView that we were pointing at last time we entered this method */
498 TimeAxisView const * const last_pointer_view = _dest_trackview;
499 /* the order of the track that we were pointing at last time we entered this method */
500 int32_t const last_pointer_order = last_pointer_view->order ();
501 /* the layer that we were pointing at last time we entered this method */
502 layer_t const last_pointer_layer = _dest_layer;
504 int32_t pointer_order_span;
505 int32_t pointer_layer_span;
506 int32_t canvas_pointer_order_span;
508 bool const clamp_y_axis = compute_y_delta (
509 last_pointer_view, current_pointer_view,
510 last_pointer_layer, current_pointer_layer, tavs,
511 &pointer_order_span, &pointer_layer_span,
512 &canvas_pointer_order_span
515 nframes64_t pending_region_position;
516 double const x_delta = compute_x_delta (event, &pending_region_position);
518 /*************************************************************
520 ************************************************************/
522 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0) {
523 /* haven't reached next snap point, and we're not switching
524 trackviews nor layers. nothing to do.
529 /*************************************************************
531 ************************************************************/
533 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
535 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
537 RegionView* rv = (*i);
539 if (rv->region()->locked()) {
543 /* here we are calculating the y distance from the
544 top of the first track view to the top of the region
545 area of the track view that we're working on */
547 /* this x value is just a dummy value so that we have something
552 /* distance from the top of this track view to the region area
553 of our track view is always 1 */
557 /* convert to world coordinates, ie distance from the top of
560 rv->get_canvas_frame()->i2w (ix1, iy1);
562 /* compensate for the ruler section and the vertical scrollbar position */
563 iy1 += _editor->get_trackview_group_vertical_offset ();
567 // hide any dependent views
569 rv->get_time_axis_view().hide_dependent_views (*rv);
572 reparent to a non scrolling group so that we can keep the
573 region selection above all time axis views.
574 reparenting means we have to move the rv as the two
575 parent groups have different coordinates.
578 rv->get_canvas_group()->property_y() = iy1 - 1;
579 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
581 rv->fake_set_opaque (true);
584 /* current view for this particular region */
585 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
586 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
588 if (pointer_order_span != 0 && !clamp_y_axis) {
590 /* INTER-TRACK MOVEMENT */
592 /* move through the height list to the track that the region is currently on */
593 vector<int32_t>::iterator j = tavs.height_list.begin ();
595 while (j != tavs.height_list.end () && x != rtv->order ()) {
601 int32_t temp_pointer_order_span = canvas_pointer_order_span;
603 if (j != tavs.height_list.end ()) {
605 /* Account for layers in the original and
606 destination tracks. If we're moving around in layers we assume
607 that only one track is involved, so it's ok to use *pointer*
610 StreamView* lv = last_pointer_view->view ();
613 /* move to the top of the last trackview */
614 if (lv->layer_display () == Stacked) {
615 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
618 StreamView* cv = current_pointer_view->view ();
621 /* move to the right layer on the current trackview */
622 if (cv->layer_display () == Stacked) {
623 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
626 /* And for being on a non-topmost layer on the new
629 while (temp_pointer_order_span > 0) {
630 /* we're moving up canvas-wise,
631 so we need to find the next track height
633 if (j != tavs.height_list.begin()) {
637 if (x != last_pointer_order) {
639 ++temp_pointer_order_span;
644 temp_pointer_order_span--;
647 while (temp_pointer_order_span < 0) {
651 if (x != last_pointer_order) {
653 --temp_pointer_order_span;
657 if (j != tavs.height_list.end()) {
661 temp_pointer_order_span++;
665 /* find out where we'll be when we move and set height accordingly */
667 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
668 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
669 rv->set_height (temp_rtv->view()->child_height());
671 /* if you un-comment the following, the region colours will follow
672 the track colours whilst dragging; personally
673 i think this can confuse things, but never mind.
676 //const GdkColor& col (temp_rtv->view->get_region_color());
677 //rv->set_color (const_cast<GdkColor&>(col));
681 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
683 /* INTER-LAYER MOVEMENT in the same track */
684 y_delta = rtv->view()->child_height () * pointer_layer_span;
689 _editor->mouse_brush_insert_region (rv, pending_region_position);
691 rv->move (x_delta, y_delta);
694 } /* foreach region */
697 _editor->cursor_group->raise_to_top();
700 if (x_delta != 0 && !_brushing) {
701 _editor->show_verbose_time_cursor (_last_frame_position, 10);
706 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
708 if (_copy && first_move) {
709 copy_regions (event);
712 RegionMotionDrag::motion (event, first_move);
716 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
718 vector<RegionView*> copies;
719 boost::shared_ptr<Diskstream> ds;
720 boost::shared_ptr<Playlist> from_playlist;
721 list<RegionView*> new_views;
722 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
723 PlaylistSet modified_playlists;
724 PlaylistSet frozen_playlists;
725 list <sigc::connection> modified_playlist_connections;
726 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
727 nframes64_t drag_delta;
728 bool changed_tracks, changed_position;
729 map<RegionView*, RouteTimeAxisView*> final;
730 RouteTimeAxisView* source_tv;
732 if (!movement_occurred) {
737 if (Config->get_edit_mode() == Splice && !_editor->pre_drag_region_selection.empty()) {
738 _editor->selection->set (_editor->pre_drag_region_selection);
739 _editor->pre_drag_region_selection.clear ();
743 /* all changes were made during motion event handlers */
746 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
747 copies.push_back (*i);
754 /* reverse this here so that we have the correct logic to finalize
758 if (Config->get_edit_mode() == Lock && !_copy) {
759 _x_constrained = !_x_constrained;
763 if (_x_constrained) {
764 _editor->begin_reversible_command (_("fixed time region copy"));
766 _editor->begin_reversible_command (_("region copy"));
769 if (_x_constrained) {
770 _editor->begin_reversible_command (_("fixed time region drag"));
772 _editor->begin_reversible_command (_("region drag"));
776 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
777 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
779 drag_delta = _primary->region()->position() - _last_frame_position;
781 _editor->update_canvas_now ();
783 /* make a list of where each region ended up */
784 final = find_time_axis_views ();
786 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
788 RegionView* rv = (*i);
789 RouteTimeAxisView* dest_rtv = final[*i];
793 if (rv->region()->locked()) {
798 if (changed_position && !_x_constrained) {
799 where = rv->region()->position() - drag_delta;
801 where = rv->region()->position();
804 boost::shared_ptr<Region> new_region;
807 /* we already made a copy */
808 new_region = rv->region();
810 /* undo the previous hide_dependent_views so that xfades don't
811 disappear on copying regions
814 //rv->get_time_axis_view().reveal_dependent_views (*rv);
816 } else if (changed_tracks && dest_rtv->playlist()) {
817 new_region = RegionFactory::create (rv->region());
820 if (changed_tracks || _copy) {
822 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
829 _editor->latest_regionviews.clear ();
831 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
833 insert_result = modified_playlists.insert (to_playlist);
835 if (insert_result.second) {
836 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
839 to_playlist->add_region (new_region, where);
843 if (!_editor->latest_regionviews.empty()) {
844 // XXX why just the first one ? we only expect one
845 // commented out in nick_m's canvas reworking. is that intended?
846 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
847 new_views.push_back (_editor->latest_regionviews.front());
852 motion on the same track. plonk the previously reparented region
853 back to its original canvas group (its streamview).
854 No need to do anything for copies as they are fake regions which will be deleted.
857 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
858 rv->get_canvas_group()->property_y() = 0;
860 /* just change the model */
862 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
864 insert_result = modified_playlists.insert (playlist);
866 if (insert_result.second) {
867 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
869 /* freeze to avoid lots of relayering in the case of a multi-region drag */
870 frozen_insert_result = frozen_playlists.insert(playlist);
872 if (frozen_insert_result.second) {
876 rv->region()->set_position (where, (void*) this);
879 if (changed_tracks && !_copy) {
881 /* get the playlist where this drag started. we can't use rv->region()->playlist()
882 because we may have copied the region and it has not been attached to a playlist.
885 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
886 ds = source_tv->get_diskstream();
887 from_playlist = ds->playlist();
891 assert (from_playlist);
893 /* moved to a different audio track, without copying */
895 /* the region that used to be in the old playlist is not
896 moved to the new one - we use a copy of it. as a result,
897 any existing editor for the region should no longer be
901 rv->hide_region_editor();
902 rv->fake_set_opaque (false);
904 /* remove the region from the old playlist */
906 insert_result = modified_playlists.insert (from_playlist);
908 if (insert_result.second) {
909 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
912 from_playlist->remove_region (rv->region());
914 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
915 was selected in all of them, then removing it from a playlist will have removed all
916 trace of it from the selection (i.e. there were N regions selected, we removed 1,
917 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
918 corresponding regionview, and the selection is now empty).
920 this could have invalidated any and all iterators into the region selection.
922 the heuristic we use here is: if the region selection is empty, break out of the loop
923 here. if the region selection is not empty, then restart the loop because we know that
924 we must have removed at least the region(view) we've just been working on as well as any
925 that we processed on previous iterations.
927 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
931 if (_views.empty()) {
942 copies.push_back (rv);
946 if (new_views.empty()) {
948 /* the region(view)s that are being dragged around are copies and do not
949 belong to any track. remove them from our list
955 _primary = _views.front ();
958 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
963 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
964 _editor->session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
967 _editor->commit_reversible_command ();
969 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
976 RegionMoveDrag::x_move_allowed () const
978 if (Config->get_edit_mode() == Lock) {
980 return !_x_constrained;
982 /* in locked edit mode, reverse the usual meaning of _x_constrained */
983 return _x_constrained;
987 return !_x_constrained;
991 RegionInsertDrag::x_move_allowed () const
993 if (Config->get_edit_mode() == Lock) {
994 return _x_constrained;
997 return !_x_constrained;
1001 RegionMotionDrag::copy_regions (GdkEvent* event)
1003 /* duplicate the regionview(s) and region(s) */
1005 list<RegionView*> new_regionviews;
1007 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1009 RegionView* rv = (*i);
1010 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1011 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1013 const boost::shared_ptr<const Region> original = rv->region();
1014 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1018 boost::shared_ptr<AudioRegion> audioregion_copy
1019 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1020 nrv = new AudioRegionView (*arv, audioregion_copy);
1022 boost::shared_ptr<MidiRegion> midiregion_copy
1023 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1024 nrv = new MidiRegionView (*mrv, midiregion_copy);
1029 nrv->get_canvas_group()->show ();
1030 new_regionviews.push_back (nrv);
1033 if (new_regionviews.empty()) {
1037 /* reflect the fact that we are dragging the copies */
1039 _primary = new_regionviews.front();
1040 _views = new_regionviews;
1042 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1045 sync the canvas to what we think is its current state
1046 without it, the canvas seems to
1047 "forget" to update properly after the upcoming reparent()
1048 ..only if the mouse is in rapid motion at the time of the grab.
1049 something to do with regionview creation raking so long?
1051 _editor->update_canvas_now();
1055 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1057 /* Which trackview is this ? */
1059 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1060 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1061 (*layer) = tvp.second;
1063 if (*tv && (*tv)->layer_display() == Overlaid) {
1067 /* The region motion is only processed if the pointer is over
1071 if (!(*tv) || !(*tv)->is_track()) {
1072 /* To make sure we hide the verbose canvas cursor when the mouse is
1073 not held over and audiotrack.
1075 _editor->hide_verbose_canvas_cursor ();
1082 /** @param new_order New track order.
1083 * @param old_order Old track order.
1084 * @param visible_y_low Lowest visible order.
1085 * @return true if y movement should not happen, otherwise false.
1088 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1090 if (new_order != old_order) {
1092 /* this isn't the pointer track */
1096 /* moving up the canvas */
1097 if ( (new_order - y_span) >= tavs.visible_y_low) {
1101 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1102 int32_t visible_tracks = 0;
1103 while (visible_tracks < y_span ) {
1105 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1106 /* passing through a hidden track */
1111 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1112 /* moving to a non-track; disallow */
1118 /* moving beyond the lowest visible track; disallow */
1122 } else if (y_span < 0) {
1124 /* moving down the canvas */
1125 if ((new_order - y_span) <= tavs.visible_y_high) {
1127 int32_t visible_tracks = 0;
1129 while (visible_tracks > y_span ) {
1132 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1133 /* passing through a hidden track */
1138 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1139 /* moving to a non-track; disallow */
1146 /* moving beyond the highest visible track; disallow */
1153 /* this is the pointer's track */
1155 if ((new_order - y_span) > tavs.visible_y_high) {
1156 /* we will overflow */
1158 } else if ((new_order - y_span) < tavs.visible_y_low) {
1159 /* we will overflow */
1168 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1169 : RegionMotionDrag (e, i, p, v, b),
1172 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1174 _dest_trackview = tv;
1175 if (tv->layer_display() == Overlaid) {
1178 _dest_layer = _primary->region()->layer ();
1182 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1183 if (rtv && rtv->is_track()) {
1184 speed = rtv->get_diskstream()->speed ();
1187 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1191 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1193 RegionMotionDrag::start_grab (event, c);
1195 _pointer_frame_offset = _grab_frame - _last_frame_position;
1198 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1199 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1201 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1202 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1204 _primary = v->view()->create_region_view (r, false, false);
1206 _primary->get_canvas_group()->show ();
1207 _primary->set_position (pos, 0);
1208 _views.push_back (_primary);
1210 _last_frame_position = pos;
1212 _item = _primary->get_canvas_group ();
1213 _dest_trackview = v;
1214 _dest_layer = _primary->region()->layer ();
1217 map<RegionView*, RouteTimeAxisView*>
1218 RegionMotionDrag::find_time_axis_views ()
1220 map<RegionView*, RouteTimeAxisView*> tav;
1222 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1224 double ix1, ix2, iy1, iy2;
1225 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1226 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1227 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1229 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1230 tav[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
1238 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1240 _editor->update_canvas_now ();
1242 map<RegionView*, RouteTimeAxisView*> final = find_time_axis_views ();
1244 RouteTimeAxisView* dest_rtv = final[_primary];
1246 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1247 _primary->get_canvas_group()->property_y() = 0;
1249 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1251 _editor->begin_reversible_command (_("insert region"));
1252 XMLNode& before = playlist->get_state ();
1253 playlist->add_region (_primary->region (), _last_frame_position);
1254 _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1255 _editor->commit_reversible_command ();
1262 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1263 : RegionMoveDrag (e, i, p, v, false, false)
1268 struct RegionSelectionByPosition {
1269 bool operator() (RegionView*a, RegionView* b) {
1270 return a->region()->position () < b->region()->position();
1275 RegionSpliceDrag::motion (GdkEvent* /*event*/, bool)
1277 RouteTimeAxisView* tv;
1280 if (!check_possible (&tv, &layer)) {
1286 if (_current_pointer_x - _grab_x > 0) {
1292 RegionSelection copy (_editor->selection->regions);
1294 RegionSelectionByPosition cmp;
1297 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1299 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1305 boost::shared_ptr<Playlist> playlist;
1307 if ((playlist = atv->playlist()) == 0) {
1311 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1316 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1320 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1326 playlist->shuffle ((*i)->region(), dir);
1328 _grab_x = _current_pointer_x;
1333 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1339 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1347 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1349 _dest_trackview = _view;
1351 Drag::start_grab (event);
1356 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1359 // TODO: create region-create-drag region view here
1362 // TODO: resize region-create-drag region view here
1366 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1368 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1373 const boost::shared_ptr<MidiDiskstream> diskstream =
1374 boost::dynamic_pointer_cast<MidiDiskstream>(mtv->view()->trackview().track()->diskstream());
1377 warning << "Cannot create non-MIDI region" << endl;
1381 if (!movement_occurred) {
1382 _editor->begin_reversible_command (_("create region"));
1383 XMLNode &before = mtv->playlist()->get_state();
1385 nframes64_t start = _grab_frame;
1386 _editor->snap_to (start, -1);
1387 const Meter& m = _editor->session->tempo_map().meter_at(start);
1388 const Tempo& t = _editor->session->tempo_map().tempo_at(start);
1389 double length = floor (m.frames_per_bar(t, _editor->session->frame_rate()));
1391 boost::shared_ptr<Source> src = _editor->session->create_midi_source_for_session(*diskstream.get());
1393 mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>
1394 (RegionFactory::create(src, 0, (nframes_t) length,
1395 PBD::basename_nosuffix(src->name()))), start);
1396 XMLNode &after = mtv->playlist()->get_state();
1397 _editor->session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
1398 _editor->commit_reversible_command();
1401 motion (event, false);
1402 // TODO: create region-create-drag region here
1410 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1416 RegionGainDrag::finished (GdkEvent *, bool)
1421 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1422 : RegionDrag (e, i, p, v)
1428 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1431 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1432 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1434 if (tv && tv->is_track()) {
1435 speed = tv->get_diskstream()->speed();
1438 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1439 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1440 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1442 Drag::start_grab (event, _editor->trimmer_cursor);
1444 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1445 _operation = ContentsTrim;
1447 /* These will get overridden for a point trim.*/
1448 if (_current_pointer_frame < (region_start + region_length/2)) {
1449 /* closer to start */
1450 _operation = StartTrim;
1451 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1453 _operation = EndTrim;
1457 switch (_operation) {
1459 _editor->show_verbose_time_cursor (region_start, 10);
1462 _editor->show_verbose_time_cursor (region_end, 10);
1465 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1471 TrimDrag::motion (GdkEvent* event, bool first_move)
1473 RegionView* rv = _primary;
1474 nframes64_t frame_delta = 0;
1476 bool left_direction;
1477 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1479 /* snap modifier works differently here..
1480 its' current state has to be passed to the
1481 various trim functions in order to work properly
1485 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1486 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1487 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1489 if (tv && tv->is_track()) {
1490 speed = tv->get_diskstream()->speed();
1493 if (_last_pointer_frame > _current_pointer_frame) {
1494 left_direction = true;
1496 left_direction = false;
1499 _editor->snap_to_with_modifier (_current_pointer_frame, event);
1505 switch (_operation) {
1507 trim_type = "Region start trim";
1510 trim_type = "Region end trim";
1513 trim_type = "Region content trim";
1517 _editor->begin_reversible_command (trim_type);
1519 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1520 (*i)->fake_set_opaque(false);
1521 (*i)->region()->freeze ();
1523 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1526 arv->temporarily_hide_envelope ();
1529 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1530 insert_result = _editor->motion_frozen_playlists.insert (pl);
1532 if (insert_result.second) {
1533 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1539 if (_current_pointer_frame == _last_pointer_frame) {
1543 if (left_direction) {
1544 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1546 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1549 bool non_overlap_trim = false;
1551 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1552 non_overlap_trim = true;
1555 switch (_operation) {
1557 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1561 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1562 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1568 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1572 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1573 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1580 bool swap_direction = false;
1582 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1583 swap_direction = true;
1586 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1588 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1594 switch (_operation) {
1596 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1599 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1602 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1606 _last_pointer_frame = _current_pointer_frame;
1611 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1613 if (movement_occurred) {
1614 motion (event, false);
1616 if (!_editor->selection->selected (_primary)) {
1617 _editor->thaw_region_after_trim (*_primary);
1620 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1621 _editor->thaw_region_after_trim (**i);
1622 (*i)->fake_set_opaque (true);
1626 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1628 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1631 _editor->motion_frozen_playlists.clear ();
1633 _editor->commit_reversible_command();
1635 /* no mouse movement */
1636 _editor->point_trim (event);
1640 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1644 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1649 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1652 // create a dummy marker for visual representation of moving the copy.
1653 // The actual copying is not done before we reach the finish callback.
1655 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1656 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1657 *new MeterSection (_marker->meter()));
1659 _item = &new_marker->the_item ();
1660 _marker = new_marker;
1664 MetricSection& section (_marker->meter());
1666 if (!section.movable()) {
1672 Drag::start_grab (event, cursor);
1674 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1676 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1680 MeterMarkerDrag::motion (GdkEvent* event, bool)
1682 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1684 if (adjusted_frame == _last_pointer_frame) {
1688 _marker->set_position (adjusted_frame);
1690 _last_pointer_frame = adjusted_frame;
1692 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1696 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1698 if (!movement_occurred) {
1702 motion (event, false);
1706 TempoMap& map (_editor->session->tempo_map());
1707 map.bbt_time (_last_pointer_frame, when);
1709 if (_copy == true) {
1710 _editor->begin_reversible_command (_("copy meter mark"));
1711 XMLNode &before = map.get_state();
1712 map.add_meter (_marker->meter(), when);
1713 XMLNode &after = map.get_state();
1714 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1715 _editor->commit_reversible_command ();
1717 // delete the dummy marker we used for visual representation of copying.
1718 // a new visual marker will show up automatically.
1721 _editor->begin_reversible_command (_("move meter mark"));
1722 XMLNode &before = map.get_state();
1723 map.move_meter (_marker->meter(), when);
1724 XMLNode &after = map.get_state();
1725 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1726 _editor->commit_reversible_command ();
1730 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1734 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1739 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1744 // create a dummy marker for visual representation of moving the copy.
1745 // The actual copying is not done before we reach the finish callback.
1747 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1748 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1749 *new TempoSection (_marker->tempo()));
1751 _item = &new_marker->the_item ();
1752 _marker = new_marker;
1756 MetricSection& section (_marker->tempo());
1758 if (!section.movable()) {
1763 Drag::start_grab (event, cursor);
1765 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1766 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1770 TempoMarkerDrag::motion (GdkEvent* event, bool)
1772 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1774 if (adjusted_frame == _last_pointer_frame) {
1778 /* OK, we've moved far enough to make it worth actually move the thing. */
1780 _marker->set_position (adjusted_frame);
1782 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1784 _last_pointer_frame = adjusted_frame;
1788 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1790 if (!movement_occurred) {
1794 motion (event, false);
1798 TempoMap& map (_editor->session->tempo_map());
1799 map.bbt_time (_last_pointer_frame, when);
1801 if (_copy == true) {
1802 _editor->begin_reversible_command (_("copy tempo mark"));
1803 XMLNode &before = map.get_state();
1804 map.add_tempo (_marker->tempo(), when);
1805 XMLNode &after = map.get_state();
1806 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1807 _editor->commit_reversible_command ();
1809 // delete the dummy marker we used for visual representation of copying.
1810 // a new visual marker will show up automatically.
1813 _editor->begin_reversible_command (_("move tempo mark"));
1814 XMLNode &before = map.get_state();
1815 map.move_tempo (_marker->tempo(), when);
1816 XMLNode &after = map.get_state();
1817 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1818 _editor->commit_reversible_command ();
1823 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1827 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1832 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1834 Drag::start_grab (event, c);
1838 nframes64_t where = _editor->event_frame (event, 0, 0);
1840 _editor->snap_to_with_modifier (where, event);
1841 _editor->playhead_cursor->set_position (where);
1845 if (_cursor == _editor->playhead_cursor) {
1846 _editor->_dragging_playhead = true;
1848 if (_editor->session && _was_rolling && _stop) {
1849 _editor->session->request_stop ();
1852 if (_editor->session && _editor->session->is_auditioning()) {
1853 _editor->session->cancel_audition ();
1857 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1861 CursorDrag::motion (GdkEvent* event, bool)
1863 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1865 if (adjusted_frame == _last_pointer_frame) {
1869 _cursor->set_position (adjusted_frame);
1871 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1874 _editor->update_canvas_now ();
1876 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1878 _last_pointer_frame = adjusted_frame;
1882 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1884 _editor->_dragging_playhead = false;
1886 if (!movement_occurred && _stop) {
1890 motion (event, false);
1892 if (_item == &_editor->playhead_cursor->canvas_item) {
1893 if (_editor->session) {
1894 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1895 _editor->_pending_locate_request = true;
1900 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1901 : RegionDrag (e, i, p, v)
1907 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1909 Drag::start_grab (event, cursor);
1911 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1912 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1914 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1918 FadeInDrag::motion (GdkEvent* event, bool)
1920 nframes64_t fade_length;
1922 nframes64_t const pos = adjusted_current_frame (event);
1924 boost::shared_ptr<Region> region = _primary->region ();
1926 if (pos < (region->position() + 64)) {
1927 fade_length = 64; // this should be a minimum defined somewhere
1928 } else if (pos > region->last_frame()) {
1929 fade_length = region->length();
1931 fade_length = pos - region->position();
1934 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1936 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1942 tmp->reset_fade_in_shape_width (fade_length);
1945 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1949 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1951 if (!movement_occurred) {
1955 nframes64_t fade_length;
1957 nframes64_t const pos = adjusted_current_frame (event);
1959 boost::shared_ptr<Region> region = _primary->region ();
1961 if (pos < (region->position() + 64)) {
1962 fade_length = 64; // this should be a minimum defined somewhere
1963 } else if (pos > region->last_frame()) {
1964 fade_length = region->length();
1966 fade_length = pos - region->position();
1969 _editor->begin_reversible_command (_("change fade in length"));
1971 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1973 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1979 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
1980 XMLNode &before = alist->get_state();
1982 tmp->audio_region()->set_fade_in_length (fade_length);
1983 tmp->audio_region()->set_fade_in_active (true);
1985 XMLNode &after = alist->get_state();
1986 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
1989 _editor->commit_reversible_command ();
1992 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1993 : RegionDrag (e, i, p, v)
1999 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2001 Drag::start_grab (event, cursor);
2003 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2004 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2006 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2010 FadeOutDrag::motion (GdkEvent* event, bool)
2012 nframes64_t fade_length;
2014 nframes64_t const pos = adjusted_current_frame (event);
2016 boost::shared_ptr<Region> region = _primary->region ();
2018 if (pos > (region->last_frame() - 64)) {
2019 fade_length = 64; // this should really be a minimum fade defined somewhere
2021 else if (pos < region->position()) {
2022 fade_length = region->length();
2025 fade_length = region->last_frame() - pos;
2028 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2030 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2036 tmp->reset_fade_out_shape_width (fade_length);
2039 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2043 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2045 if (!movement_occurred) {
2049 nframes64_t fade_length;
2051 nframes64_t const pos = adjusted_current_frame (event);
2053 boost::shared_ptr<Region> region = _primary->region ();
2055 if (pos > (region->last_frame() - 64)) {
2056 fade_length = 64; // this should really be a minimum fade defined somewhere
2058 else if (pos < region->position()) {
2059 fade_length = region->length();
2062 fade_length = region->last_frame() - pos;
2065 _editor->begin_reversible_command (_("change fade out length"));
2067 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2069 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2075 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2076 XMLNode &before = alist->get_state();
2078 tmp->audio_region()->set_fade_out_length (fade_length);
2079 tmp->audio_region()->set_fade_out_active (true);
2081 XMLNode &after = alist->get_state();
2082 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2085 _editor->commit_reversible_command ();
2088 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2091 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2094 _points.push_back (Gnome::Art::Point (0, 0));
2095 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2097 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2098 _line->property_width_pixels() = 1;
2099 _line->property_points () = _points;
2102 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2105 MarkerDrag::~MarkerDrag ()
2107 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2113 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2115 Drag::start_grab (event, cursor);
2119 Location *location = _editor->find_location_from_marker (_marker, is_start);
2120 _editor->_dragging_edit_point = true;
2122 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2124 update_item (location);
2126 // _drag_line->show();
2127 // _line->raise_to_top();
2130 _editor->show_verbose_time_cursor (location->start(), 10);
2132 _editor->show_verbose_time_cursor (location->end(), 10);
2135 Selection::Operation op = Keyboard::selection_type (event->button.state);
2138 case Selection::Toggle:
2139 _editor->selection->toggle (_marker);
2141 case Selection::Set:
2142 if (!_editor->selection->selected (_marker)) {
2143 _editor->selection->set (_marker);
2146 case Selection::Extend:
2148 Locations::LocationList ll;
2149 list<Marker*> to_add;
2151 _editor->selection->markers.range (s, e);
2152 s = min (_marker->position(), s);
2153 e = max (_marker->position(), e);
2156 if (e < max_frames) {
2159 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2160 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2161 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2164 to_add.push_back (lm->start);
2167 to_add.push_back (lm->end);
2171 if (!to_add.empty()) {
2172 _editor->selection->add (to_add);
2176 case Selection::Add:
2177 _editor->selection->add (_marker);
2181 /* set up copies for us to manipulate during the drag */
2183 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2184 Location *l = _editor->find_location_from_marker (*i, is_start);
2185 _copied_locations.push_back (new Location (*l));
2190 MarkerDrag::motion (GdkEvent* event, bool)
2192 nframes64_t f_delta = 0;
2194 bool move_both = false;
2196 Location *real_location;
2197 Location *copy_location = 0;
2199 nframes64_t const newframe = adjusted_current_frame (event);
2201 nframes64_t next = newframe;
2203 if (_current_pointer_frame == _last_pointer_frame) {
2207 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2211 MarkerSelection::iterator i;
2212 list<Location*>::iterator x;
2214 /* find the marker we're dragging, and compute the delta */
2216 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2217 x != _copied_locations.end() && i != _editor->selection->markers.end();
2223 if (marker == _marker) {
2225 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2230 if (real_location->is_mark()) {
2231 f_delta = newframe - copy_location->start();
2235 switch (marker->type()) {
2237 case Marker::LoopStart:
2238 case Marker::PunchIn:
2239 f_delta = newframe - copy_location->start();
2243 case Marker::LoopEnd:
2244 case Marker::PunchOut:
2245 f_delta = newframe - copy_location->end();
2248 /* what kind of marker is this ? */
2256 if (i == _editor->selection->markers.end()) {
2257 /* hmm, impossible - we didn't find the dragged marker */
2261 /* now move them all */
2263 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2264 x != _copied_locations.end() && i != _editor->selection->markers.end();
2270 /* call this to find out if its the start or end */
2272 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2276 if (real_location->locked()) {
2280 if (copy_location->is_mark()) {
2284 copy_location->set_start (copy_location->start() + f_delta);
2288 nframes64_t new_start = copy_location->start() + f_delta;
2289 nframes64_t new_end = copy_location->end() + f_delta;
2291 if (is_start) { // start-of-range marker
2294 copy_location->set_start (new_start);
2295 copy_location->set_end (new_end);
2296 } else if (new_start < copy_location->end()) {
2297 copy_location->set_start (new_start);
2299 _editor->snap_to (next, 1, true);
2300 copy_location->set_end (next);
2301 copy_location->set_start (newframe);
2304 } else { // end marker
2307 copy_location->set_end (new_end);
2308 copy_location->set_start (new_start);
2309 } else if (new_end > copy_location->start()) {
2310 copy_location->set_end (new_end);
2311 } else if (newframe > 0) {
2312 _editor->snap_to (next, -1, true);
2313 copy_location->set_start (next);
2314 copy_location->set_end (newframe);
2319 update_item (copy_location);
2321 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2324 lm->set_position (copy_location->start(), copy_location->end());
2328 _last_pointer_frame = _current_pointer_frame;
2330 assert (!_copied_locations.empty());
2332 _editor->edit_point_clock.set (_copied_locations.front()->start());
2333 _editor->show_verbose_time_cursor (newframe, 10);
2336 _editor->update_canvas_now ();
2338 _editor->edit_point_clock.set (copy_location->start());
2342 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2344 if (!movement_occurred) {
2346 /* just a click, do nothing but finish
2347 off the selection process
2350 Selection::Operation op = Keyboard::selection_type (event->button.state);
2353 case Selection::Set:
2354 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2355 _editor->selection->set (_marker);
2359 case Selection::Toggle:
2360 case Selection::Extend:
2361 case Selection::Add:
2368 _editor->_dragging_edit_point = false;
2370 _editor->begin_reversible_command ( _("move marker") );
2371 XMLNode &before = _editor->session->locations()->get_state();
2373 MarkerSelection::iterator i;
2374 list<Location*>::iterator x;
2377 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2378 x != _copied_locations.end() && i != _editor->selection->markers.end();
2381 Location * location = _editor->find_location_from_marker (*i, is_start);
2385 if (location->locked()) {
2389 if (location->is_mark()) {
2390 location->set_start ((*x)->start());
2392 location->set ((*x)->start(), (*x)->end());
2397 XMLNode &after = _editor->session->locations()->get_state();
2398 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
2399 _editor->commit_reversible_command ();
2405 MarkerDrag::update_item (Location* location)
2407 double const x1 = _editor->frame_to_pixel (location->start());
2409 _points.front().set_x(x1);
2410 _points.back().set_x(x1);
2411 _line->property_points() = _points;
2414 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2416 _cumulative_x_drag (0),
2417 _cumulative_y_drag (0)
2419 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2425 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2427 Drag::start_grab (event, _editor->fader_cursor);
2429 // start the grab at the center of the control point so
2430 // the point doesn't 'jump' to the mouse after the first drag
2431 _grab_x = _point->get_x();
2432 _grab_y = _point->get_y();
2434 _point->line().parent_group().i2w (_grab_x, _grab_y);
2435 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2437 _grab_frame = _editor->pixel_to_frame (_grab_x);
2439 _point->line().start_drag (_point, _grab_frame, 0);
2441 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2442 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2443 _current_pointer_x + 10, _current_pointer_y + 10);
2445 _editor->show_verbose_canvas_cursor ();
2449 ControlPointDrag::motion (GdkEvent* event, bool)
2451 double dx = _current_pointer_x - _last_pointer_x;
2452 double dy = _current_pointer_y - _last_pointer_y;
2454 if (event->button.state & Keyboard::SecondaryModifier) {
2459 double cx = _grab_x + _cumulative_x_drag + dx;
2460 double cy = _grab_y + _cumulative_y_drag + dy;
2462 // calculate zero crossing point. back off by .01 to stay on the
2463 // positive side of zero
2465 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2466 _point->line().parent_group().i2w(_unused, zero_gain_y);
2468 // make sure we hit zero when passing through
2469 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2470 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2474 if (_x_constrained) {
2477 if (_y_constrained) {
2481 _cumulative_x_drag = cx - _grab_x;
2482 _cumulative_y_drag = cy - _grab_y;
2484 _point->line().parent_group().w2i (cx, cy);
2488 cy = min ((double) _point->line().height(), cy);
2490 //translate cx to frames
2491 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2493 if (!_x_constrained) {
2494 _editor->snap_to_with_modifier (cx_frames, event);
2497 float const fraction = 1.0 - (cy / _point->line().height());
2499 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2501 _point->line().point_drag (*_point, cx_frames, fraction, push);
2503 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2507 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2509 if (!movement_occurred) {
2513 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2514 _editor->reset_point_selection ();
2518 motion (event, false);
2520 _point->line().end_drag (_point);
2524 ControlPointDrag::active (Editing::MouseMode m)
2526 if (m == Editing::MouseGain) {
2527 /* always active in mouse gain */
2531 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2532 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2535 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2538 _cumulative_y_drag (0)
2543 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2545 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2548 _item = &_line->grab_item ();
2550 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2551 origin, and ditto for y.
2554 double cx = event->button.x;
2555 double cy = event->button.y;
2557 _line->parent_group().w2i (cx, cy);
2559 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2561 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2562 /* no adjacent points */
2566 Drag::start_grab (event, _editor->fader_cursor);
2568 /* store grab start in parent frame */
2573 double fraction = 1.0 - (cy / _line->height());
2575 _line->start_drag (0, _grab_frame, fraction);
2577 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2578 _current_pointer_x + 10, _current_pointer_y + 10);
2580 _editor->show_verbose_canvas_cursor ();
2584 LineDrag::motion (GdkEvent* event, bool)
2586 double dy = _current_pointer_y - _last_pointer_y;
2588 if (event->button.state & Keyboard::SecondaryModifier) {
2592 double cy = _grab_y + _cumulative_y_drag + dy;
2594 _cumulative_y_drag = cy - _grab_y;
2597 cy = min ((double) _line->height(), cy);
2599 double const fraction = 1.0 - (cy / _line->height());
2603 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2609 _line->line_drag (_before, _after, fraction, push);
2611 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2615 LineDrag::finished (GdkEvent* event, bool)
2617 motion (event, false);
2618 _line->end_drag (0);
2622 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2624 Drag::start_grab (event);
2625 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2629 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2636 /* use a bigger drag threshold than the default */
2638 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2642 if (Config->get_rubberbanding_snaps_to_grid()) {
2644 _editor->snap_to_with_modifier (_grab_frame, event);
2646 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2649 /* base start and end on initial click position */
2651 if (_current_pointer_frame < _grab_frame) {
2652 start = _current_pointer_frame;
2655 end = _current_pointer_frame;
2656 start = _grab_frame;
2659 if (_current_pointer_y < _grab_y) {
2660 y1 = _current_pointer_y;
2663 y2 = _current_pointer_y;
2668 if (start != end || y1 != y2) {
2670 double x1 = _editor->frame_to_pixel (start);
2671 double x2 = _editor->frame_to_pixel (end);
2673 _editor->rubberband_rect->property_x1() = x1;
2674 _editor->rubberband_rect->property_y1() = y1;
2675 _editor->rubberband_rect->property_x2() = x2;
2676 _editor->rubberband_rect->property_y2() = y2;
2678 _editor->rubberband_rect->show();
2679 _editor->rubberband_rect->raise_to_top();
2681 _last_pointer_frame = _current_pointer_frame;
2683 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2688 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2690 if (movement_occurred) {
2692 motion (event, false);
2695 if (_current_pointer_y < _grab_y) {
2696 y1 = _current_pointer_y;
2699 y2 = _current_pointer_y;
2704 Selection::Operation op = Keyboard::selection_type (event->button.state);
2707 _editor->begin_reversible_command (_("rubberband selection"));
2709 if (_grab_frame < _last_pointer_frame) {
2710 committed = _editor->select_all_within (_grab_frame, _last_pointer_frame - 1, y1, y2, _editor->track_views, op);
2712 committed = _editor->select_all_within (_last_pointer_frame, _grab_frame - 1, y1, y2, _editor->track_views, op);
2716 _editor->commit_reversible_command ();
2720 if (!getenv("ARDOUR_SAE")) {
2721 _editor->selection->clear_tracks();
2723 _editor->selection->clear_regions();
2724 _editor->selection->clear_points ();
2725 _editor->selection->clear_lines ();
2728 _editor->rubberband_rect->hide();
2732 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2734 Drag::start_grab (event);
2736 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2740 TimeFXDrag::motion (GdkEvent* event, bool)
2742 RegionView* rv = _primary;
2744 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2746 if (_current_pointer_frame == _last_pointer_frame) {
2750 if (_current_pointer_frame > rv->region()->position()) {
2751 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2754 _last_pointer_frame = _current_pointer_frame;
2756 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2760 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2762 _primary->get_time_axis_view().hide_timestretch ();
2764 if (!movement_occurred) {
2768 if (_last_pointer_frame < _primary->region()->position()) {
2769 /* backwards drag of the left edge - not usable */
2773 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2775 float percentage = (double) newlen / (double) _primary->region()->length();
2777 #ifndef USE_RUBBERBAND
2778 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2779 if (_primary->region()->data_type() == DataType::AUDIO) {
2780 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2784 _editor->begin_reversible_command (_("timestretch"));
2786 // XXX how do timeFX on multiple regions ?
2791 if (_editor->time_stretch (rs, percentage) == 0) {
2792 _editor->session->commit_reversible_command ();
2797 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2799 Drag::start_grab (event);
2803 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2809 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2811 if (movement_occurred && _editor->session) {
2812 /* make sure we stop */
2813 _editor->session->request_transport_speed (0.0);
2817 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2826 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2828 nframes64_t start = 0;
2829 nframes64_t end = 0;
2831 if (_editor->session == 0) {
2835 Gdk::Cursor* cursor = 0;
2837 switch (_operation) {
2838 case CreateSelection:
2839 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2844 cursor = _editor->selector_cursor;
2845 Drag::start_grab (event, cursor);
2848 case SelectionStartTrim:
2849 if (_editor->clicked_axisview) {
2850 _editor->clicked_axisview->order_selection_trims (_item, true);
2852 Drag::start_grab (event, cursor);
2853 cursor = _editor->trimmer_cursor;
2854 start = _editor->selection->time[_editor->clicked_selection].start;
2855 _pointer_frame_offset = _grab_frame - start;
2858 case SelectionEndTrim:
2859 if (_editor->clicked_axisview) {
2860 _editor->clicked_axisview->order_selection_trims (_item, false);
2862 Drag::start_grab (event, cursor);
2863 cursor = _editor->trimmer_cursor;
2864 end = _editor->selection->time[_editor->clicked_selection].end;
2865 _pointer_frame_offset = _grab_frame - end;
2869 start = _editor->selection->time[_editor->clicked_selection].start;
2870 Drag::start_grab (event, cursor);
2871 _pointer_frame_offset = _grab_frame - start;
2875 if (_operation == SelectionMove) {
2876 _editor->show_verbose_time_cursor (start, 10);
2878 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2883 SelectionDrag::motion (GdkEvent* event, bool first_move)
2885 nframes64_t start = 0;
2886 nframes64_t end = 0;
2889 nframes64_t const pending_position = adjusted_current_frame (event);
2891 /* only alter selection if the current frame is
2892 different from the last frame position (adjusted)
2895 if (pending_position == _last_pointer_frame) {
2899 switch (_operation) {
2900 case CreateSelection:
2903 _editor->snap_to (_grab_frame);
2906 if (pending_position < _grab_frame) {
2907 start = pending_position;
2910 end = pending_position;
2911 start = _grab_frame;
2914 /* first drag: Either add to the selection
2915 or create a new selection->
2920 _editor->begin_reversible_command (_("range selection"));
2923 /* adding to the selection */
2924 _editor->clicked_selection = _editor->selection->add (start, end);
2927 /* new selection-> */
2928 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2933 case SelectionStartTrim:
2936 _editor->begin_reversible_command (_("trim selection start"));
2939 start = _editor->selection->time[_editor->clicked_selection].start;
2940 end = _editor->selection->time[_editor->clicked_selection].end;
2942 if (pending_position > end) {
2945 start = pending_position;
2949 case SelectionEndTrim:
2952 _editor->begin_reversible_command (_("trim selection end"));
2955 start = _editor->selection->time[_editor->clicked_selection].start;
2956 end = _editor->selection->time[_editor->clicked_selection].end;
2958 if (pending_position < start) {
2961 end = pending_position;
2969 _editor->begin_reversible_command (_("move selection"));
2972 start = _editor->selection->time[_editor->clicked_selection].start;
2973 end = _editor->selection->time[_editor->clicked_selection].end;
2975 length = end - start;
2977 start = pending_position;
2978 _editor->snap_to (start);
2980 end = start + length;
2985 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
2986 _editor->start_canvas_autoscroll (1, 0);
2990 _editor->selection->replace (_editor->clicked_selection, start, end);
2993 _last_pointer_frame = pending_position;
2995 if (_operation == SelectionMove) {
2996 _editor->show_verbose_time_cursor(start, 10);
2998 _editor->show_verbose_time_cursor(pending_position, 10);
3003 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3005 if (movement_occurred) {
3006 motion (event, false);
3007 /* XXX this is not object-oriented programming at all. ick */
3008 if (_editor->selection->time.consolidate()) {
3009 _editor->selection->TimeChanged ();
3011 _editor->commit_reversible_command ();
3013 /* just a click, no pointer movement.*/
3015 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3017 _editor->selection->clear_time();
3022 /* XXX what happens if its a music selection? */
3023 _editor->session->set_audio_range (_editor->selection->time);
3024 _editor->stop_canvas_autoscroll ();
3027 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3032 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3033 _drag_rect->hide ();
3035 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3036 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3040 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3042 if (_editor->session == 0) {
3046 Gdk::Cursor* cursor = 0;
3048 if (!_editor->temp_location) {
3049 _editor->temp_location = new Location;
3052 switch (_operation) {
3053 case CreateRangeMarker:
3054 case CreateTransportMarker:
3055 case CreateCDMarker:
3057 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3062 cursor = _editor->selector_cursor;
3066 Drag::start_grab (event, cursor);
3068 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3072 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3074 nframes64_t start = 0;
3075 nframes64_t end = 0;
3076 ArdourCanvas::SimpleRect *crect;
3078 switch (_operation) {
3079 case CreateRangeMarker:
3080 crect = _editor->range_bar_drag_rect;
3082 case CreateTransportMarker:
3083 crect = _editor->transport_bar_drag_rect;
3085 case CreateCDMarker:
3086 crect = _editor->cd_marker_bar_drag_rect;
3089 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3094 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3096 /* only alter selection if the current frame is
3097 different from the last frame position.
3100 if (_current_pointer_frame == _last_pointer_frame) {
3104 switch (_operation) {
3105 case CreateRangeMarker:
3106 case CreateTransportMarker:
3107 case CreateCDMarker:
3109 _editor->snap_to (_grab_frame);
3112 if (_current_pointer_frame < _grab_frame) {
3113 start = _current_pointer_frame;
3116 end = _current_pointer_frame;
3117 start = _grab_frame;
3120 /* first drag: Either add to the selection
3121 or create a new selection.
3126 _editor->temp_location->set (start, end);
3130 update_item (_editor->temp_location);
3132 //_drag_rect->raise_to_top();
3138 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3139 _editor->start_canvas_autoscroll (1, 0);
3143 _editor->temp_location->set (start, end);
3145 double x1 = _editor->frame_to_pixel (start);
3146 double x2 = _editor->frame_to_pixel (end);
3147 crect->property_x1() = x1;
3148 crect->property_x2() = x2;
3150 update_item (_editor->temp_location);
3153 _last_pointer_frame = _current_pointer_frame;
3155 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3160 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3162 Location * newloc = 0;
3166 if (movement_occurred) {
3167 motion (event, false);
3170 switch (_operation) {
3171 case CreateRangeMarker:
3172 case CreateCDMarker:
3174 _editor->begin_reversible_command (_("new range marker"));
3175 XMLNode &before = _editor->session->locations()->get_state();
3176 _editor->session->locations()->next_available_name(rangename,"unnamed");
3177 if (_operation == CreateCDMarker) {
3178 flags = Location::IsRangeMarker | Location::IsCDMarker;
3179 _editor->cd_marker_bar_drag_rect->hide();
3182 flags = Location::IsRangeMarker;
3183 _editor->range_bar_drag_rect->hide();
3185 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3186 _editor->session->locations()->add (newloc, true);
3187 XMLNode &after = _editor->session->locations()->get_state();
3188 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3189 _editor->commit_reversible_command ();
3193 case CreateTransportMarker:
3194 // popup menu to pick loop or punch
3195 _editor->new_transport_marker_context_menu (&event->button, _item);
3199 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3201 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3206 start = _editor->session->locations()->first_mark_before (_grab_frame);
3207 end = _editor->session->locations()->first_mark_after (_grab_frame);
3209 if (end == max_frames) {
3210 end = _editor->session->current_end_frame ();
3214 start = _editor->session->current_start_frame ();
3217 switch (_editor->mouse_mode) {
3219 /* find the two markers on either side and then make the selection from it */
3220 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3224 /* find the two markers on either side of the click and make the range out of it */
3225 _editor->selection->set (0, start, end);
3234 _editor->stop_canvas_autoscroll ();
3240 RangeMarkerBarDrag::update_item (Location* location)
3242 double const x1 = _editor->frame_to_pixel (location->start());
3243 double const x2 = _editor->frame_to_pixel (location->end());
3245 _drag_rect->property_x1() = x1;
3246 _drag_rect->property_x2() = x2;
3250 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3252 Drag::start_grab (event, _editor->zoom_cursor);
3253 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3257 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3262 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3265 _editor->snap_to_with_modifier (_grab_frame, event);
3268 if (_current_pointer_frame == _last_pointer_frame) {
3272 /* base start and end on initial click position */
3273 if (_current_pointer_frame < _grab_frame) {
3274 start = _current_pointer_frame;
3277 end = _current_pointer_frame;
3278 start = _grab_frame;
3284 _editor->zoom_rect->show();
3285 _editor->zoom_rect->raise_to_top();
3288 _editor->reposition_zoom_rect(start, end);
3290 _last_pointer_frame = _current_pointer_frame;
3292 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3297 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3299 if (movement_occurred) {
3300 motion (event, false);
3302 if (_grab_frame < _last_pointer_frame) {
3303 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3305 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3308 _editor->temporal_zoom_to_frame (false, _grab_frame);
3310 temporal_zoom_step (false);
3311 center_screen (_grab_frame);
3315 _editor->zoom_rect->hide();