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 #define __STDC_LIMIT_MACROS 1
22 #include "pbd/memento_command.h"
23 #include "pbd/basename.h"
24 #include "ardour/diskstream.h"
25 #include "ardour/region_command.h"
26 #include "ardour/session.h"
27 #include "ardour/dB.h"
28 #include "ardour/region_factory.h"
29 #include "ardour/midi_diskstream.h"
33 #include "audio_region_view.h"
34 #include "midi_region_view.h"
35 #include "ardour_ui.h"
36 #include "gui_thread.h"
37 #include "control_point.h"
39 #include "region_gain_line.h"
40 #include "editor_drag.h"
41 #include "audio_time_axis.h"
42 #include "midi_time_axis.h"
43 #include "canvas-note.h"
44 #include "selection.h"
45 #include "midi_selection.h"
46 #include "automation_time_axis.h"
49 using namespace ARDOUR;
52 using namespace Editing;
53 using namespace ArdourCanvas;
55 using Gtkmm2ext::Keyboard;
57 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
59 DragManager::DragManager (Editor* e)
62 , _current_pointer_frame (0)
67 DragManager::~DragManager ()
75 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
84 DragManager::break_drag ()
88 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
99 DragManager::add (Drag* d)
101 d->set_manager (this);
102 _drags.push_back (d);
106 DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
108 assert (_drags.empty ());
109 d->set_manager (this);
110 _drags.push_back (d);
115 DragManager::start_grab (GdkEvent* e)
117 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
119 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
120 (*i)->start_grab (e);
125 DragManager::end_grab (GdkEvent* e)
130 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
131 bool const t = (*i)->end_grab (e);
146 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
150 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
152 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
153 bool const t = (*i)->motion_handler (e, from_autoscroll);
164 DragManager::have_item (ArdourCanvas::Item* i) const
166 list<Drag*>::const_iterator j = _drags.begin ();
167 while (j != _drags.end() && (*j)->item () != i) {
171 return j != _drags.end ();
174 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
177 , _pointer_frame_offset (0)
178 , _move_threshold_passed (false)
180 , _last_pointer_frame (0)
186 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
192 cursor = _editor->which_grabber_cursor ();
195 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
199 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
202 cursor = _editor->which_grabber_cursor ();
205 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
207 if (Keyboard::is_button2_event (&event->button)) {
208 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
209 _y_constrained = true;
210 _x_constrained = false;
212 _y_constrained = false;
213 _x_constrained = true;
216 _x_constrained = false;
217 _y_constrained = false;
220 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
221 _grab_frame = adjusted_frame (_grab_frame, event);
222 _last_pointer_frame = _grab_frame;
223 _last_pointer_x = _grab_x;
224 _last_pointer_y = _grab_y;
226 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
230 if (_editor->session() && _editor->session()->transport_rolling()) {
233 _was_rolling = false;
236 switch (_editor->snap_type()) {
237 case SnapToRegionStart:
238 case SnapToRegionEnd:
239 case SnapToRegionSync:
240 case SnapToRegionBoundary:
241 _editor->build_region_boundary_cache ();
248 /** @param event GDK event, or 0.
249 * @return true if some movement occurred, otherwise false.
252 Drag::end_grab (GdkEvent* event)
254 _editor->stop_canvas_autoscroll ();
256 _item->ungrab (event ? event->button.time : 0);
258 finished (event, _move_threshold_passed);
260 _editor->hide_verbose_canvas_cursor();
262 return _move_threshold_passed;
266 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
270 if (f > _pointer_frame_offset) {
271 pos = f - _pointer_frame_offset;
275 _editor->snap_to_with_modifier (pos, event);
282 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
284 return adjusted_frame (_drags->current_pointer_frame (), event, snap);
288 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
290 /* check to see if we have moved in any way that matters since the last motion event */
291 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
292 (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
296 pair<nframes64_t, int> const threshold = move_threshold ();
298 bool const old_move_threshold_passed = _move_threshold_passed;
300 if (!from_autoscroll && !_move_threshold_passed) {
302 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
303 bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
305 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
308 if (active (_editor->mouse_mode) && _move_threshold_passed) {
310 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
311 if (!from_autoscroll) {
312 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
315 motion (event, _move_threshold_passed != old_move_threshold_passed);
317 _last_pointer_x = _drags->current_pointer_x ();
318 _last_pointer_y = _drags->current_pointer_y ();
319 _last_pointer_frame = adjusted_current_frame (event);
337 _editor->stop_canvas_autoscroll ();
338 _editor->hide_verbose_canvas_cursor ();
341 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
346 RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
350 RegionDrag::region_going_away (RegionView* v)
352 if (!_drags->ending ()) {
357 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
358 : RegionDrag (e, i, p, v),
369 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
371 Drag::start_grab (event);
373 _editor->show_verbose_time_cursor (_last_frame_position, 10);
376 RegionMotionDrag::TimeAxisViewSummary
377 RegionMotionDrag::get_time_axis_view_summary ()
379 int32_t children = 0;
380 TimeAxisViewSummary sum;
382 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
384 /* get a bitmask representing the visible tracks */
386 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
387 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
388 TimeAxisView::Children children_list;
390 /* zeroes are audio/MIDI tracks. ones are other types. */
392 if (!rtv->hidden()) {
394 if (!rtv->is_track()) {
395 /* not an audio nor MIDI track */
396 sum.tracks = sum.tracks |= (0x01 << rtv->order());
399 sum.height_list[rtv->order()] = (*i)->current_height();
402 if ((children_list = rtv->get_child_list()).size() > 0) {
403 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
404 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
405 sum.height_list[rtv->order() + children] = (*j)->current_height();
416 RegionMotionDrag::compute_y_delta (
417 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
418 int32_t last_pointer_layer, int32_t current_pointer_layer,
419 TimeAxisViewSummary const & tavs,
420 int32_t* pointer_order_span, int32_t* pointer_layer_span,
421 int32_t* canvas_pointer_order_span
425 *pointer_order_span = 0;
426 *pointer_layer_span = 0;
430 bool clamp_y_axis = false;
432 /* the change in track order between this callback and the last */
433 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
434 /* the change in layer between this callback and the last;
435 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
436 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
438 if (*pointer_order_span != 0) {
440 /* find the actual pointer span, in terms of the number of visible tracks;
441 to do this, we reduce |pointer_order_span| by the number of hidden tracks
444 *canvas_pointer_order_span = *pointer_order_span;
445 if (last_pointer_view->order() >= current_pointer_view->order()) {
446 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
447 if (tavs.height_list[y] == 0) {
448 *canvas_pointer_order_span--;
452 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
453 if (tavs.height_list[y] == 0) {
454 *canvas_pointer_order_span++;
459 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
461 RegionView* rv = (*i);
463 if (rv->region()->locked()) {
467 double ix1, ix2, iy1, iy2;
468 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
469 rv->get_canvas_frame()->i2w (ix1, iy1);
470 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
472 /* get the new trackview for this particular region */
473 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
475 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
477 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
478 as surely this is a per-region thing... */
480 clamp_y_axis = y_movement_disallowed (
481 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
489 } else if (_dest_trackview == current_pointer_view) {
491 if (current_pointer_layer == last_pointer_layer) {
492 /* No movement; clamp */
498 _dest_trackview = current_pointer_view;
499 _dest_layer = current_pointer_layer;
507 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
509 /* compute the amount of pointer motion in frames, and where
510 the region would be if we moved it by that much.
512 *pending_region_position = adjusted_current_frame (event);
514 nframes64_t sync_frame;
515 nframes64_t sync_offset;
518 sync_offset = _primary->region()->sync_offset (sync_dir);
520 /* we don't handle a sync point that lies before zero.
522 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
524 sync_frame = *pending_region_position + (sync_dir*sync_offset);
526 _editor->snap_to_with_modifier (sync_frame, event);
528 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
531 *pending_region_position = _last_frame_position;
534 if (*pending_region_position > max_frames - _primary->region()->length()) {
535 *pending_region_position = _last_frame_position;
540 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
542 /* now compute the canvas unit distance we need to move the regionview
543 to make it appear at the new location.
546 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
548 if (*pending_region_position <= _last_frame_position) {
550 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
552 RegionView* rv = (*i);
554 // If any regionview is at zero, we need to know so we can stop further leftward motion.
556 double ix1, ix2, iy1, iy2;
557 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
558 rv->get_canvas_frame()->i2w (ix1, iy1);
560 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
562 *pending_region_position = _last_frame_position;
569 _last_frame_position = *pending_region_position;
576 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
580 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
582 vector<int32_t>::iterator j;
584 /* *pointer* variables reflect things about the pointer; as we may be moving
585 multiple regions, much detail must be computed per-region */
587 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
588 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
589 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
590 is always 0 regardless of what the region's "real" layer is */
591 RouteTimeAxisView* current_pointer_view;
592 layer_t current_pointer_layer;
593 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
597 /* TimeAxisView that we were pointing at last time we entered this method */
598 TimeAxisView const * const last_pointer_view = _dest_trackview;
599 /* the order of the track that we were pointing at last time we entered this method */
600 int32_t const last_pointer_order = last_pointer_view->order ();
601 /* the layer that we were pointing at last time we entered this method */
602 layer_t const last_pointer_layer = _dest_layer;
604 int32_t pointer_order_span;
605 int32_t pointer_layer_span;
606 int32_t canvas_pointer_order_span;
608 bool const clamp_y_axis = compute_y_delta (
609 last_pointer_view, current_pointer_view,
610 last_pointer_layer, current_pointer_layer, tavs,
611 &pointer_order_span, &pointer_layer_span,
612 &canvas_pointer_order_span
615 nframes64_t pending_region_position;
616 double const x_delta = compute_x_delta (event, &pending_region_position);
618 /*************************************************************
620 ************************************************************/
622 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
623 /* haven't reached next snap point, and we're not switching
624 trackviews nor layers. nothing to do.
629 /*************************************************************
631 ************************************************************/
633 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
635 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
637 RegionView* rv = (*i);
639 if (rv->region()->locked()) {
643 /* here we are calculating the y distance from the
644 top of the first track view to the top of the region
645 area of the track view that we're working on */
647 /* this x value is just a dummy value so that we have something
652 /* distance from the top of this track view to the region area
653 of our track view is always 1 */
657 /* convert to world coordinates, ie distance from the top of
660 rv->get_canvas_frame()->i2w (ix1, iy1);
662 /* compensate for the ruler section and the vertical scrollbar position */
663 iy1 += _editor->get_trackview_group_vertical_offset ();
667 // hide any dependent views
669 rv->get_time_axis_view().hide_dependent_views (*rv);
672 reparent to a non scrolling group so that we can keep the
673 region selection above all time axis views.
674 reparenting means we have to move the rv as the two
675 parent groups have different coordinates.
678 rv->get_canvas_group()->property_y() = iy1 - 1;
679 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
681 rv->fake_set_opaque (true);
684 /* current view for this particular region */
685 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
686 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
688 if (pointer_order_span != 0 && !clamp_y_axis) {
690 /* INTER-TRACK MOVEMENT */
692 /* move through the height list to the track that the region is currently on */
693 vector<int32_t>::iterator j = tavs.height_list.begin ();
695 while (j != tavs.height_list.end () && x != rtv->order ()) {
701 int32_t temp_pointer_order_span = canvas_pointer_order_span;
703 if (j != tavs.height_list.end ()) {
705 /* Account for layers in the original and
706 destination tracks. If we're moving around in layers we assume
707 that only one track is involved, so it's ok to use *pointer*
710 StreamView* lv = last_pointer_view->view ();
713 /* move to the top of the last trackview */
714 if (lv->layer_display () == Stacked) {
715 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
718 StreamView* cv = current_pointer_view->view ();
721 /* move to the right layer on the current trackview */
722 if (cv->layer_display () == Stacked) {
723 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
726 /* And for being on a non-topmost layer on the new
729 while (temp_pointer_order_span > 0) {
730 /* we're moving up canvas-wise,
731 so we need to find the next track height
733 if (j != tavs.height_list.begin()) {
737 if (x != last_pointer_order) {
739 ++temp_pointer_order_span;
744 temp_pointer_order_span--;
747 while (temp_pointer_order_span < 0) {
751 if (x != last_pointer_order) {
753 --temp_pointer_order_span;
757 if (j != tavs.height_list.end()) {
761 temp_pointer_order_span++;
765 /* find out where we'll be when we move and set height accordingly */
767 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
768 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
769 rv->set_height (temp_rtv->view()->child_height());
771 /* if you un-comment the following, the region colours will follow
772 the track colours whilst dragging; personally
773 i think this can confuse things, but never mind.
776 //const GdkColor& col (temp_rtv->view->get_region_color());
777 //rv->set_color (const_cast<GdkColor&>(col));
781 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
783 /* INTER-LAYER MOVEMENT in the same track */
784 y_delta = rtv->view()->child_height () * pointer_layer_span;
789 _editor->mouse_brush_insert_region (rv, pending_region_position);
791 rv->move (x_delta, y_delta);
794 } /* foreach region */
796 _total_x_delta += x_delta;
799 _editor->cursor_group->raise_to_top();
802 if (x_delta != 0 && !_brushing) {
803 _editor->show_verbose_time_cursor (_last_frame_position, 10);
808 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
810 if (_copy && first_move) {
811 copy_regions (event);
814 RegionMotionDrag::motion (event, first_move);
818 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
820 vector<RegionView*> copies;
821 boost::shared_ptr<Diskstream> ds;
822 boost::shared_ptr<Playlist> from_playlist;
823 RegionSelection new_views;
824 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
825 PlaylistSet modified_playlists;
826 PlaylistSet frozen_playlists;
827 list <sigc::connection> modified_playlist_connections;
828 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
829 nframes64_t drag_delta;
830 bool changed_tracks, changed_position;
831 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
832 RouteTimeAxisView* source_tv;
834 if (!movement_occurred) {
840 /* all changes were made during motion event handlers */
843 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
844 copies.push_back (*i);
851 /* reverse this here so that we have the correct logic to finalize
855 if (Config->get_edit_mode() == Lock) {
856 _x_constrained = !_x_constrained;
860 if (_x_constrained) {
861 _editor->begin_reversible_command (_("fixed time region copy"));
863 _editor->begin_reversible_command (_("region copy"));
866 if (_x_constrained) {
867 _editor->begin_reversible_command (_("fixed time region drag"));
869 _editor->begin_reversible_command (_("region drag"));
873 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
874 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
876 drag_delta = _primary->region()->position() - _last_frame_position;
878 _editor->update_canvas_now ();
880 /* make a list of where each region ended up */
881 final = find_time_axis_views_and_layers ();
883 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
885 RegionView* rv = (*i);
886 RouteTimeAxisView* dest_rtv = final[*i].first;
887 layer_t dest_layer = final[*i].second;
891 if (rv->region()->locked()) {
896 if (changed_position && !_x_constrained) {
897 where = rv->region()->position() - drag_delta;
899 where = rv->region()->position();
902 boost::shared_ptr<Region> new_region;
905 /* we already made a copy */
906 new_region = rv->region();
908 /* undo the previous hide_dependent_views so that xfades don't
909 disappear on copying regions
912 //rv->get_time_axis_view().reveal_dependent_views (*rv);
914 } else if (changed_tracks && dest_rtv->playlist()) {
915 new_region = RegionFactory::create (rv->region());
918 if (changed_tracks || _copy) {
920 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
927 _editor->latest_regionviews.clear ();
929 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
931 insert_result = modified_playlists.insert (to_playlist);
933 if (insert_result.second) {
934 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
937 to_playlist->add_region (new_region, where);
938 if (dest_rtv->view()->layer_display() == Stacked) {
939 new_region->set_layer (dest_layer);
940 new_region->set_pending_explicit_relayer (true);
945 if (!_editor->latest_regionviews.empty()) {
946 // XXX why just the first one ? we only expect one
947 // commented out in nick_m's canvas reworking. is that intended?
948 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
949 new_views.push_back (_editor->latest_regionviews.front());
953 RegionCommand* rcmd = new RegionCommand (rv->region());
956 motion on the same track. plonk the previously reparented region
957 back to its original canvas group (its streamview).
958 No need to do anything for copies as they are fake regions which will be deleted.
961 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
962 rv->get_canvas_group()->property_y() = 0;
963 rv->get_time_axis_view().reveal_dependent_views (*rv);
965 /* just change the model */
967 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
969 if (dest_rtv->view()->layer_display() == Stacked) {
970 layer_t old_layer = rv->region()->layer();
971 rv->region()->set_layer (dest_layer);
972 rv->region()->set_pending_explicit_relayer (true);
973 rcmd->add_property_change (RegionCommand::Layer, old_layer, dest_layer);
976 /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
978 frozen_insert_result = frozen_playlists.insert(playlist);
980 if (frozen_insert_result.second) {
984 nframes64_t old_pos = rv->region()->position();
985 rv->region()->set_position (where, (void*) this);
986 rcmd->add_property_change (RegionCommand::Position, old_pos, where);
988 _editor->session()->add_command (rcmd);
991 if (changed_tracks && !_copy) {
993 /* get the playlist where this drag started. we can't use rv->region()->playlist()
994 because we may have copied the region and it has not been attached to a playlist.
997 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
998 ds = source_tv->get_diskstream();
999 from_playlist = ds->playlist();
1003 assert (from_playlist);
1005 /* moved to a different audio track, without copying */
1007 /* the region that used to be in the old playlist is not
1008 moved to the new one - we use a copy of it. as a result,
1009 any existing editor for the region should no longer be
1013 rv->hide_region_editor();
1014 rv->fake_set_opaque (false);
1016 /* remove the region from the old playlist */
1018 insert_result = modified_playlists.insert (from_playlist);
1020 if (insert_result.second) {
1021 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
1024 from_playlist->remove_region (rv->region());
1026 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1027 was selected in all of them, then removing it from a playlist will have removed all
1028 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1029 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1030 corresponding regionview, and the selection is now empty).
1032 this could have invalidated any and all iterators into the region selection.
1034 the heuristic we use here is: if the region selection is empty, break out of the loop
1035 here. if the region selection is not empty, then restart the loop because we know that
1036 we must have removed at least the region(view) we've just been working on as well as any
1037 that we processed on previous iterations.
1039 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1040 we can just iterate.
1043 if (_views.empty()) {
1054 copies.push_back (rv);
1058 if we've created new regions either by copying or moving
1059 to a new track, we want to replace the old selection with the new ones
1061 if (new_views.size() > 0) {
1062 _editor->selection->set (new_views);
1065 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1070 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
1071 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
1074 _editor->commit_reversible_command ();
1076 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1082 RegionMoveDrag::aborted ()
1086 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1093 RegionMotionDrag::aborted ();
1098 RegionMotionDrag::aborted ()
1100 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1101 TimeAxisView* tv = &(*i)->get_time_axis_view ();
1102 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1104 (*i)->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1105 (*i)->get_canvas_group()->property_y() = 0;
1106 (*i)->get_time_axis_view().reveal_dependent_views (**i);
1107 (*i)->fake_set_opaque (false);
1108 (*i)->move (-_total_x_delta, 0);
1109 (*i)->set_height (rtv->view()->child_height ());
1112 _editor->update_canvas_now ();
1117 RegionMotionDrag::x_move_allowed () const
1119 if (Config->get_edit_mode() == Lock) {
1120 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1121 return _x_constrained;
1124 return !_x_constrained;
1128 RegionMotionDrag::copy_regions (GdkEvent* event)
1130 /* duplicate the regionview(s) and region(s) */
1132 list<RegionView*> new_regionviews;
1134 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1136 RegionView* rv = (*i);
1137 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1138 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1140 const boost::shared_ptr<const Region> original = rv->region();
1141 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1145 boost::shared_ptr<AudioRegion> audioregion_copy
1146 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1147 nrv = new AudioRegionView (*arv, audioregion_copy);
1149 boost::shared_ptr<MidiRegion> midiregion_copy
1150 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1151 nrv = new MidiRegionView (*mrv, midiregion_copy);
1156 nrv->get_canvas_group()->show ();
1157 new_regionviews.push_back (nrv);
1159 /* swap _primary to the copy */
1161 if (rv == _primary) {
1165 /* ..and deselect the one we copied */
1167 rv->set_selected (false);
1170 if (new_regionviews.empty()) {
1174 /* reflect the fact that we are dragging the copies */
1176 _views = new_regionviews;
1178 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1181 sync the canvas to what we think is its current state
1182 without it, the canvas seems to
1183 "forget" to update properly after the upcoming reparent()
1184 ..only if the mouse is in rapid motion at the time of the grab.
1185 something to do with regionview creation taking so long?
1187 _editor->update_canvas_now();
1191 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1193 /* Which trackview is this ? */
1195 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1196 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1197 (*layer) = tvp.second;
1199 if (*tv && (*tv)->layer_display() == Overlaid) {
1203 /* The region motion is only processed if the pointer is over
1207 if (!(*tv) || !(*tv)->is_track()) {
1208 /* To make sure we hide the verbose canvas cursor when the mouse is
1209 not held over and audiotrack.
1211 _editor->hide_verbose_canvas_cursor ();
1218 /** @param new_order New track order.
1219 * @param old_order Old track order.
1220 * @param visible_y_low Lowest visible order.
1221 * @return true if y movement should not happen, otherwise false.
1224 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1226 if (new_order != old_order) {
1228 /* this isn't the pointer track */
1232 /* moving up the canvas */
1233 if ( (new_order - y_span) >= tavs.visible_y_low) {
1237 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1238 int32_t visible_tracks = 0;
1239 while (visible_tracks < y_span ) {
1241 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1242 /* passing through a hidden track */
1247 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1248 /* moving to a non-track; disallow */
1254 /* moving beyond the lowest visible track; disallow */
1258 } else if (y_span < 0) {
1260 /* moving down the canvas */
1261 if ((new_order - y_span) <= tavs.visible_y_high) {
1263 int32_t visible_tracks = 0;
1265 while (visible_tracks > y_span ) {
1268 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1269 /* passing through a hidden track */
1274 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1275 /* moving to a non-track; disallow */
1282 /* moving beyond the highest visible track; disallow */
1289 /* this is the pointer's track */
1291 if ((new_order - y_span) > tavs.visible_y_high) {
1292 /* we will overflow */
1294 } else if ((new_order - y_span) < tavs.visible_y_low) {
1295 /* we will overflow */
1304 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1305 : RegionMotionDrag (e, i, p, v, b),
1308 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1310 _dest_trackview = tv;
1311 if (tv->layer_display() == Overlaid) {
1314 _dest_layer = _primary->region()->layer ();
1318 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1319 if (rtv && rtv->is_track()) {
1320 speed = rtv->get_diskstream()->speed ();
1323 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1327 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1329 RegionMotionDrag::start_grab (event, c);
1331 _pointer_frame_offset = grab_frame() - _last_frame_position;
1334 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1335 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1337 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1338 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1340 _primary = v->view()->create_region_view (r, false, false);
1342 _primary->get_canvas_group()->show ();
1343 _primary->set_position (pos, 0);
1344 _views.push_back (_primary);
1346 _last_frame_position = pos;
1348 _item = _primary->get_canvas_group ();
1349 _dest_trackview = v;
1350 _dest_layer = _primary->region()->layer ();
1353 map<RegionView*, pair<RouteTimeAxisView*, int> >
1354 RegionMotionDrag::find_time_axis_views_and_layers ()
1356 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1358 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1360 double ix1, ix2, iy1, iy2;
1361 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1362 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1363 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1365 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1366 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1374 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1376 _editor->update_canvas_now ();
1378 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1380 RouteTimeAxisView* dest_rtv = final[_primary].first;
1382 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1383 _primary->get_canvas_group()->property_y() = 0;
1385 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1387 _editor->begin_reversible_command (_("insert region"));
1388 XMLNode& before = playlist->get_state ();
1389 playlist->add_region (_primary->region (), _last_frame_position);
1390 _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1391 _editor->commit_reversible_command ();
1399 RegionInsertDrag::aborted ()
1404 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1405 : RegionMoveDrag (e, i, p, v, false, false)
1410 struct RegionSelectionByPosition {
1411 bool operator() (RegionView*a, RegionView* b) {
1412 return a->region()->position () < b->region()->position();
1417 RegionSpliceDrag::motion (GdkEvent* event, bool)
1419 RouteTimeAxisView* tv;
1422 if (!check_possible (&tv, &layer)) {
1428 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1434 RegionSelection copy (_editor->selection->regions);
1436 RegionSelectionByPosition cmp;
1439 nframes64_t const pf = adjusted_current_frame (event);
1441 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1443 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1449 boost::shared_ptr<Playlist> playlist;
1451 if ((playlist = atv->playlist()) == 0) {
1455 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1460 if (pf < (*i)->region()->last_frame() + 1) {
1464 if (pf > (*i)->region()->first_frame()) {
1470 playlist->shuffle ((*i)->region(), dir);
1475 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1481 RegionSpliceDrag::aborted ()
1486 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1494 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1496 _dest_trackview = _view;
1498 Drag::start_grab (event);
1503 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1506 // TODO: create region-create-drag region view here
1509 // TODO: resize region-create-drag region view here
1513 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1515 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1521 if (!movement_occurred) {
1522 mtv->add_region (grab_frame ());
1524 motion (event, false);
1525 // TODO: create region-create-drag region here
1530 RegionCreateDrag::aborted ()
1535 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1543 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1546 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1548 Drag::start_grab (event);
1550 region = &cnote->region_view();
1552 double region_start = region->get_position_pixels();
1553 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1555 if (grab_x() <= middle_point) {
1556 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1559 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1563 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1565 if (event->motion.state & Keyboard::PrimaryModifier) {
1571 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1573 if (ms.size() > 1) {
1574 /* has to be relative, may make no sense otherwise */
1578 region->note_selected (cnote, true);
1580 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1581 MidiRegionSelection::iterator next;
1584 (*r)->begin_resizing (at_front);
1590 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1592 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1593 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1594 (*r)->update_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1599 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1601 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1602 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1603 (*r)->commit_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1608 NoteResizeDrag::aborted ()
1614 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1620 RegionGainDrag::finished (GdkEvent *, bool)
1626 RegionGainDrag::aborted ()
1631 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1632 : RegionDrag (e, i, p, v)
1633 , _have_transaction (false)
1639 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1642 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1643 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1645 if (tv && tv->is_track()) {
1646 speed = tv->get_diskstream()->speed();
1649 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1650 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1651 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1653 Drag::start_grab (event, _editor->trimmer_cursor);
1655 nframes64_t const pf = adjusted_current_frame (event);
1657 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1658 _operation = ContentsTrim;
1660 /* These will get overridden for a point trim.*/
1661 if (pf < (region_start + region_length/2)) {
1662 /* closer to start */
1663 _operation = StartTrim;
1664 } else if (pf > (region_end - region_length/2)) {
1666 _operation = EndTrim;
1670 switch (_operation) {
1672 _editor->show_verbose_time_cursor (region_start, 10);
1675 _editor->show_verbose_time_cursor (region_end, 10);
1678 _editor->show_verbose_time_cursor (pf, 10);
1684 TrimDrag::motion (GdkEvent* event, bool first_move)
1686 RegionView* rv = _primary;
1687 nframes64_t frame_delta = 0;
1689 bool left_direction;
1690 bool obey_snap = event ? !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) : false;
1692 /* snap modifier works differently here..
1693 its current state has to be passed to the
1694 various trim functions in order to work properly
1698 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1699 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1700 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1702 if (tv && tv->is_track()) {
1703 speed = tv->get_diskstream()->speed();
1706 nframes64_t const pf = adjusted_current_frame (event);
1708 if (last_pointer_frame() > pf) {
1709 left_direction = true;
1711 left_direction = false;
1718 switch (_operation) {
1720 trim_type = "Region start trim";
1723 trim_type = "Region end trim";
1726 trim_type = "Region content trim";
1730 _editor->begin_reversible_command (trim_type);
1731 _have_transaction = true;
1733 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1734 (*i)->fake_set_opaque(false);
1735 (*i)->region()->freeze ();
1737 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1740 arv->temporarily_hide_envelope ();
1743 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1744 insert_result = _editor->motion_frozen_playlists.insert (pl);
1746 if (insert_result.second) {
1747 _editor->session()->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1753 if (left_direction) {
1754 frame_delta = (last_pointer_frame() - pf);
1756 frame_delta = (pf - last_pointer_frame());
1759 bool non_overlap_trim = false;
1761 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1762 non_overlap_trim = true;
1765 switch (_operation) {
1767 if ((left_direction == false) && (pf <= rv->region()->first_frame()/speed)) {
1771 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1772 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1778 if ((left_direction == true) && (pf > (nframes64_t) (rv->region()->last_frame()/speed))) {
1782 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1783 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1790 bool swap_direction = false;
1792 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1793 swap_direction = true;
1796 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1797 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1803 switch (_operation) {
1805 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1808 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1811 _editor->show_verbose_time_cursor (pf, 10);
1818 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1820 if (movement_occurred) {
1821 motion (event, false);
1823 if (!_editor->selection->selected (_primary)) {
1824 _editor->thaw_region_after_trim (*_primary);
1827 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1828 _editor->thaw_region_after_trim (**i);
1829 (*i)->fake_set_opaque (true);
1832 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1834 if (_have_transaction) {
1835 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1839 _editor->motion_frozen_playlists.clear ();
1841 if (_have_transaction) {
1842 _editor->commit_reversible_command();
1846 /* no mouse movement */
1847 _editor->point_trim (event, adjusted_current_frame (event));
1852 TrimDrag::aborted ()
1854 /* Our motion method is changing model state, so use the Undo system
1855 to cancel. Perhaps not ideal, as this will leave an Undo point
1856 behind which may be slightly odd from the user's point of view.
1861 if (_have_transaction) {
1866 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1870 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1875 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1878 // create a dummy marker for visual representation of moving the copy.
1879 // The actual copying is not done before we reach the finish callback.
1881 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1882 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1883 *new MeterSection (_marker->meter()));
1885 _item = &new_marker->the_item ();
1886 _marker = new_marker;
1890 MetricSection& section (_marker->meter());
1892 if (!section.movable()) {
1898 Drag::start_grab (event, cursor);
1900 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1902 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1906 MeterMarkerDrag::motion (GdkEvent* event, bool)
1908 nframes64_t const pf = adjusted_current_frame (event);
1910 _marker->set_position (pf);
1912 _editor->show_verbose_time_cursor (pf, 10);
1916 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1918 if (!movement_occurred) {
1922 motion (event, false);
1926 TempoMap& map (_editor->session()->tempo_map());
1927 map.bbt_time (last_pointer_frame(), when);
1929 if (_copy == true) {
1930 _editor->begin_reversible_command (_("copy meter mark"));
1931 XMLNode &before = map.get_state();
1932 map.add_meter (_marker->meter(), when);
1933 XMLNode &after = map.get_state();
1934 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1935 _editor->commit_reversible_command ();
1937 // delete the dummy marker we used for visual representation of copying.
1938 // a new visual marker will show up automatically.
1941 _editor->begin_reversible_command (_("move meter mark"));
1942 XMLNode &before = map.get_state();
1943 map.move_meter (_marker->meter(), when);
1944 XMLNode &after = map.get_state();
1945 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1946 _editor->commit_reversible_command ();
1951 MeterMarkerDrag::aborted ()
1953 _marker->set_position (_marker->meter().frame ());
1956 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1960 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1965 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1970 // create a dummy marker for visual representation of moving the copy.
1971 // The actual copying is not done before we reach the finish callback.
1973 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1974 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1975 *new TempoSection (_marker->tempo()));
1977 _item = &new_marker->the_item ();
1978 _marker = new_marker;
1982 MetricSection& section (_marker->tempo());
1984 if (!section.movable()) {
1989 Drag::start_grab (event, cursor);
1991 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
1992 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
1996 TempoMarkerDrag::motion (GdkEvent* event, bool)
1998 nframes64_t const pf = adjusted_current_frame (event);
1999 _marker->set_position (pf);
2000 _editor->show_verbose_time_cursor (pf, 10);
2004 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2006 if (!movement_occurred) {
2010 motion (event, false);
2014 TempoMap& map (_editor->session()->tempo_map());
2015 map.bbt_time (last_pointer_frame(), when);
2017 if (_copy == true) {
2018 _editor->begin_reversible_command (_("copy tempo mark"));
2019 XMLNode &before = map.get_state();
2020 map.add_tempo (_marker->tempo(), when);
2021 XMLNode &after = map.get_state();
2022 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2023 _editor->commit_reversible_command ();
2025 // delete the dummy marker we used for visual representation of copying.
2026 // a new visual marker will show up automatically.
2029 _editor->begin_reversible_command (_("move tempo mark"));
2030 XMLNode &before = map.get_state();
2031 map.move_tempo (_marker->tempo(), when);
2032 XMLNode &after = map.get_state();
2033 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2034 _editor->commit_reversible_command ();
2039 TempoMarkerDrag::aborted ()
2041 _marker->set_position (_marker->tempo().frame());
2044 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2048 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2053 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2055 Drag::start_grab (event, c);
2059 nframes64_t where = _editor->event_frame (event, 0, 0);
2061 _editor->snap_to_with_modifier (where, event);
2062 _editor->playhead_cursor->set_position (where);
2066 if (_cursor == _editor->playhead_cursor) {
2067 _editor->_dragging_playhead = true;
2069 if (_editor->session() && _was_rolling && _stop) {
2070 _editor->session()->request_stop ();
2073 if (_editor->session() && _editor->session()->is_auditioning()) {
2074 _editor->session()->cancel_audition ();
2078 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2080 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2084 CursorDrag::motion (GdkEvent* event, bool)
2086 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2088 if (adjusted_frame == last_pointer_frame()) {
2092 _cursor->set_position (adjusted_frame);
2094 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2097 _editor->update_canvas_now ();
2099 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2103 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2105 _editor->_dragging_playhead = false;
2107 if (!movement_occurred && _stop) {
2111 motion (event, false);
2113 if (_item == &_editor->playhead_cursor->canvas_item) {
2114 if (_editor->session()) {
2115 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2116 _editor->_pending_locate_request = true;
2122 CursorDrag::aborted ()
2124 _editor->_dragging_playhead = false;
2125 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2128 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2129 : RegionDrag (e, i, p, v)
2135 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2137 Drag::start_grab (event, cursor);
2139 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2140 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2142 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2143 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2147 FadeInDrag::motion (GdkEvent* event, bool)
2149 nframes64_t fade_length;
2151 nframes64_t const pos = adjusted_current_frame (event);
2153 boost::shared_ptr<Region> region = _primary->region ();
2155 if (pos < (region->position() + 64)) {
2156 fade_length = 64; // this should be a minimum defined somewhere
2157 } else if (pos > region->last_frame()) {
2158 fade_length = region->length();
2160 fade_length = pos - region->position();
2163 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2165 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2171 tmp->reset_fade_in_shape_width (fade_length);
2174 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2178 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2180 if (!movement_occurred) {
2184 nframes64_t fade_length;
2186 nframes64_t const pos = adjusted_current_frame (event);
2188 boost::shared_ptr<Region> region = _primary->region ();
2190 if (pos < (region->position() + 64)) {
2191 fade_length = 64; // this should be a minimum defined somewhere
2192 } else if (pos > region->last_frame()) {
2193 fade_length = region->length();
2195 fade_length = pos - region->position();
2198 _editor->begin_reversible_command (_("change fade in length"));
2200 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2202 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2208 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2209 XMLNode &before = alist->get_state();
2211 tmp->audio_region()->set_fade_in_length (fade_length);
2212 tmp->audio_region()->set_fade_in_active (true);
2214 XMLNode &after = alist->get_state();
2215 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2218 _editor->commit_reversible_command ();
2222 FadeInDrag::aborted ()
2224 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2225 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2231 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2235 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2236 : RegionDrag (e, i, p, v)
2242 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2244 Drag::start_grab (event, cursor);
2246 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2247 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2249 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2250 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2254 FadeOutDrag::motion (GdkEvent* event, bool)
2256 nframes64_t fade_length;
2258 nframes64_t const pos = adjusted_current_frame (event);
2260 boost::shared_ptr<Region> region = _primary->region ();
2262 if (pos > (region->last_frame() - 64)) {
2263 fade_length = 64; // this should really be a minimum fade defined somewhere
2265 else if (pos < region->position()) {
2266 fade_length = region->length();
2269 fade_length = region->last_frame() - pos;
2272 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2274 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2280 tmp->reset_fade_out_shape_width (fade_length);
2283 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2287 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2289 if (!movement_occurred) {
2293 nframes64_t fade_length;
2295 nframes64_t const pos = adjusted_current_frame (event);
2297 boost::shared_ptr<Region> region = _primary->region ();
2299 if (pos > (region->last_frame() - 64)) {
2300 fade_length = 64; // this should really be a minimum fade defined somewhere
2302 else if (pos < region->position()) {
2303 fade_length = region->length();
2306 fade_length = region->last_frame() - pos;
2309 _editor->begin_reversible_command (_("change fade out length"));
2311 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2313 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2319 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2320 XMLNode &before = alist->get_state();
2322 tmp->audio_region()->set_fade_out_length (fade_length);
2323 tmp->audio_region()->set_fade_out_active (true);
2325 XMLNode &after = alist->get_state();
2326 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2329 _editor->commit_reversible_command ();
2333 FadeOutDrag::aborted ()
2335 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2336 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2342 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2346 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2349 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2352 _points.push_back (Gnome::Art::Point (0, 0));
2353 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2355 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2356 _line->property_width_pixels() = 1;
2357 _line->property_points () = _points;
2360 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2363 MarkerDrag::~MarkerDrag ()
2365 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2371 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2373 Drag::start_grab (event, cursor);
2377 Location *location = _editor->find_location_from_marker (_marker, is_start);
2378 _editor->_dragging_edit_point = true;
2380 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2382 update_item (location);
2384 // _drag_line->show();
2385 // _line->raise_to_top();
2388 _editor->show_verbose_time_cursor (location->start(), 10);
2390 _editor->show_verbose_time_cursor (location->end(), 10);
2393 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2396 case Selection::Toggle:
2397 _editor->selection->toggle (_marker);
2399 case Selection::Set:
2400 if (!_editor->selection->selected (_marker)) {
2401 _editor->selection->set (_marker);
2404 case Selection::Extend:
2406 Locations::LocationList ll;
2407 list<Marker*> to_add;
2409 _editor->selection->markers.range (s, e);
2410 s = min (_marker->position(), s);
2411 e = max (_marker->position(), e);
2414 if (e < max_frames) {
2417 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2418 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2419 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2422 to_add.push_back (lm->start);
2425 to_add.push_back (lm->end);
2429 if (!to_add.empty()) {
2430 _editor->selection->add (to_add);
2434 case Selection::Add:
2435 _editor->selection->add (_marker);
2439 /* set up copies for us to manipulate during the drag */
2441 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2442 Location *l = _editor->find_location_from_marker (*i, is_start);
2443 _copied_locations.push_back (new Location (*l));
2448 MarkerDrag::motion (GdkEvent* event, bool)
2450 nframes64_t f_delta = 0;
2452 bool move_both = false;
2454 Location *real_location;
2455 Location *copy_location = 0;
2457 nframes64_t const newframe = adjusted_current_frame (event);
2459 nframes64_t next = newframe;
2461 if (newframe == last_pointer_frame()) {
2465 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2469 MarkerSelection::iterator i;
2470 list<Location*>::iterator x;
2472 /* find the marker we're dragging, and compute the delta */
2474 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2475 x != _copied_locations.end() && i != _editor->selection->markers.end();
2481 if (marker == _marker) {
2483 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2488 if (real_location->is_mark()) {
2489 f_delta = newframe - copy_location->start();
2493 switch (marker->type()) {
2495 case Marker::LoopStart:
2496 case Marker::PunchIn:
2497 f_delta = newframe - copy_location->start();
2501 case Marker::LoopEnd:
2502 case Marker::PunchOut:
2503 f_delta = newframe - copy_location->end();
2506 /* what kind of marker is this ? */
2514 if (i == _editor->selection->markers.end()) {
2515 /* hmm, impossible - we didn't find the dragged marker */
2519 /* now move them all */
2521 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2522 x != _copied_locations.end() && i != _editor->selection->markers.end();
2528 /* call this to find out if its the start or end */
2530 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2534 if (real_location->locked()) {
2538 if (copy_location->is_mark()) {
2542 copy_location->set_start (copy_location->start() + f_delta);
2546 nframes64_t new_start = copy_location->start() + f_delta;
2547 nframes64_t new_end = copy_location->end() + f_delta;
2549 if (is_start) { // start-of-range marker
2552 copy_location->set_start (new_start);
2553 copy_location->set_end (new_end);
2554 } else if (new_start < copy_location->end()) {
2555 copy_location->set_start (new_start);
2557 _editor->snap_to (next, 1, true);
2558 copy_location->set_end (next);
2559 copy_location->set_start (newframe);
2562 } else { // end marker
2565 copy_location->set_end (new_end);
2566 copy_location->set_start (new_start);
2567 } else if (new_end > copy_location->start()) {
2568 copy_location->set_end (new_end);
2569 } else if (newframe > 0) {
2570 _editor->snap_to (next, -1, true);
2571 copy_location->set_start (next);
2572 copy_location->set_end (newframe);
2577 update_item (copy_location);
2579 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2582 lm->set_position (copy_location->start(), copy_location->end());
2586 assert (!_copied_locations.empty());
2588 _editor->show_verbose_time_cursor (newframe, 10);
2591 _editor->update_canvas_now ();
2596 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2598 if (!movement_occurred) {
2600 /* just a click, do nothing but finish
2601 off the selection process
2604 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2607 case Selection::Set:
2608 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2609 _editor->selection->set (_marker);
2613 case Selection::Toggle:
2614 case Selection::Extend:
2615 case Selection::Add:
2622 _editor->_dragging_edit_point = false;
2624 _editor->begin_reversible_command ( _("move marker") );
2625 XMLNode &before = _editor->session()->locations()->get_state();
2627 MarkerSelection::iterator i;
2628 list<Location*>::iterator x;
2631 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2632 x != _copied_locations.end() && i != _editor->selection->markers.end();
2635 Location * location = _editor->find_location_from_marker (*i, is_start);
2639 if (location->locked()) {
2643 if (location->is_mark()) {
2644 location->set_start ((*x)->start());
2646 location->set ((*x)->start(), (*x)->end());
2651 XMLNode &after = _editor->session()->locations()->get_state();
2652 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2653 _editor->commit_reversible_command ();
2659 MarkerDrag::aborted ()
2665 MarkerDrag::update_item (Location* location)
2667 double const x1 = _editor->frame_to_pixel (location->start());
2669 _points.front().set_x(x1);
2670 _points.back().set_x(x1);
2671 _line->property_points() = _points;
2674 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2676 _cumulative_x_drag (0),
2677 _cumulative_y_drag (0)
2679 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2685 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2687 Drag::start_grab (event, _editor->fader_cursor);
2689 // start the grab at the center of the control point so
2690 // the point doesn't 'jump' to the mouse after the first drag
2691 _time_axis_view_grab_x = _point->get_x();
2692 _time_axis_view_grab_y = _point->get_y();
2694 float const fraction = 1 - (_point->get_y() / _point->line().height());
2696 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2698 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2699 event->button.x + 10, event->button.y + 10);
2701 _editor->show_verbose_canvas_cursor ();
2705 ControlPointDrag::motion (GdkEvent* event, bool)
2707 double dx = _drags->current_pointer_x() - last_pointer_x();
2708 double dy = _drags->current_pointer_y() - last_pointer_y();
2710 if (event->button.state & Keyboard::SecondaryModifier) {
2715 /* coordinate in TimeAxisView's space */
2716 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2717 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2719 // calculate zero crossing point. back off by .01 to stay on the
2720 // positive side of zero
2721 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2723 // make sure we hit zero when passing through
2724 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2728 if (_x_constrained) {
2729 cx = _time_axis_view_grab_x;
2731 if (_y_constrained) {
2732 cy = _time_axis_view_grab_y;
2735 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2736 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2740 cy = min ((double) _point->line().height(), cy);
2742 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2744 if (!_x_constrained) {
2745 _editor->snap_to_with_modifier (cx_frames, event);
2748 float const fraction = 1.0 - (cy / _point->line().height());
2750 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2752 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2754 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2758 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2760 if (!movement_occurred) {
2764 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2765 _editor->reset_point_selection ();
2769 motion (event, false);
2771 _point->line().end_drag ();
2775 ControlPointDrag::aborted ()
2777 _point->line().reset ();
2781 ControlPointDrag::active (Editing::MouseMode m)
2783 if (m == Editing::MouseGain) {
2784 /* always active in mouse gain */
2788 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2789 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2792 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2795 _cumulative_y_drag (0)
2800 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2802 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2805 _item = &_line->grab_item ();
2807 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2808 origin, and ditto for y.
2811 double cx = event->button.x;
2812 double cy = event->button.y;
2814 _line->parent_group().w2i (cx, cy);
2816 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2821 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2822 /* no adjacent points */
2826 Drag::start_grab (event, _editor->fader_cursor);
2828 /* store grab start in parent frame */
2830 _time_axis_view_grab_x = cx;
2831 _time_axis_view_grab_y = cy;
2833 double fraction = 1.0 - (cy / _line->height());
2835 _line->start_drag_line (before, after, fraction);
2837 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2838 event->button.x + 10, event->button.y + 10);
2840 _editor->show_verbose_canvas_cursor ();
2844 LineDrag::motion (GdkEvent* event, bool)
2846 double dy = _drags->current_pointer_y() - last_pointer_y();
2848 if (event->button.state & Keyboard::SecondaryModifier) {
2852 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2854 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2857 cy = min ((double) _line->height(), cy);
2859 double const fraction = 1.0 - (cy / _line->height());
2863 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2869 /* we are ignoring x position for this drag, so we can just pass in anything */
2870 _line->drag_motion (0, fraction, true, push);
2872 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2876 LineDrag::finished (GdkEvent* event, bool)
2878 motion (event, false);
2883 LineDrag::aborted ()
2889 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2891 Drag::start_grab (event);
2892 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2896 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2903 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2905 nframes64_t grab = grab_frame ();
2906 if (Config->get_rubberbanding_snaps_to_grid ()) {
2907 _editor->snap_to_with_modifier (grab, event);
2910 /* base start and end on initial click position */
2920 if (_drags->current_pointer_y() < grab_y()) {
2921 y1 = _drags->current_pointer_y();
2924 y2 = _drags->current_pointer_y();
2929 if (start != end || y1 != y2) {
2931 double x1 = _editor->frame_to_pixel (start);
2932 double x2 = _editor->frame_to_pixel (end);
2934 _editor->rubberband_rect->property_x1() = x1;
2935 _editor->rubberband_rect->property_y1() = y1;
2936 _editor->rubberband_rect->property_x2() = x2;
2937 _editor->rubberband_rect->property_y2() = y2;
2939 _editor->rubberband_rect->show();
2940 _editor->rubberband_rect->raise_to_top();
2942 _editor->show_verbose_time_cursor (pf, 10);
2947 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2949 if (movement_occurred) {
2951 motion (event, false);
2954 if (_drags->current_pointer_y() < grab_y()) {
2955 y1 = _drags->current_pointer_y();
2958 y2 = _drags->current_pointer_y();
2963 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2966 _editor->begin_reversible_command (_("rubberband selection"));
2968 if (grab_frame() < last_pointer_frame()) {
2969 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
2971 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
2975 _editor->commit_reversible_command ();
2979 if (!getenv("ARDOUR_SAE")) {
2980 _editor->selection->clear_tracks();
2982 _editor->selection->clear_regions();
2983 _editor->selection->clear_points ();
2984 _editor->selection->clear_lines ();
2987 _editor->rubberband_rect->hide();
2991 RubberbandSelectDrag::aborted ()
2993 _editor->rubberband_rect->hide ();
2997 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2999 Drag::start_grab (event);
3001 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3005 TimeFXDrag::motion (GdkEvent* event, bool)
3007 RegionView* rv = _primary;
3009 nframes64_t const pf = adjusted_current_frame (event);
3011 if (pf > rv->region()->position()) {
3012 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3015 _editor->show_verbose_time_cursor (pf, 10);
3019 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3021 _primary->get_time_axis_view().hide_timestretch ();
3023 if (!movement_occurred) {
3027 if (last_pointer_frame() < _primary->region()->position()) {
3028 /* backwards drag of the left edge - not usable */
3032 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3034 float percentage = (double) newlen / (double) _primary->region()->length();
3036 #ifndef USE_RUBBERBAND
3037 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3038 if (_primary->region()->data_type() == DataType::AUDIO) {
3039 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3043 _editor->begin_reversible_command (_("timestretch"));
3045 // XXX how do timeFX on multiple regions ?
3050 if (!_editor->time_stretch (rs, percentage) == 0) {
3051 error << _("An error occurred while executing time stretch operation") << endmsg;
3056 TimeFXDrag::aborted ()
3058 _primary->get_time_axis_view().hide_timestretch ();
3063 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3065 Drag::start_grab (event);
3069 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3071 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3075 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3077 if (movement_occurred && _editor->session()) {
3078 /* make sure we stop */
3079 _editor->session()->request_transport_speed (0.0);
3084 ScrubDrag::aborted ()
3089 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3093 , _original_pointer_time_axis (-1)
3094 , _last_pointer_time_axis (-1)
3100 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3102 nframes64_t start = 0;
3103 nframes64_t end = 0;
3105 if (_editor->session() == 0) {
3109 Gdk::Cursor* cursor = 0;
3111 switch (_operation) {
3112 case CreateSelection:
3113 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3118 cursor = _editor->selector_cursor;
3119 Drag::start_grab (event, cursor);
3122 case SelectionStartTrim:
3123 if (_editor->clicked_axisview) {
3124 _editor->clicked_axisview->order_selection_trims (_item, true);
3126 Drag::start_grab (event, _editor->trimmer_cursor);
3127 start = _editor->selection->time[_editor->clicked_selection].start;
3128 _pointer_frame_offset = grab_frame() - start;
3131 case SelectionEndTrim:
3132 if (_editor->clicked_axisview) {
3133 _editor->clicked_axisview->order_selection_trims (_item, false);
3135 Drag::start_grab (event, _editor->trimmer_cursor);
3136 end = _editor->selection->time[_editor->clicked_selection].end;
3137 _pointer_frame_offset = grab_frame() - end;
3141 start = _editor->selection->time[_editor->clicked_selection].start;
3142 Drag::start_grab (event, cursor);
3143 _pointer_frame_offset = grab_frame() - start;
3147 if (_operation == SelectionMove) {
3148 _editor->show_verbose_time_cursor (start, 10);
3150 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3153 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3157 SelectionDrag::motion (GdkEvent* event, bool first_move)
3159 nframes64_t start = 0;
3160 nframes64_t end = 0;
3163 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3164 if (pending_time_axis.first == 0) {
3168 nframes64_t const pending_position = adjusted_current_frame (event);
3170 /* only alter selection if things have changed */
3172 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3176 switch (_operation) {
3177 case CreateSelection:
3179 nframes64_t grab = grab_frame ();
3182 _editor->snap_to (grab);
3185 if (pending_position < grab_frame()) {
3186 start = pending_position;
3189 end = pending_position;
3193 /* first drag: Either add to the selection
3194 or create a new selection
3200 /* adding to the selection */
3201 _editor->selection->add (_editor->clicked_axisview);
3202 _editor->clicked_selection = _editor->selection->add (start, end);
3207 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3208 _editor->selection->set (_editor->clicked_axisview);
3211 _editor->clicked_selection = _editor->selection->set (start, end);
3215 /* select the track that we're in */
3216 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3217 _editor->selection->add (pending_time_axis.first);
3218 _added_time_axes.push_back (pending_time_axis.first);
3221 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3222 tracks that we selected in the first place.
3225 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3226 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3228 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3229 while (i != _added_time_axes.end()) {
3231 list<TimeAxisView*>::iterator tmp = i;
3234 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3235 _editor->selection->remove (*i);
3236 _added_time_axes.remove (*i);
3245 case SelectionStartTrim:
3247 start = _editor->selection->time[_editor->clicked_selection].start;
3248 end = _editor->selection->time[_editor->clicked_selection].end;
3250 if (pending_position > end) {
3253 start = pending_position;
3257 case SelectionEndTrim:
3259 start = _editor->selection->time[_editor->clicked_selection].start;
3260 end = _editor->selection->time[_editor->clicked_selection].end;
3262 if (pending_position < start) {
3265 end = pending_position;
3272 start = _editor->selection->time[_editor->clicked_selection].start;
3273 end = _editor->selection->time[_editor->clicked_selection].end;
3275 length = end - start;
3277 start = pending_position;
3278 _editor->snap_to (start);
3280 end = start + length;
3285 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3286 _editor->start_canvas_autoscroll (1, 0);
3290 _editor->selection->replace (_editor->clicked_selection, start, end);
3293 if (_operation == SelectionMove) {
3294 _editor->show_verbose_time_cursor(start, 10);
3296 _editor->show_verbose_time_cursor(pending_position, 10);
3301 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3303 Session* s = _editor->session();
3305 if (movement_occurred) {
3306 motion (event, false);
3307 /* XXX this is not object-oriented programming at all. ick */
3308 if (_editor->selection->time.consolidate()) {
3309 _editor->selection->TimeChanged ();
3312 /* XXX what if its a music time selection? */
3313 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3314 s->request_play_range (&_editor->selection->time, true);
3319 /* just a click, no pointer movement.*/
3321 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3322 _editor->selection->clear_time();
3325 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3326 _editor->selection->set (_editor->clicked_axisview);
3329 if (s && s->get_play_range () && s->transport_rolling()) {
3330 s->request_stop (false, false);
3335 _editor->stop_canvas_autoscroll ();
3339 SelectionDrag::aborted ()
3344 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3349 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3350 _drag_rect->hide ();
3352 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3353 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3357 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3359 if (_editor->session() == 0) {
3363 Gdk::Cursor* cursor = 0;
3365 if (!_editor->temp_location) {
3366 _editor->temp_location = new Location;
3369 switch (_operation) {
3370 case CreateRangeMarker:
3371 case CreateTransportMarker:
3372 case CreateCDMarker:
3374 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3379 cursor = _editor->selector_cursor;
3383 Drag::start_grab (event, cursor);
3385 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3389 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3391 nframes64_t start = 0;
3392 nframes64_t end = 0;
3393 ArdourCanvas::SimpleRect *crect;
3395 switch (_operation) {
3396 case CreateRangeMarker:
3397 crect = _editor->range_bar_drag_rect;
3399 case CreateTransportMarker:
3400 crect = _editor->transport_bar_drag_rect;
3402 case CreateCDMarker:
3403 crect = _editor->cd_marker_bar_drag_rect;
3406 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3411 nframes64_t const pf = adjusted_current_frame (event);
3413 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3414 nframes64_t grab = grab_frame ();
3415 _editor->snap_to (grab);
3417 if (pf < grab_frame()) {
3425 /* first drag: Either add to the selection
3426 or create a new selection.
3431 _editor->temp_location->set (start, end);
3435 update_item (_editor->temp_location);
3437 //_drag_rect->raise_to_top();
3442 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3443 _editor->start_canvas_autoscroll (1, 0);
3447 _editor->temp_location->set (start, end);
3449 double x1 = _editor->frame_to_pixel (start);
3450 double x2 = _editor->frame_to_pixel (end);
3451 crect->property_x1() = x1;
3452 crect->property_x2() = x2;
3454 update_item (_editor->temp_location);
3457 _editor->show_verbose_time_cursor (pf, 10);
3462 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3464 Location * newloc = 0;
3468 if (movement_occurred) {
3469 motion (event, false);
3472 switch (_operation) {
3473 case CreateRangeMarker:
3474 case CreateCDMarker:
3476 _editor->begin_reversible_command (_("new range marker"));
3477 XMLNode &before = _editor->session()->locations()->get_state();
3478 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3479 if (_operation == CreateCDMarker) {
3480 flags = Location::IsRangeMarker | Location::IsCDMarker;
3481 _editor->cd_marker_bar_drag_rect->hide();
3484 flags = Location::IsRangeMarker;
3485 _editor->range_bar_drag_rect->hide();
3487 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3488 _editor->session()->locations()->add (newloc, true);
3489 XMLNode &after = _editor->session()->locations()->get_state();
3490 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3491 _editor->commit_reversible_command ();
3495 case CreateTransportMarker:
3496 // popup menu to pick loop or punch
3497 _editor->new_transport_marker_context_menu (&event->button, _item);
3501 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3503 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3508 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3510 if (end == max_frames) {
3511 end = _editor->session()->current_end_frame ();
3514 if (start == max_frames) {
3515 start = _editor->session()->current_start_frame ();
3518 switch (_editor->mouse_mode) {
3520 /* find the two markers on either side and then make the selection from it */
3521 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3525 /* find the two markers on either side of the click and make the range out of it */
3526 _editor->selection->set (start, end);
3535 _editor->stop_canvas_autoscroll ();
3539 RangeMarkerBarDrag::aborted ()
3545 RangeMarkerBarDrag::update_item (Location* location)
3547 double const x1 = _editor->frame_to_pixel (location->start());
3548 double const x2 = _editor->frame_to_pixel (location->end());
3550 _drag_rect->property_x1() = x1;
3551 _drag_rect->property_x2() = x2;
3555 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3557 Drag::start_grab (event, _editor->zoom_cursor);
3558 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3562 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3567 nframes64_t const pf = adjusted_current_frame (event);
3569 nframes64_t grab = grab_frame ();
3570 _editor->snap_to_with_modifier (grab, event);
3572 /* base start and end on initial click position */
3584 _editor->zoom_rect->show();
3585 _editor->zoom_rect->raise_to_top();
3588 _editor->reposition_zoom_rect(start, end);
3590 _editor->show_verbose_time_cursor (pf, 10);
3595 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3597 if (movement_occurred) {
3598 motion (event, false);
3600 if (grab_frame() < last_pointer_frame()) {
3601 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3603 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3606 _editor->temporal_zoom_to_frame (false, grab_frame());
3608 temporal_zoom_step (false);
3609 center_screen (grab_frame());
3613 _editor->zoom_rect->hide();
3617 MouseZoomDrag::aborted ()
3619 _editor->zoom_rect->hide ();
3622 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3625 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3626 region = &cnote->region_view();
3630 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3632 Drag::start_grab (event);
3635 drag_delta_note = 0;
3640 event_x = _drags->current_pointer_x();
3641 event_y = _drags->current_pointer_y();
3643 _item->property_parent().get_value()->w2i(event_x, event_y);
3645 last_x = region->snap_to_pixel(event_x);
3648 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3650 if (!(was_selected = cnote->selected())) {
3652 /* tertiary-click means extend selection - we'll do that on button release,
3653 so don't add it here, because otherwise we make it hard to figure
3654 out the "extend-to" range.
3657 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3660 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3663 region->note_selected (cnote, true);
3665 region->unique_select (cnote);
3672 NoteDrag::motion (GdkEvent*, bool)
3674 MidiStreamView* streamview = region->midi_stream_view();
3678 event_x = _drags->current_pointer_x();
3679 event_y = _drags->current_pointer_y();
3681 _item->property_parent().get_value()->w2i(event_x, event_y);
3683 event_x = region->snap_to_pixel(event_x);
3685 double dx = event_x - last_x;
3686 double dy = event_y - last_y;
3691 // Snap to note rows
3693 if (abs (dy) < streamview->note_height()) {
3696 int8_t this_delta_note;
3698 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3700 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3702 drag_delta_note -= this_delta_note;
3703 dy = streamview->note_height() * this_delta_note;
3704 last_y = last_y + dy;
3708 region->move_selection (dx, dy);
3710 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3712 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3713 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3714 _editor->show_verbose_canvas_cursor_with (buf);
3719 NoteDrag::finished (GdkEvent* ev, bool moved)
3721 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3724 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3727 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3729 region->note_deselected (cnote);
3732 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3733 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3735 if (!extend && !add && region->selection_size() > 1) {
3736 region->unique_select(cnote);
3737 } else if (extend) {
3738 region->note_selected (cnote, true, true);
3740 /* it was added during button press */
3745 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3750 NoteDrag::aborted ()
3755 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3758 , _nothing_to_drag (false)
3760 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3763 _line = _atav->line ();
3767 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3769 Drag::start_grab (event, cursor);
3771 list<ControlPoint*> points;
3773 XMLNode* state = &_line->get_state ();
3775 if (_ranges.empty()) {
3777 uint32_t const N = _line->npoints ();
3778 for (uint32_t i = 0; i < N; ++i) {
3779 points.push_back (_line->nth (i));
3784 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3785 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3787 /* fade into and out of the region that we're dragging;
3788 64 samples length plucked out of thin air.
3790 nframes64_t const h = (j->start + j->end) / 2;
3791 nframes64_t a = j->start + 64;
3795 nframes64_t b = j->end - 64;
3800 the_list->add (j->start, the_list->eval (j->start));
3801 _line->add_always_in_view (j->start);
3802 the_list->add (a, the_list->eval (a));
3803 _line->add_always_in_view (a);
3804 the_list->add (b, the_list->eval (b));
3805 _line->add_always_in_view (b);
3806 the_list->add (j->end, the_list->eval (j->end));
3807 _line->add_always_in_view (j->end);
3810 uint32_t const N = _line->npoints ();
3811 for (uint32_t i = 0; i < N; ++i) {
3813 ControlPoint* p = _line->nth (i);
3815 list<AudioRange>::const_iterator j = _ranges.begin ();
3816 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3820 if (j != _ranges.end()) {
3821 points.push_back (p);
3826 if (points.empty()) {
3827 _nothing_to_drag = true;
3831 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3835 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3837 if (_nothing_to_drag) {
3841 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3843 /* we are ignoring x position for this drag, so we can just pass in anything */
3844 _line->drag_motion (0, f, true, false);
3848 AutomationRangeDrag::finished (GdkEvent* event, bool)
3850 if (_nothing_to_drag) {
3854 motion (event, false);
3856 _line->clear_always_in_view ();
3860 AutomationRangeDrag::aborted ()
3862 _line->clear_always_in_view ();