#include "ardour/audioengine.h"
#include "ardour/audioregion.h"
+#include "ardour/audio_track.h"
#include "ardour/dB.h"
#include "ardour/midi_region.h"
+#include "ardour/midi_track.h"
#include "ardour/operations.h"
#include "ardour/region_factory.h"
#include "ardour/session.h"
+#include "canvas/scroll_group.h"
+
#include "editor.h"
#include "i18n.h"
#include "keyboard.h"
#include "ardour_ui.h"
#include "gui_thread.h"
#include "control_point.h"
-#include "utils.h"
#include "region_gain_line.h"
#include "editor_drag.h"
#include "audio_time_axis.h"
{
bool r = false;
- _current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y);
-
- for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
- bool const t = (*i)->motion_handler (e, from_autoscroll);
- if (t) {
- r = true;
- }
-
- }
-
- return r;
-}
-
-bool
-DragManager::window_motion_handler (GdkEvent* e, bool from_autoscroll)
-{
- bool r = false;
+ /* calling this implies that we expect the event to have canvas
+ * coordinates
+ *
+ * Can we guarantee that this is true?
+ */
_current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y);
for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
bool const t = (*i)->motion_handler (e, from_autoscroll);
+ /* run all handlers; return true if at least one of them
+ returns true (indicating that the event has been handled).
+ */
if (t) {
r = true;
}
return j != _drags.end ();
}
-Drag::Drag (Editor* e, ArdourCanvas::Item* i)
+Drag::Drag (Editor* e, ArdourCanvas::Item* i, bool trackview_only)
: _editor (e)
, _item (i)
, _pointer_frame_offset (0)
+ , _trackview_only (trackview_only)
, _move_threshold_passed (false)
, _was_double_click (false)
, _raw_grab_frame (0)
_grab_frame = adjusted_frame (_raw_grab_frame, event);
_last_pointer_frame = _grab_frame;
_last_pointer_x = _grab_x;
+
+ if (_trackview_only) {
+ _grab_y = _grab_y - _editor->get_trackview_group()->canvas_origin().y;
+ }
+
_last_pointer_y = _grab_y;
if (cursor == 0) {
_item->grab ();
-
} else {
/* CAIROCANVAS need a variant here that passes *cursor */
_item->grab ();
-
+ _editor->push_canvas_cursor (cursor);
}
if (_editor->session() && _editor->session()->transport_rolling()) {
finished (event, _move_threshold_passed);
_editor->verbose_cursor()->hide ();
+ _editor->pop_canvas_cursor ();
return _move_threshold_passed;
}
return adjusted_frame (_drags->current_pointer_frame (), event, snap);
}
+double
+Drag::current_pointer_y () const
+{
+ if (!_trackview_only) {
+ return _drags->current_pointer_y ();
+ }
+
+ return _drags->current_pointer_y () - _editor->get_trackview_group()->canvas_origin().y;
+}
+
bool
Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
{
/* check to see if we have moved in any way that matters since the last motion event */
if (_move_threshold_passed &&
(!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
- (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
+ (!y_movement_matters() || _last_pointer_y == current_pointer_y ()) ) {
return false;
}
if (!from_autoscroll && !_move_threshold_passed) {
bool const xp = (::llabs (_drags->current_pointer_frame () - _raw_grab_frame) >= threshold.first);
- bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
+ bool const yp = (::fabs ((current_pointer_y () - _grab_y)) >= threshold.second);
_move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
}
motion (event, _move_threshold_passed != old_move_threshold_passed);
_last_pointer_x = _drags->current_pointer_x ();
- _last_pointer_y = _drags->current_pointer_y ();
+ _last_pointer_y = current_pointer_y ();
_last_pointer_frame = adjusted_current_frame (event);
}
return true;
}
}
+
return false;
}
void
Drag::show_verbose_cursor_time (framepos_t frame)
{
- _editor->verbose_cursor()->set_time (
- frame,
- _drags->current_pointer_x() + 10,
- _drags->current_pointer_y() + 10
- );
-
+ _editor->verbose_cursor()->set_time (frame);
_editor->verbose_cursor()->show ();
}
void
-Drag::show_verbose_cursor_duration (framepos_t start, framepos_t end, double xoffset)
+Drag::show_verbose_cursor_duration (framepos_t start, framepos_t end, double /*xoffset*/)
{
- _editor->verbose_cursor()->show (xoffset);
-
- _editor->verbose_cursor()->set_duration (
- start, end,
- _drags->current_pointer_x() + 10,
- _drags->current_pointer_y() + 10
- );
+ _editor->verbose_cursor()->set_duration (start, end);
+ _editor->verbose_cursor()->show ();
}
void
Drag::show_verbose_cursor_text (string const & text)
{
+ _editor->verbose_cursor()->set (text);
_editor->verbose_cursor()->show ();
-
- _editor->verbose_cursor()->set (
- text,
- _drags->current_pointer_x() + 10,
- _drags->current_pointer_y() + 10
- );
}
boost::shared_ptr<Region>
*/
for (list<RegionView*>::const_iterator i = v.begin(); i != v.end(); ++i) {
- _views.push_back (DraggingView (*i, this));
+ _views.push_back (DraggingView (*i, this, &(*i)->get_time_axis_view()));
}
RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), boost::bind (&RegionDrag::region_going_away, this, _1), gui_context());
show_verbose_cursor_time (_last_frame_position);
- pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (current_pointer_y ());
if (tv.first) {
_last_pointer_time_axis_view = find_time_axis_view (tv.first);
_last_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
void
RegionMotionDrag::motion (GdkEvent* event, bool first_move)
{
- assert (!_views.empty ());
+ double delta_layer = 0;
+ int delta_time_axis_view = 0;
- /* Find the TimeAxisView that the pointer is now over */
- pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ assert (!_views.empty ());
- /* Bail early if we're not over a track */
- RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv.first);
+ /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */
- if (!rtv || !rtv->is_track()) {
- _editor->verbose_cursor()->hide ();
- return;
- }
+ /* Find the TimeAxisView that the pointer is now over */
+ pair<TimeAxisView*, double> const r = _editor->trackview_by_y_position (current_pointer_y ());
+ TimeAxisView* tv = r.first;
- if (first_move && tv.first->view()->layer_display() == Stacked) {
- tv.first->view()->set_layer_display (Expanded);
- }
+ if (tv && tv->view()) {
+ double layer = r.second;
- /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */
+ if (first_move && tv->view()->layer_display() == Stacked) {
+ tv->view()->set_layer_display (Expanded);
+ }
- /* Here's the current pointer position in terms of time axis view and layer */
- int const current_pointer_time_axis_view = find_time_axis_view (tv.first);
- double const current_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
+ /* Here's the current pointer position in terms of time axis view and layer */
+ int const current_pointer_time_axis_view = find_time_axis_view (tv);
+ double const current_pointer_layer = tv->layer_display() == Overlaid ? 0 : layer;
+
+ /* Work out the change in y */
+ delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
+ delta_layer = current_pointer_layer - _last_pointer_layer;
+ }
+
/* Work out the change in x */
framepos_t pending_region_position;
double const x_delta = compute_x_delta (event, &pending_region_position);
_last_frame_position = pending_region_position;
- /* Work out the change in y */
-
- int delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
- double delta_layer = current_pointer_layer - _last_pointer_layer;
-
+ /* Verify change in y */
if (!y_movement_allowed (delta_time_axis_view, delta_layer)) {
/* this y movement is not allowed, so do no y movement this time */
delta_time_axis_view = 0;
delta_layer = 0;
}
- if (x_delta == 0 && delta_time_axis_view == 0 && delta_layer == 0 && !first_move) {
+ if (x_delta == 0 && (tv && tv->view() && delta_time_axis_view == 0) && delta_layer == 0 && !first_move) {
/* haven't reached next snap point, and we're not switching
trackviews nor layers. nothing to do.
*/
}
if (first_move) {
-
rv->drag_start ();
- /* Reparent to a non scrolling group so that we can keep the
- region selection above all time axis views.
- Reparenting means that we will have to move the region view
- within its new parent, as the two parent groups have different coordinates.
+ /* reparent the regionview into a group above all
+ * others
+ */
+
+ ArdourCanvas::Item* rvg = rv->get_canvas_group();
+ Duple rv_canvas_offset = rvg->parent()->canvas_origin ();
+ Duple dmg_canvas_offset = _editor->_drag_motion_group->canvas_origin ();
+ rv->get_canvas_group()->reparent (_editor->_drag_motion_group);
+ /* move the item so that it continues to appear at the
+ same location now that its parent has changed.
*/
-
- ArdourCanvas::Group* rvg = rv->get_canvas_group();
- Duple rv_canvas_offset = rvg->item_to_canvas (Duple (0,0));
-
- rv->get_canvas_group()->reparent (_editor->_region_motion_group);
-
- rv->fake_set_opaque (true);
- rvg->set_position (rv_canvas_offset);
+ rvg->move (rv_canvas_offset - dmg_canvas_offset);
}
/* If we have moved tracks, we'll fudge the layer delta so that the
this_delta_layer = - i->layer;
}
- /* The TimeAxisView that this region is now on */
- TimeAxisView* tv = _time_axis_views[i->time_axis_view + delta_time_axis_view];
+ if (tv) {
- /* Ensure it is moved from stacked -> expanded if appropriate */
- if (tv->view()->layer_display() == Stacked) {
- tv->view()->set_layer_display (Expanded);
- }
+ int track_index;
+
+ if (i->time_axis_view >= 0) {
+ track_index = i->time_axis_view + delta_time_axis_view;
+ } else {
+ track_index = _time_axis_views.size() - 1 + delta_time_axis_view;
+ }
+
+ if (track_index < 0 || track_index >= (int) _time_axis_views.size()) {
+ continue;
+ }
+
+ /* The TimeAxisView that this region is now over */
+ TimeAxisView* current_tv = _time_axis_views[track_index];
+
+ /* Ensure it is moved from stacked -> expanded if appropriate */
+ if (current_tv->view()->layer_display() == Stacked) {
+ current_tv->view()->set_layer_display (Expanded);
+ }
- /* We're only allowed to go -ve in layer on Expanded views */
- if (tv->view()->layer_display() != Expanded && (i->layer + this_delta_layer) < 0) {
- this_delta_layer = - i->layer;
- }
+ /* We're only allowed to go -ve in layer on Expanded views */
+ if (current_tv->view()->layer_display() != Expanded && (i->layer + this_delta_layer) < 0) {
+ this_delta_layer = - i->layer;
+ }
- /* Set height */
- rv->set_height (tv->view()->child_height ());
+ /* Set height */
+ rv->set_height (current_tv->view()->child_height ());
- /* Update show/hidden status as the region view may have come from a hidden track,
- or have moved to one.
- */
- if (tv->hidden ()) {
- rv->get_canvas_group()->hide ();
- } else {
- rv->get_canvas_group()->show ();
- }
+ /* Update show/hidden status as the region view may have come from a hidden track,
+ or have moved to one.
+ */
+ if (current_tv->hidden ()) {
+ rv->get_canvas_group()->hide ();
+ } else {
+ rv->get_canvas_group()->show ();
+ }
- /* Update the DraggingView */
- i->time_axis_view += delta_time_axis_view;
- i->layer += this_delta_layer;
+ /* Update the DraggingView */
+ i->time_axis_view = track_index;
+ i->layer += this_delta_layer;
- if (_brushing) {
- _editor->mouse_brush_insert_region (rv, pending_region_position);
- } else {
- double x = 0;
- double y = 0;
+ if (_brushing) {
+ _editor->mouse_brush_insert_region (rv, pending_region_position);
+ } else {
+ Duple track_origin;
- /* Get the y coordinate of the top of the track that this region is now on */
- tv->canvas_display()->item_to_canvas (x, y);
+ /* Get the y coordinate of the top of the track that this region is now over */
+ track_origin = current_tv->canvas_display()->item_to_canvas (track_origin);
+
+ /* And adjust for the layer that it should be on */
+ StreamView* cv = current_tv->view ();
+ switch (cv->layer_display ()) {
+ case Overlaid:
+ break;
+ case Stacked:
+ track_origin.y += (cv->layers() - i->layer - 1) * cv->child_height ();
+ break;
+ case Expanded:
+ track_origin.y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height ();
+ break;
+ }
- /* And adjust for the layer that it should be on */
- StreamView* cv = tv->view ();
- switch (cv->layer_display ()) {
- case Overlaid:
- break;
- case Stacked:
- y += (cv->layers() - i->layer - 1) * cv->child_height ();
- break;
- case Expanded:
- y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height ();
- break;
+ /* need to get the parent of the regionview
+ * canvas group and get its position in
+ * equivalent coordinate space as the trackview
+ * we are now dragging over.
+ */
+
+ /* Now move the region view */
+ rv->move (x_delta, track_origin.y - rv->get_canvas_group()->canvas_origin().y);
}
+ } else {
- /* Now move the region view */
- rv->move (x_delta, y - rv->get_canvas_group()->position().y);
- }
+ /* Only move the region into the empty dropzone at the bottom if the pointer
+ * is down there.
+ */
+
+ if (current_pointer_y() >= 0) {
+
+ Coord last_track_bottom_edge;
+ if (!_time_axis_views.empty()) {
+ TimeAxisView* last = _time_axis_views.back();
+ last_track_bottom_edge = last->canvas_display()->canvas_origin ().y + last->effective_height();
+ } else {
+ last_track_bottom_edge = 0;
+ }
+ rv->move (x_delta, last_track_bottom_edge - rv->get_canvas_group()->canvas_origin().y);
+ i->time_axis_view = -1;
+ }
+ }
+
} /* foreach region */
_total_x_delta += x_delta;
}
nrv->get_canvas_group()->show ();
- new_regionviews.push_back (DraggingView (nrv, this));
+ new_regionviews.push_back (DraggingView (nrv, this, i->initial_time_axis_view));
/* swap _primary to the copy */
_editor->maybe_locate_with_edit_preroll (_editor->get_selection().regions.start());
}
+RouteTimeAxisView*
+RegionMoveDrag::create_destination_time_axis (boost::shared_ptr<Region> region, TimeAxisView* original)
+{
+ /* Add a new track of the correct type, and return the RouteTimeAxisView that is created to display the
+ new track.
+ */
+
+ try {
+ if (boost::dynamic_pointer_cast<AudioRegion> (region)) {
+ list<boost::shared_ptr<AudioTrack> > audio_tracks;
+ audio_tracks = _editor->session()->new_audio_track (region->n_channels(), region->n_channels(), ARDOUR::Normal, 0, 1, region->name());
+ RouteTimeAxisView* rtav = _editor->axis_view_from_route (audio_tracks.front());
+ if (rtav) {
+ rtav->set_height (original->current_height());
+ }
+ return rtav;
+ } else {
+ ChanCount one_midi_port (DataType::MIDI, 1);
+ list<boost::shared_ptr<MidiTrack> > midi_tracks;
+ midi_tracks = _editor->session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), ARDOUR::Normal, 0, 1, region->name());
+ RouteTimeAxisView* rtav = _editor->axis_view_from_route (midi_tracks.front());
+ if (rtav) {
+ rtav->set_height (original->current_height());
+ }
+ return rtav;
+ }
+ } catch (...) {
+ error << _("Could not create new track after region placed in the drop zone") << endmsg;
+ return 0;
+ }
+}
+
void
RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed_tracks*/, framecnt_t const drag_delta)
{
RegionSelection new_views;
PlaylistSet modified_playlists;
- list<RegionView*> views_to_delete;
+ RouteTimeAxisView* new_time_axis_view = 0;
if (_brushing) {
/* all changes were made during motion event handlers */
}
/* insert the regions into their new playlists */
- for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end();) {
+
+ RouteTimeAxisView* dest_rtv = 0;
if (i->view->region()->locked() || i->view->region()->video_locked()) {
continue;
} else {
where = i->view->region()->position();
}
-
- RegionView* new_view = insert_region_into_playlist (
- i->view->region(), dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]), i->layer, where, modified_playlists
- );
-
- if (new_view == 0) {
- continue;
+
+ if (i->time_axis_view < 0) {
+ if (!new_time_axis_view) {
+ new_time_axis_view = create_destination_time_axis (i->view->region(), i->initial_time_axis_view);
+ }
+ dest_rtv = new_time_axis_view;
+ } else {
+ dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
+ }
+
+ if (dest_rtv != 0) {
+ RegionView* new_view = insert_region_into_playlist (i->view->region(), dest_rtv, i->layer, where, modified_playlists);
+ if (new_view != 0) {
+ new_views.push_back (new_view);
+ }
}
+
+ /* Delete the copy of the view that was used for dragging. Need to play safe with the iterator
+ since deletion will automagically remove it from _views, thus invalidating i as an iterator.
+ */
- new_views.push_back (new_view);
-
- /* we don't need the copied RegionView any more */
- views_to_delete.push_back (i->view);
- }
-
- /* Delete views that are no longer needed; we can't do this directly in the iteration over _views
- because when views are deleted they are automagically removed from _views, which messes
- up the iteration.
- */
- for (list<RegionView*>::iterator i = views_to_delete.begin(); i != views_to_delete.end(); ++i) {
- delete *i;
+ list<DraggingView>::const_iterator next = i;
+ ++next;
+ delete i->view;
+ i = next;
}
/* If we've created new regions either by copying or moving
PlaylistSet modified_playlists;
PlaylistSet frozen_playlists;
set<RouteTimeAxisView*> views_to_update;
+ RouteTimeAxisView* new_time_axis_view = 0;
if (_brushing) {
/* all changes were made during motion event handlers */
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
RegionView* rv = i->view;
-
- RouteTimeAxisView* const dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
- double const dest_layer = i->layer;
+ RouteTimeAxisView* dest_rtv = 0;
if (rv->region()->locked() || rv->region()->video_locked()) {
++i;
continue;
}
+
+ if (i->time_axis_view < 0) {
+ if (!new_time_axis_view) {
+ new_time_axis_view = create_destination_time_axis (rv->region(), i->initial_time_axis_view);
+ }
+ dest_rtv = new_time_axis_view;
+ } else {
+ dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
+ }
+
+ assert (dest_rtv);
+ double const dest_layer = i->layer;
+
views_to_update.insert (dest_rtv);
framepos_t where;
visible.
*/
rv->hide_region_editor();
- rv->fake_set_opaque (false);
+
remove_region_from_playlist (rv->region(), i->initial_playlist, modified_playlists);
rv->get_canvas_group()->reparent (rtv->view()->canvas_item());
rv->get_canvas_group()->set_y_position (0);
rv->drag_end ();
- rv->fake_set_opaque (false);
rv->move (-_total_x_delta, 0);
rv->set_height (rtv->view()->child_height ());
}
_primary->get_canvas_group()->show ();
_primary->set_position (pos, 0);
- _views.push_back (DraggingView (_primary, this));
+ _views.push_back (DraggingView (_primary, this, v));
_last_frame_position = pos;
{
/* Which trackview is this ? */
- pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
/* The region motion is only processed if the pointer is over
*/
_editor->verbose_cursor()->hide ();
return;
+ } else {
+ _editor->verbose_cursor()->show ();
}
int dir;
(*i)->drag_start();
ArdourCanvas::Item* rvg = (*i)->get_canvas_group();
Duple rv_canvas_offset = rvg->item_to_canvas (Duple (0,0));
- rvg->reparent (_editor->_region_motion_group);
- (*i)->fake_set_opaque (true);
- rvg->set_position (rv_canvas_offset);
+ Duple dmg_canvas_offset = _editor->_drag_motion_group->canvas_origin ();
+ rvg->reparent (_editor->_drag_motion_group);
+
+ // XXX without the following, things jump in the y direction during drags
+ // with it, they jump in the x direction
+ // so we need to do the move in the y direction only
+ // rvg->move (rv_canvas_offset - dmg_canvas_offset);
+ std::cerr << "rv_canvas_offset = " << rv_canvas_offset << ", dmg_canvas_offset = " << dmg_canvas_offset << std::endl;
+ Duple fudge = rv_canvas_offset - dmg_canvas_offset;
+ fudge.x = 0;
+ rvg->move (fudge);
+
}
- _views.push_back (DraggingView (*i, this));
+ _views.push_back (DraggingView (*i, this, tav));
}
}
}
{
/* Which trackview is this ? */
- pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
/* The region motion is only processed if the pointer is over
Timecode::Time timecode;
_editor->session()->sample_to_timecode(abs(_startdrag_video_offset), timecode, true /* use_offset */, false /* use_subframes */ );
snprintf (buf, sizeof (buf), "Video Start:\n%c%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, (_startdrag_video_offset<0?'-':' '), timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
- _editor->verbose_cursor()->set(buf, event->button.x + 10, event->button.y + 10);
- _editor->verbose_cursor()->show ();
+ show_verbose_cursor_text (buf);
}
void
DEBUG_TRACE (DEBUG::Drags, string_compose("SHIFT REGION at %1 by %2\n", i->initial_position, dt));
if (first_move) {
rv->drag_start ();
- rv->fake_set_opaque (true);
rv->region()->clear_changes ();
rv->region()->suspend_property_changes();
}
, _("Diff:"),
(dt<0?'-':' '), timediff.hours, timediff.minutes, timediff.seconds, timediff.frames
);
- _editor->verbose_cursor()->set(buf, event->button.x + 10, event->button.y + 10);
- _editor->verbose_cursor()->show ();
+ show_verbose_cursor_text (buf);
}
void
for (list<AVDraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
i->view->drag_end();
- i->view->fake_set_opaque (false);
i->view->region()->resume_property_changes ();
_editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
if (pf < (region_start + region_length/2)) {
/* closer to front */
_operation = StartTrim;
- Drag::start_grab (event, _editor->cursors()->left_side_trim);
+
+ if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
+ Drag::start_grab (event, _editor->cursors()->anchored_left_side_trim);
+ } else {
+ Drag::start_grab (event, _editor->cursors()->left_side_trim);
+ }
} else {
/* closer to end */
_operation = EndTrim;
- Drag::start_grab (event, _editor->cursors()->right_side_trim);
+ if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
+ Drag::start_grab (event, _editor->cursors()->anchored_right_side_trim);
+ } else {
+ Drag::start_grab (event, _editor->cursors()->right_side_trim);
+ }
}
}
speed = tv->track()->speed();
}
- framecnt_t const dt = adjusted_current_frame (event) - raw_grab_frame () + _pointer_frame_offset;
+ framecnt_t dt = adjusted_current_frame (event) - raw_grab_frame () + _pointer_frame_offset;
if (first_move) {
case ContentsTrim:
trim_type = "Region content trim";
break;
+ default:
+ assert(0);
+ break;
}
_editor->begin_reversible_command (trim_type);
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
RegionView* rv = i->view;
- rv->fake_set_opaque (false);
rv->enable_display (false);
rv->region()->playlist()->clear_owned_changes ();
non_overlap_trim = true;
}
+ /* contstrain trim to fade length */
+ if (_preserve_fade_anchor) {
+ switch (_operation) {
+ case StartTrim:
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
+ if (!arv) continue;
+ boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+ if (ar->locked()) continue;
+ framecnt_t len = ar->fade_in()->back()->when;
+ if (len < dt) dt = min(dt, len);
+ }
+ break;
+ case EndTrim:
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
+ if (!arv) continue;
+ boost::shared_ptr<AudioRegion> ar (arv->audio_region());
+ if (ar->locked()) continue;
+ framecnt_t len = ar->fade_out()->back()->when;
+ if (len < -dt) dt = max(dt, -len);
+ }
+ break;
+ case ContentsTrim:
+ break;
+ }
+ }
+
+
switch (_operation) {
case StartTrim:
- for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
bool changed = i->view->trim_front (i->initial_position + dt, non_overlap_trim);
if (changed && _preserve_fade_anchor) {
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
if (arv) {
- double distance;
- double new_length;
- framecnt_t len;
boost::shared_ptr<AudioRegion> ar (arv->audio_region());
- distance = _drags->current_pointer_x() - grab_x();
- len = ar->fade_in()->back()->when;
- new_length = len - _editor->pixel_to_sample (distance);
- new_length = ar->verify_xfade_bounds (new_length, true /*START*/ );
- arv->reset_fade_in_shape_width (ar, new_length); //the grey shape
+ framecnt_t len = ar->fade_in()->back()->when;
+ framecnt_t diff = ar->first_frame() - i->initial_position;
+ framepos_t new_length = len - diff;
+ i->anchored_fade_length = min (ar->length(), new_length);
+ //i->anchored_fade_length = ar->verify_xfade_bounds (new_length, true /*START*/ );
+ arv->reset_fade_in_shape_width (ar, i->anchored_fade_length, true);
}
}
}
break;
case EndTrim:
- for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
bool changed = i->view->trim_end (i->initial_end + dt, non_overlap_trim);
if (changed && _preserve_fade_anchor) {
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
if (arv) {
- double distance;
- double new_length;
- framecnt_t len;
boost::shared_ptr<AudioRegion> ar (arv->audio_region());
- distance = grab_x() - _drags->current_pointer_x();
- len = ar->fade_out()->back()->when;
- new_length = len - _editor->pixel_to_sample (distance);
- new_length = ar->verify_xfade_bounds (new_length, false /*END*/ );
- arv->reset_fade_out_shape_width (ar, new_length); //the grey shape
+ framecnt_t len = ar->fade_out()->back()->when;
+ framecnt_t diff = 1 + ar->last_frame() - i->initial_end;
+ framepos_t new_length = len + diff;
+ i->anchored_fade_length = min (ar->length(), new_length);
+ //i->anchored_fade_length = ar->verify_xfade_bounds (new_length, false /*END*/ );
+ arv->reset_fade_out_shape_width (ar, i->anchored_fade_length, true);
}
}
}
if (_preserve_fade_anchor) {
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
if (arv) {
- double distance;
- double new_length;
- framecnt_t len;
boost::shared_ptr<AudioRegion> ar (arv->audio_region());
- distance = _drags->current_pointer_x() - grab_x();
- len = ar->fade_in()->back()->when;
- new_length = len - _editor->pixel_to_sample (distance);
- new_length = ar->verify_xfade_bounds (new_length, true /*START*/ );
- ar->set_fade_in_length(new_length);
+ arv->reset_fade_in_shape_width (ar, i->anchored_fade_length);
+ ar->set_fade_in_length(i->anchored_fade_length);
+ ar->set_fade_in_active(true);
}
}
if (_jump_position_when_done) {
if (_preserve_fade_anchor) {
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
if (arv) {
- double distance;
- double new_length;
- framecnt_t len;
boost::shared_ptr<AudioRegion> ar (arv->audio_region());
- distance = _drags->current_pointer_x() - grab_x();
- len = ar->fade_out()->back()->when;
- new_length = len - _editor->pixel_to_sample (distance);
- new_length = ar->verify_xfade_bounds (new_length, false /*END*/ );
- ar->set_fade_out_length(new_length);
+ arv->reset_fade_out_shape_width (ar, i->anchored_fade_length);
+ ar->set_fade_out_length(i->anchored_fade_length);
+ ar->set_fade_out_active(true);
}
}
if (_jump_position_when_done) {
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
i->view->thaw_after_trim ();
i->view->enable_display (true);
- i->view->fake_set_opaque (true);
/* Trimming one region may affect others on the playlist, so we need
to get undo Commands from the whole playlist rather than just the
}
CursorDrag::CursorDrag (Editor* e, EditorCursor& c, bool s)
- : Drag (e, &c.time_bar_canvas_item())
+ : Drag (e, &c.track_canvas_item(), false)
, _cursor (c)
, _stop (s)
{
_point->line().start_drag_single (_point, _fixed_grab_x, fraction);
- _editor->verbose_cursor()->set (_point->line().get_verbose_cursor_string (fraction),
- event->button.x + 10, event->button.y + 10);
-
- _editor->verbose_cursor()->show ();
+ show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction));
_pushing = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
ControlPointDrag::motion (GdkEvent* event, bool)
{
double dx = _drags->current_pointer_x() - last_pointer_x();
- double dy = _drags->current_pointer_y() - last_pointer_y();
+ double dy = current_pointer_y() - last_pointer_y();
if (event->button.state & Keyboard::SecondaryModifier) {
dx *= 0.1;
_point->line().drag_motion (_editor->sample_to_pixel_unrounded (cx_frames), fraction, false, _pushing, _final_index);
- _editor->verbose_cursor()->set_text (_point->line().get_verbose_cursor_string (fraction));
+ show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction));
}
void
_line->start_drag_line (before, after, fraction);
- _editor->verbose_cursor()->set (_line->get_verbose_cursor_string (fraction),
- event->button.x + 10, event->button.y + 10);
-
- _editor->verbose_cursor()->show ();
+ show_verbose_cursor_text (_line->get_verbose_cursor_string (fraction));
}
void
LineDrag::motion (GdkEvent* event, bool)
{
- double dy = _drags->current_pointer_y() - last_pointer_y();
+ double dy = current_pointer_y() - last_pointer_y();
if (event->button.state & Keyboard::SecondaryModifier) {
dy *= 0.1;
/* we are ignoring x position for this drag, so we can just pass in anything */
_line->drag_motion (0, fraction, true, false, ignored);
- _editor->verbose_cursor()->set_text (_line->get_verbose_cursor_string (fraction));
+ show_verbose_cursor_text (_line->get_verbose_cursor_string (fraction));
}
void
start = grab;
}
- if (_drags->current_pointer_y() < grab_y()) {
- y1 = _drags->current_pointer_y();
+ if (current_pointer_y() < grab_y()) {
+ y1 = current_pointer_y();
y2 = grab_y();
} else {
- y2 = _drags->current_pointer_y();
+ y2 = current_pointer_y();
y1 = grab_y();
}
-
if (start != end || y1 != y2) {
double x1 = _editor->sample_to_pixel (start);
double x2 = _editor->sample_to_pixel (end);
const double min_dimension = 2.0;
- _editor->rubberband_rect->set_x0 (x1);
if (_vertical_only) {
/* fixed 10 pixel width */
- _editor->rubberband_rect->set_x1 (x1 + 10);
+ x2 = x1 + 10;
} else {
if (x2 < x1) {
x2 = min (x1 - min_dimension, x2);
} else {
x2 = max (x1 + min_dimension, x2);
}
- _editor->rubberband_rect->set_x1 (x2);
}
- _editor->rubberband_rect->set_y0 (y1);
if (y2 < y1) {
y2 = min (y1 - min_dimension, y2);
} else {
y2 = max (y1 + min_dimension, y2);
}
- _editor->rubberband_rect->set_y1 (y2);
-
+ /* translate rect into item space and set */
+
+ ArdourCanvas::Rect r (x1, y1, x2, y2);
+
+ /* this drag is a _trackview_only == true drag, so the y1 and
+ * y2 (computed using current_pointer_y() and grab_y()) will be
+ * relative to the top of the trackview group). The
+ * rubberband rect has the same parent/scroll offset as the
+ * the trackview group, so we can use the "r" rect directly
+ * to set the shape of the rubberband.
+ */
+
+ _editor->rubberband_rect->set (r);
_editor->rubberband_rect->show();
_editor->rubberband_rect->raise_to_top();
double y1;
double y2;
- if (_drags->current_pointer_y() < grab_y()) {
- y1 = _drags->current_pointer_y();
+ if (current_pointer_y() < grab_y()) {
+ y1 = current_pointer_y();
y2 = grab_y();
} else {
- y2 = _drags->current_pointer_y();
+ y2 = current_pointer_y();
y1 = grab_y();
}
show_verbose_cursor_time (adjusted_current_frame (event));
}
- _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
+ _original_pointer_time_axis = _editor->trackview_by_y_position (current_pointer_y ()).first->order ();
}
void
TrackViewList to_be_removed_from_selection;
TrackViewList& all_tracks (_editor->track_views);
- for (TrackViewList::const_iterator i = all_tracks.begin(); i != all_tracks.end(); ++i) {
+ ArdourCanvas::Coord const top = grab_y();
+ ArdourCanvas::Coord const bottom = current_pointer_y();
+
+ if (top >= 0 && bottom >= 0) {
+
+ for (TrackViewList::const_iterator i = all_tracks.begin(); i != all_tracks.end(); ++i) {
- if ((*i)->covered_by_y_range (grab_y(), _drags->current_pointer_y())) {
- if (!(*i)->get_selected()) {
- to_be_added_to_selection.push_back (*i);
- }
- } else {
- if ((*i)->get_selected()) {
- to_be_removed_from_selection.push_back (*i);
+ if ((*i)->covered_by_y_range (top, bottom)) {
+ if (!(*i)->get_selected()) {
+ to_be_added_to_selection.push_back (*i);
+ }
+ } else {
+ if ((*i)->get_selected()) {
+ to_be_removed_from_selection.push_back (*i);
+ }
}
}
- }
- if (!to_be_added_to_selection.empty()) {
- _editor->selection->add (to_be_added_to_selection);
- }
-
- if (!to_be_removed_from_selection.empty()) {
- _editor->selection->remove (to_be_removed_from_selection);
+ if (!to_be_added_to_selection.empty()) {
+ _editor->selection->add (to_be_added_to_selection);
+ }
+
+ if (!to_be_removed_from_selection.empty()) {
+ _editor->selection->remove (to_be_removed_from_selection);
+ }
}
}
break;
break;
}
- _editor->maybe_autoscroll (true, false, false);
-
if (start != end) {
switch (_operation) {
case SelectionMove:
}
RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
- : Drag (e, i),
+ : Drag (e, i, false),
_operation (o),
_copy (false)
{
}
}
- _editor->maybe_autoscroll (true, false, false);
-
if (start != end) {
_editor->temp_location->set (start, end);
MidiStreamView* msv = _region->midi_stream_view ();
double const y = _region->midi_view()->y_position ();
/* new current note */
- uint8_t n = msv->y_to_note (_drags->current_pointer_y () - y);
+ uint8_t n = msv->y_to_note (current_pointer_y () - y);
/* clamp */
n = max (msv->lowest_note(), n);
n = min (msv->highest_note(), n);
/* Get line states before we start changing things */
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
i->state = &i->line->get_state ();
- i->original_fraction = y_fraction (i->line, _drags->current_pointer_y());
+ i->original_fraction = y_fraction (i->line, current_pointer_y());
}
if (_ranges.empty()) {
}
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
- i->line->start_drag_multiple (i->points, y_fraction (i->line, _drags->current_pointer_y()), i->state);
+ i->line->start_drag_multiple (i->points, y_fraction (i->line, current_pointer_y()), i->state);
}
}
}
for (list<Line>::iterator l = _lines.begin(); l != _lines.end(); ++l) {
- float const f = y_fraction (l->line, _drags->current_pointer_y());
+ float const f = y_fraction (l->line, current_pointer_y());
/* we are ignoring x position for this drag, so we can just pass in anything */
uint32_t ignored;
l->line->drag_motion (0, f, true, false, ignored);
}
}
-DraggingView::DraggingView (RegionView* v, RegionDrag* parent)
+DraggingView::DraggingView (RegionView* v, RegionDrag* parent, TimeAxisView* itav)
: view (v)
+ , initial_time_axis_view (itav)
{
+ /* note that time_axis_view may be null if the regionview was created
+ * as part of a copy operation.
+ */
time_axis_view = parent->find_time_axis_view (&v->get_time_axis_view ());
layer = v->region()->layer ();
initial_y = v->get_canvas_group()->position().y;