show_verbose_cursor_time (_last_frame_position);
- pair<TimeAxisView*, int> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
_last_pointer_time_axis_view = find_time_axis_view (tv.first);
_last_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
+
+ if (tv.first->view()->layer_display() == Stacked) {
+ tv.first->view()->set_layer_display (Expanded);
+ }
}
double
}
bool
-RegionMotionDrag::y_movement_allowed (int delta_track, layer_t delta_layer) const
+RegionMotionDrag::y_movement_allowed (int delta_track, double delta_layer) const
{
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
int const n = i->time_axis_view + delta_track;
return false;
}
- int const l = i->layer + delta_layer;
- if (delta_track == 0 && (l < 0 || l >= int (to->view()->layers()))) {
+ double const l = i->layer + delta_layer;
+
+ /* Note that we allow layer to be up to 0.5 below zero, as this is used by `Expanded'
+ mode to allow the user to place a region below another on layer 0.
+ */
+
+ if (delta_track == 0 && (l < -0.5 || l >= int (to->view()->layers()))) {
/* Off the top or bottom layer; note that we only refuse if the track hasn't changed.
If it has, the layers will be munged later anyway, so it's ok.
*/
assert (!_views.empty ());
/* Find the TimeAxisView that the pointer is now over */
- pair<TimeAxisView*, int> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
/* Bail early if we're not over a track */
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv.first);
/* 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);
- layer_t const current_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
+ double const current_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
/* Work out the change in x */
framepos_t pending_region_position;
/* Work out the change in y */
int delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
- int delta_layer = current_pointer_layer - _last_pointer_layer;
+ double delta_layer = current_pointer_layer - _last_pointer_layer;
if (!y_movement_allowed (delta_time_axis_view, delta_layer)) {
/* this y movement is not allowed, so do no y movement this time */
confusion when dragging regions from non-zero layers onto different
tracks.
*/
- int this_delta_layer = delta_layer;
+ double this_delta_layer = delta_layer;
if (delta_time_axis_view != 0) {
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];
+
+ /* Ensure it is moved from stacked -> expanded if appropriate */
+ if (tv->view()->layer_display() == Stacked) {
+ 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;
+ }
+
/* Set height */
rv->set_height (tv->view()->child_height ());
/* And adjust for the layer that it should be on */
StreamView* cv = tv->view ();
- if (cv->layer_display() == Stacked) {
+ 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;
}
-
+
/* Now move the region view */
rv->move (x_delta, y - rv->get_canvas_group()->property_y());
}
}
void
-RegionMoveDrag::finished (GdkEvent *, bool movement_occurred)
+RegionMotionDrag::finished (GdkEvent *, bool)
+{
+ for (vector<TimeAxisView*>::iterator i = _time_axis_views.begin(); i != _time_axis_views.end(); ++i) {
+ if ((*i)->view()->layer_display() == Expanded) {
+ (*i)->view()->set_layer_display (Stacked);
+ }
+ }
+}
+
+void
+RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred)
{
+ RegionMotionDrag::finished (ev, movement_occurred);
if (!movement_occurred) {
/* just a click */
return;
PlaylistSet modified_playlists;
PlaylistSet frozen_playlists;
+ list<pair<boost::shared_ptr<Region>, double> > pending_explicit_relayers;
+ Playlist::RegionList pending_implicit_relayers;
+
if (_brushing) {
/* all changes were made during motion event handlers */
_editor->commit_reversible_command ();
RegionView* rv = i->view;
RouteTimeAxisView* const dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
- layer_t const dest_layer = i->layer;
+ double const dest_layer = i->layer;
if (rv->region()->locked()) {
++i;
boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
- if (dest_rtv->view()->layer_display() == Stacked) {
- rv->region()->set_layer (dest_layer);
- rv->region()->set_pending_explicit_relayer (true);
+ bool const explicit_relayer = dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded;
+
+ if (explicit_relayer) {
+ pending_explicit_relayers.push_back (make_pair (rv->region (), dest_layer));
+ } else {
+ pending_implicit_relayers.push_back (rv->region ());
}
/* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
if (r.second) {
playlist->freeze ();
+ playlist->suspend_relayer ();
}
/* this movement may result in a crossfade being modified, so we need to get undo
_editor->selection->set (new_views);
}
- for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
+ /* We can't use the normal mechanism for relayering, as some regions may require an explicit relayer
+ rather than an implicit one. So we thaw before resuming relayering, then do the relayers
+ that we require.
+ */
+
+ for (PlaylistSet::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
(*p)->thaw();
+ (*p)->resume_relayer ();
+ }
+
+ for (list<pair<boost::shared_ptr<Region>, double> >::iterator i = pending_explicit_relayers.begin(); i != pending_explicit_relayers.end(); ++i) {
+ i->first->playlist()->relayer (i->first, i->second);
}
+ for (Playlist::RegionList::iterator i = pending_implicit_relayers.begin(); i != pending_implicit_relayers.end(); ++i) {
+ (*i)->playlist()->relayer (*i);
+ }
+
/* write commands for the accumulated diffs for all our modified playlists */
add_stateful_diff_commands_for_playlists (modified_playlists);
dest_playlist->add_region (region, where);
- if (dest_rtv->view()->layer_display() == Stacked) {
- region->set_layer (dest_layer);
- region->set_pending_explicit_relayer (true);
+ if (dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded) {
+ dest_playlist->relayer (region, dest_layer);
}
c.disconnect ();
void
RegionMotionDrag::aborted (bool)
{
+ for (vector<TimeAxisView*>::iterator i = _time_axis_views.begin(); i != _time_axis_views.end(); ++i) {
+ if ((*i)->view()->layer_display() == Expanded) {
+ (*i)->view()->set_layer_display (Stacked);
+ }
+ }
+
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
RegionView* rv = i->view;
TimeAxisView* tv = &(rv->get_time_axis_view ());
{
/* Which trackview is this ? */
- pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
/* The region motion is only processed if the pointer is over
}
void
-MeterMarkerDrag::aborted (bool)
+MeterMarkerDrag::aborted (bool moved)
{
_marker->set_position (_marker->meter().frame ());
- /* XXX problem: we don't know if we've moved yet, so we don't
- know if the marker is a copy yet or not
- */
-
- TempoMap& map (_editor->session()->tempo_map());
- /* we removed it before, so add it back now */
- map.add_meter (_marker->meter(), _marker->meter().frame());
- // delete the dummy marker we used for visual representation while moving.
- // a new visual marker will show up automatically.
- delete _marker;
+ if (moved) {
+ TempoMap& map (_editor->session()->tempo_map());
+ /* we removed it before, so add it back now */
+ map.add_meter (_marker->meter(), _marker->meter().frame());
+ // delete the dummy marker we used for visual representation while moving.
+ // a new visual marker will show up automatically.
+ delete _marker;
+ }
}
TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
}
void
-TempoMarkerDrag::aborted (bool)
+TempoMarkerDrag::aborted (bool moved)
{
_marker->set_position (_marker->tempo().frame());
- /* XXX problem: we don't know if we've moved yet, so we don't
- know if the marker is a copy yet or not
- */
- TempoMap& map (_editor->session()->tempo_map());
- /* we removed it before, so add it back now */
- map.add_tempo (_marker->tempo(), _marker->tempo().frame());
- // delete the dummy marker we used for visual representation while moving.
- // a new visual marker will show up automatically.
- delete _marker;
+ if (moved) {
+ TempoMap& map (_editor->session()->tempo_map());
+ /* we removed it before, so add it back now */
+ map.add_tempo (_marker->tempo(), _marker->tempo().frame());
+ // delete the dummy marker we used for visual representation while moving.
+ // a new visual marker will show up automatically.
+ delete _marker;
+ }
}
CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)