Trim session.h include dependency tree.
[ardour.git] / gtk2_ardour / editor.cc
index 16f0f0ae536eacaf1ceb116a33d4dc8c85b89b37..60d6c9a3a4c18ffc10db70eb30169e81d359cda0 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
@@ -129,9 +129,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 +211,47 @@ 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")),
+       , 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)
 
-         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;
@@ -279,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);
@@ -287,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;
@@ -328,8 +325,6 @@ 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;
@@ -343,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) {
@@ -363,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));
@@ -386,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);
@@ -456,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));
@@ -475,11 +469,9 @@ 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));
@@ -490,7 +482,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));
 
@@ -498,7 +490,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.
        */
 
@@ -542,7 +534,7 @@ Editor::Editor ()
        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);
@@ -563,7 +555,7 @@ 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);
@@ -585,11 +577,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);
@@ -608,17 +599,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)));
@@ -695,7 +690,7 @@ Editor::~Editor()
                {
                        image_socket_listener->close_connection() ;
                }
-               
+
                delete image_socket_listener ;
                image_socket_listener = 0 ;
        }
@@ -783,7 +778,7 @@ Editor::show_window ()
                */
 
                TimeAxisView *tv;
-       
+
                for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                        tv = (static_cast<TimeAxisView*>(*i));
                        tv->reset_height ();
@@ -844,7 +839,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);
 }
 
@@ -861,7 +856,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
@@ -887,7 +882,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));
@@ -911,7 +906,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
@@ -935,7 +930,7 @@ Editor::access_action (std::string action_group, std::string action_item)
        if (act) {
                act->activate();
        }
-               
+
 
 }
 
@@ -949,7 +944,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));
 
 }
@@ -971,7 +966,7 @@ Editor::map_position_change (nframes64_t frame)
 
        center_screen (frame);
        playhead_cursor->set_position (frame);
-}      
+}
 
 void
 Editor::center_screen (nframes64_t frame)
@@ -980,7 +975,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);
        }
@@ -990,7 +985,7 @@ void
 Editor::center_screen_internal (nframes64_t frame, float page)
 {
        page /= 2;
-               
+
        if (frame > page) {
                frame -= (nframes64_t) page;
        } else {
@@ -1023,7 +1018,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 ();
 }
 
@@ -1065,7 +1060,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 */
 
@@ -1091,7 +1086,7 @@ Editor::connect_to_session (Session *t)
        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)));
 
@@ -1111,9 +1106,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 ();
@@ -1137,7 +1132,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));
@@ -1153,9 +1148,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));
@@ -1175,15 +1170,13 @@ Editor::connect_to_session (Session *t)
        //tempo_map_changed (Change (0));
        session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
 
-       _routes->initial_display ();
-
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                (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:
@@ -1203,7 +1196,8 @@ Editor::connect_to_session (Session *t)
        _route_groups->connect_to_session (session);
        _regions->connect_to_session (session);
        _snapshots->connect_to_session (session);
-       
+       _routes->connect_to_session (session);
+
        start_updating ();
 }
 
@@ -1211,7 +1205,7 @@ void
 Editor::build_cursors ()
 {
        using namespace Gdk;
-       
+
        Gdk::Color mbg ("#000000" ); /* Black */
        Gdk::Color mfg ("#0000ff" ); /* Blue. */
 
@@ -1224,23 +1218,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);
@@ -1248,17 +1242,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);
@@ -1300,7 +1294,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()) {
@@ -1323,9 +1317,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)));
@@ -1394,7 +1388,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) {
@@ -1439,10 +1433,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()) {
@@ -1453,7 +1447,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;
@@ -1469,7 +1463,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;
 
@@ -1481,7 +1475,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;
 
@@ -1504,16 +1498,16 @@ Editor::build_track_region_context_menu (nframes64_t frame)
        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);
@@ -1557,11 +1551,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);
@@ -1590,7 +1584,7 @@ Editor::analyze_region_selection()
 
        analysis_window->set_regionmode();
        analysis_window->analyze();
