fix stupid MIDI::Manager design to properly handle multiple MIDI ports with the same...
[ardour.git] / gtk2_ardour / editor.cc
index 75648f0486aaccc1148cb398ca20acd81a8938d6..3bc2980e153ea58e1183021b5bb5d6310601ca31 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2000-2009 Paul Davis 
+    Copyright (C) 2000-2009 Paul Davis
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #include "mixer_strip.h"
 #include "editor_route_groups.h"
 #include "editor_regions.h"
+#include "editor_locations.h"
 #include "editor_snapshots.h"
 
 #include "i18n.h"
@@ -129,9 +130,9 @@ const double Editor::timebar_height = 15.0;
 
 static const gchar *_snap_type_strings[] = {
        N_("CD Frames"),
-       N_("SMPTE Frames"),
-       N_("SMPTE Seconds"),
-       N_("SMPTE Minutes"),
+       N_("Timecode Frames"),
+       N_("Timecode Seconds"),
+       N_("Timecode Minutes"),
        N_("Seconds"),
        N_("Minutes"),
        N_("Beats/32"),
@@ -211,50 +212,46 @@ show_me_the_size (Requisition* r, const char* what)
 }
 
 Editor::Editor ()
-       : 
          /* time display buttons */
-
-         minsec_label (_("Mins:Secs")),
-         bbt_label (_("Bars:Beats")),
-         smpte_label (_("Timecode")),
-         frame_label (_("Samples")),
-         tempo_label (_("Tempo")),
-         meter_label (_("Meter")),
-         mark_label (_("Location Markers")),
-         range_mark_label (_("Range Markers")),
-         transport_mark_label (_("Loop/Punch Ranges")),
-         cd_mark_label (_("CD Markers")),
-         edit_packer (4, 4, true),
+       : minsec_label (_("Mins:Secs"))
+       , bbt_label (_("Bars:Beats"))
+       , timecode_label (_("Timecode"))
+       , frame_label (_("Samples"))
+       , tempo_label (_("Tempo"))
+       , meter_label (_("Meter"))
+       , mark_label (_("Location Markers"))
+       , range_mark_label (_("Range Markers"))
+       , transport_mark_label (_("Loop/Punch Ranges"))
+       , cd_mark_label (_("CD Markers"))
+       , edit_packer (4, 4, true)
 
          /* the values here don't matter: layout widgets
             reset them as needed.
          */
 
-         vertical_adjustment (0.0, 0.0, 10.0, 400.0),
-         horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
+       , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
+       , horizontal_adjustment (0.0, 0.0, 20.0, 1200.0)
 
          /* tool bar related */
 
-         edit_point_clock (X_("editpoint"), false, X_("EditPointClock"), true),
-         zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
-         
-         toolbar_selection_clock_table (2,3),
-         
-         automation_mode_button (_("mode")),
-         global_automation_button (_("automation")),
+       , zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true)
+
+       , toolbar_selection_clock_table (2,3)
 
-         midi_panic_button (_("Panic")),
-         midi_tools_tearoff (0),
+       , automation_mode_button (_("mode"))
+       , global_automation_button (_("automation"))
+
+       , midi_panic_button (_("Panic"))
 
 #ifdef WITH_CMT
-         image_socket_listener(0),
+       , image_socket_listener(0)
 #endif
 
          /* nudge */
 
-         nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true),
-         meters_running(false),
-         _pending_locate_request (false)
+       , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
+       , meters_running(false)
+       , _pending_locate_request (false)
 
 {
        constructed = false;
@@ -270,6 +267,8 @@ Editor::Editor ()
        cut_buffer = new Selection (this);
 
        clicked_regionview = 0;
+       clicked_axisview = 0;
+       clicked_routeview = 0;
        clicked_crossfadeview = 0;
        clicked_control_point = 0;
        last_update_frame = 0;
@@ -277,7 +276,7 @@ Editor::Editor ()
        current_mixer_strip = 0;
        current_bbt_points = 0;
        tempo_lines = 0;
-       
+
        snap_type_strings =  I18N (_snap_type_strings);
        snap_mode_strings =  I18N (_snap_mode_strings);
        zoom_focus_strings = I18N (_zoom_focus_strings);
@@ -285,7 +284,7 @@ Editor::Editor ()
 #ifdef USE_RUBBERBAND
        rb_opt_strings = I18N (_rb_opt_strings);
 #endif
-       
+
        snap_threshold = 5.0;
        bbt_beat_subdivision = 4;
        _canvas_width = 0;
@@ -326,8 +325,8 @@ Editor::Editor ()
        region_edit_menu_split_item = 0;
        temp_location = 0;
        leftmost_frame = 0;
-       ignore_mouse_mode_toggle = false;
-       ignore_midi_edit_mode_toggle = false;
+       current_stepping_trackview = 0;
+       entered_track = 0;
        entered_regionview = 0;
        entered_marker = 0;
        clear_entered_track = false;
@@ -339,7 +338,6 @@ Editor::Editor ()
        _dragging_edit_point = false;
        _dragging_hscrollbar = false;
        select_new_marker = false;
-       zoomed_to_region = false;
        rhythm_ferret = 0;
        _bundle_manager = 0;
        for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
@@ -359,13 +357,13 @@ Editor::Editor ()
        location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
        location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
 
-       set_midi_edit_mode (MidiEditPencil, true);
        _edit_point = EditAtMouse;
-       set_mouse_mode (MouseObject, true);
+       _internal_editing = false;
+       current_canvas_cursor = 0;
 
        frames_per_unit = 2048; /* too early to use reset_zoom () */
        reset_hscrollbar_stepping ();
-       
+
        zoom_focus = ZoomFocusLeft;
        set_zoom_focus (ZoomFocusLeft);
        zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
@@ -382,12 +380,12 @@ Editor::Editor ()
        minsec_label.set_padding (5,0);
        minsec_label.hide ();
        minsec_label.set_no_show_all();
-       smpte_label.set_name ("EditorTimeButton");
-       smpte_label.set_size_request (-1, (int)timebar_height);
-       smpte_label.set_alignment (1.0, 0.5);
-       smpte_label.set_padding (5,0);
-       smpte_label.hide ();
-       smpte_label.set_no_show_all();
+       timecode_label.set_name ("EditorTimeButton");
+       timecode_label.set_size_request (-1, (int)timebar_height);
+       timecode_label.set_alignment (1.0, 0.5);
+       timecode_label.set_padding (5,0);
+       timecode_label.hide ();
+       timecode_label.set_no_show_all();
        frame_label.set_name ("EditorTimeButton");
        frame_label.set_size_request (-1, (int)timebar_height);
        frame_label.set_alignment (1.0, 0.5);
@@ -452,11 +450,11 @@ Editor::Editor ()
        h->pack_start (*_group_tabs, PACK_SHRINK);
        h->pack_start (edit_controls_vbox);
        controls_layout.add (*h);
-       
+
        controls_layout.set_name ("EditControlsBase");
        controls_layout.add_events (Gdk::SCROLL_MASK);
        controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
-       
+
        controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
        controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
        controls_layout_size_request_connection = controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
@@ -471,11 +469,7 @@ Editor::Editor ()
        edit_hscrollbar.set_name ("EditorHScrollbar");
 
        build_cursors ();
-       setup_toolbar ();
-       setup_midi_toolbar ();
 
-       edit_point_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_point_clock_changed));
-       
        ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
        ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
                        0.0, 1.0, 100.0, 1.0));
@@ -486,7 +480,7 @@ Editor::Editor ()
        time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
        time_canvas_vbox.set_size_request (-1, -1);
 
-       ruler_label_event_box.add (ruler_label_vbox);   
+       ruler_label_event_box.add (ruler_label_vbox);
        ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
        ruler_label_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
 
@@ -494,7 +488,7 @@ Editor::Editor ()
        time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
        time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
 
-       /* these enable us to have a dedicated window (for cursor setting, etc.) 
+       /* these enable us to have a dedicated window (for cursor setting, etc.)
           for the canvas areas.
        */
 
@@ -528,22 +522,7 @@ Editor::Editor ()
        _routes = new EditorRoutes (this);
        _regions = new EditorRegions (this);
        _snapshots = new EditorSnapshots (this);
-
-       named_selection_scroller.add (named_selection_display);
-       named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
-
-       named_selection_model = TreeStore::create (named_selection_columns);
-       named_selection_display.set_model (named_selection_model);
-       named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
-       named_selection_display.set_headers_visible (false);
-       named_selection_display.set_size_request (100, -1);
-       named_selection_display.set_name ("NamedSelectionDisplay");
-       
-       named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
-       named_selection_display.set_size_request (100, -1);
-       named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
-       named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
-       named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
+       _locations = new EditorLocations (this);
 
        Gtk::Label* nlabel;
 
@@ -559,19 +538,16 @@ Editor::Editor ()
        nlabel = manage (new Label (_("Route Groups")));
        nlabel->set_angle (-90);
        the_notebook.append_page (_route_groups->widget (), *nlabel);
-       
-       if (!Profile->get_sae()) {
-               nlabel = manage (new Label (_("Chunks")));
-               nlabel->set_angle (-90);
-               the_notebook.append_page (named_selection_scroller, *nlabel);
-       }
+       nlabel = manage (new Label (_("Ranges & Marks")));
+       nlabel->set_angle (-90);
+       the_notebook.append_page (_locations->widget (), *nlabel);
 
        the_notebook.set_show_tabs (true);
        the_notebook.set_scrollable (true);
-       the_notebook.popup_enable ();
+       the_notebook.popup_disable ();
        the_notebook.set_tab_pos (Gtk::POS_RIGHT);
        the_notebook.show_all ();
-
+       
        post_maximal_editor_width = 0;
        post_maximal_pane_position = 0;
 
@@ -581,11 +557,10 @@ Editor::Editor ()
 
        edit_pane.pack1 (*editor_summary_pane, true, true);
        edit_pane.pack2 (the_notebook, false, true);
-       
+
        edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
 
        top_hbox.pack_start (toolbar_frame, false, true);
-       top_hbox.pack_start (midi_toolbar_frame, false, true);
 
        HBox *hbox = manage (new HBox);
        hbox->pack_start (edit_pane, true, true);
@@ -604,17 +579,21 @@ Editor::Editor ()
        vpacker.pack_end (global_hpacker, true, true);
 
        /* register actions now so that set_state() can find them and set toggles/checks etc */
-       
+
        register_actions ();
 
-       snap_type = SnapToBeat;
-       set_snap_to (snap_type);
-       snap_mode = SnapOff;
-       set_snap_mode (snap_mode);
+       setup_toolbar ();
+       setup_midi_toolbar ();
+
+       _snap_type = SnapToBeat;
+       set_snap_to (_snap_type);
+       _snap_mode = SnapOff;
+       set_snap_mode (_snap_mode);
+       set_mouse_mode (MouseObject, true);
        set_edit_point_preference (EditAtMouse, true);
 
        XMLNode* node = ARDOUR_UI::instance()->editor_settings();
-       set_state (*node);
+       set_state (*node, Stateful::loading_state_version);
 
        _playlist_selector = new PlaylistSelector();
        _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
@@ -691,7 +670,7 @@ Editor::~Editor()
                {
                        image_socket_listener->close_connection() ;
                }
-               
+
                delete image_socket_listener ;
                image_socket_listener = 0 ;
        }
@@ -749,7 +728,7 @@ Editor::set_entered_regionview (RegionView* rv)
 }
 
 void
-Editor::set_entered_track (TimeAxisViewPtr tav)
+Editor::set_entered_track (TimeAxisView* tav)
 {
        if (entered_track) {
                entered_track->exited ();
@@ -778,10 +757,10 @@ Editor::show_window ()
                   to be re-hidden
                */
 
-               TimeAxisViewPtr tv;
-       
+               TimeAxisView *tv;
+
                for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-                       tv = (static_cast<TimeAxisViewPtr>(*i));
+                       tv = (static_cast<TimeAxisView*>(*i));
                        tv->reset_height ();
                }
        }
@@ -803,27 +782,6 @@ Editor::instant_save ()
        }
 }
 
-void
-Editor::edit_point_clock_changed()
-{
-       if (_dragging_edit_point) {
-               return;
-       }
-
-       if (selection->markers.empty()) {
-               return;
-       }
-
-       bool ignored;
-       Location* loc = find_location_from_marker (selection->markers.front(), ignored);
-
-       if (!loc) {
-               return;
-       }
-
-       loc->move_to (edit_point_clock.current_time());
-}
-
 void
 Editor::zoom_adjustment_changed ()
 {
@@ -840,7 +798,7 @@ Editor::zoom_adjustment_changed ()
                fpu = session->current_end_frame() / _canvas_width;
                zoom_range_clock.set ((nframes64_t) floor (fpu * _canvas_width));
        }
