quick hack: hide unfinished processor sidebar for 4.5 release
[ardour.git] / gtk2_ardour / mixer_ui.cc
index e28fb40edfa1c5d07fc139e9651574d7e9a8b567..f0dc9ee254879744cafd0529cd1e4ec6158b8a6e 100644 (file)
@@ -43,6 +43,7 @@
 #include "ardour/route_group.h"
 #include "ardour/route_sorters.h"
 #include "ardour/session.h"
+#include "ardour/revision.h" // XXX remove after 4.5 release
 
 #include "keyboard.h"
 #include "mixer_ui.h"
@@ -100,6 +101,7 @@ Mixer_UI::Mixer_UI ()
         , _route_deletion_in_progress (false)
        , _following_editor_selection (false)
        , _maximised (false)
+       , _show_mixer_list (true)
 {
        /* allow this window to become the key focus window */
        set_flags (CAN_FOCUS);
@@ -192,23 +194,47 @@ Mixer_UI::Mixer_UI ()
        group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
        group_display_frame.add (group_display_vbox);
 
-       rhs_pane1.pack1 (track_display_frame);
-       rhs_pane1.pack2 (group_display_frame);
+       favorite_plugins_model = ListStore::create (favorite_plugins_columns);
+       favorite_plugins_display.set_model (favorite_plugins_model);
+       favorite_plugins_display.append_column (_("Favorite Plugins"), favorite_plugins_columns.name);
+       favorite_plugins_display.set_name ("EditGroupList");
+       favorite_plugins_display.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE); // XXX needs focus/keyboard
+       favorite_plugins_display.set_reorderable (false); // ?!
+       favorite_plugins_display.set_headers_visible (true);
+       favorite_plugins_display.set_rules_hint (true);
+       favorite_plugins_display.set_can_focus (false);
+       favorite_plugins_display.add_object_drag (favorite_plugins_columns.plugin.index(), "PluginInfoPtr");
+
+       favorite_plugins_scroller.add (favorite_plugins_display);
+       favorite_plugins_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+
+       favorite_plugins_frame.set_name ("BaseFrame");
+       favorite_plugins_frame.set_shadow_type (Gtk::SHADOW_IN);
+       favorite_plugins_frame.add (favorite_plugins_scroller);
+
+       //  XXX remove after 4.5 release
+       if (!strcmp (ARDOUR::revision, "4.5") || strcmp (PROGRAM_NAME, "Ardour")) {
+               rhs_pane2.pack1 (track_display_frame);
+               rhs_pane2.pack2 (group_display_frame);
+       } else {
+               rhs_pane1.pack1 (favorite_plugins_frame, false, true);
+               rhs_pane1.pack2 (track_display_frame);
+               rhs_pane2.pack1 (rhs_pane1);
+               rhs_pane2.pack2 (group_display_frame);
+       }
 
-       list_vpacker.pack_start (rhs_pane1, true, true);
+       list_vpacker.pack_start (rhs_pane2, true, true);
 
        global_hpacker.pack_start (scroller, true, true);
-#ifdef GTKOSX
-       /* current gtk-quartz has dirty updates on borders like this one */
        global_hpacker.pack_start (out_packer, false, false, 0);
-#else
-       global_hpacker.pack_start (out_packer, false, false, 12);
-#endif
+
        list_hpane.pack1(list_vpacker, false, true);
        list_hpane.pack2(global_hpacker, true, false);
 
        rhs_pane1.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
                                                        static_cast<Gtk::Paned*> (&rhs_pane1)));
+       rhs_pane2.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
+                                                       static_cast<Gtk::Paned*> (&rhs_pane2)));
        list_hpane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
                                                         static_cast<Gtk::Paned*> (&list_hpane)));
 
@@ -240,24 +266,34 @@ Mixer_UI::Mixer_UI ()
        group_display_button_label.show();
        group_display_button.show();
        group_display_scroller.show();
+       favorite_plugins_scroller.show();
        group_display_vbox.show();
        group_display_frame.show();
+       favorite_plugins_frame.show();
        rhs_pane1.show();
+       rhs_pane2.show();
        strip_packer.show();
        out_packer.show();
        list_hpane.show();
        group_display.show();
+       favorite_plugins_display.show();
 
        MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context());
 
 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
        _plugin_selector = new PluginSelector (PluginManager::instance ());
+#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::refill_favorite_plugins, this), gui_context());
+       refill_favorite_plugins();
 }
 
 Mixer_UI::~Mixer_UI ()
 {
        if (_monitor_section) {
+               monitor_section_detached ();
                delete _monitor_section;
        }
        delete _plugin_selector;
@@ -363,6 +399,11 @@ Mixer_UI::add_strips (RouteList& routes)
                                _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_attached ();
+
                                route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
 
                                /* no regular strip shown for control out */
@@ -802,9 +843,11 @@ Mixer_UI::session_going_away ()
                delete (*i);
        }
 
