Fix setup of gain envelope visible menu item.
[ardour.git] / gtk2_ardour / editor_drag.cc
index 04dedf97ad4c05d2702b8282f10a9dbca96d4e04..0b5b789e9e6e1e2943ae0e6b11ae6a3cb97f2742 100644 (file)
 
 #include "gtkmm2ext/utils.h"
 
-#include "ardour/session.h"
+#include "ardour/audioregion.h"
 #include "ardour/dB.h"
-#include "ardour/region_factory.h"
+#include "ardour/midi_region.h"
 #include "ardour/operations.h"
+#include "ardour/region_factory.h"
+#include "ardour/session.h"
 
 #include "editor.h"
 #include "i18n.h"
@@ -409,20 +411,19 @@ RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<Re
 {
        _editor->visible_order_range (&_visible_y_low, &_visible_y_high);
 
-       /* Make a list of non-hidden tracks to refer to during the drag */
+       /* Make a list of tracks to refer to during the drag; we include hidden tracks,
+          as some of the regions we are dragging may be on such tracks.
+       */
 
        TrackViewList track_views = _editor->track_views;
        track_views.sort (EditorOrderTimeAxisViewSorter ());
 
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-               if (!(*i)->hidden()) {
-
-                       _time_axis_views.push_back (*i);
-
-                       TimeAxisView::Children children_list = (*i)->get_child_list ();
-                       for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
-                               _time_axis_views.push_back (j->get());
-                       }
+               _time_axis_views.push_back (*i);
+               
+               TimeAxisView::Children children_list = (*i)->get_child_list ();
+               for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
+                       _time_axis_views.push_back (j->get());
                }
        }
 
@@ -449,7 +450,9 @@ RegionDrag::region_going_away (RegionView* v)
        }
 }
 