-       
+
        temporal_zoom (fpu);
 }
 
@@ -857,7 +815,7 @@ Editor::control_scroll (float fraction)
 
        /*
                _control_scroll_target is an optional<T>
-       
+
                it acts like a pointer to an nframes64_t, with
                a operator conversion to boolean to check
                that it has a value could possibly use
@@ -883,7 +841,7 @@ Editor::control_scroll (float fraction)
 
        playhead_cursor->set_position (*_control_scroll_target);
        UpdateAllTransportClocks (*_control_scroll_target);
-       
+
        if (*_control_scroll_target > (current_page_frames() / 2)) {
                /* try to center PH in window */
                reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
@@ -907,7 +865,7 @@ Editor::control_scroll (float fraction)
 }
 
 bool
-Editor::deferred_control_scroll (nframes64_t target)
+Editor::deferred_control_scroll (nframes64_t /*target*/)
 {
        session->request_locate (*_control_scroll_target, session->transport_rolling());
        // reset for next stream
@@ -931,7 +889,7 @@ Editor::access_action (std::string action_group, std::string action_item)
        if (act) {
                act->activate();
        }
-               
+
 
 }
 
@@ -945,7 +903,7 @@ Editor::on_realize ()
 void
 Editor::start_scrolling ()
 {
-       scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect 
+       scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
                (mem_fun(*this, &Editor::update_current_screen));
 
 }
@@ -967,7 +925,7 @@ Editor::map_position_change (nframes64_t frame)
 
        center_screen (frame);
        playhead_cursor->set_position (frame);
-}      
+}
 
 void
 Editor::center_screen (nframes64_t frame)
@@ -976,7 +934,7 @@ Editor::center_screen (nframes64_t frame)
 
        /* if we're off the page, then scroll.
         */
-       
+
        if (frame < leftmost_frame || frame >= leftmost_frame + page) {
                center_screen_internal (frame, page);
        }
@@ -986,7 +944,7 @@ void
 Editor::center_screen_internal (nframes64_t frame, float page)
 {
        page /= 2;
-               
+
        if (frame > page) {
                frame -= (nframes64_t) page;
        } else {
@@ -1019,7 +977,7 @@ void
 Editor::update_title_s (const string & snap_name)
 {
        ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
-       
+
        update_title ();
 }
 
@@ -1061,7 +1019,7 @@ Editor::connect_to_session (Session *t)
        sensitize_the_right_region_actions (false);
 
        XMLNode* node = ARDOUR_UI::instance()->editor_settings();
-       set_state (*node);
+       set_state (*node, Stateful::loading_state_version);
 
        /* catch up with the playhead */
 
@@ -1081,21 +1039,17 @@ Editor::connect_to_session (Session *t)
        session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
        session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
        session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
-       session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
-       session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
        session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
        session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
        session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
 
-       session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
+       session_connections.push_back (session->TimecodeOffsetChanged.connect (mem_fun(*this, &Editor::update_just_timecode)));
 
        session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
 
        session_connections.push_back (session->Located.connect (mem_fun (*this, &Editor::located)));
        session_connections.push_back (session->config.ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed)));
 
-       edit_point_clock.set_mode(AudioClock::BBT);
-       edit_point_clock.set_session (session);
        zoom_range_clock.set_session (session);
        _playlist_selector->set_session (session);
        nudge_clock.set_session (session);
@@ -1107,9 +1061,9 @@ Editor::connect_to_session (Session *t)
                nframes_t pos = session->tempo_map().bbt_duration_at (0, bbt, 1);
                nudge_clock.set_mode(AudioClock::BBT);
                nudge_clock.set (pos, true, 0, AudioClock::BBT);
-               
+
        } else {
-               nudge_clock.set (session->frame_rate() * 5, true, 0, AudioClock::SMPTE); // default of 5 seconds
+               nudge_clock.set (session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
        }
 
        playhead_cursor->canvas_item.show ();
@@ -1133,7 +1087,7 @@ Editor::connect_to_session (Session *t)
                // force name
                loc->set_name (_("Loop"));
        }
-       
+
        loc = session->locations()->auto_punch_location();
        if (loc == 0) {
                loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
@@ -1149,9 +1103,9 @@ Editor::connect_to_session (Session *t)
 
        Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
        session->config.map_parameters (mem_fun (*this, &Editor::parameter_changed));
-       
+
        session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
-       
+
        refresh_location_display ();
        session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
        session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
@@ -1165,19 +1119,17 @@ Editor::connect_to_session (Session *t)
 
        handle_new_duration ();
 
-       redisplay_named_selections ();
-
        restore_ruler_visibility ();
        //tempo_map_changed (Change (0));
        session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
 
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-               (static_cast<TimeAxisViewPtr>(*i))->set_samples_per_unit (frames_per_unit);
+               (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
        }
 
        start_scrolling ();
 
-       switch (snap_type) {
+       switch (_snap_type) {
        case SnapToRegionStart:
        case SnapToRegionEnd:
        case SnapToRegionSync:
@@ -1198,7 +1150,8 @@ Editor::connect_to_session (Session *t)
        _regions->connect_to_session (session);
        _snapshots->connect_to_session (session);
        _routes->connect_to_session (session);
-       
+       _locations->connect_to_session (session);
+
        start_updating ();
 }
 
@@ -1206,7 +1159,7 @@ void
 Editor::build_cursors ()
 {
        using namespace Gdk;
-       
+
        Gdk::Color mbg ("#000000" ); /* Black */
        Gdk::Color mfg ("#0000ff" ); /* Blue. */
 
@@ -1219,23 +1172,23 @@ Editor::build_cursors ()
 
        Gdk::Color fbg ("#ffffff" );
        Gdk::Color ffg  ("#000000" );
-       
+
        {
                RefPtr<Bitmap> source, mask;
-               
+
                source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
                mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
                fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
        }
-       
-       { 
+
+       {
                RefPtr<Bitmap> source, mask;
                source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
                mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
                speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
        }
-       
-       { 
+
+       {
                RefPtr<Bitmap> bits;
                char pix[4] = { 0, 0, 0, 0 };
                bits = Bitmap::create (pix, 2, 2);
@@ -1243,17 +1196,17 @@ Editor::build_cursors ()
                transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
        }
 
-       { 
+       {
                RefPtr<Bitmap> bits;
                char pix[4] = { 0, 0, 0, 0 };
                bits = Bitmap::create (pix, 2, 2);
                Gdk::Color c;
                transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
        }
-       
+
 
        grabber_cursor = new Gdk::Cursor (HAND2);
-       
+
        {
                Glib::RefPtr<Gdk::Pixbuf> grabber_edit_point_pixbuf (::get_icon ("grabber_edit_point"));
                grabber_edit_point_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_edit_point_pixbuf, 5, 17);
@@ -1295,7 +1248,7 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i
                } else {
                        items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
                }
-               
+
                items.push_back (SeparatorElem());
 
                if (Profile->get_sae()) {
@@ -1318,9 +1271,9 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i
                } else {
                        items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
                }
-               
+
                items.push_back (SeparatorElem());
-               
+
                if (Profile->get_sae()) {
                        items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
                        items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
@@ -1389,7 +1342,7 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type,
 
        menu = (this->*build_menu_function)(frame);
        menu->set_name ("ArdourContextMenu");
-       
+
        /* now handle specific situations */
 
        switch (item_type) {
@@ -1434,10 +1387,10 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type,
        if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
 
                /* Bounce to disk */
-               
+
                using namespace Menu_Helpers;
                MenuList& edit_items  = menu->items();
-               
+
                edit_items.push_back (SeparatorElem());
 
                switch (clicked_routeview->audio_track()->freeze_state()) {
@@ -1448,7 +1401,7 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type,
                case AudioTrack::Frozen:
                        edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
                        break;
-                       
+
                case AudioTrack::UnFrozen:
                        edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
                        break;
@@ -1464,7 +1417,7 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type,
 }
 
 Menu*
-Editor::build_track_context_menu (nframes64_t ignored)
+Editor::build_track_context_menu (nframes64_t)
 {
        using namespace Menu_Helpers;
 
@@ -1476,7 +1429,7 @@ Editor::build_track_context_menu (nframes64_t ignored)
 }
 
 Menu*
-Editor::build_track_bus_context_menu (nframes64_t ignored)
+Editor::build_track_bus_context_menu (nframes64_t)
 {
        using namespace Menu_Helpers;
 
@@ -1494,21 +1447,21 @@ Editor::build_track_region_context_menu (nframes64_t frame)
        MenuList& edit_items  = track_region_context_menu.items();
        edit_items.clear();
 
-       RouteTimeAxisViewPtr rtv = boost::dynamic_pointer_cast<RouteTimeAxisView> (clicked_axisview);
+       RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
 
        if (rtv) {
                boost::shared_ptr<Diskstream> ds;
                boost::shared_ptr<Playlist> pl;
-               
+
                if ((ds = rtv->get_diskstream()) && ((pl = ds->playlist()))) {
                        Playlist::RegionList* regions = pl->regions_at ((nframes64_t) floor ( (double)frame * ds->speed()));
 
                        if (selection->regions.size() > 1) {
-                               // there's already a multiple selection: just add a 
-                               // single region context menu that will act on all 
+                               // there's already a multiple selection: just add a
+                               // single region context menu that will act on all
                                // selected regions
-                               boost::shared_ptr<Region> dummy_region; // = NULL               
-                               add_region_context_items (rtv->view(), dummy_region, edit_items);                       
+                               boost::shared_ptr<Region> dummy_region; // = NULL
+                               add_region_context_items (rtv->view(), dummy_region, edit_items);
                        } else {
                                for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
                                        add_region_context_items (rtv->view(), (*i), edit_items);
@@ -1531,7 +1484,7 @@ Editor::build_track_crossfade_context_menu (nframes64_t frame)
        MenuList& edit_items  = track_crossfade_context_menu.items();
        edit_items.clear ();
 
-       AudioTimeAxisViewPtr atv = boost::dynamic_pointer_cast<AudioTimeAxisView> (clicked_axisview);
+       AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
 
        if (atv) {
                boost::shared_ptr<Diskstream> ds;
@@ -1552,11 +1505,11 @@ Editor::build_track_crossfade_context_menu (nframes64_t frame)
                        }
 
                        if (selection->regions.size() > 1) {
-                               // there's already a multiple selection: just add a 
-                               // single region context menu that will act on all 
+                               // there's already a multiple selection: just add a
+                               // single region context menu that will act on all
                                // selected regions
-                               boost::shared_ptr<Region> dummy_region; // = NULL               
-                               add_region_context_items (atv->audio_view(), dummy_region, edit_items);                 
+                               boost::shared_ptr<Region> dummy_region; // = NULL
+                               add_region_context_items (atv->audio_view(), dummy_region, edit_items);
                        } else {
                                for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
                                        add_region_context_items (atv->audio_view(), (*i), edit_items);
@@ -1585,7 +1538,7 @@ Editor::analyze_region_selection()
 
        analysis_window->set_regionmode();
        analysis_window->analyze();
-       
+
        analysis_window->present();
 }
 
@@ -1603,12 +1556,12 @@ Editor::analyze_range_selection()
 
        analysis_window->set_rangemode();
        analysis_window->analyze();
-       
+
        analysis_window->present();
 }
 
 Menu*
-Editor::build_track_selection_context_menu (nframes64_t ignored)
+Editor::build_track_selection_context_menu (nframes64_t)
 {
        using namespace Menu_Helpers;
        MenuList& edit_items  = track_selection_context_menu.items();
@@ -1625,7 +1578,7 @@ Editor::build_track_selection_context_menu (nframes64_t ignored)
  * @param edit_items List to add the items to.
  */
 void
-Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
+Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
 {
        using namespace Menu_Helpers;
        Menu     *xfade_menu = manage (new Menu);
@@ -1635,7 +1588,7 @@ Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Cr
 
        if (xfade->active()) {
                str = _("Mute");
-       } else { 
+       } else {
                str = _("Unmute");
        }
 
@@ -1697,21 +1650,28 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
                ar = boost::dynamic_pointer_cast<AudioRegion> (region);
                mr = boost::dynamic_pointer_cast<MidiRegion> (region);
 
-               /* when this particular menu pops up, make the relevant region 
+               /* when this particular menu pops up, make the relevant region
                   become selected.
                */
 
                region_menu->signal_map_event().connect (
                        bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr<Region>(region)));
-               
+
                items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::rename_region)));
-               items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
+               if (mr && internal_editing()) {
+                       items.push_back (MenuElem (_("List editor..."), mem_fun(*this, &Editor::show_midi_list_editor)));
+               } else {
+                       items.push_back (MenuElem (_("Region editor"), mem_fun(*this, &Editor::edit_region)));
+               }
        }
 
        items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
        items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun  (*this, &Editor::lower_region_to_bottom)));
        items.push_back (SeparatorElem());
        items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_point)));
+       if (_edit_point == EditAtMouse) {
+               items.back ().set_sensitive (false);
+       }
        items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
        items.push_back (SeparatorElem());
 
@@ -1740,10 +1700,10 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
                region_lock_item->set_active();
        }
        region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
-       
+
        items.push_back (CheckMenuElem (_("Glue to Bars&Beats")));
        CheckMenuItem* bbt_glue_item = static_cast<CheckMenuItem*>(&items.back());
-       
+
        switch (region_to_check->positional_lock_style()) {
        case Region::MusicTime:
                bbt_glue_item->set_active (true);
@@ -1752,9 +1712,9 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
                bbt_glue_item->set_active (false);
                break;
        }
-       
+
        bbt_glue_item->signal_activate().connect (bind (mem_fun (*this, &Editor::set_region_lock_style), Region::MusicTime));
-       
+
        items.push_back (CheckMenuElem (_("Mute")));
        CheckMenuItem* region_mute_item = static_cast<CheckMenuItem*>(&items.back());
        fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
@@ -1763,7 +1723,7 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
                region_mute_item->set_active();
                fooc.block (false);
        }
