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"
38 using namespace ARDOUR;
42 using namespace Editing;
44 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
46 Drag::Drag (Editor* e, ArdourCanvas::Item* i) :
49 _pointer_frame_offset (0),
51 _last_pointer_frame (0),
52 _current_pointer_frame (0),
59 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
65 cursor = _editor->which_grabber_cursor ();
68 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
72 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
75 cursor = _editor->which_grabber_cursor ();
78 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
80 if (Keyboard::is_button2_event (&event->button)) {
81 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
82 _y_constrained = true;
83 _x_constrained = false;
85 _y_constrained = false;
86 _x_constrained = true;
89 _x_constrained = false;
90 _y_constrained = false;
93 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
94 _last_pointer_frame = _grab_frame;
95 _current_pointer_frame = _grab_frame;
96 _current_pointer_x = _grab_x;
97 _current_pointer_y = _grab_y;
98 _last_pointer_x = _current_pointer_x;
99 _last_pointer_y = _current_pointer_y;
101 _move_threshold_passed = false;
102 _want_move_threshold = false;
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 */
132 Drag::end_grab (GdkEvent* event)
136 bool did_drag = false;
138 _editor->stop_canvas_autoscroll ();
140 _item->ungrab (event ? event->button.time : 0);
143 _last_pointer_x = _current_pointer_x;
144 _last_pointer_y = _current_pointer_y;
148 did_drag = !_first_move;
150 _editor->hide_verbose_canvas_cursor();
160 Drag::adjusted_current_frame () const
162 if (_current_pointer_frame > _pointer_frame_offset) {
163 return _current_pointer_frame - _pointer_frame_offset;
170 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
172 _last_pointer_x = _current_pointer_x;
173 _last_pointer_y = _current_pointer_y;
174 _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
176 if (!from_autoscroll && !_move_threshold_passed) {
177 bool xp = (::llabs ((nframes64_t) (_current_pointer_x - _grab_x)) > 4LL);
178 bool yp = (::llabs ((nframes64_t) (_current_pointer_y - _grab_y)) > 4LL);
180 _move_threshold_passed = (xp || yp);
182 if (_want_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;
191 if (active (_editor->mouse_mode)) {
193 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
194 if (!from_autoscroll) {
195 _editor->maybe_autoscroll (&event->motion);
210 _editor->stop_canvas_autoscroll ();
211 _editor->hide_verbose_canvas_cursor ();
216 /* put it back where it came from */
221 _item->i2w (cxw, cyw);
222 _item->move (_original_x - cxw, _original_y - cyw);
227 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
232 RegionView::RegionViewGoingAway.connect (mem_fun (*this, &RegionDrag::region_going_away));
236 RegionDrag::region_going_away (RegionView* v)
242 RegionDrag::update_selection ()
245 copy (_views.begin(), _views.end(), back_inserter (s));
246 _editor->selection->set (s);
249 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
250 : RegionDrag (e, i, p, v),
253 _want_move_threshold = true;
256 _source_trackview = &_primary->get_time_axis_view ();
257 _source_layer = _primary->region()->layer ();
258 _dest_trackview = _source_trackview;
259 _dest_layer = _source_layer;
262 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (_source_trackview);
263 if (tv && tv->is_track()) {
264 speed = tv->get_diskstream()->speed ();
267 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
271 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
273 Drag::start_grab (event);
275 _pointer_frame_offset = _grab_frame - _last_frame_position;
276 _editor->show_verbose_time_cursor (_last_frame_position, 10);
280 RegionMoveDrag::motion (GdkEvent* event)
284 nframes64_t pending_region_position = 0;
285 int32_t pointer_order_span = 0, canvas_pointer_order_span = 0;
286 int32_t pointer_layer_span = 0;
288 bool clamp_y_axis = false;
289 vector<int32_t>::iterator j;
291 if (_copy && _move_threshold_passed && _want_move_threshold) {
292 copy_regions (event);
293 _want_move_threshold = false; // don't copy again
296 /* *pointer* variables reflect things about the pointer; as we may be moving
297 multiple regions, much detail must be computed per-region */
299 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
300 current_pointer_layer the current layer on that TimeAxisView */
301 RouteTimeAxisView* current_pointer_view;
302 layer_t current_pointer_layer;
303 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
307 /* TimeAxisView that we were pointing at last time we entered this method */
308 TimeAxisView const * const last_pointer_view = _dest_trackview;
309 /* the order of the track that we were pointing at last time we entered this method */
310 int32_t const last_pointer_order = last_pointer_view->order ();
311 /* the layer that we were pointing at last time we entered this method */
312 layer_t const last_pointer_layer = _dest_layer;
314 /************************************************************
316 ************************************************************/
318 /* Height of TimeAxisViews, indexed by order */
319 /* XXX: hard-coded limit of TimeAxisViews */
320 vector<int32_t> height_list (512);
324 pointer_order_span = 0;
328 /* the change in track order between this callback and the last */
329 pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
330 /* the change in layer between this callback and the last;
331 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
332 pointer_layer_span = last_pointer_layer - current_pointer_layer;
334 if (pointer_order_span != 0) {
336 int32_t children = 0;
337 /* XXX: hard-coded limit of tracks */
338 bitset <512> tracks (0x00);
342 _editor->visible_order_range (&visible_y_low, &visible_y_high);
344 /* get a bitmask representing the visible tracks */
346 for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
347 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
348 TimeAxisView::Children children_list;
350 /* zeroes are audio/MIDI tracks. ones are other types. */
352 if (!rtv->hidden()) {
354 if (!rtv->is_track()) {
355 /* not an audio nor MIDI track */
356 tracks = tracks |= (0x01 << rtv->order());
359 height_list[rtv->order()] = (*i)->current_height();
362 if ((children_list = rtv->get_child_list()).size() > 0) {
363 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
364 tracks = tracks |= (0x01 << (rtv->order() + children));
365 height_list[rtv->order() + children] = (*j)->current_height();
372 /* find the actual pointer span, in terms of the number of visible tracks;
373 to do this, we reduce |pointer_order_span| by the number of hidden tracks
376 canvas_pointer_order_span = pointer_order_span;
377 if (last_pointer_view->order() >= current_pointer_view->order()) {
378 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
379 if (height_list[y] == 0) {
380 canvas_pointer_order_span--;
384 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
385 if (height_list[y] == 0) {
386 canvas_pointer_order_span++;
391 for (list<RegionView*>::const_iterator i = _editor->selection->regions.by_layer().begin(); i != _editor->selection->regions.by_layer().end(); ++i) {
393 RegionView* rv = (*i);
395 if (rv->region()->locked()) {
399 double ix1, ix2, iy1, iy2;
400 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
401 rv->get_canvas_frame()->i2w (ix1, iy1);
402 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
404 /* get the new trackview for this particular region */
405 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
407 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
409 /* I know this method has a slightly excessive argument list, but I think
410 it's nice to separate the code out all the same, since it has such a
411 simple result, and it makes it clear that there are no other
415 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
416 as surely this is a per-region thing... */
418 clamp_y_axis = y_movement_disallowed (
419 rtv->order(), last_pointer_order, canvas_pointer_order_span, visible_y_low, visible_y_high,
428 } else if (_dest_trackview == current_pointer_view) {
430 if (current_pointer_layer == last_pointer_layer) {
431 /* No movement; clamp */
438 _dest_trackview = current_pointer_view;
439 _dest_layer = current_pointer_layer;
442 /************************************************************
444 ************************************************************/
446 /* compute the amount of pointer motion in frames, and where
447 the region would be if we moved it by that much.
449 if (_move_threshold_passed) {
451 if (_current_pointer_frame >= _pointer_frame_offset) {
453 nframes64_t sync_frame;
454 nframes64_t sync_offset;
457 pending_region_position = _current_pointer_frame - _pointer_frame_offset;
459 sync_offset = _primary->region()->sync_offset (sync_dir);
461 /* we don't handle a sync point that lies before zero.
463 if (sync_dir >= 0 || (sync_dir < 0 && pending_region_position >= sync_offset)) {
464 sync_frame = pending_region_position + (sync_dir*sync_offset);
466 /* we snap if the snap modifier is not enabled.
469 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
470 _editor->snap_to (sync_frame);
473 pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
476 pending_region_position = _last_frame_position;
480 pending_region_position = 0;
483 if (pending_region_position > max_frames - _primary->region()->length()) {
484 pending_region_position = _last_frame_position;
489 if (Config->get_edit_mode() == Lock) {
491 x_move_allowed = !_x_constrained;
493 /* in locked edit mode, reverse the usual meaning of _x_constrained */
494 x_move_allowed = _x_constrained;
497 x_move_allowed = !_x_constrained;
500 if (( pending_region_position != _last_frame_position) && x_move_allowed ) {
502 /* now compute the canvas unit distance we need to move the regionview
503 to make it appear at the new location.
506 if (pending_region_position > _last_frame_position) {
507 x_delta = ((double) (pending_region_position - _last_frame_position) / _editor->frames_per_unit);
509 x_delta = -((double) (_last_frame_position - pending_region_position) / _editor->frames_per_unit);
510 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
512 RegionView* rv = (*i);
514 // If any regionview is at zero, we need to know so we can stop further leftward motion.
516 double ix1, ix2, iy1, iy2;
517 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
518 rv->get_canvas_frame()->i2w (ix1, iy1);
520 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
522 pending_region_position = _last_frame_position;
529 _last_frame_position = pending_region_position;
536 /* threshold not passed */
541 /*************************************************************
543 ************************************************************/
545 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0) {
546 /* haven't reached next snap point, and we're not switching
547 trackviews nor layers. nothing to do.
552 /*************************************************************
554 ************************************************************/
557 if (!_move_threshold_passed) {
564 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
566 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
568 RegionView* rv = (*i);
570 if (rv->region()->locked()) {
574 /* here we are calculating the y distance from the
575 top of the first track view to the top of the region
576 area of the track view that we're working on */
578 /* this x value is just a dummy value so that we have something
583 /* distance from the top of this track view to the region area
584 of our track view is always 1 */
588 /* convert to world coordinates, ie distance from the top of
591 rv->get_canvas_frame()->i2w (ix1, iy1);
593 /* compensate for the ruler section and the vertical scrollbar position */
594 iy1 += _editor->get_trackview_group_vertical_offset ();
598 // hide any dependent views
600 rv->get_time_axis_view().hide_dependent_views (*rv);
603 reparent to a non scrolling group so that we can keep the
604 region selection above all time axis views.
605 reparenting means we have to move the rv as the two
606 parent groups have different coordinates.
609 rv->get_canvas_group()->property_y() = iy1 - 1;
610 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
612 rv->fake_set_opaque (true);
615 /* current view for this particular region */
616 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
617 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
619 if (pointer_order_span != 0 && !clamp_y_axis) {
621 /* INTER-TRACK MOVEMENT */
623 /* move through the height list to the track that the region is currently on */
624 vector<int32_t>::iterator j = height_list.begin ();
626 while (j != height_list.end () && x != rtv->order ()) {
632 int32_t temp_pointer_order_span = canvas_pointer_order_span;
634 if (j != height_list.end ()) {
636 /* Account for layers in the original and
637 destination tracks. If we're moving around in layers we assume
638 that only one track is involved, so it's ok to use *pointer*
641 StreamView* lv = last_pointer_view->view ();
644 /* move to the top of the last trackview */
645 if (lv->layer_display () == Stacked) {
646 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
649 StreamView* cv = current_pointer_view->view ();
652 /* move to the right layer on the current trackview */
653 if (cv->layer_display () == Stacked) {
654 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
657 /* And for being on a non-topmost layer on the new
660 while (temp_pointer_order_span > 0) {
661 /* we're moving up canvas-wise,
662 so we need to find the next track height
664 if (j != height_list.begin()) {
668 if (x != last_pointer_order) {
670 ++temp_pointer_order_span;
675 temp_pointer_order_span--;
678 while (temp_pointer_order_span < 0) {
682 if (x != last_pointer_order) {
684 --temp_pointer_order_span;
688 if (j != height_list.end()) {
692 temp_pointer_order_span++;
696 /* find out where we'll be when we move and set height accordingly */
698 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
699 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
700 rv->set_height (temp_rtv->view()->child_height());
702 /* if you un-comment the following, the region colours will follow
703 the track colours whilst dragging; personally
704 i think this can confuse things, but never mind.
707 //const GdkColor& col (temp_rtv->view->get_region_color());
708 //rv->set_color (const_cast<GdkColor&>(col));
712 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
714 /* INTER-LAYER MOVEMENT in the same track */
715 y_delta = rtv->view()->child_height () * pointer_layer_span;
720 _editor->mouse_brush_insert_region (rv, pending_region_position);
722 rv->move (x_delta, y_delta);
725 } /* foreach region */
729 if (_first_move && _move_threshold_passed) {
730 _editor->cursor_group->raise_to_top();
734 if (x_delta != 0 && !_brushing) {
735 _editor->show_verbose_time_cursor (_last_frame_position, 10);
740 RegionMoveDrag::finished (GdkEvent* event)
742 bool nocommit = true;
743 vector<RegionView*> copies;
744 RouteTimeAxisView* source_tv;
745 boost::shared_ptr<Diskstream> ds;
746 boost::shared_ptr<Playlist> from_playlist;
747 list<RegionView*> new_views;
748 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
749 PlaylistSet modified_playlists;
750 PlaylistSet frozen_playlists;
751 list <sigc::connection> modified_playlist_connections;
752 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
753 nframes64_t drag_delta;
754 bool changed_tracks, changed_position;
755 pair<TimeAxisView*, int> tvp;
756 map<RegionView*, RouteTimeAxisView*> final;
758 /* _first_move is set to false if the regionview has been moved in the
769 if (Config->get_edit_mode() == Splice && !_editor->pre_drag_region_selection.empty()) {
770 _editor->selection->set (_editor->pre_drag_region_selection);
771 _editor->pre_drag_region_selection.clear ();
775 /* all changes were made during motion event handlers */
778 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
779 copies.push_back (*i);
788 /* reverse this here so that we have the correct logic to finalize
792 if (Config->get_edit_mode() == Lock && !_copy) {
793 _x_constrained = !_x_constrained;
797 if (_x_constrained) {
798 op_string = _("fixed time region copy");
800 op_string = _("region copy");
803 if (_x_constrained) {
804 op_string = _("fixed time region drag");
806 op_string = _("region drag");
810 _editor->begin_reversible_command (op_string);
811 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
812 tvp = _editor->trackview_by_y_position (_current_pointer_y);
813 changed_tracks = (tvp.first != &_primary->get_time_axis_view());
815 drag_delta = _primary->region()->position() - _last_frame_position;
817 _editor->track_canvas->update_now ();
819 /* make a list of where each region ended up */
820 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
822 double ix1, ix2, iy1, iy2;
823 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
824 (*i)->get_canvas_frame()->i2w (ix1, iy1);
825 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
827 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
828 final[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
831 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
833 RegionView* rv = (*i);
834 RouteTimeAxisView* dest_rtv = final[*i];
838 if (rv->region()->locked()) {
843 if (changed_position && !_x_constrained) {
844 where = rv->region()->position() - drag_delta;
846 where = rv->region()->position();
849 boost::shared_ptr<Region> new_region;
852 /* we already made a copy */
853 new_region = rv->region();
855 /* undo the previous hide_dependent_views so that xfades don't
856 disappear on copying regions
859 //rv->get_time_axis_view().reveal_dependent_views (*rv);
861 } else if (changed_tracks && dest_rtv->playlist()) {
862 new_region = RegionFactory::create (rv->region());
865 if (changed_tracks || _copy) {
867 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
874 _editor->latest_regionviews.clear ();
876 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*_editor, &Editor::collect_new_region_view));
878 insert_result = modified_playlists.insert (to_playlist);
880 if (insert_result.second) {
881 _editor->session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
884 to_playlist->add_region (new_region, where);
888 if (!_editor->latest_regionviews.empty()) {
889 // XXX why just the first one ? we only expect one
890 // commented out in nick_m's canvas reworking. is that intended?
891 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
892 new_views.push_back (_editor->latest_regionviews.front());
897 motion on the same track. plonk the previously reparented region
898 back to its original canvas group (its streamview).
899 No need to do anything for copies as they are fake regions which will be deleted.
902 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
903 rv->get_canvas_group()->property_y() = 0;
905 /* just change the model */
907 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
909 insert_result = modified_playlists.insert (playlist);
911 if (insert_result.second) {
912 _editor->session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
914 /* freeze to avoid lots of relayering in the case of a multi-region drag */
915 frozen_insert_result = frozen_playlists.insert(playlist);
917 if (frozen_insert_result.second) {
921 rv->region()->set_position (where, (void*) this);
924 if (changed_tracks && !_copy) {
926 /* get the playlist where this drag started. we can't use rv->region()->playlist()
927 because we may have copied the region and it has not been attached to a playlist.
930 assert ((source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view())));
931 assert ((ds = source_tv->get_diskstream()));
932 assert ((from_playlist = ds->playlist()));
934 /* moved to a different audio track, without copying */
936 /* the region that used to be in the old playlist is not
937 moved to the new one - we use a copy of it. as a result,
938 any existing editor for the region should no longer be
942 rv->hide_region_editor();
943 rv->fake_set_opaque (false);
945 /* remove the region from the old playlist */
947 insert_result = modified_playlists.insert (from_playlist);
949 if (insert_result.second) {
950 _editor->session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
953 from_playlist->remove_region (rv->region());
955 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
956 was selected in all of them, then removing it from a playlist will have removed all
957 trace of it from the selection (i.e. there were N regions selected, we removed 1,
958 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
959 corresponding regionview, and the selection is now empty).
961 this could have invalidated any and all iterators into the region selection.
963 the heuristic we use here is: if the region selection is empty, break out of the loop
964 here. if the region selection is not empty, then restart the loop because we know that
965 we must have removed at least the region(view) we've just been working on as well as any
966 that we processed on previous iterations.
968 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
972 if (_views.empty()) {
983 copies.push_back (rv);
987 if (new_views.empty()) {
989 /* the region(view)s that are being dragged around are copies and do not
990 belong to any track. remove them from our list
996 _primary = _views.front ();
999 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1005 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
1006 _editor->session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
1009 _editor->commit_reversible_command ();
1012 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1019 RegionMoveDrag::copy_regions (GdkEvent* event)
1021 /* duplicate the regionview(s) and region(s) */
1023 list<RegionView*> new_regionviews;
1025 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1027 RegionView* rv = (*i);
1028 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1029 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1031 const boost::shared_ptr<const Region> original = rv->region();
1032 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1036 boost::shared_ptr<AudioRegion> audioregion_copy
1037 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1038 nrv = new AudioRegionView (*arv, audioregion_copy);
1040 boost::shared_ptr<MidiRegion> midiregion_copy
1041 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1042 nrv = new MidiRegionView (*mrv, midiregion_copy);
1047 nrv->get_canvas_group()->show ();
1048 new_regionviews.push_back (nrv);
1051 if (new_regionviews.empty()) {
1055 /* reflect the fact that we are dragging the copies */
1057 _primary = new_regionviews.front();
1058 _views = new_regionviews;
1060 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time);
1062 sync the canvas to what we think is its current state
1063 without it, the canvas seems to
1064 "forget" to update properly after the upcoming reparent()
1065 ..only if the mouse is in rapid motion at the time of the grab.
1066 something to do with regionview creation raking so long?
1068 _editor->track_canvas->update_now();
1072 RegionMoveDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1074 /* Which trackview is this ? */
1076 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1077 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1078 (*layer) = tvp.second;
1080 /* The region motion is only processed if the pointer is over
1084 if (!(*tv) || !(*tv)->is_track()) {
1085 /* To make sure we hide the verbose canvas cursor when the mouse is
1086 not held over and audiotrack.
1088 _editor->hide_verbose_canvas_cursor ();
1095 /** @param new_order New track order.
1096 * @param old_order Old track order.
1097 * @param visible_y_low Lowest visible order.
1098 * @param visible_y_high Highest visible order.
1099 * @param tracks Bitset of tracks indexed by order; 0 means a audio/MIDI track, 1 means something else.
1100 * @param heigh_list Heights of tracks indexed by order.
1101 * @return true if y movement should not happen, otherwise false.
1104 RegionMoveDrag::y_movement_disallowed (
1105 int new_order, int old_order, int y_span, int visible_y_low, int visible_y_high,
1106 bitset<512> const & tracks, vector<int32_t> const & height_list
1109 if (new_order != old_order) {
1111 /* this isn't the pointer track */
1115 /* moving up the canvas */
1116 if ( (new_order - y_span) >= visible_y_low) {
1120 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1121 int32_t visible_tracks = 0;
1122 while (visible_tracks < y_span ) {
1124 while (height_list[new_order - (visible_tracks - n)] == 0) {
1125 /* passing through a hidden track */
1130 if (tracks[new_order - (y_span - n)] != 0x00) {
1131 /* moving to a non-track; disallow */
1137 /* moving beyond the lowest visible track; disallow */
1141 } else if (y_span < 0) {
1143 /* moving down the canvas */
1144 if ((new_order - y_span) <= visible_y_high) {
1146 int32_t visible_tracks = 0;
1148 while (visible_tracks > y_span ) {
1151 while (height_list[new_order - (visible_tracks - n)] == 0) {
1152 /* passing through a hidden track */
1157 if (tracks[new_order - (y_span - n)] != 0x00) {
1158 /* moving to a non-track; disallow */
1165 /* moving beyond the highest visible track; disallow */
1172 /* this is the pointer's track */
1174 if ((new_order - y_span) > visible_y_high) {
1175 /* we will overflow */
1177 } else if ((new_order - y_span) < visible_y_low) {
1178 /* we will overflow */
1186 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1187 : RegionMoveDrag (e, i, p, v, false, false)
1192 struct RegionSelectionByPosition {
1193 bool operator() (RegionView*a, RegionView* b) {
1194 return a->region()->position () < b->region()->position();
1199 RegionSpliceDrag::motion (GdkEvent* event)
1201 RouteTimeAxisView* tv;
1204 if (!check_possible (&tv, &layer)) {
1208 if (!_move_threshold_passed) {
1214 if (_current_pointer_x - _grab_x > 0) {
1220 RegionSelection copy (_editor->selection->regions);
1222 RegionSelectionByPosition cmp;
1225 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1227 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1233 boost::shared_ptr<Playlist> playlist;
1235 if ((playlist = atv->playlist()) == 0) {
1239 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1244 if (_current_pointer_frame < (*i)->region()->last_frame() + 1) {
1248 if (_current_pointer_frame > (*i)->region()->first_frame()) {
1254 playlist->shuffle ((*i)->region(), dir);
1256 _grab_x = _current_pointer_x;
1261 RegionSpliceDrag::finished (GdkEvent* event)
1267 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1275 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1277 _source_trackview = _view;
1278 _dest_trackview = _view;
1279 _dest_layer = _source_layer;
1281 Drag::start_grab (event);
1286 RegionCreateDrag::motion (GdkEvent* event)
1288 if (_move_threshold_passed) {
1290 // TODO: create region-create-drag region view here
1291 _first_move = false;
1294 // TODO: resize region-create-drag region view here
1299 RegionCreateDrag::finished (GdkEvent* event)
1301 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1306 const boost::shared_ptr<MidiDiskstream> diskstream =
1307 boost::dynamic_pointer_cast<MidiDiskstream>(mtv->view()->trackview().track()->diskstream());
1310 warning << "Cannot create non-MIDI region" << endl;
1315 _editor->begin_reversible_command (_("create region"));
1316 XMLNode &before = mtv->playlist()->get_state();
1318 nframes64_t start = _grab_frame;
1319 _editor->snap_to (start, -1);
1320 const Meter& m = _editor->session->tempo_map().meter_at(start);
1321 const Tempo& t = _editor->session->tempo_map().tempo_at(start);
1322 double length = floor (m.frames_per_bar(t, _editor->session->frame_rate()));
1324 boost::shared_ptr<Source> src = _editor->session->create_midi_source_for_session(*diskstream.get());
1326 mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>
1327 (RegionFactory::create(src, 0, (nframes_t) length,
1328 PBD::basename_nosuffix(src->name()))), start);
1329 XMLNode &after = mtv->playlist()->get_state();
1330 _editor->session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
1331 _editor->commit_reversible_command();
1335 // TODO: create region-create-drag region here
1343 RegionGainDrag::motion (GdkEvent* event)
1345 if (_first_move && _move_threshold_passed) {
1346 _first_move = false;
1351 RegionGainDrag::finished (GdkEvent *)
1356 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1357 : RegionDrag (e, i, p, v)
1363 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1366 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1367 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1369 if (tv && tv->is_track()) {
1370 speed = tv->get_diskstream()->speed();
1373 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1374 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1375 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1377 Drag::start_grab (event, _editor->trimmer_cursor);
1379 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1380 _operation = ContentsTrim;
1382 /* These will get overridden for a point trim.*/
1383 if (_current_pointer_frame < (region_start + region_length/2)) {
1384 /* closer to start */
1385 _operation = StartTrim;
1386 } else if (_current_pointer_frame > (region_end - region_length/2)) {
1388 _operation = EndTrim;
1392 switch (_operation) {
1394 _editor->show_verbose_time_cursor (region_start, 10);
1397 _editor->show_verbose_time_cursor (region_end, 10);
1400 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1406 TrimDrag::motion (GdkEvent* event)
1408 RegionView* rv = _primary;
1409 nframes64_t frame_delta = 0;
1411 bool left_direction;
1412 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1414 /* snap modifier works differently here..
1415 its' current state has to be passed to the
1416 various trim functions in order to work properly
1420 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1421 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1422 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1424 if (tv && tv->is_track()) {
1425 speed = tv->get_diskstream()->speed();
1428 if (_last_pointer_frame > _current_pointer_frame) {
1429 left_direction = true;
1431 left_direction = false;
1435 _editor->snap_to (_current_pointer_frame);
1438 if (_current_pointer_frame == _last_pointer_frame) {
1446 switch (_operation) {
1448 trim_type = "Region start trim";
1451 trim_type = "Region end trim";
1454 trim_type = "Region content trim";
1458 _editor->begin_reversible_command (trim_type);
1460 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1461 (*i)->fake_set_opaque(false);
1462 (*i)->region()->freeze ();
1464 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1467 arv->temporarily_hide_envelope ();
1470 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1471 insert_result = _editor->motion_frozen_playlists.insert (pl);
1473 if (insert_result.second) {
1474 _editor->session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1480 if (left_direction) {
1481 frame_delta = (_last_pointer_frame - _current_pointer_frame);
1483 frame_delta = (_current_pointer_frame - _last_pointer_frame);
1486 bool non_overlap_trim = false;
1488 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1489 non_overlap_trim = true;
1492 switch (_operation) {
1494 if ((left_direction == false) && (_current_pointer_frame <= rv->region()->first_frame()/speed)) {
1498 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1499 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1505 if ((left_direction == true) && (_current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
1509 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1510 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1517 bool swap_direction = false;
1519 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1520 swap_direction = true;
1523 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i)
1525 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1531 switch (_operation) {
1533 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1536 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1539 _editor->show_verbose_time_cursor(_current_pointer_frame, 10);
1543 _last_pointer_frame = _current_pointer_frame;
1544 _first_move = false;
1549 TrimDrag::finished (GdkEvent* event)
1554 if (!_editor->selection->selected (_primary)) {
1555 _editor->thaw_region_after_trim (*_primary);
1558 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1559 _editor->thaw_region_after_trim (**i);
1560 (*i)->fake_set_opaque (true);
1564 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1566 _editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1569 _editor->motion_frozen_playlists.clear ();
1571 _editor->commit_reversible_command();
1573 /* no mouse movement */
1574 _editor->point_trim (event);
1578 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1583 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1588 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1591 // create a dummy marker for visual representation of moving the copy.
1592 // The actual copying is not done before we reach the finish callback.
1594 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1595 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1596 *new MeterSection (_marker->meter()));
1598 _item = &new_marker->the_item ();
1599 _marker = new_marker;
1603 MetricSection& section (_marker->meter());
1605 if (!section.movable()) {
1611 Drag::start_grab (event, cursor);
1613 _pointer_frame_offset = _grab_frame - _marker->meter().frame();
1615 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1619 MeterMarkerDrag::motion (GdkEvent* event)
1621 nframes64_t adjusted_frame = adjusted_current_frame ();
1623 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1624 _editor->snap_to (adjusted_frame);
1627 if (adjusted_frame == _last_pointer_frame) {
1631 _marker->set_position (adjusted_frame);
1633 _last_pointer_frame = adjusted_frame;
1634 _first_move = false;
1636 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1640 MeterMarkerDrag::finished (GdkEvent* event)
1650 TempoMap& map (_editor->session->tempo_map());
1651 map.bbt_time (_last_pointer_frame, when);
1653 if (_copy == true) {
1654 _editor->begin_reversible_command (_("copy meter mark"));
1655 XMLNode &before = map.get_state();
1656 map.add_meter (_marker->meter(), when);
1657 XMLNode &after = map.get_state();
1658 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1659 _editor->commit_reversible_command ();
1661 // delete the dummy marker we used for visual representation of copying.
1662 // a new visual marker will show up automatically.
1665 _editor->begin_reversible_command (_("move meter mark"));
1666 XMLNode &before = map.get_state();
1667 map.move_meter (_marker->meter(), when);
1668 XMLNode &after = map.get_state();
1669 _editor->session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1670 _editor->commit_reversible_command ();
1674 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1679 TempoMarker* _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1684 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1689 // create a dummy marker for visual representation of moving the copy.
1690 // The actual copying is not done before we reach the finish callback.
1692 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1693 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1694 *new TempoSection (_marker->tempo()));
1696 _item = &new_marker->the_item ();
1697 _marker = new_marker;
1701 MetricSection& section (_marker->tempo());
1703 if (!section.movable()) {
1708 Drag::start_grab (event, cursor);
1710 _pointer_frame_offset = _grab_frame - _marker->tempo().frame();
1711 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
1715 TempoMarkerDrag::motion (GdkEvent* event)
1717 nframes64_t adjusted_frame = adjusted_current_frame ();
1719 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1720 _editor->snap_to (adjusted_frame);
1723 if (adjusted_frame == _last_pointer_frame) {
1727 /* OK, we've moved far enough to make it worth actually move the thing. */
1729 _marker->set_position (adjusted_frame);
1731 _editor->show_verbose_time_cursor (adjusted_frame, 10);
1733 _last_pointer_frame = adjusted_frame;
1734 _first_move = false;
1738 TempoMarkerDrag::finished (GdkEvent* event)
1748 TempoMap& map (_editor->session->tempo_map());
1749 map.bbt_time (_last_pointer_frame, when);
1751 if (_copy == true) {
1752 _editor->begin_reversible_command (_("copy tempo mark"));
1753 XMLNode &before = map.get_state();
1754 map.add_tempo (_marker->tempo(), when);
1755 XMLNode &after = map.get_state();
1756 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1757 _editor->commit_reversible_command ();
1759 // delete the dummy marker we used for visual representation of copying.
1760 // a new visual marker will show up automatically.
1763 _editor->begin_reversible_command (_("move tempo mark"));
1764 XMLNode &before = map.get_state();
1765 map.move_tempo (_marker->tempo(), when);
1766 XMLNode &after = map.get_state();
1767 _editor->session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1768 _editor->commit_reversible_command ();
1773 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1777 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1782 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1784 Drag::start_grab (event, c);
1788 nframes64_t where = _editor->event_frame (event, 0, 0);
1790 _editor->snap_to (where);
1791 _editor->playhead_cursor->set_position (where);
1795 if (_cursor == _editor->playhead_cursor) {
1796 _editor->_dragging_playhead = true;
1798 if (_editor->session && _was_rolling && _stop) {
1799 _editor->session->request_stop ();
1802 if (_editor->session && _editor->session->is_auditioning()) {
1803 _editor->session->cancel_audition ();
1807 _pointer_frame_offset = _grab_frame - _cursor->current_frame;
1809 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1813 CursorDrag::motion (GdkEvent* event)
1815 nframes64_t adjusted_frame = adjusted_current_frame ();
1817 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1818 if (_cursor == _editor->playhead_cursor) {
1819 _editor->snap_to (adjusted_frame);
1823 if (adjusted_frame == _last_pointer_frame) {
1827 _cursor->set_position (adjusted_frame);
1829 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1832 _editor->track_canvas->update_now ();
1834 _editor->UpdateAllTransportClocks (_cursor->current_frame);
1836 _last_pointer_frame = adjusted_frame;
1837 _first_move = false;
1841 CursorDrag::finished (GdkEvent* event)
1843 _editor->_dragging_playhead = false;
1845 if (_first_move && _stop) {
1851 if (_item == &_editor->playhead_cursor->canvas_item) {
1852 if (_editor->session) {
1853 _editor->session->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1854 _editor->_pending_locate_request = true;
1859 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1860 : RegionDrag (e, i, p, v)
1866 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1868 Drag::start_grab (event, cursor);
1870 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1871 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1873 _pointer_frame_offset = _grab_frame - ((nframes64_t) r->fade_in()->back()->when + r->position());
1877 FadeInDrag::motion (GdkEvent* event)
1879 nframes64_t fade_length;
1881 nframes64_t pos = adjusted_current_frame ();
1883 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1884 _editor->snap_to (pos);
1887 boost::shared_ptr<Region> region = _primary->region ();
1889 if (pos < (region->position() + 64)) {
1890 fade_length = 64; // this should be a minimum defined somewhere
1891 } else if (pos > region->last_frame()) {
1892 fade_length = region->length();
1894 fade_length = pos - region->position();
1897 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1899 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1905 tmp->reset_fade_in_shape_width (fade_length);
1908 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1910 _first_move = false;
1914 FadeInDrag::finished (GdkEvent* event)
1916 nframes64_t fade_length;
1922 nframes64_t const pos = adjusted_current_frame ();
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 _editor->begin_reversible_command (_("change fade in length"));
1936 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1938 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1944 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
1945 XMLNode &before = alist->get_state();
1947 tmp->audio_region()->set_fade_in_length (fade_length);
1948 tmp->audio_region()->set_fade_in_active (true);
1950 XMLNode &after = alist->get_state();
1951 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
1954 _editor->commit_reversible_command ();
1957 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1958 : RegionDrag (e, i, p, v)
1964 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1966 Drag::start_grab (event, cursor);
1968 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1969 boost::shared_ptr<AudioRegion> r = a->audio_region ();
1971 _pointer_frame_offset = _grab_frame - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
1975 FadeOutDrag::motion (GdkEvent* event)
1977 nframes64_t fade_length;
1979 nframes64_t pos = adjusted_current_frame ();
1981 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1982 _editor->snap_to (pos);
1985 boost::shared_ptr<Region> region = _primary->region ();
1987 if (pos > (region->last_frame() - 64)) {
1988 fade_length = 64; // this should really be a minimum fade defined somewhere
1990 else if (pos < region->position()) {
1991 fade_length = region->length();
1994 fade_length = region->last_frame() - pos;
1997 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1999 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2005 tmp->reset_fade_out_shape_width (fade_length);
2008 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2010 _first_move = false;
2014 FadeOutDrag::finished (GdkEvent* event)
2020 nframes64_t fade_length;
2022 nframes64_t pos = adjusted_current_frame ();
2024 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2025 _editor->snap_to (pos);
2028 boost::shared_ptr<Region> region = _primary->region ();
2030 if (pos > (region->last_frame() - 64)) {
2031 fade_length = 64; // this should really be a minimum fade defined somewhere
2033 else if (pos < region->position()) {
2034 fade_length = region->length();
2037 fade_length = region->last_frame() - pos;
2040 _editor->begin_reversible_command (_("change fade out length"));
2042 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2044 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2050 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2051 XMLNode &before = alist->get_state();
2053 tmp->audio_region()->set_fade_out_length (fade_length);
2054 tmp->audio_region()->set_fade_out_active (true);
2056 XMLNode &after = alist->get_state();
2057 _editor->session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2060 _editor->commit_reversible_command ();
2063 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2066 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2069 _points.push_back (Gnome::Art::Point (0, 0));
2070 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2072 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2073 _line->property_width_pixels() = 1;
2074 _line->property_points () = _points;
2077 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2080 MarkerDrag::~MarkerDrag ()
2082 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2088 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2090 Drag::start_grab (event, cursor);
2094 Location *location = _editor->find_location_from_marker (_marker, is_start);
2095 _editor->_dragging_edit_point = true;
2097 _pointer_frame_offset = _grab_frame - (is_start ? location->start() : location->end());
2099 update_item (location);
2101 // _drag_line->show();
2102 // _line->raise_to_top();
2105 _editor->show_verbose_time_cursor (location->start(), 10);
2107 _editor->show_verbose_time_cursor (location->end(), 10);
2110 Selection::Operation op = Keyboard::selection_type (event->button.state);
2113 case Selection::Toggle:
2114 _editor->selection->toggle (_marker);
2116 case Selection::Set:
2117 if (!_editor->selection->selected (_marker)) {
2118 _editor->selection->set (_marker);
2121 case Selection::Extend:
2123 Locations::LocationList ll;
2124 list<Marker*> to_add;
2126 _editor->selection->markers.range (s, e);
2127 s = min (_marker->position(), s);
2128 e = max (_marker->position(), e);
2131 if (e < max_frames) {
2134 _editor->session->locations()->find_all_between (s, e, ll, Location::Flags (0));
2135 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2136 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2139 to_add.push_back (lm->start);
2142 to_add.push_back (lm->end);
2146 if (!to_add.empty()) {
2147 _editor->selection->add (to_add);
2151 case Selection::Add:
2152 _editor->selection->add (_marker);
2156 /* set up copies for us to manipulate during the drag */
2158 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2159 Location *l = _editor->find_location_from_marker (*i, is_start);
2160 _copied_locations.push_back (new Location (*l));
2165 MarkerDrag::motion (GdkEvent* event)
2167 nframes64_t f_delta = 0;
2169 bool move_both = false;
2171 Location *real_location;
2172 Location *copy_location = 0;
2174 nframes64_t newframe = adjusted_current_frame ();
2176 nframes64_t next = newframe;
2178 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2179 _editor->snap_to (newframe, 0, true);
2182 if (_current_pointer_frame == _last_pointer_frame) {
2186 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2190 MarkerSelection::iterator i;
2191 list<Location*>::iterator x;
2193 /* find the marker we're dragging, and compute the delta */
2195 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2196 x != _copied_locations.end() && i != _editor->selection->markers.end();
2202 if (marker == _marker) {
2204 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2209 if (real_location->is_mark()) {
2210 f_delta = newframe - copy_location->start();
2214 switch (marker->type()) {
2216 case Marker::LoopStart:
2217 case Marker::PunchIn:
2218 f_delta = newframe - copy_location->start();
2222 case Marker::LoopEnd:
2223 case Marker::PunchOut:
2224 f_delta = newframe - copy_location->end();
2227 /* what kind of marker is this ? */
2235 if (i == _editor->selection->markers.end()) {
2236 /* hmm, impossible - we didn't find the dragged marker */
2240 /* now move them all */
2242 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2243 x != _copied_locations.end() && i != _editor->selection->markers.end();
2249 /* call this to find out if its the start or end */
2251 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2255 if (real_location->locked()) {
2259 if (copy_location->is_mark()) {
2263 copy_location->set_start (copy_location->start() + f_delta);
2267 nframes64_t new_start = copy_location->start() + f_delta;
2268 nframes64_t new_end = copy_location->end() + f_delta;
2270 if (is_start) { // start-of-range marker
2273 copy_location->set_start (new_start);
2274 copy_location->set_end (new_end);
2275 } else if (new_start < copy_location->end()) {
2276 copy_location->set_start (new_start);
2278 _editor->snap_to (next, 1, true);
2279 copy_location->set_end (next);
2280 copy_location->set_start (newframe);
2283 } else { // end marker
2286 copy_location->set_end (new_end);
2287 copy_location->set_start (new_start);
2288 } else if (new_end > copy_location->start()) {
2289 copy_location->set_end (new_end);
2290 } else if (newframe > 0) {
2291 _editor->snap_to (next, -1, true);
2292 copy_location->set_start (next);
2293 copy_location->set_end (newframe);
2298 update_item (copy_location);
2300 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2303 lm->set_position (copy_location->start(), copy_location->end());
2307 _last_pointer_frame = _current_pointer_frame;
2308 _first_move = false;
2310 assert (!_copied_locations.empty());
2312 _editor->edit_point_clock.set (_copied_locations.front()->start());
2313 _editor->show_verbose_time_cursor (newframe, 10);
2316 _editor->track_canvas->update_now ();
2318 _editor->edit_point_clock.set (copy_location->start());
2322 MarkerDrag::finished (GdkEvent* event)
2326 /* just a click, do nothing but finish
2327 off the selection process
2330 Selection::Operation op = Keyboard::selection_type (event->button.state);
2333 case Selection::Set:
2334 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2335 _editor->selection->set (_marker);
2339 case Selection::Toggle:
2340 case Selection::Extend:
2341 case Selection::Add:
2348 _editor->_dragging_edit_point = false;
2351 _editor->begin_reversible_command ( _("move marker") );
2352 XMLNode &before = _editor->session->locations()->get_state();
2354 MarkerSelection::iterator i;
2355 list<Location*>::iterator x;
2358 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2359 x != _copied_locations.end() && i != _editor->selection->markers.end();
2362 Location * location = _editor->find_location_from_marker (*i, is_start);
2366 if (location->locked()) {
2370 if (location->is_mark()) {
2371 location->set_start ((*x)->start());
2373 location->set ((*x)->start(), (*x)->end());
2378 XMLNode &after = _editor->session->locations()->get_state();
2379 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
2380 _editor->commit_reversible_command ();
2386 MarkerDrag::update_item (Location* location)
2388 double const x1 = _editor->frame_to_pixel (location->start());
2390 _points.front().set_x(x1);
2391 _points.back().set_x(x1);
2392 _line->property_points() = _points;
2395 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2397 _cumulative_x_drag (0),
2398 _cumulative_y_drag (0)
2400 ControlPoint* _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2406 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2408 Drag::start_grab (event, _editor->fader_cursor);
2410 // start the grab at the center of the control point so
2411 // the point doesn't 'jump' to the mouse after the first drag
2412 _grab_x = _point->get_x();
2413 _grab_y = _point->get_y();
2415 _point->line().parent_group().i2w (_grab_x, _grab_y);
2416 _editor->track_canvas->w2c (_grab_x, _grab_y, _grab_x, _grab_y);
2418 _grab_frame = _editor->pixel_to_frame (_grab_x);
2420 _point->line().start_drag (_point, _grab_frame, 0);
2422 float fraction = 1.0 - (_point->get_y() / _point->line().height());
2423 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2424 _current_pointer_x + 10, _current_pointer_y + 10);
2426 _editor->show_verbose_canvas_cursor ();
2430 ControlPointDrag::motion (GdkEvent* event)
2432 double dx = _current_pointer_x - _last_pointer_x;
2433 double dy = _current_pointer_y - _last_pointer_y;
2435 if (event->button.state & Keyboard::SecondaryModifier) {
2440 double cx = _grab_x + _cumulative_x_drag + dx;
2441 double cy = _grab_y + _cumulative_y_drag + dy;
2443 // calculate zero crossing point. back off by .01 to stay on the
2444 // positive side of zero
2446 double zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2447 _point->line().parent_group().i2w(_unused, zero_gain_y);
2449 // make sure we hit zero when passing through
2450 if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
2451 or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
2455 if (_x_constrained) {
2458 if (_y_constrained) {
2462 _cumulative_x_drag = cx - _grab_x;
2463 _cumulative_y_drag = cy - _grab_y;
2465 _point->line().parent_group().w2i (cx, cy);
2469 cy = min ((double) _point->line().height(), cy);
2471 //translate cx to frames
2472 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2474 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !_x_constrained) {
2475 _editor->snap_to (cx_frames);
2478 float const fraction = 1.0 - (cy / _point->line().height());
2480 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2482 _point->line().point_drag (*_point, cx_frames, fraction, push);
2484 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2486 _first_move = false;
2490 ControlPointDrag::finished (GdkEvent* event)
2496 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2497 _editor->reset_point_selection ();
2503 _point->line().end_drag (_point);
2506 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2509 _cumulative_y_drag (0)
2514 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2516 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2519 _item = &_line->grab_item ();
2521 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2522 origin, and ditto for y.
2525 double cx = event->button.x;
2526 double cy = event->button.y;
2528 _line->parent_group().w2i (cx, cy);
2530 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2532 if (!_line->control_points_adjacent (frame_within_region, _before, _after)) {
2533 /* no adjacent points */
2537 Drag::start_grab (event, _editor->fader_cursor);
2539 /* store grab start in parent frame */
2544 double fraction = 1.0 - (cy / _line->height());
2546 _line->start_drag (0, _grab_frame, fraction);
2548 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2549 _current_pointer_x + 10, _current_pointer_y + 10);
2551 _editor->show_verbose_canvas_cursor ();
2555 LineDrag::motion (GdkEvent* event)
2557 double dy = _current_pointer_y - _last_pointer_y;
2559 if (event->button.state & Keyboard::SecondaryModifier) {
2563 double cy = _grab_y + _cumulative_y_drag + dy;
2565 _cumulative_y_drag = cy - _grab_y;
2568 cy = min ((double) _line->height(), cy);
2570 double const fraction = 1.0 - (cy / _line->height());
2574 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2580 _line->line_drag (_before, _after, fraction, push);
2582 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2586 LineDrag::finished (GdkEvent* event)
2589 _line->end_drag (0);
2593 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2595 Drag::start_grab (event);
2596 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2600 RubberbandSelectDrag::motion (GdkEvent* event)
2607 /* use a bigger drag threshold than the default */
2609 if (abs ((int) (_current_pointer_frame - _grab_frame)) < 8) {
2613 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && Config->get_rubberbanding_snaps_to_grid()) {
2615 _editor->snap_to (_grab_frame);
2617 _editor->snap_to (_current_pointer_frame);
2620 /* base start and end on initial click position */
2622 if (_current_pointer_frame < _grab_frame) {
2623 start = _current_pointer_frame;
2626 end = _current_pointer_frame;
2627 start = _grab_frame;
2630 if (_current_pointer_y < _grab_y) {
2631 y1 = _current_pointer_y;
2634 y2 = _current_pointer_y;
2639 if (start != end || y1 != y2) {
2641 double x1 = _editor->frame_to_pixel (start);
2642 double x2 = _editor->frame_to_pixel (end);
2644 _editor->rubberband_rect->property_x1() = x1;
2645 _editor->rubberband_rect->property_y1() = y1;
2646 _editor->rubberband_rect->property_x2() = x2;
2647 _editor->rubberband_rect->property_y2() = y2;
2649 _editor->rubberband_rect->show();
2650 _editor->rubberband_rect->raise_to_top();
2652 _last_pointer_frame = _current_pointer_frame;
2653 _first_move = false;
2655 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2660 RubberbandSelectDrag::finished (GdkEvent* event)
2667 if (_current_pointer_y < _grab_y) {
2668 y1 = _current_pointer_y;
2671 y2 = _current_pointer_y;
2676 Selection::Operation op = Keyboard::selection_type (event->button.state);
2679 _editor->begin_reversible_command (_("rubberband selection"));
2681 if (_grab_frame < _last_pointer_frame) {
2682 commit = _editor->select_all_within (_grab_frame, _last_pointer_frame, y1, y2, _editor->track_views, op);
2684 commit = _editor->select_all_within (_last_pointer_frame, _grab_frame, y1, y2, _editor->track_views, op);
2688 _editor->commit_reversible_command ();
2692 if (!getenv("ARDOUR_SAE")) {
2693 _editor->selection->clear_tracks();
2695 _editor->selection->clear_regions();
2696 _editor->selection->clear_points ();
2697 _editor->selection->clear_lines ();
2700 _editor->rubberband_rect->hide();
2704 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2706 Drag::start_grab (event);
2708 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2712 TimeFXDrag::motion (GdkEvent* event)
2714 RegionView* rv = _primary;
2716 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2717 _editor->snap_to (_current_pointer_frame);
2720 if (_current_pointer_frame == _last_pointer_frame) {
2724 if (_current_pointer_frame > rv->region()->position()) {
2725 rv->get_time_axis_view().show_timestretch (rv->region()->position(), _current_pointer_frame);
2728 _last_pointer_frame = _current_pointer_frame;
2729 _first_move = false;
2731 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2735 TimeFXDrag::finished (GdkEvent* event)
2737 _primary->get_time_axis_view().hide_timestretch ();
2743 if (_last_pointer_frame < _primary->region()->position()) {
2744 /* backwards drag of the left edge - not usable */
2748 nframes64_t newlen = _last_pointer_frame - _primary->region()->position();
2750 float percentage = (double) newlen / (double) _primary->region()->length();
2752 #ifndef USE_RUBBERBAND
2753 // Soundtouch uses percentage / 100 instead of normal (/ 1)
2754 if (_primary->region()->data_type() == DataType::AUDIO) {
2755 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2759 _editor->begin_reversible_command (_("timestretch"));
2761 // XXX how do timeFX on multiple regions ?
2766 if (_editor->time_stretch (rs, percentage) == 0) {
2767 _editor->session->commit_reversible_command ();
2771 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2779 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2781 nframes64_t start = 0;
2782 nframes64_t end = 0;
2784 if (_editor->session == 0) {
2788 Gdk::Cursor* cursor = 0;
2790 switch (_operation) {
2791 case CreateSelection:
2792 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2797 cursor = _editor->selector_cursor;
2798 Drag::start_grab (event, cursor);
2801 case SelectionStartTrim:
2802 if (_editor->clicked_axisview) {
2803 _editor->clicked_axisview->order_selection_trims (_item, true);
2805 Drag::start_grab (event, cursor);
2806 cursor = _editor->trimmer_cursor;
2807 start = _editor->selection->time[_editor->clicked_selection].start;
2808 _pointer_frame_offset = _grab_frame - start;
2811 case SelectionEndTrim:
2812 if (_editor->clicked_axisview) {
2813 _editor->clicked_axisview->order_selection_trims (_item, false);
2815 Drag::start_grab (event, cursor);
2816 cursor = _editor->trimmer_cursor;
2817 end = _editor->selection->time[_editor->clicked_selection].end;
2818 _pointer_frame_offset = _grab_frame - end;
2822 start = _editor->selection->time[_editor->clicked_selection].start;
2823 Drag::start_grab (event, cursor);
2824 _pointer_frame_offset = _grab_frame - start;
2828 if (_operation == SelectionMove) {
2829 _editor->show_verbose_time_cursor (start, 10);
2831 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
2836 SelectionDrag::motion (GdkEvent* event)
2838 nframes64_t start = 0;
2839 nframes64_t end = 0;
2842 nframes64_t pending_position = adjusted_current_frame ();
2844 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2845 _editor->snap_to (pending_position);
2848 /* only alter selection if the current frame is
2849 different from the last frame position (adjusted)
2852 if (pending_position == _last_pointer_frame) {
2856 switch (_operation) {
2857 case CreateSelection:
2860 _editor->snap_to (_grab_frame);
2863 if (pending_position < _grab_frame) {
2864 start = pending_position;
2867 end = pending_position;
2868 start = _grab_frame;
2871 /* first drag: Either add to the selection
2872 or create a new selection->
2877 _editor->begin_reversible_command (_("range selection"));
2880 /* adding to the selection */
2881 _editor->clicked_selection = _editor->selection->add (start, end);
2884 /* new selection-> */
2885 _editor->clicked_selection = _editor->selection->set (_editor->clicked_axisview, start, end);
2890 case SelectionStartTrim:
2893 _editor->begin_reversible_command (_("trim selection start"));
2896 start = _editor->selection->time[_editor->clicked_selection].start;
2897 end = _editor->selection->time[_editor->clicked_selection].end;
2899 if (pending_position > end) {
2902 start = pending_position;
2906 case SelectionEndTrim:
2909 _editor->begin_reversible_command (_("trim selection end"));
2912 start = _editor->selection->time[_editor->clicked_selection].start;
2913 end = _editor->selection->time[_editor->clicked_selection].end;
2915 if (pending_position < start) {
2918 end = pending_position;
2926 _editor->begin_reversible_command (_("move selection"));
2929 start = _editor->selection->time[_editor->clicked_selection].start;
2930 end = _editor->selection->time[_editor->clicked_selection].end;
2932 length = end - start;
2934 start = pending_position;
2935 _editor->snap_to (start);
2937 end = start + length;
2942 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->canvas_width) {
2943 _editor->start_canvas_autoscroll (1, 0);
2947 _editor->selection->replace (_editor->clicked_selection, start, end);
2950 _last_pointer_frame = pending_position;
2951 _first_move = false;
2953 if (_operation == SelectionMove) {
2954 _editor->show_verbose_time_cursor(start, 10);
2956 _editor->show_verbose_time_cursor(pending_position, 10);
2961 SelectionDrag::finished (GdkEvent* event)
2965 /* XXX this is not object-oriented programming at all. ick */
2966 if (_editor->selection->time.consolidate()) {
2967 _editor->selection->TimeChanged ();
2969 _editor->commit_reversible_command ();
2971 /* just a click, no pointer movement.*/
2973 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
2975 _editor->selection->clear_time();
2980 /* XXX what happens if its a music selection? */
2981 _editor->session->set_audio_range (_editor->selection->time);
2982 _editor->stop_canvas_autoscroll ();
2985 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2989 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
2990 _drag_rect->hide ();
2992 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
2993 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
2997 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2999 if (_editor->session == 0) {
3003 Gdk::Cursor* cursor = 0;
3005 if (!_editor->temp_location) {
3006 _editor->temp_location = new Location;
3009 switch (_operation) {
3010 case CreateRangeMarker:
3011 case CreateTransportMarker:
3012 case CreateCDMarker:
3014 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3019 cursor = _editor->selector_cursor;
3023 Drag::start_grab (event, cursor);
3025 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3029 RangeMarkerBarDrag::motion (GdkEvent* event)
3031 nframes64_t start = 0;
3032 nframes64_t end = 0;
3033 ArdourCanvas::SimpleRect *crect;
3035 switch (_operation) {
3036 case CreateRangeMarker:
3037 crect = _editor->range_bar_drag_rect;
3039 case CreateTransportMarker:
3040 crect = _editor->transport_bar_drag_rect;
3042 case CreateCDMarker:
3043 crect = _editor->cd_marker_bar_drag_rect;
3046 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3051 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3052 _editor->snap_to (_current_pointer_frame);
3055 /* only alter selection if the current frame is
3056 different from the last frame position.
3059 if (_current_pointer_frame == _last_pointer_frame) {
3063 switch (_operation) {
3064 case CreateRangeMarker:
3065 case CreateTransportMarker:
3066 case CreateCDMarker:
3068 _editor->snap_to (_grab_frame);
3071 if (_current_pointer_frame < _grab_frame) {
3072 start = _current_pointer_frame;
3075 end = _current_pointer_frame;
3076 start = _grab_frame;
3079 /* first drag: Either add to the selection
3080 or create a new selection.
3085 _editor->temp_location->set (start, end);
3089 update_item (_editor->temp_location);
3091 //_drag_rect->raise_to_top();
3097 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->canvas_width) {
3098 _editor->start_canvas_autoscroll (1, 0);
3102 _editor->temp_location->set (start, end);
3104 double x1 = _editor->frame_to_pixel (start);
3105 double x2 = _editor->frame_to_pixel (end);
3106 crect->property_x1() = x1;
3107 crect->property_x2() = x2;
3109 update_item (_editor->temp_location);
3112 _last_pointer_frame = _current_pointer_frame;
3113 _first_move = false;
3115 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3120 RangeMarkerBarDrag::finished (GdkEvent* event)
3122 Location * newloc = 0;
3129 switch (_operation) {
3130 case CreateRangeMarker:
3131 case CreateCDMarker:
3133 _editor->begin_reversible_command (_("new range marker"));
3134 XMLNode &before = _editor->session->locations()->get_state();
3135 _editor->session->locations()->next_available_name(rangename,"unnamed");
3136 if (_operation == CreateCDMarker) {
3137 flags = Location::IsRangeMarker | Location::IsCDMarker;
3138 _editor->cd_marker_bar_drag_rect->hide();
3141 flags = Location::IsRangeMarker;
3142 _editor->range_bar_drag_rect->hide();
3144 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3145 _editor->session->locations()->add (newloc, true);
3146 XMLNode &after = _editor->session->locations()->get_state();
3147 _editor->session->add_command(new MementoCommand<Locations>(*(_editor->session->locations()), &before, &after));
3148 _editor->commit_reversible_command ();
3154 case CreateTransportMarker:
3155 // popup menu to pick loop or punch
3156 _editor->new_transport_marker_context_menu (&event->button, _item);
3161 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3163 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3168 start = _editor->session->locations()->first_mark_before (_grab_frame);
3169 end = _editor->session->locations()->first_mark_after (_grab_frame);
3171 if (end == max_frames) {
3172 end = _editor->session->current_end_frame ();
3176 start = _editor->session->current_start_frame ();
3179 switch (_editor->mouse_mode) {
3181 /* find the two markers on either side and then make the selection from it */
3182 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3186 /* find the two markers on either side of the click and make the range out of it */
3187 _editor->selection->set (0, start, end);
3196 _editor->stop_canvas_autoscroll ();
3202 RangeMarkerBarDrag::update_item (Location* location)
3204 double const x1 = _editor->frame_to_pixel (location->start());
3205 double const x2 = _editor->frame_to_pixel (location->end());
3207 _drag_rect->property_x1() = x1;
3208 _drag_rect->property_x2() = x2;
3212 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3214 Drag::start_grab (event, _editor->zoom_cursor);
3215 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3219 MouseZoomDrag::motion (GdkEvent* event)
3224 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3225 _editor->snap_to (_current_pointer_frame);
3228 _editor->snap_to (_grab_frame);
3232 if (_current_pointer_frame == _last_pointer_frame) {
3236 /* base start and end on initial click position */
3237 if (_current_pointer_frame < _grab_frame) {
3238 start = _current_pointer_frame;
3241 end = _current_pointer_frame;
3242 start = _grab_frame;
3248 _editor->zoom_rect->show();
3249 _editor->zoom_rect->raise_to_top();
3252 _editor->reposition_zoom_rect(start, end);
3254 _last_pointer_frame = _current_pointer_frame;
3255 _first_move = false;
3257 _editor->show_verbose_time_cursor (_current_pointer_frame, 10);
3262 MouseZoomDrag::finished (GdkEvent* event)
3267 if (_grab_frame < _last_pointer_frame) {
3268 _editor->temporal_zoom_by_frame (_grab_frame, _last_pointer_frame, "mouse zoom");
3270 _editor->temporal_zoom_by_frame (_last_pointer_frame, _grab_frame, "mouse zoom");
3273 _editor->temporal_zoom_to_frame (false, _grab_frame);
3275 temporal_zoom_step (false);
3276 center_screen (_grab_frame);
3280 _editor->zoom_rect->hide();