Add Auditioned to Export Report Dialog.
[ardour.git] / gtk2_ardour / editor.cc
index c8b3437662beb7bbbb68976ffcb4f2ff8352b02c..f080ed24fb1c0ecc0513932de63db2fcb35f1b95 100644 (file)
@@ -68,6 +68,7 @@
 #include "ardour/audio_track.h"
 #include "ardour/audioengine.h"
 #include "ardour/audioregion.h"
+#include "ardour/lmath.h"
 #include "ardour/location.h"
 #include "ardour/profile.h"
 #include "ardour/route_group.h"
 #include "note_base.h"
 #include "playlist_selector.h"
 #include "public_editor.h"
+#include "quantize_dialog.h"
 #include "region_layering_order_editor.h"
 #include "rgb_macros.h"
 #include "rhythm_ferret.h"
 #include "tempo_lines.h"
 #include "time_axis_view.h"
 #include "timers.h"
+#include "tooltips.h"
+#include "ui_config.h"
 #include "utils.h"
 #include "verbose_cursor.h"
 
@@ -231,7 +235,7 @@ pane_size_watcher (Paned* pane)
 
              X: hard to access
              Quartz: impossible to access
-             
+
           so stop that by preventing it from ever getting too narrow. 35
           pixels is basically a rough guess at the tab width.
 
@@ -299,6 +303,8 @@ Editor::Editor ()
        , _following_mixer_selection (false)
        , _control_point_toggled_on_press (false)
        , _stepping_axis_view (0)
+       , quantize_dialog (0)
+       , _main_menu_disabler (0)
 {
        constructed = false;
 
@@ -307,7 +313,7 @@ Editor::Editor ()
        PublicEditor::_instance = this;
 
        _have_idled = false;
-       
+
        selection = new Selection (this);
        cut_buffer = new Selection (this);
        _selection_memento = new SelectionMemento ();
@@ -317,6 +323,7 @@ Editor::Editor ()
        clicked_regionview = 0;
        clicked_axisview = 0;
        clicked_routeview = 0;
+       clicked_selection = 0;
        clicked_control_point = 0;
        last_update_frame = 0;
        last_paste_pos = 0;
@@ -376,6 +383,7 @@ Editor::Editor ()
        region_edit_menu_split_item = 0;
        temp_location = 0;
        leftmost_frame = 0;
+       mouse_mode = MouseObject;
        current_stepping_trackview = 0;
        entered_track = 0;
        entered_regionview = 0;
@@ -397,21 +405,21 @@ Editor::Editor ()
 
        sfbrowser = 0;
 
-       location_marker_color = ARDOUR_UI::config()->color ("location marker");
-       location_range_color = ARDOUR_UI::config()->color ("location range");
-       location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
-       location_loop_color = ARDOUR_UI::config()->color ("location loop");
-       location_punch_color = ARDOUR_UI::config()->color ("location punch");
+       location_marker_color = UIConfiguration::instance().color ("location marker");
+       location_range_color = UIConfiguration::instance().color ("location range");
+       location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
+       location_loop_color = UIConfiguration::instance().color ("location loop");
+       location_punch_color = UIConfiguration::instance().color ("location punch");
 
-       zoom_focus = ZoomFocusLeft;
+       zoom_focus = ZoomFocusPlayhead;
        _edit_point = EditAtMouse;
        _visible_track_count = -1;
 
        samples_per_pixel = 2048; /* too early to use reset_zoom () */
 
-       timebar_height = std::max(12., ceil (15. * ARDOUR_UI::config()->get_font_scale() / 102400.));
+       timebar_height = std::max(12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
        TimeAxisView::setup_sizes ();
-       Marker::setup_sizes (timebar_height);
+       ArdourMarker::setup_sizes (timebar_height);
 
        _scroll_callbacks = 0;
 
@@ -525,8 +533,8 @@ Editor::Editor ()
        controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
 
        _cursors = new MouseCursors;
-       _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
-       cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
+       _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
+       cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
 
        /* Push default cursor to ever-present bottom of cursor stack. */
        push_canvas_cursor(_cursors->grabber);
@@ -694,10 +702,10 @@ Editor::Editor ()
        /* nudge stuff */
 
        nudge_forward_button.set_name ("nudge button");
-       nudge_forward_button.set_image(::get_icon("nudge_right"));
+       nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
 
        nudge_backward_button.set_name ("nudge button");
-       nudge_backward_button.set_image(::get_icon("nudge_left"));
+       nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
 
        fade_context_menu.set_name ("ArdourContextMenu");
 
@@ -735,7 +743,7 @@ Editor::Editor ()
        signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
 
        Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
-       
+
        /* allow external control surfaces/protocols to do various things */
 
        ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
@@ -766,7 +774,7 @@ Editor::Editor ()
        Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
 
        Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
-       ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
+       UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
 
        TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
 
@@ -793,7 +801,7 @@ Editor::Editor ()
 
        /* grab current parameter state */
        boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
-       ARDOUR_UI::config()->map_parameters (pc);
+       UIConfiguration::instance().map_parameters (pc);
 
        setup_fade_images ();
 
@@ -808,6 +816,17 @@ Editor::~Editor()
        delete _track_canvas_viewport;
        delete _drags;
        delete nudge_clock;
+       delete quantize_dialog;
+       delete _summary;
+       delete _group_tabs;
+       delete _regions;
+       delete _snapshots;
+       delete _locations;
+       delete _playlist_selector;
+
+       for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
+               delete *i;
+       }
 }
 
 XMLNode*