-       
+
        if (!Profile->get_sae()) {
                items.push_back (CheckMenuElem (_("Opaque")));
                CheckMenuItem* region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
@@ -1774,19 +1734,19 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
                        fooc.block (false);
                }
        }
-       
+
        items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
        if (region_to_check->at_natural_position()) {
                items.back().set_sensitive (false);
        }
-       
+
        items.push_back (SeparatorElem());
-       
+
        if (ar) {
-               
+
                RegionView* rv = sv->find_view (ar);
                AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
-               
+
                if (!Profile->get_sae()) {
                        items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
 
@@ -1798,11 +1758,11 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
                                region_envelope_visible_item->set_active (true);
                                fooc.block (false);
                        }
-               
+
                        items.push_back (CheckMenuElem (_("Envelope Active")));
                        CheckMenuItem* region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
                        fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
-                       
+
                        if (ar->envelope_active()) {
                                fooc.block (true);
                                region_envelope_active_item->set_active (true);
@@ -1812,10 +1772,9 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
                        items.push_back (SeparatorElem());
                }
 
-               if (ar->scale_amplitude() != 1.0f) {
-                       items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
-               } else {
-                       items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
+               items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
+               if (ar->scale_amplitude() != 1) {
+                       items.push_back (MenuElem (_("Reset Gain"), mem_fun(*this, &Editor::reset_region_scale_amplitude)));
                }
 
        } else if (mr) {
@@ -1823,7 +1782,7 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
                items.push_back (SeparatorElem());
        }
 
-       items.push_back (MenuElem (_("Strip silence..."), mem_fun (*this, &Editor::strip_region_silence)));
+       items.push_back (MenuElem (_("Strip Silence..."), mem_fun (*this, &Editor::strip_region_silence)));
        items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
        items.push_back (SeparatorElem());
 
@@ -1837,13 +1796,13 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
 
        items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_region)));
        items.push_back (SeparatorElem());
-                        
+
        /* Nudge region */
 
        Menu *nudge_menu = manage (new Menu());
        MenuList& nudge_items = nudge_menu->items();
        nudge_menu->set_name ("ArdourContextMenu");
-       
+
        nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false, false))));
        nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false, false))));
        nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
@@ -1855,7 +1814,7 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
        Menu *trim_menu = manage (new Menu);
        MenuList& trim_items = trim_menu->items();
        trim_menu->set_name ("ArdourContextMenu");
-       
+
        trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point)));
        foo_item = &trim_items.back();
        if (_edit_point == EditAtMouse) {
@@ -1868,13 +1827,13 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
        }
        trim_items.push_back (MenuElem (_("Trim To Loop"), mem_fun(*this, &Editor::trim_region_to_loop)));
        trim_items.push_back (MenuElem (_("Trim To Punch"), mem_fun(*this, &Editor::trim_region_to_punch)));
-                            
+
        items.push_back (MenuElem (_("Trim"), *trim_menu));
        items.push_back (SeparatorElem());
 
-       items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
+       items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split))));
        region_edit_menu_split_item = &items.back();
-       
+
        if (_edit_point == EditAtMouse) {
                region_edit_menu_split_item->set_sensitive (false);
        }
@@ -1903,7 +1862,7 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
                menu_item_name.replace (pos, 1, "__");
                pos += 2;
        }
-       
+
        edit_items.push_back (MenuElem (menu_item_name, *region_menu));
        edit_items.push_back (SeparatorElem());
 }
