On selection, move/scroll VCA into view
[ardour.git] / gtk2_ardour / mixer_ui.cc
index 3b0436d31b391e8519bc989c6e86d46f7ed75e32..52b5708216fb7d1bcd443583bf38a45f0b0b1eeb 100644 (file)
@@ -103,20 +103,18 @@ Mixer_UI::Mixer_UI ()
        , no_track_list_redisplay (false)
        , in_group_row_change (false)
        , track_menu (0)
-       , _monitor_section (0)
        , _plugin_selector (0)
        , _strip_width (UIConfiguration::instance().get_default_narrow_ms() ? Narrow : Wide)
+       , _spill_scroll_position (0)
        , ignore_reorder (false)
        , _in_group_rebuild_or_clear (false)
        , _route_deletion_in_progress (false)
        , _maximised (false)
-       , _show_mixer_list (true)
        , _strip_selection_change_without_scroll (false)
-       , myactions (X_("mixer"))
        , _selection (*this, *this)
 {
-       register_actions ();
        load_bindings ();
+       register_actions ();
        _content.set_data ("ardour-bindings", bindings);
 
        PresentationInfo::Change.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::presentation_info_changed, this, _1), gui_context());
@@ -139,18 +137,28 @@ Mixer_UI::Mixer_UI ()
        Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
        w->show ();
        add_vca_button.add (*w);
+       add_vca_button.set_can_focus(false);
        add_vca_button.signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
 
        /* create a button to add mixer strips */
        w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
        w->show ();
        add_button.add (*w);
+       add_button.set_can_focus(false);
        add_button.signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
 
        /* add as last item of strip packer */
        strip_packer.pack_end (scroller_base, true, true);
        strip_packer.pack_end (add_button, false, false);
 
+#ifdef MIXBUS
+       /* create a drop-shadow at the end of the mixer strips */
+       mb_shadow.set_size_request( 4, -1 );
+       mb_shadow.set_name("EditorWindow");
+       mb_shadow.show();
+       strip_packer.pack_end (mb_shadow, false, false);
+#endif
+
        _group_tabs = new MixerGroupTabs (this);
        VBox* b = manage (new VBox);
        b->set_spacing (0);
@@ -220,7 +228,6 @@ Mixer_UI::Mixer_UI ()
        favorite_plugins_display.set_headers_visible (true);
        favorite_plugins_display.set_rules_hint (true);
        favorite_plugins_display.set_can_focus (false);
-       favorite_plugins_display.set_tooltip_column (0);
        favorite_plugins_display.add_object_drag (favorite_plugins_columns.plugin.index(), "PluginFavoritePtr");
        favorite_plugins_display.set_drag_column (favorite_plugins_columns.name.index());
        favorite_plugins_display.add_drop_targets (target_list);
@@ -229,6 +236,9 @@ Mixer_UI::Mixer_UI ()
        favorite_plugins_display.signal_drop.connect (sigc::mem_fun (*this, &Mixer_UI::plugin_drop));
        favorite_plugins_display.signal_row_expanded().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state));
        favorite_plugins_display.signal_row_collapsed().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state));
+       if (UIConfiguration::instance().get_use_tooltips()) {
+               favorite_plugins_display.set_tooltip_column (0);
+       }
        favorite_plugins_model->signal_row_has_child_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::sync_treeview_favorite_ui_state));
 
        favorite_plugins_scroller.add (favorite_plugins_display);
@@ -257,6 +267,7 @@ Mixer_UI::Mixer_UI ()
        vca_scroller_base.set_name (X_("MixerWindow"));
        vca_scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::masters_scroller_button_release), false);
 
+       vca_hpacker.signal_scroll_event().connect (sigc::mem_fun (*this, &Mixer_UI::on_vca_scroll_event), false);
        vca_scroller.add (vca_hpacker);
        vca_scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
        vca_scroller.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
@@ -337,6 +348,11 @@ Mixer_UI::Mixer_UI ()
        favorite_plugins_display.show();
        add_button.show ();
 
+       XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
+       if (mnode) {
+               _monitor_section.tearoff().set_state (*mnode);
+       }
+
        MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context());
        VCAMasterStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_master, this, _1), gui_context());
 
@@ -351,19 +367,28 @@ Mixer_UI::Mixer_UI ()
 #endif
 
        PluginManager::instance ().PluginListChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::plugin_list_changed, this), gui_context());
+       PluginManager::instance ().PluginStatusChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::plugin_list_changed, this), gui_context());
        ARDOUR::Plugin::PresetsChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
 }
 
 Mixer_UI::~Mixer_UI ()
 {
-       if (_monitor_section) {
-               monitor_section_detached ();
-               delete _monitor_section;
-       }
+       monitor_section_detached ();
+
        delete _plugin_selector;
        delete track_menu;
 }
 
