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