@@ -1916,43 +1875,46 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
 {
        using namespace Menu_Helpers;
 
-       edit_items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
-       edit_items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
+       edit_items.push_back (MenuElem (_("Play Range"), mem_fun(*this, &Editor::play_selection)));
+       edit_items.push_back (MenuElem (_("Loop Range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
 
        edit_items.push_back (SeparatorElem());
        edit_items.push_back (MenuElem (_("Spectral Analysis"), mem_fun(*this, &Editor::analyze_range_selection)));
-       
-       edit_items.push_back (SeparatorElem());
-       edit_items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
-       edit_items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
+
+       if (!selection->regions.empty()) {
+               edit_items.push_back (SeparatorElem());
+               edit_items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
+               edit_items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
+       }
 
        edit_items.push_back (SeparatorElem());
-       edit_items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
-       edit_items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
-       
+       edit_items.push_back (MenuElem (_("Silence Range"), mem_fun(*this, &Editor::separate_region_from_selection)));
+       edit_items.push_back (MenuElem (_("Convert to Region in Region List"), mem_fun(*this, &Editor::new_region_from_selection)));
+
        edit_items.push_back (SeparatorElem());
-       edit_items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
+       edit_items.push_back (MenuElem (_("Select All in Range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
 
        edit_items.push_back (SeparatorElem());
-       edit_items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
-       edit_items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
-       
+       edit_items.push_back (MenuElem (_("Set Loop from Range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
+       edit_items.push_back (MenuElem (_("Set Punch from Range"), mem_fun(*this, &Editor::set_punch_from_selection)));
+
        edit_items.push_back (SeparatorElem());
        edit_items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
+
        edit_items.push_back (SeparatorElem());
-       edit_items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
-       edit_items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
-       edit_items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
-       edit_items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
+       edit_items.push_back (MenuElem (_("Crop Region to Range"), mem_fun(*this, &Editor::crop_region_to_selection)));
+       edit_items.push_back (MenuElem (_("Fill Range with Region"), mem_fun(*this, &Editor::region_fill_selection)));
+       edit_items.push_back (MenuElem (_("Duplicate Range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
+
        edit_items.push_back (SeparatorElem());
-       edit_items.push_back (MenuElem (_("Consolidate range"), bind (mem_fun(*this, &Editor::bounce_range_selection), true, false)));
-       edit_items.push_back (MenuElem (_("Consolidate range with processing"), bind (mem_fun(*this, &Editor::bounce_range_selection), true, true)));
-       edit_items.push_back (MenuElem (_("Bounce range to region list"), bind (mem_fun(*this, &Editor::bounce_range_selection), false, false)));
-       edit_items.push_back (MenuElem (_("Bounce range to region list with processing"), bind (mem_fun(*this, &Editor::bounce_range_selection), false, true)));
-       edit_items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_range)));
+       edit_items.push_back (MenuElem (_("Consolidate Range"), bind (mem_fun(*this, &Editor::bounce_range_selection), true, false)));
+       edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), bind (mem_fun(*this, &Editor::bounce_range_selection), true, true)));
+       edit_items.push_back (MenuElem (_("Bounce Range to Region List"), bind (mem_fun(*this, &Editor::bounce_range_selection), false, false)));
+       edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), bind (mem_fun(*this, &Editor::bounce_range_selection), false, true)));
+       edit_items.push_back (MenuElem (_("Export Range"), mem_fun(*this, &Editor::export_range)));
 }
 
-       
+
 void
 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
 {
@@ -1963,13 +1925,13 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
        Menu *play_menu = manage (new Menu);
        MenuList& play_items = play_menu->items();
        play_menu->set_name ("ArdourContextMenu");
-       
+
        play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
        play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
        play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
        play_items.push_back (SeparatorElem());
        play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
-       
+
        edit_items.push_back (MenuElem (_("Play"), *play_menu));
 
        /* Selection */
@@ -1977,7 +1939,7 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
        Menu *select_menu = manage (new Menu);
        MenuList& select_items = select_menu->items();
        select_menu->set_name ("ArdourContextMenu");
-       
+
        select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
        select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
        select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
@@ -1994,8 +1956,6 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
        select_items.push_back (MenuElem (_("Select All Within Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), true)));
        select_items.push_back (MenuElem (_("Select Range Between Playhead & Edit Point"), mem_fun(*this, &Editor::select_range_between)));
 
-       select_items.push_back (SeparatorElem());
-
        edit_items.push_back (MenuElem (_("Select"), *select_menu));
 
        /* Cut-n-Paste */
@@ -2003,7 +1963,7 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
        Menu *cutnpaste_menu = manage (new Menu);
        MenuList& cutnpaste_items = cutnpaste_menu->items();
        cutnpaste_menu->set_name ("ArdourContextMenu");
-       
+
        cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
        cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
        cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
@@ -2015,12 +1975,10 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
 
        cutnpaste_items.push_back (SeparatorElem());
 
-       cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
-
        edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
 
        /* Adding new material */
-       
+
        edit_items.push_back (SeparatorElem());
        edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
        edit_items.push_back (MenuElem (_("Insert Existing Media"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
@@ -2030,7 +1988,7 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
        Menu *nudge_menu = manage (new Menu());
        MenuList& nudge_items = nudge_menu->items();
        nudge_menu->set_name ("ArdourContextMenu");
-       
+
        edit_items.push_back (SeparatorElem());
        nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
        nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
@@ -2050,7 +2008,7 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
        Menu *play_menu = manage (new Menu);
        MenuList& play_items = play_menu->items();
        play_menu->set_name ("ArdourContextMenu");
-       
+
        play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
        play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
        edit_items.push_back (MenuElem (_("Play"), *play_menu));
@@ -2060,7 +2018,7 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
        Menu *select_menu = manage (new Menu);
        MenuList& select_items = select_menu->items();
        select_menu->set_name ("ArdourContextMenu");
-       
+
        select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
        select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
        select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
@@ -2078,7 +2036,7 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
        Menu *cutnpaste_menu = manage (new Menu);
        MenuList& cutnpaste_items = cutnpaste_menu->items();
        cutnpaste_menu->set_name ("ArdourContextMenu");
-       
+
        cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
        cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
        cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
@@ -2086,7 +2044,7 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
        Menu *nudge_menu = manage (new Menu());
        MenuList& nudge_items = nudge_menu->items();
        nudge_menu->set_name ("ArdourContextMenu");
-       
+
        edit_items.push_back (SeparatorElem());
        nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
        nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
@@ -2096,18 +2054,30 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
        edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
 }
 
+SnapType
+Editor::snap_type() const
+{
+       return _snap_type;
+}
+
+SnapMode
+Editor::snap_mode() const
+{
+       return _snap_mode;
+}
+
 void
 Editor::set_snap_to (SnapType st)
 {
        unsigned int snap_ind = (unsigned int)st;
 
-       snap_type = st;
-       
+       _snap_type = st;
+
        if (snap_ind > snap_type_strings.size() - 1) {
                snap_ind = 0;
-               snap_type = (SnapType)snap_ind;
+               _snap_type = (SnapType)snap_ind;
        }
-       
+
        string str = snap_type_strings[snap_ind];
 
        if (str != snap_type_selector.get_active_text()) {
@@ -2116,7 +2086,7 @@ Editor::set_snap_to (SnapType st)
 
        instant_save ();
 
-       switch (snap_type) {
+       switch (_snap_type) {
        case SnapToAThirtysecondBeat:
        case SnapToASixteenthBeat:
        case SnapToAEighthBeat:
@@ -2142,7 +2112,7 @@ Editor::set_snap_to (SnapType st)
 void
 Editor::set_snap_mode (SnapMode mode)
 {
-       snap_mode = mode;
+       _snap_mode = mode;
        string str = snap_mode_strings[(int)mode];
 
        if (str != snap_mode_selector.get_active_text ()) {
@@ -2221,7 +2191,7 @@ Editor::set_edit_point_preference (EditPoint ep, bool force)
 }
 
 int
-Editor::set_state (const XMLNode& node)
+Editor::set_state (const XMLNode& node, int /*version*/)
 {
        const XMLProperty* prop;
        XMLNode* geometry;
@@ -2297,7 +2267,7 @@ Editor::set_state (const XMLNode& node)
                   position may be zero already, and it does nothing in such
                   circumstances.
                */
-               
+
                leftmost_frame = 0;
                horizontal_adjustment.set_value (0);
        }
@@ -2322,10 +2292,6 @@ Editor::set_state (const XMLNode& node)
                set_snap_mode ((SnapMode) atoi (prop->value()));
        }
 
-       if ((prop = node.property ("edit-point"))) {
-               set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
-       }
-
        if ((prop = node.property ("mouse-mode"))) {
                MouseMode m = str2mousemode(prop->value());
                mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
@@ -2335,8 +2301,22 @@ Editor::set_state (const XMLNode& node)
                set_mouse_mode (MouseObject, true);
        }
 
+       if ((prop = node.property ("internal-edit"))) {
+               bool yn = string_is_affirmative (prop->value());
+               RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
+               if (act) {
+                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
+                       tact->set_active (!yn);
+                       tact->set_active (yn);
+               }
+       }
+
+       if ((prop = node.property ("edit-point"))) {
+               set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
+       }
+
        if ((prop = node.property ("show-waveforms-recording"))) {
-               bool yn = (prop->value() == "yes");
+               bool yn = string_is_affirmative (prop->value());
                _show_waveforms_recording = !yn;
                RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
                if (act) {
@@ -2346,9 +2326,9 @@ Editor::set_state (const XMLNode& node)
                        tact->set_active (yn);
                }
        }
-       
+
        if ((prop = node.property ("show-measures"))) {
-               bool yn = (prop->value() == "yes");
+               bool yn = string_is_affirmative (prop->value());
                _show_measures = !yn;
                RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
                if (act) {
@@ -2360,7 +2340,7 @@ Editor::set_state (const XMLNode& node)
        }
 
        if ((prop = node.property ("follow-playhead"))) {
-               bool yn = (prop->value() == "yes");
+               bool yn = string_is_affirmative (prop->value());
                set_follow_playhead (yn);
                RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
                if (act) {
@@ -2376,7 +2356,7 @@ Editor::set_state (const XMLNode& node)
        }
 
        if ((prop = node.property ("xfades-visible"))) {
-               bool yn = (prop->value() == "yes");
+               bool yn = string_is_affirmative (prop->value());
                _xfade_visibility = !yn;
                // set_xfade_visibility (yn);
        }
@@ -2387,15 +2367,15 @@ Editor::set_state (const XMLNode& node)
                if (act) {
 
                        Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
-                       bool yn = (prop->value() == X_("yes"));
+                       bool yn = string_is_affirmative (prop->value());
 
                        /* do it twice to force the change */
-                       
+
                        tact->set_active (!yn);
                        tact->set_active (yn);
                }
        }
-       
+
        if ((prop = node.property ("show-editor-list"))) {
 
                Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
@@ -2403,10 +2383,10 @@ Editor::set_state (const XMLNode& node)
                if (act) {
 
                        Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
-                       bool yn = (prop->value() == X_("yes"));
+                       bool yn = string_is_affirmative (prop->value());
 
                        /* do it twice to force the change */
-                       
+
                        tact->set_active (!yn);
                        tact->set_active (yn);
                }
@@ -2424,15 +2404,15 @@ Editor::get_state ()
 
        _id.print (buf, sizeof (buf));
        node->add_property ("id", buf);
-       
+
        if (is_realized()) {
                Glib::RefPtr<Gdk::Window> win = get_window();
-               
+
                int x, y, xoff, yoff, width, height;
                win->get_root_origin(x, y);
                win->get_position(xoff, yoff);
                win->get_size(width, height);
-               
+
                XMLNode* geometry = new XMLNode ("geometry");
 
                snprintf(buf, sizeof(buf), "%d", width);
@@ -2454,14 +2434,14 @@ Editor::get_state ()
        }
 
        maybe_add_mixer_strip_width (*node);
-       
+
        snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
        node->add_property ("zoom-focus", buf);
        snprintf (buf, sizeof(buf), "%f", frames_per_unit);
        node->add_property ("zoom", buf);
-       snprintf (buf, sizeof(buf), "%d", (int) snap_type);
+       snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
        node->add_property ("snap-to", buf);
-       snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
+       snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
        node->add_property ("snap-mode", buf);
 
        node->add_property ("edit-point", enum_2_string (_edit_point));
@@ -2475,13 +2455,14 @@ Editor::get_state ()
        node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
        node->add_property ("region-list-sort-type", enum2str (_regions->sort_type ()));
        node->add_property ("mouse-mode", enum2str(mouse_mode));
-       
+       node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
+
        Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
        if (act) {
                Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
                node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
        }
-       
+
        act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
        if (act) {
                Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
@@ -2498,24 +2479,47 @@ Editor::get_state ()
  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
  *  in stacked region display mode, otherwise 0.
  */
-std::pair<TimeAxisViewPtr, layer_t>
+std::pair<TimeAxisView *, layer_t>
 Editor::trackview_by_y_position (double y)
 {
        for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
 
-               std::pair<TimeAxisViewPtr, int> const r = (*iter)->covers_y_position (y);
+               std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
                if (r.first) {
                        return r;
                }
        }
 
-       return std::make_pair (TimeAxisViewPtr (), 0);
+       return std::make_pair ( (TimeAxisView *) 0, 0);
+}
+
+/** Snap a position to the grid, if appropriate, taking into account current
+ *  grid settings and also the state of any snap modifier keys that may be pressed.
+ *  @param start Position to snap.
+ *  @param event Event to get current key modifier information from.
+ */
+void
+Editor::snap_to_with_modifier (nframes64_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
+{
+       if (!session) {
+               return;
+       }
+
+       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
+               if (_snap_mode == SnapOff) {
+                       snap_to_internal (start, direction, for_mark);
+               }
+       } else {
+               if (_snap_mode != SnapOff) {
+                       snap_to_internal (start, direction, for_mark);
+               }
+       }
 }
 
 void
 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
 {
-       if (!session || snap_mode == SnapOff) {
+       if (!session || _snap_mode == SnapOff) {
                return;
        }
 
@@ -2523,75 +2527,89 @@ Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
 }
 
 void
-Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark)
+Editor::timecode_snap_to_internal (nframes64_t& start, int32_t direction, bool /*for_mark*/)
 {
-       Location* before = 0;
-       Location* after = 0;
-
-       const nframes64_t one_second = session->frame_rate();
-       const nframes64_t one_minute = session->frame_rate() * 60;
-       const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
-       nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
-       nframes64_t presnap = start;
+       const nframes64_t one_timecode_second = (nframes64_t)(rint(session->timecode_frames_per_second()) * session->frames_per_timecode_frame());
+       nframes64_t one_timecode_minute = (nframes64_t)(rint(session->timecode_frames_per_second()) * session->frames_per_timecode_frame() * 60);
 
-       switch (snap_type) {
-       case SnapToCDFrame:
-               if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
-                       start = (nframes64_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
-               } else {
-                       start = (nframes64_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
-               }
-               break;
-
-       case SnapToSMPTEFrame:
-               if (((direction == 0) && (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2))) || (direction > 0)) {
-                       start = (nframes64_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
+       switch (_snap_type) {
+       case SnapToTimecodeFrame:
+               if (((direction == 0) && (fmod((double)start, (double)session->frames_per_timecode_frame()) > (session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
+                       start = (nframes64_t) (ceil ((double) start / session->frames_per_timecode_frame()) * session->frames_per_timecode_frame());
                } else {
-                       start = (nframes64_t) (floor ((double) start / session->frames_per_smpte_frame()) *  session->frames_per_smpte_frame());
+                       start = (nframes64_t) (floor ((double) start / session->frames_per_timecode_frame()) *  session->frames_per_timecode_frame());
                }
                break;
 
-       case SnapToSMPTESeconds:
-               if (session->smpte_offset_negative())
+       case SnapToTimecodeSeconds:
+               if (session->timecode_offset_negative())
                {
-                       start += session->smpte_offset ();
+                       start += session->timecode_offset ();
                } else {
-                       start -= session->smpte_offset ();
-               }    
-               if (((direction == 0) && (start % one_smpte_second > one_smpte_second / 2)) || direction > 0) {
-                       start = (nframes64_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
+                       start -= session->timecode_offset ();
+               }
+               if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
+                       start = (nframes64_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
                } else {
-                       start = (nframes64_t) floor ((double) start / one_smpte_second) * one_smpte_second;
+                       start = (nframes64_t) floor ((double) start / one_timecode_second) * one_timecode_second;
                }
-               
-               if (session->smpte_offset_negative())
+
+               if (session->timecode_offset_negative())
                {
-                       start -= session->smpte_offset ();
+                       start -= session->timecode_offset ();
                } else {
-                       start += session->smpte_offset ();
+                       start += session->timecode_offset ();
                }
                break;
-               
-       case SnapToSMPTEMinutes:
-               if (session->smpte_offset_negative())
+
+       case SnapToTimecodeMinutes:
+               if (session->timecode_offset_negative())
                {
-                       start += session->smpte_offset ();
+                       start += session->timecode_offset ();
                } else {
-                       start -= session->smpte_offset ();
+                       start -= session->timecode_offset ();
                }
-               if (((direction == 0) && (start % one_smpte_minute > one_smpte_minute / 2)) || direction > 0) {
-                       start = (nframes64_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
+               if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
+                       start = (nframes64_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
                } else {
-                       start = (nframes64_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
+                       start = (nframes64_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
                }
-               if (session->smpte_offset_negative())
+               if (session->timecode_offset_negative())
                {
-                       start -= session->smpte_offset ();
+                       start -= session->timecode_offset ();
                } else {
-                       start += session->smpte_offset ();
+                       start += session->timecode_offset ();
                }
                break;
-               
+       default:
+               fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
+               /*NOTREACHED*/
+       }
+}
+
+void
+Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark)
+{
+       const nframes64_t one_second = session->frame_rate();
+       const nframes64_t one_minute = session->frame_rate() * 60;
+       nframes64_t presnap = start;
+       nframes64_t before;
+       nframes64_t after;
+
+       switch (_snap_type) {
+       case SnapToTimecodeFrame:
+       case SnapToTimecodeSeconds:
+       case SnapToTimecodeMinutes:
+               return timecode_snap_to_internal (start, direction, for_mark);
+
+       case SnapToCDFrame:
+               if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
+                       start = (nframes64_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
+               } else {
+                       start = (nframes64_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
+               }
+               break;
+
        case SnapToSeconds:
                if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
                        start = (nframes64_t) ceil ((double) start / one_second) * one_second;
@@ -2599,7 +2617,7 @@ Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark)
                        start = (nframes64_t) floor ((double) start / one_second) * one_second;
                }
                break;
-               
+
        case SnapToMinutes:
                if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
                        start = (nframes64_t) ceil ((double) start / one_minute) * one_minute;
@@ -2617,23 +2635,23 @@ Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark)
                break;
 
        case SnapToAThirtysecondBeat:
-               start = session->tempo_map().round_to_beat_subdivision (start, 32);
+               start = session->tempo_map().round_to_beat_subdivision (start, 32, direction);
                break;
 
        case SnapToASixteenthBeat:
-               start = session->tempo_map().round_to_beat_subdivision (start, 16);
+               start = session->tempo_map().round_to_beat_subdivision (start, 16, direction);
                break;
 
        case SnapToAEighthBeat:
-               start = session->tempo_map().round_to_beat_subdivision (start, 8);
+               start = session->tempo_map().round_to_beat_subdivision (start, 8, direction);
                break;
 
        case SnapToAQuarterBeat:
-               start = session->tempo_map().round_to_beat_subdivision (start, 4);
+               start = session->tempo_map().round_to_beat_subdivision (start, 4, direction);
                break;
 
        case SnapToAThirdBeat:
-               start = session->tempo_map().round_to_beat_subdivision (start, 3);
+               start = session->tempo_map().round_to_beat_subdivision (start, 3, direction);
                break;
 
        case SnapToMark:
@@ -2641,39 +2659,21 @@ Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark)
                        return;
                }
 
-               before = session->locations()->first_location_before (start);
-               after = session->locations()->first_location_after (start);
+               session->locations()->marks_either_side (start, before, after);
 
-               if (direction < 0) {
-                       if (before) {
-                               start = before->start();
+               if (before == max_frames) {
+                       start = after;
+               } else if (after == max_frames) {
+                       start = before;
+               } else if (before != max_frames && after != max_frames) {
+                       /* have before and after */
+                       if ((start - before) < (after - start)) {
+                               start = before;
                        } else {
-                               start = 0;
-                       }
-               } else if (direction > 0) {
-                       if (after) {
-                               start = after->start();
-                       } else {
-                               start = session->current_end_frame();
-                       }
-               } else {
-                       if (before) {
-                               if (after) {
-                                       /* find nearest of the two */
-                                       if ((start - before->start()) < (after->start() - start)) {
-                                               start = before->start();
-                                       } else {
-                                               start = after->start();
-                                       }
-                               } else {
-                                       start = before->start();
-                               }
-                       } else if (after) {
-                               start = after->start();
-                       } else {
-                               /* relax */
+                               start = after;
                        }
                }
+
                break;
 
        case SnapToRegionStart:
@@ -2681,95 +2681,58 @@ Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark)
        case SnapToRegionSync:
        case SnapToRegionBoundary:
                if (!region_boundary_cache.empty()) {
-                       vector<nframes64_t>::iterator i;
+
+                       vector<nframes64_t>::iterator prev = region_boundary_cache.end ();
+                       vector<nframes64_t>::iterator next = region_boundary_cache.end ();
 
                        if (direction > 0) {
-                               i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
+                               next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
                        } else {
-                               i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
+                               next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
                        }
-                       
-                       if (i != region_boundary_cache.end()) {
-
-                               /* lower bound doesn't quite to the right thing for our purposes */
 
-                               if (direction < 0 && i != region_boundary_cache.begin()) {
-                                       --i;
-                               }
+                       if (next != region_boundary_cache.begin ()) {
+                               prev = next;
+                               prev--;
+                       }
 
-                               start = *i;
+                       nframes64_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
+                       nframes64_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
 
+                       if (start > (p + n) / 2) {
+                               start = n;
                        } else {
-                               start = region_boundary_cache.back();
+                               start = p;
                        }
-               } 
+               }
                break;
        }
 
-       switch (snap_mode) {
+       switch (_snap_mode) {
        case SnapNormal:
-               return;                 
-               
+               return;
+
        case SnapMagnetic:
-               
+
                if (presnap > start) {
                        if (presnap > (start + unit_to_frame(snap_threshold))) {
                                start = presnap;
                        }
-                       
+
                } else if (presnap < start) {
                        if (presnap < (start - unit_to_frame(snap_threshold))) {
                                start = presnap;
                        }
                }
-               
+
        default:
                /* handled at entry */
                return;
-               
-       }
-}
-
-double
-Editor::snap_length_beats (nframes64_t start)
-{
-       if (!session) {
-               return 1.0;
-       }
-
-       /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
-
-       switch (snap_type) {
-       case SnapToBar:
-               return session->tempo_map().meter_at(start).beats_per_bar();
 
-       case SnapToBeat:
-               return 1.0;
-
-       case SnapToAThirtysecondBeat:
-               return 1.0 / (double)32.0;
-               break;
-
-       case SnapToASixteenthBeat:
-               return 1.0 / (double)16.0;
-               break;
-
-       case SnapToAEighthBeat:
-               return 1.0 / (double)8.0;
-               break;
-
-       case SnapToAQuarterBeat:
-               return 1.0 / (double)4.0;
-               break;
-
-       case SnapToAThirdBeat:
-               return 1.0 / (double)3.0;
-
-       default:
-               return 1.0;
        }
 }
 
+
 void
 Editor::setup_toolbar ()
 {
@@ -2777,36 +2740,13 @@ Editor::setup_toolbar ()
 
        /* Mode Buttons (tool selection) */
 
-       vector<ToggleButton *> mouse_mode_buttons;
-
-       mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
        mouse_move_button.set_relief(Gtk::RELIEF_NONE);
-       mouse_mode_buttons.push_back (&mouse_move_button);
-
-       if (!Profile->get_sae()) {
-               mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
-               mouse_select_button.set_relief(Gtk::RELIEF_NONE);
-               mouse_mode_buttons.push_back (&mouse_select_button);
-
-               mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
-               mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
-               mouse_mode_buttons.push_back (&mouse_gain_button);
-       }
-
-       mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
+       mouse_select_button.set_relief(Gtk::RELIEF_NONE);
+       mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
        mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
-       mouse_mode_buttons.push_back (&mouse_zoom_button);
-       mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
        mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
-       mouse_mode_buttons.push_back (&mouse_timefx_button);
-       mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
        mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
-       mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
-       mouse_note_button.set_relief(Gtk::RELIEF_NONE);
-       mouse_mode_buttons.push_back (&mouse_note_button);
-       mouse_mode_buttons.push_back (&mouse_audition_button);
-       
-       mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
+       // internal_edit_button.set_relief(Gtk::RELIEF_NONE);
 
        HBox* mode_box = manage(new HBox);
        mode_box->set_border_width (2);
@@ -2822,7 +2762,7 @@ Editor::setup_toolbar ()
        }
        mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
        mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
-       mouse_mode_button_box.pack_start(mouse_note_button, true, true);
+       mouse_mode_button_box.pack_start(internal_edit_button, true, true);
        mouse_mode_button_box.set_homogeneous(true);
 
        vector<string> edit_mode_strings;
@@ -2838,38 +2778,39 @@ Editor::setup_toolbar ()
 
        mode_box->pack_start(edit_mode_selector);
        mode_box->pack_start(mouse_mode_button_box);
-       
+
        mouse_mode_tearoff = manage (new TearOff (*mode_box));
        mouse_mode_tearoff->set_name ("MouseModeBase");
+       mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (bind (sigc::ptr_fun (relay_key_press), &mouse_mode_tearoff->tearoff_window()), false);
 
        if (Profile->get_sae()) {
                mouse_mode_tearoff->set_can_be_torn_off (false);
        }
 
-       mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
+       mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
                                                  &mouse_mode_tearoff->tearoff_window()));
-       mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
+       mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
                                                  &mouse_mode_tearoff->tearoff_window(), 1));
-       mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
+       mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
                                                  &mouse_mode_tearoff->tearoff_window()));
-       mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
+       mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
                                                   &mouse_mode_tearoff->tearoff_window(), 1));
 
+       mouse_move_button.set_mode (false);
+       mouse_select_button.set_mode (false);
+       mouse_gain_button.set_mode (false);
+       mouse_zoom_button.set_mode (false);
+       mouse_timefx_button.set_mode (false);
+       mouse_audition_button.set_mode (false);
+
        mouse_move_button.set_name ("MouseModeButton");
        mouse_select_button.set_name ("MouseModeButton");
        mouse_gain_button.set_name ("MouseModeButton");
        mouse_zoom_button.set_name ("MouseModeButton");
        mouse_timefx_button.set_name ("MouseModeButton");
        mouse_audition_button.set_name ("MouseModeButton");
-       mouse_note_button.set_name ("MouseModeButton");
 
-       ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
-       ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
-       ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
-       ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
-       ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
-       ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
-       ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
+       internal_edit_button.set_name ("MouseModeButton");
 
        mouse_move_button.unset_flags (CAN_FOCUS);
        mouse_select_button.unset_flags (CAN_FOCUS);
@@ -2877,41 +2818,25 @@ Editor::setup_toolbar ()
        mouse_zoom_button.unset_flags (CAN_FOCUS);
        mouse_timefx_button.unset_flags (CAN_FOCUS);
        mouse_audition_button.unset_flags (CAN_FOCUS);
-       mouse_note_button.unset_flags (CAN_FOCUS);
-
-       mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
-       mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
-
-       mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
-       mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
-       mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
-       mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
-       mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
-       mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
-
-       // mouse_move_button.set_active (true);
-       
+       internal_edit_button.unset_flags (CAN_FOCUS);
 
        /* Zoom */
-       
+
        zoom_box.set_spacing (1);
        zoom_box.set_border_width (0);
 
        zoom_in_button.set_name ("EditorTimeButton");
-       zoom_in_button.set_size_request(-1,16);
-       zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
+       zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_BUTTON))));
        zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
        ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
-       
+
        zoom_out_button.set_name ("EditorTimeButton");
-       zoom_out_button.set_size_request(-1,16);
-       zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
+       zoom_out_button.set_image (*(manage (new Image (Stock::ZOOM_OUT, Gtk::ICON_SIZE_BUTTON))));
        zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
        ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
 
        zoom_out_full_button.set_name ("EditorTimeButton");
-       zoom_out_full_button.set_size_request(-1,16);
-       zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
+       zoom_out_full_button.set_image (*(manage (new Image (Stock::ZOOM_100, Gtk::ICON_SIZE_BUTTON))));
        zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
        ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
 
@@ -2924,10 +2849,30 @@ Editor::setup_toolbar ()
        zoom_box.pack_start (zoom_in_button, false, false);
        zoom_box.pack_start (zoom_out_full_button, false, false);
 
+       /* Track zoom buttons */
+       tav_expand_button.set_name ("TrackHeightButton");
+       tav_expand_button.set_size_request(-1,20);
+       tav_expand_button.add (*(manage (new Image (::get_icon("tav_exp")))));
+       tav_expand_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::tav_zoom_step), true));
+       ARDOUR_UI::instance()->tooltips().set_tip (tav_expand_button, _("Expand Tracks"));
+
+       tav_shrink_button.set_name ("TrackHeightButton");
+       tav_shrink_button.set_size_request(-1,20);
+       tav_shrink_button.add (*(manage (new Image (::get_icon("tav_shrink")))));
+       tav_shrink_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::tav_zoom_step), false));
+       ARDOUR_UI::instance()->tooltips().set_tip (tav_shrink_button, _("Shrink Tracks"));
+
+       track_zoom_box.set_spacing (1);
+       track_zoom_box.set_border_width (0);
+
+       track_zoom_box.pack_start (tav_shrink_button, false, false);
+       track_zoom_box.pack_start (tav_expand_button, false, false);
+
        HBox* zbc = manage (new HBox);
        zbc->pack_start (zoom_focus_selector, PACK_SHRINK);
        zoom_vbox.pack_start (*zbc, PACK_SHRINK);
        zoom_vbox.pack_start (zoom_box, PACK_SHRINK);
+       zoom_vbox.pack_start (track_zoom_box, PACK_SHRINK);
 
        snap_box.set_spacing (1);
        snap_box.set_border_width (2);
@@ -2947,7 +2892,6 @@ Editor::setup_toolbar ()
        edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
        ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
 
-       snap_box.pack_start (edit_point_clock, false, false);
        snap_box.pack_start (snap_mode_selector, false, false);
        snap_box.pack_start (snap_type_selector, false, false);
        snap_box.pack_start (edit_point_selector, false, false);
@@ -2973,18 +2917,19 @@ Editor::setup_toolbar ()
 
        tools_tearoff = manage (new TearOff (*hbox));
        tools_tearoff->set_name ("MouseModeBase");
+       tools_tearoff->tearoff_window().signal_key_press_event().connect (bind (sigc::ptr_fun (relay_key_press), &tools_tearoff->tearoff_window()), false);
 
        if (Profile->get_sae()) {
                tools_tearoff->set_can_be_torn_off (false);
        }
 
-       tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
+       tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
                                             &tools_tearoff->tearoff_window()));
-       tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
+       tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
                                             &tools_tearoff->tearoff_window(), 0));
-       tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
+       tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
                                             &tools_tearoff->tearoff_window()));