-       
+
        analysis_window->present();
 }
 
@@ -1608,12 +1602,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();
@@ -1630,7 +1624,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);
@@ -1640,7 +1634,7 @@ Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Cr
 
        if (xfade->active()) {
                str = _("Mute");
-       } else { 
+       } else {
                str = _("Unmute");
        }
 
@@ -1702,21 +1696,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());
 
@@ -1745,10 +1746,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);
@@ -1757,9 +1758,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));
@@ -1768,7 +1769,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());
@@ -1779,19 +1780,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)));
 
@@ -1803,11 +1804,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);
@@ -1817,10 +1818,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) {
@@ -1828,7 +1828,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());
 
@@ -1842,13 +1842,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))));
@@ -1860,7 +1860,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) {
@@ -1873,13 +1873,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);
        }
@@ -1908,7 +1908,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());
 }
@@ -1921,43 +1921,47 @@ 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 (MenuElem (_("Create Chunk from Range"), mem_fun(*this, &Editor::create_named_selection)));
+
        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)
 {
@@ -1968,13 +1972,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 */
@@ -1982,7 +1986,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)));
@@ -1999,8 +2003,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 */
@@ -2008,7 +2010,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)));
@@ -2025,7 +2027,7 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
        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)));
@@ -2035,7 +2037,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))));
@@ -2055,7 +2057,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));
@@ -2065,7 +2067,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)));
@@ -2083,7 +2085,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)));
@@ -2091,7 +2093,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))));
@@ -2101,18 +2103,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()) {
@@ -2121,7 +2135,7 @@ Editor::set_snap_to (SnapType st)
 
        instant_save ();
 
-       switch (snap_type) {
+       switch (_snap_type) {
        case SnapToAThirtysecondBeat:
        case SnapToASixteenthBeat:
        case SnapToAEighthBeat:
@@ -2147,7 +2161,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 ()) {
@@ -2226,7 +2240,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;
@@ -2302,7 +2316,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);
        }
@@ -2327,10 +2341,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 */
@@ -2340,8 +2350,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) {
@@ -2351,9 +2375,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) {
@@ -2365,7 +2389,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) {
@@ -2381,7 +2405,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);
        }
@@ -2392,15 +2416,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"));
@@ -2408,10 +2432,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);
                }
@@ -2429,15 +2453,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);
@@ -2459,14 +2483,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));
@@ -2480,13 +2504,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);
@@ -2517,86 +2542,123 @@ Editor::trackview_by_y_position (double y)
        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 (nframes64_t& start, int32_t direction, bool for_mark)
+Editor::snap_to_with_modifier (nframes64_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
 {
-       if (!session || snap_mode == SnapOff) {
+       if (!session) {
                return;
        }
 
-       snap_to_internal (start, direction, for_mark);
+       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_internal (nframes64_t& start, int32_t direction, bool for_mark)
+Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
 {
-       Location* before = 0;
-       Location* after = 0;
+       if (!session || _snap_mode == SnapOff) {
+               return;
+       }
 
-       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;
+       snap_to_internal (start, direction, for_mark);
+}
 
-       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;
+void
+Editor::timecode_snap_to_internal (nframes64_t& start, int32_t direction, bool /*for_mark*/)
+{
+       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);
 
-       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;
@@ -2604,7 +2666,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;
@@ -2622,23 +2684,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:
@@ -2646,39 +2708,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();
-                       } 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();
+               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 {
-                               /* relax */
+                               start = after;
                        }
                }
+
                break;
 
        case SnapToRegionStart:
@@ -2686,95 +2730,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 ()
 {
@@ -2782,36 +2789,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);
@@ -2827,7 +2811,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;
@@ -2843,38 +2827,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);
@@ -2882,23 +2867,10 @@ 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);
 
@@ -2907,7 +2879,7 @@ Editor::setup_toolbar ()
        zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
        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")))));
@@ -2929,10 +2901,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);
@@ -2978,18 +2970,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);
@@ -2998,13 +2991,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);
 
