f1ff7fcd7eb466f8eb54febda2f5d3715d86a412
[ardour.git] / gtk2_ardour / monitor_section.cc
1 /*
2   Copyright (C) 2012 Paul Davis
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program; if not, write to the Free Software
16   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <gdkmm/pixbuf.h>
21
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
25
26 #include "gtkmm2ext/actions.h"
27 #include "gtkmm2ext/utils.h"
28
29 #include <gtkmm/menu.h>
30 #include <gtkmm/menuitem.h>
31
32 #include "widgets/tearoff.h"
33 #include "widgets/tooltips.h"
34
35 #include "ardour/amp.h"
36 #include "ardour/audioengine.h"
37 #include "ardour/monitor_processor.h"
38 #include "ardour/port.h"
39 #include "ardour/route.h"
40 #include "ardour/solo_isolate_control.h"
41 #include "ardour/user_bundle.h"
42 #include "ardour/plugin_manager.h"
43
44 #include "ardour_ui.h"
45 #include "gui_thread.h"
46 #include "mixer_ui.h"
47 #include "monitor_section.h"
48 #include "public_editor.h"
49 #include "timers.h"
50 #include "ui_config.h"
51 #include "utils.h"
52
53 #include "pbd/i18n.h"
54
55 using namespace ARDOUR;
56 using namespace ArdourWidgets;
57 using namespace ARDOUR_UI_UTILS;
58 using namespace Gtk;
59 using namespace Gtkmm2ext;
60 using namespace PBD;
61 using namespace std;
62
63 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
64
65 MonitorSection::MonitorSection ()
66         : RouteUI ((Session*) 0)
67         , _tearoff (0)
68         , channel_table (0)
69         , channel_table_viewport (*channel_table_scroller.get_hadjustment()
70                                   , *channel_table_scroller.get_vadjustment ())
71         , gain_control (0)
72         , dim_control (0)
73         , solo_boost_control (0)
74         , solo_cut_control (0)
75         , gain_display (0)
76         , dim_display (0)
77         , solo_boost_display (0)
78         , solo_cut_display (0)
79         , _output_selector (0)
80         , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
81         , afl_button (_("AFL"), ArdourButton::led_default_elements)
82         , pfl_button (_("PFL"), ArdourButton::led_default_elements)
83         , exclusive_solo_button (ArdourButton::led_default_elements)
84         , solo_mute_override_button (ArdourButton::led_default_elements)
85         , toggle_processorbox_button (ArdourButton::default_elements)
86         , _inhibit_solo_model_update (false)
87         , _rr_selection ()
88         , _ui_initialized (false)
89 {
90         using namespace Menu_Helpers;
91
92         Glib::RefPtr<Action> act;
93
94         load_bindings ();
95         register_actions ();
96         set_data ("ardour-bindings", bindings);
97
98         channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
99
100         _plugin_selector = new PluginSelector (PluginManager::instance());
101         insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
102         insert_box->set_no_show_all ();
103         insert_box->show ();
104         // TODO allow keyboard shortcuts in ProcessorBox
105
106         /* Rude Solo  & Solo Isolated */
107         rude_solo_button.set_text (_("Soloing"));
108         rude_solo_button.set_name ("rude solo");
109         rude_solo_button.show ();
110
111         rude_iso_button.set_text (_("Isolated"));
112         rude_iso_button.set_name ("rude isolate");
113         rude_iso_button.show ();
114
115         rude_audition_button.set_text (_("Auditioning"));
116         rude_audition_button.set_name ("rude audition");
117         rude_audition_button.show ();
118
119         Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
120
121         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
122
123         rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
124         UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
125
126         rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
127         UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
128
129         /* SIP, AFL, PFL radio */
130
131         solo_in_place_button.set_name ("monitor section solo model");
132         afl_button.set_name ("monitor section solo model");
133         pfl_button.set_name ("monitor section solo model");
134
135         solo_in_place_button.set_led_left (true);
136         afl_button.set_led_left (true);
137         pfl_button.set_led_left (true);
138
139         solo_in_place_button.show ();
140         afl_button.show ();
141         pfl_button.show ();
142
143         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
144         set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
145         if (act) {
146                 solo_in_place_button.set_related_action (act);
147         }
148
149         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
150         set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
151         if (act) {
152                 afl_button.set_related_action (act);
153         }
154
155         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
156         set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
157         if (act) {
158                 pfl_button.set_related_action (act);
159         }
160
161         /* Solo option buttons */
162         exclusive_solo_button.set_text (_("Excl. Solo"));
163         exclusive_solo_button.set_name (X_("monitor section solo option"));
164         set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
165
166         act = ActionManager::get_action (X_("Solo"), X_("toggle-exclusive-solo"));
167         if (act) {
168                 exclusive_solo_button.set_related_action (act);
169         }
170
171         solo_mute_override_button.set_text (_("Solo ยป Mute"));
172         solo_mute_override_button.set_name (X_("monitor section solo option"));
173         set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
174
175         solo_mute_override_button.set_related_action (ActionManager::get_action (X_("Solo"), X_("toggle-mute-overrides-solo")));
176
177         /* Processor Box hide/shos */
178         toggle_processorbox_button.set_text (_("Processors"));
179         toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
180         set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
181
182         proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
183         toggle_processorbox_button.set_related_action (proctoggle);
184
185         /* Knobs */
186         Label* solo_boost_label;
187         Label* solo_cut_label;
188         Label* dim_label;
189
190         /* Solo Boost Knob */
191
192         solo_boost_control = new ArdourKnob ();
193         solo_boost_control->set_name("monitor section knob");
194         solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
195         set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
196
197         solo_boost_display = new ArdourDisplay ();
198         solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
199         solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
200         solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
201         solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
202         solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
203
204         solo_boost_label = manage (new Label (_("Solo Boost")));
205
206         /* Solo (SiP) cut */
207
208         solo_cut_control = new ArdourKnob ();
209         solo_cut_control->set_name ("monitor section knob");
210         solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
211         set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
212
213         solo_cut_display = new ArdourDisplay ();
214         solo_cut_display->set_name("monitor section dropdown"); // XXX
215         solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
216         solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
217         solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
218         solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
219         solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
220         solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
221
222         solo_cut_label = manage (new Label (_("SiP Cut")));
223
224         /* Dim */
225
226         dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
227         dim_control->set_name ("monitor section knob");
228         dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
229         set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
230
231         dim_display = new ArdourDisplay ();
232         dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
233         dim_display->add_controllable_preset(_("0 dB"), 0.0);
234         dim_display->add_controllable_preset(_("-3 dB"), -3.0);
235         dim_display->add_controllable_preset(_("-6 dB"), -6.0);
236         dim_display->add_controllable_preset(_("-12 dB"), -12.0);
237         dim_display->add_controllable_preset(_("-20 dB"), -20.0);
238
239         dim_label = manage (new Label (_("Dim")));
240
241         // mute button
242         cut_all_button.set_text (_("Mute"));
243         cut_all_button.set_name ("mute button");
244         cut_all_button.set_size_request (-1, PX_SCALE(30));
245         cut_all_button.show ();
246
247         act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
248         if (act) {
249                 cut_all_button.set_related_action (act);
250         }
251
252         // dim button
253         dim_all_button.set_text (_("Dim"));
254         dim_all_button.set_name ("monitor section dim");
255         dim_all_button.set_size_request (-1, PX_SCALE(25));
256         act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
257         if (act) {
258                 dim_all_button.set_related_action (act);
259         }
260
261         // mono button
262         mono_button.set_text (_("Mono"));
263         mono_button.set_name ("monitor section mono");
264         mono_button.set_size_request (-1, PX_SCALE(25));
265         act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
266         if (act) {
267                 mono_button.set_related_action (act);
268         }
269
270         /* Gain */
271
272         gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
273         gain_control->set_name("monitor section knob");
274         gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
275
276         gain_display = new ArdourDisplay ();
277         gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
278         gain_display->add_controllable_preset(_("0 dB"), 0.0);
279         gain_display->add_controllable_preset(_("-3 dB"), -3.0);
280         gain_display->add_controllable_preset(_("-6 dB"), -6.0);
281         gain_display->add_controllable_preset(_("-12 dB"), -12.0);
282         gain_display->add_controllable_preset(_("-20 dB"), -20.0);
283         gain_display->add_controllable_preset(_("-30 dB"), -30.0);
284
285         Label* output_label = manage (new Label (_("Output")));
286         output_label->set_name (X_("MonitorSectionLabel"));
287
288         output_button = new ArdourButton ();
289         output_button->set_text (_("Output"));
290         output_button->set_name (X_("monitor section cut")); // XXX
291         output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
292         output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
293
294         channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
295         channel_table_scroller.set_size_request (-1, PX_SCALE(150));
296         channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
297         channel_table_scroller.show ();
298         channel_table_scroller.add (channel_table_viewport);
299
300         channel_size_group->add_widget (channel_table_header);
301         channel_table_header.resize (1, 5);
302
303         Label* l1 = manage (new Label (X_("  ")));
304         l1->set_name (X_("MonitorSectionLabel"));
305         channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
306
307         l1 = manage (new Label (_("Mute")));
308         l1->set_name (X_("MonitorSectionLabel"));
309         channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
310
311         l1 = manage (new Label (_("Dim")));
312         l1->set_name (X_("MonitorSectionLabel"));
313         channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
314
315         l1 = manage (new Label (_("Solo")));
316         l1->set_name (X_("MonitorSectionLabel"));
317         channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
318
319         l1 = manage (new Label (_("Inv")));
320         l1->set_name (X_("MonitorSectionLabel"));
321         channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
322
323         channel_table_header.show ();
324
325
326         /****************************************************************************
327          * LAYOUT  top to bottom
328          */
329
330         // solo, iso information
331         HBox* rude_box = manage (new HBox);
332         rude_box->set_spacing (PX_SCALE(4));
333         rude_box->set_homogeneous (true);
334         rude_box->pack_start (rude_solo_button, true, true);
335         rude_box->pack_start (rude_iso_button, true, true);
336
337         // solo options (right align)
338         HBox* tbx1 = manage (new HBox);
339         tbx1->pack_end (exclusive_solo_button, false, false);
340
341         HBox* tbx2 = manage (new HBox);
342         tbx2->pack_end (solo_mute_override_button, false, false);
343
344         HBox* tbx3 = manage (new HBox);
345         tbx3->pack_end (toggle_processorbox_button, false, false);
346
347         HBox* tbx0 = manage (new HBox); // space
348
349         // combined solo mode (Sip, AFL, PFL) & solo options
350         Table *solo_tbl = manage (new Table);
351         solo_tbl->attach (solo_in_place_button,   0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
352         solo_tbl->attach (pfl_button,             0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
353         solo_tbl->attach (afl_button,             0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
354         solo_tbl->attach (*tbx0,                  1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
355         solo_tbl->attach (*tbx1,                  2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
356         solo_tbl->attach (*tbx2,                  2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
357         solo_tbl->attach (*tbx3,                  2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
358
359         // boost, cut, dim  volume control
360         Table *level_tbl = manage (new Table);
361         level_tbl->attach (*solo_boost_label,    0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
362         level_tbl->attach (*solo_boost_control,  0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
363         level_tbl->attach (*solo_boost_display,  0, 2, 2, 3, EXPAND     , SHRINK, 1, 2);
364
365         level_tbl->attach (*solo_cut_label,      2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
366         level_tbl->attach (*solo_cut_control,    2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
367         level_tbl->attach (*solo_cut_display,    2, 4, 2, 3, EXPAND     , SHRINK, 1, 2);
368
369         level_tbl->attach (*dim_label,           1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
370         level_tbl->attach (*dim_control,         1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
371         level_tbl->attach (*dim_display,         1, 3, 5, 6, EXPAND     , SHRINK, 1, 2);
372
373         // mono, dim
374         HBox* mono_dim_box = manage (new HBox);
375         mono_dim_box->set_spacing (PX_SCALE(4));
376         mono_dim_box->set_homogeneous (true);
377         mono_dim_box->pack_start (mono_button, true, true);
378         mono_dim_box->pack_end (dim_all_button, true, true);
379
380         // master gain
381         Label* spin_label = manage (new Label (_("Monitor")));
382         VBox* spin_packer = manage (new VBox);
383         spin_packer->set_spacing (PX_SCALE(2));
384         spin_packer->pack_start (*spin_label, false, false);
385         spin_packer->pack_start (*gain_control, false, false);
386         spin_packer->pack_start (*gain_display, false, false);
387
388         master_packer.pack_start (*spin_packer, true, false);
389
390         // combined gain section (channels, mute, dim)
391         VBox* lower_packer = manage (new VBox);
392         lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
393         lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
394         lower_packer->pack_start (*mono_dim_box,        false, false, PX_SCALE(2));
395         lower_packer->pack_start (cut_all_button,       false, false, PX_SCALE(2));
396
397         // calc height of mixer scrollbar
398         int scrollbar_height = 0;
399         {
400                 Gtk::Window window (WINDOW_TOPLEVEL);
401                 HScrollbar scrollbar;
402                 window.add (scrollbar);
403                 scrollbar.set_name ("MixerWindow");
404                 scrollbar.ensure_style();
405                 Gtk::Requisition requisition(scrollbar.size_request ());
406                 scrollbar_height = requisition.height;
407         }
408
409         // output port select
410         VBox* out_packer = manage (new VBox);
411         out_packer->set_spacing (PX_SCALE(2));
412         out_packer->pack_start (*output_label, false, false);
413         out_packer->pack_start (*output_button, false, false);
414
415         /****************************************************************************
416          * TOP LEVEL LAYOUT
417          */
418         vpacker.set_border_width (PX_SCALE(3));
419         vpacker.pack_start (*rude_box,            false, false, PX_SCALE(3));
420         vpacker.pack_start (rude_audition_button, false, false, 0);
421         vpacker.pack_start (*solo_tbl,            false, false, PX_SCALE(8));
422         vpacker.pack_start (*insert_box,          true,  true,  PX_SCALE(8));
423         vpacker.pack_start (*level_tbl,           false, false, PX_SCALE(8));
424         vpacker.pack_start (*lower_packer,        false, false, PX_SCALE(8));
425         vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
426         vpacker.pack_end   (*out_packer,          false, false,
427 #ifdef MIXBUS
428                         scrollbar_height - 2 /* no outer sample */
429 #else
430                         scrollbar_height + 2 /* sample borders */
431 #endif
432                         );
433
434         hpacker.set_spacing (0);
435         hpacker.pack_start (vpacker, true, true);
436
437         add (hpacker);
438
439         gain_control->show_all ();
440         gain_display->show_all ();
441         dim_control->show_all ();
442         dim_display->show_all();
443         solo_boost_control->show_all ();
444         solo_boost_display->show_all();
445
446         mono_dim_box->show ();
447         spin_packer->show ();
448         master_packer.show ();
449
450         rude_box->show();
451         solo_tbl->show_all();
452         level_tbl->show();
453         lower_packer->show ();
454         out_packer->show ();
455
456         vpacker.show ();
457         hpacker.show ();
458
459         map_state ();
460         assign_controllables ();
461
462         output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
463         output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
464
465         signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
466         signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
467         set_flags (CAN_FOCUS);
468
469         _tearoff = new TearOff (*this);
470
471         if (!UIConfiguration::instance().get_floating_monitor_section()) {
472                 /* if torn off, make this a normal window
473                  * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
474                  */
475                 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
476         }
477         _tearoff->tearoff_window().set_title (X_("Monitor"));
478         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
479
480         update_output_display ();
481         update_processor_box ();
482         _ui_initialized = true;
483
484         /* catch changes that affect us */
485         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
486                 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
487                 );
488         Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
489 }
490
491 MonitorSection::~MonitorSection ()
492 {
493         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
494                 delete *i;
495         }
496
497         _channel_buttons.clear ();
498         output_changed_connections.drop_connections ();
499
500         delete insert_box; insert_box = 0;
501         delete output_button; output_button = 0;
502         delete gain_control; gain_control = 0;
503         delete gain_display; gain_display = 0;
504         delete dim_control; dim_control = 0;
505         delete dim_display; dim_display = 0;
506         delete solo_boost_control; solo_boost_control = 0;
507         delete solo_boost_display; solo_boost_display = 0;
508         delete solo_cut_control; solo_cut_control = 0;
509         delete solo_cut_display; solo_cut_display = 0;
510         delete _tearoff; _tearoff = 0;
511         delete _output_selector; _output_selector = 0;
512         delete channel_table; channel_table = 0;
513 }
514
515 bool
516 MonitorSection::enter_handler (GdkEventCrossing* ev)
517 {
518         grab_focus ();
519         return false;
520 }
521
522 bool
523 MonitorSection::leave_handler (GdkEventCrossing* ev)
524 {
525         switch (ev->detail) {
526         case GDK_NOTIFY_INFERIOR:
527                 return false;
528         default:
529                 break;
530         }
531
532         /* cancel focus if we're not torn off. With X11 WM's that do
533          * focus-follows-mouse, focus will be taken from us anyway.
534          */
535
536         Widget* top = get_toplevel();
537
538         if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
539                 Window* win = dynamic_cast<Window*> (top);
540                 gtk_window_set_focus (win->gobj(), 0);
541         }
542
543         return false;
544 }
545
546 void
547 MonitorSection::update_processor_box ()
548 {
549         bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
550
551         if (count_processors () > 0 && !show_processor_box) {
552                 toggle_processorbox_button.set_name (X_("monitor section processors present"));
553         } else {
554                 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
555         }
556
557         if (insert_box->is_visible() == show_processor_box) {
558                 return;
559         }
560
561         if (show_processor_box) {
562                 if (master_packer.get_parent()) {
563                         master_packer.get_parent()->remove (master_packer);
564                 }
565                 insert_box->show();
566                 vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
567         } else {
568                 if (master_packer.get_parent()) {
569                         master_packer.get_parent()->remove (master_packer);
570                 }
571                 insert_box->hide();
572                 vpacker.pack_start (master_packer,        true,  false, PX_SCALE(10));
573         }
574 }
575
576 void
577 MonitorSection::set_session (Session* s)
578 {
579         RouteUI::set_session (s);
580         _plugin_selector->set_session (_session);
581
582         if (_session) {
583
584                 /* These are not actually dependent on the Session, but they
585                  * need to be set after construction, not during, and
586                  * this is as good a place as any.
587                  */
588
589                 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
590                 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
591
592                 _route = _session->monitor_out ();
593
594                 if (_route) {
595                         /* session with monitor section */
596                         _monitor = _route->monitor_control ();
597                         assign_controllables ();
598                         _route->output()->changed.connect (output_changed_connections, invalidator (*this),
599                                                                                         boost::bind (&MonitorSection::update_output_display, this),
600                                                                                         gui_context());
601                         insert_box->set_route (_route);
602                         _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
603                         _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
604                         if (_ui_initialized) {
605                                 update_processor_box ();
606                         }
607
608                         ActionManager::set_sensitive (monitor_actions, true);
609                         ActionManager::set_sensitive (solo_actions, true);
610
611                 } else {
612                         /* session with no monitor section */
613                         output_changed_connections.drop_connections();
614                         _monitor.reset ();
615                         _route.reset ();
616                         delete _output_selector;
617                         _output_selector = 0;
618
619                         ActionManager::set_sensitive (monitor_actions, false);
620                         ActionManager::set_sensitive (solo_actions, true);
621                 }
622
623                 populate_buttons ();
624
625
626         } else {
627
628                 /* no session */
629
630                 output_changed_connections.drop_connections();
631                 _monitor.reset ();
632                 _route.reset ();
633                 control_connections.drop_connections ();
634                 rude_iso_button.unset_active_state ();
635                 rude_solo_button.unset_active_state ();
636                 delete _output_selector;
637                 _output_selector = 0;
638
639                 assign_controllables ();
640
641                 ActionManager::set_sensitive (monitor_actions, false);
642                 ActionManager::set_sensitive (solo_actions, false);
643         }
644 }
645
646 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
647 {
648         cut.set_name (X_("mute button"));
649         dim.set_name (X_("monitor section dim"));
650         solo.set_name (X_("solo button"));
651         invert.set_name (X_("invert button"));
652
653         cut.unset_flags (Gtk::CAN_FOCUS);
654         dim.unset_flags (Gtk::CAN_FOCUS);
655         solo.unset_flags (Gtk::CAN_FOCUS);
656         invert.unset_flags (Gtk::CAN_FOCUS);
657 }
658
659 void
660 MonitorSection::populate_buttons ()
661 {
662         if (!_monitor) {
663                 return;
664         }
665
666         if (channel_table) {
667                 channel_size_group->remove_widget (*channel_table);
668                 delete channel_table;
669         }
670
671         channel_table = new Gtk::Table();
672
673         channel_table->set_col_spacings (6);
674         channel_table->set_row_spacings (6);
675         channel_table->set_homogeneous (true);
676
677         channel_size_group->add_widget (*channel_table);
678         channel_table->show ();
679         table_hpacker.pack_start (*channel_table, true, true);
680
681         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
682                 delete *i;
683         }
684         _channel_buttons.clear ();
685
686         Glib::RefPtr<Action> act;
687         uint32_t nchans = _monitor->output_streams().n_audio();
688
689         channel_table->resize (nchans, 5);
690
691         const uint32_t row_offset = 0;
692
693         for (uint32_t i = 0; i < nchans; ++i) {
694
695                 string l;
696                 char buf[64];
697
698                 if (nchans == 2) {
699                         if (i == 0) {
700                                 l = "L";
701                         } else {
702                                 l = "R";
703                         }
704                 } else {
705                         char buf[32];
706                         snprintf (buf, sizeof (buf), "%d", i+1);
707                         l = buf;
708                 }
709
710                 Label* label = manage (new Label (l));
711                 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
712
713                 ChannelButtonSet* cbs = new ChannelButtonSet;
714
715                 _channel_buttons.push_back (cbs);
716
717                 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
718                 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
719                 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
720                 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
721
722                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
723                 act = ActionManager::get_action (X_("Monitor"), buf);
724                 if (act) {
725                         cbs->cut.set_related_action (act);
726                 }
727
728                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
729                 act = ActionManager::get_action (X_("Monitor"), buf);
730                 if (act) {
731                         cbs->dim.set_related_action (act);
732                 }
733
734                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
735                 act = ActionManager::get_action (X_("Monitor"), buf);
736                 if (act) {
737                         cbs->solo.set_related_action (act);
738                 }
739
740                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
741                 act = ActionManager::get_action (X_("Monitor"), buf);
742                 if (act) {
743                         cbs->invert.set_related_action (act);
744                 }
745         }
746
747         channel_table->show_all ();
748
749         if (channel_table_scroller.get_parent()) {
750                 /* scroller is packed, so remove it */
751                 channel_table_packer.remove (channel_table_scroller);
752         }
753
754         if (table_hpacker.get_parent () == &channel_table_packer) {
755                 /* this occurs when the table hpacker is directly
756                          packed, so remove it.
757                          */
758                 channel_table_packer.remove (table_hpacker);
759         } else if (table_hpacker.get_parent()) {
760                 channel_table_viewport.remove ();
761         }
762
763         if (nchans > 7) {
764                 /* put the table into a scrolled window, and then put
765                  * that into the channel vpacker, after the table header
766                  */
767                 channel_table_viewport.add (table_hpacker);
768                 channel_table_packer.pack_start (channel_table_scroller, true, true);
769                 channel_table_viewport.show ();
770                 channel_table_scroller.show ();
771
772         } else {
773                 /* just put the channel table itself into the channel
774                  * vpacker, after the table header
775                  */
776                 channel_table_packer.pack_start (table_hpacker, true, true);
777                 channel_table_scroller.hide ();
778         }
779         table_hpacker.show ();
780         channel_table->show ();
781 }
782
783 void
784 MonitorSection::toggle_exclusive_solo ()
785 {
786         if (!_monitor) {
787                 return;
788         }
789
790         Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
791 }
792
793 void
794 MonitorSection::toggle_mute_overrides_solo ()
795 {
796         if (!_monitor) {
797                 return;
798         }
799
800         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), "toggle-mute-overrides-solo");
801         if (act) {
802                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
803                 Config->set_solo_mute_override (tact->get_active());
804         }
805 }
806
807 void
808 MonitorSection::dim_all ()
809 {
810         if (!_monitor) {
811                 return;
812         }
813
814         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
815         if (act) {
816                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
817                 _monitor->set_dim_all (tact->get_active());
818         }
819
820 }
821
822 void
823 MonitorSection::cut_all ()
824 {
825         if (!_monitor) {
826                 return;
827         }
828
829         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
830         if (act) {
831                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
832                 _monitor->set_cut_all (tact->get_active());
833         }
834 }
835
836 void
837 MonitorSection::mono ()
838 {
839         if (!_monitor) {
840                 return;
841         }
842
843         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
844         if (act) {
845                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
846                 _monitor->set_mono (tact->get_active());
847         }
848 }
849
850 void
851 MonitorSection::cut_channel (uint32_t chn)
852 {
853         if (!_monitor) {
854                 return;
855         }
856
857         char buf[64];
858         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
859
860         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
861         if (act) {
862                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
863                 _monitor->set_cut (chn, tact->get_active());
864         }
865 }
866
867 void
868 MonitorSection::dim_channel (uint32_t chn)
869 {
870         if (!_monitor) {
871                 return;
872         }
873
874         char buf[64];
875         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
876
877         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
878         if (act) {
879                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
880                 _monitor->set_dim (chn, tact->get_active());
881         }
882
883 }
884
885 void
886 MonitorSection::solo_channel (uint32_t chn)
887 {
888         if (!_monitor) {
889                 return;
890         }
891
892         char buf[64];
893         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
894
895         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
896         if (act) {
897                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
898                 _monitor->set_solo (chn, tact->get_active());
899         }
900
901 }
902
903 void
904 MonitorSection::invert_channel (uint32_t chn)
905 {
906         if (!_monitor) {
907                 return;
908         }
909
910         char buf[64];
911         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
912
913         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
914         if (act) {
915                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
916                 _monitor->set_polarity (chn, tact->get_active());
917         }
918 }
919
920 void
921 MonitorSection::register_actions ()
922 {
923         string action_name;
924         string action_descr;
925         Glib::RefPtr<Action> act;
926
927         /* ...will get sensitized if a mon-session is added */
928
929         monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
930         solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
931
932         ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
933         ActionManager::register_toggle_action (monitor_actions, "monitor-mono", _("Monitor Section: Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
934         ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", _("Monitor Section: Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
935         ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", _("Monitor Section: Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
936
937         ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
938                                                sigc::mem_fun (*this, &MonitorSection::update_processor_box));
939
940
941         for (uint32_t chn = 0; chn < 16; ++chn) {
942
943                 action_name = string_compose (X_("monitor-cut-%1"), chn);
944                 action_descr = string_compose (_("Cut monitor channel %1"), chn);
945                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
946                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
947
948                 action_name = string_compose (X_("monitor-dim-%1"), chn);
949                 action_descr = string_compose (_("Dim monitor channel %1"), chn);
950                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
951                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
952
953                 action_name = string_compose (X_("monitor-solo-%1"), chn);
954                 action_descr = string_compose (_("Solo monitor channel %1"), chn);
955                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
956                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
957
958                 action_name = string_compose (X_("monitor-invert-%1"), chn);
959                 action_descr = string_compose (_("Invert monitor channel %1"), chn);
960                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
961                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
962
963         }
964
965         solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
966         RadioAction::Group solo_group;
967
968         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
969                                               sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
970         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
971                                               sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
972         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
973                                               sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
974
975         ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
976                                                sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
977         ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
978                                                sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
979 }
980
981 void
982 MonitorSection::solo_use_in_place ()
983 {
984         /* this is driven by a toggle on a radio group, and so is invoked twice,
985                  once for the item that became inactive and once for the one that became
986                  active.
987                  */
988
989         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
990
991         if (act) {
992                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
993                 if (ract) {
994                         if (!ract->get_active ()) {
995                                 /* We are turning SiP off, which means that AFL or PFL will be turned on
996                                          shortly; don't update the solo model in the mean time, as if the currently
997                                          configured listen position is not the one that is about to be turned on,
998                                          things will go wrong.
999                                          */
1000                                 _inhibit_solo_model_update = true;
1001                         }
1002                         Config->set_solo_control_is_listen_control (!ract->get_active());
1003                         _inhibit_solo_model_update = false;
1004                 }
1005         }
1006 }
1007
1008 void
1009 MonitorSection::solo_use_afl ()
1010 {
1011         /* this is driven by a toggle on a radio group, and so is invoked twice,
1012                  once for the item that became inactive and once for the one that became
1013                  active.
1014                  */
1015
1016         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1017         if (act) {
1018                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1019                 if (ract) {
1020                         if (ract->get_active()) {
1021                                 Config->set_solo_control_is_listen_control (true);
1022                                 Config->set_listen_position (AfterFaderListen);
1023                         }
1024                 }
1025         }
1026 }
1027
1028 void
1029 MonitorSection::solo_use_pfl ()
1030 {
1031         /* this is driven by a toggle on a radio group, and so is invoked twice,
1032            once for the item that became inactive and once for the one that became
1033            active.
1034         */
1035
1036         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1037         if (act) {
1038                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1039                 if (ract) {
1040                         if (ract->get_active()) {
1041                                 Config->set_solo_control_is_listen_control (true);
1042                                 Config->set_listen_position (PreFaderListen);
1043                         }
1044                 }
1045         }
1046 }
1047
1048 void
1049 MonitorSection::update_solo_model ()
1050 {
1051         if (_inhibit_solo_model_update) {
1052                 return;
1053         }
1054
1055         const char* action_name = 0;
1056         Glib::RefPtr<Action> act;
1057
1058         if (Config->get_solo_control_is_listen_control()) {
1059                 switch (Config->get_listen_position()) {
1060                         case AfterFaderListen:
1061                                 action_name = X_("solo-use-afl");
1062                                 break;
1063                         case PreFaderListen:
1064                                 action_name = X_("solo-use-pfl");
1065                                 break;
1066                 }
1067         } else {
1068                 action_name = X_("solo-use-in-place");
1069         }
1070
1071         act = ActionManager::get_action (X_("Solo"), action_name);
1072         if (act) {
1073
1074                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1075                 if (ract) {
1076                         /* because these are radio buttons, one of them will be
1077                                  active no matter what. to trigger a change in the
1078                                  action so that the view picks it up, toggle it.
1079                                  */
1080                         if (ract->get_active()) {
1081                                 ract->set_active (false);
1082                         }
1083                         ract->set_active (true);
1084                 }
1085
1086         }
1087 }
1088
1089 void
1090 MonitorSection::map_state ()
1091 {
1092         if (!_route || !_monitor) {
1093                 return;
1094         }
1095
1096         update_solo_model ();
1097
1098         Glib::RefPtr<Action> act;
1099         Glib::RefPtr<ToggleAction> tact;
1100
1101         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1102         if (act) {
1103                 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1104                 if (tact) {
1105                         tact->set_active (_monitor->cut_all());
1106                 }
1107         }
1108
1109         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1110         if (act) {
1111                 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1112                 if (tact) {
1113                         tact->set_active (_monitor->dim_all());
1114                 }
1115         }
1116
1117         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1118         if (act) {
1119                 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1120                 if (tact) {
1121                         tact->set_active (_monitor->mono());
1122                 }
1123         }
1124
1125         uint32_t nchans = _monitor->output_streams().n_audio();
1126
1127         assert (nchans == _channel_buttons.size ());
1128
1129         for (uint32_t n = 0; n < nchans; ++n) {
1130
1131                 char action_name[32];
1132
1133                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1134                 act = ActionManager::get_action (X_("Monitor"), action_name);
1135                 if (act) {
1136                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1137                         if (tact) {
1138                                 tact->set_active (_monitor->cut (n));
1139                         }
1140                 }
1141
1142                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1143                 act = ActionManager::get_action (X_("Monitor"), action_name);
1144                 if (act) {
1145                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1146                         if (tact) {
1147                                 tact->set_active (_monitor->dimmed (n));
1148                         }
1149                 }
1150
1151                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1152                 act = ActionManager::get_action (X_("Monitor"), action_name);
1153                 if (act) {
1154                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1155                         if (tact) {
1156                                 tact->set_active (_monitor->soloed (n));
1157                         }
1158                 }
1159
1160                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1161                 act = ActionManager::get_action (X_("Monitor"), action_name);
1162                 if (act) {
1163                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1164                         if (tact) {
1165                                 tact->set_active (_monitor->inverted (n));
1166                         }
1167                 }
1168         }
1169 }
1170
1171 void
1172 MonitorSection::do_blink (bool onoff)
1173 {
1174         if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1175                 onoff = true;
1176         }
1177
1178         solo_blink (onoff);
1179         audition_blink (onoff);
1180 }
1181
1182 void
1183 MonitorSection::audition_blink (bool onoff)
1184 {
1185         if (_session == 0) {
1186                 return;
1187         }
1188
1189         if (_session->is_auditioning()) {
1190                 rude_audition_button.set_active (onoff);
1191         } else {
1192                 rude_audition_button.set_active (false);
1193         }
1194 }
1195
1196 void
1197 MonitorSection::solo_blink (bool onoff)
1198 {
1199         if (_session == 0) {
1200                 return;
1201         }
1202
1203         if (_session->soloing() || _session->listening()) {
1204                 rude_solo_button.set_active (onoff);
1205
1206                 if (_session->soloing()) {
1207                         if (_session->solo_isolated()) {
1208                                 rude_iso_button.set_active (onoff);
1209                         } else {
1210                                 rude_iso_button.set_active (false);
1211                         }
1212                 }
1213
1214         } else {
1215                 rude_solo_button.set_active (false);
1216                 rude_iso_button.set_active (false);
1217         }
1218 }
1219
1220 bool
1221 MonitorSection::cancel_isolate (GdkEventButton*)
1222 {
1223         if (_session) {
1224                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1225                 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1226         }
1227
1228         return true;
1229 }
1230
1231 bool
1232 MonitorSection::cancel_audition (GdkEventButton*)
1233 {
1234         if (_session) {
1235                 _session->cancel_audition();
1236         }
1237         return true;
1238 }
1239
1240 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1241         if (action && action->get_active() != value) { \
1242                 action->set_active(value); \
1243         } \
1244
1245 void
1246 MonitorSection::parameter_changed (std::string name)
1247 {
1248         if (name == "solo-control-is-listen-control") {
1249                 update_solo_model ();
1250         } else if (name == "listen-position") {
1251                 update_solo_model ();
1252         } else if (name == "solo-mute-override") {
1253                 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1254         } else if (name == "exclusive-solo") {
1255                 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1256         }
1257 }
1258
1259 void
1260 MonitorSection::assign_controllables ()
1261 {
1262         boost::shared_ptr<Controllable> none;
1263
1264         if (!gain_control) {
1265                 /* too early - GUI controls not set up yet */
1266                 return;
1267         }
1268
1269         if (_session) {
1270                 solo_cut_control->set_controllable (_session->solo_cut_control());
1271                 solo_cut_display->set_controllable (_session->solo_cut_control());
1272         } else {
1273                 solo_cut_control->set_controllable (none);
1274                 solo_cut_display->set_controllable (none);
1275         }
1276
1277         if (_route) {
1278                 gain_control->set_controllable (_route->gain_control());
1279                 gain_display->set_controllable (_route->gain_control());
1280         } else {
1281                 gain_control->set_controllable (none);
1282         }
1283
1284         if (_monitor) {
1285
1286                 cut_all_button.set_controllable (_monitor->cut_control());
1287                 cut_all_button.watch ();
1288                 dim_all_button.set_controllable (_monitor->dim_control());
1289                 dim_all_button.watch ();
1290                 mono_button.set_controllable (_monitor->mono_control());
1291                 mono_button.watch ();
1292
1293                 dim_control->set_controllable (_monitor->dim_level_control ());
1294                 dim_display->set_controllable (_monitor->dim_level_control ());
1295                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1296                 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1297
1298         } else {
1299
1300                 cut_all_button.set_controllable (none);
1301                 dim_all_button.set_controllable (none);
1302                 mono_button.set_controllable (none);
1303
1304                 dim_control->set_controllable (none);
1305                 dim_display->set_controllable (none);
1306                 solo_boost_control->set_controllable (none);
1307                 solo_boost_display->set_controllable (none);
1308         }
1309 }
1310
1311 string
1312 MonitorSection::state_id() const
1313 {
1314         return "monitor-section";
1315 }
1316
1317 void
1318 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1319 {
1320         using namespace Menu_Helpers;
1321
1322         if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1323                 return;
1324         }
1325
1326         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1327         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1328                 ++i;
1329         }
1330
1331         if (i != output_menu_bundles.end()) {
1332                 return;
1333         }
1334
1335         output_menu_bundles.push_back (b);
1336
1337         MenuList& citems = output_menu.items();
1338
1339         std::string n = b->name ();
1340         replace_all (n, "_", " ");
1341
1342         citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1343 }
1344
1345 void
1346 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1347 {
1348
1349         ARDOUR::BundleList current = _route->output()->bundles_connected ();
1350
1351         if (std::find (current.begin(), current.end(), c) == current.end()) {
1352                 _route->output()->connect_ports_to_bundle (c, true, this);
1353         } else {
1354                 _route->output()->disconnect_ports_from_bundle (c, this);
1355         }
1356 }
1357
1358 gint
1359 MonitorSection::output_release (GdkEventButton *ev)
1360 {
1361         switch (ev->button) {
1362         case 3:
1363                 edit_output_configuration ();
1364                 break;
1365         }
1366
1367         return false;
1368 }
1369
1370 struct RouteCompareByName {
1371         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1372                 return a->name().compare (b->name()) < 0;
1373         }
1374 };
1375
1376 gint
1377 MonitorSection::output_press (GdkEventButton *ev)
1378 {
1379         using namespace Menu_Helpers;
1380         if (!_session) {
1381                 MessageDialog msg (_("No session - no I/O changes are possible"));
1382                 msg.run ();
1383                 return true;
1384         }
1385
1386         MenuList& citems = output_menu.items();
1387         switch (ev->button) {
1388
1389         case 3:
1390                 return false;  //wait for the mouse-up to pop the dialog
1391
1392         case 1:
1393         {
1394                 output_menu.set_name ("ArdourContextMenu");
1395                 citems.clear ();
1396                 output_menu_bundles.clear ();
1397
1398                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1399
1400                 citems.push_back (SeparatorElem());
1401                 uint32_t const n_with_separator = citems.size ();
1402
1403                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1404
1405                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1406
1407                 /* give user bundles first chance at being in the menu */
1408
1409                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1410                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1411                                 maybe_add_bundle_to_output_menu (*i, current);
1412                         }
1413                 }
1414
1415                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1416                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1417                                 maybe_add_bundle_to_output_menu (*i, current);
1418                         }
1419                 }
1420
1421                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1422                 RouteList copy = *routes;
1423                 copy.sort (RouteCompareByName ());
1424                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1425                         maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1426                 }
1427
1428                 if (citems.size() == n_with_separator) {
1429                         /* no routes added; remove the separator */
1430                         citems.pop_back ();
1431                 }
1432
1433                 citems.push_back (SeparatorElem());
1434                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1435
1436                 output_menu.popup (1, ev->time);
1437                 break;
1438         }
1439
1440         default:
1441                 break;
1442         }
1443         return TRUE;
1444 }
1445
1446 void
1447 MonitorSection::update_output_display ()
1448 {
1449         if (!_route || !_monitor || _session->deletion_in_progress()) {
1450                 return;
1451         }
1452
1453         uint32_t io_count;
1454         uint32_t io_index;
1455         boost::shared_ptr<Port> port;
1456         vector<string> port_connections;
1457
1458         uint32_t total_connection_count = 0;
1459         uint32_t io_connection_count = 0;
1460         uint32_t ardour_connection_count = 0;
1461         uint32_t system_connection_count = 0;
1462         uint32_t other_connection_count = 0;
1463
1464         ostringstream label;
1465
1466         bool have_label = false;
1467         bool each_io_has_one_connection = true;
1468
1469         string connection_name;
1470         string ardour_track_name;
1471         string other_connection_type;
1472         string system_ports;
1473         string system_port;
1474
1475         ostringstream tooltip;
1476         char * tooltip_cstr;
1477
1478         io_count = _route->n_outputs().n_total();
1479         tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1480
1481
1482         for (io_index = 0; io_index < io_count; ++io_index) {
1483
1484                 port = _route->output()->nth (io_index);
1485
1486                 //ignore any port connections that don't match our DataType
1487                 if (port->type() != DataType::AUDIO) {
1488                         continue;
1489                 }
1490
1491                 port_connections.clear ();
1492                 port->get_connections(port_connections);
1493                 io_connection_count = 0;
1494
1495                 if (!port_connections.empty()) {
1496                         for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1497                                 string pn = "";
1498                                 string& connection_name (*i);
1499
1500                                 if (connection_name.find("system:") == 0) {
1501                                         pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1502                                 }
1503
1504                                 if (io_connection_count == 0) {
1505                                         tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1506                                                 << " -> "
1507                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1508                                 } else {
1509                                         tooltip << ", "
1510                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1511                                 }
1512
1513                                 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1514                                         if (ardour_track_name.empty()) {
1515                                                 // "ardour:Master/in 1" -> "ardour:Master/"
1516                                                 string::size_type slash = connection_name.find("/");
1517                                                 if (slash != string::npos) {
1518                                                         ardour_track_name = connection_name.substr(0, slash + 1);
1519                                                 }
1520                                         }
1521
1522                                         if (connection_name.find(ardour_track_name) == 0) {
1523                                                 ++ardour_connection_count;
1524                                         }
1525                                 } else if (!pn.empty()) {
1526                                         if (system_ports.empty()) {
1527                                                 system_ports += pn;
1528                                         } else {
1529                                                 system_ports += "/" + pn;
1530                                         }
1531                                         if (connection_name.find("system:") == 0) {
1532                                                 ++system_connection_count;
1533                                         }
1534                                 } else if (connection_name.find("system:") == 0) {
1535                                         // "system:playback_123" -> "123"
1536                                         system_port = connection_name.substr(16);
1537                                         if (system_ports.empty()) {
1538                                                 system_ports += system_port;
1539                                         } else {
1540                                                 system_ports += "/" + system_port;
1541                                         }
1542
1543                                         ++system_connection_count;
1544                                 } else {
1545                                         if (other_connection_type.empty()) {
1546                                                 // "jamin:in 1" -> "jamin:"
1547                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1548                                         }
1549
1550                                         if (connection_name.find(other_connection_type) == 0) {
1551                                                 ++other_connection_count;
1552                                         }
1553                                 }
1554
1555                                 ++total_connection_count;
1556                                 ++io_connection_count;
1557                         }
1558                 }
1559
1560                 if (io_connection_count != 1) {
1561                         each_io_has_one_connection = false;
1562                 }
1563         }
1564
1565         if (total_connection_count == 0) {
1566                 tooltip << endl << _("Disconnected");
1567         }
1568
1569         tooltip_cstr = new char[tooltip.str().size() + 1];
1570         strcpy(tooltip_cstr, tooltip.str().c_str());
1571
1572         set_tooltip (output_button, tooltip_cstr, "");
1573
1574         if (each_io_has_one_connection) {
1575                 if (total_connection_count == ardour_connection_count) {
1576                         // all connections are to the same track in ardour
1577                         // "ardour:Master/" -> "Master"
1578                         string::size_type slash = ardour_track_name.find("/");
1579                         if (slash != string::npos) {
1580                                 label << ardour_track_name.substr(7, slash - 7);
1581                                 have_label = true;
1582                         }
1583                 } else if (total_connection_count == system_connection_count) {
1584                         // all connections are to system ports
1585                         label << system_ports;
1586                         have_label = true;
1587                 } else if (total_connection_count == other_connection_count) {
1588                         // all connections are to the same external program eg jamin
1589                         // "jamin:" -> "jamin"
1590                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1591                         have_label = true;
1592                 }
1593         }
1594
1595         if (!have_label) {
1596                 if (total_connection_count == 0) {
1597                         // Disconnected
1598                         label << "-";
1599                 } else {
1600                         // Odd configuration
1601                         label << "*" << total_connection_count << "*";
1602                 }
1603         }
1604
1605         output_button->set_text (label.str());
1606 }
1607
1608 void
1609 MonitorSection::disconnect_output ()
1610 {
1611         if (_route) {
1612                 _route->output()->disconnect(this);
1613         }
1614 }
1615
1616 void
1617 MonitorSection::edit_output_configuration ()
1618 {
1619         if (_output_selector == 0) {
1620                 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1621         }
1622         _output_selector->present ();
1623 }
1624
1625 void
1626 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1627 {
1628         if (!_route) {
1629                 return;
1630         }
1631         boost::shared_ptr<Port> a = wa.lock ();
1632         boost::shared_ptr<Port> b = wb.lock ();
1633         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1634                 update_output_display ();
1635         }
1636 }
1637
1638 void
1639 MonitorSection::load_bindings ()
1640 {
1641         bindings = Bindings::get_bindings (X_("Monitor Section"));
1642 }
1643
1644 void
1645 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1646 {
1647         boost::shared_ptr<Processor> processor (p.lock ());
1648         if (!processor || !processor->display_to_user()) {
1649                 return;
1650         }
1651         if (boost::dynamic_pointer_cast<Amp>(processor)) {
1652                 return;
1653         }
1654         ++(*cnt);
1655 }
1656
1657 uint32_t
1658 MonitorSection::count_processors ()
1659 {
1660         uint32_t processor_count = 0;
1661         if (_route) {
1662                 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1663         }
1664         return processor_count;
1665 }
1666
1667 void
1668 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1669 {
1670         update_processor_box ();
1671 }
1672
1673 void
1674 MonitorSection::use_others_actions ()
1675 {
1676         rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1677 }
1678
1679 void
1680 MonitorSection::toggle_use_monitor_section ()
1681 {
1682         if (!_session) {
1683                 return;
1684         }
1685
1686         bool yn = ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active();
1687
1688         if (yn) {
1689                 _session->add_monitor_section ();
1690         } else {
1691                 _session->remove_monitor_section ();
1692         }
1693
1694         Config->set_use_monitor_bus (yn);
1695 }