-       tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
+       tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
                                              &tools_tearoff->tearoff_window(), 0));
 
        toolbar_hbox.set_spacing (10);
@@ -2993,13 +2938,12 @@ Editor::setup_toolbar ()
        toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
        toolbar_hbox.pack_start (*tools_tearoff, false, false);
 
-       
        hbox->pack_start (snap_box, false, false);
-       // hbox->pack_start (zoom_box, false, false); 
        hbox->pack_start (*nudge_box, false, false);
+       hbox->pack_start (panic_box, false, false);
 
        hbox->show_all ();
-       
+
        toolbar_base.set_name ("ToolBarBase");
        toolbar_base.add (toolbar_hbox);
 
@@ -3009,8 +2953,10 @@ Editor::setup_toolbar ()
 }
 
 void
-Editor::midi_panic_button_pressed ()
+Editor::midi_panic ()
 {
+       cerr << "MIDI panic\n";
+
        if (session) {
                session->midi_panic();
        }
@@ -3019,122 +2965,35 @@ Editor::midi_panic_button_pressed ()
 void
 Editor::setup_midi_toolbar ()
 {
-       string pixmap_path;
-
-       /* Mode Buttons (tool selection) */
-
-       vector<ToggleButton *> midi_tool_buttons;
-
-       midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
-       midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
-       midi_tool_buttons.push_back (&midi_tool_pencil_button);
-       midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
-       midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
-       midi_tool_buttons.push_back (&midi_tool_select_button);
-       midi_tool_resize_button.add (*(manage (new Image (::get_icon("strip_width")))));
-       midi_tool_resize_button.set_relief(Gtk::RELIEF_NONE);
-       midi_tool_buttons.push_back (&midi_tool_resize_button);
-       midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
-       midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
-       midi_tool_buttons.push_back (&midi_tool_erase_button);
-
-       midi_tool_pencil_button.set_active(true);
-       
-       midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
-
-       midi_tool_button_box.set_border_width (2);
-       midi_tool_button_box.set_spacing(1);
-       midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
-       midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
-       midi_tool_button_box.pack_start(midi_tool_resize_button, true, true);
-       midi_tool_button_box.pack_start(midi_tool_erase_button , true, true);
-       midi_tool_button_box.set_homogeneous(true);
-
-       midi_tool_pencil_button.set_name ("MouseModeButton");
-       midi_tool_select_button.set_name ("MouseModeButton");
-       midi_tool_resize_button.set_name ("MouseModeButton");
-       midi_tool_erase_button .set_name ("MouseModeButton");
-
-       ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
-       ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
-       ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_resize_button, _("Resize Notes"));
-       ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button,  _("Erase Notes"));
-
-       midi_tool_pencil_button.unset_flags (CAN_FOCUS);
-       midi_tool_select_button.unset_flags (CAN_FOCUS);
-       midi_tool_resize_button.unset_flags (CAN_FOCUS);
-       midi_tool_erase_button.unset_flags (CAN_FOCUS);
-       
-       midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
-                               &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
-       midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
-                               &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
-       midi_tool_resize_button.signal_toggled().connect (bind (mem_fun(*this,
-                               &Editor::midi_edit_mode_toggled), Editing::MidiEditResize));
-       midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
-                               &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
+       RefPtr<Action> act;
 
