merge (with conflict fixes) with master (even against rgareus' recommendation)
[ardour.git] / gtk2_ardour / mixer_strip.cc
index a8ac81f770e76c6b11e97f2049161f3d6e93d31b..80548ea20b71c60a4b6d2fd525ed13fefadc269c 100644 (file)
@@ -41,6 +41,7 @@
 #include "ardour/pannable.h"
 #include "ardour/panner.h"
 #include "ardour/panner_shell.h"
+#include "ardour/panner_manager.h"
 #include "ardour/port.h"
 #include "ardour/profile.h"
 #include "ardour/route.h"
@@ -62,6 +63,7 @@
 #include "utils.h"
 #include "gui_thread.h"
 #include "route_group_menu.h"
+#include "meter_patterns.h"
 
 #include "i18n.h"
 
@@ -70,6 +72,7 @@ using namespace PBD;
 using namespace Gtk;
 using namespace Gtkmm2ext;
 using namespace std;
+using namespace ArdourMeter;
 
 int MixerStrip::scrollbar_height = 0;
 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
@@ -410,8 +413,10 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
        if (gpm.gain_display.get_parent()) {
                gpm.gain_display.get_parent()->remove (gpm.gain_display);
        }
+
+       gpm.set_type (rt->meter_type());
        
-       middle_button_table.attach (gpm.gain_display,0,1,1,2);
+       middle_button_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
        middle_button_table.attach (gpm.peak_display,1,2,1,2);
 
        if (solo_button->get_parent()) {
@@ -485,12 +490,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
                at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
        }
 
-       if (has_audio_outputs ()) {
-               panners.show_all ();
-       } else {
-               panners.hide_all ();
-       }
-
        if (is_track ()) {
 
                rec_solo_table.attach (*rec_enable_button, 0, 1, 0, 2);
@@ -513,9 +512,14 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
        route_ops_menu = 0;
 
        _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
+       _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
+       _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
        _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
 
+       _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
+
        if (_route->panner_shell()) {
+               update_panner_choices();
                _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
        }
 
@@ -539,6 +543,12 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
        connect_to_pan ();
        panners.setup_pan ();
 
+       if (has_audio_outputs ()) {
+               panners.show_all ();
+       } else {
+               panners.hide_all ();
+       }
+
        update_diskstream_display ();
        update_input_display ();
        update_output_display ();
@@ -629,8 +639,6 @@ MixerStrip::set_width_enum (Width w, void* owner)
                                        panners.astate_string(_route->panner()->automation_state()));
                }
 
-               solo_isolated_led->set_text (_("iso"));
-               solo_safe_led->set_text (_("lock"));
 
                Gtkmm2ext::set_size_request_to_display_given_text (name_button, longest_label.c_str(), 2, 2);
                set_size_request (-1, -1);
@@ -646,6 +654,7 @@ MixerStrip::set_width_enum (Width w, void* owner)
                                gpm.short_astyle_string(gain_automation->automation_style()));
                gpm.gain_automation_state_button.set_text (
                                gpm.short_astate_string(gain_automation->automation_state()));
+               gain_meter().setup_meters (); // recalc meter width
 
                if (_route->panner()) {
                        ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
@@ -653,9 +662,6 @@ MixerStrip::set_width_enum (Width w, void* owner)
                        ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
                        panners.short_astate_string(_route->panner()->automation_state()));
                }
-               
-               solo_isolated_led->set_text (_("iso"));
-               solo_safe_led->set_text (_("Lck"));
 
                Gtkmm2ext::set_size_request_to_display_given_text (name_button, "long", 2, 2);
                set_size_request (max (50, gpm.get_gm_width()), -1);