@@ -1000,12 +1019,12 @@ Editor::control_unselect ()
 }
 
 void
-Editor::control_select (uint32_t rid, Selection::Operation op) 
+Editor::control_select (uint32_t rid, Selection::Operation op)
 {
        /* handles the (static) signal from the ControlProtocol class that
         * requests setting the selected track to a given RID
         */
-        
+
        if (!_session) {
                return;
        }
@@ -1144,7 +1163,7 @@ Editor::on_realize ()
        Window::on_realize ();
        Realized ();
 
-       if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
+       if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
                start_lock_event_timing ();
        }
 
@@ -1176,7 +1195,7 @@ Editor::generic_event_handler (GdkEvent* ev)
                case GDK_NOTIFY_UNKNOWN:
                case GDK_NOTIFY_INFERIOR:
                case GDK_NOTIFY_ANCESTOR:
-                       break; 
+                       break;
                case GDK_NOTIFY_VIRTUAL:
                case GDK_NOTIFY_NONLINEAR:
                case GDK_NOTIFY_NONLINEAR_VIRTUAL:
@@ -1204,7 +1223,7 @@ Editor::lock_timeout_callback ()
 
        timersub (&now, &last_event_time, &delta);
 
-       if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
+       if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
                lock ();
                /* don't call again. Returning false will effectively
                   disconnect us from the timer callback.
@@ -1450,18 +1469,18 @@ Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
                        sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
                        )
                );
-       
+
        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
-       
+
        items.push_back (
                ImageMenuElem (
                        _("Constant power"),
                        *(*images)[FadeConstantPower],
                        sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
                        ));
-       
+
        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
-       
+
        items.push_back (
                ImageMenuElem (
                        _("Symmetric"),
@@ -1469,25 +1488,25 @@ Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
                        sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
                        )
                );
-       
+
        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
-       
+
        items.push_back (
                ImageMenuElem (
                        _("Slow"),
                        *(*images)[FadeSlow],
                        sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
                        ));
-       
+
        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
-       
+
        items.push_back (
                ImageMenuElem (
                        _("Fast"),
                        *(*images)[FadeFast],
                        sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
                        ));
-       
+
        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 }
 
@@ -1795,10 +1814,18 @@ Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::sha
                _popup_region_menu_item->set_label (menu_item_name);
        }
 
-       const framepos_t position = get_preferred_edit_position (false, true);
+       /* No latering allowed in later is higher layering model */
+       RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
+       if (act && Config->get_layer_model() == LaterHigher) {
+               act->set_sensitive (false);
+       } else if (act) {
+               act->set_sensitive (true);
+       }
+
+       const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
 
        edit_items.push_back (*_popup_region_menu_item);
-       if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
+       if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
                edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
        }
        edit_items.push_back (SeparatorElem());
@@ -1868,17 +1895,16 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
 
        edit_items.push_back (SeparatorElem());
        edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