-       
        /* Midi sound notes */
        midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
        midi_sound_notes.set_relief(Gtk::RELIEF_NONE);
        ARDOUR_UI::instance()->tooltips().set_tip (midi_sound_notes, _("Sound Notes"));
        midi_sound_notes.unset_flags (CAN_FOCUS);
-       
-       /* Panic */
-       
-       HBox* panic_box = manage (new HBox);
-       midi_panic_button.set_name("MidiPanicButton");
-       midi_panic_button.signal_pressed().connect (
-                       mem_fun(this, &Editor::midi_panic_button_pressed));
-       panic_box->pack_start (midi_sound_notes , true, true);
-       panic_box->pack_start (midi_panic_button, true, true);
-       
-       /* Pack everything in... */
-
-       midi_tools_tearoff = manage (new TearOff (midi_tool_button_box));
-       midi_tools_tearoff->set_name ("MouseModeBase");
-
-       /*
-       midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox), 
-                                            &midi_tools_tearoff->tearoff_window()));
-       midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox), 
-                                            &midi_tools_tearoff->tearoff_window(), 0));
-       midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox), 
-                                            &midi_tools_tearoff->tearoff_window()));
-       midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox), 
-                                             &midi_tools_tearoff->tearoff_window(), 0));
-       */
-
-       midi_toolbar_hbox.set_spacing (10);
-       midi_toolbar_hbox.set_border_width (1);
 
-       midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
-       
-       midi_toolbar_hbox.pack_start(*panic_box, false, true, 4);
+       /* Panic */
 
-       midi_tool_button_box.show_all ();
-       midi_toolbar_hbox.show_all();
-       midi_tools_tearoff->show_all();
-       
-       midi_toolbar_base.set_name ("ToolBarBase");
-       midi_toolbar_base.add (midi_toolbar_hbox);
+       act = ActionManager::get_action (X_("MIDI"), X_("panic"));
+       midi_panic_button.set_name("MidiPanicButton");
+       ARDOUR_UI::instance()->tooltips().set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
+       act->connect_proxy (midi_panic_button);
 
-       midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
-       midi_toolbar_frame.set_name ("BaseFrame");
-       midi_toolbar_frame.add (midi_toolbar_base);
+       panic_box.pack_start (midi_sound_notes , true, true);
+       panic_box.pack_start (midi_panic_button, true, true);
 }
 
 int
 Editor::convert_drop_to_paths (
-               vector<ustring>&                paths, 
-               const RefPtr<Gdk::DragContext>& context,
-               gint                            x,
-               gint                            y,
+               vector<ustring>&                paths,
+               const RefPtr<Gdk::DragContext>& /*context*/,
+               gint                            /*x*/,
+               gint                            /*y*/,
                const SelectionData&            data,
-               guint                           info,
-               guint                           time)
-{      
+               guint                           /*info*/,
+               guint                           /*time*/)
+{
        if (session == 0) {
                return -1;
        }
@@ -3150,8 +3009,8 @@ Editor::convert_drop_to_paths (
                if (data.get_target() != "text/plain") {
                        return -1;
                }
-  
-               /* Parse the "uri-list" format that Nautilus provides, 
+
+               /* Parse the "uri-list" format that Nautilus provides,
                   where each pathname is delimited by \r\n.
 
                   THERE MAY BE NO NULL TERMINATING CHAR!!!
@@ -3171,18 +3030,18 @@ Editor::convert_drop_to_paths (
                        {
                                while (g_ascii_isspace (*p))
                                        p++;
-                               
+
                                q = p;
                                while (*q && (*q != '\n') && (*q != '\r')) {
                                        q++;
                                }
-                               
+
                                if (q > p)
                                {
                                        q--;
                                        while (q > p && g_ascii_isspace (*q))
                                                q--;
-                                       
+
                                        if (q > p)
                                        {
                                                uris.push_back (ustring (p, q - p + 1));
@@ -3195,21 +3054,21 @@ Editor::convert_drop_to_paths (
                }
 
                free ((void*)p);
-               
+
                if (uris.empty()) {
                        return -1;
                }
        }
-       
+
        for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
 
                if ((*i).substr (0,7) == "file://") {
-                       
+
                        ustring p = *i;
                        PBD::url_decode (p);
 
                        // scan forward past three slashes
-                       
+
                        ustring::size_type slashcnt = 0;
                        ustring::size_type n = 0;
                        ustring::iterator x = p.begin();
@@ -3326,7 +3185,7 @@ Editor::set_route_group_mute (Route& route, bool yn)
                route.set_mute (yn, this);
        }
 }
-               
+
 void
 Editor::history_changed ()
 {
@@ -3364,7 +3223,7 @@ Editor::duplicate_dialog (bool with_dialog)
 
        RegionSelection rs;
        get_regions_for_action (rs);
-       
+
        if (mouse_mode != MouseRange) {
 
                if (rs.empty()) {
@@ -3374,21 +3233,21 @@ Editor::duplicate_dialog (bool with_dialog)
 
        if (with_dialog) {
 
-               ArdourDialog win ("Duplication Dialog");
+               ArdourDialog win ("Duplicate");
                Label  label (_("Number of Duplications:"));
                Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
                SpinButton spinner (adjustment, 0.0, 1);
                HBox hbox;
-               
+
                win.get_vbox()->set_spacing (12);
                win.get_vbox()->pack_start (hbox);
                hbox.set_border_width (6);
                hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
-               
+
                /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
                   place, visually. so do this by hand.
                */
-               
+
                hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
                spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
                spinner.grab_focus();
@@ -3396,22 +3255,22 @@ Editor::duplicate_dialog (bool with_dialog)
                hbox.show ();
                label.show ();
                spinner.show ();
-               
+
                win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
                win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
                win.set_default_response (RESPONSE_ACCEPT);
-               
+
                win.set_position (WIN_POS_MOUSE);
-               
+
                spinner.grab_focus ();
-               
+
                switch (win.run ()) {
                case RESPONSE_ACCEPT:
                        break;
                default:
                        return;
                }
-               
+
                times = adjustment.get_value();
        }
 
@@ -3459,6 +3318,31 @@ Editor::clamp_verbose_cursor_y (double y)
        return y;
 }
 
+void
+Editor::show_verbose_canvas_cursor_with (const string & txt)
+{
+       verbose_canvas_cursor->property_text() = txt.c_str();
+
+       int x, y;
+       double wx, wy;
+
+       track_canvas->get_pointer (x, y);
+       track_canvas->window_to_world (x, y, wx, wy);
+
+       /* move it away from the mouse pointer to avoid an
+          infinite loop of enter/leave events.
+       */
+
+       wx += 20;
+       wy += 20;
+
+       /* don't get too close to the edge */
+       verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx);
+       verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy);
+
+       show_verbose_canvas_cursor ();
+}
+
 void
 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
 {
@@ -3519,7 +3403,7 @@ Editor::edit_mode_selection_done ()
        }
 
        Config->set_edit_mode (mode);
-}      
+}
 
 void
 Editor::snap_type_selection_done ()
@@ -3553,12 +3437,12 @@ Editor::snap_type_selection_done ()
                snaptype = SnapToRegionSync;
        } else if (choice == _("CD Frames")) {
                snaptype = SnapToCDFrame;
-       } else if (choice == _("SMPTE Frames")) {
-               snaptype = SnapToSMPTEFrame;
-       } else if (choice == _("SMPTE Seconds")) {
-               snaptype = SnapToSMPTESeconds;
-       } else if (choice == _("SMPTE Minutes")) {
-               snaptype = SnapToSMPTEMinutes;
+       } else if (choice == _("Timecode Frames")) {
+               snaptype = SnapToTimecodeFrame;
+       } else if (choice == _("Timecode Seconds")) {
+               snaptype = SnapToTimecodeSeconds;
+       } else if (choice == _("Timecode Minutes")) {
+               snaptype = SnapToTimecodeMinutes;
        } else if (choice == _("Seconds")) {
                snaptype = SnapToSeconds;
        } else if (choice == _("Minutes")) {
@@ -3569,7 +3453,7 @@ Editor::snap_type_selection_done ()
        if (ract) {
                ract->set_active ();
        }
-}      
+}
 
 void
 Editor::snap_mode_selection_done ()
@@ -3655,14 +3539,14 @@ Editor::zoom_focus_selection_done ()
                focus_type = ZoomFocusEdit;
        } else {
                focus_type = ZoomFocusMouse;
-       } 
-       
+       }
+
        RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
 
        if (ract) {
                ract->set_active ();
        }
-}      
+}
 
 gint
 Editor::edit_controls_button_release (GdkEventButton* ev)
@@ -3686,7 +3570,7 @@ Editor::mouse_select_button_release (GdkEventButton* ev)
 }
 
 Editor::TrackViewList *
-Editor::get_valid_views (TimeAxisViewPtr track, RouteGroup* group)
+Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
 {
        TrackViewList::iterator i;
 
@@ -3701,16 +3585,16 @@ Editor::get_valid_views (TimeAxisViewPtr track, RouteGroup* group)
                }
 
        } else if ((track != 0 && group == 0) || (track != 0 && group != 0 && !group->active_property (RouteGroup::Select))) {
-               
+
                /* just the view for this track
                 */
 
                v->push_back (track);
 
        } else {
-               
+
                /* views for all tracks in the route group */
-               
+
                for (i = track_views.begin(); i != track_views.end (); ++i) {
 
                        if (group == 0 || ((*i)->route_group() == group && group->active_property (RouteGroup::Select))) {
@@ -3718,7 +3602,7 @@ Editor::get_valid_views (TimeAxisViewPtr track, RouteGroup* group)
                        }
                }
        }