@@ -696,7 +702,7 @@ MixerStrip::output_press (GdkEventButton *ev)
 {
        using namespace Menu_Helpers;
        if (!_session->engine().connected()) {
-               MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
+               MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
                msg.run ();
                return true;
        }
@@ -824,7 +830,7 @@ MixerStrip::input_press (GdkEventButton *ev)
        citems.clear();
 
        if (!_session->engine().connected()) {
-               MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
+               MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
                msg.run ();
                return true;
        }
@@ -1017,9 +1023,32 @@ MixerStrip::connect_to_pan ()
        p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
        p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
 
-       panners.panshell_changed ();
+       /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
+        * However, that only works a panner was previously set.
+        *
+        * PannerUI must remain subscribed to _panshell->Changed() in case
+        * we switch the panner eg. AUX-Send and back
+        * _route->panner_shell()->Changed() vs _panshell->Changed
+        */
+       if (panners._panner == 0) {
+               panners.panshell_changed ();
+       }
 }
 
+void
+MixerStrip::update_panner_choices ()
+{
+       ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
+       if (!_route->panner_shell()) { return; }
+
+       uint32_t in = _route->output()->n_ports().n_audio();
+       uint32_t out = in;
+       if (_route->panner()) {
+               in = _route->panner()->in().n_audio();
+       }
+
+       panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
+}
 
 /*
  * Output port labelling
@@ -1235,6 +1264,13 @@ MixerStrip::update_input_display ()
 {
        update_io_button (_route, _width, true);
        panners.setup_pan ();
+
+       if (has_audio_outputs ()) {
+               panners.show_all ();
+       } else {
+               panners.hide_all ();
+       }
+
 }
 
 void
@@ -1243,6 +1279,12 @@ MixerStrip::update_output_display ()
        update_io_button (_route, _width, false);
        gpm.setup_meters ();
        panners.setup_pan ();
+
+       if (has_audio_outputs ()) {
+               panners.show_all ();
+       } else {
+               panners.hide_all ();
+       }
 }
 
 void
@@ -1257,6 +1299,12 @@ MixerStrip::diskstream_changed ()
        Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
 }
 
+void
+MixerStrip::io_changed_proxy ()
+{
+       Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
+}
+
 void
 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
 {
@@ -1350,7 +1398,6 @@ void
 MixerStrip::setup_comment_editor ()
 {
        comment_window = new ArdourWindow (""); // title will be reset to show route
-       comment_window->set_position (Gtk::WIN_POS_MOUSE);
        comment_window->set_skip_taskbar_hint (true);
        comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
        comment_window->set_default_size (400, 200);
@@ -1459,7 +1506,7 @@ MixerStrip::build_route_ops_menu ()
 
        items.push_back (SeparatorElem());
        items.push_back (CheckMenuElem (_("Active")));
-       CheckMenuItem* i = dynamic_cast<CheckMenuItem *> (&items.back());
+       Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
        i->set_active (_route->active());
        i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
 
@@ -1469,7 +1516,7 @@ MixerStrip::build_route_ops_menu ()
 
        items.push_back (SeparatorElem());
        items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
-       denormal_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
+       denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
        denormal_menu_item->set_active (_route->denormal_protection());
 
        if (!Profile->get_sae()) {
@@ -1561,11 +1608,11 @@ MixerStrip::width_button_pressed (GdkEventButton* ev)
        if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
                switch (_width) {
                case Wide:
-                       _mixer.set_strip_width (Narrow);
+                       _mixer.set_strip_width (Narrow, true);
                        break;
 
                case Narrow:
-                       _mixer.set_strip_width (Wide);
+                       _mixer.set_strip_width (Wide, true);
                        break;
                }
        } else {
@@ -1658,28 +1705,22 @@ MixerStrip::reset_strip_style ()
                if (is_midi_track()) {
                        if (_route->active()) {
                                set_name ("MidiTrackStripBase");
-                               gpm.set_meter_strip_name ("MidiTrackMetrics");
                        } else {
                                set_name ("MidiTrackStripBaseInactive");
-                               gpm.set_meter_strip_name ("MidiTrackMetricsInactive");
                        }
                        gpm.set_fader_name ("MidiTrackFader");
                } else if (is_audio_track()) {
                        if (_route->active()) {
                                set_name ("AudioTrackStripBase");
-                               gpm.set_meter_strip_name ("AudioTrackMetrics");
                        } else {
                                set_name ("AudioTrackStripBaseInactive");
-                               gpm.set_meter_strip_name ("AudioTrackMetricsInactive");
                        }
                        gpm.set_fader_name ("AudioTrackFader");
                } else {
                        if (_route->active()) {
                                set_name ("AudioBusStripBase");
-                               gpm.set_meter_strip_name ("AudioBusMetrics");
                        } else {
                                set_name ("AudioBusStripBaseInactive");
-                               gpm.set_meter_strip_name ("AudioBusMetricsInactive");
                        }
                        gpm.set_fader_name ("AudioBusFader");
 
@@ -1834,8 +1875,13 @@ MixerStrip::show_send (boost::shared_ptr<Send> send)
        gain_meter().set_controls (_route, send->meter(), send->amp());
        gain_meter().setup_meters ();
 
+       uint32_t const in = _current_delivery->pans_required();
+       uint32_t const out = _current_delivery->pan_outs();
+
        panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
+       panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
        panner_ui().setup_pan ();
+       panner_ui().show_all ();
 
        input_button.set_sensitive (false);
        group_button.set_sensitive (false);
@@ -1868,8 +1914,15 @@ MixerStrip::revert_to_default_display ()
        gain_meter().setup_meters ();
 
        panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
+       update_panner_choices();
        panner_ui().setup_pan ();
 
+       if (has_audio_outputs ()) {
+               panners.show_all ();
+       } else {
+               panners.hide_all ();
+       }
+
        reset_strip_style ();
 }
 
@@ -1884,26 +1937,24 @@ MixerStrip::set_button_names ()
                monitor_disk_button->set_text (_("Disk"));
 
                if (_route && _route->solo_safe()) {
-                       if (solo_safe_pixbuf == 0) {
-                               solo_safe_pixbuf = ::get_icon("solo-safe-icon");
-                       }
-                       solo_button->set_image (solo_safe_pixbuf);
-                       solo_button->set_text (string());
+                       solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
                } else {
-                       solo_button->set_image (Glib::RefPtr<Gdk::Pixbuf>());
-                       if (!Config->get_solo_control_is_listen_control()) {
-                               solo_button->set_text (_("Solo"));
-                       } else {
-                               switch (Config->get_listen_position()) {
-                               case AfterFaderListen:
-                                       solo_button->set_text (_("AFL"));
-                                       break;
-                               case PreFaderListen:
-                                       solo_button->set_text (_("PFL"));
-                                       break;
-                               }
+                       solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
+               }
+               if (!Config->get_solo_control_is_listen_control()) {
+                       solo_button->set_text (_("Solo"));
+               } else {
+                       switch (Config->get_listen_position()) {
+                       case AfterFaderListen:
+                               solo_button->set_text (_("AFL"));
+                               break;
+                       case PreFaderListen:
+                               solo_button->set_text (_("PFL"));
+                               break;
                        }
                }
+               solo_isolated_led->set_text (_("iso"));
+               solo_safe_led->set_text (_("lock"));
                break;
 
        default:
@@ -1911,30 +1962,28 @@ MixerStrip::set_button_names ()
                mute_button->set_text (_("M"));
                monitor_input_button->set_text (_("I"));
                monitor_disk_button->set_text (_("D"));
+
                if (_route && _route->solo_safe()) {
-                       solo_button->remove ();
-                       if (solo_safe_pixbuf == 0) {
-                               solo_safe_pixbuf =::get_icon("solo-safe-icon");
-                       }
-                       solo_button->set_image (solo_safe_pixbuf);
-                       solo_button->set_text (string());
+                       solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
                } else {
-                       solo_button->set_image (Glib::RefPtr<Gdk::Pixbuf>());
-                       if (!Config->get_solo_control_is_listen_control()) {
-                               solo_button->set_text (_("S"));
-                       } else {
-                               switch (Config->get_listen_position()) {
-                               case AfterFaderListen:
-                                       solo_button->set_text (_("A"));
-                                       break;
-                               case PreFaderListen:
-                                       solo_button->set_text (_("P"));
-                                       break;
-                               }
+                       solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
+               }
+               if (!Config->get_solo_control_is_listen_control()) {
+                       solo_button->set_text (_("S"));
+               } else {
+                       switch (Config->get_listen_position()) {
+                       case AfterFaderListen:
+                               solo_button->set_text (_("A"));
+                               break;
+                       case PreFaderListen:
+                               solo_button->set_text (_("P"));
+                               break;
                        }
                }
-               break;
 
+               solo_isolated_led->set_text (_("i"));
+               solo_safe_led->set_text (_("L"));
+               break;
        }
 
        if (_route) {
@@ -2087,6 +2136,9 @@ MixerStrip::ab_plugins ()
 bool
 MixerStrip::level_meter_button_press (GdkEventButton* ev)
 {
+       if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
+               return false;
+       }
        if (ev->button == 3) {
                popup_level_meter_menu (ev);
                return true;
@@ -2105,17 +2157,61 @@ MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
 
        RadioMenuItem::Group group;
 
-       add_level_meter_item (items, group, _("Input"), MeterInput);
-       add_level_meter_item (items, group, _("Pre-fader"), MeterPreFader);
-       add_level_meter_item (items, group, _("Post-fader"), MeterPostFader);
-       add_level_meter_item (items, group, _("Output"), MeterOutput);
-       add_level_meter_item (items, group, _("Custom"), MeterCustom);
+       _suspend_menu_callbacks = true;
+       add_level_meter_item_point (items, group, _("Input"), MeterInput);
+       add_level_meter_item_point (items, group, _("Pre-fader"), MeterPreFader);
+       add_level_meter_item_point (items, group, _("Post-fader"), MeterPostFader);
+       add_level_meter_item_point (items, group, _("Output"), MeterOutput);
+       add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
+
+       RadioMenuItem::Group tgroup;
+       items.push_back (SeparatorElem());
+
+       add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
+       add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms),  MeterKrms);
+       add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
+       add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
+       add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
+       add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
+       add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
+       add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
+       add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
+       add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU),  MeterVU);
+
+       int _strip_type;
+       if (_route->is_master()) {
+               _strip_type = 4;
+       }
+       else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
+                       && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
+               /* non-master bus */
+               _strip_type = 3;
+       }
+       else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
+               _strip_type = 2;
+       }
+       else {
+               _strip_type = 1;
+       }
+
+       MeterType cmt = _route->meter_type();
+       const std::string cmn = ArdourMeter::meter_type_string(cmt);
+
+       items.push_back (SeparatorElem());
+       items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
+                               sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
+       items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
+                               sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
+       items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
+                               sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
 
        m->popup (ev->button, ev->time);
+       _suspend_menu_callbacks = false;
 }
 
 void
-MixerStrip::add_level_meter_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterPoint point)
+MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
+               RadioMenuItem::Group& group, string const & name, MeterPoint point)
 {
        using namespace Menu_Helpers;
        
@@ -2127,5 +2223,24 @@ MixerStrip::add_level_meter_item (Menu_Helpers::MenuList& items, RadioMenuItem::
 void
 MixerStrip::set_meter_point (MeterPoint p)
 {
+       if (_suspend_menu_callbacks) return;
        _route->set_meter_point (p);
 }
+
+void
+MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
+               RadioMenuItem::Group& group, string const & name, MeterType type)
+{
+       using namespace Menu_Helpers;
+       
+       items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
+       RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
+       i->set_active (_route->meter_type() == type);
+}
+
+void
+MixerStrip::set_meter_type (MeterType t)
+{
+       if (_suspend_menu_callbacks) return;
+       gpm.set_type (t);
+}