-       edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
        edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
 
        edit_items.push_back (SeparatorElem());
        edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
-       edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
+       edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
        edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
-       edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
+       edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
        edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
        if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
-               edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
+               edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
        }
 }
 
@@ -1894,8 +1920,8 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
        MenuList& play_items = play_menu->items();
        play_menu->set_name ("ArdourContextMenu");
 
-       play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
-       play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
+       play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
+       play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
        play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
        play_items.push_back (SeparatorElem());
        play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
@@ -1915,9 +1941,10 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
        select_items.push_back (SeparatorElem());
        select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
        select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
+       select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
        select_items.push_back (SeparatorElem());
-       select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
-       select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
+       select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
+       select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
        select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
        select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
        select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
@@ -1975,8 +2002,8 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
        MenuList& play_items = play_menu->items();
        play_menu->set_name ("ArdourContextMenu");
 
-       play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
-       play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
+       play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
+       play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
        edit_items.push_back (MenuElem (_("Play"), *play_menu));
 
        /* Selection */
@@ -1990,8 +2017,8 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
        select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
        select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
        select_items.push_back (SeparatorElem());
-       select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
-       select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
+       select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
+       select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
        select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
        select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
 
@@ -2078,7 +2105,7 @@ Editor::set_snap_to (SnapType st)
        case SnapToBeatDiv2: {
                ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
                ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
-               
+
                compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
                                            current_bbt_points_begin, current_bbt_points_end);
                compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
@@ -2123,6 +2150,7 @@ Editor::set_snap_mode (SnapMode mode)
 
        instant_save ();
 }
+
 void
 Editor::set_edit_point_preference (EditPoint ep, bool force)
 {
@@ -2321,37 +2349,16 @@ Editor::set_state (const XMLNode& node, int /*version*/)
        if ((prop = node.property ("show-measures"))) {
                bool yn = string_is_affirmative (prop->value());
                _show_measures = yn;
-               RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
-               if (act) {
-                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
-                       /* do it twice to force the change */
-                       tact->set_active (!yn);
-                       tact->set_active (yn);
-               }
        }
 
        if ((prop = node.property ("follow-playhead"))) {
                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) {
-                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
-                       if (tact->get_active() != yn) {
-                               tact->set_active (yn);
-                       }
-               }
        }
 
        if ((prop = node.property ("stationary-playhead"))) {
                bool yn = string_is_affirmative (prop->value());
                set_stationary_playhead (yn);
-               RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
-               if (act) {
-                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
-                       if (tact->get_active() != yn) {
-                               tact->set_active (yn);
-                       }
-               }
        }
 
        if ((prop = node.property ("region-list-sort-type"))) {
@@ -2427,6 +2434,42 @@ Editor::set_state (const XMLNode& node, int /*version*/)
                nudge_clock->set (_session->frame_rate() * 5, true);
        }
 
+       {
+               /* apply state
+                * Not all properties may have been in XML, but
+                * those that are linked to a private variable may need changing
+                */
+               RefPtr<Action> act;
+               bool yn;
+
+               act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
+               if (act) {
+                       yn = _show_measures;
+                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
+                       /* do it twice to force the change */
+                       tact->set_active (!yn);
+                       tact->set_active (yn);
+               }
+
+               act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
+               yn = _follow_playhead;
+               if (act) {
+                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
+                       if (tact->get_active() != yn) {
+                               tact->set_active (yn);
+                       }
+               }
+
+               act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
+               yn = _stationary_playhead;
+               if (act) {
+                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
+                       if (tact->get_active() != yn) {
+                               tact->set_active (yn);
+                       }
+               }
+       }
+
        return 0;
 }
 
@@ -2548,9 +2591,9 @@ Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
        }
 
        for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
-                       
+
                std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
-                       
+
                if (r.first) {
                        return r;
                }
@@ -2571,25 +2614,28 @@ Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundM
                return;
        }
 
-       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
+       if (ArdourKeyboard::indicates_snap (event->button.state)) {
                if (_snap_mode == SnapOff) {
                        snap_to_internal (start, direction, for_mark);
                }
        } else {
                if (_snap_mode != SnapOff) {
                        snap_to_internal (start, direction, for_mark);
+               } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
+                       /* SnapOff, but we pressed the snap_delta modifier */
+                       snap_to_internal (start, direction, for_mark);
                }
        }
 }
 
 void
-Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
+Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
 {
-       if (!_session || _snap_mode == SnapOff) {
+       if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
                return;
        }
 
-       snap_to_internal (start, direction, for_mark);
+       snap_to_internal (start, direction, for_mark, ensure_snap);
 }
 
 void
@@ -2659,7 +2705,7 @@ Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool
 }
 
 void
-Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
+Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
 {
        const framepos_t one_second = _session->frame_rate();
        const framepos_t one_minute = _session->frame_rate() * 60;
@@ -2829,6 +2875,10 @@ Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
 
        case SnapMagnetic:
 
+               if (ensure_snap) {
+                       return;
+               }
+
                if (presnap > start) {
                        if (presnap > (start + pixel_to_sample(snap_threshold))) {
                                start = presnap;
@@ -2902,7 +2952,7 @@ Editor::setup_toolbar ()
        if (!ARDOUR::Profile->get_mixbus()) {
                mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
        }
-       
+
        if (!ARDOUR::Profile->get_trx()) {
                mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
                mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
@@ -2953,17 +3003,17 @@ Editor::setup_toolbar ()
        zoom_preset_selector.set_size_request (42, -1);
 
        zoom_in_button.set_name ("zoom button");
-       zoom_in_button.set_image(::get_icon ("zoom_in"));
+       zoom_in_button.set_icon (ArdourIcon::ZoomIn);
        act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
        zoom_in_button.set_related_action (act);
 
        zoom_out_button.set_name ("zoom button");
-       zoom_out_button.set_image(::get_icon ("zoom_out"));
+       zoom_out_button.set_icon (ArdourIcon::ZoomOut);
        act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
        zoom_out_button.set_related_action (act);
 
        zoom_out_full_button.set_name ("zoom button");
-       zoom_out_full_button.set_image(::get_icon ("zoom_full"));
+       zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
        act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
        zoom_out_full_button.set_related_action (act);
 
@@ -2991,12 +3041,12 @@ Editor::setup_toolbar ()
        }
 
        tav_expand_button.set_name ("zoom button");
-       tav_expand_button.set_image(::get_icon ("tav_exp"));
+       tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
        act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
        tav_expand_button.set_related_action (act);
 
        tav_shrink_button.set_name ("zoom button");
-       tav_shrink_button.set_image(::get_icon ("tav_shrink"));
+       tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
        act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
        tav_shrink_button.set_related_action (act);
 
@@ -3013,7 +3063,7 @@ Editor::setup_toolbar ()
 
        if (!ARDOUR::Profile->get_trx()) {
                _zoom_tearoff = manage (new TearOff (_zoom_box));
-               
+
                _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
                                                           &_zoom_tearoff->tearoff_window()));
                _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
@@ -3022,7 +3072,7 @@ Editor::setup_toolbar ()
                                                           &_zoom_tearoff->tearoff_window()));
                _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
                                                            &_zoom_tearoff->tearoff_window(), 0));
-       } 
+       }
 
        if (Profile->get_sae() || Profile->get_mixbus() ) {
                _zoom_tearoff->set_can_be_torn_off (false);
@@ -3088,11 +3138,7 @@ Editor::setup_toolbar ()
 
        if (!ARDOUR::Profile->get_trx()) {
                hbox->pack_start (snap_box, false, false);
-               if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
-                       hbox->pack_start (*nudge_box, false, false);
-               } else {
-                       ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
-               }
+               hbox->pack_start (*nudge_box, false, false);
        }
        hbox->pack_start (panic_box, false, false);
 
