Monitor new signal to rebuild sendlist
[ardour.git] / gtk2_ardour / foldback_strip.cc
1 /*
2     Copyright (C) 2018-2019 Len Ovens
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <cmath>
20 #include <list>
21 #include <algorithm>
22
23 #include <sigc++/bind.h>
24
25 #include <gtkmm/messagedialog.h>
26
27 #include "pbd/convert.h"
28 #include "pbd/enumwriter.h"
29 #include "pbd/replace_all.h"
30 #include "pbd/stacktrace.h"
31
32 #include "ardour/amp.h"
33 #include "ardour/audioengine.h"
34 #include "ardour/internal_send.h"
35 #include "ardour/internal_return.h"
36 #include "ardour/io.h"
37 #include "ardour/io_processor.h"
38 #include "ardour/pannable.h"
39 #include "ardour/panner.h"
40 #include "ardour/panner_shell.h"
41 #include "ardour/panner_manager.h"
42 #include "ardour/port.h"
43 #include "ardour/profile.h"
44 #include "ardour/route.h"
45 #include "ardour/send.h"
46 #include "ardour/session.h"
47 #include "ardour/types.h"
48 #include "ardour/user_bundle.h"
49 #include "ardour/value_as_string.h"
50
51 #include "gtkmm2ext/gtk_ui.h"
52 #include "gtkmm2ext/menu_elems.h"
53 #include "gtkmm2ext/utils.h"
54 #include "gtkmm2ext/doi.h"
55
56 #include "widgets/tooltips.h"
57
58 #include "ardour_window.h"
59 #include "enums_convert.h"
60 #include "foldback_strip.h"
61 #include "mixer_ui.h"
62 #include "keyboard.h"
63 #include "public_editor.h"
64 #include "send_ui.h"
65 #include "io_selector.h"
66 #include "utils.h"
67 #include "gui_thread.h"
68 #include "ui_config.h"
69
70 #include "pbd/i18n.h"
71
72 using namespace ARDOUR;
73 using namespace ArdourWidgets;
74 using namespace PBD;
75 using namespace Gtk;
76 using namespace Gtkmm2ext;
77 using namespace std;
78
79 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
80
81 FoldbackSend::FoldbackSend (boost::shared_ptr<Send> snd, \
82         boost::shared_ptr<ARDOUR::Route> sr,  boost::shared_ptr<ARDOUR::Route> fr)
83         : _button (ArdourButton::led_default_elements)
84         , _send (snd)
85         , _send_route (sr)
86         , _foldback_route (fr)
87         , _send_proc (snd)
88         , _send_del (snd)
89         , pan_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
90         , _adjustment (gain_to_slider_position_with_max (1.0, Config->get_max_gain()), 0, 1, 0.01, 0.1)
91         , _slider (&_adjustment, boost::shared_ptr<PBD::Controllable>(), 0, max(13.f, rintf(13.f * UIConfiguration::instance().get_ui_scale())))
92         , _ignore_ui_adjustment (true)
93         , _slider_persistant_tooltip (&_slider)
94
95 {
96
97         HBox * snd_but_pan = new HBox ();
98
99         _button.set_distinct_led_click (true);
100         _button.set_fallthrough_to_parent(true);
101         _button.set_led_left (true);
102         _button.signal_led_clicked.connect (sigc::mem_fun (*this, &FoldbackSend::led_clicked));
103         _button.set_name ("processor prefader");
104         _button.set_text (_send_route->name());
105         snd_but_pan->pack_start (_button, true, true);
106         _button.set_active (_send_proc->enabled ());
107         _button.show ();
108
109         if (_foldback_route->input()->n_ports().n_audio() == 2) {
110                 boost::shared_ptr<Pannable> pannable = _send_del->panner()->pannable();
111                 boost::shared_ptr<AutomationControl> ac;
112                 ac = pannable->pan_azimuth_control;
113                 pan_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
114                 pan_control.set_tooltip_prefix (_("Pan: "));
115                 pan_control.set_name ("trim knob");
116                 pan_control.set_no_show_all (true);
117                 snd_but_pan->pack_start (pan_control, false, false);
118                 pan_control.show ();
119                 pan_control.set_controllable (ac);
120         }
121         boost::shared_ptr<AutomationControl> lc;
122         lc = _send->gain_control();
123         _slider.set_controllable (lc);
124         _slider.set_name ("ProcessorControlSlider");
125         _slider.set_text (_("Level"));
126
127
128
129         pack_start (*snd_but_pan, Gtk::PACK_SHRINK);
130         snd_but_pan->show();
131         pack_start (_slider, true, true);
132         _slider.show ();
133         level_changed ();
134         _adjustment.signal_value_changed().connect (sigc::mem_fun (*this,  &FoldbackSend::level_adjusted));
135         lc->Changed.connect (_connections, invalidator (*this), boost::bind (&FoldbackSend::level_changed, this), gui_context ());
136         _send_proc->ActiveChanged.connect (_connections, invalidator (*this), boost::bind (&FoldbackSend::send_state_changed, this), gui_context ());
137
138         show ();
139
140
141 }
142
143 FoldbackSend::~FoldbackSend ()
144 {
145         _send = boost::shared_ptr<Send> ();
146         _send_route = boost::shared_ptr<Route> ();
147         _foldback_route = boost::shared_ptr<Route> ();
148         _send_proc = boost::shared_ptr<Processor> ();
149         _send_del = boost::shared_ptr<Delivery> ();
150         _connections.drop_connections();
151         pan_control.set_controllable (boost::shared_ptr<AutomationControl> ());
152         _slider.set_controllable (boost::shared_ptr<AutomationControl> ());
153
154 }
155
156 void
157 FoldbackSend::led_clicked(GdkEventButton *ev)
158 {
159         if (_send_proc) {
160                 if (_button.get_active ()) {
161                         _send_proc->enable (false);
162
163                 } else {
164                         _send_proc->enable (true);
165                 }
166         }
167 }
168
169 void
170 FoldbackSend::send_state_changed ()
171 {
172         _button.set_active (_send_proc->enabled ());
173
174 }
175
176 void
177 FoldbackSend::level_adjusted ()
178 {
179         if (_ignore_ui_adjustment) {
180                 return;
181         }
182         boost::shared_ptr<AutomationControl> lc = _send->gain_control();
183
184         if (!lc) {
185                 return;
186         }
187
188         lc->set_value ( lc->interface_to_internal(_adjustment.get_value ()) , Controllable::NoGroup);
189         set_tooltip ();
190 }
191
192 void
193 FoldbackSend::level_changed ()
194 {
195         boost::shared_ptr<AutomationControl> lc = _send->gain_control();
196         if (!lc) {
197                 return;
198         }
199
200         _ignore_ui_adjustment = true;
201
202         const double nval = lc->internal_to_interface (lc->get_value ());
203         if (_adjustment.get_value() != nval) {
204                 _adjustment.set_value (nval);
205                 set_tooltip ();
206         }
207
208         _ignore_ui_adjustment = false;
209 }
210
211 void
212 FoldbackSend::set_tooltip ()
213 {
214         boost::shared_ptr<AutomationControl> lc = _send->gain_control();
215
216         if (!lc) {
217                 return;
218         }
219         std::string tt = ARDOUR::value_as_string (lc->desc(), lc->get_value ());
220         string sm = Gtkmm2ext::markup_escape_text (tt);
221         _slider_persistant_tooltip.set_tip (sm);
222         ArdourWidgets::set_tooltip (_button, Gtkmm2ext::markup_escape_text (sm));
223 }
224
225
226 FoldbackStrip* FoldbackStrip::_entered_foldback_strip;
227 PBD::Signal1<void,FoldbackStrip*> FoldbackStrip::CatchDeletion;
228
229 FoldbackStrip::FoldbackStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt)
230         : SessionHandlePtr (sess)
231         , RouteUI (sess)
232         , _mixer(mx)
233         , _mixer_owned (true)
234         , _pr_selection ()
235         , panners (sess)
236         , mute_solo_table (1, 2)
237         , bottom_button_table (1, 1)
238         , _plugin_insert_cnt (0)
239         , _comment_button (_("Comments"))
240         , fb_level_control (0)
241 {
242         _session = sess;
243         init ();
244         set_route (rt);
245 }
246
247 void
248 FoldbackStrip::init ()
249 {
250         _entered_foldback_strip= 0;
251         route_ops_menu = 0;
252         route_select_menu = 0;
253         ignore_comment_edit = false;
254         ignore_toggle = false;
255         comment_area = 0;
256         _width_owner = 0;
257
258         /* the length of this string determines the width of the mixer strip when it is set to `wide' */
259         longest_label = "longest label";
260
261         output_button.set_text (_("Output"));
262         output_button.set_name ("mixer strip button");
263
264         send_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
265         send_scroller.add (send_display);
266
267         send_display.set_flags (CAN_FOCUS);
268         //send_display.set_name ("ProcessorList");
269         send_display.set_name ("AudioBusStripBase");
270         send_display.set_spacing (4);
271
272         insert_box = new ProcessorBox (0, boost::bind (&FoldbackStrip::plugin_selector, this), _pr_selection, 0);
273         insert_box->set_no_show_all ();
274         insert_box->show ();
275         insert_box->set_session (_session);
276
277         send_scroller.show ();
278         send_display.show ();
279
280         fb_level_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
281         fb_level_control->set_size_request (PX_SCALE(65), PX_SCALE(65));
282         fb_level_control->set_tooltip_prefix (_("Level: "));
283         fb_level_control->set_name ("monitor section knob");
284         fb_level_control->set_no_show_all (true);
285
286         bottom_button_table.attach (*fb_level_control, 0, 1, 0, 1,FILL,FILL,20,20); //EXPAND
287         bottom_button_table.set_spacings (20);
288         bottom_button_table.set_row_spacings (20);
289         bottom_button_table.set_homogeneous (true);
290
291         mute_solo_table.set_homogeneous (true);
292         mute_solo_table.set_spacings (2);
293
294         show_sends_button->set_text (_("Show Sends"));
295
296         show_sends_box.pack_start (*show_sends_button, true, true);
297         show_sends_button->show();
298
299
300         name_button.set_name ("mixer strip button");
301         name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
302
303         _select_button.set_name ("mixer strip button");
304         _select_button.set_text (_("Select Foldback Bus"));
305
306         _comment_button.set_name (X_("mixer strip button"));
307         _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
308         _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
309
310         global_vpacker.set_border_width (1);
311         global_vpacker.set_spacing (4);
312
313         global_vpacker.pack_start (_select_button, Gtk::PACK_SHRINK);
314         global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
315         global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
316         global_vpacker.pack_start (show_sends_box, Gtk::PACK_SHRINK);
317         global_vpacker.pack_start (send_scroller, true, true);
318 #ifndef MIXBUS
319         //add a spacer underneath the foldback bus;
320         //this fills the area that is taken up by the scrollbar on the tracks;
321         //and therefore keeps the strip boxes "even" across the bottom
322         int scrollbar_height = 0;
323         {
324                 Gtk::Window window (WINDOW_TOPLEVEL);
325                 HScrollbar scrollbar;
326                 window.add (scrollbar);
327                 scrollbar.set_name ("MixerWindow");
328                 scrollbar.ensure_style();
329                 Gtk::Requisition requisition(scrollbar.size_request ());
330                 scrollbar_height = requisition.height;
331         }
332         spacer.set_size_request (-1, scrollbar_height);
333         global_vpacker.pack_end (spacer, false, false);
334 #endif
335         global_vpacker.pack_end (_comment_button, Gtk::PACK_SHRINK);
336         global_vpacker.pack_end (output_button, Gtk::PACK_SHRINK);
337         global_vpacker.pack_end (*insert_box, Gtk::PACK_SHRINK);
338         global_vpacker.pack_end (bottom_button_table, Gtk::PACK_SHRINK);
339         global_vpacker.pack_end (mute_solo_table, Gtk::PACK_SHRINK);
340         global_vpacker.pack_end (panners, Gtk::PACK_SHRINK);
341
342         global_frame.add (global_vpacker);
343         global_frame.set_shadow_type (Gtk::SHADOW_IN);
344         global_frame.set_name ("BaseFrame");
345
346         add (global_frame);
347
348         /* force setting of visible selected status */
349
350         _selected = true;
351         set_selected (false);
352         _packed = false;
353         _embedded = false;
354
355         _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&FoldbackStrip::engine_stopped, this), gui_context());
356         _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&FoldbackStrip::engine_running, this), gui_context());
357
358         output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
359         output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &FoldbackStrip::output_press), false);
360         output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &FoldbackStrip::output_release), false);
361
362         name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &FoldbackStrip::name_button_button_press), false);
363         _select_button.signal_button_press_event().connect (sigc::mem_fun (*this, &FoldbackStrip::select_button_button_press), false);
364
365         _width = Wide;
366
367         add_events (Gdk::BUTTON_RELEASE_MASK|
368                     Gdk::ENTER_NOTIFY_MASK|
369                     Gdk::LEAVE_NOTIFY_MASK|
370                     Gdk::KEY_PRESS_MASK|
371                     Gdk::KEY_RELEASE_MASK);
372
373         set_flags (get_flags() | Gtk::CAN_FOCUS);
374
375         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
376                 *this, invalidator (*this), boost::bind (&FoldbackStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
377                 );
378
379         //watch for mouse enter/exit so we can do some stuff
380         signal_enter_notify_event().connect (sigc::mem_fun(*this, &FoldbackStrip::mixer_strip_enter_event ));
381         signal_leave_notify_event().connect (sigc::mem_fun(*this, &FoldbackStrip::mixer_strip_leave_event ));
382
383 }
384
385 FoldbackStrip::~FoldbackStrip ()
386 {
387         CatchDeletion (this);
388         delete fb_level_control;
389         fb_level_control = 0;
390         _connections.drop_connections();
391         clear_send_box ();
392
393         if (this ==_entered_foldback_strip)
394                 _entered_foldback_strip = NULL;
395 }
396
397 bool
398 FoldbackStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
399 {
400         _entered_foldback_strip = this;
401
402         //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
403         //because the FoldbackStrip control is a parent that encompasses the strip
404         deselect_all_processors();
405
406         return false;
407 }
408
409 bool
410 FoldbackStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
411 {
412         //if we have moved outside our strip, but not into a child view, then deselect ourselves
413         if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
414                 _entered_foldback_strip= 0;
415
416         }
417
418         return false;
419 }
420
421 string
422 FoldbackStrip::name() const
423 {
424         if (_route) {
425                 return _route->name();
426         }
427         return string();
428 }
429
430 void
431 FoldbackStrip::update_fb_level_control ()
432 {
433         fb_level_control->show ();
434         fb_level_control->set_controllable (_route->gain_control());
435 }
436
437 void
438 FoldbackStrip::set_route (boost::shared_ptr<Route> rt)
439 {
440         /// FIX NO route
441         if (!rt) {
442                 clear_send_box ();
443                 RouteUI::self_delete ();
444
445                 return;
446         }
447
448         RouteUI::set_route (rt);
449
450         insert_box->set_route (_route);
451         revert_to_default_display ();
452         if (solo_button->get_parent()) {
453                 mute_solo_table.remove (*solo_button);
454         }
455
456         if (mute_button->get_parent()) {
457                 mute_solo_table.remove (*mute_button);
458         }
459
460         mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
461         mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
462         mute_button->show ();
463         solo_button->show ();
464         show_sends_box.show ();
465         spacer.show();
466         update_fb_level_control();
467
468         BusSendDisplayChanged (boost::shared_ptr<Route> ());
469         show_sends_button->show();
470
471         delete route_ops_menu;
472         route_ops_menu = 0;
473         delete route_select_menu;
474         route_select_menu = 0;
475
476         _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&FoldbackStrip::update_output_display, this), gui_context());
477         _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&FoldbackStrip::io_changed_proxy, this), gui_context ());
478
479         if (_route->panner_shell()) {
480                 update_panner_choices();
481                 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&FoldbackStrip::connect_to_pan, this), gui_context());
482         }
483
484         _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&FoldbackStrip::setup_comment_button, this), gui_context());
485
486         set_stuff_from_route ();
487
488         /* now force an update of all the various elements */
489
490         update_mute_display ();
491         update_solo_display ();
492         name_changed ();
493         comment_changed ();
494         connect_to_pan ();
495         panners.setup_pan ();
496         panners.show_all ();
497         update_output_display ();
498
499         add_events (Gdk::BUTTON_RELEASE_MASK);
500
501         insert_box->show ();
502         update_send_box ();
503         _session->FBSendsChanged.connect (route_connections, invalidator (*this), boost::bind (&FoldbackStrip::update_send_box, this), gui_context());
504
505         global_frame.show();
506         global_vpacker.show();
507         mute_solo_table.show();
508         bottom_button_table.show();
509         show_sends_box.show_all();
510         //send_scroller.show ();
511         send_display.show ();
512         output_button.show();
513         name_button.show();
514         _select_button.show();
515         _comment_button.show();
516
517         map_frozen();
518
519         show ();
520 }
521
522 void
523 FoldbackStrip::update_send_box ()
524 {
525         clear_send_box ();
526         if (!_route) {
527                 return;
528         }
529         Route::FedBy fed_by = _route->fed_by();
530         for (Route::FedBy::iterator i = fed_by.begin(); i != fed_by.end(); ++i) {
531                 if (i->sends_only) {
532                         boost::shared_ptr<Route> s_rt (i->r.lock());
533                         boost::shared_ptr<Send> snd = s_rt->internal_send_for (_route);
534                         if (snd) {
535                                 FoldbackSend * fb_s = new FoldbackSend (snd, s_rt, _route);
536                                 send_display.pack_start (*fb_s, Gtk::PACK_SHRINK);
537                                 fb_s->show ();
538                                 s_rt->processors_changed.connect (_connections, invalidator (*this), boost::bind (&FoldbackStrip::processors_changed, this, _1), gui_context ());
539                         }
540                 }
541         }
542 }
543
544 void
545 FoldbackStrip::clear_send_box ()
546 {
547         std::vector< Widget* > snd_list = send_display.get_children ();
548         _connections.drop_connections ();
549         for (uint32_t i = 0; i < snd_list.size(); i++) {
550                 send_display.remove (*(snd_list[i]));
551                 delete snd_list[i];
552         }
553         snd_list.clear();
554 }
555
556 void
557 FoldbackStrip::processors_changed (RouteProcessorChange)
558 {
559         update_send_box ();
560 }
561
562 void
563 FoldbackStrip::set_stuff_from_route ()
564 {
565         /* if width is not set, it will be set by the MixerUI or editor */
566
567         Width width;
568         if (get_gui_property ("strip-width", width)) {
569 //              set_width_enum (width, this);
570         }
571 }
572
573 void
574 FoldbackStrip::set_packed (bool yn)
575 {
576         _packed = yn;
577         set_gui_property ("visible", _packed);
578 }
579
580
581 struct RouteCompareByName {
582         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
583                 return a->name().compare (b->name()) < 0;
584         }
585 };
586
587 gint
588 FoldbackStrip::output_release (GdkEventButton *ev)
589 {
590         switch (ev->button) {
591         case 3:
592                 edit_output_configuration ();
593                 break;
594         }
595
596         return false;
597 }
598
599 gint
600 FoldbackStrip::output_press (GdkEventButton *ev)
601 {
602         using namespace Menu_Helpers;
603         if (!ARDOUR_UI_UTILS::engine_is_running ()) {
604                 return true;
605         }
606
607         MenuList& citems = output_menu.items();
608         switch (ev->button) {
609
610         case 3:
611                 return false;  //wait for the mouse-up to pop the dialog
612
613         case 1:
614         {
615                 output_menu.set_name ("ArdourContextMenu");
616                 citems.clear ();
617                 output_menu_bundles.clear ();
618
619                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
620
621                 citems.push_back (SeparatorElem());
622                 uint32_t const n_with_separator = citems.size ();
623
624                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
625
626                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
627
628                 /* guess the user-intended main type of the route output */
629                 DataType intended_type = guess_main_type(false);
630
631                 /* try adding the master bus first */
632                 boost::shared_ptr<Route> master = _session->master_out();
633                 if (master) {
634                         maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
635                 }
636
637                 /* then other routes inputs */
638                 RouteList copy = _session->get_routelist ();
639                 copy.sort (RouteCompareByName ());
640                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
641                         maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
642                 }
643
644                 /* then try adding user bundles, often labeled/grouped physical inputs */
645                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
646                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
647                                 maybe_add_bundle_to_output_menu (*i, current, intended_type);
648                         }
649                 }
650
651                 /* then all other bundles, including physical outs or other sofware */
652                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
653                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
654                                 maybe_add_bundle_to_output_menu (*i, current, intended_type);
655                         }
656                 }
657
658                 if (citems.size() == n_with_separator) {
659                         /* no routes added; remove the separator */
660                         citems.pop_back ();
661                 }
662
663                 if (!ARDOUR::Profile->get_mixbus()) {
664                         citems.push_back (SeparatorElem());
665
666                         for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
667                                 citems.push_back (
668                                                 MenuElem (
669                                                         string_compose (_("Add %1 port"), (*i).to_i18n_string()),
670                                                         sigc::bind (sigc::mem_fun (*this, &FoldbackStrip::add_output_port), *i)
671                                                         )
672                                                 );
673                         }
674                 }
675
676                 citems.push_back (SeparatorElem());
677                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
678
679                 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
680                                                1, ev->time);
681
682                 break;
683         }
684
685         default:
686                 break;
687         }
688         return TRUE;
689 }
690
691 void
692 FoldbackStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
693 {
694         if (ignore_toggle) {
695                 return;
696         }
697
698         _route->output()->connect_ports_to_bundle (c, true, true, this);
699 }
700
701 void
702 FoldbackStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
703                                              DataType type)
704 {
705         using namespace Menu_Helpers;
706
707         /* The bundle should be an input one, but not ours */
708         if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
709                 return;
710         }
711
712         /* Don't add the monitor input unless we are Master */
713         boost::shared_ptr<Route> monitor = _session->monitor_out();
714         if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
715                 return;
716
717         /* It should either match exactly our outputs (if |type| is DataType::NIL)
718          * or have the same number of |type| channels than our outputs. */
719         if (type == DataType::NIL) {
720                 if(b->nchannels() != _route->n_outputs())
721                         return;
722         } else {
723                 if (b->nchannels().n(type) != _route->n_outputs().n(type))
724                         return;
725         }
726
727         /* Avoid adding duplicates */
728         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
729         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
730                 ++i;
731         }
732         if (i != output_menu_bundles.end()) {
733                 return;
734         }
735
736         /* Now add the bundle to the menu */
737         output_menu_bundles.push_back (b);
738
739         MenuList& citems = output_menu.items();
740         citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &FoldbackStrip::bundle_output_chosen), b)));
741 }
742
743 void
744 FoldbackStrip::connect_to_pan ()
745 {
746         ENSURE_GUI_THREAD (*this, &FoldbackStrip::connect_to_pan)
747
748         panstate_connection.disconnect ();
749         panstyle_connection.disconnect ();
750
751         if (!_route->panner()) {
752                 return;
753         }
754
755         boost::shared_ptr<Pannable> p = _route->pannable ();
756
757         //p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
758
759         /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
760          * However, that only works a panner was previously set.
761          *
762          * PannerUI must remain subscribed to _panshell->Changed() in case
763          * we switch the panner eg. AUX-Send and back
764          * _route->panner_shell()->Changed() vs _panshell->Changed
765          */
766         /*if (panners._panner == 0) {
767                 panners.panshell_changed ();
768         }*/
769         update_panner_choices();
770 }
771
772 void
773 FoldbackStrip::update_panner_choices ()
774 {
775         ENSURE_GUI_THREAD (*this, &FoldbackStrip::update_panner_choices)
776         if (!_route->panner_shell()) { return; }
777
778         uint32_t in = _route->output()->n_ports().n_audio();
779         uint32_t out = in;
780         if (_route->panner()) {
781                 in = _route->panner()->in().n_audio();
782         }
783
784         panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
785 }
786
787 DataType
788 FoldbackStrip::guess_main_type(bool for_input, bool favor_connected) const
789 {
790         /* The heuristic follows these principles:
791          *  A) If all ports that the user connected are of the same type, then he
792          *     very probably intends to use the IO with that type. A common subcase
793          *     is when the IO has only ports of the same type (connected or not).
794          *  B) If several types of ports are connected, then we should guess based
795          *     on the likeliness of the user wanting to use a given type.
796          *     We assume that the DataTypes are ordered from the most likely to the
797          *     least likely when iterating or comparing them with "<".
798          *  C) If no port is connected, the same logic can be applied with all ports
799          *     instead of connected ones. TODO: Try other ideas, for instance look at
800          *     the last plugin output when |for_input| is false (note: when StrictIO
801          *     the outs of the last plugin should be the same as the outs of the route
802          *     modulo the panner which forwards non-audio anyway).
803          * All of these constraints are respected by the following algorithm that
804          * just returns the most likely datatype found in connected ports if any, or
805          * available ports if any (since if all ports are of the same type, the most
806          * likely found will be that one obviously). */
807
808         boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
809
810         /* Find most likely type among connected ports */
811         if (favor_connected) {
812                 DataType type = DataType::NIL; /* NIL is always last so least likely */
813                 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
814                         if (p->connected() && p->type() < type)
815                                 type = p->type();
816                 }
817                 if (type != DataType::NIL) {
818                         /* There has been a connected port (necessarily non-NIL) */
819                         return type;
820                 }
821         }
822
823         /* Find most likely type among available ports.
824          * The iterator stops before NIL. */
825         for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
826                 if (io->n_ports().n(*t) > 0)
827                         return *t;
828         }
829
830         /* No port at all, return the most likely datatype by default */
831         return DataType::front();
832 }
833
834 /*
835  * Output port labelling
836  *
837  * Case 1: Each output has one connection, all connections are to system:playback_%i
838  *   out 1 -> system:playback_1
839  *   out 2 -> system:playback_2
840  *   out 3 -> system:playback_3
841  *   Display as: 1/2/3
842  *
843  * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
844  *   out 1 -> ardour:track_x/in 1
845  *   out 2 -> ardour:track_x/in 2
846  *   Display as: track_x
847  *
848  * Case 3: Each output has one connection, all connections are to Jack client "program x"
849  *   out 1 -> program x:foo
850  *   out 2 -> program x:foo
851  *   Display as: program x
852  *
853  * Case 4: No connections (Disconnected)
854  *   Display as: -
855  *
856  * Default case (unusual routing):
857  *   Display as: *number of connections*
858  *
859  *
860  * Tooltips
861  *
862  * .-----------------------------------------------.
863  * | Mixdown                                       |
864  * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
865  * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
866  * '-----------------------------------------------'
867  * .-----------------------------------------------.
868  * | Guitar SM58                                   |
869  * | Disconnected                                  |
870  * '-----------------------------------------------'
871  */
872
873 void
874 FoldbackStrip::update_io_button ()
875 {
876         ostringstream tooltip;
877         ostringstream label;
878         bool have_label = false;
879
880         uint32_t total_connection_count = 0;
881         uint32_t typed_connection_count = 0;
882         bool each_typed_port_has_one_connection = true;
883
884         DataType dt = guess_main_type(false);
885         boost::shared_ptr<IO> io = _route->output();
886
887         /* Fill in the tooltip. Also count:
888          *  - The total number of connections.
889          *  - The number of main-typed connections.
890          *  - Whether each main-typed port has exactly one connection. */
891
892         tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
893                         Gtkmm2ext::markup_escape_text (_route->name()));
894
895         string arrow = Gtkmm2ext::markup_escape_text(" -> ");
896         vector<string> port_connections;
897         for (PortSet::iterator port = io->ports().begin();
898                                port != io->ports().end();
899                                ++port) {
900                 port_connections.clear();
901                 port->get_connections(port_connections);
902
903                 uint32_t port_connection_count = 0;
904
905                 for (vector<string>::iterator i = port_connections.begin();
906                                               i != port_connections.end();
907                                               ++i) {
908                         ++port_connection_count;
909
910                         if (port_connection_count == 1) {
911                                 tooltip << endl << Gtkmm2ext::markup_escape_text (
912                                                 port->name().substr(port->name().find("/") + 1));
913                                 tooltip << arrow;
914                         } else {
915                                 tooltip << ", ";
916                         }
917
918                         tooltip << Gtkmm2ext::markup_escape_text(*i);
919                 }
920
921                 total_connection_count += port_connection_count;
922                 if (port->type() == dt) {
923                         typed_connection_count += port_connection_count;
924                         each_typed_port_has_one_connection &= (port_connection_count == 1);
925                 }
926
927         }
928
929         if (total_connection_count == 0) {
930                 tooltip << endl << _("Disconnected");
931         }
932
933         if (typed_connection_count == 0) {
934                 label << "-";
935                 have_label = true;
936         }
937
938         /* Are all main-typed channels connected to the same route ? */
939         if (!have_label) {
940                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
941                 for (ARDOUR::RouteList::const_iterator route = routes->begin();
942                                                        route != routes->end();
943                                                        ++route) {
944                         boost::shared_ptr<IO> dest_io = (*route)->output();
945                         if (io->bundle()->connected_to(dest_io->bundle(),
946                                                        _session->engine(),
947                                                        dt, true)) {
948                                 label << Gtkmm2ext::markup_escape_text ((*route)->name());
949                                 have_label = true;
950                                 break;
951                         }
952                 }
953         }
954
955         /* Are all main-typed channels connected to the same (user) bundle ? */
956         if (!have_label) {
957                 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
958                 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
959                                                   bundle != bundles->end();
960                                                   ++bundle) {
961                         if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
962                                 continue;
963                         if (io->bundle()->connected_to(*bundle, _session->engine(),
964                                                        dt, true)) {
965                                 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
966                                 have_label = true;
967                                 break;
968                         }
969                 }
970         }
971
972         /* Is each main-typed channel only connected to a physical output ? */
973         if (!have_label && each_typed_port_has_one_connection) {
974                 ostringstream temp_label;
975                 vector<string> phys;
976                 string playorcapture;
977
978                 _session->engine().get_physical_outputs(dt, phys);
979                 playorcapture = "playback_";
980                 for (PortSet::iterator port = io->ports().begin(dt);
981                                        port != io->ports().end(dt);
982                                        ++port) {
983                         string pn = "";
984                         for (vector<string>::iterator s = phys.begin();
985                                                       s != phys.end();
986                                                       ++s) {
987                                 if (!port->connected_to(*s))
988                                         continue;
989                                 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
990                                 if (pn.empty()) {
991                                         string::size_type start = (*s).find(playorcapture);
992                                         if (start != string::npos) {
993                                                 pn = (*s).substr(start + playorcapture.size());
994                                         }
995                                 }
996                                 break;
997                         }
998                         if (pn.empty()) {
999                                 temp_label.str(""); /* erase the failed attempt */
1000                                 break;
1001                         }
1002                         if (port != io->ports().begin(dt))
1003                                 temp_label << "/";
1004                         temp_label << pn;
1005                 }
1006
1007                 if (!temp_label.str().empty()) {
1008                         label << temp_label.str();
1009                         have_label = true;
1010                 }
1011         }
1012
1013         /* Is each main-typed channel connected to a single and different port with
1014          * the same client name (e.g. another JACK client) ? */
1015         if (!have_label && each_typed_port_has_one_connection) {
1016                 string maybe_client = "";
1017                 vector<string> connections;
1018                 for (PortSet::iterator port = io->ports().begin(dt);
1019                                        port != io->ports().end(dt);
1020                                        ++port) {
1021                         port_connections.clear();
1022                         port->get_connections(port_connections);
1023                         string connection = port_connections.front();
1024
1025                         vector<string>::iterator i = connections.begin();
1026                         while (i != connections.end() && *i != connection) {
1027                                 ++i;
1028                         }
1029                         if (i != connections.end())
1030                                 break; /* duplicate connection */
1031                         connections.push_back(connection);
1032
1033                         connection = connection.substr(0, connection.find(":"));
1034                         if (maybe_client.empty())
1035                                 maybe_client = connection;
1036                         if (maybe_client != connection)
1037                                 break;
1038                 }
1039                 if (connections.size() == io->n_ports().n(dt)) {
1040                         label << maybe_client;
1041                         have_label = true;
1042                 }
1043         }
1044
1045         /* Odd configuration */
1046         if (!have_label) {
1047                 label << "*" << total_connection_count << "*";
1048         }
1049
1050         if (total_connection_count > typed_connection_count) {
1051                 label << "\u2295"; /* circled plus */
1052         }
1053
1054         /* Actually set the properties of the button */
1055         char * cstr = new char[tooltip.str().size() + 1];
1056         strcpy(cstr, tooltip.str().c_str());
1057
1058         output_button.set_text (label.str());
1059         set_tooltip (&output_button, cstr);
1060
1061         delete [] cstr;
1062 }
1063
1064 void
1065 FoldbackStrip::update_output_display ()
1066 {
1067         update_io_button ();
1068         panners.setup_pan ();
1069
1070         if (has_audio_outputs ()) {
1071                 panners.show_all ();
1072         } else {
1073                 panners.hide_all ();
1074         }
1075 }
1076
1077 void
1078 FoldbackStrip::io_changed_proxy ()
1079 {
1080         Glib::signal_idle().connect_once (sigc::mem_fun (*this, &FoldbackStrip::update_panner_choices));
1081 }
1082
1083 void
1084 FoldbackStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1085 {
1086         boost::shared_ptr<Port> a = wa.lock ();
1087         boost::shared_ptr<Port> b = wb.lock ();
1088
1089         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1090                 update_output_display ();
1091         }
1092 }
1093
1094 void
1095 FoldbackStrip::setup_comment_button ()
1096 {
1097         std::string comment = _route->comment();
1098
1099         set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1100
1101         if (comment.empty ()) {
1102                 _comment_button.set_name ("generic button");
1103                 _comment_button.set_text (_("Comments"));
1104                 return;
1105         }
1106
1107         _comment_button.set_name ("comment button");
1108
1109         string::size_type pos = comment.find_first_of (" \t\n");
1110         if (pos != string::npos) {
1111                 comment = comment.substr (0, pos);
1112         }
1113         if (comment.empty()) {
1114                 _comment_button.set_text (_("Comments"));
1115         } else {
1116                 _comment_button.set_text (comment);
1117         }
1118 }
1119
1120 void
1121 FoldbackStrip::show_passthru_color ()
1122 {
1123         //reset_strip_style ();
1124 }
1125
1126
1127 void
1128 FoldbackStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1129 {
1130         boost::shared_ptr<Processor> processor (p.lock ());
1131         if (!processor || !processor->display_to_user()) {
1132                 return;
1133         }
1134         boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1135 #ifdef MIXBUS
1136         if (pi && pi->is_channelstrip ()) {
1137                 return;
1138         }
1139 #endif
1140         if (pi) {
1141                 ++_plugin_insert_cnt;
1142         }
1143 }
1144 void
1145 FoldbackStrip::build_route_ops_menu ()
1146 {
1147         using namespace Menu_Helpers;
1148         route_ops_menu = new Menu;
1149         route_ops_menu->set_name ("ArdourContextMenu");
1150
1151         MenuList& items = route_ops_menu->items();
1152
1153         items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1154
1155         items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1156
1157         items.push_back (SeparatorElem());
1158
1159         items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1160
1161         items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1162
1163         items.push_back (SeparatorElem());
1164         items.push_back (CheckMenuElem (_("Active")));
1165         Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1166         i->set_active (_route->active());
1167         i->set_sensitive(! _session->transport_rolling());
1168         i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1169
1170         items.push_back (SeparatorElem());
1171         items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1172         denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1173         denormal_menu_item->set_active (_route->denormal_protection());
1174
1175         items.push_back (SeparatorElem());
1176         items.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &FoldbackStrip::remove_current_fb)));
1177 }
1178
1179 void
1180 FoldbackStrip::build_route_select_menu ()
1181 {
1182         using namespace Menu_Helpers;
1183         route_select_menu = new Menu;
1184         route_select_menu->set_name ("ArdourContextMenu");
1185
1186         MenuList& items = route_select_menu->items();
1187         StripableList fb_list;
1188         _session->get_stripables (fb_list, PresentationInfo::FoldbackBus);
1189         for (StripableList::iterator s = fb_list.begin(); s != fb_list.end(); ++s) {
1190
1191                 boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> ((*s));
1192                 if (route == _route) {
1193                         continue;
1194                 }
1195                 items.push_back (MenuElem (route->name (), sigc::bind (sigc::mem_fun (*this, &FoldbackStrip::set_route), route)));
1196         }
1197
1198 }
1199
1200
1201 gboolean
1202 FoldbackStrip::name_button_button_press (GdkEventButton* ev)
1203 {
1204         if (ev->button == 1 || ev->button == 3) {
1205                 list_route_operations ();
1206
1207                 if (ev->button == 1) {
1208                         Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1209                                                        1, ev->time);
1210                 } else {
1211                         route_ops_menu->popup (3, ev->time);
1212                 }
1213
1214                 return true;
1215         }
1216
1217         return false;
1218 }
1219
1220 gboolean
1221 FoldbackStrip::select_button_button_press (GdkEventButton* ev)
1222 {
1223         if (ev->button == 1 || ev->button == 3) {
1224                 list_fb_routes ();
1225
1226                 if (ev->button == 1) {
1227                         Gtkmm2ext::anchored_menu_popup(route_select_menu, &_select_button, "",
1228                                                        1, ev->time);
1229                 } else {
1230                         route_select_menu->popup (3, ev->time);
1231                 }
1232
1233                 return true;
1234         }
1235
1236         return false;
1237 }
1238
1239 void
1240 FoldbackStrip::list_route_operations ()
1241 {
1242         delete route_ops_menu;
1243         build_route_ops_menu ();
1244 }
1245
1246 void
1247 FoldbackStrip::list_fb_routes ()
1248 {
1249         delete route_select_menu;
1250         build_route_select_menu ();
1251 }
1252
1253 void
1254 FoldbackStrip::set_selected (bool yn)
1255 {
1256         AxisView::set_selected (yn);
1257
1258         if (selected()) {
1259                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1260                 global_frame.set_name ("MixerStripSelectedFrame");
1261         } else {
1262                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1263                 global_frame.set_name ("MixerStripFrame");
1264         }
1265
1266         global_frame.queue_draw ();
1267
1268 //      if (!yn)
1269 //              processor_box.deselect_all_processors();
1270 }
1271
1272 void
1273 FoldbackStrip::route_property_changed (const PropertyChange& what_changed)
1274 {
1275         if (what_changed.contains (ARDOUR::Properties::name)) {
1276                 name_changed ();
1277         }
1278 }
1279
1280 void
1281 FoldbackStrip::name_changed ()
1282 {
1283
1284         name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
1285         name_button.set_text (_route->name());
1286
1287         set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1288
1289 }
1290
1291 void
1292 FoldbackStrip::set_embedded (bool yn)
1293 {
1294         _embedded = yn;
1295 }
1296
1297 void
1298 FoldbackStrip::map_frozen ()
1299 {
1300         ENSURE_GUI_THREAD (*this, &FoldbackStrip::map_frozen)
1301
1302
1303         RouteUI::map_frozen ();
1304 }
1305
1306 void
1307 FoldbackStrip::hide_redirect_editors ()
1308 {
1309         _route->foreach_processor (sigc::mem_fun (*this, &FoldbackStrip::hide_processor_editor));
1310 }
1311
1312 void
1313 FoldbackStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1314 {
1315         boost::shared_ptr<Processor> processor (p.lock ());
1316         if (!processor) {
1317                 return;
1318         }
1319
1320         Gtk::Window* w = insert_box->get_processor_ui (processor);
1321
1322         if (w) {
1323                 w->hide ();
1324         }
1325 }
1326
1327 void
1328 FoldbackStrip::reset_strip_style ()
1329 {
1330                         if (_route->active()) {
1331                                 set_name ("AudioBusStripBase");
1332                         } else {
1333                                 set_name ("AudioBusStripBaseInactive");
1334                         }
1335
1336 }
1337
1338 void
1339 FoldbackStrip::engine_stopped ()
1340 {
1341 }
1342
1343 void
1344 FoldbackStrip::engine_running ()
1345 {
1346 }
1347
1348 void
1349 FoldbackStrip::drop_send ()
1350 {
1351         boost::shared_ptr<Send> current_send;
1352
1353         if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
1354                 current_send->set_metering (false);
1355         }
1356
1357         send_gone_connection.disconnect ();
1358         output_button.set_sensitive (true);
1359         set_invert_sensitive (true);
1360         mute_button->set_sensitive (true);
1361         solo_button->set_sensitive (true);
1362         _comment_button.set_sensitive (true);
1363         fb_level_control->set_sensitive (true);
1364         set_button_names (); // update solo button visual state
1365 }
1366
1367 void
1368 FoldbackStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
1369 {
1370         _current_delivery = d;
1371         DeliveryChanged (_current_delivery);
1372 }
1373
1374 void
1375 FoldbackStrip::revert_to_default_display ()
1376 {
1377         drop_send ();
1378
1379         set_current_delivery (_route->main_outs ());
1380
1381         panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
1382         update_panner_choices();
1383         panner_ui().setup_pan ();
1384         panner_ui().set_send_drawing_mode (false);
1385
1386         if (has_audio_outputs ()) {
1387                 panners.show_all ();
1388         } else {
1389                 panners.hide_all ();
1390         }
1391
1392         reset_strip_style ();
1393 }
1394
1395 void
1396 FoldbackStrip::set_button_names ()
1397 {
1398
1399         mute_button->set_text (_("Mute"));
1400
1401         if (_route && _route->solo_safe_control()->solo_safe()) {
1402                 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1403         } else {
1404                 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1405         }
1406         if (!Config->get_solo_control_is_listen_control()) {
1407                 solo_button->set_text (_("Solo"));
1408         } else {
1409                 switch (Config->get_listen_position()) {
1410                 case AfterFaderListen:
1411                         solo_button->set_text (_("AFL"));
1412                         break;
1413                 case PreFaderListen:
1414                         solo_button->set_text (_("PFL"));
1415                         break;
1416                 }
1417         }
1418 }
1419
1420 PluginSelector*
1421 FoldbackStrip::plugin_selector()
1422 {
1423         return _mixer.plugin_selector();
1424 }
1425
1426 string
1427 FoldbackStrip::state_id () const
1428 {
1429         return string_compose ("strip %1", _route->id().to_s());
1430 }
1431
1432 void
1433 FoldbackStrip::add_output_port (DataType t)
1434 {
1435         _route->output()->add_port ("", this, t);
1436 }
1437
1438 void
1439 FoldbackStrip::route_active_changed ()
1440 {
1441         reset_strip_style ();
1442 }
1443
1444 void
1445 FoldbackStrip::copy_processors ()
1446 {
1447         insert_box->processor_operation (ProcessorBox::ProcessorsCopy);
1448 }
1449
1450 void
1451 FoldbackStrip::cut_processors ()
1452 {
1453         insert_box->processor_operation (ProcessorBox::ProcessorsCut);
1454 }
1455
1456 void
1457 FoldbackStrip::paste_processors ()
1458 {
1459         insert_box->processor_operation (ProcessorBox::ProcessorsPaste);
1460 }
1461
1462 void
1463 FoldbackStrip::select_all_processors ()
1464 {
1465         insert_box->processor_operation (ProcessorBox::ProcessorsSelectAll);
1466 }
1467
1468 void
1469 FoldbackStrip::deselect_all_processors ()
1470 {
1471         insert_box->processor_operation (ProcessorBox::ProcessorsSelectNone);
1472 }
1473
1474 bool
1475 FoldbackStrip::delete_processors ()
1476 {
1477         return insert_box->processor_operation (ProcessorBox::ProcessorsDelete);
1478 }
1479
1480 void
1481 FoldbackStrip::toggle_processors ()
1482 {
1483         insert_box->processor_operation (ProcessorBox::ProcessorsToggleActive);
1484 }
1485
1486 void
1487 FoldbackStrip::ab_plugins ()
1488 {
1489         insert_box->processor_operation (ProcessorBox::ProcessorsAB);
1490 }
1491
1492 void
1493 FoldbackStrip::build_sends_menu ()
1494 {
1495         using namespace Menu_Helpers;
1496
1497         sends_menu = new Menu;
1498         sends_menu->set_name ("ArdourContextMenu");
1499         MenuList& items = sends_menu->items();
1500
1501         items.push_back (
1502                 MenuElem(_("Assign all tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1503                 );
1504
1505         items.push_back (
1506                 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1507                 );
1508
1509         items.push_back (
1510                 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1511                 );
1512
1513         items.push_back (
1514                 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1515
1516         items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1517         items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1518         items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1519
1520 }
1521
1522 Gdk::Color
1523 FoldbackStrip::color () const
1524 {
1525         return route_color ();
1526 }
1527
1528 void
1529 FoldbackStrip::remove_current_fb ()
1530 {
1531         clear_send_box ();
1532         StripableList slist;
1533         boost::shared_ptr<Route> next = boost::shared_ptr<Route> ();
1534         boost::shared_ptr<Route> old_route = _route;
1535         _session->get_stripables (slist, PresentationInfo::FoldbackBus);
1536         if (slist.size ()) {
1537                 for (StripableList::iterator s = slist.begin(); s != slist.end(); ++s) {
1538                         if ((*s) != _route) {
1539                                 next = boost::dynamic_pointer_cast<Route> (*s);
1540                                 break;
1541                         }
1542                 }
1543         }
1544         if (next) {
1545                 set_route (next);
1546                 _session->remove_route (old_route);
1547         } else {
1548                 clear_send_box ();
1549                 RouteUI::self_delete ();
1550                 _session->remove_route (old_route);
1551         }
1552
1553
1554 }