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