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