1 /*
2  * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
3  * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
5  * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
6  * Copyright (C) 2008-2012 Carl Hetherington <carl@carlh.net>
7  * Copyright (C) 2009 Sampo Savolainen <v2@iki.fi>
8  * Copyright (C) 2012-2015 Tim Mayberry <mojofunk@gmail.com>
9  * Copyright (C) 2013-2015 Nick Mainsbridge <mainsbridge@gmail.com>
10  * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
11  * Copyright (C) 2014-2017 Ben Loftis <ben@harrisonconsoles.com>
12  * Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com>
13  * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License along
26  * with this program; if not, write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28  */
29 
30 #include <map>
31 #include <boost/algorithm/string.hpp>
32 
33 #include <gtkmm/stock.h>
34 
35 #include "pbd/memento_command.h"
36 #include "pbd/controllable.h"
37 #include "pbd/enumwriter.h"
38 
39 #include "ardour/dB.h"
40 #include "ardour/route_group.h"
41 #include "ardour/solo_isolate_control.h"
42 #include "ardour/vca.h"
43 #include "ardour/vca_manager.h"
44 #include "ardour/audio_track.h"
45 #include "ardour/audio_port.h"
46 #include "ardour/audioengine.h"
47 #include "ardour/filename_extensions.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/monitor_control.h"
50 #include "ardour/internal_send.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/polarity_processor.h"
53 #include "ardour/profile.h"
54 #include "ardour/phase_control.h"
55 #include "ardour/send.h"
56 #include "ardour/route.h"
57 #include "ardour/session.h"
58 #include "ardour/session_playlists.h"
59 #include "ardour/solo_mute_release.h"
60 #include "ardour/template_utils.h"
61 
62 #include "gtkmm2ext/gtk_ui.h"
63 #include "gtkmm2ext/doi.h"
64 #include "gtkmm2ext/gtk_ui.h"
65 #include "gtkmm2ext/utils.h"
66 
67 #include "widgets/ardour_button.h"
68 #include "widgets/binding_proxy.h"
69 #include "widgets/prompter.h"
70 
71 #include "ardour_dialog.h"
72 #include "ardour_ui.h"
73 #include "automation_time_axis.h"
74 #include "editor.h"
75 #include "group_tabs.h"
76 #include "gui_object.h"
77 #include "gui_thread.h"
78 #include "keyboard.h"
79 #include "latency_gui.h"
80 #include "mixer_strip.h"
81 #include "mixer_ui.h"
82 #include "patch_change_widget.h"
83 #include "playlist_selector.h"
84 #include "plugin_pin_dialog.h"
85 #include "rgb_macros.h"
86 #include "route_time_axis.h"
87 #include "route_ui.h"
88 #include "save_template_dialog.h"
89 #include "timers.h"
90 #include "ui_config.h"
91 #include "utils.h"
92 
93 #include "pbd/i18n.h"
94 
95 using namespace Gtk;
96 using namespace Gtkmm2ext;
97 using namespace ARDOUR;
98 using namespace ARDOUR_UI_UTILS;
99 using namespace ArdourWidgets;
100 using namespace PBD;
101 using namespace std;
102 
103 uint32_t RouteUI::_max_invert_buttons = 3;
104 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
105 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
106 std::string RouteUI::program_port_prefix;
107 
108 RouteUI::IOSelectorMap RouteUI::input_selectors;
109 RouteUI::IOSelectorMap RouteUI::output_selectors;
110 
111 void
delete_ioselector(IOSelectorMap & m,boost::shared_ptr<ARDOUR::Route> r)112 RouteUI::delete_ioselector (IOSelectorMap& m, boost::shared_ptr<ARDOUR::Route> r)
113 {
114 	if (!r) {
115 		return;
116 	}
117 	IOSelectorMap::iterator i = m.find (r->id ());
118 	if (i != m.end ()) {
119 		delete i->second;
120 		m.erase (i);
121 	}
122 }
123 
RouteUI(ARDOUR::Session * sess)124 RouteUI::RouteUI (ARDOUR::Session* sess)
125 	: monitor_input_button (0)
126 	, monitor_disk_button (0)
127 	, mute_menu(0)
128 	, solo_menu(0)
129 	, sends_menu(0)
130 	, playlist_action_menu (0)
131 	, _playlist_selector(0)
132 	, _record_menu(0)
133 	, _comment_window(0)
134 	, _comment_area(0)
135 	, _invert_menu(0)
136 {
137 	if (program_port_prefix.empty()) {
138 		// compare to gtk2_ardour/port_group.cc
139 		string lpn (PROGRAM_NAME);
140 		boost::to_lower (lpn);
141 		program_port_prefix = lpn + ":"; // e.g. "ardour:"
142 	}
143 
144 	if (sess) {
145 		init ();
146 	}
147 }
148 
~RouteUI()149 RouteUI::~RouteUI()
150 {
151 	if (_route) {
152 		ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
153 	}
154 
155 	delete_patch_change_dialog ();
156 
157 	delete_ioselector (input_selectors, _route);
158 	delete_ioselector (output_selectors, _route);
159 
160 	_route.reset (); /* drop reference to route, so that it can be cleaned up */
161 	route_connections.drop_connections ();
162 
163 	delete solo_menu;
164 	delete mute_menu;
165 	delete sends_menu;
166 	delete monitor_input_button;
167 	delete monitor_disk_button;
168 	delete playlist_action_menu;
169 	delete _record_menu;
170 	delete _comment_window;
171 	delete _invert_menu;
172 	delete _playlist_selector;
173 
174 	send_blink_connection.disconnect ();
175 	rec_blink_connection.disconnect ();
176 }
177 
178 void
init()179 RouteUI::init ()
180 {
181 	self_destruct = true;
182 	_playlist_selector = 0;
183 	mute_menu = 0;
184 	solo_menu = 0;
185 	sends_menu = 0;
186 	_record_menu = 0;
187 	_invert_menu = 0;
188 	pre_fader_mute_check = 0;
189 	post_fader_mute_check = 0;
190 	listen_mute_check = 0;
191 	main_mute_check = 0;
192 	solo_safe_check = 0;
193 	solo_isolated_check = 0;
194 	solo_isolated_led = 0;
195 	solo_safe_led = 0;
196 	_solo_release = 0;
197 	_mute_release = 0;
198 	denormal_menu_item = 0;
199 	_step_edit_item = 0;
200 	_rec_safe_item = 0;
201 	_ignore_comment_edit = false;
202 	_i_am_the_modifier = 0;
203 	_n_polarity_invert = 0;
204 
205 	setup_invert_buttons ();
206 
207 	mute_button = manage (new ArdourButton);
208 	mute_button->set_name ("mute button");
209 	UI::instance()->set_tip (mute_button, _("Mute this track"), "");
210 
211 	solo_button = manage (new ArdourButton);
212 	solo_button->set_name ("solo button");
213 	solo_button->set_no_show_all (true);
214 
215 	rec_enable_button = manage (new ArdourButton);
216 	rec_enable_button->set_name ("record enable button");
217 	rec_enable_button->set_icon (ArdourIcon::RecButton);
218 	UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
219 
220 	if (UIConfiguration::instance().get_blink_rec_arm()) {
221 		rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
222 	}
223 
224 	show_sends_button = manage (new ArdourButton);
225 	show_sends_button->set_name ("send alert button");
226 	UI::instance()->set_tip (show_sends_button, _("Show the strips that send to this bus, and control them from the faders"), "");
227 
228 	monitor_input_button = new ArdourButton (ArdourButton::default_elements);
229 	monitor_input_button->set_name ("monitor button");
230 	monitor_input_button->set_text (_("In"));
231 	UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
232 	monitor_input_button->set_no_show_all (true);
233 
234 	monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
235 	monitor_disk_button->set_name ("monitor button");
236 	monitor_disk_button->set_text (_("Disk"));
237 	UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
238 	monitor_disk_button->set_no_show_all (true);
239 
240 	_session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
241 	_session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
242 	_session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
243 	_session->MonitorBusAddedOrRemoved.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_button, this), gui_context());
244 
245 	_session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
246 	Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
247 	UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
248 
249 	rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
250 	rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
251 
252 	show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
253 	show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
254 
255 	solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
256 	solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
257 	mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
258 	mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
259 
260 	monitor_input_button->set_distinct_led_click (false);
261 	monitor_disk_button->set_distinct_led_click (false);
262 
263 	monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
264 	monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
265 
266 	monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
267 	monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
268 
269 	BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
270 }
271 
272 void
reset()273 RouteUI::reset ()
274 {
275 	route_connections.drop_connections ();
276 
277 	delete solo_menu;
278 	solo_menu = 0;
279 
280 	delete mute_menu;
281 	mute_menu = 0;
282 
283 	delete_patch_change_dialog ();
284 	_color_picker.reset ();
285 
286 	denormal_menu_item = 0;
287 }
288 
289 void
self_delete()290 RouteUI::self_delete ()
291 {
292 	delete this;
293 }
294 
295 void
set_session(ARDOUR::Session * s)296 RouteUI::set_session (ARDOUR::Session*s)
297 {
298 	SessionHandlePtr::set_session (s);
299 
300 	if (!s) {
301 		/* This is needed to clean out IDs of sends, when using output selector
302 		 * with MixerStrip::_current_delivery.
303 		 * It's also prudent to hide/destroy input-selectors early, before delayed
304 		 * self_delete() can do that in the ~RouteUI.
305 		 */
306 		for (IOSelectorMap::const_iterator i = input_selectors.begin(); i != input_selectors.end() ; ++i) {
307 			delete i->second;
308 		}
309 		for (IOSelectorMap::const_iterator i = output_selectors.begin(); i != output_selectors.end() ; ++i) {
310 			delete i->second;
311 		}
312 		input_selectors.clear ();
313 		output_selectors.clear ();
314 	}
315 }
316 
317 void
set_route(boost::shared_ptr<Route> rp)318 RouteUI::set_route (boost::shared_ptr<Route> rp)
319 {
320 	reset ();
321 
322 	_route = rp;
323 
324 	if (!_route->presentation_info().color_set()) {
325 		/* deal with older 4.x color, which was stored in the GUI object state */
326 
327 		string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
328 
329 		if (!p.empty()) {
330 
331 			/* old v4.x or earlier session. Use this information */
332 
333 			int red, green, blue;
334 			char colon;
335 
336 			stringstream ss (p);
337 
338 			/* old color format version was:
339 
340 			   16bit value for red:16 bit value for green:16 bit value for blue
341 
342 			   decode to rgb ..
343 			*/
344 
345 			ss >> red;
346 			ss >> colon;
347 			ss >> green;
348 			ss >> colon;
349 			ss >> blue;
350 
351 			red >>= 2;
352 			green >>= 2;
353 			blue >>= 2;
354 
355 			_route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
356 		}
357 	}
358 
359 	if (set_color_from_route()) {
360 		set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
361 	}
362 
363 	if (self_destruct) {
364 		rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
365 	}
366 
367 	mute_button->set_controllable (_route->mute_control());
368 	solo_button->set_controllable (_route->solo_control());
369 
370 	_route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
371 
372 	_route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
373 
374 	_route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
375 	_route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
376 	_route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
377 	_route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
378 	_route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_polarity_display, this), gui_context());
379 
380 	if (is_track()) {
381 		track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
382 		track_mode_changed();
383 	}
384 
385 
386 	_route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
387 	_route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
388 
389 	_route->polarity()->ConfigurationChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context());
390 
391 	if (_session->writable() && is_track()) {
392 		boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
393 
394 		t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
395 		t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
396 
397 		rec_enable_button->show();
398 		rec_enable_button->set_controllable (t->rec_enable_control());
399 
400 		if (is_midi_track()) {
401 			midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
402 					boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
403 		}
404 
405 	}
406 
407 	/* this will work for busses and tracks, and needs to be called to
408 	   set up the name entry/name label display.
409 	*/
410 
411 	if (is_track()) {
412 		boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
413 		t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
414 
415 		update_monitoring_display ();
416 	}
417 
418 	mute_button->unset_flags (Gtk::CAN_FOCUS);
419 	solo_button->unset_flags (Gtk::CAN_FOCUS);
420 
421 	mute_button->show();
422 
423 	if (_route->is_monitor() || _route->is_master()) {
424 		solo_button->hide ();
425 	} else {
426 		solo_button->show();
427 	}
428 
429 	map_frozen ();
430 
431 	setup_invert_buttons ();
432 
433 	boost::shared_ptr<Route> s = _showing_sends_to.lock ();
434 	bus_send_display_changed (s);
435 
436 	update_mute_display ();
437 	update_solo_display ();
438 	update_solo_button ();
439 
440 	if (!UIConfiguration::instance().get_blink_rec_arm()) {
441 		blink_rec_display(true); // set initial rec-en button state
442 	}
443 
444 	check_rec_enable_sensitivity ();
445 	maybe_add_route_print_mgr ();
446 	route_color_changed();
447 	route_gui_changed (PropertyChange (Properties::selected));
448 }
449 
450 bool
mute_press(GdkEventButton * ev)451 RouteUI::mute_press (GdkEventButton* ev)
452 {
453 	if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
454 		return true;
455 	}
456 
457 	//if this is a binding action, let the ArdourButton handle it
458 	if (BindingProxy::is_bind_action(ev) )
459 		return false;
460 
461 	if (Keyboard::is_context_menu_event (ev)) {
462 
463 		if (mute_menu == 0){
464 			build_mute_menu();
465 		}
466 
467 		mute_menu->popup(0,ev->time);
468 
469 		return true;
470 
471 	} else {
472 
473 		if (Keyboard::is_button2_event (ev)) {
474 			// button2-click is "momentary"
475 
476 			_mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
477 		}
478 
479 		if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
480 
481 			if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
482 
483 				/* toggle mute on everything (but
484 				 * exclude the master and monitor)
485 				 *
486 				 * because we are going to erase
487 				 * elements of the list we need to work
488 				 * on a copy.
489 				 */
490 
491 				boost::shared_ptr<RouteList> copy (new RouteList);
492 
493 				*copy = *_session->get_routes ();
494 
495 				for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
496 					if ((*i)->is_master() || (*i)->is_monitor()) {
497 						i = copy->erase (i);
498 					} else {
499 						++i;
500 					}
501 				}
502 
503 				if (_mute_release) {
504 					_mute_release->set (copy);
505 				}
506 
507 				_session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
508 
509 			} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
510 
511 				/* Primary-button1 inverts the implication of
512 				   the group being active. If the group is
513 				   active (for mute), then this modifier means
514 				   "do not apply to mute". If the group is
515 				   inactive (for mute), then this modifier
516 				   means "apply to route". This is all
517 				   accomplished by passing just the actual
518 				   route, along with the InverseGroup group
519 				   control disposition.
520 
521 				   NOTE: Primary-button2 is MIDI learn.
522 				*/
523 
524 				boost::shared_ptr<RouteList> rl;
525 
526 				if (ev->button == 1) {
527 
528 					rl.reset (new RouteList);
529 					rl->push_back (_route);
530 
531 					if (_mute_release) {
532 						_mute_release->set (rl);
533 					}
534 
535 					boost::shared_ptr<MuteControl> mc = _route->mute_control();
536 					mc->start_touch (_session->audible_sample ());
537 					_session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
538 				}
539 
540 			} else {
541 
542 				/* plain click applies change to this route */
543 
544 				boost::shared_ptr<RouteList> rl (new RouteList);
545 				rl->push_back (_route);
546 
547 				if (_mute_release) {
548 					_mute_release->set (rl);
549 				}
550 
551 				boost::shared_ptr<MuteControl> mc = _route->mute_control();
552 				mc->start_touch (_session->audible_sample ());
553 				mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
554 			}
555 		}
556 	}
557 
558 	return false;
559 }
560 
561 bool
mute_release(GdkEventButton *)562 RouteUI::mute_release (GdkEventButton* /*ev*/)
563 {
564 	if (_mute_release) {
565 		_mute_release->release (_session, true);
566 		delete _mute_release;
567 		_mute_release = 0;
568 	}
569 
570 	_route->mute_control()->stop_touch (_session->audible_sample ());
571 
572 	return false;
573 }
574 
575 void
edit_output_configuration()576 RouteUI::edit_output_configuration ()
577 {
578 	boost::shared_ptr<Send> send = boost::dynamic_pointer_cast<Send>(_current_delivery);
579 	if (send && !boost::dynamic_pointer_cast<InternalSend>(send)) {
580 		send.reset ();
581 	}
582 
583 	PBD::ID id = send ? send->id () : _route->id ();
584 
585 	if (output_selectors.find (id) == output_selectors.end ()) {
586 		output_selectors[_route->id ()] =  new IOSelectorWindow (_session, send ? send->output () : _route->output ());
587 	}
588 
589 	IOSelectorWindow* w = output_selectors[id];
590 
591 	if (w->is_visible()) {
592 		w->get_toplevel()->get_window()->raise();
593 	} else {
594 		w->present ();
595 	}
596 
597 	//w->set_keep_above (true);
598 }
599 
600 void
edit_input_configuration()601 RouteUI::edit_input_configuration ()
602 {
603 	if (input_selectors.find (_route->id ()) == input_selectors.end ()) {
604 		input_selectors[_route->id ()] = new IOSelectorWindow (_session, _route->input());
605 	}
606 
607 	IOSelectorWindow* w = input_selectors[_route->id ()];
608 
609 	if (w->is_visible()) {
610 		w->get_toplevel()->get_window()->raise();
611 	} else {
612 		w->present ();
613 	}
614 
615 	//w->set_keep_above (true);
616 }
617 
618 bool
solo_press(GdkEventButton * ev)619 RouteUI::solo_press(GdkEventButton* ev)
620 {
621 	/* ignore double/triple clicks */
622 
623 	if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
624 		return true;
625 	}
626 
627 	//if this is a binding action, let the ArdourButton handle it
628 	if (BindingProxy::is_bind_action(ev) )
629 		return false;
630 
631 	if (Keyboard::is_context_menu_event (ev)) {
632 
633 		if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
634 		    ! (solo_safe_led && solo_safe_led->is_visible())) {
635 
636 			if (solo_menu == 0) {
637 				build_solo_menu ();
638 			}
639 
640 			solo_menu->popup (1, ev->time);
641 		}
642 
643 	} else {
644 
645 		if (Keyboard::is_button2_event (ev)) {
646 
647 			// button2-click is "momentary"
648 			_solo_release = new SoloMuteRelease (_route->self_soloed());
649 		}
650 
651 		if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
652 
653 			if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
654 
655 				/* Primary-Tertiary-click applies change to all routes */
656 
657 				if (_solo_release) {
658 					_solo_release->set (_session->get_routes ());
659 				}
660 
661 				_session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
662 
663 			} else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) || (!_route->self_soloed() && Config->get_exclusive_solo ())) {
664 
665 				/* Primary-Secondary-click: exclusively solo this track */
666 
667 				if (_solo_release) {
668 					_session->prepare_momentary_solo (_solo_release, true, _route);
669 				} else {
670 					/* clear solo state */
671 					_session->prepare_momentary_solo (0, true, _route);
672 				}
673 
674 				DisplaySuspender ds;
675 				_route->solo_control()->set_value (1.0, Controllable::NoGroup);
676 
677 			} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
678 
679 				// shift-click: toggle solo isolated status
680 
681 				_route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
682 				delete _solo_release;
683 				_solo_release = 0;
684 
685 			} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
686 
687 				/* Primary-button1: solo mix group.
688 				   NOTE: Primary-button2 is MIDI learn.
689 				*/
690 
691 				/* Primary-button1 applies change to the mix group even if it is not active
692 				   NOTE: Primary-button2 is MIDI learn.
693 				*/
694 
695 				boost::shared_ptr<RouteList> rl;
696 
697 				if (ev->button == 1) {
698 
699 					/* Primary-button1 inverts the implication of
700 					   the group being active. If the group is
701 					   active (for solo), then this modifier means
702 					   "do not apply to solo". If the group is
703 					   inactive (for mute), then this modifier
704 					   means "apply to route". This is all
705 					   accomplished by passing just the actual
706 					   route, along with the InverseGroup group
707 					   control disposition.
708 
709 					   NOTE: Primary-button2 is MIDI learn.
710 					*/
711 
712 					rl.reset (new RouteList);
713 					rl->push_back (_route);
714 
715 #if 0 // XX why? _solo_release is deleted below
716 					if (_solo_release) {
717 						_solo_release->set (rl);
718 					}
719 #endif
720 
721 					_session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
722 				}
723 
724 				delete _solo_release;
725 				_solo_release = 0;
726 
727 			} else {
728 
729 				/* click: solo this route */
730 
731 				boost::shared_ptr<RouteList> rl (new RouteList);
732 				rl->push_back (route());
733 
734 				if (_solo_release) {
735 					_solo_release->set (rl);
736 				}
737 
738 				_session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
739 			}
740 		}
741 	}
742 
743 	return false;
744 }
745 
746 bool
solo_release(GdkEventButton *)747 RouteUI::solo_release (GdkEventButton* /*ev*/)
748 {
749 	if (_solo_release) {
750 		_solo_release->release (_session, false);
751 		delete _solo_release;
752 		_solo_release = 0;
753 	}
754 
755 	return false;
756 }
757 
758 bool
rec_enable_press(GdkEventButton * ev)759 RouteUI::rec_enable_press(GdkEventButton* ev)
760 {
761 	if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
762 		return true;
763 	}
764 
765 	//if this is a binding action, let the ArdourButton handle it
766 	if (BindingProxy::is_bind_action(ev) )
767 		return false;
768 
769 	if (!ARDOUR_UI_UTILS::engine_is_running ()) {
770 		return false;
771 	}
772 
773 	if (is_midi_track()) {
774 
775 		/* rec-enable button exits from step editing, but not context click */
776 
777 		if (!Keyboard::is_context_menu_event (ev) && midi_track()->step_editing()) {
778 			midi_track()->set_step_editing (false);
779 			return false;
780 		}
781 	}
782 
783 	if (is_track() && rec_enable_button) {
784 
785 		if (Keyboard::is_button2_event (ev)) {
786 
787 			//rec arm does not have a momentary mode
788 			return false;
789 
790 		} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
791 
792 			_session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
793 
794 		} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
795 
796 			/* Primary-button1 applies change to the route group (even if it is not active)
797 			   NOTE: Primary-button2 is MIDI learn.
798 			*/
799 
800 			if (ev->button == 1) {
801 
802 				boost::shared_ptr<RouteList> rl;
803 
804 				rl.reset (new RouteList);
805 				rl->push_back (_route);
806 
807 				_session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
808 			}
809 
810 		} else if (Keyboard::is_context_menu_event (ev)) {
811 
812 			/* do this on release */
813 
814 		} else {
815 
816 			boost::shared_ptr<Track> trk = track();
817 			trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
818 		}
819 	}
820 
821 	return false;
822 }
823 
824 void
update_monitoring_display()825 RouteUI::update_monitoring_display ()
826 {
827 	if (!_route) {
828 		return;
829 	}
830 
831 	boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
832 
833 	if (!t) {
834 		return;
835 	}
836 
837 	MonitorState ms = t->monitoring_state();
838 
839 	if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
840 		monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
841 	} else {
842 		if (ms & MonitoringInput) {
843 			monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
844 		} else {
845 			monitor_input_button->unset_active_state ();
846 		}
847 	}
848 
849 	if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
850 		monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
851 	} else {
852 		if (ms & MonitoringDisk) {
853 			monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
854 		} else {
855 			monitor_disk_button->unset_active_state ();
856 		}
857 	}
858 }
859 
860 bool
monitor_input_press(GdkEventButton *)861 RouteUI::monitor_input_press(GdkEventButton*)
862 {
863 	return false;
864 }
865 
866 bool
monitor_input_release(GdkEventButton * ev)867 RouteUI::monitor_input_release(GdkEventButton* ev)
868 {
869 	return monitor_release (ev, MonitorInput);
870 }
871 
872 bool
monitor_disk_press(GdkEventButton *)873 RouteUI::monitor_disk_press (GdkEventButton*)
874 {
875 	return false;
876 }
877 
878 bool
monitor_disk_release(GdkEventButton * ev)879 RouteUI::monitor_disk_release (GdkEventButton* ev)
880 {
881 	return monitor_release (ev, MonitorDisk);
882 }
883 
884 bool
monitor_release(GdkEventButton * ev,MonitorChoice monitor_choice)885 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
886 {
887 	if (ev->button != 1) {
888 		return false;
889 	}
890 
891 	boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
892 
893 	if (!t) {
894 		return true;
895 	}
896 
897 	MonitorChoice mc;
898 	boost::shared_ptr<RouteList> rl;
899 
900 	if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
901 		mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
902 	} else {
903 		mc = MonitorChoice (t->monitoring_control()->monitoring_choice() | monitor_choice);
904 	}
905 
906 	if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
907 		/* Primary-Tertiary-click applies change to all routes */
908 		rl = _session->get_routes ();
909 		_session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
910 	} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
911 		/* Primary-click overrides group */
912 		rl.reset (new RouteList);
913 		rl->push_back (route());
914 		_session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
915 	} else {
916 		rl.reset (new RouteList);
917 		rl->push_back (route());
918 		_session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
919 	}
920 
921 	return false;
922 }
923 
924 void
build_record_menu()925 RouteUI::build_record_menu ()
926 {
927 	if (!_record_menu) {
928 		_record_menu = new Menu;
929 		_record_menu->set_name ("ArdourContextMenu");
930 		using namespace Menu_Helpers;
931 		MenuList& items = _record_menu->items();
932 
933 		items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
934 		_rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
935 
936 		if (is_midi_track()) {
937 			items.push_back (SeparatorElem());
938 			items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
939 			_step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
940 		}
941 	}
942 
943 	if (_step_edit_item) {
944 		if (track()->rec_enable_control()->get_value()) {
945 			_step_edit_item->set_sensitive (false);
946 		}
947 		_step_edit_item->set_active (midi_track()->step_editing());
948 	}
949 	if (_rec_safe_item) {
950 		_rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
951 		_rec_safe_item->set_active (_route->rec_safe_control()->get_value());
952 	}
953 }
954 
955 void
toggle_step_edit()956 RouteUI::toggle_step_edit ()
957 {
958 	if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
959 		return;
960 	}
961 
962 	midi_track()->set_step_editing (_step_edit_item->get_active());
963 }
964 
965 void
toggle_rec_safe()966 RouteUI::toggle_rec_safe ()
967 {
968 	boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
969 
970 	if (!rs) {
971 		return;
972 	}
973 
974 	/* This check is made inside the control too, but dong it here can't
975 	 * hurt.
976 	 */
977 
978 	if (_route->rec_enable_control()->get_value()) {
979 		return;
980 	}
981 
982 	rs->set_value (_rec_safe_item->get_active (), Controllable::UseGroup);
983 }
984 
985 void
step_edit_changed(bool yn)986 RouteUI::step_edit_changed (bool yn)
987 {
988 	if (yn) {
989 		if (rec_enable_button) {
990 			rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
991 		}
992 
993 		start_step_editing ();
994 
995 		if (_step_edit_item) {
996 			_step_edit_item->set_active (true);
997 		}
998 
999 	} else {
1000 
1001 		if (rec_enable_button) {
1002 			rec_enable_button->unset_active_state ();
1003 		}
1004 
1005 		stop_step_editing ();
1006 
1007 		if (_step_edit_item) {
1008 			_step_edit_item->set_active (false);
1009 		}
1010 	}
1011 }
1012 
1013 bool
rec_enable_release(GdkEventButton * ev)1014 RouteUI::rec_enable_release (GdkEventButton* ev)
1015 {
1016 	if (Keyboard::is_context_menu_event (ev)) {
1017 		build_record_menu ();
1018 		if (_record_menu) {
1019 			_record_menu->popup (1, ev->time);
1020 		}
1021 		return false;
1022 	}
1023 
1024 	return false;
1025 }
1026 
1027 void
build_sends_menu()1028 RouteUI::build_sends_menu ()
1029 {
1030 	using namespace Menu_Helpers;
1031 
1032 	sends_menu = new Menu;
1033 	sends_menu->set_name ("ArdourContextMenu");
1034 	MenuList& items = sends_menu->items();
1035 
1036 	if (!is_foldbackbus ()) {
1037 		items.push_back (
1038 				MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1039 				);
1040 
1041 		items.push_back (
1042 				MenuElem(_("Assign all tracks and busses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1043 				);
1044 
1045 		items.push_back (
1046 				MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1047 				);
1048 
1049 		items.push_back (
1050 				MenuElem(_("Assign all tracks and busses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1051 				);
1052 	}
1053 
1054 	items.push_back (
1055 		MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1056 		);
1057 
1058 	if (!is_foldbackbus ()) {
1059 		items.push_back (
1060 				MenuElem(_("Assign selected tracks and busses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1061 	}
1062 
1063 	items.push_back (
1064 		MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1065 		);
1066 
1067 	if (!is_foldbackbus ()) {
1068 		items.push_back (
1069 				MenuElem(_("Assign selected tracks and busses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1070 				);
1071 	}
1072 
1073 	items.push_back (SeparatorElem());
1074 
1075 	items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1076 	items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1077 	items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1078 
1079 }
1080 
1081 void
create_sends(Placement p,bool include_buses)1082 RouteUI::create_sends (Placement p, bool include_buses)
1083 {
1084 	_session->globally_add_internal_sends (_route, p, include_buses);
1085 }
1086 
1087 void
create_selected_sends(Placement p,bool include_buses)1088 RouteUI::create_selected_sends (Placement p, bool include_buses)
1089 {
1090 	boost::shared_ptr<RouteList> rlist (new RouteList);
1091 	TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1092 
1093 	for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1094 		RouteTimeAxisView* rtv;
1095 		RouteUI* rui;
1096 		if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1097 			if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1098 				if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1099 					rlist->push_back (rui->route());
1100 				}
1101 			}
1102 		}
1103 	}
1104 
1105 	_session->add_internal_sends (_route, p, rlist);
1106 }
1107 
1108 void
set_sends_gain_from_track()1109 RouteUI::set_sends_gain_from_track ()
1110 {
1111 	_session->globally_set_send_gains_from_track (_route);
1112 }
1113 
1114 void
set_sends_gain_to_zero()1115 RouteUI::set_sends_gain_to_zero ()
1116 {
1117 	_session->globally_set_send_gains_to_zero (_route);
1118 }
1119 
1120 void
set_sends_gain_to_unity()1121 RouteUI::set_sends_gain_to_unity ()
1122 {
1123 	_session->globally_set_send_gains_to_unity (_route);
1124 }
1125 
1126 bool
show_sends_press(GdkEventButton * ev)1127 RouteUI::show_sends_press(GdkEventButton* ev)
1128 {
1129 	if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1130 		return true;
1131 	}
1132 
1133 	if (!is_track() && show_sends_button) {
1134 
1135 		if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1136 
1137 			// do nothing on midi sigc::bind event
1138 			return false;
1139 
1140 		} else if (Keyboard::is_context_menu_event (ev)) {
1141 
1142 			if (sends_menu == 0) {
1143 				build_sends_menu ();
1144 			}
1145 
1146 			sends_menu->popup (0, ev->time);
1147 
1148 		} else if (ev->button == 1) {
1149 
1150 			boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1151 
1152 			if (s == _route) {
1153 				set_showing_sends_to (boost::shared_ptr<Route> ());
1154 				Mixer_UI::instance()->show_spill (boost::shared_ptr<ARDOUR::Stripable>());
1155 			} else {
1156 				set_showing_sends_to (_route);
1157 				Mixer_UI::instance()->show_spill (_route);
1158 			}
1159 		}
1160 		return true;
1161 	}
1162 
1163 	return false;
1164 }
1165 
1166 bool
show_sends_release(GdkEventButton *)1167 RouteUI::show_sends_release (GdkEventButton*)
1168 {
1169 	return true;
1170 }
1171 
1172 void
send_blink(bool onoff)1173 RouteUI::send_blink (bool onoff)
1174 {
1175 	if (!show_sends_button) {
1176 		return;
1177 	}
1178 
1179 	if (onoff) {
1180 		show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1181 	} else {
1182 		show_sends_button->unset_active_state ();
1183 	}
1184 }
1185 
1186 Gtkmm2ext::ActiveState
solo_active_state(boost::shared_ptr<Stripable> s)1187 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1188 {
1189 	boost::shared_ptr<SoloControl> sc = s->solo_control();
1190 
1191 	if (!sc) {
1192 		return Gtkmm2ext::Off;
1193 	}
1194 
1195 	if (!sc->can_solo()) {
1196 		return Gtkmm2ext::Off;
1197 	}
1198 
1199 
1200 	if (sc->self_soloed()) {
1201 		return Gtkmm2ext::ExplicitActive;
1202 	} else if (sc->soloed_by_others()) {
1203 		return Gtkmm2ext::ImplicitActive;
1204 	} else {
1205 		return Gtkmm2ext::Off;
1206 	}
1207 }
1208 
1209 Gtkmm2ext::ActiveState
solo_isolate_active_state(boost::shared_ptr<Stripable> s)1210 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1211 {
1212 	boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1213 
1214 	if (!sc) {
1215 		return Gtkmm2ext::Off;
1216 	}
1217 
1218 	if (s->is_master() || s->is_monitor()) {
1219 		return Gtkmm2ext::Off;
1220 	}
1221 
1222 	if (sc->solo_isolated()) {
1223 		return Gtkmm2ext::ExplicitActive;
1224 	} else {
1225 		return Gtkmm2ext::Off;
1226 	}
1227 }
1228 
1229 Gtkmm2ext::ActiveState
solo_safe_active_state(boost::shared_ptr<Stripable> s)1230 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1231 {
1232 	boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1233 
1234 	if (!sc) {
1235 		return Gtkmm2ext::Off;
1236 	}
1237 
1238 	if (s->is_master() || s->is_monitor()) {
1239 		return Gtkmm2ext::Off;
1240 	}
1241 
1242 	if (sc->solo_safe()) {
1243 		return Gtkmm2ext::ExplicitActive;
1244 	} else {
1245 		return Gtkmm2ext::Off;
1246 	}
1247 }
1248 
1249 void
update_solo_display()1250 RouteUI::update_solo_display ()
1251 {
1252 	bool yn = _route->solo_safe_control()->solo_safe ();
1253 
1254 	if (solo_safe_check && solo_safe_check->get_active() != yn) {
1255 		solo_safe_check->set_active (yn);
1256 	}
1257 
1258 	yn = _route->solo_isolate_control()->solo_isolated ();
1259 
1260 	if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1261 		solo_isolated_check->set_active (yn);
1262 	}
1263 
1264 	set_button_names ();
1265 
1266 	if (solo_isolated_led) {
1267 		if (_route->solo_isolate_control()->solo_isolated()) {
1268 			solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1269 		} else {
1270 			solo_isolated_led->unset_active_state ();
1271 		}
1272 	}
1273 
1274 	if (solo_safe_led) {
1275 		if (_route->solo_safe_control()->solo_safe()) {
1276 			solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1277 		} else {
1278 			solo_safe_led->unset_active_state ();
1279 		}
1280 	}
1281 
1282 	solo_button->set_active_state (solo_active_state (_route));
1283 
1284 	/* some changes to solo status can affect mute display, so catch up
1285 	 */
1286 
1287 	update_mute_display ();
1288 }
1289 
1290 void
solo_changed_so_update_mute()1291 RouteUI::solo_changed_so_update_mute ()
1292 {
1293 	update_mute_display ();
1294 }
1295 
1296 ActiveState
mute_active_state(Session *,boost::shared_ptr<Stripable> s)1297 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1298 {
1299 	boost::shared_ptr<MuteControl> mc = s->mute_control();
1300 
1301 	if (s->is_monitor()) {
1302 		return Gtkmm2ext::Off;
1303 	}
1304 
1305 	if (!mc) {
1306 		return Gtkmm2ext::Off;
1307 	}
1308 
1309 	if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1310 
1311 		if (mc->muted_by_self ()) {
1312 			/* full mute */
1313 			return Gtkmm2ext::ExplicitActive;
1314 		} else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1315 			/* this will reflect both solo mutes AND master mutes */
1316 			return Gtkmm2ext::ImplicitActive;
1317 		} else {
1318 			/* no mute at all */
1319 			return Gtkmm2ext::Off;
1320 		}
1321 
1322 	} else {
1323 
1324 		if (mc->muted_by_self()) {
1325 			/* full mute */
1326 			return Gtkmm2ext::ExplicitActive;
1327 		} else if (mc->muted_by_masters ()) {
1328 			/* this shows only master mutes, not mute-by-others-soloing */
1329 			return Gtkmm2ext::ImplicitActive;
1330 		} else {
1331 			/* no mute at all */
1332 			return Gtkmm2ext::Off;
1333 		}
1334 	}
1335 
1336 	return ActiveState(0);
1337 }
1338 
1339 void
update_mute_display()1340 RouteUI::update_mute_display ()
1341 {
1342 	if (!_route) {
1343 		return;
1344 	}
1345 
1346 	mute_button->set_active_state (mute_active_state (_session, _route));
1347 }
1348 
1349 
1350 void
route_rec_enable_changed()1351 RouteUI::route_rec_enable_changed ()
1352 {
1353 	blink_rec_display (true);  //this lets the button change "immediately" rather than wait for the next blink
1354 }
1355 
1356 void
session_rec_enable_changed()1357 RouteUI::session_rec_enable_changed ()
1358 {
1359 	blink_rec_display (true);  //this lets the button change "immediately" rather than wait for the next blink
1360 }
1361 
1362 void
blink_rec_display(bool blinkOn)1363 RouteUI::blink_rec_display (bool blinkOn)
1364 {
1365 	if (!rec_enable_button || !_route) {
1366 		return;
1367 	}
1368 
1369 	if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1370 		return;
1371 	}
1372 
1373 	if (!is_track()) {
1374 		return;
1375 	}
1376 
1377 	if (track()->rec_enable_control()->get_value()) {
1378 		switch (_session->record_status ()) {
1379 			case Session::Recording:
1380 				rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1381 				break;
1382 
1383 			case Session::Disabled:
1384 			case Session::Enabled:
1385 				if (UIConfiguration::instance().get_blink_rec_arm()) {
1386 					rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1387 				} else {
1388 					rec_enable_button->set_active_state ( ImplicitActive );
1389 				}
1390 				break;
1391 		}
1392 
1393 		if (_step_edit_item) {
1394 			_step_edit_item->set_sensitive (false);
1395 		}
1396 
1397 	} else {
1398 		rec_enable_button->unset_active_state ();
1399 
1400 		if (_step_edit_item) {
1401 			_step_edit_item->set_sensitive (true);
1402 		}
1403 	}
1404 
1405 	check_rec_enable_sensitivity ();
1406 }
1407 
1408 void
build_solo_menu(void)1409 RouteUI::build_solo_menu (void)
1410 {
1411 	using namespace Menu_Helpers;
1412 
1413 	solo_menu = new Menu;
1414 	solo_menu->set_name ("ArdourContextMenu");
1415 	MenuList& items = solo_menu->items();
1416 	Gtk::CheckMenuItem* check;
1417 
1418 	check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1419 	check->set_active (_route->solo_isolate_control()->solo_isolated());
1420 	check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1421 	items.push_back (CheckMenuElem(*check));
1422 	solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1423 	check->show_all();
1424 
1425 	check = new Gtk::CheckMenuItem(_("Solo Safe"));
1426 	check->set_active (_route->solo_safe_control()->solo_safe());
1427 	check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1428 	items.push_back (CheckMenuElem(*check));
1429 	solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1430 	check->show_all();
1431 }
1432 
1433 void
build_mute_menu(void)1434 RouteUI::build_mute_menu(void)
1435 {
1436 	using namespace Menu_Helpers;
1437 
1438 	mute_menu = new Menu;
1439 	mute_menu->set_name ("ArdourContextMenu");
1440 
1441 	MenuList& items = mute_menu->items();
1442 
1443 	pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1444 	init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1445 	pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1446 	items.push_back (CheckMenuElem(*pre_fader_mute_check));
1447 	pre_fader_mute_check->show_all();
1448 
1449 	post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1450 	init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1451 	post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1452 	items.push_back (CheckMenuElem(*post_fader_mute_check));
1453 	post_fader_mute_check->show_all();
1454 
1455 	listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1456 	init_mute_menu(MuteMaster::Listen, listen_mute_check);
1457 	listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1458 	items.push_back (CheckMenuElem(*listen_mute_check));
1459 	listen_mute_check->show_all();
1460 
1461 	main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1462 	init_mute_menu(MuteMaster::Main, main_mute_check);
1463 	main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1464 	items.push_back (CheckMenuElem(*main_mute_check));
1465 	main_mute_check->show_all();
1466 
1467 	_route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1468 }
1469 
1470 void
init_mute_menu(MuteMaster::MutePoint mp,Gtk::CheckMenuItem * check)1471 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1472 {
1473 	check->set_active (_route->mute_control()->mute_points() & mp);
1474 }
1475 
1476 void
toggle_mute_menu(MuteMaster::MutePoint mp,Gtk::CheckMenuItem * check)1477 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1478 {
1479 	if (check->get_active()) {
1480 		_route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1481 	} else {
1482 		_route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1483 	}
1484 }
1485 
1486 void
muting_change()1487 RouteUI::muting_change ()
1488 {
1489 	ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1490 
1491 	bool yn;
1492 	MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1493 
1494 	yn = (current & MuteMaster::PreFader);
1495 
1496 	if (pre_fader_mute_check->get_active() != yn) {
1497 		pre_fader_mute_check->set_active (yn);
1498 	}
1499 
1500 	yn = (current & MuteMaster::PostFader);
1501 
1502 	if (post_fader_mute_check->get_active() != yn) {
1503 		post_fader_mute_check->set_active (yn);
1504 	}
1505 
1506 	yn = (current & MuteMaster::Listen);
1507 
1508 	if (listen_mute_check->get_active() != yn) {
1509 		listen_mute_check->set_active (yn);
1510 	}
1511 
1512 	yn = (current & MuteMaster::Main);
1513 
1514 	if (main_mute_check->get_active() != yn) {
1515 		main_mute_check->set_active (yn);
1516 	}
1517 }
1518 
1519 bool
solo_isolate_button_release(GdkEventButton * ev)1520 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1521 {
1522 	if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1523 		return true;
1524 	}
1525 
1526 	bool view = solo_isolated_led->active_state();
1527 	bool model = _route->solo_isolate_control()->solo_isolated();
1528 
1529 	/* called BEFORE the view has changed */
1530 
1531 	if (ev->button == 1) {
1532 		if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1533 
1534 			if (model) {
1535 				/* disable isolate for all routes */
1536 				_session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1537 			} else {
1538 				/* enable isolate for all routes */
1539 				_session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1540 			}
1541 
1542 		} else {
1543 
1544 			if (model == view) {
1545 
1546 				/* flip just this route */
1547 
1548 				boost::shared_ptr<RouteList> rl (new RouteList);
1549 				rl->push_back (_route);
1550 				_session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1551 			}
1552 		}
1553 	}
1554 
1555 	return false;
1556 }
1557 
1558 bool
solo_safe_button_release(GdkEventButton * ev)1559 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1560 {
1561 	if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1562 		return true;
1563 	}
1564 
1565 	bool view = solo_safe_led->active_state();
1566 	bool model = _route->solo_safe_control()->solo_safe();
1567 
1568 	if (ev->button == 1) {
1569 		if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1570 			boost::shared_ptr<RouteList> rl (_session->get_routes());
1571 			if (model) {
1572 				/* disable solo safe for all routes */
1573 				DisplaySuspender ds;
1574 				for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1575 					(*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1576 				}
1577 			} else {
1578 				/* enable solo safe for all routes */
1579 				DisplaySuspender ds;
1580 				for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1581 					(*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1582 				}
1583 			}
1584 		}
1585 		else {
1586 			if (model == view) {
1587 				/* flip just this route */
1588 				_route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1589 			}
1590 		}
1591 	}
1592 
1593 	return false;
1594 }
1595 
1596 void
toggle_solo_isolated(Gtk::CheckMenuItem * check)1597 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1598 {
1599 	bool view = check->get_active();
1600 	bool model = _route->solo_isolate_control()->solo_isolated();
1601 
1602 	/* called AFTER the view has changed */
1603 
1604 	if (model != view) {
1605 		_route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1606 	}
1607 }
1608 
1609 void
toggle_solo_safe(Gtk::CheckMenuItem * check)1610 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1611 {
1612 	_route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1613 }
1614 
1615 void
delete_patch_change_dialog()1616 RouteUI::delete_patch_change_dialog ()
1617 {
1618 	if (!_route) {
1619 		return;
1620 	}
1621 	delete _route->patch_selector_dialog ();
1622 	_route->set_patch_selector_dialog (0);
1623 }
1624 
1625 PatchChangeGridDialog*
patch_change_dialog() const1626 RouteUI::patch_change_dialog () const
1627 {
1628 	return _route->patch_selector_dialog ();
1629 }
1630 
1631 void
select_midi_patch()1632 RouteUI::select_midi_patch ()
1633 {
1634 	if (patch_change_dialog ()) {
1635 		patch_change_dialog()->present ();
1636 		return;
1637 	}
1638 
1639 	/* note: RouteTimeAxisView is resoponsible to updating
1640 	 * the Dialog (PatchChangeGridDialog::refresh())
1641 	 * when the midnam model changes.
1642 	 */
1643 	PatchChangeGridDialog* d = new PatchChangeGridDialog (_route);
1644 	_route->set_patch_selector_dialog (d);
1645 	d->present ();
1646 }
1647 
1648 /** Ask the user to choose a colour, and then apply that color to my route */
1649 void
choose_color()1650 RouteUI::choose_color ()
1651 {
1652 	_color_picker.popup (_route);
1653 }
1654 
1655 /** Set the route's own color.  This may not be used for display if
1656  *  the route is in a group which shares its color with its routes.
1657  */
1658 void
set_color(uint32_t c)1659 RouteUI::set_color (uint32_t c)
1660 {
1661 	_route->presentation_info().set_color (c);
1662 }
1663 
1664 /** @return GUI state ID for things that are common to the route in all its representations */
1665 string
route_state_id() const1666 RouteUI::route_state_id () const
1667 {
1668 	return string_compose (X_("route %1"), _route->id().to_s());
1669 }
1670 
1671 int
set_color_from_route()1672 RouteUI::set_color_from_route ()
1673 {
1674 	if (_route->presentation_info().color_set()) {
1675 		return 0; /* nothing to do */
1676 	}
1677 
1678 	return 1; /* pick a color */
1679 }
1680 
1681 /** @return true if this name should be used for the route, otherwise false */
1682 bool
verify_new_route_name(const std::string & name)1683 RouteUI::verify_new_route_name (const std::string& name)
1684 {
1685 	if (name.find (':') == string::npos) {
1686 		return true;
1687 	}
1688 
1689 	MessageDialog colon_msg (
1690 		_("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1691 		false, MESSAGE_QUESTION, BUTTONS_NONE
1692 		);
1693 
1694 	colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1695 	colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1696 
1697 	return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1698 }
1699 
1700 void
route_rename()1701 RouteUI::route_rename ()
1702 {
1703 	ArdourWidgets::Prompter name_prompter (true);
1704 	string result;
1705 	bool done = false;
1706 
1707 	if (is_track()) {
1708 		name_prompter.set_title (_("Rename Track"));
1709 	} else {
1710 		name_prompter.set_title (_("Rename Bus"));
1711 	}
1712 	name_prompter.set_prompt (_("New name:"));
1713 	name_prompter.set_initial_text (_route->name());
1714 	name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1715 	name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1716 	name_prompter.show_all ();
1717 
1718 	while (!done) {
1719 		switch (name_prompter.run ()) {
1720 		case Gtk::RESPONSE_ACCEPT:
1721 			name_prompter.get_result (result);
1722 			name_prompter.hide ();
1723 			if (result.length()) {
1724 				if (verify_new_route_name (result)) {
1725 					_route->set_name (result);
1726 					done = true;
1727 				} else {
1728 					/* back to name prompter */
1729 				}
1730 
1731 			} else {
1732 				/* nothing entered, just get out of here */
1733 				done = true;
1734 			}
1735 			break;
1736 		default:
1737 			done = true;
1738 			break;
1739 		}
1740 	}
1741 
1742 	return;
1743 
1744 }
1745 
1746 void
toggle_comment_editor()1747 RouteUI::toggle_comment_editor ()
1748 {
1749 	if (_comment_window && _comment_window->is_visible ()) {
1750 		_comment_window->hide ();
1751 	} else {
1752 		open_comment_editor ();
1753 	}
1754 }
1755 
1756 
1757 void
open_comment_editor()1758 RouteUI::open_comment_editor ()
1759 {
1760 	if (_comment_window == 0) {
1761 		setup_comment_editor ();
1762 	}
1763 
1764 	string title;
1765 	title = _route->name();
1766 	title += _(": comment editor");
1767 
1768 	_comment_window->set_title (title);
1769 	_comment_window->present();
1770 }
1771 
1772 void
setup_comment_editor()1773 RouteUI::setup_comment_editor ()
1774 {
1775 	_comment_window = new ArdourWindow (""); // title will be reset to show route
1776 	_comment_window->set_skip_taskbar_hint (true);
1777 	_comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1778 	_comment_window->set_default_size (400, 200);
1779 
1780 	_comment_area = manage (new TextView());
1781 	_comment_area->set_name ("MixerTrackCommentArea");
1782 	_comment_area->set_wrap_mode (WRAP_WORD);
1783 	_comment_area->set_editable (true);
1784 	_comment_area->get_buffer()->set_text (_route->comment());
1785 	_comment_area->show ();
1786 
1787 	_comment_window->add (*_comment_area);
1788 }
1789 
1790 void
comment_changed()1791 RouteUI::comment_changed ()
1792 {
1793 	_ignore_comment_edit = true;
1794 	if (_comment_area) {
1795 		_comment_area->get_buffer()->set_text (_route->comment());
1796 	}
1797 	_ignore_comment_edit = false;
1798 }
1799 
1800 void
comment_editor_done_editing()1801 RouteUI::comment_editor_done_editing ()
1802 {
1803 	ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1804 
1805 	string const str = _comment_area->get_buffer()->get_text();
1806 	if (str == _route->comment ()) {
1807 		return;
1808 	}
1809 
1810 	_route->set_comment (str, this);
1811 }
1812 
1813 void
set_route_active(bool a,bool apply_to_selection)1814 RouteUI::set_route_active (bool a, bool apply_to_selection)
1815 {
1816 	if (apply_to_selection) {
1817 		ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::set_route_active, _1, a, false));
1818 	} else {
1819 		_route->set_active (a, this);
1820 	}
1821 }
1822 
1823 void
duplicate_selected_routes()1824 RouteUI::duplicate_selected_routes ()
1825 {
1826 	ARDOUR_UI::instance()->start_duplicate_routes();
1827 }
1828 
1829 void
toggle_denormal_protection()1830 RouteUI::toggle_denormal_protection ()
1831 {
1832 	if (denormal_menu_item) {
1833 
1834 		bool x;
1835 
1836 		ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1837 
1838 		if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1839 			_route->set_denormal_protection (x);
1840 		}
1841 	}
1842 }
1843 
1844 void
denormal_protection_changed()1845 RouteUI::denormal_protection_changed ()
1846 {
1847 	if (denormal_menu_item) {
1848 		denormal_menu_item->set_active (_route->denormal_protection());
1849 	}
1850 }
1851 
1852 void
disconnect_input()1853 RouteUI::disconnect_input ()
1854 {
1855 	_route->input()->disconnect (this);
1856 }
1857 
1858 void
disconnect_output()1859 RouteUI::disconnect_output ()
1860 {
1861 	_route->output()->disconnect (this);
1862 }
1863 
1864 bool
is_track() const1865 RouteUI::is_track () const
1866 {
1867 	return boost::dynamic_pointer_cast<Track>(_route) != 0;
1868 }
1869 
1870 bool
is_master() const1871 RouteUI::is_master () const
1872 {
1873 	return _route && _route->is_master ();
1874 }
1875 
1876 bool
is_foldbackbus() const1877 RouteUI::is_foldbackbus () const
1878 {
1879 	return _route && _route->is_foldbackbus ();
1880 }
1881 
1882 boost::shared_ptr<Track>
track() const1883 RouteUI::track() const
1884 {
1885 	return boost::dynamic_pointer_cast<Track>(_route);
1886 }
1887 
1888 bool
is_audio_track() const1889 RouteUI::is_audio_track () const
1890 {
1891 	return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1892 }
1893 
1894 boost::shared_ptr<AudioTrack>
audio_track() const1895 RouteUI::audio_track() const
1896 {
1897 	return boost::dynamic_pointer_cast<AudioTrack>(_route);
1898 }
1899 
1900 bool
is_midi_track() const1901 RouteUI::is_midi_track () const
1902 {
1903 	return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1904 }
1905 
1906 boost::shared_ptr<MidiTrack>
midi_track() const1907 RouteUI::midi_track() const
1908 {
1909 	return boost::dynamic_pointer_cast<MidiTrack>(_route);
1910 }
1911 
1912 bool
has_audio_outputs() const1913 RouteUI::has_audio_outputs () const
1914 {
1915 	return (_route->n_outputs().n_audio() > 0);
1916 }
1917 
1918 void
map_frozen()1919 RouteUI::map_frozen ()
1920 {
1921 	ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1922 
1923 	AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1924 
1925 	if (at) {
1926 		check_rec_enable_sensitivity ();
1927 	}
1928 }
1929 
1930 void
save_as_template_dialog_response(int response,SaveTemplateDialog * d)1931 RouteUI::save_as_template_dialog_response (int response, SaveTemplateDialog* d)
1932 {
1933 	if (response == RESPONSE_ACCEPT) {
1934 		const string name = d->get_template_name ();
1935 		const string desc = d->get_description ();
1936 		const string path = Glib::build_filename(ARDOUR::user_route_template_directory (), name + ARDOUR::template_suffix);
1937 
1938 		if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) { /* file already exists. */
1939 			bool overwrite = overwrite_file_dialog (*d,
1940 								_("Confirm Template Overwrite"),
1941 								_("A template already exists with that name. Do you want to overwrite it?"));
1942 
1943 			if (!overwrite) {
1944 				d->show ();
1945 				return;
1946 			}
1947 		}
1948 		_route->save_as_template (path, name, desc);
1949 	}
1950 
1951 	delete d;
1952 }
1953 
1954 void
save_as_template()1955 RouteUI::save_as_template ()
1956 {
1957 	const std::string dir = ARDOUR::user_route_template_directory ();
1958 
1959 	if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1960 		error << string_compose (_("Cannot create template directory %1"), dir) << endmsg;
1961 		return;
1962 	}
1963 
1964 	SaveTemplateDialog* d = new SaveTemplateDialog (_route->name(), _route->comment());
1965 	d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::save_as_template_dialog_response), d));
1966 	d->show ();
1967 }
1968 
1969 void
check_rec_enable_sensitivity()1970 RouteUI::check_rec_enable_sensitivity ()
1971 {
1972 	if (!rec_enable_button) {
1973 		assert (0); // This should not happen
1974 		return;
1975 	}
1976 	if (!_session->writable()) {
1977 		rec_enable_button->set_sensitive (false);
1978 		return;
1979 	}
1980 
1981 	if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1982 		rec_enable_button->set_sensitive (false);
1983 	} else if (is_audio_track ()  && track()->freeze_state() == AudioTrack::Frozen) {
1984 		rec_enable_button->set_sensitive (false);
1985 	} else {
1986 		rec_enable_button->set_sensitive (true);
1987 	}
1988 	if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1989 		rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1990 	} else {
1991 		rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1992 	}
1993 	update_monitoring_display ();
1994 }
1995 
1996 void
update_solo_button()1997 RouteUI::update_solo_button ()
1998 {
1999 	set_button_names ();
2000 
2001 	if (Config->get_solo_control_is_listen_control()) {
2002 		UI::instance()->set_tip (solo_button, _("Listen to this track"), "");
2003 	} else {
2004 		UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
2005 	}
2006 }
2007 
2008 void
parameter_changed(string const & p)2009 RouteUI::parameter_changed (string const & p)
2010 {
2011 	/* this handles RC and per-session parameter changes */
2012 
2013 	if (p == "disable-disarm-during-roll") {
2014 		check_rec_enable_sensitivity ();
2015 	} else if (p == "solo-control-is-listen-control" || p == "listen-position") {
2016 		update_solo_button ();
2017 	} else if (p == "session-monitoring") {
2018 		update_monitoring_display ();
2019 	} else if (p == "auto-input") {
2020 		update_monitoring_display ();
2021 	} else if (p == "layered-record-mode") {
2022 		update_monitoring_display ();
2023 	} else if (p == "auto-input-does-talkback") {
2024 		update_monitoring_display ();
2025 	} else if (p == "blink-rec-arm") {
2026 		if (UIConfiguration::instance().get_blink_rec_arm()) {
2027 			rec_blink_connection.disconnect ();
2028 			rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2029 		} else {
2030 			rec_blink_connection.disconnect ();
2031 			RouteUI::blink_rec_display(false);
2032 		}
2033 	}
2034 }
2035 
2036 void
setup_invert_buttons()2037 RouteUI::setup_invert_buttons ()
2038 {
2039 	uint32_t const N = _route ? _route->phase_control()->size() : 0;
2040 
2041 	if (_n_polarity_invert == N) {
2042 		/* buttons are already setup for this strip, but we should still set the values */
2043 		update_polarity_display ();
2044 		return;
2045 	}
2046 	_n_polarity_invert = N;
2047 
2048 	/* remove old invert buttons */
2049 	for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2050 		invert_button_box.remove (**i);
2051 	}
2052 
2053 	_invert_buttons.clear ();
2054 
2055 	if (N == 0) {
2056 		return;
2057 	}
2058 
2059 	uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2060 
2061 	for (uint32_t i = 0; i < to_add; ++i) {
2062 		ArdourButton* b = manage (new ArdourButton);
2063 		b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2064 		b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2065 
2066 		b->set_name (X_("invert button"));
2067 		if (to_add == 1) {
2068 			if (N > 1) {
2069 				b->set_text (string_compose (X_("Ø (%1)"), N));
2070 			} else {
2071 				b->set_text (X_("Ø"));
2072 			}
2073 		} else {
2074 			b->set_text (string_compose (X_("Ø%1"), i + 1));
2075 		}
2076 
2077 		if (N <= _max_invert_buttons) {
2078 			UI::instance()->set_tip (*b, string_compose (_("Left-click to invert polarity of channel %1 of this track. Right-click to show menu."), i + 1));
2079 		} else {
2080 			UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2081 		}
2082 
2083 		_invert_buttons.push_back (b);
2084 		invert_button_box.pack_start (*b);
2085 	}
2086 
2087 	invert_button_box.set_spacing (1);
2088 	invert_button_box.show_all ();
2089 
2090 	update_polarity_display ();
2091 }
2092 
2093 void
update_polarity_display()2094 RouteUI::update_polarity_display ()
2095 {
2096 	if (!_route) {
2097 		return;
2098 	}
2099 
2100 	uint32_t const N = _route->phase_control()->size();
2101 	if (N > _max_invert_buttons) {
2102 
2103 		/* One button for many channels; explicit active if all channels are inverted,
2104 		   implicit active if some are, off if none are.
2105 		*/
2106 
2107 		ArdourButton* b = _invert_buttons.front ();
2108 
2109 		if (_route->phase_control()->count() == _route->phase_control()->size()) {
2110 			b->set_active_state (Gtkmm2ext::ExplicitActive);
2111 		} else if (_route->phase_control()->any()) {
2112 			b->set_active_state (Gtkmm2ext::ImplicitActive);
2113 		} else {
2114 			b->set_active_state (Gtkmm2ext::Off);
2115 		}
2116 
2117 	} else {
2118 
2119 		/* One button per channel; just set active */
2120 
2121 		int j = 0;
2122 		for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2123 			(*i)->set_active (_route->phase_control()->inverted (j));
2124 		}
2125 
2126 	}
2127 }
2128 
2129 bool
invert_release(GdkEventButton * ev,uint32_t i)2130 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2131 {
2132 	if (ev->button == 1 && i < _invert_buttons.size()) {
2133 		uint32_t const N = _route->phase_control()->size();
2134 		if (N <= _max_invert_buttons) {
2135 			/* left-click inverts phase so long as we have a button per channel */
2136 			_route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2137 			return false;
2138 		}
2139 	}
2140 	return false;
2141 }
2142 
2143 bool
invert_press(GdkEventButton * ev)2144 RouteUI::invert_press (GdkEventButton* ev)
2145 {
2146 	using namespace Menu_Helpers;
2147 
2148 	uint32_t const N = _route->phase_control()->size();
2149 	if (N <= _max_invert_buttons && ev->button != 3) {
2150 		/* If we have an invert button per channel, we only pop
2151 		   up a menu on right-click; left click is handled
2152 		   on release.
2153 		*/
2154 		return false;
2155 	}
2156 
2157 	delete _invert_menu;
2158 	_invert_menu = new Menu;
2159 	_invert_menu->set_name ("ArdourContextMenu");
2160 	MenuList& items = _invert_menu->items ();
2161 
2162 	for (uint32_t i = 0; i < N; ++i) {
2163 		items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2164 		Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2165 		++_i_am_the_modifier;
2166 		e->set_active (_route->phase_control()->inverted (i));
2167 		--_i_am_the_modifier;
2168 	}
2169 
2170 	_invert_menu->popup (0, ev->time);
2171 
2172 	return true;
2173 }
2174 
2175 void
invert_menu_toggled(uint32_t c)2176 RouteUI::invert_menu_toggled (uint32_t c)
2177 {
2178 	if (_i_am_the_modifier) {
2179 		return;
2180 	}
2181 
2182 	_route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2183 }
2184 
2185 void
set_invert_sensitive(bool yn)2186 RouteUI::set_invert_sensitive (bool yn)
2187 {
2188 	for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2189 		(*b)->set_sensitive (yn);
2190 	}
2191 }
2192 
2193 /** The Route's gui_changed signal has been emitted */
2194 void
route_gui_changed(PropertyChange const & what_changed)2195 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2196 {
2197 	if (what_changed.contains (Properties::color)) {
2198 		if (set_color_from_route () == 0) {
2199 			route_color_changed ();
2200 		}
2201 	}
2202 }
2203 
2204 void
track_mode_changed(void)2205 RouteUI::track_mode_changed (void)
2206 {
2207 	assert(is_track());
2208 	rec_enable_button->set_icon (ArdourIcon::RecButton);
2209 	rec_enable_button->queue_draw();
2210 }
2211 
2212 /** @return the color that this route should use; it maybe its own,
2213  *  or it maybe that of its route group.
2214  */
2215 Gdk::Color
route_color() const2216 RouteUI::route_color () const
2217 {
2218 	Gdk::Color c;
2219 	RouteGroup* g = _route->route_group ();
2220 	string p;
2221 
2222 	if (g && g->is_color()) {
2223 		set_color_from_rgba (c, GroupTabs::group_color (g));
2224 	} else {
2225 		set_color_from_rgba (c, _route->presentation_info().color());
2226 	}
2227 
2228 	return c;
2229 }
2230 
2231 void
set_showing_sends_to(boost::shared_ptr<Route> send_to)2232 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2233 {
2234 	_showing_sends_to = send_to;
2235 	BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2236 }
2237 
2238 void
bus_send_display_changed(boost::shared_ptr<Route> send_to)2239 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2240 {
2241 	if (_route == send_to) {
2242 		show_sends_button->set_active (true);
2243 		send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2244 	} else {
2245 		show_sends_button->set_active (false);
2246 		send_blink_connection.disconnect ();
2247 	}
2248 }
2249 
2250 RouteGroup*
route_group() const2251 RouteUI::route_group() const
2252 {
2253 	return _route->route_group();
2254 }
2255 
2256 
RoutePinWindowProxy(std::string const & name,boost::shared_ptr<ARDOUR::Route> route)2257 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2258 	: WM::ProxyBase (name, string())
2259 	, _route (boost::weak_ptr<Route> (route))
2260 {
2261 	route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2262 }
2263 
~RoutePinWindowProxy()2264 RoutePinWindowProxy::~RoutePinWindowProxy()
2265 {
2266 	_window = 0;
2267 }
2268 
2269 ARDOUR::SessionHandlePtr*
session_handle()2270 RoutePinWindowProxy::session_handle ()
2271 {
2272 	ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2273 	if (aw) { return aw; }
2274 	return 0;
2275 }
2276 
2277 Gtk::Window*
get(bool create)2278 RoutePinWindowProxy::get (bool create)
2279 {
2280 	boost::shared_ptr<Route> r = _route.lock ();
2281 	if (!r) {
2282 		return 0;
2283 	}
2284 
2285 	if (!_window) {
2286 		if (!create) {
2287 			return 0;
2288 		}
2289 		_window = new PluginPinDialog (r);
2290 		ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2291 		if (aw) {
2292 			aw->set_session (_session);
2293 		}
2294 		_window->show_all ();
2295 	}
2296 	return _window;
2297 }
2298 
2299 void
route_going_away()2300 RoutePinWindowProxy::route_going_away ()
2301 {
2302 	delete _window;
2303 	_window = 0;
2304 	WM::Manager::instance().remove (this);
2305 	going_away_connection.disconnect();
2306 	delete this;
2307 }
2308 
2309 void
maybe_add_route_print_mgr()2310 RouteUI::maybe_add_route_print_mgr ()
2311 {
2312 	if (_route->pinmgr_proxy ()) {
2313 		return;
2314 	}
2315 	RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2316 			string_compose ("RPM-%1", _route->id()), _route);
2317 	wp->set_session (_session);
2318 
2319 	const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2320 	if (ui_xml) {
2321 		wp->set_state (*ui_xml, 0);
2322 	}
2323 
2324 #if 0
2325 	void* existing_ui = _route->pinmgr_proxy ();
2326 	if (existing_ui) {
2327 		wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2328 	}
2329 #endif
2330 	_route->set_pingmgr_proxy (wp);
2331 
2332 	WM::Manager::instance().register_window (wp);
2333 }
2334 
2335 void
manage_pins()2336 RouteUI::manage_pins ()
2337 {
2338 	RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2339 	if (proxy) {
2340 		proxy->get (true);
2341 		proxy->present();
2342 	}
2343 }
2344 
2345 void
fan_out(bool to_busses,bool group)2346 RouteUI::fan_out (bool to_busses, bool group)
2347 {
2348 	Mixer_UI::instance()->fan_out (_route, to_busses, group);
2349 }
2350 
2351 bool
mark_hidden(bool yn)2352 RouteUI::mark_hidden (bool yn)
2353 {
2354 	if (yn != _route->presentation_info().hidden()) {
2355 		_route->presentation_info().set_hidden (yn);
2356 		return true; // things changed
2357 	}
2358 	return false;
2359 }
2360 
2361 boost::shared_ptr<Stripable>
stripable() const2362 RouteUI::stripable () const
2363 {
2364 	return _route;
2365 }
2366 
2367 void
set_disk_io_point(DiskIOPoint diop)2368 RouteUI::set_disk_io_point (DiskIOPoint diop)
2369 {
2370 	if (_route && is_track()) {
2371 		track()->set_disk_io_point (diop);
2372 	}
2373 }
2374 
2375 
2376 std::string
playlist_tip() const2377 RouteUI::playlist_tip () const
2378 {
2379 	if (!is_track()) {
2380 		return "";
2381 	}
2382 
2383 	RouteGroup* rg = route_group ();
2384 	if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
2385 		string group_string = "." + rg->name() + ".";
2386 
2387 		string take_name = track()->playlist()->name();
2388 		string::size_type idx = take_name.find(group_string);
2389 
2390 		if (idx != string::npos) {
2391 			/* find the bit containing the take number / name */
2392 			take_name = take_name.substr (idx + group_string.length());
2393 
2394 			/* set the playlist button tooltip to the take name */
2395 				return string_compose(_("Take: %1.%2"),
2396 					Gtkmm2ext::markup_escape_text (rg->name()),
2397 					Gtkmm2ext::markup_escape_text (take_name));
2398 		}
2399 	}
2400 
2401 	/* set the playlist button tooltip to the playlist name */
2402 	return  _("Playlist") + std::string(": ") + Gtkmm2ext::markup_escape_text (track()->playlist()->name());
2403 }
2404 
2405 std::string
resolve_new_group_playlist_name(std::string const & basename,vector<boost::shared_ptr<Playlist>> const & playlists)2406 RouteUI::resolve_new_group_playlist_name (std::string const& basename, vector<boost::shared_ptr<Playlist> > const& playlists)
2407 {
2408 	std::string ret (basename);
2409 
2410 	std::string const group_string = "." + route_group()->name() + ".";
2411 
2412 	// iterate through all playlists
2413 	int maxnumber = 0;
2414 	for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
2415 		std::string tmp = (*i)->name();
2416 
2417 		std::string::size_type idx = tmp.find(group_string);
2418 		// find those which belong to this group
2419 		if (idx != string::npos) {
2420 			tmp = tmp.substr(idx + group_string.length());
2421 
2422 			// and find the largest current number
2423 			int x = atoi(tmp);
2424 			if (x > maxnumber) {
2425 				maxnumber = x;
2426 			}
2427 		}
2428 	}
2429 
2430 	maxnumber++;
2431 
2432 	char buf[32];
2433 	snprintf (buf, sizeof(buf), "%d", maxnumber);
2434 
2435 	ret = _route->name() + "." + route_group()->name () + "." + buf;
2436 
2437 	return ret;
2438 }
2439 
2440 void
use_new_playlist(std::string name,std::string gid,vector<boost::shared_ptr<Playlist>> const & playlists_before_op,bool copy)2441 RouteUI::use_new_playlist (std::string name, std::string gid, vector<boost::shared_ptr<Playlist> > const& playlists_before_op, bool copy)
2442 {
2443 	boost::shared_ptr<Track> tr = track ();
2444 	if (!tr) {
2445 		return;
2446 	}
2447 
2448 	boost::shared_ptr<const Playlist> pl = tr->playlist();
2449 	if (!pl) {
2450 		return;
2451 	}
2452 
2453 	if (copy) {
2454 		tr->use_copy_playlist ();
2455 	} else {
2456 		tr->use_default_new_playlist ();
2457 	}
2458 	tr->playlist()->set_name (name);
2459 	tr->playlist()->set_pgroup_id (gid);
2460 }
2461 
2462 void
clear_playlist()2463 RouteUI::clear_playlist ()
2464 {
2465 	boost::shared_ptr<Track> tr = track ();
2466 	if (!tr) {
2467 		return;
2468 	}
2469 
2470 	boost::shared_ptr<Playlist> pl = tr->playlist();
2471 	if (!pl) {
2472 		return;
2473 	}
2474 
2475 	ARDOUR_UI::instance()->the_editor().clear_playlist (pl);
2476 }
2477 
2478 void
build_playlist_menu()2479 RouteUI::build_playlist_menu ()
2480 {
2481 	using namespace Menu_Helpers;
2482 
2483 	if (!is_track()) {
2484 		return;
2485 	}
2486 
2487 	PublicEditor* editor = &ARDOUR_UI::instance()->the_editor();
2488 
2489 	delete playlist_action_menu;
2490 	playlist_action_menu = new Menu;
2491 	playlist_action_menu->set_name ("ArdourContextMenu");
2492 
2493 	MenuList& playlist_items = playlist_action_menu->items();
2494 	playlist_action_menu->set_name ("ArdourContextMenu");
2495 	playlist_items.clear();
2496 
2497 	RadioMenuItem::Group playlist_group;
2498 	boost::shared_ptr<Track> tr = track ();
2499 
2500 	vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists()->playlists_for_track (tr);
2501 
2502 	/* sort the playlists */
2503 	PlaylistSorterByID cmp;
2504 	sort (playlists_tr.begin(), playlists_tr.end(), cmp);
2505 
2506 	/* add the playlists to the menu */
2507 	for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
2508 		string text = (*i)->name();
2509 		playlist_items.push_back (RadioMenuElem (playlist_group, text));
2510 		RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
2511 		item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
2512 
2513 		if (tr->playlist()->id() == (*i)->id()) {
2514 			item->set_active();
2515 		}
2516 	}
2517 
2518 	playlist_items.push_back (SeparatorElem());
2519 	playlist_items.push_back (MenuElem(_("Select ..."), sigc::mem_fun(*this, &RouteUI::show_playlist_selector)));
2520 
2521 	playlist_items.push_back (SeparatorElem());
2522 	playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::rename_current_playlist)));
2523 	playlist_items.push_back (SeparatorElem());
2524 
2525 	if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
2526 		playlist_items.push_back (MenuElem (_("New Playlist..."), sigc::bind(sigc::mem_fun(editor, &PublicEditor::new_playlists_for_grouped_tracks), this, false)));
2527 		playlist_items.push_back (MenuElem (_("Copy Playlist..."), sigc::bind(sigc::mem_fun(editor, &PublicEditor::new_playlists_for_grouped_tracks), this, true)));
2528 	} else {
2529 		playlist_items.push_back (MenuElem (_("New Playlist (for group)"), sigc::bind(sigc::mem_fun(editor, &PublicEditor::new_playlists_for_grouped_tracks), this, false)));
2530 		playlist_items.push_back (MenuElem (_("Copy Playlist (for group)"), sigc::bind(sigc::mem_fun(editor, &PublicEditor::new_playlists_for_grouped_tracks), this, true)));
2531 	}
2532 
2533 	playlist_items.push_back (SeparatorElem());
2534 	if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
2535 		playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(editor, &PublicEditor::clear_grouped_playlists), this)));
2536 	} else {
2537 		playlist_items.push_back (MenuElem (_("Clear Current (for group)"), sigc::bind(sigc::mem_fun(editor, &PublicEditor::clear_grouped_playlists), this)));
2538 	}
2539 	playlist_items.push_back (SeparatorElem());
2540 
2541 	Menu* advanced_menu = manage (new Menu);
2542 	MenuList& advanced_items = advanced_menu->items();
2543 	advanced_items.push_back (MenuElem(_("Copy from ..."), sigc::mem_fun(*this, &RouteUI::show_playlist_copy_selector)));
2544 	advanced_items.push_back (MenuElem(_("Share with ..."), sigc::mem_fun(*this, &RouteUI::show_playlist_share_selector)));
2545 	advanced_items.push_back (MenuElem(_("Steal from ..."), sigc::mem_fun(*this, &RouteUI::show_playlist_steal_selector)));
2546 	playlist_items.push_back (MenuElem (_("Advanced"), *advanced_menu));
2547 }
2548 
2549 void
use_playlist(RadioMenuItem * item,boost::weak_ptr<Playlist> wpl)2550 RouteUI::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
2551 {
2552 	assert (is_track());
2553 
2554 	// exit if we were triggered by deactivating the old playlist
2555 	if (item && !item->get_active()) {
2556 		return;
2557 	}
2558 
2559 	boost::shared_ptr<Playlist> pl (wpl.lock());
2560 
2561 	if (!pl) {
2562 		return;
2563 	}
2564 
2565 	if (track()->playlist() == pl) {
2566 		// exit when use_playlist is called by the creation of the playlist menu
2567 		// or the playlist choice is unchanged
2568 		return;
2569 	}
2570 
2571 	track()->use_playlist (track()->data_type(), pl);
2572 
2573 	RouteGroup* rg = route_group();
2574 
2575 	if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
2576 
2577 		std::string pgrp_id = pl->pgroup_id();
2578 		if (pgrp_id.length()>0) {  //easy: find other pl's with the same group id
2579 			boost::shared_ptr<RouteList> rl (rg->route_list());
2580 			for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
2581 				if ((*i) == this->route()) {
2582 					continue;
2583 				}
2584 				if ((*i)->route_group() != rg) {
2585 					continue;
2586 				}
2587 				boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
2588 				if (!track) {
2589 					continue;
2590 				}
2591 				boost::shared_ptr<Playlist> ipl = session()->playlists()->for_pgroup(pgrp_id, track->id());
2592 				if (ipl) {
2593 					track->use_playlist(track->data_type(), ipl);
2594 				}
2595 			}
2596 		} else {  //fallback to prior behavior ... try to find matching names /*DEPRECATED*/
2597 			std::string take_name = pl->name();
2598 			std::string group_string = "." + rg->name() + ".";
2599 
2600 			std::string::size_type idx = take_name.find(group_string);
2601 
2602 			if (idx == std::string::npos)
2603 				return;
2604 
2605 			take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
2606 
2607 			boost::shared_ptr<RouteList> rl (rg->route_list());
2608 			for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
2609 				if ((*i) == this->route()) {
2610 					continue;
2611 				}
2612 
2613 				std::string playlist_name = (*i)->name()+group_string+take_name;
2614 
2615 				boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
2616 				if (!track) {
2617 					continue;
2618 				}
2619 
2620 				if (track->freeze_state() == Track::Frozen) {
2621 					/* Don't change playlists of frozen tracks */
2622 					continue;
2623 				}
2624 
2625 				boost::shared_ptr<Playlist> ipl = session()->playlists()->by_name(playlist_name);
2626 				if (!ipl) {
2627 					// No playlist for this track for this take yet, make it
2628 					track->use_default_new_playlist();
2629 					track->playlist()->set_name(playlist_name);
2630 				} else {
2631 					track->use_playlist(track->data_type(), ipl);
2632 				}
2633 			}
2634 		} //fallback
2635 	}
2636 }
2637 
2638 void
show_playlist_selector()2639 RouteUI::show_playlist_selector ()
2640 {
2641 	if (!_playlist_selector) {
2642 		_playlist_selector = new PlaylistSelector();
2643 		_playlist_selector->set_session(_session);
2644 	}
2645 
2646 	_playlist_selector->prepare(this, PlaylistSelector::plSelect);
2647 	_playlist_selector->show_all ();
2648 }
2649 
2650 void
show_playlist_copy_selector()2651 RouteUI::show_playlist_copy_selector ()
2652 {
2653 	if (!_playlist_selector) {
2654 		_playlist_selector = new PlaylistSelector();
2655 		_playlist_selector->set_session(_session);
2656 	}
2657 
2658 	_playlist_selector->prepare(this, PlaylistSelector::plCopy);
2659 	_playlist_selector->show_all ();
2660 }
2661 
2662 void
show_playlist_share_selector()2663 RouteUI::show_playlist_share_selector ()
2664 {
2665 	if (!_playlist_selector) {
2666 		_playlist_selector = new PlaylistSelector();
2667 		_playlist_selector->set_session(_session);
2668 	}
2669 
2670 	_playlist_selector->prepare(this, PlaylistSelector::plShare);
2671 	_playlist_selector->show_all ();
2672 }
2673 
2674 void
show_playlist_steal_selector()2675 RouteUI::show_playlist_steal_selector ()
2676 {
2677 	if (!_playlist_selector) {
2678 		_playlist_selector = new PlaylistSelector();
2679 		_playlist_selector->set_session(_session);
2680 	}
2681 
2682 	_playlist_selector->prepare(this, PlaylistSelector::plSteal);
2683 	_playlist_selector->show_all ();
2684 }
2685 
2686 void
rename_current_playlist()2687 RouteUI::rename_current_playlist ()
2688 {
2689 	Prompter prompter (true);
2690 	string name;
2691 
2692 	boost::shared_ptr<Track> tr = track();
2693 	if (!tr) {
2694 		return;
2695 	}
2696 
2697 	boost::shared_ptr<Playlist> pl = tr->playlist();
2698 	if (!pl) {
2699 		return;
2700 	}
2701 
2702 	prompter.set_title (_("Rename Playlist"));
2703 	prompter.set_prompt (_("New name for playlist:"));
2704 	prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
2705 	prompter.set_initial_text (pl->name());
2706 	prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
2707 
2708 	while (true) {
2709 		if (prompter.run () != Gtk::RESPONSE_ACCEPT) {
2710 			break;
2711 		}
2712 		prompter.get_result (name);
2713 		if (name.length()) {
2714 			if (_session->playlists()->by_name (name)) {
2715 				prompter.set_prompt (_("That name is already in use.  Use this instead?"));
2716 				prompter.set_initial_text (Playlist::bump_name (name, *_session));
2717 			} else {
2718 				break;
2719 			}
2720 		}
2721 	}
2722 
2723 	if (name.length()) {
2724 		vector<boost::shared_ptr<Playlist> > playlists_gr = _session->playlists()->playlists_for_pgroup (pl->pgroup_id());
2725 		for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_gr.begin(); i != playlists_gr.end(); ++i) {
2726 			(*i)->set_name (name);
2727 		}
2728 	}
2729 }
2730