7fcfbd0810ff94a46b903af6e0afa1a1a9ed52f2
[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 "mixer_ui.h"
46 #include "monitor_section.h"
47 #include "public_editor.h"
48 #include "timers.h"
49 #include "tooltips.h"
50 #include "ui_config.h"
51 #include "utils.h"
52
53 #include "pbd/i18n.h"
54
55 using namespace ARDOUR;
56 using namespace ARDOUR_UI_UTILS;
57 using namespace Gtk;
58 using namespace Gtkmm2ext;
59 using namespace PBD;
60 using namespace std;
61
62 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
63 Gtkmm2ext::ActionMap MonitorSection::myactions (X_("monitor section"));
64 Gtkmm2ext::Bindings* MonitorSection::bindings = 0;
65
66 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
67
68 MonitorSection::MonitorSection (Session* s)
69         : SessionHandlePtr (s)
70         , RouteUI (s)
71         , _tearoff (0)
72         , channel_table_viewport (*channel_table_scroller.get_hadjustment()
73                                   , *channel_table_scroller.get_vadjustment ())
74         , gain_control (0)
75         , dim_control (0)
76         , solo_boost_control (0)
77         , solo_cut_control (0)
78         , gain_display (0)
79         , dim_display (0)
80         , solo_boost_display (0)
81         , solo_cut_display (0)
82         , _output_selector (0)
83         , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
84         , afl_button (_("AFL"), ArdourButton::led_default_elements)
85         , pfl_button (_("PFL"), ArdourButton::led_default_elements)
86         , exclusive_solo_button (ArdourButton::led_default_elements)
87         , solo_mute_override_button (ArdourButton::led_default_elements)
88         , toggle_processorbox_button (ArdourButton::default_elements)
89         , _inhibit_solo_model_update (false)
90         , _ui_initialized (false)
91 {
92
93         using namespace Menu_Helpers;
94
95         Glib::RefPtr<Action> act;
96
97         if (!monitor_actions) {
98                 register_actions ();
99                 load_bindings ();
100         }
101
102         set_data ("ardour-bindings", bindings);
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::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorMono));
899
900         myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
901                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorCutAll));
902
903         myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
904                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorDimAll));
905
906         act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
907                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
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::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
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::ptr_fun (action_proxy1), CutChannel, 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::ptr_fun (action_proxy1), DimChannel, 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::ptr_fun (action_proxy1), SoloChannel, 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::ptr_fun (action_proxy1), InvertChannel, 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::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
948         myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
949                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
950         myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
951                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
952
953         myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
954                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
955
956 }
957
958 void
959 MonitorSection::solo_use_in_place ()
960 {
961         /* this is driven by a toggle on a radio group, and so is invoked twice,
962                  once for the item that became inactive and once for the one that became
963                  active.
964                  */
965
966         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
967
968         if (act) {
969                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
970                 if (ract) {
971                         if (!ract->get_active ()) {
972                                 /* We are turning SiP off, which means that AFL or PFL will be turned on
973                                          shortly; don't update the solo model in the mean time, as if the currently
974                                          configured listen position is not the one that is about to be turned on,
975                                          things will go wrong.
976                                          */
977                                 _inhibit_solo_model_update = true;
978                         }
979                         Config->set_solo_control_is_listen_control (!ract->get_active());
980                         _inhibit_solo_model_update = false;
981                 }
982         }
983 }
984
985 void
986 MonitorSection::solo_use_afl ()
987 {
988         /* this is driven by a toggle on a radio group, and so is invoked twice,
989                  once for the item that became inactive and once for the one that became
990                  active.
991                  */
992
993         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
994         if (act) {
995                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
996                 if (ract) {
997                         if (ract->get_active()) {
998                                 Config->set_solo_control_is_listen_control (true);
999                                 Config->set_listen_position (AfterFaderListen);
1000                         }
1001                 }
1002         }
1003 }
1004
1005 void
1006 MonitorSection::solo_use_pfl ()
1007 {
1008         /* this is driven by a toggle on a radio group, and so is invoked twice,
1009            once for the item that became inactive and once for the one that became
1010            active.
1011         */
1012
1013         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1014         if (act) {
1015                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1016                 if (ract) {
1017                         if (ract->get_active()) {
1018                                 Config->set_solo_control_is_listen_control (true);
1019                                 Config->set_listen_position (PreFaderListen);
1020                         }
1021                 }
1022         }
1023 }
1024
1025 void
1026 MonitorSection::update_solo_model ()
1027 {
1028         if (_inhibit_solo_model_update) {
1029                 return;
1030         }
1031
1032         const char* action_name = 0;
1033         Glib::RefPtr<Action> act;
1034
1035         if (Config->get_solo_control_is_listen_control()) {
1036                 switch (Config->get_listen_position()) {
1037                         case AfterFaderListen:
1038                                 action_name = X_("solo-use-afl");
1039                                 break;
1040                         case PreFaderListen:
1041                                 action_name = X_("solo-use-pfl");
1042                                 break;
1043                 }
1044         } else {
1045                 action_name = X_("solo-use-in-place");
1046         }
1047
1048         act = ActionManager::get_action (X_("Solo"), action_name);
1049         if (act) {
1050
1051                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1052                 if (ract) {
1053                         /* because these are radio buttons, one of them will be
1054                                  active no matter what. to trigger a change in the
1055                                  action so that the view picks it up, toggle it.
1056                                  */
1057                         if (ract->get_active()) {
1058                                 ract->set_active (false);
1059                         }
1060                         ract->set_active (true);
1061                 }
1062
1063         }
1064 }
1065
1066 void
1067 MonitorSection::map_state ()
1068 {
1069         if (!_route || !_monitor) {
1070                 return;
1071         }
1072
1073         Glib::RefPtr<Action> act;
1074
1075         update_solo_model ();
1076
1077         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1078         if (act) {
1079                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1080                 if (tact) {
1081                         tact->set_active (_monitor->cut_all());
1082                 }
1083         }
1084
1085         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1086         if (act) {
1087                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1088                 if (tact) {
1089                         tact->set_active (_monitor->dim_all());
1090                 }
1091         }
1092
1093         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1094         if (act) {
1095                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1096                 if (tact) {
1097                         tact->set_active (_monitor->mono());
1098                 }
1099         }
1100
1101         uint32_t nchans = _monitor->output_streams().n_audio();
1102
1103         assert (nchans == _channel_buttons.size ());
1104
1105         for (uint32_t n = 0; n < nchans; ++n) {
1106
1107                 char action_name[32];
1108
1109                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1110                 act = ActionManager::get_action (X_("Monitor"), action_name);
1111                 if (act) {
1112                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1113                         if (tact) {
1114                                 tact->set_active (_monitor->cut (n));
1115                         }
1116                 }
1117
1118                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1119                 act = ActionManager::get_action (X_("Monitor"), action_name);
1120                 if (act) {
1121                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1122                         if (tact) {
1123                                 tact->set_active (_monitor->dimmed (n));
1124                         }
1125                 }
1126
1127                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1128                 act = ActionManager::get_action (X_("Monitor"), action_name);
1129                 if (act) {
1130                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1131                         if (tact) {
1132                                 tact->set_active (_monitor->soloed (n));
1133                         }
1134                 }
1135
1136                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1137                 act = ActionManager::get_action (X_("Monitor"), action_name);
1138                 if (act) {
1139                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1140                         if (tact) {
1141                                 tact->set_active (_monitor->inverted (n));
1142                         }
1143                 }
1144         }
1145 }
1146
1147 void
1148 MonitorSection::do_blink (bool onoff)
1149 {
1150         solo_blink (onoff);
1151         audition_blink (onoff);
1152 }
1153
1154 void
1155 MonitorSection::audition_blink (bool onoff)
1156 {
1157         if (_session == 0) {
1158                 return;
1159         }
1160
1161         if (_session->is_auditioning()) {
1162                 rude_audition_button.set_active (onoff);
1163         } else {
1164                 rude_audition_button.set_active (false);
1165         }
1166 }
1167
1168 void
1169 MonitorSection::solo_blink (bool onoff)
1170 {
1171         if (_session == 0) {
1172                 return;
1173         }
1174
1175         if (_session->soloing() || _session->listening()) {
1176                 rude_solo_button.set_active (onoff);
1177
1178                 if (_session->soloing()) {
1179                         if (_session->solo_isolated()) {
1180                                 rude_iso_button.set_active (onoff);
1181                         } else {
1182                                 rude_iso_button.set_active (false);
1183                         }
1184                 }
1185
1186         } else {
1187                 rude_solo_button.set_active (false);
1188                 rude_iso_button.set_active (false);
1189         }
1190 }
1191
1192 bool
1193 MonitorSection::cancel_isolate (GdkEventButton*)
1194 {
1195         if (_session) {
1196                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1197                 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1198         }
1199
1200         return true;
1201 }
1202
1203 bool
1204 MonitorSection::cancel_audition (GdkEventButton*)
1205 {
1206         if (_session) {
1207                 _session->cancel_audition();
1208         }
1209         return true;
1210 }
1211
1212 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1213         if (action) { \
1214                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1215                 if (tact && tact->get_active() != value) { \
1216                         tact->set_active(value); \
1217                 } \
1218         }
1219
1220 void
1221 MonitorSection::parameter_changed (std::string name)
1222 {
1223         if (name == "solo-control-is-listen-control") {
1224                 update_solo_model ();
1225         } else if (name == "listen-position") {
1226                 update_solo_model ();
1227         } else if (name == "solo-mute-override") {
1228                 SYNCHRONIZE_TOGGLE_ACTION(
1229                                 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1230                                 Config->get_solo_mute_override ())
1231         } else if (name == "exclusive-solo") {
1232                 SYNCHRONIZE_TOGGLE_ACTION(
1233                                 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1234                                 Config->get_exclusive_solo ())
1235         }
1236 }
1237
1238 void
1239 MonitorSection::assign_controllables ()
1240 {
1241         boost::shared_ptr<Controllable> none;
1242
1243         if (!gain_control) {
1244                 /* too early - GUI controls not set up yet */
1245                 return;
1246         }
1247
1248         if (_session) {
1249                 solo_cut_control->set_controllable (_session->solo_cut_control());
1250                 solo_cut_display->set_controllable (_session->solo_cut_control());
1251         } else {
1252                 solo_cut_control->set_controllable (none);
1253                 solo_cut_display->set_controllable (none);
1254         }
1255
1256         if (_route) {
1257                 gain_control->set_controllable (_route->gain_control());
1258                 gain_display->set_controllable (_route->gain_control());
1259         } else {
1260                 gain_control->set_controllable (none);
1261         }
1262
1263         if (_monitor) {
1264
1265                 cut_all_button.set_controllable (_monitor->cut_control());
1266                 cut_all_button.watch ();
1267                 dim_all_button.set_controllable (_monitor->dim_control());
1268                 dim_all_button.watch ();
1269                 mono_button.set_controllable (_monitor->mono_control());
1270                 mono_button.watch ();
1271
1272                 dim_control->set_controllable (_monitor->dim_level_control ());
1273                 dim_display->set_controllable (_monitor->dim_level_control ());
1274                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1275                 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1276
1277         } else {
1278
1279                 cut_all_button.set_controllable (none);
1280                 dim_all_button.set_controllable (none);
1281                 mono_button.set_controllable (none);
1282
1283                 dim_control->set_controllable (none);
1284                 dim_display->set_controllable (none);
1285                 solo_boost_control->set_controllable (none);
1286                 solo_boost_display->set_controllable (none);
1287         }
1288 }
1289
1290 string
1291 MonitorSection::state_id() const
1292 {
1293         return "monitor-section";
1294 }
1295
1296 void
1297 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1298 {
1299         using namespace Menu_Helpers;
1300
1301         if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1302                 return;
1303         }
1304
1305         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1306         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1307                 ++i;
1308         }
1309
1310         if (i != output_menu_bundles.end()) {
1311                 return;
1312         }
1313
1314         output_menu_bundles.push_back (b);
1315
1316         MenuList& citems = output_menu.items();
1317
1318         std::string n = b->name ();
1319         replace_all (n, "_", " ");
1320
1321         citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1322 }
1323
1324 void
1325 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1326 {
1327
1328         ARDOUR::BundleList current = _route->output()->bundles_connected ();
1329
1330         if (std::find (current.begin(), current.end(), c) == current.end()) {
1331                 _route->output()->connect_ports_to_bundle (c, true, this);
1332         } else {
1333                 _route->output()->disconnect_ports_from_bundle (c, this);
1334         }
1335 }
1336
1337 gint
1338 MonitorSection::output_release (GdkEventButton *ev)
1339 {
1340         switch (ev->button) {
1341         case 3:
1342                 edit_output_configuration ();
1343                 break;
1344         }
1345
1346         return false;
1347 }
1348
1349 struct RouteCompareByName {
1350         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1351                 return a->name().compare (b->name()) < 0;
1352         }
1353 };
1354
1355 gint
1356 MonitorSection::output_press (GdkEventButton *ev)
1357 {
1358         using namespace Menu_Helpers;
1359         if (!_session) {
1360                 MessageDialog msg (_("No session - no I/O changes are possible"));
1361                 msg.run ();
1362                 return true;
1363         }
1364
1365         MenuList& citems = output_menu.items();
1366         switch (ev->button) {
1367
1368         case 3:
1369                 return false;  //wait for the mouse-up to pop the dialog
1370
1371         case 1:
1372         {
1373                 output_menu.set_name ("ArdourContextMenu");
1374                 citems.clear ();
1375                 output_menu_bundles.clear ();
1376
1377                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1378
1379                 citems.push_back (SeparatorElem());
1380                 uint32_t const n_with_separator = citems.size ();
1381
1382                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1383
1384                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1385
1386                 /* give user bundles first chance at being in the menu */
1387
1388                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1389                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1390                                 maybe_add_bundle_to_output_menu (*i, current);
1391                         }
1392                 }
1393
1394                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1395                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1396                                 maybe_add_bundle_to_output_menu (*i, current);
1397                         }
1398                 }
1399
1400                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1401                 RouteList copy = *routes;
1402                 copy.sort (RouteCompareByName ());
1403                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1404                         maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1405                 }
1406
1407                 if (citems.size() == n_with_separator) {
1408                         /* no routes added; remove the separator */
1409                         citems.pop_back ();
1410                 }
1411
1412                 citems.push_back (SeparatorElem());
1413                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1414
1415                 output_menu.popup (1, ev->time);
1416                 break;
1417         }
1418
1419         default:
1420                 break;
1421         }
1422         return TRUE;
1423 }
1424
1425 void
1426 MonitorSection::update_output_display ()
1427 {
1428         if (!_route || !_monitor || _session->deletion_in_progress()) {
1429                 return;
1430         }
1431
1432         uint32_t io_count;
1433         uint32_t io_index;
1434         boost::shared_ptr<Port> port;
1435         vector<string> port_connections;
1436
1437         uint32_t total_connection_count = 0;
1438         uint32_t io_connection_count = 0;
1439         uint32_t ardour_connection_count = 0;
1440         uint32_t system_connection_count = 0;
1441         uint32_t other_connection_count = 0;
1442
1443         ostringstream label;
1444
1445         bool have_label = false;
1446         bool each_io_has_one_connection = true;
1447
1448         string connection_name;
1449         string ardour_track_name;
1450         string other_connection_type;
1451         string system_ports;
1452         string system_port;
1453
1454         ostringstream tooltip;
1455         char * tooltip_cstr;
1456
1457         io_count = _route->n_outputs().n_total();
1458         tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1459
1460
1461         for (io_index = 0; io_index < io_count; ++io_index) {
1462
1463                 port = _route->output()->nth (io_index);
1464
1465                 //ignore any port connections that don't match our DataType
1466                 if (port->type() != DataType::AUDIO) {
1467                         continue;
1468                 }
1469
1470                 port_connections.clear ();
1471                 port->get_connections(port_connections);
1472                 io_connection_count = 0;
1473
1474                 if (!port_connections.empty()) {
1475                         for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1476                                 string pn = "";
1477                                 string& connection_name (*i);
1478
1479                                 if (connection_name.find("system:") == 0) {
1480                                         pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1481                                 }
1482
1483                                 if (io_connection_count == 0) {
1484                                         tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1485                                                 << " -> "
1486                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1487                                 } else {
1488                                         tooltip << ", "
1489                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1490                                 }
1491
1492                                 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1493                                         if (ardour_track_name.empty()) {
1494                                                 // "ardour:Master/in 1" -> "ardour:Master/"
1495                                                 string::size_type slash = connection_name.find("/");
1496                                                 if (slash != string::npos) {
1497                                                         ardour_track_name = connection_name.substr(0, slash + 1);
1498                                                 }
1499                                         }
1500
1501                                         if (connection_name.find(ardour_track_name) == 0) {
1502                                                 ++ardour_connection_count;
1503                                         }
1504                                 } else if (!pn.empty()) {
1505                                         if (system_ports.empty()) {
1506                                                 system_ports += pn;
1507                                         } else {
1508                                                 system_ports += "/" + pn;
1509                                         }
1510                                         if (connection_name.find("system:") == 0) {
1511                                                 ++system_connection_count;
1512                                         }
1513                                 } else if (connection_name.find("system:") == 0) {
1514                                         // "system:playback_123" -> "123"
1515                                         system_port = connection_name.substr(16);
1516                                         if (system_ports.empty()) {
1517                                                 system_ports += system_port;
1518                                         } else {
1519                                                 system_ports += "/" + system_port;
1520                                         }
1521
1522                                         ++system_connection_count;
1523                                 } else {
1524                                         if (other_connection_type.empty()) {
1525                                                 // "jamin:in 1" -> "jamin:"
1526                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1527                                         }
1528
1529                                         if (connection_name.find(other_connection_type) == 0) {
1530                                                 ++other_connection_count;
1531                                         }
1532                                 }
1533
1534                                 ++total_connection_count;
1535                                 ++io_connection_count;
1536                         }
1537                 }
1538
1539                 if (io_connection_count != 1) {
1540                         each_io_has_one_connection = false;
1541                 }
1542         }
1543
1544         if (total_connection_count == 0) {
1545                 tooltip << endl << _("Disconnected");
1546         }
1547
1548         tooltip_cstr = new char[tooltip.str().size() + 1];
1549         strcpy(tooltip_cstr, tooltip.str().c_str());
1550
1551         set_tooltip (output_button, tooltip_cstr, "");
1552
1553         if (each_io_has_one_connection) {
1554                 if (total_connection_count == ardour_connection_count) {
1555                         // all connections are to the same track in ardour
1556                         // "ardour:Master/" -> "Master"
1557                         string::size_type slash = ardour_track_name.find("/");
1558                         if (slash != string::npos) {
1559                                 label << ardour_track_name.substr(7, slash - 7);
1560                                 have_label = true;
1561                         }
1562                 } else if (total_connection_count == system_connection_count) {
1563                         // all connections are to system ports
1564                         label << system_ports;
1565                         have_label = true;
1566                 } else if (total_connection_count == other_connection_count) {
1567                         // all connections are to the same external program eg jamin
1568                         // "jamin:" -> "jamin"
1569                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1570                         have_label = true;
1571                 }
1572         }
1573
1574         if (!have_label) {
1575                 if (total_connection_count == 0) {
1576                         // Disconnected
1577                         label << "-";
1578                 } else {
1579                         // Odd configuration
1580                         label << "*" << total_connection_count << "*";
1581                 }
1582         }
1583
1584         output_button->set_text (label.str());
1585 }
1586
1587 void
1588 MonitorSection::disconnect_output ()
1589 {
1590         if (_route) {
1591                 _route->output()->disconnect(this);
1592         }
1593 }
1594
1595 void
1596 MonitorSection::edit_output_configuration ()
1597 {
1598         if (_output_selector == 0) {
1599                 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1600         }
1601         _output_selector->present ();
1602 }
1603
1604 void
1605 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1606 {
1607         if (!_route) {
1608                 return;
1609         }
1610         boost::shared_ptr<Port> a = wa.lock ();
1611         boost::shared_ptr<Port> b = wb.lock ();
1612         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1613                 update_output_display ();
1614         }
1615 }
1616
1617 void
1618 MonitorSection::load_bindings ()
1619 {
1620         bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1621 }
1622
1623 void
1624 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1625 {
1626         boost::shared_ptr<Processor> processor (p.lock ());
1627         if (!processor || !processor->display_to_user()) {
1628                 return;
1629         }
1630         if (boost::dynamic_pointer_cast<Amp>(processor)) {
1631                 return;
1632         }
1633         ++(*cnt);
1634 }
1635
1636 uint32_t
1637 MonitorSection::count_processors ()
1638 {
1639         uint32_t processor_count = 0;
1640         if (_route) {
1641                 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1642         }
1643         return processor_count;
1644 }
1645
1646 void
1647 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1648 {
1649         update_processor_box ();
1650 }
1651
1652 void
1653 MonitorSection::action_proxy0 (enum MonitorActions action)
1654 {
1655         MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1656         if (!ms) {
1657                 return;
1658         }
1659         switch (action) {
1660                 case MonitorMono:
1661                         ms->mono ();
1662                         break;
1663                 case MonitorCutAll:
1664                         ms->cut_all ();
1665                         break;
1666                 case MonitorDimAll:
1667                         ms->dim_all ();
1668                         break;
1669                 case ToggleExclusiveSolo:
1670                         ms->toggle_exclusive_solo ();
1671                         break;
1672                 case ToggleMuteOverridesSolo:
1673                         ms->toggle_mute_overrides_solo ();
1674                         break;
1675                 case SoloUseInPlace:
1676                         ms->solo_use_in_place ();
1677                         break;
1678                 case SoloUseAFL:
1679                         ms->solo_use_afl ();
1680                         break;
1681                 case SoloUsePFL:
1682                         ms->solo_use_pfl ();
1683                         break;
1684                 case ToggleMonitorProcessorBox:
1685                         ms->update_processor_box ();
1686                         break;
1687         }
1688 }
1689
1690 void
1691 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1692 {
1693         MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1694         if (!ms) {
1695                 return;
1696         }
1697         switch (action) {
1698                 case CutChannel:
1699                         ms->cut_channel (chn);
1700                         break;
1701                 case DimChannel:
1702                         ms->dim_channel (chn);
1703                         break;
1704                 case SoloChannel:
1705                         ms->solo_channel (chn);
1706                         break;
1707                 case InvertChannel:
1708                         ms->invert_channel (chn);
1709                         break;
1710         }
1711 }