+
+ back = ev.time ();
+ }
+
+ midi_stream_view()->check_record_layers (region(), back);
+}
+
+void
+MidiRegionView::trim_front_starting ()
+{
+ /* Reparent the note group to the region view's parent, so that it doesn't change
+ when the region view is trimmed.
+ */
+ _temporary_note_group = new ArdourCanvas::Group (*group->property_parent ());
+ _temporary_note_group->move (group->property_x(), group->property_y());
+ _note_group->reparent (*_temporary_note_group);
+}
+
+void
+MidiRegionView::trim_front_ending ()
+{
+ _note_group->reparent (*group);
+ delete _temporary_note_group;
+ _temporary_note_group = 0;
+
+ if (_region->start() < 0) {
+ /* Trim drag made start time -ve; fix this */
+ midi_region()->fix_negative_start ();
+ }
+}
+
+void
+MidiRegionView::edit_patch_change (ArdourCanvas::CanvasPatchChange* pc)
+{
+ PatchChangeDialog d (&_source_relative_time_converter, trackview.session(), *pc->patch (), Gtk::Stock::APPLY);
+ if (d.run () != Gtk::RESPONSE_ACCEPT) {
+ return;
+ }
+
+ change_patch_change (pc->patch(), d.patch ());
+}
+
+
+void
+MidiRegionView::show_verbose_cursor (boost::shared_ptr<NoteType> n) const
+{
+ char buf[24];
+ snprintf (buf, sizeof (buf), "%s (%d) Chn %d\nVel %d",
+ Evoral::midi_note_name (n->note()).c_str(),
+ (int) n->note (),
+ (int) n->channel() + 1,
+ (int) n->velocity());
+
+ show_verbose_cursor (buf, 10, 20);
+}
+
+void
+MidiRegionView::show_verbose_cursor (string const & text, double xoffset, double yoffset) const
+{
+ double wx, wy;
+
+ trackview.editor().get_pointer_position (wx, wy);
+
+ wx += xoffset;
+ wy += yoffset;
+
+ /* Flip the cursor above the mouse pointer if it would overlap the bottom of the canvas */
+
+ double x1, y1, x2, y2;
+ trackview.editor().verbose_cursor()->canvas_item()->get_bounds (x1, y1, x2, y2);
+
+ if ((wy + y2 - y1) > trackview.editor().canvas_height()) {
+ wy -= (y2 - y1) + 2 * yoffset;
+ }
+
+ trackview.editor().verbose_cursor()->set (text, wx, wy);
+ trackview.editor().verbose_cursor()->show ();
+}
+
+/** @param p A session framepos.
+ * @param grid_frames Filled in with the number of frames that a grid interval is at p.
+ * @return p snapped to the grid subdivision underneath it.
+ */
+framepos_t
+MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, framecnt_t& grid_frames) const
+{
+ PublicEditor& editor = trackview.editor ();
+
+ bool success;
+ Evoral::MusicalTime grid_beats = editor.get_grid_type_as_beats (success, p);
+
+ if (!success) {
+ grid_beats = 1;
+ }
+
+ grid_frames = region_beats_to_region_frames (grid_beats);
+
+ /* Hack so that we always snap to the note that we are over, instead of snapping
+ to the next one if we're more than halfway through the one we're over.
+ */
+ if (editor.snap_mode() == SnapNormal && p >= grid_frames / 2) {
+ p -= grid_frames / 2;
+ }
+
+ 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;