@@ -3014,8 +3006,10 @@ Editor::setup_toolbar ()
 }
 
 void
-Editor::midi_panic_button_pressed ()
+Editor::midi_panic ()
 {
+       cerr << "MIDI panic\n";
+
        if (session) {
                session->midi_panic();
        }
@@ -3024,122 +3018,34 @@ Editor::midi_panic_button_pressed ()
 void
 Editor::setup_midi_toolbar ()
 {
-       string pixmap_path;
-
-       /* Mode Buttons (tool selection) */
+       RefPtr<Action> act;
 
-       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));
-
-       
        /* 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");
+       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;
        }
@@ -3155,8 +3061,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!!!
@@ -3176,18 +3082,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));
@@ -3200,21 +3106,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();
@@ -3331,7 +3237,7 @@ Editor::set_route_group_mute (Route& route, bool yn)
                route.set_mute (yn, this);
        }
 }
-               
+
 void
 Editor::history_changed ()
 {
@@ -3369,7 +3275,7 @@ Editor::duplicate_dialog (bool with_dialog)
 
        RegionSelection rs;
        get_regions_for_action (rs);
-       
+
        if (mouse_mode != MouseRange) {
 
                if (rs.empty()) {
@@ -3379,21 +3285,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();
@@ -3401,22 +3307,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();
        }
 
@@ -3464,6 +3370,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)
 {
@@ -3524,7 +3455,7 @@ Editor::edit_mode_selection_done ()
        }
 
        Config->set_edit_mode (mode);
-}      
+}
 
 void
 Editor::snap_type_selection_done ()
@@ -3558,12 +3489,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")) {
@@ -3574,7 +3505,7 @@ Editor::snap_type_selection_done ()
        if (ract) {
                ract->set_active ();
        }
-}      
+}
 
 void
 Editor::snap_mode_selection_done ()
@@ -3660,14 +3591,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)
@@ -3706,16 +3637,16 @@ Editor::get_valid_views (TimeAxisView* 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))) {
@@ -3723,7 +3654,7 @@ Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
                        }
                }
        }
-       
+
        return v;
 }
 
@@ -3735,7 +3666,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;
 
@@ -3751,7 +3682,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
@@ -3807,17 +3738,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);
        }
@@ -3888,16 +3822,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));
 }
@@ -3908,6 +3842,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)
 {
@@ -3936,7 +3924,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);
 
@@ -4026,7 +4014,7 @@ Editor::control_layout_scroll (GdkEventScroll* ev)
        case GDK_SCROLL_DOWN:
                scroll_tracks_down_line ();
                return true;
-               
+
        default:
                /* no left/right handling yet */
                break;
@@ -4039,7 +4027,7 @@ void
 Editor::session_state_saved (string snap_name)
 {
        ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
-       
+
        _snapshots->redisplay ();
 }
 
@@ -4059,7 +4047,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);
@@ -4090,7 +4078,7 @@ Editor::restore_editing_space ()
  *  @param v Track.
  */
 
-void 
+void
 Editor::new_playlists (TimeAxisView* v)
 {
        begin_reversible_command (_("new playlists"));
@@ -4121,7 +4109,7 @@ Editor::copy_playlists (TimeAxisView* v)
  *  @param v Track.
  */
 
-void 
+void
 Editor::clear_playlists (TimeAxisView* v)
 {
        begin_reversible_command (_("clear playlists"));
@@ -4131,7 +4119,7 @@ Editor::clear_playlists (TimeAxisView* v)
        commit_reversible_command ();
 }
 
-void 
+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);
@@ -4143,8 +4131,8 @@ Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<bo
        atv.use_copy_playlist (sz > 1 ? false : true, playlists);
 }
 
-void 
-Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
+void
+Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
 {
        atv.clear_playlist ();
 }
@@ -4201,14 +4189,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;
 }
 
@@ -4259,22 +4246,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 ();
 
@@ -4296,7 +4282,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.
        */
@@ -4304,7 +4290,7 @@ Editor::set_frames_per_unit (double fpu)
        if (max_frames / fpu < 800.0) {
                return;
        }
