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