Add missing files.
[ardour.git] / gtk2_ardour / midi_region_view.cc
index 0900ecc34eeab1110cfcc13b0a9516cca4cf9fc7..fcab48328711f3ad127de3f199dc51c668c2883d 100644 (file)
@@ -80,6 +80,8 @@ using namespace Editing;
 using namespace ArdourCanvas;
 using Gtkmm2ext::Keyboard;
 
+PBD::Signal1<void, MidiRegionView *> MidiRegionView::SelectionCleared;
+
 #define MIDI_BP_ZERO ((Config->get_first_midi_bank_is_zero())?0:1)
 
 MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv,
@@ -116,6 +118,8 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
 
        Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
        connect_to_diskstream ();
+
+       SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), ui_bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
 }
 
 MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv,
@@ -149,6 +153,8 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
        PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
 
        connect_to_diskstream ();
+
+       SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), ui_bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
 }
 
 void
@@ -284,6 +290,14 @@ MidiRegionView::init (Gdk::Color const & basic_color, bool wfd)
 
        Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
        connect_to_diskstream ();
+
+       SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), ui_bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
+}
+
+const boost::shared_ptr<ARDOUR::MidiRegion>
+MidiRegionView::midi_region() const
+{
+       return boost::dynamic_pointer_cast<ARDOUR::MidiRegion>(_region);
 }
 
 void
@@ -380,7 +394,7 @@ MidiRegionView::enter_notify (GdkEventCrossing* ev)
 }
 
 bool
-MidiRegionView::leave_notify (GdkEventCrossing* ev)
+MidiRegionView::leave_notify (GdkEventCrossing*)
 {
        _mouse_mode_connection.disconnect ();
 
@@ -711,6 +725,13 @@ MidiRegionView::scroll (GdkEventScroll* ev)
                return false;
        }
 
+       if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
+               /* XXX: bit of a hack; allow PrimaryModifier scroll through so that
+                  it still works for zoom.
+               */
+               return false;
+       }
+
        trackview.editor().verbose_cursor()->hide ();
 
        bool fine = !Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier);
@@ -835,7 +856,7 @@ void
 MidiRegionView::channel_edit ()
 {
        bool first = true;
-       uint8_t current_channel;
+       uint8_t current_channel = 0;
 
        if (_selection.empty()) {
                return;
@@ -1960,7 +1981,7 @@ MidiRegionView::delete_note (boost::shared_ptr<NoteType> n)
 }
 
 void
-MidiRegionView::clear_selection_except (ArdourCanvas::CanvasNoteEvent* ev)
+MidiRegionView::clear_selection_except (ArdourCanvas::CanvasNoteEvent* ev, bool signal)
 {
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
                if ((*i) != ev) {
@@ -1980,6 +2001,10 @@ MidiRegionView::clear_selection_except (ArdourCanvas::CanvasNoteEvent* ev)
        /* this does not change the status of this regionview w.r.t the editor
           selection.
        */
+
+       if (signal) {
+               SelectionCleared (this); /* EMIT SIGNAL */
+       }
 }
 
 void
@@ -2008,6 +2033,31 @@ MidiRegionView::select_all_notes ()
        }
 }
 
+void
+MidiRegionView::select_range (framepos_t start, framepos_t end)
+{
+       clear_selection ();
+
+       for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
+               framepos_t t = source_beats_to_absolute_frames((*i)->note()->time());
+               if (t >= start && t <= end) {
+                       add_to_selection (*i);
+               }
+       }
+}
+
+void
+MidiRegionView::invert_selection ()
+{
+       for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
+               if ((*i)->selected()) {
+                       remove_from_selection(*i);
+               } else {
+                       add_to_selection (*i);
+               }
+       }
+}
+
 void
 MidiRegionView::select_matching_notes (uint8_t notenum, uint16_t channel_mask, bool add, bool extend)
 {
@@ -2332,12 +2382,6 @@ MidiRegionView::note_dropped(CanvasNoteEvent *, frameoffset_t dt, int8_t dnote)
                // keep notes in standard midi range
                clamp_to_0_127(new_pitch);
 
-               // keep original pitch if note is dragged outside valid midi range
-               if ((original_pitch != 0 && new_pitch == 0)
-                   || (original_pitch != 127 && new_pitch == 127)) {
-                       new_pitch = original_pitch;
-               }
-
                lowest_note_in_selection  = std::min(lowest_note_in_selection,  new_pitch);
                highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
 
@@ -2353,6 +2397,9 @@ MidiRegionView::note_dropped(CanvasNoteEvent *, frameoffset_t dt, int8_t dnote)
        }
 }
 
