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 "pbd/stateful_diff_command.h"
25 #include "ardour/session.h"
26 #include "ardour/dB.h"
27 #include "ardour/region_factory.h"
31 #include "audio_region_view.h"
32 #include "midi_region_view.h"
33 #include "ardour_ui.h"
34 #include "gui_thread.h"
35 #include "control_point.h"
37 #include "region_gain_line.h"
38 #include "editor_drag.h"
39 #include "audio_time_axis.h"
40 #include "midi_time_axis.h"
41 #include "canvas-note.h"
42 #include "selection.h"
43 #include "midi_selection.h"
44 #include "automation_time_axis.h"
47 using namespace ARDOUR;
50 using namespace Editing;
51 using namespace ArdourCanvas;
53 using Gtkmm2ext::Keyboard;
55 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
57 DragManager::DragManager (Editor* e)
60 , _current_pointer_frame (0)
65 DragManager::~DragManager ()
73 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
82 DragManager::break_drag ()
86 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
97 DragManager::add (Drag* d)
99 d->set_manager (this);
100 _drags.push_back (d);
104 DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
106 assert (_drags.empty ());
107 d->set_manager (this);
108 _drags.push_back (d);
113 DragManager::start_grab (GdkEvent* e)
115 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
117 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
118 (*i)->start_grab (e);
123 DragManager::end_grab (GdkEvent* e)
128 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
129 bool const t = (*i)->end_grab (e);
144 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
148 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
150 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
151 bool const t = (*i)->motion_handler (e, from_autoscroll);
162 DragManager::have_item (ArdourCanvas::Item* i) const
164 list<Drag*>::const_iterator j = _drags.begin ();
165 while (j != _drags.end() && (*j)->item () != i) {
169 return j != _drags.end ();
172 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
175 , _pointer_frame_offset (0)
176 , _move_threshold_passed (false)
178 , _last_pointer_frame (0)
184 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
190 cursor = _editor->which_grabber_cursor ();
193 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
197 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
200 cursor = _editor->which_grabber_cursor ();
203 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
205 if (Keyboard::is_button2_event (&event->button)) {
206 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
207 _y_constrained = true;
208 _x_constrained = false;
210 _y_constrained = false;
211 _x_constrained = true;
214 _x_constrained = false;
215 _y_constrained = false;
218 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
219 _grab_frame = adjusted_frame (_grab_frame, event);
220 _last_pointer_frame = _grab_frame;
221 _last_pointer_x = _grab_x;
222 _last_pointer_y = _grab_y;
224 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
228 if (_editor->session() && _editor->session()->transport_rolling()) {
231 _was_rolling = false;
234 switch (_editor->snap_type()) {
235 case SnapToRegionStart:
236 case SnapToRegionEnd:
237 case SnapToRegionSync:
238 case SnapToRegionBoundary:
239 _editor->build_region_boundary_cache ();
246 /** @param event GDK event, or 0.
247 * @return true if some movement occurred, otherwise false.
250 Drag::end_grab (GdkEvent* event)
252 _editor->stop_canvas_autoscroll ();
254 _item->ungrab (event ? event->button.time : 0);
256 finished (event, _move_threshold_passed);
258 _editor->hide_verbose_canvas_cursor();
260 return _move_threshold_passed;
264 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
268 if (f > _pointer_frame_offset) {
269 pos = f - _pointer_frame_offset;
273 _editor->snap_to_with_modifier (pos, event);
280 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
282 return adjusted_frame (_drags->current_pointer_frame (), event, snap);
286 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
288 /* check to see if we have moved in any way that matters since the last motion event */
289 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
290 (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
294 pair<nframes64_t, int> const threshold = move_threshold ();
296 bool const old_move_threshold_passed = _move_threshold_passed;
298 if (!from_autoscroll && !_move_threshold_passed) {
300 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
301 bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
303 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
306 if (active (_editor->mouse_mode) && _move_threshold_passed) {
308 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
309 if (!from_autoscroll) {
310 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
313 motion (event, _move_threshold_passed != old_move_threshold_passed);
315 _last_pointer_x = _drags->current_pointer_x ();
316 _last_pointer_y = _drags->current_pointer_y ();
317 _last_pointer_frame = adjusted_current_frame (event);
335 _editor->stop_canvas_autoscroll ();
336 _editor->hide_verbose_canvas_cursor ();
339 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
343 for (list<RegionView*>::const_iterator i = v.begin(); i != v.end(); ++i) {
344 _views.push_back (DraggingView (*i));
347 RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
351 RegionDrag::region_going_away (RegionView* v)
353 list<DraggingView>::iterator i = _views.begin ();
354 while (i != _views.end() && i->view != v) {
358 if (i != _views.end()) {
363 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
364 : RegionDrag (e, i, p, v),
375 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
377 Drag::start_grab (event);
379 _editor->show_verbose_time_cursor (_last_frame_position, 10);
382 RegionMotionDrag::TimeAxisViewSummary
383 RegionMotionDrag::get_time_axis_view_summary ()
385 int32_t children = 0;
386 TimeAxisViewSummary sum;
388 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
390 /* get a bitmask representing the visible tracks */
392 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
393 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
394 TimeAxisView::Children children_list;
396 /* zeroes are audio/MIDI tracks. ones are other types. */
398 if (!rtv->hidden()) {
400 if (!rtv->is_track()) {
401 /* not an audio nor MIDI track */
402 sum.tracks = sum.tracks |= (0x01 << rtv->order());
405 sum.height_list[rtv->order()] = (*i)->current_height();
408 if ((children_list = rtv->get_child_list()).size() > 0) {
409 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
410 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
411 sum.height_list[rtv->order() + children] = (*j)->current_height();
422 RegionMotionDrag::compute_y_delta (
423 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
424 int32_t last_pointer_layer, int32_t current_pointer_layer,
425 TimeAxisViewSummary const & tavs,
426 int32_t* pointer_order_span, int32_t* pointer_layer_span,
427 int32_t* canvas_pointer_order_span
431 *pointer_order_span = 0;
432 *pointer_layer_span = 0;
436 bool clamp_y_axis = false;
438 /* the change in track order between this callback and the last */
439 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
440 /* the change in layer between this callback and the last;
441 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
442 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
444 if (*pointer_order_span != 0) {
446 /* find the actual pointer span, in terms of the number of visible tracks;
447 to do this, we reduce |pointer_order_span| by the number of hidden tracks
450 *canvas_pointer_order_span = *pointer_order_span;
451 if (last_pointer_view->order() >= current_pointer_view->order()) {
452 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
453 if (tavs.height_list[y] == 0) {
454 *canvas_pointer_order_span--;
458 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
459 if (tavs.height_list[y] == 0) {
460 *canvas_pointer_order_span++;
465 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
467 RegionView* rv = i->view;
469 if (rv->region()->locked()) {
473 double ix1, ix2, iy1, iy2;
474 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
475 rv->get_canvas_frame()->i2w (ix1, iy1);
476 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
478 /* get the new trackview for this particular region */
479 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
481 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
483 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
484 as surely this is a per-region thing... */
486 clamp_y_axis = y_movement_disallowed (
487 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
495 } else if (_dest_trackview == current_pointer_view) {
497 if (current_pointer_layer == last_pointer_layer) {
498 /* No movement; clamp */
504 _dest_trackview = current_pointer_view;
505 _dest_layer = current_pointer_layer;
513 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
515 /* compute the amount of pointer motion in frames, and where
516 the region would be if we moved it by that much.
518 *pending_region_position = adjusted_current_frame (event);
520 nframes64_t sync_frame;
521 nframes64_t sync_offset;
524 sync_offset = _primary->region()->sync_offset (sync_dir);
526 /* we don't handle a sync point that lies before zero.
528 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
530 sync_frame = *pending_region_position + (sync_dir*sync_offset);
532 _editor->snap_to_with_modifier (sync_frame, event);
534 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
537 *pending_region_position = _last_frame_position;
540 if (*pending_region_position > max_frames - _primary->region()->length()) {
541 *pending_region_position = _last_frame_position;
546 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
548 /* now compute the canvas unit distance we need to move the regionview
549 to make it appear at the new location.
552 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
554 if (*pending_region_position <= _last_frame_position) {
556 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
558 RegionView* rv = i->view;
560 // If any regionview is at zero, we need to know so we can stop further leftward motion.
562 double ix1, ix2, iy1, iy2;
563 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
564 rv->get_canvas_frame()->i2w (ix1, iy1);
566 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
568 *pending_region_position = _last_frame_position;
575 _last_frame_position = *pending_region_position;
582 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
586 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
588 vector<int32_t>::iterator j;
590 /* *pointer* variables reflect things about the pointer; as we may be moving
591 multiple regions, much detail must be computed per-region */
593 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
594 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
595 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
596 is always 0 regardless of what the region's "real" layer is */
597 RouteTimeAxisView* current_pointer_view;
598 layer_t current_pointer_layer;
599 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
603 /* TimeAxisView that we were pointing at last time we entered this method */
604 TimeAxisView const * const last_pointer_view = _dest_trackview;
605 /* the order of the track that we were pointing at last time we entered this method */
606 int32_t const last_pointer_order = last_pointer_view->order ();
607 /* the layer that we were pointing at last time we entered this method */
608 layer_t const last_pointer_layer = _dest_layer;
610 int32_t pointer_order_span;
611 int32_t pointer_layer_span;
612 int32_t canvas_pointer_order_span;
614 bool const clamp_y_axis = compute_y_delta (
615 last_pointer_view, current_pointer_view,
616 last_pointer_layer, current_pointer_layer, tavs,
617 &pointer_order_span, &pointer_layer_span,
618 &canvas_pointer_order_span
621 nframes64_t pending_region_position;
622 double const x_delta = compute_x_delta (event, &pending_region_position);
624 /*************************************************************
626 ************************************************************/
628 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
629 /* haven't reached next snap point, and we're not switching
630 trackviews nor layers. nothing to do.
635 /*************************************************************
637 ************************************************************/
639 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
641 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
643 RegionView* rv = i->view;
645 if (rv->region()->locked()) {
649 /* here we are calculating the y distance from the
650 top of the first track view to the top of the region
651 area of the track view that we're working on */
653 /* this x value is just a dummy value so that we have something
658 /* distance from the top of this track view to the region area
659 of our track view is always 1 */
663 /* convert to world coordinates, ie distance from the top of
666 rv->get_canvas_frame()->i2w (ix1, iy1);
668 /* compensate for the ruler section and the vertical scrollbar position */
669 iy1 += _editor->get_trackview_group_vertical_offset ();
673 // hide any dependent views
675 rv->get_time_axis_view().hide_dependent_views (*rv);
678 reparent to a non scrolling group so that we can keep the
679 region selection above all time axis views.
680 reparenting means we have to move the rv as the two
681 parent groups have different coordinates.
684 rv->get_canvas_group()->property_y() = iy1 - 1;
685 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
687 rv->fake_set_opaque (true);
690 /* current view for this particular region */
691 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
692 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
694 if (pointer_order_span != 0 && !clamp_y_axis) {
696 /* INTER-TRACK MOVEMENT */
698 /* move through the height list to the track that the region is currently on */
699 vector<int32_t>::iterator j = tavs.height_list.begin ();
701 while (j != tavs.height_list.end () && x != rtv->order ()) {
707 int32_t temp_pointer_order_span = canvas_pointer_order_span;
709 if (j != tavs.height_list.end ()) {
711 /* Account for layers in the original and
712 destination tracks. If we're moving around in layers we assume
713 that only one track is involved, so it's ok to use *pointer*
716 StreamView* lv = last_pointer_view->view ();
719 /* move to the top of the last trackview */
720 if (lv->layer_display () == Stacked) {
721 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
724 StreamView* cv = current_pointer_view->view ();
727 /* move to the right layer on the current trackview */
728 if (cv->layer_display () == Stacked) {
729 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
732 /* And for being on a non-topmost layer on the new
735 while (temp_pointer_order_span > 0) {
736 /* we're moving up canvas-wise,
737 so we need to find the next track height
739 if (j != tavs.height_list.begin()) {
743 if (x != last_pointer_order) {
745 ++temp_pointer_order_span;
750 temp_pointer_order_span--;
753 while (temp_pointer_order_span < 0) {
757 if (x != last_pointer_order) {
759 --temp_pointer_order_span;
763 if (j != tavs.height_list.end()) {
767 temp_pointer_order_span++;
771 /* find out where we'll be when we move and set height accordingly */
773 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
774 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
775 rv->set_height (temp_rtv->view()->child_height());
777 /* if you un-comment the following, the region colours will follow
778 the track colours whilst dragging; personally
779 i think this can confuse things, but never mind.
782 //const GdkColor& col (temp_rtv->view->get_region_color());
783 //rv->set_color (const_cast<GdkColor&>(col));
787 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
789 /* INTER-LAYER MOVEMENT in the same track */
790 y_delta = rtv->view()->child_height () * pointer_layer_span;
795 _editor->mouse_brush_insert_region (rv, pending_region_position);
797 rv->move (x_delta, y_delta);
800 } /* foreach region */
802 _total_x_delta += x_delta;
805 _editor->cursor_group->raise_to_top();
808 if (x_delta != 0 && !_brushing) {
809 _editor->show_verbose_time_cursor (_last_frame_position, 10);
814 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
816 if (_copy && first_move) {
817 copy_regions (event);
820 RegionMotionDrag::motion (event, first_move);
824 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
826 vector<RegionView*> copies;
827 boost::shared_ptr<Track> tr;
828 boost::shared_ptr<Playlist> from_playlist;
829 boost::shared_ptr<Playlist> to_playlist;
830 RegionSelection new_views;
831 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
832 PlaylistSet modified_playlists;
833 PlaylistSet frozen_playlists;
834 list <sigc::connection> modified_playlist_connections;
835 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
836 nframes64_t drag_delta;
837 bool changed_tracks, changed_position;
838 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
839 RouteTimeAxisView* source_tv;
840 vector<StatefulDiffCommand*> sdc;
842 if (!movement_occurred) {
848 /* all changes were made during motion event handlers */
851 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
852 copies.push_back (i->view);
859 /* reverse this here so that we have the correct logic to finalize
863 if (Config->get_edit_mode() == Lock) {
864 _x_constrained = !_x_constrained;
868 if (_x_constrained) {
869 _editor->begin_reversible_command (_("fixed time region copy"));
871 _editor->begin_reversible_command (_("region copy"));
874 if (_x_constrained) {
875 _editor->begin_reversible_command (_("fixed time region drag"));
877 _editor->begin_reversible_command (_("region drag"));
881 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
882 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
884 drag_delta = _primary->region()->position() - _last_frame_position;
886 _editor->update_canvas_now ();
888 /* make a list of where each region ended up */
889 final = find_time_axis_views_and_layers ();
891 cerr << "Iterate over " << _views.size() << " views\n";
893 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
895 RegionView* rv = i->view;
896 RouteTimeAxisView* dest_rtv = final[rv].first;
897 layer_t dest_layer = final[rv].second;
901 from_playlist.reset ();
902 to_playlist.reset ();
904 if (rv->region()->locked()) {
909 if (changed_position && !_x_constrained) {
910 where = rv->region()->position() - drag_delta;
912 where = rv->region()->position();
915 boost::shared_ptr<Region> new_region;
918 /* we already made a copy */
919 new_region = rv->region();
921 /* undo the previous hide_dependent_views so that xfades don't
922 disappear on copying regions
925 //rv->get_time_axis_view().reveal_dependent_views (*rv);
927 } else if (changed_tracks && dest_rtv->playlist()) {
928 new_region = RegionFactory::create (rv->region());
931 if (changed_tracks || _copy) {
933 to_playlist = dest_rtv->playlist();
940 _editor->latest_regionviews.clear ();
942 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
944 insert_result = modified_playlists.insert (to_playlist);
946 if (insert_result.second) {
947 to_playlist->clear_history ();
950 cerr << "To playlist " << to_playlist->name() << " region history contains "
951 << to_playlist->region_list().change().added.size() << " adds and "
952 << to_playlist->region_list().change().removed.size() << " removes\n";
954 cerr << "Adding new region " << new_region->id() << " based on "
955 << rv->region()->id() << endl;
957 to_playlist->add_region (new_region, where);
959 if (dest_rtv->view()->layer_display() == Stacked) {
960 new_region->set_layer (dest_layer);
961 new_region->set_pending_explicit_relayer (true);
966 if (!_editor->latest_regionviews.empty()) {
967 // XXX why just the first one ? we only expect one
968 // commented out in nick_m's canvas reworking. is that intended?
969 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
970 new_views.push_back (_editor->latest_regionviews.front());
974 rv->region()->clear_history ();
977 motion on the same track. plonk the previously reparented region
978 back to its original canvas group (its streamview).
979 No need to do anything for copies as they are fake regions which will be deleted.
982 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
983 rv->get_canvas_group()->property_y() = i->initial_y;
984 rv->get_time_axis_view().reveal_dependent_views (*rv);
986 /* just change the model */
988 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
990 if (dest_rtv->view()->layer_display() == Stacked) {
991 rv->region()->set_layer (dest_layer);
992 rv->region()->set_pending_explicit_relayer (true);
995 /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
997 frozen_insert_result = frozen_playlists.insert(playlist);
999 if (frozen_insert_result.second) {
1003 cerr << "Moving region " << rv->region()->id() << endl;
1005 rv->region()->set_position (where, (void*) this);
1007 sdc.push_back (new StatefulDiffCommand (rv->region()));
1010 if (changed_tracks && !_copy) {
1012 /* get the playlist where this drag started. we can't use rv->region()->playlist()
1013 because we may have copied the region and it has not been attached to a playlist.
1016 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
1017 tr = source_tv->track();
1018 from_playlist = tr->playlist();
1022 assert (from_playlist);
1024 /* moved to a different audio track, without copying */
1026 /* the region that used to be in the old playlist is not
1027 moved to the new one - we use a copy of it. as a result,
1028 any existing editor for the region should no longer be
1032 rv->hide_region_editor();
1033 rv->fake_set_opaque (false);
1035 /* remove the region from the old playlist */
1037 insert_result = modified_playlists.insert (from_playlist);
1039 if (insert_result.second) {
1040 from_playlist->clear_history ();
1043 cerr << "From playlist " << from_playlist->name() << " region history contains "
1044 << from_playlist->region_list().change().added.size() << " adds and "
1045 << from_playlist->region_list().change().removed.size() << " removes\n";
1047 cerr << "removing region " << rv->region() << endl;
1049 from_playlist->remove_region (rv->region());
1051 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1052 was selected in all of them, then removing it from a playlist will have removed all
1053 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1054 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1055 corresponding regionview, and the selection is now empty).
1057 this could have invalidated any and all iterators into the region selection.
1059 the heuristic we use here is: if the region selection is empty, break out of the loop
1060 here. if the region selection is not empty, then restart the loop because we know that
1061 we must have removed at least the region(view) we've just been working on as well as any
1062 that we processed on previous iterations.
1064 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1065 we can just iterate.
1068 if (_views.empty()) {
1070 sdc.push_back (new StatefulDiffCommand (to_playlist));
1071 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1074 if (from_playlist && (from_playlist != to_playlist)) {
1075 sdc.push_back (new StatefulDiffCommand (from_playlist));
1076 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1088 copies.push_back (rv);
1091 cerr << "Done with TV, top = " << to_playlist << " from = " << from_playlist << endl;
1094 sdc.push_back (new StatefulDiffCommand (to_playlist));
1095 cerr << "Saved diff for to:" << to_playlist->name() << endl;
1098 if (from_playlist && (from_playlist != to_playlist)) {
1099 sdc.push_back (new StatefulDiffCommand (from_playlist));
1100 cerr << "Saved diff for from:" << from_playlist->name() << endl;
1105 if we've created new regions either by copying or moving
1106 to a new track, we want to replace the old selection with the new ones
1109 if (new_views.size() > 0) {
1110 _editor->selection->set (new_views);
1113 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1118 for (vector<StatefulDiffCommand*>::iterator i = sdc.begin(); i != sdc.end(); ++i) {
1119 _editor->session()->add_command (*i);
1122 _editor->commit_reversible_command ();
1124 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1130 RegionMoveDrag::aborted ()
1134 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1141 RegionMotionDrag::aborted ();
1146 RegionMotionDrag::aborted ()
1148 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1149 RegionView* rv = i->view;
1150 TimeAxisView* tv = &(rv->get_time_axis_view ());
1151 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1153 rv->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1154 rv->get_canvas_group()->property_y() = 0;
1155 rv->get_time_axis_view().reveal_dependent_views (*rv);
1156 rv->fake_set_opaque (false);
1157 rv->move (-_total_x_delta, 0);
1158 rv->set_height (rtv->view()->child_height ());
1161 _editor->update_canvas_now ();
1166 RegionMotionDrag::x_move_allowed () const
1168 if (Config->get_edit_mode() == Lock) {
1169 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1170 return _x_constrained;
1173 return !_x_constrained;
1177 RegionMotionDrag::copy_regions (GdkEvent* event)
1179 /* duplicate the regionview(s) and region(s) */
1181 list<DraggingView> new_regionviews;
1183 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1185 RegionView* rv = i->view;
1186 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1187 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1189 const boost::shared_ptr<const Region> original = rv->region();
1190 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1191 region_copy->set_position (original->position(), this);
1195 boost::shared_ptr<AudioRegion> audioregion_copy
1196 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1198 nrv = new AudioRegionView (*arv, audioregion_copy);
1200 boost::shared_ptr<MidiRegion> midiregion_copy
1201 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1202 nrv = new MidiRegionView (*mrv, midiregion_copy);
1207 nrv->get_canvas_group()->show ();
1208 new_regionviews.push_back (DraggingView (nrv));
1210 /* swap _primary to the copy */
1212 if (rv == _primary) {
1216 /* ..and deselect the one we copied */
1218 rv->set_selected (false);
1221 if (new_regionviews.empty()) {
1225 /* reflect the fact that we are dragging the copies */
1227 _views = new_regionviews;
1229 swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0);
1232 sync the canvas to what we think is its current state
1233 without it, the canvas seems to
1234 "forget" to update properly after the upcoming reparent()
1235 ..only if the mouse is in rapid motion at the time of the grab.
1236 something to do with regionview creation taking so long?
1238 _editor->update_canvas_now();
1242 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1244 /* Which trackview is this ? */
1246 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1247 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1248 (*layer) = tvp.second;
1250 if (*tv && (*tv)->layer_display() == Overlaid) {
1254 /* The region motion is only processed if the pointer is over
1258 if (!(*tv) || !(*tv)->is_track()) {
1259 /* To make sure we hide the verbose canvas cursor when the mouse is
1260 not held over and audiotrack.
1262 _editor->hide_verbose_canvas_cursor ();
1269 /** @param new_order New track order.
1270 * @param old_order Old track order.
1271 * @param visible_y_low Lowest visible order.
1272 * @return true if y movement should not happen, otherwise false.
1275 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1277 if (new_order != old_order) {
1279 /* this isn't the pointer track */
1283 /* moving up the canvas */
1284 if ( (new_order - y_span) >= tavs.visible_y_low) {
1288 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1289 int32_t visible_tracks = 0;
1290 while (visible_tracks < y_span ) {
1292 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1293 /* passing through a hidden track */
1298 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1299 /* moving to a non-track; disallow */
1305 /* moving beyond the lowest visible track; disallow */
1309 } else if (y_span < 0) {
1311 /* moving down the canvas */
1312 if ((new_order - y_span) <= tavs.visible_y_high) {
1314 int32_t visible_tracks = 0;
1316 while (visible_tracks > y_span ) {
1319 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1320 /* passing through a hidden track */
1325 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1326 /* moving to a non-track; disallow */
1333 /* moving beyond the highest visible track; disallow */
1340 /* this is the pointer's track */
1342 if ((new_order - y_span) > tavs.visible_y_high) {
1343 /* we will overflow */
1345 } else if ((new_order - y_span) < tavs.visible_y_low) {
1346 /* we will overflow */
1355 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1356 : RegionMotionDrag (e, i, p, v, b),
1359 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1361 _dest_trackview = tv;
1362 if (tv->layer_display() == Overlaid) {
1365 _dest_layer = _primary->region()->layer ();
1369 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1370 if (rtv && rtv->is_track()) {
1371 speed = rtv->track()->speed ();
1374 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1378 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1380 RegionMotionDrag::start_grab (event, c);
1382 _pointer_frame_offset = grab_frame() - _last_frame_position;
1385 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1386 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1388 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1389 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1391 _primary = v->view()->create_region_view (r, false, false);
1393 _primary->get_canvas_group()->show ();
1394 _primary->set_position (pos, 0);
1395 _views.push_back (DraggingView (_primary));
1397 _last_frame_position = pos;
1399 _item = _primary->get_canvas_group ();
1400 _dest_trackview = v;
1401 _dest_layer = _primary->region()->layer ();
1404 map<RegionView*, pair<RouteTimeAxisView*, int> >
1405 RegionMotionDrag::find_time_axis_views_and_layers ()
1407 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1409 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1411 double ix1, ix2, iy1, iy2;
1412 RegionView* rv = i->view;
1413 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1414 rv->get_canvas_frame()->i2w (ix1, iy1);
1415 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1417 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1418 tav[rv] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1426 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1428 _editor->update_canvas_now ();
1430 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1432 RouteTimeAxisView* dest_rtv = final[_primary].first;
1434 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1435 _primary->get_canvas_group()->property_y() = 0;
1437 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1439 _editor->begin_reversible_command (_("insert region"));
1440 playlist->clear_history ();
1441 playlist->add_region (_primary->region (), _last_frame_position);
1442 _editor->session()->add_command (new StatefulDiffCommand (playlist));
1443 _editor->commit_reversible_command ();
1451 RegionInsertDrag::aborted ()
1456 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1457 : RegionMoveDrag (e, i, p, v, false, false)
1462 struct RegionSelectionByPosition {
1463 bool operator() (RegionView*a, RegionView* b) {
1464 return a->region()->position () < b->region()->position();
1469 RegionSpliceDrag::motion (GdkEvent* event, bool)
1471 RouteTimeAxisView* tv;
1474 if (!check_possible (&tv, &layer)) {
1480 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1486 RegionSelection copy (_editor->selection->regions);
1488 RegionSelectionByPosition cmp;
1491 nframes64_t const pf = adjusted_current_frame (event);
1493 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1495 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1501 boost::shared_ptr<Playlist> playlist;
1503 if ((playlist = atv->playlist()) == 0) {
1507 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1512 if (pf < (*i)->region()->last_frame() + 1) {
1516 if (pf > (*i)->region()->first_frame()) {
1522 playlist->shuffle ((*i)->region(), dir);
1527 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1533 RegionSpliceDrag::aborted ()
1538 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1546 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1548 _dest_trackview = _view;
1550 Drag::start_grab (event);
1555 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1558 // TODO: create region-create-drag region view here
1561 // TODO: resize region-create-drag region view here
1565 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1567 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1573 if (!movement_occurred) {
1574 mtv->add_region (grab_frame ());
1576 motion (event, false);
1577 // TODO: create region-create-drag region here
1582 RegionCreateDrag::aborted ()
1587 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1595 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1598 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1600 Drag::start_grab (event);
1602 region = &cnote->region_view();
1604 double region_start = region->get_position_pixels();
1605 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1607 if (grab_x() <= middle_point) {
1608 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1611 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1615 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1617 if (event->motion.state & Keyboard::PrimaryModifier) {
1623 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1625 if (ms.size() > 1) {
1626 /* has to be relative, may make no sense otherwise */
1630 region->note_selected (cnote, true);
1632 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1633 MidiRegionSelection::iterator next;
1636 (*r)->begin_resizing (at_front);
1642 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1644 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1645 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1646 (*r)->update_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1651 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1653 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1654 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1655 (*r)->commit_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1660 NoteResizeDrag::aborted ()
1666 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1672 RegionGainDrag::finished (GdkEvent *, bool)
1678 RegionGainDrag::aborted ()
1683 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1684 : RegionDrag (e, i, p, v)
1685 , _have_transaction (false)
1691 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1694 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1695 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1697 if (tv && tv->is_track()) {
1698 speed = tv->track()->speed();
1701 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1702 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1703 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1705 Drag::start_grab (event, _editor->trimmer_cursor);
1707 nframes64_t const pf = adjusted_current_frame (event);
1709 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1710 _operation = ContentsTrim;
1712 /* These will get overridden for a point trim.*/
1713 if (pf < (region_start + region_length/2)) {
1714 /* closer to start */
1715 _operation = StartTrim;
1716 } else if (pf > (region_end - region_length/2)) {
1718 _operation = EndTrim;
1722 switch (_operation) {
1724 _editor->show_verbose_time_cursor (region_start, 10);
1727 _editor->show_verbose_time_cursor (region_end, 10);
1730 _editor->show_verbose_time_cursor (pf, 10);
1736 TrimDrag::motion (GdkEvent* event, bool first_move)
1738 RegionView* rv = _primary;
1740 /* snap modifier works differently here..
1741 its current state has to be passed to the
1742 various trim functions in order to work properly
1746 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1747 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1748 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1750 if (tv && tv->is_track()) {
1751 speed = tv->track()->speed();
1754 nframes64_t const pf = adjusted_current_frame (event);
1760 switch (_operation) {
1762 trim_type = "Region start trim";
1765 trim_type = "Region end trim";
1768 trim_type = "Region content trim";
1772 _editor->begin_reversible_command (trim_type);
1773 _have_transaction = true;
1775 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1776 RegionView* rv = i->view;
1777 rv->fake_set_opaque(false);
1778 rv->region()->clear_history ();
1779 rv->region()->suspend_property_changes ();
1781 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
1784 arv->temporarily_hide_envelope ();
1787 boost::shared_ptr<Playlist> pl = rv->region()->playlist();
1788 insert_result = _editor->motion_frozen_playlists.insert (pl);
1790 if (insert_result.second) {
1796 bool non_overlap_trim = false;
1798 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1799 non_overlap_trim = true;
1802 switch (_operation) {
1804 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1805 _editor->single_start_trim (*i->view, pf, non_overlap_trim);
1810 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1811 _editor->single_end_trim (*i->view, pf, non_overlap_trim);
1817 bool swap_direction = false;
1819 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1820 swap_direction = true;
1823 nframes64_t frame_delta = 0;
1825 bool left_direction = false;
1826 if (last_pointer_frame() > pf) {
1827 left_direction = true;
1830 if (left_direction) {
1831 frame_delta = (last_pointer_frame() - pf);
1833 frame_delta = (pf - last_pointer_frame());
1836 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1837 _editor->single_contents_trim (*i->view, frame_delta, left_direction, swap_direction);
1843 switch (_operation) {
1845 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1848 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1851 _editor->show_verbose_time_cursor (pf, 10);
1858 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1860 if (movement_occurred) {
1861 motion (event, false);
1863 if (!_editor->selection->selected (_primary)) {
1864 _editor->thaw_region_after_trim (*_primary);
1867 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1868 _editor->thaw_region_after_trim (*i->view);
1869 i->view->fake_set_opaque (true);
1870 if (_have_transaction) {
1871 _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
1875 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1879 _editor->motion_frozen_playlists.clear ();
1881 if (_have_transaction) {
1882 _editor->commit_reversible_command();
1886 /* no mouse movement */
1887 _editor->point_trim (event, adjusted_current_frame (event));
1892 TrimDrag::aborted ()
1894 /* Our motion method is changing model state, so use the Undo system
1895 to cancel. Perhaps not ideal, as this will leave an Undo point
1896 behind which may be slightly odd from the user's point of view.
1901 if (_have_transaction) {
1906 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1910 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1915 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1918 // create a dummy marker for visual representation of moving the copy.
1919 // The actual copying is not done before we reach the finish callback.
1921 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1922 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1923 *new MeterSection (_marker->meter()));
1925 _item = &new_marker->the_item ();
1926 _marker = new_marker;
1930 MetricSection& section (_marker->meter());
1932 if (!section.movable()) {
1938 Drag::start_grab (event, cursor);
1940 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1942 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1946 MeterMarkerDrag::motion (GdkEvent* event, bool)
1948 nframes64_t const pf = adjusted_current_frame (event);
1950 _marker->set_position (pf);
1952 _editor->show_verbose_time_cursor (pf, 10);
1956 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1958 if (!movement_occurred) {
1962 motion (event, false);
1966 TempoMap& map (_editor->session()->tempo_map());
1967 map.bbt_time (last_pointer_frame(), when);
1969 if (_copy == true) {
1970 _editor->begin_reversible_command (_("copy meter mark"));
1971 XMLNode &before = map.get_state();
1972 map.add_meter (_marker->meter(), when);
1973 XMLNode &after = map.get_state();
1974 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1975 _editor->commit_reversible_command ();
1977 // delete the dummy marker we used for visual representation of copying.
1978 // a new visual marker will show up automatically.
1981 _editor->begin_reversible_command (_("move meter mark"));
1982 XMLNode &before = map.get_state();
1983 map.move_meter (_marker->meter(), when);
1984 XMLNode &after = map.get_state();
1985 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1986 _editor->commit_reversible_command ();
1991 MeterMarkerDrag::aborted ()
1993 _marker->set_position (_marker->meter().frame ());
1996 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
2000 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
2005 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2010 // create a dummy marker for visual representation of moving the copy.
2011 // The actual copying is not done before we reach the finish callback.
2013 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
2014 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
2015 *new TempoSection (_marker->tempo()));
2017 _item = &new_marker->the_item ();
2018 _marker = new_marker;
2022 MetricSection& section (_marker->tempo());
2024 if (!section.movable()) {
2029 Drag::start_grab (event, cursor);
2031 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
2032 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2036 TempoMarkerDrag::motion (GdkEvent* event, bool)
2038 nframes64_t const pf = adjusted_current_frame (event);
2039 _marker->set_position (pf);
2040 _editor->show_verbose_time_cursor (pf, 10);
2044 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2046 if (!movement_occurred) {
2050 motion (event, false);
2054 TempoMap& map (_editor->session()->tempo_map());
2055 map.bbt_time (last_pointer_frame(), when);
2057 if (_copy == true) {
2058 _editor->begin_reversible_command (_("copy tempo mark"));
2059 XMLNode &before = map.get_state();
2060 map.add_tempo (_marker->tempo(), when);
2061 XMLNode &after = map.get_state();
2062 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2063 _editor->commit_reversible_command ();
2065 // delete the dummy marker we used for visual representation of copying.
2066 // a new visual marker will show up automatically.
2069 _editor->begin_reversible_command (_("move tempo mark"));
2070 XMLNode &before = map.get_state();
2071 map.move_tempo (_marker->tempo(), when);
2072 XMLNode &after = map.get_state();
2073 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2074 _editor->commit_reversible_command ();
2079 TempoMarkerDrag::aborted ()
2081 _marker->set_position (_marker->tempo().frame());
2084 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2088 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2093 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2095 Drag::start_grab (event, c);
2099 nframes64_t where = _editor->event_frame (event, 0, 0);
2101 _editor->snap_to_with_modifier (where, event);
2102 _editor->playhead_cursor->set_position (where);
2106 if (_cursor == _editor->playhead_cursor) {
2107 _editor->_dragging_playhead = true;
2109 if (_editor->session() && _was_rolling && _stop) {
2110 _editor->session()->request_stop ();
2113 if (_editor->session() && _editor->session()->is_auditioning()) {
2114 _editor->session()->cancel_audition ();
2118 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2120 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2124 CursorDrag::motion (GdkEvent* event, bool)
2126 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2128 if (adjusted_frame == last_pointer_frame()) {
2132 _cursor->set_position (adjusted_frame);
2134 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2137 _editor->update_canvas_now ();
2139 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2143 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2145 _editor->_dragging_playhead = false;
2147 if (!movement_occurred && _stop) {
2151 motion (event, false);
2153 if (_item == &_editor->playhead_cursor->canvas_item) {
2154 if (_editor->session()) {
2155 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2156 _editor->_pending_locate_request = true;
2162 CursorDrag::aborted ()
2164 _editor->_dragging_playhead = false;
2165 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2168 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2169 : RegionDrag (e, i, p, v)
2175 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2177 Drag::start_grab (event, cursor);
2179 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2180 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2182 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2183 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2187 FadeInDrag::motion (GdkEvent* event, bool)
2189 nframes64_t fade_length;
2191 nframes64_t const pos = adjusted_current_frame (event);
2193 boost::shared_ptr<Region> region = _primary->region ();
2195 if (pos < (region->position() + 64)) {
2196 fade_length = 64; // this should be a minimum defined somewhere
2197 } else if (pos > region->last_frame()) {
2198 fade_length = region->length();
2200 fade_length = pos - region->position();
2203 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2205 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2211 tmp->reset_fade_in_shape_width (fade_length);
2214 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2218 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2220 if (!movement_occurred) {
2224 nframes64_t fade_length;
2226 nframes64_t const pos = adjusted_current_frame (event);
2228 boost::shared_ptr<Region> region = _primary->region ();
2230 if (pos < (region->position() + 64)) {
2231 fade_length = 64; // this should be a minimum defined somewhere
2232 } else if (pos > region->last_frame()) {
2233 fade_length = region->length();
2235 fade_length = pos - region->position();
2238 _editor->begin_reversible_command (_("change fade in length"));
2240 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2242 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2248 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2249 XMLNode &before = alist->get_state();
2251 tmp->audio_region()->set_fade_in_length (fade_length);
2252 tmp->audio_region()->set_fade_in_active (true);
2254 XMLNode &after = alist->get_state();
2255 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2258 _editor->commit_reversible_command ();
2262 FadeInDrag::aborted ()
2264 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2265 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2271 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2275 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2276 : RegionDrag (e, i, p, v)
2282 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2284 Drag::start_grab (event, cursor);
2286 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2287 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2289 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2290 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2294 FadeOutDrag::motion (GdkEvent* event, bool)
2296 nframes64_t fade_length;
2298 nframes64_t const pos = adjusted_current_frame (event);
2300 boost::shared_ptr<Region> region = _primary->region ();
2302 if (pos > (region->last_frame() - 64)) {
2303 fade_length = 64; // this should really be a minimum fade defined somewhere
2305 else if (pos < region->position()) {
2306 fade_length = region->length();
2309 fade_length = region->last_frame() - pos;
2312 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2314 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2320 tmp->reset_fade_out_shape_width (fade_length);
2323 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2327 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2329 if (!movement_occurred) {
2333 nframes64_t fade_length;
2335 nframes64_t const pos = adjusted_current_frame (event);
2337 boost::shared_ptr<Region> region = _primary->region ();
2339 if (pos > (region->last_frame() - 64)) {
2340 fade_length = 64; // this should really be a minimum fade defined somewhere
2342 else if (pos < region->position()) {
2343 fade_length = region->length();
2346 fade_length = region->last_frame() - pos;
2349 _editor->begin_reversible_command (_("change fade out length"));
2351 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2353 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2359 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2360 XMLNode &before = alist->get_state();
2362 tmp->audio_region()->set_fade_out_length (fade_length);
2363 tmp->audio_region()->set_fade_out_active (true);
2365 XMLNode &after = alist->get_state();
2366 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2369 _editor->commit_reversible_command ();
2373 FadeOutDrag::aborted ()
2375 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2376 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2382 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2386 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2389 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2392 _points.push_back (Gnome::Art::Point (0, 0));
2393 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2395 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2396 _line->property_width_pixels() = 1;
2397 _line->property_points () = _points;
2400 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2403 MarkerDrag::~MarkerDrag ()
2405 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2411 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2413 Drag::start_grab (event, cursor);
2417 Location *location = _editor->find_location_from_marker (_marker, is_start);
2418 _editor->_dragging_edit_point = true;
2420 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2422 update_item (location);
2424 // _drag_line->show();
2425 // _line->raise_to_top();
2428 _editor->show_verbose_time_cursor (location->start(), 10);
2430 _editor->show_verbose_time_cursor (location->end(), 10);
2433 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2436 case Selection::Toggle:
2437 _editor->selection->toggle (_marker);
2439 case Selection::Set:
2440 if (!_editor->selection->selected (_marker)) {
2441 _editor->selection->set (_marker);
2444 case Selection::Extend:
2446 Locations::LocationList ll;
2447 list<Marker*> to_add;
2449 _editor->selection->markers.range (s, e);
2450 s = min (_marker->position(), s);
2451 e = max (_marker->position(), e);
2454 if (e < max_frames) {
2457 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2458 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2459 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2462 to_add.push_back (lm->start);
2465 to_add.push_back (lm->end);
2469 if (!to_add.empty()) {
2470 _editor->selection->add (to_add);
2474 case Selection::Add:
2475 _editor->selection->add (_marker);
2479 /* Set up copies for us to manipulate during the drag */
2481 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2482 Location* l = _editor->find_location_from_marker (*i, is_start);
2483 _copied_locations.push_back (new Location (*l));
2488 MarkerDrag::motion (GdkEvent* event, bool)
2490 nframes64_t f_delta = 0;
2492 bool move_both = false;
2494 Location *real_location;
2495 Location *copy_location = 0;
2497 nframes64_t const newframe = adjusted_current_frame (event);
2499 nframes64_t next = newframe;
2501 if (newframe == last_pointer_frame()) {
2505 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2509 MarkerSelection::iterator i;
2510 list<Location*>::iterator x;
2512 /* find the marker we're dragging, and compute the delta */
2514 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2515 x != _copied_locations.end() && i != _editor->selection->markers.end();
2521 if (marker == _marker) {
2523 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2528 if (real_location->is_mark()) {
2529 f_delta = newframe - copy_location->start();
2533 switch (marker->type()) {
2535 case Marker::LoopStart:
2536 case Marker::PunchIn:
2537 f_delta = newframe - copy_location->start();
2541 case Marker::LoopEnd:
2542 case Marker::PunchOut:
2543 f_delta = newframe - copy_location->end();
2546 /* what kind of marker is this ? */
2554 if (i == _editor->selection->markers.end()) {
2555 /* hmm, impossible - we didn't find the dragged marker */
2559 /* now move them all */
2561 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2562 x != _copied_locations.end() && i != _editor->selection->markers.end();
2568 /* call this to find out if its the start or end */
2570 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2574 if (real_location->locked()) {
2578 if (copy_location->is_mark()) {
2582 copy_location->set_start (copy_location->start() + f_delta);
2586 nframes64_t new_start = copy_location->start() + f_delta;
2587 nframes64_t new_end = copy_location->end() + f_delta;
2589 if (is_start) { // start-of-range marker
2592 copy_location->set_start (new_start);
2593 copy_location->set_end (new_end);
2594 } else if (new_start < copy_location->end()) {
2595 copy_location->set_start (new_start);
2597 _editor->snap_to (next, 1, true);
2598 copy_location->set_end (next);
2599 copy_location->set_start (newframe);
2602 } else { // end marker
2605 copy_location->set_end (new_end);
2606 copy_location->set_start (new_start);
2607 } else if (new_end > copy_location->start()) {
2608 copy_location->set_end (new_end);
2609 } else if (newframe > 0) {
2610 _editor->snap_to (next, -1, true);
2611 copy_location->set_start (next);
2612 copy_location->set_end (newframe);
2617 update_item (copy_location);
2619 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2622 lm->set_position (copy_location->start(), copy_location->end());
2626 assert (!_copied_locations.empty());
2628 _editor->show_verbose_time_cursor (newframe, 10);
2631 _editor->update_canvas_now ();
2636 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2638 if (!movement_occurred) {
2640 /* just a click, do nothing but finish
2641 off the selection process
2644 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2647 case Selection::Set:
2648 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2649 _editor->selection->set (_marker);
2653 case Selection::Toggle:
2654 case Selection::Extend:
2655 case Selection::Add:
2662 _editor->_dragging_edit_point = false;
2664 _editor->begin_reversible_command ( _("move marker") );
2665 XMLNode &before = _editor->session()->locations()->get_state();
2667 MarkerSelection::iterator i;
2668 list<Location*>::iterator x;
2671 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2672 x != _copied_locations.end() && i != _editor->selection->markers.end();
2675 Location * location = _editor->find_location_from_marker (*i, is_start);
2679 if (location->locked()) {
2683 if (location->is_mark()) {
2684 location->set_start ((*x)->start());
2686 location->set ((*x)->start(), (*x)->end());
2691 XMLNode &after = _editor->session()->locations()->get_state();
2692 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2693 _editor->commit_reversible_command ();
2699 MarkerDrag::aborted ()
2705 MarkerDrag::update_item (Location* location)
2707 double const x1 = _editor->frame_to_pixel (location->start());
2709 _points.front().set_x(x1);
2710 _points.back().set_x(x1);
2711 _line->property_points() = _points;
2714 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2716 _cumulative_x_drag (0),
2717 _cumulative_y_drag (0)
2719 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2725 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2727 Drag::start_grab (event, _editor->fader_cursor);
2729 // start the grab at the center of the control point so
2730 // the point doesn't 'jump' to the mouse after the first drag
2731 _time_axis_view_grab_x = _point->get_x();
2732 _time_axis_view_grab_y = _point->get_y();
2734 float const fraction = 1 - (_point->get_y() / _point->line().height());
2736 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2738 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2739 event->button.x + 10, event->button.y + 10);
2741 _editor->show_verbose_canvas_cursor ();
2745 ControlPointDrag::motion (GdkEvent* event, bool)
2747 double dx = _drags->current_pointer_x() - last_pointer_x();
2748 double dy = _drags->current_pointer_y() - last_pointer_y();
2750 if (event->button.state & Keyboard::SecondaryModifier) {
2755 /* coordinate in TimeAxisView's space */
2756 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2757 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2759 // calculate zero crossing point. back off by .01 to stay on the
2760 // positive side of zero
2761 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2763 // make sure we hit zero when passing through
2764 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2768 if (_x_constrained) {
2769 cx = _time_axis_view_grab_x;
2771 if (_y_constrained) {
2772 cy = _time_axis_view_grab_y;
2775 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2776 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2780 cy = min ((double) _point->line().height(), cy);
2782 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2784 if (!_x_constrained) {
2785 _editor->snap_to_with_modifier (cx_frames, event);
2788 float const fraction = 1.0 - (cy / _point->line().height());
2790 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2792 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2794 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2798 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2800 if (!movement_occurred) {
2804 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2805 _editor->reset_point_selection ();
2809 motion (event, false);
2811 _point->line().end_drag ();
2815 ControlPointDrag::aborted ()
2817 _point->line().reset ();
2821 ControlPointDrag::active (Editing::MouseMode m)
2823 if (m == Editing::MouseGain) {
2824 /* always active in mouse gain */
2828 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2829 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2832 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2835 _cumulative_y_drag (0)
2840 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2842 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2845 _item = &_line->grab_item ();
2847 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2848 origin, and ditto for y.
2851 double cx = event->button.x;
2852 double cy = event->button.y;
2854 _line->parent_group().w2i (cx, cy);
2856 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2861 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2862 /* no adjacent points */
2866 Drag::start_grab (event, _editor->fader_cursor);
2868 /* store grab start in parent frame */
2870 _time_axis_view_grab_x = cx;
2871 _time_axis_view_grab_y = cy;
2873 double fraction = 1.0 - (cy / _line->height());
2875 _line->start_drag_line (before, after, fraction);
2877 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2878 event->button.x + 10, event->button.y + 10);
2880 _editor->show_verbose_canvas_cursor ();
2884 LineDrag::motion (GdkEvent* event, bool)
2886 double dy = _drags->current_pointer_y() - last_pointer_y();
2888 if (event->button.state & Keyboard::SecondaryModifier) {
2892 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2894 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2897 cy = min ((double) _line->height(), cy);
2899 double const fraction = 1.0 - (cy / _line->height());
2903 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2909 /* we are ignoring x position for this drag, so we can just pass in anything */
2910 _line->drag_motion (0, fraction, true, push);
2912 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2916 LineDrag::finished (GdkEvent* event, bool)
2918 motion (event, false);
2923 LineDrag::aborted ()
2929 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2931 Drag::start_grab (event);
2932 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2936 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2943 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2945 nframes64_t grab = grab_frame ();
2946 if (Config->get_rubberbanding_snaps_to_grid ()) {
2947 _editor->snap_to_with_modifier (grab, event);
2950 /* base start and end on initial click position */
2960 if (_drags->current_pointer_y() < grab_y()) {
2961 y1 = _drags->current_pointer_y();
2964 y2 = _drags->current_pointer_y();
2969 if (start != end || y1 != y2) {
2971 double x1 = _editor->frame_to_pixel (start);
2972 double x2 = _editor->frame_to_pixel (end);
2974 _editor->rubberband_rect->property_x1() = x1;
2975 _editor->rubberband_rect->property_y1() = y1;
2976 _editor->rubberband_rect->property_x2() = x2;
2977 _editor->rubberband_rect->property_y2() = y2;
2979 _editor->rubberband_rect->show();
2980 _editor->rubberband_rect->raise_to_top();
2982 _editor->show_verbose_time_cursor (pf, 10);
2987 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2989 if (movement_occurred) {
2991 motion (event, false);
2994 if (_drags->current_pointer_y() < grab_y()) {
2995 y1 = _drags->current_pointer_y();
2998 y2 = _drags->current_pointer_y();
3003 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
3006 _editor->begin_reversible_command (_("rubberband selection"));
3008 if (grab_frame() < last_pointer_frame()) {
3009 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
3011 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
3015 _editor->commit_reversible_command ();
3019 if (!getenv("ARDOUR_SAE")) {
3020 _editor->selection->clear_tracks();
3022 _editor->selection->clear_regions();
3023 _editor->selection->clear_points ();
3024 _editor->selection->clear_lines ();
3027 _editor->rubberband_rect->hide();
3031 RubberbandSelectDrag::aborted ()
3033 _editor->rubberband_rect->hide ();
3037 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3039 Drag::start_grab (event);
3041 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3045 TimeFXDrag::motion (GdkEvent* event, bool)
3047 RegionView* rv = _primary;
3049 nframes64_t const pf = adjusted_current_frame (event);
3051 if (pf > rv->region()->position()) {
3052 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3055 _editor->show_verbose_time_cursor (pf, 10);
3059 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3061 _primary->get_time_axis_view().hide_timestretch ();
3063 if (!movement_occurred) {
3067 if (last_pointer_frame() < _primary->region()->position()) {
3068 /* backwards drag of the left edge - not usable */
3072 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3074 float percentage = (double) newlen / (double) _primary->region()->length();
3076 #ifndef USE_RUBBERBAND
3077 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3078 if (_primary->region()->data_type() == DataType::AUDIO) {
3079 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3083 _editor->begin_reversible_command (_("timestretch"));
3085 // XXX how do timeFX on multiple regions ?
3090 if (_editor->time_stretch (rs, percentage) == -1) {
3091 error << _("An error occurred while executing time stretch operation") << endmsg;
3096 TimeFXDrag::aborted ()
3098 _primary->get_time_axis_view().hide_timestretch ();
3103 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3105 Drag::start_grab (event);
3109 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3111 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3115 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3117 if (movement_occurred && _editor->session()) {
3118 /* make sure we stop */
3119 _editor->session()->request_transport_speed (0.0);
3124 ScrubDrag::aborted ()
3129 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3133 , _original_pointer_time_axis (-1)
3134 , _last_pointer_time_axis (-1)
3140 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3142 nframes64_t start = 0;
3143 nframes64_t end = 0;
3145 if (_editor->session() == 0) {
3149 Gdk::Cursor* cursor = 0;
3151 switch (_operation) {
3152 case CreateSelection:
3153 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3158 cursor = _editor->selector_cursor;
3159 Drag::start_grab (event, cursor);
3162 case SelectionStartTrim:
3163 if (_editor->clicked_axisview) {
3164 _editor->clicked_axisview->order_selection_trims (_item, true);
3166 Drag::start_grab (event, _editor->trimmer_cursor);
3167 start = _editor->selection->time[_editor->clicked_selection].start;
3168 _pointer_frame_offset = grab_frame() - start;
3171 case SelectionEndTrim:
3172 if (_editor->clicked_axisview) {
3173 _editor->clicked_axisview->order_selection_trims (_item, false);
3175 Drag::start_grab (event, _editor->trimmer_cursor);
3176 end = _editor->selection->time[_editor->clicked_selection].end;
3177 _pointer_frame_offset = grab_frame() - end;
3181 start = _editor->selection->time[_editor->clicked_selection].start;
3182 Drag::start_grab (event, cursor);
3183 _pointer_frame_offset = grab_frame() - start;
3187 if (_operation == SelectionMove) {
3188 _editor->show_verbose_time_cursor (start, 10);
3190 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3193 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3197 SelectionDrag::motion (GdkEvent* event, bool first_move)
3199 nframes64_t start = 0;
3200 nframes64_t end = 0;
3203 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3204 if (pending_time_axis.first == 0) {
3208 nframes64_t const pending_position = adjusted_current_frame (event);
3210 /* only alter selection if things have changed */
3212 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3216 switch (_operation) {
3217 case CreateSelection:
3219 nframes64_t grab = grab_frame ();
3222 _editor->snap_to (grab);
3225 if (pending_position < grab_frame()) {
3226 start = pending_position;
3229 end = pending_position;
3233 /* first drag: Either add to the selection
3234 or create a new selection
3240 /* adding to the selection */
3241 _editor->selection->add (_editor->clicked_axisview);
3242 _editor->clicked_selection = _editor->selection->add (start, end);
3247 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3248 _editor->selection->set (_editor->clicked_axisview);
3251 _editor->clicked_selection = _editor->selection->set (start, end);
3255 /* select the track that we're in */
3256 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3257 _editor->selection->add (pending_time_axis.first);
3258 _added_time_axes.push_back (pending_time_axis.first);
3261 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3262 tracks that we selected in the first place.
3265 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3266 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3268 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3269 while (i != _added_time_axes.end()) {
3271 list<TimeAxisView*>::iterator tmp = i;
3274 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3275 _editor->selection->remove (*i);
3276 _added_time_axes.remove (*i);
3285 case SelectionStartTrim:
3287 start = _editor->selection->time[_editor->clicked_selection].start;
3288 end = _editor->selection->time[_editor->clicked_selection].end;
3290 if (pending_position > end) {
3293 start = pending_position;
3297 case SelectionEndTrim:
3299 start = _editor->selection->time[_editor->clicked_selection].start;
3300 end = _editor->selection->time[_editor->clicked_selection].end;
3302 if (pending_position < start) {
3305 end = pending_position;
3312 start = _editor->selection->time[_editor->clicked_selection].start;
3313 end = _editor->selection->time[_editor->clicked_selection].end;
3315 length = end - start;
3317 start = pending_position;
3318 _editor->snap_to (start);
3320 end = start + length;
3325 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3326 _editor->start_canvas_autoscroll (1, 0);
3330 _editor->selection->replace (_editor->clicked_selection, start, end);
3333 if (_operation == SelectionMove) {
3334 _editor->show_verbose_time_cursor(start, 10);
3336 _editor->show_verbose_time_cursor(pending_position, 10);
3341 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3343 Session* s = _editor->session();
3345 if (movement_occurred) {
3346 motion (event, false);
3347 /* XXX this is not object-oriented programming at all. ick */
3348 if (_editor->selection->time.consolidate()) {
3349 _editor->selection->TimeChanged ();
3352 /* XXX what if its a music time selection? */
3353 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3354 s->request_play_range (&_editor->selection->time, true);
3359 /* just a click, no pointer movement.*/
3361 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3362 _editor->selection->clear_time();
3365 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3366 _editor->selection->set (_editor->clicked_axisview);
3369 if (s && s->get_play_range () && s->transport_rolling()) {
3370 s->request_stop (false, false);
3375 _editor->stop_canvas_autoscroll ();
3379 SelectionDrag::aborted ()
3384 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3389 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3390 _drag_rect->hide ();
3392 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3393 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3397 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3399 if (_editor->session() == 0) {
3403 Gdk::Cursor* cursor = 0;
3405 if (!_editor->temp_location) {
3406 _editor->temp_location = new Location;
3409 switch (_operation) {
3410 case CreateRangeMarker:
3411 case CreateTransportMarker:
3412 case CreateCDMarker:
3414 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3419 cursor = _editor->selector_cursor;
3423 Drag::start_grab (event, cursor);
3425 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3429 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3431 nframes64_t start = 0;
3432 nframes64_t end = 0;
3433 ArdourCanvas::SimpleRect *crect;
3435 switch (_operation) {
3436 case CreateRangeMarker:
3437 crect = _editor->range_bar_drag_rect;
3439 case CreateTransportMarker:
3440 crect = _editor->transport_bar_drag_rect;
3442 case CreateCDMarker:
3443 crect = _editor->cd_marker_bar_drag_rect;
3446 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3451 nframes64_t const pf = adjusted_current_frame (event);
3453 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3454 nframes64_t grab = grab_frame ();
3455 _editor->snap_to (grab);
3457 if (pf < grab_frame()) {
3465 /* first drag: Either add to the selection
3466 or create a new selection.
3471 _editor->temp_location->set (start, end);
3475 update_item (_editor->temp_location);
3477 //_drag_rect->raise_to_top();
3482 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3483 _editor->start_canvas_autoscroll (1, 0);
3487 _editor->temp_location->set (start, end);
3489 double x1 = _editor->frame_to_pixel (start);
3490 double x2 = _editor->frame_to_pixel (end);
3491 crect->property_x1() = x1;
3492 crect->property_x2() = x2;
3494 update_item (_editor->temp_location);
3497 _editor->show_verbose_time_cursor (pf, 10);
3502 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3504 Location * newloc = 0;
3508 if (movement_occurred) {
3509 motion (event, false);
3512 switch (_operation) {
3513 case CreateRangeMarker:
3514 case CreateCDMarker:
3516 _editor->begin_reversible_command (_("new range marker"));
3517 XMLNode &before = _editor->session()->locations()->get_state();
3518 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3519 if (_operation == CreateCDMarker) {
3520 flags = Location::IsRangeMarker | Location::IsCDMarker;
3521 _editor->cd_marker_bar_drag_rect->hide();
3524 flags = Location::IsRangeMarker;
3525 _editor->range_bar_drag_rect->hide();
3527 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3528 _editor->session()->locations()->add (newloc, true);
3529 XMLNode &after = _editor->session()->locations()->get_state();
3530 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3531 _editor->commit_reversible_command ();
3535 case CreateTransportMarker:
3536 // popup menu to pick loop or punch
3537 _editor->new_transport_marker_context_menu (&event->button, _item);
3541 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3543 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3548 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3550 if (end == max_frames) {
3551 end = _editor->session()->current_end_frame ();
3554 if (start == max_frames) {
3555 start = _editor->session()->current_start_frame ();
3558 switch (_editor->mouse_mode) {
3560 /* find the two markers on either side and then make the selection from it */
3561 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3565 /* find the two markers on either side of the click and make the range out of it */
3566 _editor->selection->set (start, end);
3575 _editor->stop_canvas_autoscroll ();
3579 RangeMarkerBarDrag::aborted ()
3585 RangeMarkerBarDrag::update_item (Location* location)
3587 double const x1 = _editor->frame_to_pixel (location->start());
3588 double const x2 = _editor->frame_to_pixel (location->end());
3590 _drag_rect->property_x1() = x1;
3591 _drag_rect->property_x2() = x2;
3595 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3597 Drag::start_grab (event, _editor->zoom_cursor);
3598 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3602 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3607 nframes64_t const pf = adjusted_current_frame (event);
3609 nframes64_t grab = grab_frame ();
3610 _editor->snap_to_with_modifier (grab, event);
3612 /* base start and end on initial click position */
3624 _editor->zoom_rect->show();
3625 _editor->zoom_rect->raise_to_top();
3628 _editor->reposition_zoom_rect(start, end);
3630 _editor->show_verbose_time_cursor (pf, 10);
3635 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3637 if (movement_occurred) {
3638 motion (event, false);
3640 if (grab_frame() < last_pointer_frame()) {
3641 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3643 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3646 _editor->temporal_zoom_to_frame (false, grab_frame());
3648 temporal_zoom_step (false);
3649 center_screen (grab_frame());
3653 _editor->zoom_rect->hide();
3657 MouseZoomDrag::aborted ()
3659 _editor->zoom_rect->hide ();
3662 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3665 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3666 region = &cnote->region_view();
3670 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3672 Drag::start_grab (event);
3675 drag_delta_note = 0;
3680 event_x = _drags->current_pointer_x();
3681 event_y = _drags->current_pointer_y();
3683 _item->property_parent().get_value()->w2i(event_x, event_y);
3685 last_x = region->snap_to_pixel(event_x);
3688 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3690 if (!(was_selected = cnote->selected())) {
3692 /* tertiary-click means extend selection - we'll do that on button release,
3693 so don't add it here, because otherwise we make it hard to figure
3694 out the "extend-to" range.
3697 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3700 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3703 region->note_selected (cnote, true);
3705 region->unique_select (cnote);
3712 NoteDrag::motion (GdkEvent*, bool)
3714 MidiStreamView* streamview = region->midi_stream_view();
3718 event_x = _drags->current_pointer_x();
3719 event_y = _drags->current_pointer_y();
3721 _item->property_parent().get_value()->w2i(event_x, event_y);
3723 event_x = region->snap_to_pixel(event_x);
3725 double dx = event_x - last_x;
3726 double dy = event_y - last_y;
3731 // Snap to note rows
3733 if (abs (dy) < streamview->note_height()) {
3736 int8_t this_delta_note;
3738 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3740 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3742 drag_delta_note -= this_delta_note;
3743 dy = streamview->note_height() * this_delta_note;
3744 last_y = last_y + dy;
3748 region->move_selection (dx, dy);
3750 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3752 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3753 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3754 _editor->show_verbose_canvas_cursor_with (buf);
3759 NoteDrag::finished (GdkEvent* ev, bool moved)
3761 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3764 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3767 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3769 region->note_deselected (cnote);
3772 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3773 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3775 if (!extend && !add && region->selection_size() > 1) {
3776 region->unique_select(cnote);
3777 } else if (extend) {
3778 region->note_selected (cnote, true, true);
3780 /* it was added during button press */
3785 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3790 NoteDrag::aborted ()
3795 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3798 , _nothing_to_drag (false)
3800 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3803 _line = _atav->line ();
3807 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3809 Drag::start_grab (event, cursor);
3811 list<ControlPoint*> points;
3813 XMLNode* state = &_line->get_state ();
3815 if (_ranges.empty()) {
3817 uint32_t const N = _line->npoints ();
3818 for (uint32_t i = 0; i < N; ++i) {
3819 points.push_back (_line->nth (i));
3824 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3825 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3827 /* fade into and out of the region that we're dragging;
3828 64 samples length plucked out of thin air.
3830 nframes64_t const h = (j->start + j->end) / 2;
3831 nframes64_t a = j->start + 64;
3835 nframes64_t b = j->end - 64;
3840 the_list->add (j->start, the_list->eval (j->start));
3841 _line->add_always_in_view (j->start);
3842 the_list->add (a, the_list->eval (a));
3843 _line->add_always_in_view (a);
3844 the_list->add (b, the_list->eval (b));
3845 _line->add_always_in_view (b);
3846 the_list->add (j->end, the_list->eval (j->end));
3847 _line->add_always_in_view (j->end);
3850 uint32_t const N = _line->npoints ();
3851 for (uint32_t i = 0; i < N; ++i) {
3853 ControlPoint* p = _line->nth (i);
3855 list<AudioRange>::const_iterator j = _ranges.begin ();
3856 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3860 if (j != _ranges.end()) {
3861 points.push_back (p);
3866 if (points.empty()) {
3867 _nothing_to_drag = true;
3871 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3875 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3877 if (_nothing_to_drag) {
3881 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3883 /* we are ignoring x position for this drag, so we can just pass in anything */
3884 _line->drag_motion (0, f, true, false);
3888 AutomationRangeDrag::finished (GdkEvent* event, bool)
3890 if (_nothing_to_drag) {
3894 motion (event, false);
3896 _line->clear_always_in_view ();
3900 AutomationRangeDrag::aborted ()
3902 _line->clear_always_in_view ();
3906 DraggingView::DraggingView (RegionView* v)
3909 initial_y = v->get_canvas_group()->property_y ();