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