-        if (_monitor_section) {
-                _monitor_section->tearoff().hide_visible ();
-        }
+       if (_monitor_section) {
+               _monitor_section->tearoff().hide_visible ();
+       }
+
+       monitor_section_detached ();
 
        strips.clear ();
 
@@ -1429,6 +1472,40 @@ Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange&
        }
 }
 
+void
+Mixer_UI::show_mixer_list (bool yn)
+{
+       if (yn) {
+               list_vpacker.show ();
+               
+               //if user wants to show the pane, we should make sure that it is wide enough to be visible 
+               int width = list_hpane.get_position();
+               if (width < 40)
+                       list_hpane.set_position(40);
+       } else {
+               list_vpacker.hide ();
+       }
+       
+       _show_mixer_list = yn;
+}
+
+void
+Mixer_UI::show_monitor_section (bool yn)
+{
+       if (!monitor_section()) {
+               return;
+       }
+       if (monitor_section()->tearoff().torn_off()) {
+               return;
+       }
+
+       if (yn) {
+               monitor_section()->tearoff().show();
+       } else {
+               monitor_section()->tearoff().hide();
+       }
+}
+
 void
 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
 {
@@ -1561,13 +1638,36 @@ Mixer_UI::set_window_pos_and_size ()
        move (m_root_x, m_root_y);
 }
 
-       void
+void
 Mixer_UI::get_window_pos_and_size ()
 {
        get_position(m_root_x, m_root_y);
        get_size(m_width, m_height);
 }
 
+struct PluginStateSorter {
+public:
+       bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
+               std::list<std::string>::const_iterator aiter = std::find(_user.begin(), _user.end(), (*a).unique_id);
+               std::list<std::string>::const_iterator biter = std::find(_user.begin(), _user.end(), (*b).unique_id);
+               if (aiter != _user.end() && biter != _user.end()) {
+                       return std::distance (_user.begin(), aiter)  < std::distance (_user.begin(), biter);
+               }
+               if (aiter != _user.end()) {
+                       return true;
+               }
+               if (biter != _user.end()) {
+                       return false;
+               }
+               printf("BITTER\n");
+               return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
+       }
+
+       PluginStateSorter(std::list<std::string> user) : _user (user)  {}
+private:
+       std::list<std::string> _user;
+};
+
 int
 Mixer_UI::set_state (const XMLNode& node)
 {
@@ -1639,6 +1739,33 @@ Mixer_UI::set_state (const XMLNode& node)
                }
        }
 
+       if ((prop = node.property ("show-mixer-list"))) {
+               bool yn = string_is_affirmative (prop->value());
+               Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMixerList"));
+               assert (act);
+               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+
+               /* do it twice to force the change */
+               tact->set_active (!yn);
+               tact->set_active (yn);
+       }
+
+       XMLNode* plugin_order;
+       if ((plugin_order = find_named_node (node, "PluginOrder")) != 0) {
+               std::list<string> order;
+               const XMLNodeList& kids = plugin_order->children("PluginInfo");
+               XMLNodeConstIterator i;
+               for (i = kids.begin(); i != kids.end(); ++i) {
+                       if ((prop = (*i)->property ("unique-id"))) {
+                               order.push_back (prop->value());
+                       }
+               }
+
+               store_current_favorite_order ();
+               PluginStateSorter cmp (order);
+               favorite_order.sort (cmp);
+               sync_treeview_from_favorite_order ();
+       }
 
        return 0;
 }
@@ -1672,6 +1799,8 @@ Mixer_UI::get_state (void)
 
                snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
                geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
+               snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane2)->gobj()));
+               geometry->add_property(X_("mixer_rhs_pane2_pos"), string(buf));
                snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
                geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
 
@@ -1682,8 +1811,21 @@ Mixer_UI::get_state (void)
 
        node->add_property ("show-mixer", _visible ? "yes" : "no");
 
+       node->add_property ("show-mixer-list", _show_mixer_list ? "yes" : "no");
+
        node->add_property ("maximised", _maximised ? "yes" : "no");
 
+       store_current_favorite_order ();
+       XMLNode* plugin_order = new XMLNode ("PluginOrder");
+       int cnt = 0;
+       for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i, ++cnt) {
+                       XMLNode* p = new XMLNode ("PluginInfo");
+                       p->add_property ("sort", cnt);
+                       p->add_property ("unique-id", (*i)->unique_id);
+                       plugin_order->add_child_nocopy (*p);
+               ;
+       }
+       node->add_child_nocopy (*plugin_order);
        return *node;
 }
 
@@ -1693,7 +1835,6 @@ Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
 {
        int pos;
        XMLProperty* prop = 0;
-       char buf[32];
        XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
        XMLNode* geometry;
        int height;
@@ -1719,7 +1860,6 @@ Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
 
                if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
                        pos = height / 3;
-                       snprintf (buf, sizeof(buf), "%d", pos);
                } else {
                        pos = atoi (prop->value());
                }
@@ -1728,18 +1868,30 @@ Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
                        rhs_pane1.set_position (pos);
                }
 