-       
+
        return v;
 }
 
@@ -3730,7 +3614,7 @@ Editor::set_zoom_focus (ZoomFocus f)
        if (str != zoom_focus_selector.get_active_text()) {
                zoom_focus_selector.set_active_text (str);
        }
-       
+
        if (zoom_focus != f) {
                zoom_focus = f;
 
@@ -3746,7 +3630,7 @@ Editor::ensure_float (Window& win)
        win.set_transient_for (*this);
 }
 
-void 
+void
 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
 {
        /* recover or initialize pane positions. do this here rather than earlier because
@@ -3802,17 +3686,20 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
 }
 
 void
-Editor::detach_tearoff (Box* b, Window* w)
+Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
 {
-       if (tools_tearoff->torn_off() && 
+       cerr << "remove tearoff\n";
+
+       if (tools_tearoff->torn_off() &&
            mouse_mode_tearoff->torn_off()) {
                top_hbox.remove (toolbar_frame);
        }
 }
 
 void
-Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
+Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
 {
+       cerr << "reattach tearoff\n";
        if (toolbar_frame.get_parent() == 0) {
                top_hbox.pack_end (toolbar_frame);
        }
@@ -3883,16 +3770,16 @@ Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
        }
 
        CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
-               
+
        ensure_float (cew);
-       
+
        switch (cew.run ()) {
        case RESPONSE_ACCEPT:
                break;
        default:
                return;
        }
-       
+
        cew.apply ();
        xfade->StateChanged (Change (~0));
 }
@@ -3903,6 +3790,60 @@ Editor::playlist_selector () const
        return *_playlist_selector;
 }
 
+Evoral::MusicalTime
+Editor::get_grid_type_as_beats (bool& success, nframes64_t position)
+{
+       success = true;
+
+       switch (_snap_type) {
+       case SnapToBeat:
+               return 1.0;
+               break;
+
+       case SnapToAThirtysecondBeat:
+               return 1.0/32.0;
+               break;
+
+       case SnapToASixteenthBeat:
+               return 1.0/16.0;
+               break;
+
+       case SnapToAEighthBeat:
+               return 1.0/8.0;
+               break;
+
+       case SnapToAQuarterBeat:
+               return 1.0/4.0;
+               break;
+
+       case SnapToAThirdBeat:
+               return 1.0/3.0;
+               break;
+
+       case SnapToBar:
+               if (session) {
+                       return session->tempo_map().meter_at (position).beats_per_bar();
+               }
+               break;
+
+       case SnapToCDFrame:
+       case SnapToTimecodeFrame:
+       case SnapToTimecodeSeconds:
+       case SnapToTimecodeMinutes:
+       case SnapToSeconds:
+       case SnapToMinutes:
+       case SnapToRegionStart:
+       case SnapToRegionEnd:
+       case SnapToRegionSync:
+       case SnapToRegionBoundary:
+       default:
+               success = false;
+               break;
+       }
+
+       return 0.0;
+}
+
 nframes64_t
 Editor::get_nudge_distance (nframes64_t pos, nframes64_t& next)
 {
@@ -3931,7 +3872,7 @@ Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
                                        "If left alone, no audio files used by it will be cleaned.\n"
                                        "If deleted, audio files used by it alone by will cleaned."),
                                      pl->name()));
-       
+
        dialog.set_position (WIN_POS_CENTER);
        dialog.get_vbox()->pack_start (label);
 
@@ -4021,7 +3962,7 @@ Editor::control_layout_scroll (GdkEventScroll* ev)
        case GDK_SCROLL_DOWN:
                scroll_tracks_down_line ();
                return true;
-               
+
        default:
                /* no left/right handling yet */
                break;
@@ -4034,7 +3975,7 @@ void
 Editor::session_state_saved (string snap_name)
 {
        ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
-       
+
        _snapshots->redisplay ();
 }
 
@@ -4054,7 +3995,7 @@ Editor::maximise_editing_space ()
        fullscreen();
 
        if(post_maximal_editor_width) {
-               edit_pane.set_position (post_maximal_pane_position - 
+               edit_pane.set_position (post_maximal_pane_position -
                        abs(post_maximal_editor_width - pre_maximal_editor_width));
        } else {
                edit_pane.set_position (post_maximal_pane_position);
@@ -4085,14 +4026,9 @@ Editor::restore_editing_space ()
  *  @param v Track.
  */
 
-void 
-Editor::new_playlists (boost::weak_ptr<TimeAxisView> w)
+void
+Editor::new_playlists (TimeAxisView* v)
 {
-       TimeAxisViewPtr v = w.lock ();
-       if (!v) {
-               return;
-       }
-       
        begin_reversible_command (_("new playlists"));
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
        session->get_playlists(playlists);
@@ -4107,13 +4043,8 @@ Editor::new_playlists (boost::weak_ptr<TimeAxisView> w)
  */
 
 void
-Editor::copy_playlists (boost::weak_ptr<TimeAxisView> w)
+Editor::copy_playlists (TimeAxisView* v)
 {
-       TimeAxisViewPtr v = w.lock ();
-       if (!v) {
-               return;
-       }
-       
        begin_reversible_command (_("copy playlists"));
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
        session->get_playlists(playlists);
@@ -4126,14 +4057,9 @@ Editor::copy_playlists (boost::weak_ptr<TimeAxisView> w)
  *  @param v Track.
  */
 
-void 
-Editor::clear_playlists (boost::weak_ptr<TimeAxisView> w)
+void
+Editor::clear_playlists (TimeAxisView* v)
 {
-       TimeAxisViewPtr v = w.lock ();
-       if (!v) {
-               return;
-       }
-       
        begin_reversible_command (_("clear playlists"));
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
        session->get_playlists(playlists);
@@ -4141,22 +4067,22 @@ Editor::clear_playlists (boost::weak_ptr<TimeAxisView> w)
        commit_reversible_command ();
 }
 
-void 
-Editor::mapped_use_new_playlist (RouteTimeAxisViewPtr atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
+void
+Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
 {
-       atv->use_new_playlist (sz > 1 ? false : true, playlists);
+       atv.use_new_playlist (sz > 1 ? false : true, playlists);
 }
 
 void
-Editor::mapped_use_copy_playlist (RouteTimeAxisViewPtr atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
+Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
 {
-       atv->use_copy_playlist (sz > 1 ? false : true, playlists);
+       atv.use_copy_playlist (sz > 1 ? false : true, playlists);
 }
 
-void 
-Editor::mapped_clear_playlist (RouteTimeAxisViewPtr atv, uint32_t sz)
+void
+Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
 {
-       atv->clear_playlist ();
+       atv.clear_playlist ();
 }
 
 bool
@@ -4211,14 +4137,13 @@ Editor::current_visual_state (bool with_tracks)
        vs->frames_per_unit = frames_per_unit;
        vs->leftmost_frame = leftmost_frame;
        vs->zoom_focus = zoom_focus;
-       vs->zoomed_to_region = zoomed_to_region;
 
        if (with_tracks) {
                for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                        vs->track_states.push_back (TAVState ((*i), &(*i)->get_state()));
                }
        }
-       
+
        return vs;
 }
 
@@ -4269,22 +4194,21 @@ Editor::use_visual_state (VisualState& vs)
 
        set_zoom_focus (vs.zoom_focus);
        reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
-       zoomed_to_region = vs.zoomed_to_region;
-       
+
        for (list<TAVState>::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) {
                TrackViewList::iterator t;
 
                /* check if the track still exists - it could have been deleted */
 
                if ((t = find (track_views.begin(), track_views.end(), i->first)) != track_views.end()) {
-                       (*t)->set_state (*(i->second));
+                       (*t)->set_state (*(i->second), Stateful::loading_state_version);
                }
        }
 
 
        if (!vs.track_states.empty()) {
                _routes->update_visibility ();
-       } 
+       }
 
        _routes->resume_redisplay ();
 
@@ -4306,7 +4230,7 @@ Editor::set_frames_per_unit (double fpu)
                fpu = 2.0;
        }
 
-       
+
        /* don't allow zooms that fit more than the maximum number
           of frames into an 800 pixel wide space.
        */
@@ -4314,7 +4238,7 @@ Editor::set_frames_per_unit (double fpu)
        if (max_frames / fpu < 800.0) {
                return;
        }
-       
+
        if (tempo_lines)
                tempo_lines->tempo_map_changed();
 
@@ -4374,17 +4298,17 @@ void
 Editor::queue_visual_change (nframes64_t where)
 {
        pending_visual_change.add (VisualChange::TimeOrigin);
-       
+
        /* if we're moving beyond the end, make sure the upper limit of the horizontal adjustment
           can reach.
        */
-       
+
        if (where > session->current_end_frame()) {
                horizontal_adjustment.set_upper ((where + current_page_frames()) / frames_per_unit);
        }
-       
+
        pending_visual_change.time_origin = where;
-       
+
        ensure_visual_change_idle_handler ();
 }
 
@@ -4395,7 +4319,7 @@ Editor::queue_visual_change (double fpu)
        pending_visual_change.frames_per_unit = fpu;
 
        ensure_visual_change_idle_handler ();
-       
+
 }
 
 void
@@ -4445,15 +4369,15 @@ Editor::idle_visual_changer ()
        if (p & VisualChange::YOrigin) {
                vertical_adjustment.set_value (pending_visual_change.y_origin);
        }
-       
+
        nframes64_t csf=0, cef=0;
        nframes64_t current_time_origin = (nframes64_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
-       
+
        if (session) {
                csf = session->current_start_frame();
                cef = session->current_end_frame();
        }
-       
+
        /* if we seek beyond the current end of the canvas, move the end */
 
 #ifdef FIX_THIS_FOR_V3
@@ -4463,7 +4387,7 @@ Editor::idle_visual_changer ()
                redisplay_tempo (true);
        }
 #endif
-       
+
        if (current_time_origin != pending_visual_change.time_origin) {
                cef += current_page_frames() / 10; // Add a little extra so we can see the end marker
                horizontal_adjustment.set_upper (cef / frames_per_unit);
@@ -4474,18 +4398,18 @@ Editor::idle_visual_changer ()
        }
 
        _summary->set_overlays_dirty ();
-       
+
        //cerr << "Editor::idle_visual_changer () called ha v:l:u:ps:fpu = " << horizontal_adjustment.get_value() << ":" << horizontal_adjustment.get_lower() << ":" << horizontal_adjustment.get_upper() << ":" << horizontal_adjustment.get_page_size() << ":" << frames_per_unit << endl;//DEBUG
        pending_visual_change.idle_handler_id = -1;
        return 0; /* this is always a one-shot call */
 }
 
 struct EditorOrderTimeAxisSorter {
-    bool operator() (const TimeAxisViewPtr a, const TimeAxisViewPtr b) const {
+    bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
            return a->order () < b->order ();
     }
 };
-       
+
 void
 Editor::sort_track_selection (TrackSelection* sel)
 {
@@ -4517,7 +4441,7 @@ Editor::get_preferred_edit_position (bool ignore_playhead)
        case EditAtPlayhead:
                where = session->audible_frame();
                break;
-               
+
        case EditAtSelectedMarker:
                if (!selection->markers.empty()) {
                        bool is_start;
@@ -4530,9 +4454,9 @@ Editor::get_preferred_edit_position (bool ignore_playhead)
                                }
                                break;
                        }
-               } 
+               }
                /* fallthru */
-               
+
        default:
        case EditAtMouse:
                if (!mouse_frame (where, ignored)) {
@@ -4552,7 +4476,7 @@ Editor::set_loop_range (nframes64_t start, nframes64_t end, string cmd)
        if (!session) return;
 
        begin_reversible_command (cmd);
-       
+
        Location* tll;
 
        if ((tll = transport_loop_location()) == 0) {
@@ -4569,7 +4493,7 @@ Editor::set_loop_range (nframes64_t start, nframes64_t end, string cmd)
                XMLNode &after = tll->get_state();
                session->add_command (new MementoCommand<Location>(*tll, &before, &after));
        }
-       
+
        commit_reversible_command ();
 }
 
@@ -4579,7 +4503,7 @@ Editor::set_punch_range (nframes64_t start, nframes64_t end, string cmd)
        if (!session) return;
 
        begin_reversible_command (cmd);
-       
+
        Location* tpl;
 
        if ((tpl = transport_punch_location()) == 0) {
@@ -4597,10 +4521,15 @@ Editor::set_punch_range (nframes64_t start, nframes64_t end, string cmd)
                XMLNode &after = tpl->get_state();
                session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
        }