@@ -3127,7 +3173,7 @@ void
 Editor::build_edit_mode_menu ()
 {
        using namespace Menu_Helpers;
-       
+
        edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
 //     edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
        edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
@@ -3191,30 +3237,30 @@ Editor::build_snap_type_menu ()
 void
 Editor::setup_tooltips ()
 {
-       ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
-       ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
-       ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
-       ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
-       ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
-       ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
-       ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
-       ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and gain curves inside regions)"));
-       ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
-       ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
-       ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
-       ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
-       ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
-       ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
-       ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
-       ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
-       ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
-       ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
-       ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
-       ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
-       ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
-       ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
-       ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
-       ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
+       set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
+       set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
+       set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
+       set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
+       set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
+       set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
+       set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
+       set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
+       set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
+       set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
+       set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
+       set_tooltip (zoom_in_button, _("Zoom In"));
+       set_tooltip (zoom_out_button, _("Zoom Out"));
+       set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
+       set_tooltip (zoom_out_full_button, _("Zoom to Session"));
+       set_tooltip (zoom_focus_selector, _("Zoom Focus"));
+       set_tooltip (tav_expand_button, _("Expand Tracks"));
+       set_tooltip (tav_shrink_button, _("Shrink Tracks"));
+       set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
+       set_tooltip (snap_type_selector, _("Snap/Grid Units"));
+       set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
+       set_tooltip (edit_point_selector, _("Edit Point"));
+       set_tooltip (edit_mode_selector, _("Edit Mode"));
+       set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
 }
 
 int
@@ -3326,7 +3372,12 @@ Editor::begin_selection_op_history ()
 {
        selection_op_cmd_depth = 0;
        selection_op_history_it = 0;
-       selection_op_history.clear();
+
+       while(!selection_op_history.empty()) {
+               delete selection_op_history.front();
+               selection_op_history.pop_front();
+       }
+
        selection_undo_action->set_sensitive (false);
        selection_redo_action->set_sensitive (false);
        selection_op_history.push_front (&_selection_memento->get_state ());
@@ -3349,10 +3400,19 @@ Editor::commit_reversible_selection_op ()
                if (selection_op_cmd_depth == 1) {
 
                        if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
-                               /* the user has undone some selection ops and then made a new one */
+                               /**
+                                   The user has undone some selection ops and then made a new one,
+                                   making anything earlier in the list invalid.
+                               */
+
                                list<XMLNode *>::iterator it = selection_op_history.begin();
-                               advance (it, selection_op_history_it);
-                               selection_op_history.erase (selection_op_history.begin(), it);
+                               list<XMLNode *>::iterator e_it = it;
+                               advance (e_it, selection_op_history_it);
+
+                               for ( ; it != e_it; ++it) {
+                                       delete *it;
+                               }
+                               selection_op_history.erase (selection_op_history.begin(), e_it);
                        }
 
                        selection_op_history.push_front (&_selection_memento->get_state ());
@@ -3432,7 +3492,10 @@ void
 Editor::abort_reversible_command ()
 {
        if (_session) {
-               before.clear();
+               while(!before.empty()) {
+                       delete before.front();
+                       before.pop_front();
+               }
                _session->abort_reversible_command ();
        }
 }
@@ -3475,8 +3538,10 @@ Editor::history_changed ()
        if (redo_action && _session) {
                if (_session->redo_depth() == 0) {
                        label = _("Redo");
+                       redo_action->set_sensitive (false);
                } else {
                        label = string_compose(_("Redo (%1)"), _session->next_redo());
+                       redo_action->set_sensitive (true);
                }
                redo_action->property_label() = label;
        }
@@ -3541,7 +3606,7 @@ Editor::duplicate_range (bool with_dialog)
        } else if (get_smart_mode()) {
                if (selection->time.length()) {
                        duplicate_selection (times);
-               } else 
+               } else
                        duplicate_some_regions (rs, times);
        } else {
                duplicate_some_regions (rs, times);
@@ -3705,7 +3770,7 @@ Editor::set_zoom_preset (int64_t ms)
                temporal_zoom_session();
                return;
        }
-       
+
        ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
        temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
 }
@@ -3720,7 +3785,7 @@ Editor::set_visible_track_count (int32_t n)
           allocation happens, we will get called again and then we can do the
           real work.
        */
-       
+
        if (_visible_canvas_height <= 1) {
                return;
        }
@@ -3728,7 +3793,7 @@ Editor::set_visible_track_count (int32_t n)
        int h;
        string str;
        DisplaySuspender ds;