+/** @param x Pixel relative to the region position.
+ *  @return Snapped frame relative to the region position.
+ */
 framepos_t
 MidiRegionView::snap_pixel_to_frame(double x)
 {
@@ -2360,32 +2407,9 @@ MidiRegionView::snap_pixel_to_frame(double x)
        return snap_frame_to_frame (editor.pixel_to_frame (x));
 }
 
-/** Snap a frame offset within our region using the current snap settings.
- *  @param x Frame offset from this region's position.
- *  @return Snapped frame offset from this region's position.
+/** @param x Pixel relative to the region position.
+ *  @return Snapped pixel relative to the region position.
  */
-frameoffset_t
-MidiRegionView::snap_frame_to_frame (frameoffset_t x) const
-{
-       PublicEditor& editor = trackview.editor();
-
-       /* x is region relative, convert it to global absolute frames */
-       framepos_t const session_frame = x + _region->position();
-
-       /* try a snap in either direction */
-       framepos_t frame = session_frame;
-       editor.snap_to (frame, 0);
-
-       /* if we went off the beginning of the region, snap forwards */
-       if (frame < _region->position ()) {
-               frame = session_frame;
-               editor.snap_to (frame, 1);
-       }
-
-       /* back to region relative */
-       return frame - _region->position();
-}
-
 double
 MidiRegionView::snap_to_pixel(double x)
 {
@@ -2525,9 +2549,6 @@ MidiRegionView::update_resizing (ArdourCanvas::CanvasNoteEvent* primary, bool at
                        double beats;
 
                        beats = snap_pixel_to_frame (current_x);
-                       /* XXX not sure this is correct - snap_pixel_to_frame()
-                          returns an absolute frame.
-                       */
                        beats = region_frames_to_region_beats (beats);
 
                        double len;
@@ -2590,13 +2611,10 @@ MidiRegionView::commit_resizing (ArdourCanvas::CanvasNoteEvent* primary, bool at
                        }
                }
 
-               /* Convert that to a frame within the region */
+               /* Convert that to a frame within the source */
                current_x = snap_pixel_to_frame (current_x) + _region->start ();
 
                /* and then to beats */
-               /* XXX not sure this is correct - snap_pixel_to_frame()
-                  returns an absolute frame.
-               */
                current_x = region_frames_to_region_beats (current_x);
 
                if (at_front && current_x < canvas_note->note()->end_time()) {
@@ -3356,9 +3374,9 @@ MidiRegionView::update_ghost_note (double x, double y)
        double length = region_frames_to_region_beats (snap_frame_to_frame (f + grid_frames) - f);
 
        /* note that this sets the time of the ghost note in beats relative to
-          the start of the region.
+          the start of the source; that is how all note times are stored.
        */
-       _ghost_note->note()->set_time (region_frames_to_region_beats (f));
+       _ghost_note->note()->set_time (absolute_frames_to_source_beats (f + _region->position ()));
        _ghost_note->note()->set_length (length);
        _ghost_note->note()->set_note (midi_stream_view()->y_to_note (y));
        _ghost_note->note()->set_channel (mtv->get_channel_for_add ());
@@ -3659,3 +3677,17 @@ MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, framecnt_t& grid_fr
 
        return snap_frame_to_frame (p);
 }
+
+/** Called when the selection has been cleared in any MidiRegionView.
+ *  @param rv MidiRegionView that the selection was cleared in.
+ */
+void
+MidiRegionView::selection_cleared (MidiRegionView* rv)
+{
+       if (rv == this) {
+               return;
+       }
+
+       /* Clear our selection in sympathy; but don't signal the fact */
+       clear_selection (false);
+}