-
/*
Copyright (C) 2000-2001 Paul Davis
#include "keyboard.h"
#include "editing.h"
#include "rgb_macros.h"
+#include "control_point_dialog.h"
#include <ardour/types.h>
#include <ardour/profile.h>
{
switch (current_mouse_mode()) {
case MouseObject:
- if (next) set_mouse_mode (MouseRange);
- else set_mouse_mode (MouseTimeFX);
+ if (next) {
+ if (Profile->get_sae()) {
+ set_mouse_mode (MouseZoom);
+ } else {
+ set_mouse_mode (MouseRange);
+ }
+ } else {
+ set_mouse_mode (MouseTimeFX);
+ }
break;
case MouseRange:
break;
case MouseZoom:
- if (next) set_mouse_mode (MouseGain);
- else set_mouse_mode (MouseRange);
+ if (next) {
+ if (Profile->get_sae()) {
+ set_mouse_mode (MouseTimeFX);
+ } else {
+ set_mouse_mode (MouseGain);
+ }
+ } else {
+ if (Profile->get_sae()) {
+ set_mouse_mode (MouseObject);
+ } else {
+ set_mouse_mode (MouseRange);
+ }
+ }
break;
case MouseGain:
break;
case MouseTimeFX:
- if (next) set_mouse_mode (MouseAudition);
- else set_mouse_mode (MouseGain);
+ if (next) {
+ set_mouse_mode (MouseAudition);
+ } else {
+ if (Profile->get_sae()) {
+ set_mouse_mode (MouseZoom);
+ } else {
+ set_mouse_mode (MouseGain);
+ }
+ }
break;
case MouseAudition:
void
Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
{
- /* in object/audition/timefx mode, any button press sets
- the selection if the object can be selected. this is a
- bit of hack, because we want to avoid this if the
- mouse operation is a region alignment.
+ /* in object/audition/timefx/gain-automation mode,
+ any button press sets the selection if the object
+ can be selected. this is a bit of hack, because
+ we want to avoid this if the mouse operation is a
+ region alignment.
note: not dbl-click or triple-click
*/
if (((mouse_mode != MouseObject) &&
(mouse_mode != MouseAudition || item_type != RegionItem) &&
(mouse_mode != MouseTimeFX || item_type != RegionItem) &&
+ (mouse_mode != MouseGain) &&
(mouse_mode != MouseRange)) ||
((event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) || event->button.button > 3)) {
}
}
}
-
+
Selection::Operation op = Keyboard::selection_type (event->button.state);
bool press = (event->type == GDK_BUTTON_PRESS);
Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
{
Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->track_canvas->get_window();
-
+
if (canvas_window) {
Glib::RefPtr<const Gdk::Window> pointer_window;
int x, y;
}
button_selection (item, event, item_type);
-
+
if (drag_info.item == 0 &&
(Keyboard::is_delete_event (&event->button) ||
Keyboard::is_context_menu_event (&event->button) ||
}
return true;
+ case MarkerBarItem:
case TempoBarItem:
- return true;
-
case MeterBarItem:
+ if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
+ start_cursor_grab_no_stop(&playhead_cursor->canvas_item, event);
+ }
return true;
+ break;
+
case RangeMarkerBarItem:
- start_range_markerbar_op (item, event, CreateRangeMarker);
+ if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
+ start_cursor_grab_no_stop(&playhead_cursor->canvas_item, event);
+ } else {
+ start_range_markerbar_op (item, event, CreateRangeMarker);
+ }
return true;
break;
case CdMarkerBarItem:
- start_range_markerbar_op (item, event, CreateCDMarker);
+ if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
+ start_cursor_grab_no_stop(&playhead_cursor->canvas_item, event);
+ } else {
+ start_range_markerbar_op (item, event, CreateCDMarker);
+ }
return true;
break;
case TransportMarkerBarItem:
- start_range_markerbar_op (item, event, CreateTransportMarker);
+ if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
+ start_cursor_grab_no_stop(&playhead_cursor->canvas_item, event);
+ } else {
+ start_range_markerbar_op (item, event, CreateTransportMarker);
+ }
return true;
break;
-
+
default:
break;
}
case MouseGain:
switch (item_type) {
case RegionItem:
- // start_line_grab_from_regionview (item, event);
+ /* start a grab so that if we finish after moving
+ we can tell what happened.
+ */
+ drag_info.item = item;
+ drag_info.motion_callback = &Editor::region_gain_motion_callback;
+ drag_info.finished_callback = 0;
+ start_grab (event, current_canvas_cursor);
break;
case GainLineItem:
{
nframes64_t where = event_frame (event, 0, 0);
AutomationTimeAxisView* atv = 0;
-
+
/* no action if we're recording */
if (session && session->actively_recording()) {
button_selection (item, event, item_type);
/* edit events get handled here */
-
+
if (drag_info.item == 0 && Keyboard::is_edit_event (&event->button)) {
switch (item_type) {
case RegionItem:
}
break;
+ case ControlPointItem:
+ edit_control_point (item);
+ break;
+
default:
break;
}
return true;
case MarkerBarItem:
- if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
- snap_to (where, 0, true);
+ if (!_dragging_playhead) {
+ if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
+ snap_to (where, 0, true);
+ }
+ mouse_add_new_marker (where);
}
- mouse_add_new_marker (where);
return true;
case CdMarkerBarItem:
- // if we get here then a dragged range wasn't done
- if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
- snap_to (where, 0, true);
+ if (!_dragging_playhead) {
+ // if we get here then a dragged range wasn't done
+ if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
+ snap_to (where, 0, true);
+ }
+ mouse_add_new_marker (where, true);
}
- mouse_add_new_marker (where, true);
return true;
case TempoBarItem:
- if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
- snap_to (where);
+ if (!_dragging_playhead) {
+ if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
+ snap_to (where);
+ }
+ mouse_add_new_tempo_event (where);
}
- mouse_add_new_tempo_event (where);
return true;
case MeterBarItem:
- mouse_add_new_meter_event (pixel_to_frame (event->button.x));
+ if (!_dragging_playhead) {
+ mouse_add_new_meter_event (pixel_to_frame (event->button.x));
+ }
return true;
break;
default:
break;
}
-
+
switch (mouse_mode) {
case MouseObject:
switch (item_type) {
switch (item_type) {
case RegionItem:
- dynamic_cast<AudioRegionView*>(clicked_regionview)->add_gain_point_event (item, event);
+ /* check that we didn't drag before releasing, since
+ its really annoying to create new control
+ points when doing this.
+ */
+ if (drag_info.first_move) {
+ dynamic_cast<AudioRegionView*>(clicked_regionview)->add_gain_point_event (item, event);
+ }
return true;
break;
case TempoBarItem:
case MarkerBarItem:
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*timebar_cursor);
+ track_canvas->get_window()->set_cursor (*current_canvas_cursor);
}
break;
case PlayheadCursorItem:
case MarkerItem:
case ControlPointItem:
+ case MarkerBarItem:
+ case TempoBarItem:
+ case MeterBarItem:
case RangeMarkerBarItem:
case TransportMarkerBarItem:
case CdMarkerBarItem:
if (!from_autoscroll) {
maybe_autoscroll_horizontally (&event->motion);
}
- (this->*(drag_info.motion_callback)) (item, event);
+ if (drag_info.motion_callback) {
+ (this->*(drag_info.motion_callback)) (item, event);
+ }
goto handled;
}
goto not_handled;
}
switch (mouse_mode) {
+ case MouseGain:
+ if (item_type == RegionItem) {
+ if (drag_info.item && drag_info.motion_callback) {
+ (this->*(drag_info.motion_callback)) (item, event);
+ }
+ goto handled;
+ }
+ break;
+
case MouseObject:
case MouseRange:
case MouseZoom:
if (!from_autoscroll) {
maybe_autoscroll (&event->motion);
}
- (this->*(drag_info.motion_callback)) (item, event);
+ if (drag_info.motion_callback) {
+ (this->*(drag_info.motion_callback)) (item, event);
+ }
goto handled;
}
goto not_handled;
// if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
- if (event->button.button == 2) {
+ if (Keyboard::is_button2_event (&event->button)) {
if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
drag_info.y_constrained = true;
drag_info.x_constrained = false;
return did_drag;
}
+void
+Editor::region_gain_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
+{
+ if (drag_info.first_move && drag_info.move_threshold_passed) {
+ drag_info.first_move = false;
+ }
+}
+
void
Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
{
show_verbose_time_cursor (cursor->current_frame, 10);
}
+void
+Editor::start_cursor_grab_no_stop (ArdourCanvas::Item* item, GdkEvent* event)
+{
+ drag_info.item = item;
+ drag_info.motion_callback = &Editor::cursor_drag_motion_callback;
+ drag_info.finished_callback = &Editor::cursor_drag_finished_ensure_locate_callback;
+
+ start_grab (event);
+
+ if ((drag_info.data = (item->get_data ("cursor"))) == 0) {
+ fatal << _("programming error: cursor canvas item has no cursor data pointer!") << endmsg;
+ /*NOTREACHED*/
+ }
+
+ Cursor* cursor = (Cursor *) drag_info.data;
+ nframes64_t where = event_frame (event, 0, 0);
+
+ snap_to(where);
+ playhead_cursor->set_position (where);
+
+ if (cursor == playhead_cursor) {
+ _dragging_playhead = true;
+
+ if (session && session->is_auditioning()) {
+ session->cancel_audition ();
+ }
+ }
+
+ drag_info.pointer_frame_offset = drag_info.grab_frame - cursor->current_frame;
+
+ show_verbose_time_cursor (cursor->current_frame, 10);
+}
+
void
Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
{
void
Editor::cursor_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
{
- if (drag_info.first_move) return;
+ _dragging_playhead = false;
+
+ if (drag_info.first_move) {
+ return;
+ }
cursor_drag_motion_callback (item, event);
+
+ if (item == &playhead_cursor->canvas_item) {
+ if (session) {
+ session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
+ }
+ }
+}
+void
+Editor::cursor_drag_finished_ensure_locate_callback (ArdourCanvas::Item* item, GdkEvent* event)
+{
_dragging_playhead = false;
+ cursor_drag_motion_callback (item, event);
+
if (item == &playhead_cursor->canvas_item) {
if (session) {
session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
Marker* dragged_marker = (Marker*) drag_info.data;
Marker* marker;
Location *real_location;
- Location *copy_location;
+ Location *copy_location = 0;
if (drag_info.pointer_frame_offset <= drag_info.current_pointer_frame) {
newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
cp->line().end_drag (cp);
}
+void
+Editor::edit_control_point (ArdourCanvas::Item* item)
+{
+ ControlPoint* p = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
+
+ if (p == 0) {
+ fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
+ /*NOTREACHED*/
+ }
+
+ ControlPointDialog d (p);
+ d.set_position (Gtk::WIN_POS_MOUSE);
+ ensure_float (d);
+
+ if (d.run () != RESPONSE_ACCEPT) {
+ return;
+ }
+
+ p->line().modify_point_y (*p, d.get_y_fraction ());
+}
+
+
void
Editor::start_line_grab_from_regionview (ArdourCanvas::Item* item, GdkEvent* event)
{
nframes64_t frame_within_region;
/* need to get x coordinate in terms of parent (TimeAxisItemView)
- origin.
+ origin, and ditto for y.
*/
cx = event->button.x;
cy = event->button.y;
+
line->parent_group().w2i (cx, cy);
+
frame_within_region = (nframes64_t) floor (cx * frames_per_unit);
if (!line->control_points_adjacent (frame_within_region, current_line_drag_info.before,
start_grab (event, fader_cursor);
+ /* store grab start in parent frame */
+
+ drag_info.grab_x = cx;
+ drag_info.grab_y = cy;
+
double fraction = 1.0 - (cy / line->height());
line->start_drag (0, drag_info.grab_frame, fraction);
AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
double dy = drag_info.current_pointer_y - drag_info.last_pointer_y;
-
+
if (event->button.state & Keyboard::SecondaryModifier) {
dy *= 0.1;
}
// calculate zero crossing point. back off by .01 to stay on the
// positive side of zero
- double _unused = 0;
double zero_gain_y = (1.0 - ZERO_GAIN_FRACTION) * line->height() - .01;
- line->parent_group().i2w(_unused, zero_gain_y);
+
+ // line->parent_group().i2w(_unused, zero_gain_y);
// make sure we hit zero when passing through
if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
cy = max (0.0, cy);
cy = min ((double) line->height(), cy);
+
double fraction = 1.0 - (cy / line->height());
bool push;
drag_info.last_frame_position = (nframes64_t) (clicked_regionview->region()->position() / speed);
drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
drag_info.source_trackview = &clicked_regionview->get_time_axis_view();
+ drag_info.source_layer = clicked_regionview->region()->layer();
drag_info.dest_trackview = drag_info.source_trackview;
+ drag_info.dest_layer = drag_info.source_layer;
// we want a move threshold
drag_info.want_move_threshold = true;
show_verbose_time_cursor (drag_info.last_frame_position, 10);
drag_info.data = clicked_axisview;
drag_info.source_trackview = clicked_axisview;
drag_info.dest_trackview = drag_info.source_trackview;
+ drag_info.dest_layer = drag_info.source_layer;
drag_info.motion_callback = &Editor::create_region_drag_motion_callback;
drag_info.finished_callback = &Editor::create_region_drag_finished_callback;
drag_info.source_trackview = &clicked_regionview->get_time_axis_view();
drag_info.dest_trackview = drag_info.source_trackview;
+ drag_info.dest_layer = drag_info.source_layer;
drag_info.last_frame_position = (nframes64_t) (clicked_regionview->region()->position() / speed);
drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
// we want a move threshold
drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
drag_info.source_trackview = &clicked_regionview->get_time_axis_view();
drag_info.dest_trackview = drag_info.source_trackview;
+ drag_info.dest_layer = drag_info.source_layer;
// we want a move threshold
drag_info.want_move_threshold = true;
drag_info.brushing = true;
}
bool
-Editor::check_region_drag_possible (RouteTimeAxisView** tv)
+Editor::check_region_drag_possible (RouteTimeAxisView** tv, layer_t* layer)
{
/* Which trackview is this ? */
- TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
- (*tv) = dynamic_cast<RouteTimeAxisView*>(tvp);
+ std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (drag_info.current_pointer_y);
+ (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
+ (*layer) = tvp.second;
/* The region motion is only processed if the pointer is over
an audio track.
Editor::region_drag_splice_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
{
RouteTimeAxisView* tv;
+ layer_t layer;
- if (!check_region_drag_possible (&tv)) {
+ if (!check_region_drag_possible (&tv, &layer)) {
return;
}
{
}
+void
+Editor::visible_order_range (int* low, int* high) const
+{
+ *low = TimeAxisView::max_order ();
+ *high = 0;
+
+ for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
+
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
+
+ if (!rtv->hidden()) {
+
+ if (*high < rtv->order()) {
+ *high = rtv->order ();
+ }
+
+ if (*low > rtv->order()) {
+ *low = rtv->order ();
+ }
+ }
+ }
+}
+
+/** @param new_order New track order.
+ * @param old_order Old track order.
+ * @param visible_y_low Lowest visible order.
+ * @param visible_y_high Highest visible order.
+ * @param tracks Bitset of tracks indexed by order; 0 means a audio/MIDI track, 1 means something else.
+ * @param heigh_list Heights of tracks indexed by order.
+ * @return true if y movement should not happen, otherwise false.
+ */
+bool
+Editor::y_movement_disallowed (
+ int new_order, int old_order, int y_span, int visible_y_low, int visible_y_high,
+ bitset<512> const & tracks, vector<int32_t> const & height_list
+ ) const
+{
+ if (new_order != old_order) {
+
+ /* this isn't the pointer track */
+
+ if (y_span > 0) {
+
+ /* moving up the canvas */
+ if ( (new_order - y_span) >= visible_y_low) {
+
+ int32_t n = 0;
+
+ /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
+ int32_t visible_tracks = 0;
+ while (visible_tracks < y_span ) {
+ visible_tracks++;
+ while (height_list[new_order - (visible_tracks - n)] == 0) {
+ /* passing through a hidden track */
+ n--;
+ }
+ }
+
+ if (tracks[new_order - (y_span - n)] != 0x00) {
+ /* moving to a non-track; disallow */
+ return true;
+ }
+
+
+ } else {
+ /* moving beyond the lowest visible track; disallow */
+ return true;
+ }
+
+ } else if (y_span < 0) {
+
+ /* moving down the canvas */
+ if ((new_order - y_span) <= visible_y_high) {
+
+ int32_t visible_tracks = 0;
+ int32_t n = 0;
+ while (visible_tracks > y_span ) {
+ visible_tracks--;
+
+ while (height_list[new_order - (visible_tracks - n)] == 0) {
+ /* passing through a hidden track */
+ n++;
+ }
+ }
+
+ if (tracks[new_order - (y_span - n)] != 0x00) {
+ /* moving to a non-track; disallow */
+ return true;
+ }
+
+
+ } else {
+
+ /* moving beyond the highest visible track; disallow */
+ return true;
+ }
+ }
+
+ } else {
+
+ /* this is the pointer's track */
+
+ if ((new_order - y_span) > visible_y_high) {
+ /* we will overflow */
+ return true;
+ } else if ((new_order - y_span) < visible_y_low) {
+ /* we will overflow */
+ return true;
+ }
+ }
+
+ return false;
+}
+
void
Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
{
double x_delta;
double y_delta = 0;
nframes64_t pending_region_position = 0;
- int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
- int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen
+ int32_t pointer_order_span = 0, canvas_pointer_order_span = 0;
+ int32_t pointer_layer_span = 0;
+
bool clamp_y_axis = false;
- vector<int32_t> height_list(512) ;
vector<int32_t>::iterator j;
- RouteTimeAxisView* tv;
possibly_copy_regions_during_grab (event);
- if (!check_region_drag_possible (&tv)) {
+ /* *pointer* variables reflect things about the pointer; as we may be moving
+ multiple regions, much detail must be computed per-region */
+
+ /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
+ current_pointer_layer the current layer on that TimeAxisView */
+ RouteTimeAxisView* current_pointer_view;
+ layer_t current_pointer_layer;
+ if (!check_region_drag_possible (¤t_pointer_view, ¤t_pointer_layer)) {
return;
}
- original_pointer_order = drag_info.dest_trackview->order;
-
+ /* TimeAxisView that we were pointing at last time we entered this method */
+ TimeAxisView const * const last_pointer_view = drag_info.dest_trackview;
+ /* the order of the track that we were pointing at last time we entered this method */
+ int32_t const last_pointer_order = last_pointer_view->order ();
+ /* the layer that we were pointing at last time we entered this method */
+ layer_t const last_pointer_layer = drag_info.dest_layer;
+
/************************************************************
- Y-Delta Computation
+ Y DELTA COMPUTATION
************************************************************/
+ /* Height of TimeAxisViews, indexed by order */
+ /* XXX: hard-coded limit of TimeAxisViews */
+ vector<int32_t> height_list (512);
+
if (drag_info.brushing) {
clamp_y_axis = true;
- pointer_y_span = 0;
+ pointer_order_span = 0;
goto y_axis_done;
}
- if ((pointer_y_span = (drag_info.dest_trackview->order - tv->order)) != 0) {
+ /* the change in track order between this callback and the last */
+ pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
+ /* the change in layer between this callback and the last;
+ only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
+ pointer_layer_span = last_pointer_layer - current_pointer_layer;
+
+ if (pointer_order_span != 0) {
- int32_t children = 0, numtracks = 0;
- // XXX hard coding track limit, oh my, so very very bad
- bitset <1024> tracks (0x00);
+ int32_t children = 0;
+ /* XXX: hard-coded limit of tracks */
+ bitset <512> tracks (0x00);
+
+ int visible_y_high;
+ int visible_y_low;
+ visible_order_range (&visible_y_low, &visible_y_high);
+
/* get a bitmask representing the visible tracks */
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
- TimeAxisView *tracklist_timeview;
- tracklist_timeview = (*i);
- RouteTimeAxisView* rtv2 = dynamic_cast<RouteTimeAxisView*>(tracklist_timeview);
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
TimeAxisView::Children children_list;
- /* zeroes are audio tracks. ones are other types. */
+ /* zeroes are audio/MIDI tracks. ones are other types. */
- if (!rtv2->hidden()) {
+ if (!rtv->hidden()) {
- if (visible_y_high < rtv2->order) {
- visible_y_high = rtv2->order;
- }
- if (visible_y_low > rtv2->order) {
- visible_y_low = rtv2->order;
- }
-
- if (!rtv2->is_track()) {
- tracks = tracks |= (0x01 << rtv2->order);
+ if (!rtv->is_track()) {
+ /* not an audio nor MIDI track */
+ tracks = tracks |= (0x01 << rtv->order());
}
- height_list[rtv2->order] = (*i)->current_height();
+ height_list[rtv->order()] = (*i)->current_height();
children = 1;
- if ((children_list = rtv2->get_child_list()).size() > 0) {
+ if ((children_list = rtv->get_child_list()).size() > 0) {
for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
- tracks = tracks |= (0x01 << (rtv2->order + children));
- height_list[rtv2->order + children] = (*j)->current_height();
- numtracks++;
+ tracks = tracks |= (0x01 << (rtv->order() + children));
+ height_list[rtv->order() + children] = (*j)->current_height();
children++;
}
}
- numtracks++;
}
}
- /* find the actual span according to the canvas */
-
- canvas_pointer_y_span = pointer_y_span;
- if (drag_info.dest_trackview->order >= tv->order) {
- int32_t y;
- for (y = tv->order; y < drag_info.dest_trackview->order; y++) {
- if (height_list[y] == 0 ) {
- canvas_pointer_y_span--;
+
+ /* find the actual pointer span, in terms of the number of visible tracks;
+ to do this, we reduce |pointer_order_span| by the number of hidden tracks
+ over the span */
+
+ canvas_pointer_order_span = pointer_order_span;
+ if (last_pointer_view->order() >= current_pointer_view->order()) {
+ for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
+ if (height_list[y] == 0) {
+ canvas_pointer_order_span--;
}
}
} else {
- int32_t y;
- for (y = drag_info.dest_trackview->order;y <= tv->order; y++) {
- if ( height_list[y] == 0 ) {
- canvas_pointer_y_span++;
+ for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
+ if (height_list[y] == 0) {
+ canvas_pointer_order_span++;
}
}
}
for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
- RegionView* rv2 = (*i);
- double ix1, ix2, iy1, iy2;
- int32_t n = 0;
+
+ RegionView* rv = (*i);
- if (rv2->region()->locked()) {
+ if (rv->region()->locked()) {
continue;
}
- rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
- rv2->get_canvas_frame()->i2w (ix1, iy1);
+ double ix1, ix2, iy1, iy2;
+ rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
+ rv->get_canvas_frame()->i2w (ix1, iy1);
iy1 += vertical_adjustment.get_value() - canvas_timebars_vsize;
- TimeAxisView* tvp2 = trackview_by_y_position (iy1);
- RouteTimeAxisView* rtv2 = dynamic_cast<RouteTimeAxisView*>(tvp2);
-
- if (rtv2->order != original_pointer_order) {
- /* this isn't the pointer track */
+ /* get the new trackview for this particular region */
+ std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (iy1);
+ assert (tvp.first);
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
- if (canvas_pointer_y_span > 0) {
-
- /* moving up the canvas */
- if ((rtv2->order - canvas_pointer_y_span) >= visible_y_low) {
-
- int32_t visible_tracks = 0;
- while (visible_tracks < canvas_pointer_y_span ) {
- visible_tracks++;
-
- while (height_list[rtv2->order - (visible_tracks - n)] == 0) {
- /* we're passing through a hidden track */
- n--;
- }
- }
-
- if (tracks[rtv2->order - (canvas_pointer_y_span - n)] != 0x00) {
- clamp_y_axis = true;
- }
-
- } else {
- clamp_y_axis = true;
- }
-
- } else if (canvas_pointer_y_span < 0) {
+ /* I know this method has a slightly excessive argument list, but I think
+ it's nice to separate the code out all the same, since it has such a
+ simple result, and it makes it clear that there are no other
+ side-effects.
+ */
- /*moving down the canvas*/
+ /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
+ as surely this is a per-region thing... */
+
+ clamp_y_axis = y_movement_disallowed (
+ rtv->order(), last_pointer_order, canvas_pointer_order_span, visible_y_low, visible_y_high,
+ tracks, height_list
+ );
- if ((rtv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
-
-
- int32_t visible_tracks = 0;
-
- while (visible_tracks > canvas_pointer_y_span ) {
- visible_tracks--;
-
- while (height_list[rtv2->order - (visible_tracks - n)] == 0) {
- n++;
- }
- }
- if ( tracks[rtv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
- clamp_y_axis = true;
-
- }
- } else {
-
- clamp_y_axis = true;
- }
- }
-
- } else {
-
- /* this is the pointer's track */
- if ((rtv2->order - pointer_y_span) > visible_y_high) { // we will overflow
- clamp_y_axis = true;
- } else if ((rtv2->order - pointer_y_span) < visible_y_low) { // we will underflow
- clamp_y_axis = true;
- }
- }
if (clamp_y_axis) {
break;
}
}
- } else if (drag_info.dest_trackview == tv) {
- clamp_y_axis = true;
- }
+ } else if (drag_info.dest_trackview == current_pointer_view) {
+
+ if (current_pointer_layer == last_pointer_layer) {
+ /* No movement; clamp */
+ clamp_y_axis = true;
+ }
+ }
y_axis_done:
if (!clamp_y_axis) {
- drag_info.dest_trackview = tv;
+ drag_info.dest_trackview = current_pointer_view;
+ drag_info.dest_layer = current_pointer_layer;
}
/************************************************************
pending_region_position = drag_info.last_frame_position;
}
- // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position );
-
bool x_move_allowed;
if (Config->get_edit_mode() == Lock) {
x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
- RegionView* rv2 = (*i);
+ RegionView* rv = (*i);
// If any regionview is at zero, we need to know so we can stop further leftward motion.
double ix1, ix2, iy1, iy2;
- rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
- rv2->get_canvas_frame()->i2w (ix1, iy1);
-
+ rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
+ rv->get_canvas_frame()->i2w (ix1, iy1);
+
if (-x_delta > ix1 + horizontal_adjustment.get_value()) {
- // do_move = false;
x_delta = 0;
pending_region_position = drag_info.last_frame_position;
break;
PREPARE TO MOVE
************************************************************/
- if (x_delta == 0 && (pointer_y_span == 0)) {
+ if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0) {
/* haven't reached next snap point, and we're not switching
- trackviews. nothing to do.
+ trackviews nor layers. nothing to do.
*/
return;
}
const list<RegionView*>& layered_regions = selection->regions.by_layer();
for (list<RegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) {
-
+
RegionView* rv = (*i);
- double ix1, ix2, iy1, iy2;
- int32_t temp_pointer_y_span = pointer_y_span;
if (rv->region()->locked()) {
continue;
}
- /* get item BBox, which will be relative to parent. so we have
- to query on a child, then convert to world coordinates using
- the parent.
- */
+ /* here we are calculating the y distance from the
+ top of the first track view to the top of the region
+ area of the track view that we're working on */
- rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
- rv->get_canvas_frame()->i2w (ix1, iy1);
+ /* this x value is just a dummy value so that we have something
+ to pass to i2w () */
+
+ double ix1 = 0;
+
+ /* distance from the top of this track view to the region area
+ of our track view is always 1 */
- cerr << "adjust y from " << iy1 << " using "
- << vertical_adjustment.get_value() << " - "
- << canvas_timebars_vsize
- << endl;
+ double iy1 = 1;
- iy1 += get_trackview_group_vertical_offset ();;
+ /* convert to world coordinates, ie distance from the top of
+ the ruler section */
+
+ rv->get_canvas_frame()->i2w (ix1, iy1);
+
+ /* compensate for the ruler section and the vertical scrollbar position */
+ iy1 += get_trackview_group_vertical_offset ();
if (drag_info.first_move) {
parent groups have different coordinates.
*/
- rv->get_canvas_group()->property_y() = iy1 - 1;
+ rv->get_canvas_group()->property_y() = iy1 - 1;
rv->get_canvas_group()->reparent(*_region_motion_group);
rv->fake_set_opaque (true);
}
- TimeAxisView* tvp2 = trackview_by_y_position (iy1);
- RouteTimeAxisView* canvas_rtv = dynamic_cast<RouteTimeAxisView*>(tvp2);
- RouteTimeAxisView* temp_rtv;
+ /* current view for this particular region */
+ std::pair<TimeAxisView*, int> pos = trackview_by_y_position (iy1);
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
- if ((pointer_y_span != 0) && !clamp_y_axis) {
- y_delta = 0;
+ if (pointer_order_span != 0 && !clamp_y_axis) {
+
+ /* INTER-TRACK MOVEMENT */
+
+ /* move through the height list to the track that the region is currently on */
+ vector<int32_t>::iterator j = height_list.begin ();
int32_t x = 0;
- for (j = height_list.begin(); j!= height_list.end(); j++) {
- if (x == canvas_rtv->order) {
- /* we found the track the region is on */
- if (x != original_pointer_order) {
- /*this isn't from the same track we're dragging from */
- temp_pointer_y_span = canvas_pointer_y_span;
- }
- while (temp_pointer_y_span > 0) {
- /* we're moving up canvas-wise,
- so we need to find the next track height
- */
- if (j != height_list.begin()) {
- j--;
+ while (j != height_list.end () && x != rtv->order ()) {
+ ++x;
+ ++j;
+ }
+
+ y_delta = 0;
+ int32_t temp_pointer_order_span = canvas_pointer_order_span;
+
+ if (j != height_list.end ()) {
+
+ /* Account for layers in the original and
+ destination tracks. If we're moving around in layers we assume
+ that only one track is involved, so it's ok to use *pointer*
+ variables here. */
+
+ StreamView* lv = last_pointer_view->view ();
+ assert (lv);
+
+ /* move to the top of the last trackview */
+ if (lv->layer_display () == Stacked) {
+ y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
+ }
+
+ StreamView* cv = current_pointer_view->view ();
+ assert (cv);
+
+ /* move to the right layer on the current trackview */
+ if (cv->layer_display () == Stacked) {
+ y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
+ }
+
+ /* And for being on a non-topmost layer on the new
+ track */
+
+ while (temp_pointer_order_span > 0) {
+ /* we're moving up canvas-wise,
+ so we need to find the next track height
+ */
+ if (j != height_list.begin()) {
+ j--;
+ }
+
+ if (x != last_pointer_order) {
+ if ((*j) == 0) {
+ ++temp_pointer_order_span;
}
- if (x != original_pointer_order) {
- /* we're not from the dragged track, so ignore hidden tracks. */
- if ((*j) == 0) {
- temp_pointer_y_span++;
- }
- }
- y_delta -= (*j);
- temp_pointer_y_span--;
}
- while (temp_pointer_y_span < 0) {
- y_delta += (*j);
- if (x != original_pointer_order) {
- if ((*j) == 0) {
- temp_pointer_y_span--;
- }
- }
-
- if (j != height_list.end()) {
- j++;
+ y_delta -= (*j);
+ temp_pointer_order_span--;
+ }
+
+ while (temp_pointer_order_span < 0) {
+
+ y_delta += (*j);
+
+ if (x != last_pointer_order) {
+ if ((*j) == 0) {
+ --temp_pointer_order_span;
}
- temp_pointer_y_span++;
}
- /* find out where we'll be when we move and set height accordingly */
-
- tvp2 = trackview_by_y_position (iy1 + y_delta);
- temp_rtv = dynamic_cast<RouteTimeAxisView*>(tvp2);
- rv->set_height (temp_rtv->current_height());
+
+ if (j != height_list.end()) {
+ j++;
+ }
- /* if you un-comment the following, the region colours will follow the track colours whilst dragging,
- personally, i think this can confuse things, but never mind.
- */
-
- //const GdkColor& col (temp_rtv->view->get_region_color());
- //rv->set_color (const_cast<GdkColor&>(col));
- break;
+ temp_pointer_order_span++;
}
- x++;
+
+
+ /* find out where we'll be when we move and set height accordingly */
+
+ std::pair<TimeAxisView*, int> const pos = trackview_by_y_position (iy1 + y_delta);
+ RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
+ rv->set_height (temp_rtv->view()->child_height());
+
+ /* if you un-comment the following, the region colours will follow
+ the track colours whilst dragging; personally
+ i think this can confuse things, but never mind.
+ */
+
+ //const GdkColor& col (temp_rtv->view->get_region_color());
+ //rv->set_color (const_cast<GdkColor&>(col));
}
}
+ if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
+
+ /* INTER-LAYER MOVEMENT in the same track */
+ y_delta = rtv->view()->child_height () * pointer_layer_span;
+ }
+
+
if (drag_info.brushing) {
mouse_brush_insert_region (rv, pending_region_position);
} else {
pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
nframes64_t drag_delta;
bool changed_tracks, changed_position;
+ std::pair<TimeAxisView*, int> tvp;
+ std::map<RegionView*, RouteTimeAxisView*> final;
/* first_move is set to false if the regionview has been moved in the
motion handler.
}
begin_reversible_command (op_string);
-
changed_position = (drag_info.last_frame_position != (nframes64_t) (clicked_regionview->region()->position()));
- changed_tracks = (trackview_by_y_position (drag_info.current_pointer_y) != &clicked_regionview->get_time_axis_view());
+ tvp = trackview_by_y_position (drag_info.current_pointer_y);
+ changed_tracks = (tvp.first != &clicked_regionview->get_time_axis_view());
drag_delta = clicked_regionview->region()->position() - drag_info.last_frame_position;
track_canvas->update_now ();
- for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) {
-
- RegionView* rv = (*i);
+ /* make a list of where each region ended up */
+ for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
+
double ix1, ix2, iy1, iy2;
- rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
- rv->get_canvas_frame()->i2w (ix1, iy1);
+ (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
+ (*i)->get_canvas_frame()->i2w (ix1, iy1);
iy1 += vertical_adjustment.get_value() - canvas_timebars_vsize;
- TimeAxisView* dest_tv = trackview_by_y_position (iy1);
- RouteTimeAxisView* dest_rtv = dynamic_cast<RouteTimeAxisView*>(dest_tv);
+ std::pair<TimeAxisView*, int> tv = trackview_by_y_position (iy1);
+ final[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
+ }
+
+ for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) {
+
+ RegionView* rv = (*i);
+ RouteTimeAxisView* dest_rtv = final[*i];
+
nframes64_t where;
if (rv->region()->locked()) {
++i;
continue;
}
-
+
if (changed_position && !drag_info.x_constrained) {
-- where = rv->region()->position() - drag_delta;
+ where = rv->region()->position() - drag_delta;
} else {
where = rv->region()->position();
}
}
} else {
- selection->clear_tracks();
+ if (!getenv("ARDOUR_SAE")) {
+ selection->clear_tracks();
+ }
selection->clear_regions();
selection->clear_points ();
selection->clear_lines ();