-       
+
        if (_visible_track_count > 0) {
                h = trackviews_height() / _visible_track_count;
                std::ostringstream s;
@@ -3744,7 +3809,7 @@ Editor::set_visible_track_count (int32_t n)
                h = trackviews_height() / n;
                str = _("All");
        } else {
-               /* negative value means that the visible track count has 
+               /* negative value means that the visible track count has
                   been overridden by explicit track height changes.
                */
                visible_tracks_selector.set_text (X_("*"));
@@ -3752,9 +3817,9 @@ Editor::set_visible_track_count (int32_t n)
        }
 
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-               (*i)->set_height (h);
+               (*i)->set_height (h, TimeAxisView::HeightPerLane);
        }
-       
+
        if (str != visible_tracks_selector.get_text()) {
                visible_tracks_selector.set_text (str);
        }
@@ -3908,8 +3973,8 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
 void
 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
 {
-       if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) && 
-           (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) && 
+       if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
+           (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
            (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
                top_hbox.remove (toolbar_frame);
        }
@@ -3936,10 +4001,10 @@ Editor::set_show_measures (bool yn)
 
                        ARDOUR::TempoMap::BBTPointList::const_iterator begin;
                        ARDOUR::TempoMap::BBTPointList::const_iterator end;
-                       
+
                        compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
                        draw_measures (begin, end);
-               } 
+               }
 
                instant_save ();
        }
@@ -4095,19 +4160,34 @@ Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
 
        label.show ();
 
+       dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
        dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
-       dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
+       Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
+       dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
        dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
 
+       // by default gtk uses the left most button
+       keep->grab_focus ();
+
        switch (dialog.run ()) {
+       case RESPONSE_NO:
+               /* keep this and all remaining ones */
+               return -2;
+               break;
+
+       case RESPONSE_YES:
+               /* delete this and all others */
+               return 2;
+               break;
+
        case RESPONSE_ACCEPT:
                /* delete the playlist */
-               return 0;
+               return 1;
                break;
 
        case RESPONSE_REJECT:
                /* keep the playlist */
-               return 1;
+               return 0;
                break;
 
        default:
@@ -4190,7 +4270,7 @@ Editor::session_state_saved (string)
 void
 Editor::update_tearoff_visibility()
 {
-       bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
+       bool visible = UIConfiguration::instance().get_keep_tearoffs();
        _mouse_mode_tearoff->set_visible (visible);
        _tools_tearoff->set_visible (visible);
        if (_zoom_tearoff) {
@@ -4270,7 +4350,7 @@ Editor::copy_playlists (TimeAxisView* v)
 void
 Editor::clear_playlists (TimeAxisView* v)
 {
-       begin_reversible_command (_("clear playlists"));        
+       begin_reversible_command (_("clear playlists"));
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
        _session->playlists->get (playlists);
        mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
@@ -4375,7 +4455,7 @@ Editor::current_visual_state (bool with_tracks)
        vs->leftmost_frame = leftmost_frame;
        vs->zoom_focus = zoom_focus;
 
-       if (with_tracks) {      
+       if (with_tracks) {
                *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
        }
 
@@ -4439,11 +4519,12 @@ Editor::use_visual_state (VisualState& vs)
 
        set_zoom_focus (vs.zoom_focus);
        reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
-       
+
        if (vs.gui_state) {
                *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
-               
-               for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {    
+
+               for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+                       (*i)->clear_property_cache();
                        (*i)->reset_visual_state ();
                }
        }
@@ -4552,7 +4633,7 @@ Editor::idle_visual_changer ()
 
        pending_visual_change.idle_handler_id = -1;
        pending_visual_change.being_handled = true;
-       
+
        VisualChange vc = pending_visual_change;
 
        pending_visual_change.pending = (VisualChange::Type) 0;
@@ -4576,7 +4657,7 @@ Editor::visual_changer (const VisualChange& vc)
 
                ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
                ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
-               
+
                compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
                                            current_bbt_points_begin, current_bbt_points_end);
                compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
@@ -4621,15 +4702,15 @@ Editor::sort_track_selection (TrackViewList& sel)
 }
 
 framepos_t
-Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu, bool from_outside_canvas)
+Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
 {
        bool ignored;
        framepos_t where = 0;
        EditPoint ep = _edit_point;
 
-       if(Profile->get_mixbus())
+       if (Profile->get_mixbus())
                if (ep == EditAtSelectedMarker)
-                       ep=EditAtPlayhead;
+                       ep = EditAtPlayhead;
 
        if (from_outside_canvas && (ep == EditAtMouse)) {
                ep = EditAtPlayhead;
@@ -4642,19 +4723,21 @@ Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_men
                return entered_marker->position();
        }
 
-       if (ignore_playhead && ep == EditAtPlayhead) {
+       if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
                ep = EditAtSelectedMarker;
        }
 
+       if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
+               ep = EditAtPlayhead;
+       }
+
        switch (ep) {
        case EditAtPlayhead:
                if (_dragging_playhead) {
-                       if (!mouse_frame (where, ignored)) {
-                               /* XXX not right but what can we do ? */
-                               return 0;
-                       }
-               } else
+                       where = *_control_scroll_target;
+               } else {
                        where = _session->audible_frame();
+               }
                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
                break;
 
@@ -4846,7 +4929,7 @@ Editor::get_regions_from_selection_and_edit_point ()
                if (!tracks.empty()) {
                        /* no region selected or entered, but some selected tracks:
                         * act on all regions on the selected tracks at the edit point
-                        */ 
+                        */
                        framepos_t const where = get_preferred_edit_position ();
                        get_regions_at(regions, where, tracks);
                }
@@ -4883,7 +4966,7 @@ Editor::get_regions_from_selection_and_mouse (framepos_t pos)
                if (!tracks.empty()) {
                        /* no region selected or entered, but some selected tracks:
                         * act on all regions on the selected tracks at the edit point
-                        */ 
+                        */
                        get_regions_at(regions, pos, tracks);
                }
        }
@@ -4913,17 +4996,17 @@ Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) cons
 {
        for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
                RouteTimeAxisView* rtav;
-               
+
                if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
                        boost::shared_ptr<Playlist> pl;
                        std::vector<boost::shared_ptr<Region> > results;
                        boost::shared_ptr<Track> tr;
-                       
+
                        if ((tr = rtav->track()) == 0) {
                                /* bus */
                                continue;
                        }
-                       
+
                        if ((pl = (tr->playlist())) != 0) {
                                boost::shared_ptr<Region> r = pl->region_by_id (id);
                                if (r) {
@@ -4949,7 +5032,7 @@ Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<
                        mtav->get_per_region_note_selection (selection);
                }
        }
-       
+
 }
 
 void
