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 RegionSelection 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*, pair<RouteTimeAxisView*, int> > 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_and_layers ();
786 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
788 RegionView* rv = (*i);
789 RouteTimeAxisView* dest_rtv = final[*i].first;
790 layer_t dest_layer = final[*i].second;
794 if (rv->region()->locked()) {
799 if (changed_position && !_x_constrained) {
800 where = rv->region()->position() - drag_delta;
802 where = rv->region()->position();
805 boost::shared_ptr<Region> new_region;
808 /* we already made a copy */
809 new_region = rv->region();
811 /* undo the previous hide_dependent_views so that xfades don't
812 disappear on copying regions
815 //rv->get_time_axis_view().reveal_dependent_views (*rv);
817 } else if (changed_tracks && dest_rtv->playlist()) {
818 new_region = RegionFactory::create (rv->region());
821 if (changed_tracks || _copy) {
823 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
830 _editor->latest_regionviews.clear ();
832 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
834 insert_result = modified_playlists.insert (to_playlist);
836 if (insert_result.second) {
837 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
840 to_playlist->add_region (new_region, where);
841 if (dest_rtv->view()->layer_display() == Stacked) {
842 new_region->set_layer (dest_layer);
843 new_region->set_pending_explicit_relayer (true);
848 if (!_editor->latest_regionviews.empty()) {
849 // XXX why just the first one ? we only expect one
850 // commented out in nick_m's canvas reworking. is that intended?
851 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
852 new_views.push_back (_editor->latest_regionviews.front());
857 motion on the same track. plonk the previously reparented region
858 back to its original canvas group (its streamview).
859 No need to do anything for copies as they are fake regions which will be deleted.
862 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
863 rv->get_canvas_group()->property_y() = 0;
865 /* just change the model */
867 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
869 if (dest_rtv->view()->layer_display() == Stacked) {
870 rv->region()->set_layer (dest_layer);
871 rv->region()->set_pending_explicit_relayer (true);
874 insert_result = modified_playlists.insert (playlist);
876 if (insert_result.second) {
877 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
879 /* freeze to avoid lots of relayering in the case of a multi-region drag */
880 frozen_insert_result = frozen_playlists.insert(playlist);
882 if (frozen_insert_result.second) {
886 rv->region()->set_position (where, (void*) this);
889 if (changed_tracks && !_copy) {
891 /* get the playlist where this drag started. we can't use rv->region()->playlist()
892 because we may have copied the region and it has not been attached to a playlist.
895 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
896 ds = source_tv->get_diskstream();
897 from_playlist = ds->playlist();
901 assert (from_playlist);
903 /* moved to a different audio track, without copying */
905 /* the region that used to be in the old playlist is not
906 moved to the new one - we use a copy of it. as a result,
907 any existing editor for the region should no longer be
911 rv->hide_region_editor();
912 rv->fake_set_opaque (false);
914 /* remove the region from the old playlist */
916 insert_result = modified_playlists.insert (from_playlist);
918 if (insert_result.second) {
919 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
922 from_playlist->remove_region (rv->region());
924 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
925 was selected in all of them, then removing it from a playlist will have removed all
926 trace of it from the selection (i.e. there were N regions selected, we removed 1,
927 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
928 corresponding regionview, and the selection is now empty).
930 this could have invalidated any and all iterators into the region selection.
932 the heuristic we use here is: if the region selection is empty, break out of the loop
933 here. if the region selection is not empty, then restart the loop because we know that
934 we must have removed at least the region(view) we've just been working on as well as any
935 that we processed on previous iterations.
937 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
941 if (_views.empty()) {
952 copies.push_back (rv);
956 _editor->selection->add (new_views);
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*, pair<RouteTimeAxisView*, int> >
1218 RegionMotionDrag::find_time_axis_views_and_layers ()
1220 map<RegionView*, pair<RouteTimeAxisView*, int> > 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] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1238 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1240 _editor->update_canvas_now ();
1242 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1244 RouteTimeAxisView* dest_rtv = final[_primary].first;
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);
1374 if (!movement_occurred) {
1375 mtv->add_region (_grab_frame);
1377 motion (event, false);
1378 // TODO: create region-create-drag region here
1383 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1389 RegionGainDrag::finished (GdkEvent *, bool)
1394 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1395 : RegionDrag (e, i, p, v)
1401 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1404 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1405 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1407 if (tv && tv->is_track()) {
1408 speed = tv->get_diskstream()->speed();
1411 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1412 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1413 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1415 Drag::start_grab (event, _editor->trimmer_cursor);
1417 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1418 _operation = ContentsTrim;
1420 /* These will get overridden for a point trim.*/
1421 if (_current_pointer_frame < (region_start + region_length/2)) {
1422 /* closer to start */
1423 _operation = StartTrim;
1424 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1426 _operation = EndTrim;
1430 switch (_operation) {
1432 _editor->show_verbose_time_cursor (region_start, 10);
1435 _editor->show_verbose_time_cursor (region_end, 10);
1438 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1444 TrimDrag::motion (GdkEvent* event, bool first_move)
1446 RegionView* rv = _primary;
1447 nframes64_t frame_delta = 0;
1449 bool left_direction;
1450 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1452 /* snap modifier works differently here..
1453 its' current state has to be passed to the
1454 various trim functions in order to work properly
1458 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1459 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1460 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1462 if (tv && tv->is_track()) {
1463 speed = tv->get_diskstream()->speed();
1466 if (_last_pointer_frame > _current_pointer_frame) {
1467 left_direction = true;
1469 left_direction = false;
1472 _editor->snap_to_with_modifier (_current_pointer_frame, event);
1478 switch (_operation) {
1480 trim_type = "Region start trim";
1483 trim_type = "Region end trim";
1486 trim_type = "Region content trim";
1490 _editor->begin_reversible_command (trim_type);
1492 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1493 (*i)->fake_set_opaque(false);
1494 (*i)->region()->freeze ();
1496 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1499 arv->temporarily_hide_envelope ();
1502 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1503 insert_result = _editor->motion_frozen_playlists.insert (pl);
1505 if (insert_result.second) {
1506 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1512 if (_current_pointer_frame == _last_pointer_frame) {
1516 if (left_direction) {
1517 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1519 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1522 bool non_overlap_trim = false;
1524 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1525 non_overlap_trim = true;
1528 switch (_operation) {
1530 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1534 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1535 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1541 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1545 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1546 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1553 bool swap_direction = false;
1555 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1556 swap_direction = true;
1559 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1561 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1567 switch (_operation) {
1569 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1572 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1575 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1579 _last_pointer_frame = _current_pointer_frame;
1584 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1586 if (movement_occurred) {
1587 motion (event, false);
1589 if (!_editor->selection->selected (_primary)) {
1590 _editor->thaw_region_after_trim (*_primary);
1593 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1594 _editor->thaw_region_after_trim (**i);
1595 (*i)->fake_set_opaque (true);
1599 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1601 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1604 _editor->motion_frozen_playlists.clear ();
1606 _editor->commit_reversible_command();
1608 /* no mouse movement */
1609 _editor->point_trim (event);
1613 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1617 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1622 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1625 // create a dummy marker for visual representation of moving the copy.
1626 // The actual copying is not done before we reach the finish callback.
1628 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1629 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1630 *new MeterSection (_marker->meter()));
1632 _item = &new_marker->the_item ();
1633 _marker = new_marker;
1637 MetricSection& section (_marker->meter());
1639 if (!section.movable()) {
1645 Drag::start_grab (event, cursor);
1647 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1649 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1653 MeterMarkerDrag::motion (GdkEvent* event, bool)
1655 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1657 if (adjusted_frame == _last_pointer_frame) {
1661 _marker->set_position (adjusted_frame);
1663 _last_pointer_frame = adjusted_frame;
1665 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1669 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1671 if (!movement_occurred) {
1675 motion (event, false);
1679 TempoMap& map (_editor->session->tempo_map());
1680 map.bbt_time (_last_pointer_frame, when);
1682 if (_copy == true) {
1683 _editor->begin_reversible_command (_("copy meter mark"));
1684 XMLNode &before = map.get_state();
1685 map.add_meter (_marker->meter(), when);
1686 XMLNode &after = map.get_state();
1687 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1688 _editor->commit_reversible_command ();
1690 // delete the dummy marker we used for visual representation of copying.
1691 // a new visual marker will show up automatically.
1694 _editor->begin_reversible_command (_("move meter mark"));
1695 XMLNode &before = map.get_state();
1696 map.move_meter (_marker->meter(), when);
1697 XMLNode &after = map.get_state();
1698 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1699 _editor->commit_reversible_command ();
1703 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1707 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1712 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1717 // create a dummy marker for visual representation of moving the copy.
1718 // The actual copying is not done before we reach the finish callback.
1720 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1721 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1722 *new TempoSection (_marker->tempo()));
1724 _item = &new_marker->the_item ();
1725 _marker = new_marker;
1729 MetricSection& section (_marker->tempo());
1731 if (!section.movable()) {
1736 Drag::start_grab (event, cursor);
1738 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1739 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1743 TempoMarkerDrag::motion (GdkEvent* event, bool)
1745 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1747 if (adjusted_frame == _last_pointer_frame) {
1751 /* OK, we've moved far enough to make it worth actually move the thing. */
1753 _marker->set_position (adjusted_frame);
1755 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1757 _last_pointer_frame = adjusted_frame;
1761 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1763 if (!movement_occurred) {
1767 motion (event, false);
1771 TempoMap& map (_editor->session->tempo_map());
1772 map.bbt_time (_last_pointer_frame, when);
1774 if (_copy == true) {
1775 _editor->begin_reversible_command (_("copy tempo mark"));
1776 XMLNode &before = map.get_state();
1777 map.add_tempo (_marker->tempo(), when);
1778 XMLNode &after = map.get_state();
1779 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1780 _editor->commit_reversible_command ();
1782 // delete the dummy marker we used for visual representation of copying.
1783 // a new visual marker will show up automatically.
1786 _editor->begin_reversible_command (_("move tempo mark"));
1787 XMLNode &before = map.get_state();
1788 map.move_tempo (_marker->tempo(), when);
1789 XMLNode &after = map.get_state();
1790 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1791 _editor->commit_reversible_command ();
1796 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1800 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1805 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1807 Drag::start_grab (event, c);
1811 nframes64_t where = _editor->event_frame (event, 0, 0);
1813 _editor->snap_to_with_modifier (where, event);
1814 _editor->playhead_cursor->set_position (where);
1818 if (_cursor == _editor->playhead_cursor) {
1819 _editor->_dragging_playhead = true;
1821 if (_editor->session && _was_rolling && _stop) {
1822 _editor->session->request_stop ();
1825 if (_editor->session && _editor->session->is_auditioning()) {
1826 _editor->session->cancel_audition ();
1830 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1834 CursorDrag::motion (GdkEvent* event, bool)
1836 nframes64_t const adjusted_frame = adjusted_current_frame (event);
1838 if (adjusted_frame == _last_pointer_frame) {
1842 _cursor->set_position (adjusted_frame);
1844 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1847 _editor->update_canvas_now ();
1849 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1851 _last_pointer_frame = adjusted_frame;
1855 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1857 _editor->_dragging_playhead = false;
1859 if (!movement_occurred && _stop) {
1863 motion (event, false);
1865 if (_item == &_editor->playhead_cursor->canvas_item) {
1866 if (_editor->session) {
1867 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1868 _editor->_pending_locate_request = true;
1873 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1874 : RegionDrag (e, i, p, v)
1880 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1882 Drag::start_grab (event, cursor);
1884 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1885 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1887 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1891 FadeInDrag::motion (GdkEvent* event, bool)
1893 nframes64_t fade_length;
1895 nframes64_t const pos = adjusted_current_frame (event);
1897 boost::shared_ptr<Region> region = _primary->region ();
1899 if (pos < (region->position() + 64)) {
1900 fade_length = 64; // this should be a minimum defined somewhere
1901 } else if (pos > region->last_frame()) {
1902 fade_length = region->length();
1904 fade_length = pos - region->position();
1907 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1909 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1915 tmp->reset_fade_in_shape_width (fade_length);
1918 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1922 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1924 if (!movement_occurred) {
1928 nframes64_t fade_length;
1930 nframes64_t const pos = adjusted_current_frame (event);
1932 boost::shared_ptr<Region> region = _primary->region ();
1934 if (pos < (region->position() + 64)) {
1935 fade_length = 64; // this should be a minimum defined somewhere
1936 } else if (pos > region->last_frame()) {
1937 fade_length = region->length();
1939 fade_length = pos - region->position();
1942 _editor->begin_reversible_command (_("change fade in length"));
1944 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1946 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1952 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
1953 XMLNode &before = alist->get_state();
1955 tmp->audio_region()->set_fade_in_length (fade_length);
1956 tmp->audio_region()->set_fade_in_active (true);
1958 XMLNode &after = alist->get_state();
1959 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
1962 _editor->commit_reversible_command ();
1965 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1966 : RegionDrag (e, i, p, v)
1972 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1974 Drag::start_grab (event, cursor);
1976 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1977 boost::shared_ptr<AudioRegion> r = a->audio_region ();
1979 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
1983 FadeOutDrag::motion (GdkEvent* event, bool)
1985 nframes64_t fade_length;
1987 nframes64_t const pos = adjusted_current_frame (event);
1989 boost::shared_ptr<Region> region = _primary->region ();
1991 if (pos > (region->last_frame() - 64)) {
1992 fade_length = 64; // this should really be a minimum fade defined somewhere
1994 else if (pos < region->position()) {
1995 fade_length = region->length();
1998 fade_length = region->last_frame() - pos;
2001 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2003 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2009 tmp->reset_fade_out_shape_width (fade_length);
2012 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2016 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2018 if (!movement_occurred) {
2022 nframes64_t fade_length;
2024 nframes64_t const pos = adjusted_current_frame (event);
2026 boost::shared_ptr<Region> region = _primary->region ();
2028 if (pos > (region->last_frame() - 64)) {
2029 fade_length = 64; // this should really be a minimum fade defined somewhere
2031 else if (pos < region->position()) {
2032 fade_length = region->length();
2035 fade_length = region->last_frame() - pos;
2038 _editor->begin_reversible_command (_("change fade out length"));
2040 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2042 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2048 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2049 XMLNode &before = alist->get_state();
2051 tmp->audio_region()->set_fade_out_length (fade_length);
2052 tmp->audio_region()->set_fade_out_active (true);
2054 XMLNode &after = alist->get_state();
2055 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2058 _editor->commit_reversible_command ();
2061 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2064 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2067 _points.push_back (Gnome::Art::Point (0, 0));
2068 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2070 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2071 _line->property_width_pixels() = 1;
2072 _line->property_points () = _points;
2075 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2078 MarkerDrag::~MarkerDrag ()
2080 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2086 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2088 Drag::start_grab (event, cursor);
2092 Location *location = _editor->find_location_from_marker (_marker, is_start);
2093 _editor->_dragging_edit_point = true;
2095 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2097 update_item (location);
2099 // _drag_line->show();
2100 // _line->raise_to_top();
2103 _editor->show_verbose_time_cursor (location->start(), 10);
2105 _editor->show_verbose_time_cursor (location->end(), 10);
2108 Selection::Operation op = Keyboard::selection_type (event->button.state);
2111 case Selection::Toggle:
2112 _editor->selection->toggle (_marker);
2114 case Selection::Set:
2115 if (!_editor->selection->selected (_marker)) {
2116 _editor->selection->set (_marker);
2119 case Selection::Extend:
2121 Locations::LocationList ll;
2122 list<Marker*> to_add;
2124 _editor->selection->markers.range (s, e);
2125 s = min (_marker->position(), s);
2126 e = max (_marker->position(), e);
2129 if (e < max_frames) {
2132 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2133 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2134 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2137 to_add.push_back (lm->start);
2140 to_add.push_back (lm->end);
2144 if (!to_add.empty()) {
2145 _editor->selection->add (to_add);
2149 case Selection::Add:
2150 _editor->selection->add (_marker);
2154 /* set up copies for us to manipulate during the drag */
2156 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2157 Location *l = _editor->find_location_from_marker (*i, is_start);
2158 _copied_locations.push_back (new Location (*l));
2163 MarkerDrag::motion (GdkEvent* event, bool)
2165 nframes64_t f_delta = 0;
2167 bool move_both = false;
2169 Location *real_location;
2170 Location *copy_location = 0;
2172 nframes64_t const newframe = adjusted_current_frame (event);
2174 nframes64_t next = newframe;
2176 if (_current_pointer_frame == _last_pointer_frame) {
2180 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2184 MarkerSelection::iterator i;
2185 list<Location*>::iterator x;
2187 /* find the marker we're dragging, and compute the delta */
2189 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2190 x != _copied_locations.end() && i != _editor->selection->markers.end();
2196 if (marker == _marker) {
2198 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2203 if (real_location->is_mark()) {
2204 f_delta = newframe - copy_location->start();
2208 switch (marker->type()) {
2210 case Marker::LoopStart:
2211 case Marker::PunchIn:
2212 f_delta = newframe - copy_location->start();
2216 case Marker::LoopEnd:
2217 case Marker::PunchOut:
2218 f_delta = newframe - copy_location->end();
2221 /* what kind of marker is this ? */
2229 if (i == _editor->selection->markers.end()) {
2230 /* hmm, impossible - we didn't find the dragged marker */
2234 /* now move them all */
2236 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2237 x != _copied_locations.end() && i != _editor->selection->markers.end();
2243 /* call this to find out if its the start or end */
2245 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2249 if (real_location->locked()) {
2253 if (copy_location->is_mark()) {
2257 copy_location->set_start (copy_location->start() + f_delta);
2261 nframes64_t new_start = copy_location->start() + f_delta;
2262 nframes64_t new_end = copy_location->end() + f_delta;
2264 if (is_start) { // start-of-range marker
2267 copy_location->set_start (new_start);
2268 copy_location->set_end (new_end);
2269 } else if (new_start < copy_location->end()) {
2270 copy_location->set_start (new_start);
2272 _editor->snap_to (next, 1, true);
2273 copy_location->set_end (next);
2274 copy_location->set_start (newframe);
2277 } else { // end marker
2280 copy_location->set_end (new_end);
2281 copy_location->set_start (new_start);
2282 } else if (new_end > copy_location->start()) {
2283 copy_location->set_end (new_end);
2284 } else if (newframe > 0) {
2285 _editor->snap_to (next, -1, true);
2286 copy_location->set_start (next);
2287 copy_location->set_end (newframe);
2292 update_item (copy_location);
2294 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2297 lm->set_position (copy_location->start(), copy_location->end());
2301 _last_pointer_frame = _current_pointer_frame;
2303 assert (!_copied_locations.empty());
2305 _editor->edit_point_clock.set (_copied_locations.front()->start());
2306 _editor->show_verbose_time_cursor (newframe, 10);
2309 _editor->update_canvas_now ();
2311 _editor->edit_point_clock.set (copy_location->start());
2315 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2317 if (!movement_occurred) {
2319 /* just a click, do nothing but finish
2320 off the selection process
2323 Selection::Operation op = Keyboard::selection_type (event->button.state);
2326 case Selection::Set:
2327 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2328 _editor->selection->set (_marker);
2332 case Selection::Toggle:
2333 case Selection::Extend:
2334 case Selection::Add:
2341 _editor->_dragging_edit_point = false;
2343 _editor->begin_reversible_command ( _("move marker") );
2344 XMLNode &before = _editor->session->locations()->get_state();
2346 MarkerSelection::iterator i;
2347 list<Location*>::iterator x;
2350 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2351 x != _copied_locations.end() && i != _editor->selection->markers.end();
2354 Location * location = _editor->find_location_from_marker (*i, is_start);
2358 if (location->locked()) {
2362 if (location->is_mark()) {
2363 location->set_start ((*x)->start());
2365 location->set ((*x)->start(), (*x)->end());
2370 XMLNode &after = _editor->session->locations()->get_state();
2371 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
2372 _editor->commit_reversible_command ();
2378 MarkerDrag::update_item (Location* location)
2380 double const x1 = _editor->frame_to_pixel (location->start());
2382 _points.front().set_x(x1);
2383 _points.back().set_x(x1);
2384 _line->property_points() = _points;
2387 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2389 _cumulative_x_drag (0),
2390 _cumulative_y_drag (0)
2392 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2398 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2400 Drag::start_grab (event, _editor->fader_cursor);
2402 // start the grab at the center of the control point so
2403 // the point doesn't 'jump' to the mouse after the first drag
2404 _grab_x = _point->get_x();
2405 _grab_y = _point->get_y();
2407 _point->line().parent_group().i2w (_grab_x, _grab_y);
2408 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2410 _grab_frame = _editor->pixel_to_frame (_grab_x);
2412 _point->line().start_drag (_point, _grab_frame, 0);
2414 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2415 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2416 _current_pointer_x + 10, _current_pointer_y + 10);
2418 _editor->show_verbose_canvas_cursor ();
2422 ControlPointDrag::motion (GdkEvent* event, bool)
2424 double dx = _current_pointer_x - _last_pointer_x;
2425 double dy = _current_pointer_y - _last_pointer_y;
2427 if (event->button.state & Keyboard::SecondaryModifier) {
2432 double cx = _grab_x + _cumulative_x_drag + dx;
2433 double cy = _grab_y + _cumulative_y_drag + dy;
2435 // calculate zero crossing point. back off by .01 to stay on the
2436 // positive side of zero
2438 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2439 _point->line().parent_group().i2w(_unused, zero_gain_y);
2441 // make sure we hit zero when passing through
2442 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2443 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2447 if (_x_constrained) {
2450 if (_y_constrained) {
2454 _cumulative_x_drag = cx - _grab_x;
2455 _cumulative_y_drag = cy - _grab_y;
2457 _point->line().parent_group().w2i (cx, cy);
2461 cy = min ((double) _point->line().height(), cy);
2463 //translate cx to frames
2464 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2466 if (!_x_constrained) {
2467 _editor->snap_to_with_modifier (cx_frames, event);
2470 float const fraction = 1.0 - (cy / _point->line().height());
2472 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2474 _point->line().point_drag (*_point, cx_frames, fraction, push);
2476 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2480 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2482 if (!movement_occurred) {
2486 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2487 _editor->reset_point_selection ();
2491 motion (event, false);
2493 _point->line().end_drag (_point);
2497 ControlPointDrag::active (Editing::MouseMode m)
2499 if (m == Editing::MouseGain) {
2500 /* always active in mouse gain */
2504 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2505 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2508 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2511 _cumulative_y_drag (0)
2516 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2518 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2521 _item = &_line->grab_item ();
2523 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2524 origin, and ditto for y.
2527 double cx = event->button.x;
2528 double cy = event->button.y;
2530 _line->parent_group().w2i (cx, cy);
2532 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2534 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2535 /* no adjacent points */
2539 Drag::start_grab (event, _editor->fader_cursor);
2541 /* store grab start in parent frame */
2546 double fraction = 1.0 - (cy / _line->height());
2548 _line->start_drag (0, _grab_frame, fraction);
2550 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2551 _current_pointer_x + 10, _current_pointer_y + 10);
2553 _editor->show_verbose_canvas_cursor ();
2557 LineDrag::motion (GdkEvent* event, bool)
2559 double dy = _current_pointer_y - _last_pointer_y;
2561 if (event->button.state & Keyboard::SecondaryModifier) {
2565 double cy = _grab_y + _cumulative_y_drag + dy;
2567 _cumulative_y_drag = cy - _grab_y;
2570 cy = min ((double) _line->height(), cy);
2572 double const fraction = 1.0 - (cy / _line->height());
2576 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2582 _line->line_drag (_before, _after, fraction, push);
2584 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2588 LineDrag::finished (GdkEvent* event, bool)
2590 motion (event, false);
2591 _line->end_drag (0);
2595 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2597 Drag::start_grab (event);
2598 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2602 RubberbandSelectDrag::motion (GdkEvent* event, bool first_move)
2609 /* use a bigger drag threshold than the default */
2611 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2615 if (Config->get_rubberbanding_snaps_to_grid()) {
2617 _editor->snap_to_with_modifier (_grab_frame, event);
2619 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2622 /* base start and end on initial click position */
2624 if (_current_pointer_frame < _grab_frame) {
2625 start = _current_pointer_frame;
2628 end = _current_pointer_frame;
2629 start = _grab_frame;
2632 if (_current_pointer_y < _grab_y) {
2633 y1 = _current_pointer_y;
2636 y2 = _current_pointer_y;
2641 if (start != end || y1 != y2) {
2643 double x1 = _editor->frame_to_pixel (start);
2644 double x2 = _editor->frame_to_pixel (end);
2646 _editor->rubberband_rect->property_x1() = x1;
2647 _editor->rubberband_rect->property_y1() = y1;
2648 _editor->rubberband_rect->property_x2() = x2;
2649 _editor->rubberband_rect->property_y2() = y2;
2651 _editor->rubberband_rect->show();
2652 _editor->rubberband_rect->raise_to_top();
2654 _last_pointer_frame = _current_pointer_frame;
2656 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2661 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2663 if (movement_occurred) {
2665 motion (event, false);
2668 if (_current_pointer_y < _grab_y) {
2669 y1 = _current_pointer_y;
2672 y2 = _current_pointer_y;
2677 Selection::Operation op = Keyboard::selection_type (event->button.state);
2680 _editor->begin_reversible_command (_("rubberband selection"));
2682 if (_grab_frame < _last_pointer_frame) {
2683 committed = _editor->select_all_within (_grab_frame, _last_pointer_frame - 1, y1, y2, _editor->track_views, op);
2685 committed = _editor->select_all_within (_last_pointer_frame, _grab_frame - 1, y1, y2, _editor->track_views, op);
2689 _editor->commit_reversible_command ();
2693 if (!getenv("ARDOUR_SAE")) {
2694 _editor->selection->clear_tracks();
2696 _editor->selection->clear_regions();
2697 _editor->selection->clear_points ();
2698 _editor->selection->clear_lines ();
2701 _editor->rubberband_rect->hide();
2705 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2707 Drag::start_grab (event);
2709 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2713 TimeFXDrag::motion (GdkEvent* event, bool)
2715 RegionView* rv = _primary;
2717 _editor->snap_to_with_modifier (_current_pointer_frame, event);
2719 if (_current_pointer_frame == _last_pointer_frame) {
2723 if (_current_pointer_frame > rv->region()->position()) {
2724 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2727 _last_pointer_frame = _current_pointer_frame;
2729 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2733 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2735 _primary->get_time_axis_view().hide_timestretch ();
2737 if (!movement_occurred) {
2741 if (_last_pointer_frame < _primary->region()->position()) {
2742 /* backwards drag of the left edge - not usable */
2746 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2748 float percentage = (double) newlen / (double) _primary->region()->length();
2750 #ifndef USE_RUBBERBAND
2751 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2752 if (_primary->region()->data_type() == DataType::AUDIO) {
2753 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2757 _editor->begin_reversible_command (_("timestretch"));
2759 // XXX how do timeFX on multiple regions ?
2764 if (_editor->time_stretch (rs, percentage) == 0) {
2765 _editor->session->commit_reversible_command ();
2770 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2772 Drag::start_grab (event);
2776 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2782 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2784 if (movement_occurred && _editor->session) {
2785 /* make sure we stop */
2786 _editor->session->request_transport_speed (0.0);
2790 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2799 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2801 nframes64_t start = 0;
2802 nframes64_t end = 0;
2804 if (_editor->session == 0) {
2808 Gdk::Cursor* cursor = 0;
2810 switch (_operation) {
2811 case CreateSelection:
2812 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2817 cursor = _editor->selector_cursor;
2818 Drag::start_grab (event, cursor);
2821 case SelectionStartTrim:
2822 if (_editor->clicked_axisview) {
2823 _editor->clicked_axisview->order_selection_trims (_item, true);
2825 Drag::start_grab (event, cursor);
2826 cursor = _editor->trimmer_cursor;
2827 start = _editor->selection->time[_editor->clicked_selection].start;
2828 _pointer_frame_offset = _grab_frame - start;
2831 case SelectionEndTrim:
2832 if (_editor->clicked_axisview) {
2833 _editor->clicked_axisview->order_selection_trims (_item, false);
2835 Drag::start_grab (event, cursor);
2836 cursor = _editor->trimmer_cursor;
2837 end = _editor->selection->time[_editor->clicked_selection].end;
2838 _pointer_frame_offset = _grab_frame - end;
2842 start = _editor->selection->time[_editor->clicked_selection].start;
2843 Drag::start_grab (event, cursor);
2844 _pointer_frame_offset = _grab_frame - start;
2848 if (_operation == SelectionMove) {
2849 _editor->show_verbose_time_cursor (start, 10);
2851 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2856 SelectionDrag::motion (GdkEvent* event, bool first_move)
2858 nframes64_t start = 0;
2859 nframes64_t end = 0;
2862 nframes64_t const pending_position = adjusted_current_frame (event);
2864 /* only alter selection if the current frame is
2865 different from the last frame position (adjusted)
2868 if (pending_position == _last_pointer_frame) {
2872 switch (_operation) {
2873 case CreateSelection:
2876 _editor->snap_to (_grab_frame);
2879 if (pending_position < _grab_frame) {
2880 start = pending_position;
2883 end = pending_position;
2884 start = _grab_frame;
2887 /* first drag: Either add to the selection
2888 or create a new selection->
2893 _editor->begin_reversible_command (_("range selection"));
2896 /* adding to the selection */
2897 _editor->clicked_selection = _editor->selection->add (start, end);
2900 /* new selection-> */
2901 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2906 case SelectionStartTrim:
2909 _editor->begin_reversible_command (_("trim selection start"));
2912 start = _editor->selection->time[_editor->clicked_selection].start;
2913 end = _editor->selection->time[_editor->clicked_selection].end;
2915 if (pending_position > end) {
2918 start = pending_position;
2922 case SelectionEndTrim:
2925 _editor->begin_reversible_command (_("trim selection end"));
2928 start = _editor->selection->time[_editor->clicked_selection].start;
2929 end = _editor->selection->time[_editor->clicked_selection].end;
2931 if (pending_position < start) {
2934 end = pending_position;
2942 _editor->begin_reversible_command (_("move selection"));
2945 start = _editor->selection->time[_editor->clicked_selection].start;
2946 end = _editor->selection->time[_editor->clicked_selection].end;
2948 length = end - start;
2950 start = pending_position;
2951 _editor->snap_to (start);
2953 end = start + length;
2958 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
2959 _editor->start_canvas_autoscroll (1, 0);
2963 _editor->selection->replace (_editor->clicked_selection, start, end);
2966 _last_pointer_frame = pending_position;
2968 if (_operation == SelectionMove) {
2969 _editor->show_verbose_time_cursor(start, 10);
2971 _editor->show_verbose_time_cursor(pending_position, 10);
2976 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
2978 if (movement_occurred) {
2979 motion (event, false);
2980 /* XXX this is not object-oriented programming at all. ick */
2981 if (_editor->selection->time.consolidate()) {
2982 _editor->selection->TimeChanged ();
2984 _editor->commit_reversible_command ();
2986 /* just a click, no pointer movement.*/
2988 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
2990 _editor->selection->clear_time();
2995 /* XXX what happens if its a music selection? */
2996 _editor->session->set_audio_range (_editor->selection->time);
2997 _editor->stop_canvas_autoscroll ();
3000 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3005 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3006 _drag_rect->hide ();
3008 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3009 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3013 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3015 if (_editor->session == 0) {
3019 Gdk::Cursor* cursor = 0;
3021 if (!_editor->temp_location) {
3022 _editor->temp_location = new Location;
3025 switch (_operation) {
3026 case CreateRangeMarker:
3027 case CreateTransportMarker:
3028 case CreateCDMarker:
3030 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3035 cursor = _editor->selector_cursor;
3039 Drag::start_grab (event, cursor);
3041 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3045 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3047 nframes64_t start = 0;
3048 nframes64_t end = 0;
3049 ArdourCanvas::SimpleRect *crect;
3051 switch (_operation) {
3052 case CreateRangeMarker:
3053 crect = _editor->range_bar_drag_rect;
3055 case CreateTransportMarker:
3056 crect = _editor->transport_bar_drag_rect;
3058 case CreateCDMarker:
3059 crect = _editor->cd_marker_bar_drag_rect;
3062 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3067 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3069 /* only alter selection if the current frame is
3070 different from the last frame position.
3073 if (_current_pointer_frame == _last_pointer_frame) {
3077 switch (_operation) {
3078 case CreateRangeMarker:
3079 case CreateTransportMarker:
3080 case CreateCDMarker:
3082 _editor->snap_to (_grab_frame);
3085 if (_current_pointer_frame < _grab_frame) {
3086 start = _current_pointer_frame;
3089 end = _current_pointer_frame;
3090 start = _grab_frame;
3093 /* first drag: Either add to the selection
3094 or create a new selection.
3099 _editor->temp_location->set (start, end);
3103 update_item (_editor->temp_location);
3105 //_drag_rect->raise_to_top();
3111 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3112 _editor->start_canvas_autoscroll (1, 0);
3116 _editor->temp_location->set (start, end);
3118 double x1 = _editor->frame_to_pixel (start);
3119 double x2 = _editor->frame_to_pixel (end);
3120 crect->property_x1() = x1;
3121 crect->property_x2() = x2;
3123 update_item (_editor->temp_location);
3126 _last_pointer_frame = _current_pointer_frame;
3128 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3133 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3135 Location * newloc = 0;
3139 if (movement_occurred) {
3140 motion (event, false);
3143 switch (_operation) {
3144 case CreateRangeMarker:
3145 case CreateCDMarker:
3147 _editor->begin_reversible_command (_("new range marker"));
3148 XMLNode &before = _editor->session->locations()->get_state();
3149 _editor->session->locations()->next_available_name(rangename,"unnamed");
3150 if (_operation == CreateCDMarker) {
3151 flags = Location::IsRangeMarker | Location::IsCDMarker;
3152 _editor->cd_marker_bar_drag_rect->hide();
3155 flags = Location::IsRangeMarker;
3156 _editor->range_bar_drag_rect->hide();
3158 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3159 _editor->session->locations()->add (newloc, true);
3160 XMLNode &after = _editor->session->locations()->get_state();
3161 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3162 _editor->commit_reversible_command ();
3166 case CreateTransportMarker:
3167 // popup menu to pick loop or punch
3168 _editor->new_transport_marker_context_menu (&event->button, _item);
3172 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3174 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3179 start = _editor->session->locations()->first_mark_before (_grab_frame);
3180 end = _editor->session->locations()->first_mark_after (_grab_frame);
3182 if (end == max_frames) {
3183 end = _editor->session->current_end_frame ();
3187 start = _editor->session->current_start_frame ();
3190 switch (_editor->mouse_mode) {
3192 /* find the two markers on either side and then make the selection from it */
3193 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3197 /* find the two markers on either side of the click and make the range out of it */
3198 _editor->selection->set (0, start, end);
3207 _editor->stop_canvas_autoscroll ();
3213 RangeMarkerBarDrag::update_item (Location* location)
3215 double const x1 = _editor->frame_to_pixel (location->start());
3216 double const x2 = _editor->frame_to_pixel (location->end());
3218 _drag_rect->property_x1() = x1;
3219 _drag_rect->property_x2() = x2;
3223 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3225 Drag::start_grab (event, _editor->zoom_cursor);
3226 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3230 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3235 _editor->snap_to_with_modifier (_current_pointer_frame, event);
3238 _editor->snap_to_with_modifier (_grab_frame, event);
3241 if (_current_pointer_frame == _last_pointer_frame) {
3245 /* base start and end on initial click position */
3246 if (_current_pointer_frame < _grab_frame) {
3247 start = _current_pointer_frame;
3250 end = _current_pointer_frame;
3251 start = _grab_frame;
3257 _editor->zoom_rect->show();
3258 _editor->zoom_rect->raise_to_top();
3261 _editor->reposition_zoom_rect(start, end);
3263 _last_pointer_frame = _current_pointer_frame;
3265 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3270 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3272 if (movement_occurred) {
3273 motion (event, false);
3275 if (_grab_frame < _last_pointer_frame) {
3276 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3278 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3281 _editor->temporal_zoom_to_frame (false, _grab_frame);
3283 temporal_zoom_step (false);
3284 center_screen (_grab_frame);
3288 _editor->zoom_rect->hide();