+struct MixerStripSorter {
+       bool operator() (const MixerStrip* ms_a, const MixerStrip* ms_b)
+       {
+               boost::shared_ptr<ARDOUR::Stripable> const& a = ms_a->stripable ();
+               boost::shared_ptr<ARDOUR::Stripable> const& b = ms_b->stripable ();
+               return ARDOUR::Stripable::Sorter(true)(a, b);
+       }
+};
+
+
 void
 Mixer_UI::escape ()
 {
@@ -459,6 +484,12 @@ Mixer_UI::masters_scroller_button_release (GdkEventButton* ev)
        return false;
 }
 
+void
+Mixer_UI::new_masters_created ()
+{
+       ActionManager::get_toggle_action ("Mixer", "ToggleVCAPane")->set_active (true);
+}
+
 void
 Mixer_UI::add_masters (VCAList& vlist)
 {
@@ -541,23 +572,14 @@ Mixer_UI::add_stripables (StripableList& slist)
 
                                if (route->is_monitor()) {
 
-                                       if (!_monitor_section) {
-                                               _monitor_section = new MonitorSection (_session);
-
-                                               XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
-                                               if (mnode) {
-                                                       _monitor_section->tearoff().set_state (*mnode);
-                                               }
-                                       }
-
-                                       out_packer.pack_end (_monitor_section->tearoff(), false, false);
-                                       _monitor_section->set_session (_session);
-                                       _monitor_section->tearoff().show_all ();
+                                       out_packer.pack_end (_monitor_section.tearoff(), false, false);
+                                       _monitor_section.set_session (_session);
+                                       _monitor_section.tearoff().show_all ();
 
-                                       _monitor_section->tearoff().Detach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_detached));
-                                       _monitor_section->tearoff().Attach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_attached));
+                                       _monitor_section.tearoff().Detach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_detached));
+                                       _monitor_section.tearoff().Attach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_attached));
 
-                                       if (_monitor_section->tearoff().torn_off()) {
+                                       if (_monitor_section.tearoff().torn_off()) {
                                                monitor_section_detached ();
                                        } else {
                                                monitor_section_attached ();
@@ -581,7 +603,12 @@ Mixer_UI::add_stripables (StripableList& slist)
 
                                show_strip (strip);
 
-                               if (!route->is_master()) {
+                               if (route->is_master()) {
+
+                                       out_packer.pack_start (*strip, false, false);
+                                       strip->set_packed (true);
+
+                               } else {
 
                                        TreeModel::Row row = *(track_model->insert (insert_iter));
 
@@ -589,11 +616,6 @@ Mixer_UI::add_stripables (StripableList& slist)
                                        row[stripable_columns.visible] = strip->marked_for_display();
                                        row[stripable_columns.stripable] = route;
                                        row[stripable_columns.strip] = strip;
-
-                               } else {
-
-                                       out_packer.pack_start (*strip, false, false);
-                                       strip->set_packed (true);
                                }
 
                                strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
@@ -629,16 +651,24 @@ Mixer_UI::deselect_all_strip_processors ()
 }
 
 void
-Mixer_UI::select_all_tracks ()
+Mixer_UI::select_none ()
 {
-       PublicEditor::instance().select_all_tracks ();
+       _selection.clear_routes();
+       deselect_all_strip_processors();
 }
 
 void
-Mixer_UI::select_none ()
+Mixer_UI::select_next_strip ()
+{
+       deselect_all_strip_processors();
+       _session->selection().select_next_stripable (true, false);
+}
+
+void
+Mixer_UI::select_prev_strip ()
 {
-       _selection.clear_routes();
        deselect_all_strip_processors();
+       _session->selection().select_prev_stripable (true, false);
 }
 
 void
@@ -901,15 +931,6 @@ Mixer_UI::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
        return 0;
 }
 
-struct MixerStripSorter {
-       bool operator() (const MixerStrip* ms_a, const MixerStrip* ms_b)
-       {
-               boost::shared_ptr<ARDOUR::Stripable> const& a = ms_a->stripable ();
-               boost::shared_ptr<ARDOUR::Stripable> const& b = ms_b->stripable ();
-               return ARDOUR::Stripable::Sorter(true)(a, b);
-       }
-};
-
 bool
 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
 {
@@ -1013,6 +1034,7 @@ void
 Mixer_UI::set_session (Session* sess)
 {
        SessionHandlePtr::set_session (sess);
+       _monitor_section.set_session (sess);
 
        if (_plugin_selector) {
                _plugin_selector->set_session (_session);
@@ -1020,10 +1042,6 @@ Mixer_UI::set_session (Session* sess)
 
        _group_tabs->set_session (sess);
 
-       if (_monitor_section) {
-               _monitor_section->set_session (_session);
-       }
-
        if (!_session) {
                _selection.clear ();
                return;
@@ -1048,6 +1066,7 @@ Mixer_UI::set_session (Session* sess)
        _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
 
        _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_masters, this, _1), gui_context());
+       _session->vca_manager().VCACreated.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::new_masters_created, this), gui_context());
 
        Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
 
@@ -1082,9 +1101,7 @@ Mixer_UI::session_going_away ()
                delete (*i);
        }
 