+       } else if (which == static_cast<Gtk::Paned*> (&rhs_pane2)) {
+               if (done[1]) {
+                       return;
+               }
+
+               if (!geometry || (prop = geometry->property("mixer-rhs-pane2-pos")) == 0) {
+                       pos = 2 * height / 3;
+               } else {
+                       pos = atoi (prop->value());
+               }
+
+               if ((done[1] = GTK_WIDGET(rhs_pane2.gobj())->allocation.height > pos)) {
+                       rhs_pane2.set_position (pos);
+               }
        } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
 
                if (done[2]) {
                        return;
                }
 
-               if (!geometry) {
-                       pos = 0;
-                       snprintf (buf, sizeof(buf), "%d", pos);
+               if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
+                       pos = std::max ((float)100, rintf ((float) 125 * UIConfiguration::instance().get_ui_scale()));
                } else {
-                       prop = geometry->property("mixer-list-hpane-pos");
-                       pos = atoi (prop->value());
+                       pos = max (36, atoi (prop->value ()));
                }
 
                if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
@@ -1850,6 +2002,10 @@ Mixer_UI::parameter_changed (string const & p)
                }
        } else if (p == "remote-model") {
                reset_remote_control_ids ();
+       } else if (p == "use-monitor-bus") {
+               if (!_session->monitor_out()) {
+                       monitor_section_detached ();
+               }
        }
 }
 
@@ -1995,8 +2151,11 @@ void
 Mixer_UI::monitor_section_going_away ()
 {
        if (_monitor_section) {
+               monitor_section_detached ();
                out_packer.remove (_monitor_section->tearoff());
                _monitor_section->set_session (0);
+               delete _monitor_section;
+               _monitor_section = 0;
        }
 }
 
@@ -2043,3 +2202,108 @@ Mixer_UI::restore_mixer_space ()
 
        _maximised = false;
 }
+
+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);
+       act->set_sensitive (true);
+       tact->set_active ();
+}
+
+void
+Mixer_UI::monitor_section_detached ()
+{
+       Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
+       act->set_sensitive (false);
+}
+
+void
+Mixer_UI::store_current_favorite_order ()
+{
+       typedef Gtk::TreeModel::Children type_children;
+       type_children children = favorite_plugins_model->children();
+       favorite_order.clear();
+       for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter)
+       {
+               Gtk::TreeModel::Row row = *iter;
+               favorite_order.push_back (row[favorite_plugins_columns.plugin]);
+               std::string name = row[favorite_plugins_columns.name];
+       }
+}
+
+void
+Mixer_UI::refiller (PluginInfoList& result, const PluginInfoList& plugs)
+{
+       PluginManager& manager (PluginManager::instance());
+       for (PluginInfoList::const_iterator i = plugs.begin(); i != plugs.end(); ++i) {
+               if (manager.get_status (*i) != PluginManager::Favorite) {
+                       continue;
+               }
+               result.push_back (*i);
+       }
+}
+
+struct PluginCustomSorter {
+public:
+       bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
+               PluginInfoList::const_iterator aiter = std::find(_user.begin(), _user.end(), a);
+               PluginInfoList::const_iterator biter = std::find(_user.begin(), _user.end(), b);
+
+               if (aiter != _user.end() && biter != _user.end()) {
+                       return std::distance (_user.begin(), aiter)  < std::distance (_user.begin(), biter);
+               }
+               if (aiter != _user.end()) {
+                       return true;
+               }
+               if (biter != _user.end()) {
+                       return false;
+               }
+               return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
+       }
+       PluginCustomSorter(PluginInfoList user) : _user (user)  {}
+private:
+       PluginInfoList _user;
+};
+
+void
+Mixer_UI::refill_favorite_plugins ()
+{
+       PluginInfoList plugs;
+       PluginManager& mgr (PluginManager::instance());
+
+#ifdef LV2_SUPPORT
+       refiller (plugs, mgr.lv2_plugin_info ());
+#endif
+#ifdef WINDOWS_VST_SUPPORT
+       refiller (plugs, mgr.windows_vst_plugin_info ());
+#endif
+#ifdef LXVST_SUPPORT
+       refiller (plugs, mgr.lxvst_plugin_info ());
+#endif
+#ifdef AUDIOUNIT_SUPPORT
+       refiller (plugs, mgr.au_plugin_info ());
+#endif
+       refiller (plugs, mgr.ladspa_plugin_info ());
+
+       store_current_favorite_order ();
+
+       PluginCustomSorter cmp (favorite_order);
+       plugs.sort (cmp);
+
+       favorite_order = plugs;
+
+       sync_treeview_from_favorite_order ();
+}
+
+void
+Mixer_UI::sync_treeview_from_favorite_order ()
+{
+       favorite_plugins_model->clear ();
+       for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i) {
+               TreeModel::Row newrow = *(favorite_plugins_model->append());
+               newrow[favorite_plugins_columns.name] = (*i)->name;
+               newrow[favorite_plugins_columns.plugin] = *i;
+       }
+}