start using ActionMap in preference to ActionManager
[ardour.git] / gtk2_ardour / mixer_ui.cc
index 209644c5d1d15a514ff4241e4e30a6421179d119..07193c3286912ac723f3834a47ce682662a9ae5a 100644 (file)
@@ -100,19 +100,20 @@ Mixer_UI::instance ()
 
 Mixer_UI::Mixer_UI ()
        : Tabbable (_content, _("Mixer"))
+       , ActionMapOwner (X_("mixer"))
        , 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 ();
@@ -135,8 +136,31 @@ Mixer_UI::Mixer_UI ()
        scroller_base.drag_dest_set (target_table);
        scroller_base.signal_drag_data_received().connect (sigc::mem_fun(*this, &Mixer_UI::scroller_drag_data_received));
 
-       // add as last item of strip packer
+       /* create a button to add VCA strips ... will get packed in redisplay_track_list() */
+       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);
@@ -188,37 +212,13 @@ Mixer_UI::Mixer_UI ()
        group_display_scroller.add (group_display);
        group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
 
-       HBox* route_group_display_button_box = manage (new HBox());
-
-       Button* route_group_add_button = manage (new Button ());
-       Button* route_group_remove_button = manage (new Button ());
-
-       Widget* w;
-
-       w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
-       w->show();
-       route_group_add_button->add (*w);
-
-       w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
-       w->show();
-       route_group_remove_button->add (*w);
-
-       route_group_display_button_box->set_homogeneous (true);
-
-       route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
-       route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
-
-       route_group_display_button_box->add (*route_group_add_button);
-       route_group_display_button_box->add (*route_group_remove_button);
 
        group_display_vbox.pack_start (group_display_scroller, true, true);
-       group_display_vbox.pack_start (*route_group_display_button_box, false, false);
 
        group_display_frame.set_name ("BaseFrame");
        group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
        group_display_frame.add (group_display_vbox);
 
-
        list<TargetEntry> target_list;
        target_list.push_back (TargetEntry ("PluginPresetPtr"));
 
@@ -231,7 +231,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);
@@ -240,6 +239,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);
@@ -267,7 +269,6 @@ Mixer_UI::Mixer_UI ()
        vca_scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
        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.pack_end (vca_scroller_base, true, true);
 
        vca_scroller.add (vca_hpacker);
        vca_scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
@@ -284,7 +285,7 @@ Mixer_UI::Mixer_UI ()
        list_hpane.set_check_divider_position (true);
        list_hpane.add (list_vpacker);
        list_hpane.add (global_hpacker);
-       list_hpane.set_child_minsize (list_vpacker, 1);
+       list_hpane.set_child_minsize (list_vpacker, 30);
 
        XMLNode const * settings = ARDOUR_UI::instance()->mixer_settings();
        float fract;
@@ -318,10 +319,6 @@ Mixer_UI::Mixer_UI ()
 
        update_title ();
 
-       route_group_display_button_box->show();
-       route_group_add_button->show();
-       route_group_remove_button->show();
-
        _content.show ();
        _content.set_name ("MixerWindow");
 
@@ -332,7 +329,6 @@ Mixer_UI::Mixer_UI ()
        mixer_scroller_vpacker.show();
        list_vpacker.show();
        group_display_button_label.show();
-       group_display_button.show();
        group_display_scroller.show();
        favorite_plugins_scroller.show();
        group_display_vbox.show();
@@ -352,6 +348,7 @@ Mixer_UI::Mixer_UI ()
        list_hpane.show();
        group_display.show();
        favorite_plugins_display.show();
+       add_button.show ();
 
        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());
@@ -365,11 +362,10 @@ Mixer_UI::Mixer_UI ()
 #else
 #error implement deferred Plugin-Favorite list
 #endif
-       PluginManager::instance ().PluginListChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
-       PluginManager::instance ().PluginStatusesChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::plugin_status_changed, this, _1, _2, _3), gui_context());
-       ARDOUR::Plugin::PresetsChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
 
-       PluginManager::instance ().PluginTagsChanged.connect(*this, invalidator (*this), boost::bind (&Mixer_UI::tags_changed, this, _1, _2, _3), gui_context());
+       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 ()
@@ -382,6 +378,16 @@ Mixer_UI::~Mixer_UI ()
        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 ()
 {
@@ -599,7 +605,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));
 