-       if (_monitor_section) {
-               _monitor_section->tearoff().hide_visible ();
-       }
+       _monitor_section.tearoff().hide_visible ();
 
        monitor_section_detached ();
 
@@ -1430,6 +1447,9 @@ Mixer_UI::redisplay_track_list ()
        if (ss) {
                boost::shared_ptr<VCA> sv = boost::dynamic_pointer_cast<VCA> (ss);
                if (sv) {
+                       if (_spill_scroll_position <= 0 && scroller.get_hscrollbar()) {
+                               _spill_scroll_position = scroller.get_hscrollbar()->get_adjustment()->get_value();
+                       }
                        spill_redisplay (sv);
                        return;
                }
@@ -1446,7 +1466,7 @@ Mixer_UI::redisplay_track_list ()
 
        add_vca_button.show ();
        vca_scroller_base.show();
-       
+
        for (i = rows.begin(); i != rows.end(); ++i) {
 
                AxisView* s = (*i)[stripable_columns.strip];
@@ -1500,14 +1520,35 @@ Mixer_UI::redisplay_track_list ()
        /* update visibility of VCA assign buttons */
 
        if (n_masters == 0) {
+               //show/hide the channelstrip VCA assign buttons on channelstrips:
                UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::remove_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
+
+               Glib::RefPtr<Action> act = ActionManager::get_action ("Mixer", "ToggleVCAPane");
+               if (act) {
+                       act->set_sensitive (false);
+               }
+
+               //remove the VCA packer, but don't change our prior setting for show/hide:
                vca_vpacker.hide ();
        } else {
+               //show/hide the channelstrip VCA assign buttons on channelstrips:
                UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::add_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
-               vca_vpacker.show ();
+
+               Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action ("Mixer", "ToggleVCAPane");
+               act->set_sensitive (true);
+
+               //if we were showing VCAs before, show them now:
+               showhide_vcas (act->get_active ());
        }
 
        _group_tabs->set_dirty ();
+
+       if (_spill_scroll_position > 0 && scroller.get_hscrollbar()) {
+               Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
+               adj->set_value (max (adj->get_lower(), min (adj->get_upper(), _spill_scroll_position)));
+       }
+       _spill_scroll_position = 0;
+
 }
 
 void
@@ -1556,18 +1597,7 @@ void
 Mixer_UI::initial_track_display ()
 {
        StripableList sl;
-
-       boost::shared_ptr<RouteList> routes = _session->get_routes();
-
-       for (RouteList::iterator r = routes->begin(); r != routes->end(); ++r) {
-               sl.push_back (*r);
-       }
-
-       VCAList vcas = _session->vca_manager().vcas();
-
-       for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
-               sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
-       }
+       _session->get_stripables (sl);
 
        sl.sort (PresentationInfoMixerSorter());
 
@@ -1611,15 +1641,56 @@ Mixer_UI::track_display_button_press (GdkEventButton* ev)
        return false;
 }
 
+void
+Mixer_UI::move_vca_into_view (boost::shared_ptr<ARDOUR::Stripable> s)
+{
+       if (!vca_scroller.get_hscrollbar()) {
+               return;
+       }
+
+       bool found = false;
+       int x0 = 0;
+       Gtk::Allocation alloc;
+
+       TreeModel::Children rows = track_model->children();
+       for (TreeModel::Children::const_iterator i = rows.begin(); i != rows.end(); ++i) {
+               AxisView* av = (*i)[stripable_columns.strip];
+               VCAMasterStrip* vms = dynamic_cast<VCAMasterStrip*> (av);
+               if (vms && vms->stripable () == s) {
+                       int y;
+                       found = true;
+                       vms->translate_coordinates (vca_hpacker, 0, 0, x0, y);
+                       alloc = vms->get_allocation ();
+                       break;
+               }
+       }
+
+       if (!found) {
+               return;
+       }
+
+       Adjustment* adj = vca_scroller.get_hscrollbar()->get_adjustment();
+
+       if (x0 < adj->get_value()) {
+               adj->set_value (max (adj->get_lower(), min (adj->get_upper(), (double) x0)));
+       } else if (x0 + alloc.get_width() >= adj->get_value() + adj->get_page_size()) {
+               int x1 = x0 + alloc.get_width() - adj->get_page_size();
+               adj->set_value (max (adj->get_lower(), min (adj->get_upper(), (double) x1)));
+       }
+}
+
 void
 Mixer_UI::move_stripable_into_view (boost::shared_ptr<ARDOUR::Stripable> s)
 {
        if (!scroller.get_hscrollbar()) {
                return;
        }
-       if (s->presentation_info().special () || s->presentation_info().flag_match (PresentationInfo::VCA)) {
+       if (s->presentation_info().special ()) {
                return;
        }
+       if (s->presentation_info().flag_match (PresentationInfo::VCA)) {
+               move_vca_into_view (s);
+       }
 #ifdef MIXBUS
        if (s->mixbus ()) {
                return;
@@ -1665,10 +1736,10 @@ Mixer_UI::build_track_menu ()
        items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
        items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
        items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
-       items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
-       items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
        items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::show_all_miditracks)));
        items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::hide_all_miditracks)));