-/** Given a non-hidden TimeAxisView, return the index of it into the _time_axis_views vector */
+/** Given a TimeAxisView, return the index of it into the _time_axis_views vector,
+ *  or -1 if it is not found.
+ */
 int
 RegionDrag::find_time_axis_view (TimeAxisView* t) const
 {
@@ -633,49 +636,24 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
 
                if (first_move) {
 
-                       /* 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 */
-
-                       /* 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 */
-
-                       double iy1 = 1;
-
-                       /* 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 += _editor->get_trackview_group_vertical_offset ();
-
-                       // hide any dependent views
-
                        rv->get_time_axis_view().hide_dependent_views (*rv);
-
-                       /*
-                         reparent to a non scrolling group so that we can keep the
-                         region selection above all time axis views.
-                         reparenting means we have to move the rv as the two
-                         parent groups have different coordinates.
+                                                                                   
+                       /* 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
+                          later, as the two parent groups have different coordinates.
                        */
-
-                       rv->get_canvas_group()->property_y() = iy1 - 1;
+                       
                        rv->get_canvas_group()->reparent (*(_editor->_region_motion_group));
-
+                       
                        rv->fake_set_opaque (true);
+                       
+                       if (!rv->get_time_axis_view().hidden()) {
+                               /* the track that this region view is on is hidden, so hide the region too */
+                               rv->get_canvas_group()->hide ();
+                       }
                }
 
-               /* Work out the change in y position of this region view */
-
-               double y_delta = 0;
-
                /* If we have moved tracks, we'll fudge the layer delta so that the
                   region gets moved back onto layer 0 on its new track; this avoids
                   confusion when dragging regions from non-zero layers onto different
@@ -686,33 +664,21 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                        this_delta_layer = - i->layer;
                }
 
-               /* Move this region to layer 0 on its old track */
-               StreamView* lv = _time_axis_views[i->time_axis_view]->view ();
-               if (lv->layer_display() == Stacked) {
-                       y_delta -= (lv->layers() - i->layer - 1) * lv->child_height ();
-               }
-
-               /* Now move it to its right layer on the current track */
-               StreamView* cv = _time_axis_views[i->time_axis_view + delta_time_axis_view]->view ();
-               if (cv->layer_display() == Stacked) {
-                       y_delta += (cv->layers() - (i->layer + this_delta_layer) - 1) * cv->child_height ();
-               }
+               /* The TimeAxisView that this region is now on */
+               TimeAxisView* tv = _time_axis_views[i->time_axis_view + delta_time_axis_view];
+                       
+               /* Set height */
+               rv->set_height (tv->view()->child_height ());
 
-               /* Move tracks */
-               if (delta_time_axis_view > 0) {
-                       for (int j = 0; j < delta_time_axis_view; ++j) {
-                               y_delta += _time_axis_views[i->time_axis_view + j]->current_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 {
-                       /* start by subtracting the height of the track above where we are now */
-                       for (int j = 1; j <= -delta_time_axis_view; ++j) {
-                               y_delta -= _time_axis_views[i->time_axis_view - j]->current_height ();
-                       }
+                       rv->get_canvas_group()->show ();
                }
 
-               /* Set height */
-               rv->set_height (_time_axis_views[i->time_axis_view + delta_time_axis_view]->view()->child_height ());
-
                /* Update the DraggingView */
                i->time_axis_view += delta_time_axis_view;
                i->layer += this_delta_layer;
@@ -720,7 +686,21 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                if (_brushing) {
                        _editor->mouse_brush_insert_region (rv, pending_region_position);
                } else {
-                       rv->move (x_delta, y_delta);
+                       double x = 0;
+                       double y = 0;
+
+                       /* Get the y coordinate of the top of the track that this region is now on */
+                       tv->canvas_display()->i2w (x, y);
+                       y += _editor->get_trackview_group_vertical_offset();
+                       
+                       /* And adjust for the layer that it should be on */
+                       StreamView* cv = tv->view ();
+                       if (cv->layer_display() == Stacked) {
+                               y += (cv->layers() - i->layer - 1) * cv->child_height ();
+                       }
+                       
+                       /* Now move the region view */
+                       rv->move (x_delta, y - rv->get_canvas_group()->property_y());
                }
 
        } /* foreach region */
@@ -826,10 +806,18 @@ RegionMoveDrag::finished (GdkEvent *, bool movement_occurred)
 
        assert (!_views.empty ());
 
+       /* We might have hidden region views so that they weren't visible during the drag
+          (when they have been reparented).  Now everything can be shown again, as region
+          views are back in their track parent groups.
+       */
+       for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
+               i->view->get_canvas_group()->show ();
+       }
+       
        bool const changed_position = (_last_frame_position != _primary->region()->position());
        bool const changed_tracks = (_time_axis_views[_views.front().time_axis_view] != &_views.front().view->get_time_axis_view());
        framecnt_t const drag_delta = _primary->region()->position() - _last_frame_position;
-
+       
        _editor->update_canvas_now ();
 
        if (_copy) {
@@ -1541,7 +1529,10 @@ NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
 void
 NoteResizeDrag::aborted (bool)
 {
-       /* XXX: TODO */
+       MidiRegionSelection& ms (_editor->get_selection().midi_regions);
+       for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
+               (*r)->abort_resizing ();
+       }
 }
 
 RegionGainDrag::RegionGainDrag (Editor* e, ArdourCanvas::Item* i)
@@ -2106,39 +2097,6 @@ CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
 void
 CursorDrag::motion (GdkEvent* event, bool)
 {
-       if (_drags->current_pointer_y() != last_pointer_y()) {
-
-               /* zoom when we move the pointer up and down */
-
-               /* y range to operate over (pixels) */
-               double const y_range = 512;
-               /* we will multiply the grab zoom by a factor between scale_range and scale_range^-1 */
-               double const scale_range = 4;
-               /* dead zone around the grab point in which to do no zooming (pixels) */
-               double const dead_zone = 100;
-
-               /* current dy */
-               double dy = _drags->current_pointer_y() - grab_y();
-
-               if (dy < -dead_zone || dy > dead_zone) {
-                       /* we are outside the dead zone; remove it from our calculation */
-                       if (dy < 0) {
-                               dy += dead_zone;
-                       } else {
-                               dy -= dead_zone;
-                       }
-
-                       /* get a number from -1 to 1 as dy ranges from -y_range to y_range */
-                       double udy = max (min (dy / y_range, 1.0), -1.0);
-
-                       /* and zoom, using playhead focus temporarily */
-                       Editing::ZoomFocus const zf = _editor->get_zoom_focus ();
-                       _editor->set_zoom_focus (Editing::ZoomFocusPlayhead);
-                       _editor->temporal_zoom (_grab_zoom * pow (scale_range, -udy));
-                       _editor->set_zoom_focus (zf);
-               }
-       }
-
        framepos_t const adjusted_frame = adjusted_current_frame (event);
        if (adjusted_frame != last_pointer_frame()) {
                fake_locate (adjusted_frame);
@@ -3112,7 +3070,37 @@ RubberbandSelectDrag::motion (GdkEvent* event, bool)
                _editor->rubberband_rect->raise_to_top();
 
                show_verbose_cursor_time (pf);
+
+               do_select_things (event, true);
+       }
+}
+
+void
+RubberbandSelectDrag::do_select_things (GdkEvent* event, bool drag_in_progress)
+{
+       framepos_t x1;
+       framepos_t x2;
+       
+       if (grab_frame() < last_pointer_frame()) {
+               x1 = grab_frame ();
+               x2 = last_pointer_frame ();
+       } else {
+               x2 = grab_frame ();
+               x1 = last_pointer_frame ();
        }
+
+       double y1;
+       double y2;
+       
+       if (_drags->current_pointer_y() < grab_y()) {
+               y1 = _drags->current_pointer_y();
+               y2 = grab_y();
+       } else {
+               y2 = _drags->current_pointer_y();
+               y1 = grab_y();
+       }
+
+       select_things (event->button.state, x1, x2, y1, y2, drag_in_progress);
 }
 
 void
@@ -3121,36 +3109,12 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
        if (movement_occurred) {
 
                motion (event, false);
+               do_select_things (event, false);
 
-               double y1,y2;
-               if (_drags->current_pointer_y() < grab_y()) {
-                       y1 = _drags->current_pointer_y();
-                       y2 = grab_y();
-               } else {
-                       y2 = _drags->current_pointer_y();
-                       y1 = grab_y();
-               }
-
-
-               Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
-
-               _editor->begin_reversible_command (_("rubberband selection"));
-
-               if (grab_frame() < last_pointer_frame()) {
-                       _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op, false);
-               } else {
-                       _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op, false);
-               }
+       } else {
 
-               _editor->commit_reversible_command ();
+               deselect_things ();
 
-       } else {
-               if (!getenv("ARDOUR_SAE")) {
-                       _editor->selection->clear_tracks();
-               }
-               _editor->selection->clear_regions();
-               _editor->selection->clear_points ();
-               _editor->selection->clear_lines ();
        }
 
        _editor->rubberband_rect->hide();