@@ -607,11 +618,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));
@@ -647,16 +653,24 @@ Mixer_UI::deselect_all_strip_processors ()
 }
 
 void
-Mixer_UI::select_all_tracks ()
+Mixer_UI::select_none ()
+{
+       _selection.clear_routes();
+       deselect_all_strip_processors();
+}
+
+void
+Mixer_UI::select_next_strip ()
 {
-       PublicEditor::instance().select_all_tracks ();
+       deselect_all_strip_processors();
+       _session->selection().select_next_stripable (true, false);
 }
 
 void
-Mixer_UI::select_none ()
+Mixer_UI::select_prev_strip ()
 {
-       _selection.clear_routes();
        deselect_all_strip_processors();
+       _session->selection().select_prev_stripable (true, false);
 }
 
 void
@@ -919,15 +933,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)
 {
@@ -1448,6 +1453,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;
                }
@@ -1458,7 +1466,12 @@ Mixer_UI::redisplay_track_list ()
        uint32_t n_masters = 0;
 
        container_clear (vca_hpacker);
+
        vca_hpacker.pack_end (vca_scroller_base, true, true);
+       vca_hpacker.pack_end (add_vca_button, false, false);
+
+       add_vca_button.show ();
+       vca_scroller_base.show();
 
        for (i = rows.begin(); i != rows.end(); ++i) {
 
@@ -1515,12 +1528,32 @@ Mixer_UI::redisplay_track_list ()
        if (n_masters == 0) {
                UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::remove_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
                vca_vpacker.hide ();
+               Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleVCAPane");
+               if (act) {
+                       act->set_sensitive (false);
+               }
+
        } else {
                UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::add_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
-               vca_vpacker.show ();
+
+               Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleVCAPane");
+               if (act) {
+                       act->set_sensitive (true);
+                       Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+                       showhide_vcas (tact->get_active());
+               } else {
+                       vca_vpacker.show ();
+               }
        }
 
        _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
@@ -1569,18 +1602,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());
 
@@ -1678,10 +1700,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)));
 
 }
 
@@ -2164,12 +2186,12 @@ Mixer_UI::set_state (const XMLNode& node, int version)
                show_monitor_section (yn);
        }
 
-
-       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;
@@ -2183,10 +2205,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 ()
 {
@@ -2209,20 +2280,6 @@ Mixer_UI::get_state ()
        assert (tact);
        node->set_property ("monitor-section-visible", tact->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);
-
        return *node;
 }
 
@@ -2241,6 +2298,14 @@ Mixer_UI::scroll_left ()
        using namespace Gtk::Box_Helpers;
        const BoxList& strips = strip_packer.children();
        for (BoxList::const_iterator i = strips.begin(); i != strips.end(); ++i) {
+               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 ();
@@ -2265,6 +2330,14 @@ Mixer_UI::scroll_right ()
        using namespace Gtk::Box_Helpers;
        const BoxList& strips = strip_packer.children();
        for (BoxList::const_iterator i = strips.begin(); i != strips.end(); ++i) {
+               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;
@@ -2373,16 +2446,6 @@ Mixer_UI::setup_track_display ()
        v->show ();
        v->pack_start (track_display_scroller, true, true);
 
-       Button* b = manage (new Button);
-       b->show ();
-       Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
-       w->show ();
-       b->add (*w);
-
-       b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
-
-       v->pack_start (*b, false, false);
-
        track_display_frame.set_name("BaseFrame");
        track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
        track_display_frame.add (*v);
@@ -2667,18 +2730,12 @@ Mixer_UI::refill_favorite_plugins ()
 }
 
 void
-Mixer_UI::plugin_status_changed (PluginType, std::string, PluginManager::PluginStatusType)
+Mixer_UI::plugin_list_changed ()
 {
        refill_favorite_plugins();
        refill_tag_combo();
 }
 
-void
-Mixer_UI::tags_changed (PluginType t, std::string unique_id, std::string tag)
-{
-       refill_tag_combo();
-}
-
 void
 Mixer_UI::refill_tag_combo ()
 {
@@ -3036,7 +3093,9 @@ Mixer_UI::register_actions ()
        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));
+
+       myactions.register_action (group, "select-next-stripable", _("Select Next Mixer Strip"), sigc::mem_fun (*this, &Mixer_UI::select_next_strip));
+       myactions.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));