-       
+
        commit_reversible_command ();
 }
 
+/** Find regions which exist at a given time, and optionally on a given list of tracks.
+ *  @param rs List to which found regions are added.
+ *  @param where Time to look at.
+ *  @param ts Tracks to look on; if this is empty, all tracks are examined.
+ */
 void
 Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackSelection& ts) const
 {
@@ -4613,11 +4542,11 @@ Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackSelec
        }
 
        for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
-               RouteTimeAxisViewPtr rtv = boost::dynamic_pointer_cast<RouteTimeAxisView>(*t);
+               RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
                if (rtv) {
                        boost::shared_ptr<Diskstream> ds;
                        boost::shared_ptr<Playlist> pl;
-                       
+
                        if ((ds = rtv->get_diskstream()) && ((pl = ds->playlist()))) {
 
                                Playlist::RegionList* regions = pl->regions_at (
@@ -4648,11 +4577,11 @@ Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackSe
        }
 
        for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
-               RouteTimeAxisViewPtr rtv = boost::dynamic_pointer_cast<RouteTimeAxisView>(*t);
+               RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
                if (rtv) {
                        boost::shared_ptr<Diskstream> ds;
                        boost::shared_ptr<Playlist> pl;
-                       
+
                        if ((ds = rtv->get_diskstream()) && ((pl = ds->playlist()))) {
 
                                Playlist::RegionList* regions = pl->regions_touched (
@@ -4673,26 +4602,41 @@ Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackSe
        }
 }
 
+/** Find all regions which are either:
+ *      - selected or
+ *      - the entered_regionview (if allow_entered == true) or
+ *      - under the preferred edit position AND on a selected track, or on a track
+ *        which is in the same active edit-enable route group as a selected region (if allow_edit_position == true)
+ *  @param rs Returned region list.
+ *  @param allow_entered true to include the entered_regionview in the list.
+ */
 void
-Editor::get_regions_for_action (RegionSelection& rs, bool allow_entered)
+Editor::get_regions_for_action (RegionSelection& rs, bool allow_entered, bool allow_edit_position)
 {
+       /* Start with selected regions */
        rs = selection->regions;
 
+       /* Add the entered_regionview, if requested */
        if (allow_entered && entered_regionview) {
                rs.add (entered_regionview);
        }
 
-       TrackSelection tracks = selection->tracks;
+       if (allow_edit_position) {
 
-       RegionSelection to_map = rs;
+               TrackSelection tracks = selection->tracks;
 
-       for (RegionSelection::iterator i = to_map.begin (); i != to_map.end(); ++i) {
+               /* tracks is currently the set of selected tracks; add any other tracks that
+                * have regions that are in the same edit-activated route group as one of
+                * our regions */
+               for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
 
-               RouteGroup* g = (*i)->get_time_axis_view()->route_group ();
-               if (g && g->active_property (RouteGroup::Edit)) {
-                       tracks.add (axis_views_from_routes (g->route_list()));
+                       RouteGroup* g = (*i)->get_time_axis_view().route_group ();
+                       if (g && g->active_property (RouteGroup::Edit)) {
+                               tracks.add (axis_views_from_routes (g->route_list()));
+                       }
                }
 
+               /* now find regions that are at the edit position on those tracks */
                nframes64_t const where = get_preferred_edit_position ();
                get_regions_at (rs, where, tracks);
        }
@@ -4701,36 +4645,35 @@ Editor::get_regions_for_action (RegionSelection& rs, bool allow_entered)
 void
 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
 {
-
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-               
-               RouteTimeAxisViewPtr tatv;
-               
-               if ((tatv = boost::dynamic_pointer_cast<RouteTimeAxisView> (*i)) != 0) {
-                       
+
+               RouteTimeAxisView* tatv;
+
+               if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
+
                        boost::shared_ptr<Playlist> pl;
                        vector<boost::shared_ptr<Region> > results;
                        RegionView* marv;
                        boost::shared_ptr<Diskstream> ds;
-                       
+
                        if ((ds = tatv->get_diskstream()) == 0) {
                                /* bus */
                                continue;
                        }
-                       
+
                        if ((pl = (ds->playlist())) != 0) {
                                pl->get_region_list_equivalent_regions (region, results);
                        }
-                       
+
                        for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
                                if ((marv = tatv->view()->find_view (*ir)) != 0) {
                                        regions.push_back (marv);
                                }
                        }
-                       
+
                }
        }
-}      
+}
 
 void
 Editor::show_rhythm_ferret ()
@@ -4769,8 +4712,8 @@ Editor::first_idle ()
 {
        MessageDialog* dialog = 0;
 
-       if (track_views.size() > 1) { 
-               dialog = new MessageDialog (*this, 
+       if (track_views.size() > 1) {
+               dialog = new MessageDialog (*this,
                                            _("Please wait while Ardour loads visual data"),
                                            true,
                                            Gtk::MESSAGE_INFO,
@@ -4785,7 +4728,7 @@ Editor::first_idle ()
 
        // first idle adds route children (automation tracks), so we need to redisplay here
        _routes->redisplay ();
-       
+
        delete dialog;
 
        _have_idled = true;
@@ -4798,7 +4741,7 @@ _idle_resizer (gpointer arg)
 }
 
 void
-Editor::add_to_idle_resize (TimeAxisViewPtr view, int32_t h)
+Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
 {
        if (resize_idle_id < 0) {
                resize_idle_id = g_idle_add (_idle_resizer, this);
@@ -4837,20 +4780,20 @@ Editor::idle_resize ()
 {
        _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
 
-       if (boost::dynamic_pointer_cast<AutomationTimeAxisView> (_pending_resize_view) == 0 &&
+       if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
            selection->tracks.contains (_pending_resize_view)) {
-               
+
                for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
                        if (*i != _pending_resize_view) {
                                (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
                        }
                }
        }
-       
+
        flush_canvas ();
        _group_tabs->set_dirty ();
        resize_idle_id = -1;
-       
+
        return false;
 }
 
@@ -4874,19 +4817,31 @@ Editor::streamview_height_changed ()
        _summary->set_dirty ();
 }
 
+TimeAxisView*
+Editor::axis_view_from_route (Route* r) const
+{
+       TrackViewList::const_iterator j = track_views.begin ();
+       while (j != track_views.end()) {
+               RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
+               if (rtv && rtv->route().get() == r) {
+                       return rtv;
+               }
+               ++j;
+       }
+
+       return 0;
+}
+
+
 TrackSelection
 Editor::axis_views_from_routes (list<Route*> r) const
 {
        TrackSelection t;
-       
+
        for (list<Route*>::const_iterator i = r.begin(); i != r.end(); ++i) {
-               TrackViewList::const_iterator j = track_views.begin ();
-               while (j != track_views.end()) {
-                       RouteTimeAxisViewPtr rtv = boost::dynamic_pointer_cast<RouteTimeAxisView> (*j);
-                       if (rtv && rtv->route().get() == *i) {
-                               t.push_back (rtv);
-                       }
-                       ++j;
+               TimeAxisView* tv = axis_view_from_route (*i);
+               if (tv) {
+                       t.push_back (tv);
                }
        }
 
@@ -4898,9 +4853,9 @@ void
 Editor::handle_new_route (RouteList& routes)
 {
        ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::handle_new_route), routes));
-       
-       RouteTimeAxisViewPtr rtv;
-       list<RouteTimeAxisViewPtr> new_views;
+
+       RouteTimeAxisView *rtv;
+       list<RouteTimeAxisView*> new_views;
 
        for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
                boost::shared_ptr<Route> route = (*x);
@@ -4912,21 +4867,21 @@ Editor::handle_new_route (RouteList& routes)
                DataType dt = route->input()->default_type();
 
                if (dt == ARDOUR::DataType::AUDIO) {
-                       rtv = AudioTimeAxisView::create (*this, *session, route, *track_canvas);
+                       rtv = new AudioTimeAxisView (*this, *session, route, *track_canvas);
                } else if (dt == ARDOUR::DataType::MIDI) {
-                       rtv = MidiTimeAxisView::create (*this, *session, route, *track_canvas);
+                       rtv = new MidiTimeAxisView (*this, *session, route, *track_canvas);
                } else {
                        throw unknown_type();
                }
 
                new_views.push_back (rtv);
                track_views.push_back (rtv);
-               
+
                rtv->effective_gain_display ();
-               
+
                rtv->view()->RegionViewAdded.connect (mem_fun (*this, &Editor::region_view_added));
                rtv->view()->HeightChanged.connect (mem_fun (*this, &Editor::streamview_height_changed));
-               
+
                rtv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), rtv));
        }
 
@@ -4942,16 +4897,22 @@ Editor::handle_new_route (RouteList& routes)
 }
 
 void
-Editor::remove_route (TimeAxisViewPtr tv)
+Editor::remove_route (TimeAxisView *tv)
 {
-       ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::remove_route), tv));
+       ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route), tv));
 
        TrackViewList::iterator i;
+
        boost::shared_ptr<Route> route;
-       TimeAxisViewPtr next_tv;
+       RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
+       if (rtav) {
+               route = rtav->route ();
+       }
+               
+       TimeAxisView* next_tv = 0;
 
        if (tv == entered_track) {
-               entered_track.reset ();
+               entered_track = 0;
        }
 
        if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
@@ -4959,18 +4920,18 @@ Editor::remove_route (TimeAxisViewPtr tv)
                i = track_views.erase (i);
 
                if (track_views.empty()) {
-                       next_tv.reset ();
+                       next_tv = 0;
                } else if (i == track_views.end()) {
                        next_tv = track_views.front();
                } else {
                       next_tv = (*i);
                }
        }
-       
+
        if (current_mixer_strip && current_mixer_strip->route() == route) {
 
                if (next_tv) {
-                       set_selected_mixer_strip (next_tv);
+                       set_selected_mixer_strip (*next_tv);
                } else {
                        /* make the editor mixer strip go away setting the
                         * button to inactive (which also unticks the menu option)
@@ -4978,13 +4939,13 @@ Editor::remove_route (TimeAxisViewPtr tv)
 
                        ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
                }
-       } 
+       }
 }
 
 void
-Editor::hide_track_in_display (TimeAxisViewPtr tv, bool temponly)
+Editor::hide_track_in_display (TimeAxisView& tv, bool /*temponly*/)
 {
-       RouteTimeAxisViewPtr rtv = boost::dynamic_pointer_cast<RouteTimeAxisView> (tv);
+       RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
 
        if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
                // this will hide the mixer strip
@@ -4998,35 +4959,35 @@ bool
 Editor::sync_track_view_list_and_routes ()
 {
        track_views = TrackSelection (_routes->views ());
-       
+
        _summary->set_dirty ();
        _group_tabs->set_dirty ();
-       
+
        return false; // do not call again (until needed)
 }
 
 void
-Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisViewPtr> theslot)
+Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
 {
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-               theslot (*i);
+               theslot (**i);
        }
 }
 
-RouteTimeAxisViewPtr
+RouteTimeAxisView*
 Editor::get_route_view_by_id (PBD::ID& id)
 {
-       RouteTimeAxisViewPtr v;
+       RouteTimeAxisView* v;
 
        for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-               if((v = boost::dynamic_pointer_cast<RouteTimeAxisView>(*i)) != 0) {
+               if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
                        if(v->route()->id() == id) {
                                return v;
                        }
                }
        }
 
-       return RouteTimeAxisViewPtr ();
+       return 0;
 }
 
 void
@@ -5082,22 +5043,27 @@ Editor::hide_region_from_region_list ()
        _regions->selection_mapover (mem_fun (*this, &Editor::hide_a_region));
 }
 
-TimeAxisViewPtr
-Editor::find_time_axis (TimeAxisView* v)
+void
+Editor::start_step_editing ()
 {
-       TrackViewList::iterator i = track_views.begin ();
-       while (i != track_views.end()) {
-               if (i->get() == v) {
-                       return *i;
-               }
+       step_edit_connection = Glib::signal_timeout().connect (mem_fun (*this, &Editor::check_step_edit), 20);
+}
 
-               TimeAxisViewPtr p = (*i)->find_time_axis (v);
-               if (p) {
-                       return p;
-               }
+void
+Editor::stop_step_editing ()
+{
+       step_edit_connection.disconnect ();
+}
 
-               ++i;
+bool
+Editor::check_step_edit ()
+{
+       for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+               MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
+               if (mtv) {
+                       mtv->check_step_edit ();
+               }
        }
 
-       return TimeAxisViewPtr ();
+       return true; // do it again, till we stop
 }