+       items.push_back (MenuElem (_("Show All Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
+       items.push_back (MenuElem (_("Hide All Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
 
 }
 
@@ -1899,34 +1970,81 @@ Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange&
 }
 
 void
-Mixer_UI::show_mixer_list (bool yn)
+Mixer_UI::toggle_mixer_list ()
+{
+       Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action ("Mixer", "ToggleMixerList");
+       showhide_mixer_list (act->get_active());
+}
+
+void
+Mixer_UI::showhide_mixer_list (bool yn)
 {
        if (yn) {
                list_vpacker.show ();
        } else {
                list_vpacker.hide ();
        }
+}
 
-       _show_mixer_list = yn;
+void
+Mixer_UI::toggle_monitor_section ()
+{
+       Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action ("Mixer", "ToggleMonitorSection");
+       showhide_monitor_section (act->get_active());
 }
 
+
 void
-Mixer_UI::show_monitor_section (bool yn)
+Mixer_UI::showhide_monitor_section (bool yn)
 {
-       if (!monitor_section()) {
+       if (monitor_section().tearoff().torn_off()) {
                return;
        }
-       if (monitor_section()->tearoff().torn_off()) {
-               return;
+
+       if (yn) {
+               monitor_section().tearoff().show();
+       } else {
+               monitor_section().tearoff().hide();
        }
+}
+
+void
+Mixer_UI::toggle_vcas ()
+{
+       Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action ("Mixer", "ToggleVCAPane");
+       showhide_vcas (act->get_active());
+}
 
+void
+Mixer_UI::showhide_vcas (bool yn)
+{
        if (yn) {
-               monitor_section()->tearoff().show();
+               vca_vpacker.show();
        } else {
-               monitor_section()->tearoff().hide();
+               vca_vpacker.hide();
        }
 }
 
+#ifdef MIXBUS
+void
+Mixer_UI::toggle_mixbuses ()
+{
+       Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action ("Mixer", "ToggleMixbusPane");
+       showhide_mixbuses (act->get_active());
+}
+
+void
+Mixer_UI::showhide_mixbuses (bool on)
+{
+       if (on) {
+               mb_vpacker.show();
+       } else {
+               mb_vpacker.hide();
+       }
+}
+#endif
+
+
 void
 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
 {
@@ -2123,40 +2241,60 @@ Mixer_UI::set_state (const XMLNode& node, int version)
 
        node.get_property ("show-mixer", _visible);
 
-       if (node.get_property ("maximised", yn)) {
-               Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer"));
-               assert (act);
-               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
-               bool fs = tact && tact->get_active();
+       yn = false;
+       node.get_property ("maximised", yn);
+       {
+               Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action (X_("Common"), X_("ToggleMaximalMixer"));
+               bool fs = act && act->get_active();
                if (yn ^ fs) {
                        ActionManager::do_action ("Common", "ToggleMaximalMixer");
                }
        }
 
-       if (node.get_property ("show-mixer-list", yn)) {
-               Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMixerList"));
-               assert (act);
-               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+       yn = true;
+       node.get_property ("show-mixer-list", yn);
+       {
+               Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleMixerList"));
+               /* do it twice to force the change */
+               act->set_active (!yn);
+               act->set_active (yn);
+       }
 
+       yn = true;
+       node.get_property ("monitor-section-visible", yn);
+       {
+               Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleMonitorSection"));
                /* do it twice to force the change */
-               tact->set_active (!yn);
-               tact->set_active (yn);
+               act->set_active (!yn);
+               act->set_active (yn);
        }
 
-       if (node.get_property ("monitor-section-visible", yn)) {
-               Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
-               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+       yn = true;
+       node.get_property ("show-vca-pane", yn);
+       {
+               Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleVCAPane"));
                /* do it twice to force the change */
-               tact->set_active (yn);
-               show_monitor_section (yn);
+               act->set_active (!yn);
+               act->set_active (yn);
        }
 
+#ifdef MIXBUS
+       yn = true;
+       node.get_property ("show-mixbus-pane", yn);
+       {
+               Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleMixbusPane"));
+               /* do it twice to force the change */
+               act->set_active (!yn);
+               act->set_active (yn);
+       }
+#endif
 
-       XMLNode* plugin_order;
-       if ((plugin_order = find_named_node (node, "PluginOrder")) != 0) {
+       //check for the user's plugin_order file
+       XMLNode plugin_order_new(X_("PO"));
+       if (PluginManager::instance().load_plugin_order_file(plugin_order_new)) {
                store_current_favorite_order ();
                std::list<string> order;
-               const XMLNodeList& kids = plugin_order->children("PluginInfo");
+               const XMLNodeList& kids = plugin_order_new.children("PluginInfo");
                XMLNodeConstIterator i;
                for (i = kids.begin(); i != kids.end(); ++i) {
                        std::string unique_id;
@@ -2170,10 +2308,59 @@ Mixer_UI::set_state (const XMLNode& node, int version)
                PluginStateSorter cmp (order);
                favorite_order.sort (cmp);
                sync_treeview_from_favorite_order ();
+
+       } else {
+               //if there is no user file, then use an existing one from instant.xml
+               //NOTE: if you are loading an old session, this might come from the session's instant.xml
+               //Todo:  in the next major version, we should probably stop doing the instant.xml check, and just use the new file
+               XMLNode* plugin_order;
+               if ((plugin_order = find_named_node (node, "PluginOrder")) != 0) {
+                       store_current_favorite_order ();
+                       std::list<string> order;
+                       const XMLNodeList& kids = plugin_order->children("PluginInfo");
+                       XMLNodeConstIterator i;
+                       for (i = kids.begin(); i != kids.end(); ++i) {
+                               std::string unique_id;
+                               if ((*i)->get_property ("unique-id", unique_id)) {
+                                       order.push_back (unique_id);
+                                       if ((*i)->get_property ("expanded", yn)) {
+                                               favorite_ui_state[unique_id] = yn;
+                                       }
+                               }
+                       }
+
+                       PluginStateSorter cmp (order);
+                       favorite_order.sort (cmp);
+                       sync_treeview_from_favorite_order ();
+               }
        }
+
        return 0;
 }
 
+void
+Mixer_UI::save_plugin_order_file ()
+{
+       //this writes the plugin order to the user's preference file ( plugin_metadata/plugin_order )
+
+       //NOTE:  this replaces the old code that stores info in instant.xml
+       //why?  because instant.xml prefers the per-session settings, and we want this to be a global pref
+
+       store_current_favorite_order ();
+       XMLNode plugin_order ("PluginOrder");
+       uint32_t cnt = 0;
+       for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i, ++cnt) {
+               XMLNode* p = new XMLNode ("PluginInfo");
+               p->set_property ("sort", cnt);
+               p->set_property ("unique-id", (*i)->unique_id);
+               if (favorite_ui_state.find ((*i)->unique_id) != favorite_ui_state.end ()) {
+                       p->set_property ("expanded", favorite_ui_state[(*i)->unique_id]);
+               }
+               plugin_order.add_child_nocopy (*p);
+       }
+       PluginManager::instance().save_plugin_order_file( plugin_order );
+}
+
 XMLNode&
 Mixer_UI::get_state ()
 {
@@ -2188,27 +2375,21 @@ Mixer_UI::get_state ()
 
        node->set_property ("narrow-strips", (_strip_width == Narrow));
        node->set_property ("show-mixer", _visible);
-       node->set_property ("show-mixer-list", _show_mixer_list);
        node->set_property ("maximised", _maximised);
 
-       Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
-       Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
-       assert (tact);
-       node->set_property ("monitor-section-visible", tact->get_active ());
+       Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action ("Mixer", "ToggleMixerList");
+       node->set_property ("show-mixer-list", act->get_active ());
 
-       store_current_favorite_order ();
-       XMLNode* plugin_order = new XMLNode ("PluginOrder");
-       uint32_t cnt = 0;
-       for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i, ++cnt) {
-               XMLNode* p = new XMLNode ("PluginInfo");
-               p->set_property ("sort", cnt);
-               p->set_property ("unique-id", (*i)->unique_id);
-               if (favorite_ui_state.find ((*i)->unique_id) != favorite_ui_state.end ()) {
-                       p->set_property ("expanded", favorite_ui_state[(*i)->unique_id]);
-               }
-               plugin_order->add_child_nocopy (*p);
-       }
-       node->add_child_nocopy (*plugin_order);
+       act = ActionManager::get_toggle_action ("Mixer", "ToggleMonitorSection");
+       node->set_property ("monitor-section-visible", act->get_active ());
+
+       act = ActionManager::get_toggle_action ("Mixer", "ToggleVCAPane");
+       node->set_property ("show-vca-pane", act->get_active ());
+
+#ifdef MIXBUS
+       act = ActionManager::get_toggle_action ("Mixer", "ToggleMixbusPane");
+       node->set_property ("show-mixbus-pane", act->get_active ());
+#endif
 
        return *node;
 }
@@ -2231,6 +2412,11 @@ Mixer_UI::scroll_left ()
                if (i->get_widget() == & add_button) {
                        continue;
                }
+#ifdef MIXBUS
+               if (i->get_widget() == &mb_shadow) {
+                       continue;
+               }
+#endif
                lm += i->get_widget()->get_width ();
                if (lm >= lp) {
                        lm -= i->get_widget()->get_width ();
@@ -2258,6 +2444,11 @@ Mixer_UI::scroll_right ()
                if (i->get_widget() == & add_button) {
                        continue;
                }
+#ifdef MIXBUS
+               if (i->get_widget() == &mb_shadow) {
+                       continue;
+               }
+#endif
                lm += i->get_widget()->get_width ();
                if (lm > lp + 1) {
                        break;
@@ -2295,6 +2486,87 @@ Mixer_UI::on_scroll_event (GdkEventScroll* ev)
        return false;
 }
 
+void
+Mixer_UI::vca_scroll_left ()
+{
+       if (!vca_scroller.get_hscrollbar()) return;
+       Adjustment* adj = vca_scroller.get_hscrollbar()->get_adjustment();
+       int sc_w = vca_scroller.get_width();
+       int sp_w = strip_packer.get_width();
+       if (sp_w <= sc_w) {
+               return;
+       }
+       int lp = adj->get_value();
+       int lm = 0;
+       using namespace Gtk::Box_Helpers;
+       const BoxList& strips = vca_hpacker.children();
+       for (BoxList::const_iterator i = strips.begin(); i != strips.end(); ++i) {
+               if (i->get_widget() == &add_vca_button) {
+                       continue;
+               }
+               lm += i->get_widget()->get_width ();
+               if (lm >= lp) {
+                       lm -= i->get_widget()->get_width ();
+                       break;
+               }
+       }
+       vca_scroller.get_hscrollbar()->set_value (max (adj->get_lower(), min (adj->get_upper(), lm - 1.0)));
+}
+
+void
+Mixer_UI::vca_scroll_right ()
+{
+       if (!vca_scroller.get_hscrollbar()) return;
+       Adjustment* adj = vca_scroller.get_hscrollbar()->get_adjustment();
+       int sc_w = vca_scroller.get_width();
+       int sp_w = strip_packer.get_width();
+       if (sp_w <= sc_w) {
+               return;
+       }
+       int lp = adj->get_value();
+       int lm = 0;
+       using namespace Gtk::Box_Helpers;
+       const BoxList& strips = vca_hpacker.children();
+       for (BoxList::const_iterator i = strips.begin(); i != strips.end(); ++i) {
+               if (i->get_widget() == &add_vca_button) {
+                       continue;
+               }
+               lm += i->get_widget()->get_width ();
+               if (lm > lp + 1) {
+                       break;
+               }
+       }
+       vca_scroller.get_hscrollbar()->set_value (max (adj->get_lower(), min (adj->get_upper(), lm - 1.0)));
+}
+
+bool
+Mixer_UI::on_vca_scroll_event (GdkEventScroll* ev)
+{
+       switch (ev->direction) {
+       case GDK_SCROLL_LEFT:
+               vca_scroll_left ();
+               return true;
+       case GDK_SCROLL_UP:
+               if (ev->state & Keyboard::TertiaryModifier) {
+                       vca_scroll_left ();
+                       return true;
+               }
+               return false;
+
+       case GDK_SCROLL_RIGHT:
+               vca_scroll_right ();
+               return true;
+
+       case GDK_SCROLL_DOWN:
+               if (ev->state & Keyboard::TertiaryModifier) {
+                       vca_scroll_right ();
+                       return true;
+               }
+               return false;
+       }
+
+       return false;
+}
 
 void
 Mixer_UI::parameter_changed (string const & p)
@@ -2448,29 +2720,27 @@ Mixer_UI::set_axis_targets_for_operation ()
 void
 Mixer_UI::monitor_section_going_away ()
 {
-       if (_monitor_section) {
-               XMLNode* ui_node = Config->extra_xml(X_("UI"));
-               /* immediate state save.
-                *
-                * Tearoff settings are otherwise only stored during
-                * save_ardour_state(). The mon-section may or may not
-                * exist at that point.
-                * */
-               if (ui_node) {
-                       XMLNode* tearoff_node = ui_node->child (X_("Tearoffs"));
-                       if (tearoff_node) {
-                               tearoff_node->remove_nodes_and_delete (X_("monitor-section"));
-                               XMLNode* t = new XMLNode (X_("monitor-section"));
-                               _monitor_section->tearoff().add_state (*t);
-                               tearoff_node->add_child_nocopy (*t);
-                       }
+       XMLNode* ui_node = Config->extra_xml(X_("UI"));
+
+       /* immediate state save.
+        *
+        * Tearoff settings are otherwise only stored during
+        * save_ardour_state(). The mon-section may or may not
+        * exist at that point.
+        */
+
+       if (ui_node) {
+               XMLNode* tearoff_node = ui_node->child (X_("Tearoffs"));
+               if (tearoff_node) {
+                       tearoff_node->remove_nodes_and_delete (X_("monitor-section"));
+                       XMLNode* t = new XMLNode (X_("monitor-section"));
+                       _monitor_section.tearoff().add_state (*t);
+                       tearoff_node->add_child_nocopy (*t);
                }
-               monitor_section_detached ();
-               out_packer.remove (_monitor_section->tearoff());
-               _monitor_section->set_session (0);
-               delete _monitor_section;
-               _monitor_section = 0;
        }
+
+       monitor_section_detached ();
+       out_packer.remove (_monitor_section.tearoff());
 }
 
 void
@@ -2526,16 +2796,15 @@ Mixer_UI::restore_mixer_space ()
 void
 Mixer_UI::monitor_section_attached ()
 {
-       Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
-       Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+       Glib::RefPtr<ToggleAction> act = ActionManager::get_toggle_action ("Mixer", "ToggleMonitorSection");
        act->set_sensitive (true);
-       show_monitor_section (tact->get_active ());
+       showhide_monitor_section (act->get_active ());
 }
 
 void
 Mixer_UI::monitor_section_detached ()
 {
-       Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
+       Glib::RefPtr<Action> act = ActionManager::get_action ("Mixer", "ToggleMonitorSection");
        act->set_sensitive (false);
 }
 
@@ -2708,6 +2977,9 @@ Mixer_UI::sync_treeview_from_favorite_order ()
 
                vector<ARDOUR::Plugin::PresetRecord> presets = (*i)->get_presets (true);
                for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator j = presets.begin(); j != presets.end(); ++j) {
+                       if (!(*j).user) {
+                               continue;
+                       }
                        Gtk::TreeModel::Row child_row = *(favorite_plugins_model->append (newrow.children()));
                        child_row[favorite_plugins_columns.name] = (*j).label;
                        child_row[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip, &(*j)));
@@ -2725,7 +2997,7 @@ Mixer_UI::popup_note_context_menu (GdkEventButton *ev)
 {
        using namespace Gtk::Menu_Helpers;
 
-       Gtk::Menu* m = manage (new Menu);
+       Gtk::Menu* m = ARDOUR_UI::instance()->shared_popup_menu ();
        MenuList& items = m->items ();
 
        if (_selection.axes.empty()) {
@@ -2984,48 +3256,52 @@ Mixer_UI::showing_spill_for (boost::shared_ptr<Stripable> s) const
        return s == spilled_strip.lock();
 }
 
-void
-Mixer_UI::show_editor_window () const
-{
-       PublicEditor::instance().make_visible ();
-}
-
 void
 Mixer_UI::register_actions ()
 {
-       Glib::RefPtr<ActionGroup> group = myactions.create_action_group (X_("Mixer"));
+       Glib::RefPtr<ActionGroup> group = ActionManager::create_action_group (bindings, X_("Mixer"));
 
-       myactions.register_action (group, "show-editor", _("Show Editor"), sigc::mem_fun (*this, &Mixer_UI::show_editor_window));
+       ActionManager::register_action (group, "solo", _("Toggle Solo on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::solo_action));
+       ActionManager::register_action (group, "mute", _("Toggle Mute on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::mute_action));
+       ActionManager::register_action (group, "recenable", _("Toggle Rec-enable on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::rec_enable_action));
+       ActionManager::register_action (group, "increment-gain", _("Decrease Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::step_gain_up_action));
+       ActionManager::register_action (group, "decrement-gain", _("Increase Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::step_gain_down_action));
+       ActionManager::register_action (group, "unity-gain", _("Set Gain to 0dB on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::unity_gain_action));
 
-       myactions.register_action (group, "solo", _("Toggle Solo on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::solo_action));
-       myactions.register_action (group, "mute", _("Toggle Mute on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::mute_action));
-       myactions.register_action (group, "recenable", _("Toggle Rec-enable on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::rec_enable_action));
-       myactions.register_action (group, "increment-gain", _("Decrease Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::step_gain_up_action));
-       myactions.register_action (group, "decrement-gain", _("Increase Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::step_gain_down_action));
-       myactions.register_action (group, "unity-gain", _("Set Gain to 0dB on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::unity_gain_action));
 
+       ActionManager::register_action (group, "copy-processors", _("Copy Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::copy_processors));
+       ActionManager::register_action (group, "cut-processors", _("Cut Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::cut_processors));
+       ActionManager::register_action (group, "paste-processors", _("Paste Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::paste_processors));
+       ActionManager::register_action (group, "delete-processors", _("Delete Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::delete_processors));
+       ActionManager::register_action (group, "select-all-processors", _("Select All (visible) Processors"), sigc::mem_fun (*this, &Mixer_UI::select_all_processors));
+       ActionManager::register_action (group, "toggle-processors", _("Toggle Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::toggle_processors));
+       ActionManager::register_action (group, "ab-plugins", _("Toggle Selected Plugins"), sigc::mem_fun (*this, &Mixer_UI::ab_plugins));
+       ActionManager::register_action (group, "select-none", _("Deselect all strips and processors"), sigc::mem_fun (*this, &Mixer_UI::select_none));
 
-       myactions.register_action (group, "copy-processors", _("Copy Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::copy_processors));
-       myactions.register_action (group, "cut-processors", _("Cut Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::cut_processors));
-       myactions.register_action (group, "paste-processors", _("Paste Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::paste_processors));
-       myactions.register_action (group, "delete-processors", _("Delete Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::delete_processors));
-       myactions.register_action (group, "select-all-processors", _("Select All (visible) Processors"), sigc::mem_fun (*this, &Mixer_UI::select_all_processors));
-       myactions.register_action (group, "toggle-processors", _("Toggle Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::toggle_processors));
-       myactions.register_action (group, "ab-plugins", _("Toggle Selected Plugins"), sigc::mem_fun (*this, &Mixer_UI::ab_plugins));
-       myactions.register_action (group, "select-none", _("Deselect all strips and processors"), sigc::mem_fun (*this, &Mixer_UI::select_none));
-       myactions.register_action (group, "select-all-tracks", _("Select All Tracks"), sigc::mem_fun (*this, &Mixer_UI::select_all_tracks));
+       ActionManager::register_action (group, "select-next-stripable", _("Select Next Mixer Strip"), sigc::mem_fun (*this, &Mixer_UI::select_next_strip));
+       ActionManager::register_action (group, "select-prev-stripable", _("Scroll Previous Mixer Strip"), sigc::mem_fun (*this, &Mixer_UI::select_prev_strip));
 
-       myactions.register_action (group, "scroll-left", _("Scroll Mixer Window to the left"), sigc::mem_fun (*this, &Mixer_UI::scroll_left));
-       myactions.register_action (group, "scroll-right", _("Scroll Mixer Window to the right"), sigc::mem_fun (*this, &Mixer_UI::scroll_right));
+       ActionManager::register_action (group, "scroll-left", _("Scroll Mixer Window to the left"), sigc::mem_fun (*this, &Mixer_UI::scroll_left));
+       ActionManager::register_action (group, "scroll-right", _("Scroll Mixer Window to the right"), sigc::mem_fun (*this, &Mixer_UI::scroll_right));
 
-       myactions.register_action (group, "toggle-midi-input-active", _("Toggle MIDI Input Active for Mixer-Selected Tracks/Busses"),
+       ActionManager::register_action (group, "toggle-midi-input-active", _("Toggle MIDI Input Active for Mixer-Selected Tracks/Busses"),
                                   sigc::bind (sigc::mem_fun (*this, &Mixer_UI::toggle_midi_input_active), false));
+
+       ActionManager::register_toggle_action (group, X_("ToggleMixerList"), _("Mixer: Show Mixer List"), sigc::mem_fun (*this, &Mixer_UI::toggle_mixer_list));
+
+       ActionManager::register_toggle_action (group, X_("ToggleVCAPane"), _("Mixer: Show VCAs"), sigc::mem_fun (*this, &Mixer_UI::toggle_vcas));
+
+#ifdef MIXBUS
+       ActionManager::register_toggle_action (group, X_("ToggleMixbusPane"), _("Mixer: Show Mixbusses"), sigc::mem_fun (*this, &Mixer_UI::toggle_mixbuses));
+#endif
+
+       ActionManager::register_toggle_action (group, X_("ToggleMonitorSection"), _("Mixer: Show Monitor Section"), sigc::mem_fun (*this, &Mixer_UI::toggle_monitor_section));
 }
 
 void
 Mixer_UI::load_bindings ()
 {
-       bindings = Bindings::get_bindings (X_("Mixer"), myactions);
+       bindings = Bindings::get_bindings (X_("Mixer"));
 }
 
 template<class T> void