@@ -5005,8 +5088,9 @@ void
 Editor::first_idle ()
 {
        MessageDialog* dialog = 0;
-       
+
        if (track_views.size() > 1) {
+               Timers::TimerSuspender t;
                dialog = new MessageDialog (
                        *this,
                        string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
@@ -5192,6 +5276,7 @@ void
 Editor::resume_route_redisplay ()
 {
        if (_routes) {
+               _routes->redisplay(); // queue redisplay
                _routes->resume_redisplay();
        }
 }
@@ -5203,6 +5288,8 @@ Editor::add_routes (RouteList& routes)
 
        RouteTimeAxisView *rtv;
        list<RouteTimeAxisView*> new_views;
+       TrackViewList new_selection;
+       bool from_scratch = (track_views.size() == 0);
 
        for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
                boost::shared_ptr<Route> route = (*x);
@@ -5225,6 +5312,7 @@ Editor::add_routes (RouteList& routes)
 
                new_views.push_back (rtv);
                track_views.push_back (rtv);
+               new_selection.push_back (rtv);
 
                rtv->effective_gain_display ();
 
@@ -5237,6 +5325,12 @@ Editor::add_routes (RouteList& routes)
                _summary->routes_added (new_views);
        }
 
+       if (!from_scratch) {
+               selection->tracks.clear();
+               selection->add (new_selection);
+               begin_selection_op_history();
+       }
+
        if (show_editor_mixer_when_tracks_arrive) {
                show_editor_mixer (true);
        }
@@ -5340,7 +5434,7 @@ Editor::sync_track_view_list_and_routes ()
 {
        track_views = TrackViewList (_routes->views ());
 
-       _summary->set_dirty ();
+       _summary->set_background_dirty();
        _group_tabs->set_dirty ();
 
        return false; // do not call again (until needed)
@@ -5531,7 +5625,7 @@ Editor::reset_x_origin_to_follow_playhead ()
                } else {
 
                        framepos_t l = 0;
-                       
+
                        if (frame < leftmost_frame) {
                                /* moving left */
                                if (_session->transport_rolling()) {
@@ -5555,7 +5649,7 @@ Editor::reset_x_origin_to_follow_playhead ()
                        if (l < 0) {
                                l = 0;
                        }
-                       
+
                        center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
                }
        }
@@ -5622,24 +5716,20 @@ Editor::super_rapid_screen_update ()
 
                } else {
 
-                       /* don't do continuous scroll till the new position is in the rightmost quarter of the
-                          editor canvas
-                       */
-#if 0
-                       // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
-                       double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
-                       if (target <= 0.0) {
-                               target = 0.0;
-                       }
-                       if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
-                               target = (target * 0.15) + (current * 0.85);
-                       } else {
-                               /* relax */
+                       if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
+                               framepos_t const frame = playhead_cursor->current_frame ();
+                               double target = ((double)frame - (double)current_page_samples()/2.0);
+                               if (target <= 0.0) {
+                                       target = 0.0;
+                               }
+                               // compare to EditorCursor::set_position()
+                               double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
+                               double const new_pos = sample_to_pixel_unrounded (target);
+                               if (rint (new_pos) != rint (old_pos)) {
+                                       reset_x_origin (pixel_to_sample (floor (new_pos)));
+                               }
                        }
 
-                       current = target;
-                       set_horizontal_position (current);
-#endif
                }
 
        }
