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