-       
+
        if (tempo_lines)
                tempo_lines->tempo_map_changed();
 
@@ -4364,17 +4350,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 ();
 }
 
@@ -4385,7 +4371,7 @@ Editor::queue_visual_change (double fpu)
        pending_visual_change.frames_per_unit = fpu;
 
        ensure_visual_change_idle_handler ();
-       
+
 }
 
 void
@@ -4435,15 +4421,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
@@ -4453,7 +4439,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);
@@ -4464,7 +4450,7 @@ 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 */
@@ -4475,7 +4461,7 @@ struct EditorOrderTimeAxisSorter {
            return a->order () < b->order ();
     }
 };
-       
+
 void
 Editor::sort_track_selection (TrackSelection* sel)
 {
@@ -4507,7 +4493,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;
@@ -4520,9 +4506,9 @@ Editor::get_preferred_edit_position (bool ignore_playhead)
                                }
                                break;
                        }
-               } 
+               }
                /* fallthru */
-               
+
        default:
        case EditAtMouse:
                if (!mouse_frame (where, ignored)) {
@@ -4542,7 +4528,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) {
@@ -4559,7 +4545,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 ();
 }
 
@@ -4569,7 +4555,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) {
@@ -4587,10 +4573,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
 {
@@ -4607,7 +4598,7 @@ Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackSelec
                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 (
@@ -4642,7 +4633,7 @@ Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackSe
                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 (
@@ -4663,26 +4654,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);
        }
@@ -4691,36 +4697,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) {
-               
+
                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 ()
@@ -4759,8 +4764,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,
@@ -4775,7 +4780,7 @@ Editor::first_idle ()
 
        // first idle adds route children (automation tracks), so we need to redisplay here
        _routes->redisplay ();
-       
+
        delete dialog;
 
        _have_idled = true;
@@ -4829,18 +4834,18 @@ Editor::idle_resize ()
 
        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;
 }
 
@@ -4864,19 +4869,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()) {
-                       RouteTimeAxisView* rtv = dynamic_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);
                }
        }
 
@@ -4888,7 +4905,7 @@ void
 Editor::handle_new_route (RouteList& routes)
 {
        ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::handle_new_route), routes));
-       
+
        RouteTimeAxisView *rtv;
        list<RouteTimeAxisView*> new_views;
 
@@ -4911,12 +4928,12 @@ Editor::handle_new_route (RouteList& routes)
 
                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));
        }
 
@@ -4938,7 +4955,7 @@ Editor::remove_route (TimeAxisView *tv)
 
        TrackViewList::iterator i;
        boost::shared_ptr<Route> route;
-       TimeAxisView* next_tv;
+       TimeAxisView* next_tv = 0;
 
        if (tv == entered_track) {
                entered_track = 0;
@@ -4956,7 +4973,7 @@ Editor::remove_route (TimeAxisView *tv)
                       next_tv = (*i);
                }
        }
-       
+
        if (current_mixer_strip && current_mixer_strip->route() == route) {
 
                if (next_tv) {
@@ -4968,11 +4985,11 @@ Editor::remove_route (TimeAxisView *tv)
 
                        ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
                }
-       } 
+       }
 }
 
 void
-Editor::hide_track_in_display (TimeAxisView& tv, bool temponly)
+Editor::hide_track_in_display (TimeAxisView& tv, bool /*temponly*/)
 {
        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
 
@@ -4988,10 +5005,10 @@ 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)
 }
 
@@ -5072,3 +5089,27 @@ Editor::hide_region_from_region_list ()
        _regions->selection_mapover (mem_fun (*this, &Editor::hide_a_region));
 }
 
+void
+Editor::start_step_editing ()
+{
+       step_edit_connection = Glib::signal_timeout().connect (mem_fun (*this, &Editor::check_step_edit), 20);
+}
+
+void
+Editor::stop_step_editing ()
+{
+       step_edit_connection.disconnect ();
+}
+
+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 true; // do it again, till we stop
+}