@@ -5704,7 +5794,7 @@ Editor::session_going_away ()
        clear_marker_display ();
 
        stop_step_editing ();
-       
+
        /* get rid of any existing editor mixer strip */
 
        WindowTitle title(Glib::get_application_name());
@@ -5729,7 +5819,7 @@ Editor::show_editor_list (bool yn)
 void
 Editor::change_region_layering_order (bool from_context_menu)
 {
-       const framepos_t position = get_preferred_edit_position (false, from_context_menu);
+       const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
 
        if (!clicked_routeview) {
                if (layering_order_editor) {
@@ -5780,7 +5870,7 @@ Editor::setup_fade_images ()
        _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
        _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
        _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
-       
+
        _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
        _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
        _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
@@ -5851,10 +5941,10 @@ void
 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
 {
        using namespace Menu_Helpers;
-       
+
        MenuList& items = _control_point_context_menu.items ();
        items.clear ();
-       
+
        items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
        items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
        if (!can_remove_control_point (item)) {
@@ -5880,20 +5970,41 @@ Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
 
        MidiRegionView&       mrv = note->region_view();
        const RegionSelection rs  = get_regions_from_selection_and_entered ();
+       const uint32_t sel_size = mrv.selection_size ();
 
        MenuList& items = _note_context_menu.items();
        items.clear();
 
-       items.push_back(MenuElem(_("Delete"),
-                                sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
+       if (sel_size > 0) {
+               items.push_back(MenuElem(_("Delete"),
+                                        sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
+       }
+
        items.push_back(MenuElem(_("Edit..."),
-                                sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
+                                sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
+       if (sel_size != 1) {
+               items.back().set_sensitive (false);
+       }
+
+       items.push_back(MenuElem(_("Transpose..."),
+                                sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
+
+
        items.push_back(MenuElem(_("Legatize"),
-                                sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
+                                sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
+       if (sel_size < 2) {
+               items.back().set_sensitive (false);
+       }
+
        items.push_back(MenuElem(_("Quantize..."),
                                 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
+
        items.push_back(MenuElem(_("Remove Overlap"),
-                                sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
+                                sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
+       if (sel_size < 2) {
+               items.back().set_sensitive (false);
+       }
+
        items.push_back(MenuElem(_("Transform..."),
                                 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
 
@@ -5913,11 +6024,11 @@ Editor::ui_parameter_changed (string parameter)
                while (!_cursor_stack.empty()) {
                        _cursor_stack.pop_back();
                }
-               _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
+               _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
                _cursor_stack.push_back(_cursors->grabber);
        } else if (parameter == "draggable-playhead") {
                if (_verbose_cursor) {
-                       playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());
+                       playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
                }
        }
 }