@@ -3878,16 +3842,16 @@ NoteDrag::total_dx () const
        /* primary note time */
        frameoffset_t const n = _region->source_beats_to_absolute_frames (_primary->note()->time ());
 
-       /* new time of the primary note relative to the region position */
+       /* new time of the primary note in session frames */
        frameoffset_t st = n + dx;
 
+       framepos_t const rp = _region->region()->position ();
+
        /* prevent the note being dragged earlier than the region's position */
-       if (st < 0) {
-               st = 0;
-       }
+       st = max (st, rp);
 
        /* snap and return corresponding delta */
-       return _region->snap_frame_to_frame (st) - n;
+       return _region->snap_frame_to_frame (st - rp) + rp - n;
 }
 
 /** @return Current total drag y change in note number */
@@ -4239,3 +4203,67 @@ PatchChangeDrag::setup_pointer_frame_offset ()
        _pointer_frame_offset = raw_grab_frame() - _region_view->source_beats_to_absolute_frames (_patch_change->patch()->time());
 }
 
+MidiRubberbandSelectDrag::MidiRubberbandSelectDrag (Editor* e, MidiRegionView* rv)
+       : RubberbandSelectDrag (e, rv->get_canvas_frame ())
+       , _region_view (rv)
+{
+
+}
+
+void
+MidiRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress)
+{
+       framepos_t const p = _region_view->region()->position ();
+       double const y = _region_view->midi_view()->y_position ();
+
+       x1 = max ((framepos_t) 0, x1 - p);
+       x2 = max ((framepos_t) 0, x2 - p);
+       y1 = max (0.0, y1 - y);
+       y2 = max (0.0, y2 - y);
+       
+       _region_view->update_drag_selection (
+               _editor->frame_to_pixel (x1),
+               _editor->frame_to_pixel (x2),
+               y1,
+               y2,
+               Keyboard::modifier_state_contains (button_state, Keyboard::TertiaryModifier)
+               );
+}
+
+void
+MidiRubberbandSelectDrag::deselect_things ()
+{
+       /* XXX */
+}
+
+EditorRubberbandSelectDrag::EditorRubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i)
+       : RubberbandSelectDrag (e, i)
+{
+
+}
+
+void
+EditorRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress)
+{
+       if (drag_in_progress) {
+               /* We just want to select things at the end of the drag, not during it */
+               return;
+       }
+       
+       Selection::Operation op = ArdourKeyboard::selection_type (button_state);
+       
+       _editor->begin_reversible_command (_("rubberband selection"));
+       _editor->select_all_within (x1, x2 - 1, y1, y2, _editor->track_views, op, false);
+       _editor->commit_reversible_command ();
+}
+
+void
+EditorRubberbandSelectDrag::deselect_things ()
+{
+       if (!getenv("ARDOUR_SAE")) {
+               _editor->selection->clear_tracks();
+       }
+       _editor->selection->clear_regions();
+       _editor->selection->clear_points ();
+       _editor->selection->clear_lines ();
+}