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