ardour
mixer_strip.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000-2006 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 
19 #include <cmath>
20 #include <list>
21 #include <algorithm>
22 
23 #include <sigc++/bind.h>
24 
25 #include "pbd/convert.h"
26 #include "pbd/enumwriter.h"
27 #include "pbd/replace_all.h"
28 #include "pbd/stacktrace.h"
29 
30 #include <gtkmm2ext/gtk_ui.h>
31 #include <gtkmm2ext/utils.h>
32 #include <gtkmm2ext/choice.h>
33 #include <gtkmm2ext/doi.h>
36 
37 #include "ardour/amp.h"
38 #include "ardour/audio_track.h"
39 #include "ardour/audioengine.h"
40 #include "ardour/internal_send.h"
41 #include "ardour/meter.h"
42 #include "ardour/midi_track.h"
43 #include "ardour/pannable.h"
44 #include "ardour/panner.h"
45 #include "ardour/panner_shell.h"
46 #include "ardour/panner_manager.h"
47 #include "ardour/port.h"
48 #include "ardour/profile.h"
49 #include "ardour/route.h"
50 #include "ardour/route_group.h"
51 #include "ardour/send.h"
52 #include "ardour/session.h"
53 #include "ardour/types.h"
54 #include "ardour/user_bundle.h"
55 
56 #include "ardour_ui.h"
57 #include "ardour_window.h"
58 #include "mixer_strip.h"
59 #include "mixer_ui.h"
60 #include "keyboard.h"
61 #include "ardour_button.h"
62 #include "public_editor.h"
63 #include "send_ui.h"
64 #include "io_selector.h"
65 #include "utils.h"
66 #include "gui_thread.h"
67 #include "route_group_menu.h"
68 #include "meter_patterns.h"
69 
70 #include "i18n.h"
71 
72 using namespace ARDOUR;
73 using namespace ARDOUR_UI_UTILS;
74 using namespace PBD;
75 using namespace Gtk;
76 using namespace Gtkmm2ext;
77 using namespace std;
78 using namespace ArdourMeter;
79 
81 
82 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
83 
84 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
85  : AxisView(sess)
86  , RouteUI (sess)
87  , _mixer(mx)
88  , _mixer_owned (in_mixer)
89  , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
90  , gpm (sess, 250)
91  , panners (sess)
92  , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
93  , rec_mon_table (2, 2)
94  , solo_iso_table (1, 2)
95  , mute_solo_table (1, 2)
96  , bottom_button_table (1, 3)
97  , meter_point_button (_("pre"))
98  , midi_input_enable_button (0)
99  , _comment_button (_("Comments"))
100  , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
101  , _visibility (X_("mixer-element-visibility"))
102 {
103  init ();
104 
105  if (!_mixer_owned) {
106  /* the editor mixer strip: don't destroy it every time
107  the underlying route goes away.
108  */
109 
110  self_destruct = false;
111  }
112 }
113 
115  : AxisView(sess)
116  , RouteUI (sess)
117  , _mixer(mx)
118  , _mixer_owned (in_mixer)
119  , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
120  , gpm (sess, 250)
121  , panners (sess)
122  , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
123  , rec_mon_table (2, 2)
124  , solo_iso_table (1, 2)
125  , mute_solo_table (1, 2)
126  , bottom_button_table (1, 3)
127  , meter_point_button (_("pre"))
128  , midi_input_enable_button (0)
129  , _comment_button (_("Comments"))
130  , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
131  , _visibility (X_("mixer-element-visibility"))
132 {
133  init ();
134  set_route (rt);
135 }
136 
137 void
139 {
141  group_menu = 0;
142  route_ops_menu = 0;
143  ignore_comment_edit = false;
144  ignore_toggle = false;
145  comment_area = 0;
146  _width_owner = 0;
147  spacer = 0;
148 
149  /* the length of this string determines the width of the mixer strip when it is set to `wide' */
150  longest_label = "longest label";
151 
152  string t = _("Click to toggle the width of this mixer strip.");
153  if (_mixer_owned) {
154  t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
155  }
156 
160 
163  ARDOUR_UI::instance()->set_tip (&hide_button, _("Hide this mixer strip"));
164 
165  input_button_box.set_spacing(2);
166 
167  input_button.set_text (_("Input"));
168  input_button.set_name ("mixer strip button");
169  input_button_box.pack_start (input_button, true, true);
170 
171  output_button.set_text (_("Output"));
172  output_button.set_name ("mixer strip button");
173 
174  ARDOUR_UI::instance()->set_tip (&meter_point_button, _("Click to select metering point"), "");
175  meter_point_button.set_name ("mixer strip button");
176 
177  bottom_button_table.attach (meter_point_button, 2, 3, 0, 1);
178 
179  meter_point_button.signal_button_press_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_press), false);
180  meter_point_button.signal_button_release_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_release), false);
181 
182  hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
183 
185  solo_isolated_led->show ();
186  solo_isolated_led->set_no_show_all (true);
187  solo_isolated_led->set_name (X_("solo isolate"));
188  solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
189  solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
190  UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
191 
193  solo_safe_led->show ();
194  solo_safe_led->set_no_show_all (true);
195  solo_safe_led->set_name (X_("solo safe"));
196  solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
197  solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
198  UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
199 
200  solo_safe_led->set_text (S_("SoloLock|Lock"));
201  solo_isolated_led->set_text (_("Iso"));
202 
203  solo_iso_table.set_homogeneous (true);
204  solo_iso_table.set_spacings (2);
205  if (!ARDOUR::Profile->get_trx()) {
206  solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
207  solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
208  }
209  solo_iso_table.show ();
210 
211  rec_mon_table.set_homogeneous (true);
212  rec_mon_table.set_row_spacings (2);
213  rec_mon_table.set_col_spacings (2);
214  if (ARDOUR::Profile->get_mixbus()) {
215  rec_mon_table.resize (1, 3);
216  rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
217  rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
218  } else if (!ARDOUR::Profile->get_trx()) {
219  rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
220  rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
221  }
222  rec_mon_table.show ();
223 
224  if (solo_isolated_led) {
225  button_size_group->add_widget (*solo_isolated_led);
226  }
227  if (solo_safe_led) {
228  button_size_group->add_widget (*solo_safe_led);
229  }
230 
231  if (!ARDOUR::Profile->get_mixbus()) {
232  if (rec_enable_button) {
233  button_size_group->add_widget (*rec_enable_button);
234  }
235  if (monitor_disk_button) {
236  button_size_group->add_widget (*monitor_disk_button);
237  }
238  if (monitor_input_button) {
240  }
241  }
242 
243  mute_solo_table.set_homogeneous (true);
244  mute_solo_table.set_spacings (2);
245 
246  bottom_button_table.set_spacings (2);
247  bottom_button_table.set_homogeneous (true);
248  bottom_button_table.attach (group_button, 1, 2, 0, 1);
250 
251  name_button.set_name ("mixer strip button");
252  name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
253  name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
254 
255  ARDOUR_UI::instance()->set_tip (&group_button, _("Mix group"), "");
256  group_button.set_name ("mixer strip button");
257 
258  _comment_button.set_name (X_("mixer strip button"));
259  _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
260 
261  // TODO implement ArdourKnob::on_size_request properly
262 #define PX_SCALE(px) std::max((float)px, rintf((float)px * ARDOUR_UI::ui_scale))
263  trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
264 #undef PX_SCALE
265  trim_control.set_tooltip_prefix (_("Trim: "));
266  trim_control.set_name ("trim knob");
267  trim_control.set_no_show_all (true);
268  input_button_box.pack_start (trim_control, false, false);
269 
270  global_vpacker.set_border_width (1);
271  global_vpacker.set_spacing (0);
272 
273  width_button.set_name ("mixer strip button");
274  hide_button.set_name ("mixer strip button");
275 
276  width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
277  hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
278 
279 // width_hide_box.set_border_width (1);
280  width_hide_box.set_spacing (2);
281  width_hide_box.pack_start (width_button, false, true);
282  width_hide_box.pack_start (number_label, true, true);
283  width_hide_box.pack_end (hide_button, false, true);
284 
285  number_label.set_text ("-");
287  number_label.set_no_show_all ();
288  number_label.set_name ("tracknumber label");
289  number_label.set_fixed_colors (0x80808080, 0x80808080);
290  number_label.set_alignment (.5, .5);
292 
293  global_vpacker.set_spacing (2);
294  if (!ARDOUR::Profile->get_trx()) {
295  global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
296  global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
297  global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
298  global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
299  global_vpacker.pack_start (processor_box, true, true);
300  }
301  global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
302  global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
303  global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
304  global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
305  global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
306  global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
307  if (!ARDOUR::Profile->get_trx()) {
308  global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
309  global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
310  } else {
311  global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
312  }
313 
315  global_frame.set_shadow_type (Gtk::SHADOW_IN);
316  global_frame.set_name ("BaseFrame");
317 
318  add (global_frame);
319 
320  /* force setting of visible selected status */
321 
322  _selected = true;
323  set_selected (false);
324 
325  _packed = false;
326  _embedded = false;
327 
328  _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
329  _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
330 
331  input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
332  input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
333  input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
334 
335  input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
336  output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
337 
338  output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
339  output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
340  output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
341 
342  number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
343 
344  name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
345  name_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_release), false);
346 
347  group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
348 
349  _width = (Width) -1;
350 
351  /* start off as a passthru strip. we'll correct this, if necessary,
352  in update_diskstream_display().
353  */
354 
355  /* start off as a passthru strip. we'll correct this, if necessary,
356  in update_diskstream_display().
357  */
358 
359  if (is_midi_track()) {
360  set_name ("MidiTrackStripBase");
361  } else {
362  set_name ("AudioTrackStripBase");
363  }
364 
365  add_events (Gdk::BUTTON_RELEASE_MASK|
366  Gdk::ENTER_NOTIFY_MASK|
367  Gdk::LEAVE_NOTIFY_MASK|
368  Gdk::KEY_PRESS_MASK|
369  Gdk::KEY_RELEASE_MASK);
370 
371  set_flags (get_flags() | Gtk::CAN_FOCUS);
372 
373  AudioEngine::instance()->PortConnectedOrDisconnected.connect (
374  *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
375  );
376 
377  /* Add the widgets under visibility control to the VisibilityGroup; the names used here
378  must be the same as those used in RCOptionEditor so that the configuration changes
379  are recognised when they occur.
380  */
381  _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
382  _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
383  _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
384  _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
385  _visibility.add (&output_button, X_("Output"), _("Output"), false);
386  _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
387 
388  parameter_changed (X_("mixer-element-visibility"));
389  ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
392 
393  //watch for mouse enter/exit so we can do some stuff
394  signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
395  signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
396 
397  gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
398 }
399 
401 {
402  CatchDeletion (this);
403 
404  if (this ==_entered_mixer_strip)
405  _entered_mixer_strip = NULL;
406 }
407 
408 bool
409 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
410 {
411  _entered_mixer_strip = this;
412 
413  //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
414  //because the mixerstrip control is a parent that encompasses the strip
416 
417  return false;
418 }
419 
420 bool
422 {
423  //if we have moved outside our strip, but not into a child view, then deselect ourselves
424  if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
426 
427  //clear keyboard focus in the gain display. this is cheesy but fixes a longstanding "bug" where the user starts typing in the gain entry, and leaves it active, thereby prohibiting other keybindings from working
428  gpm.gain_display.set_sensitive(false);
429  gpm.show_gain();
430  gpm.gain_display.set_sensitive(true);
431 
432  //if we leave this mixer strip we need to clear out any selections
433  //processor_box.processor_display.select_none(); //but this doesn't work, because it gets triggered when (for example) you open the menu or start a drag
434  }
435 
436  return false;
437 }
438 
439 void
441 {
442  //the rec/monitor stuff only shows up for tracks.
443  //the show_sends only shows up for buses.
444  //remove them all here, and we may add them back later
445  if (show_sends_button->get_parent()) {
447  }
448  if (rec_enable_button->get_parent()) {
450  }
451  if (monitor_input_button->get_parent()) {
453  }
454  if (monitor_disk_button->get_parent()) {
456  }
457  if (group_button.get_parent()) {
459  }
460 
461  RouteUI::set_route (rt);
462 
463  /* ProcessorBox needs access to _route so that it can read
464  GUI object state.
465  */
467 
469 
470  /* unpack these from the parent and stuff them into our own
471  table
472  */
473 
474  if (gpm.peak_display.get_parent()) {
475  gpm.peak_display.get_parent()->remove (gpm.peak_display);
476  }
477  if (gpm.gain_display.get_parent()) {
478  gpm.gain_display.get_parent()->remove (gpm.gain_display);
479  }
480 
481  gpm.set_type (rt->meter_type());
482 
483  mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
484  mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
485 
486  if (solo_button->get_parent()) {
487  mute_solo_table.remove (*solo_button);
488  }
489 
490  if (mute_button->get_parent()) {
491  mute_solo_table.remove (*mute_button);
492  }
493 
494  if (route()->is_master()) {
495  mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
496  solo_button->hide ();
497  mute_button->show ();
498  rec_mon_table.hide ();
499  if (solo_iso_table.get_parent()) {
500  solo_iso_table.get_parent()->remove(solo_iso_table);
501  }
502  } else {
503  bottom_button_table.attach (group_button, 1, 2, 0, 1);
504  mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
505  mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
506  mute_button->show ();
507  solo_button->show ();
508  rec_mon_table.show ();
509  }
510 
511  if (_mixer_owned && route()->is_master() ) {
512 
513  HScrollbar scrollbar;
514  Gtk::Requisition requisition(scrollbar.size_request ());
515  int scrollbar_height = requisition.height;
516 
517  spacer = manage (new EventBox);
518  spacer->set_size_request (-1, scrollbar_height+2);
519  global_vpacker.pack_start (*spacer, false, false);
520  spacer->show();
521  }
522 
523  if (is_track()) {
524  monitor_input_button->show ();
525  monitor_disk_button->show ();
526  } else {
527  monitor_input_button->hide();
528  monitor_disk_button->hide ();
529  }
530 
531  if (route()->trim() && route()->trim()->active()) {
532  trim_control.show ();
533  trim_control.set_controllable (route()->trim()->gain_control());
534  } else {
535  trim_control.hide ();
538  }
539 
540  if (is_midi_track()) {
541  if (midi_input_enable_button == 0) {
542  midi_input_enable_button = manage (new ArdourButton);
543  midi_input_enable_button->set_name ("midi input button");
546  midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
547  midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
548  ARDOUR_UI::instance()->set_tip (midi_input_enable_button, _("Enable/Disable MIDI input"));
549  } else {
551  }
552  /* get current state */
554  input_button_box.pack_start (*midi_input_enable_button, false, false);
555  /* follow changes */
557  } else {
559  /* removal from the container will delete it */
562  }
563  }
564 
565  if (is_audio_track()) {
567  at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
568  }
569 
570  if (is_track ()) {
571 
572  rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
573  rec_enable_button->set_sensitive (_session->writable());
574  rec_enable_button->show();
575 
576  if (ARDOUR::Profile->get_mixbus()) {
577  rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
578  rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
579  } else if (ARDOUR::Profile->get_trx()) {
580  rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
581  } else {
582  rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
583  rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
584  }
585 
586  } else {
587 
588  /* non-master bus */
589 
590  if (!_route->is_master()) {
591  rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
592  show_sends_button->show();
593  }
594  }
595 
597 
598  delete route_ops_menu;
599  route_ops_menu = 0;
600 
602  _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
603  _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
605 
606  _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
607 
608  if (_route->panner_shell()) {
610  _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
611  }
612 
613  if (is_audio_track()) {
614  audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
615  }
616 
618  _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::property_changed, this, _1), gui_context());
619 
621 
622  /* now force an update of all the various elements */
623 
626  name_changed ();
627  comment_changed (0);
629 
630  connect_to_pan ();
631  panners.setup_pan ();
632 
633  if (has_audio_outputs ()) {
634  panners.show_all ();
635  } else {
636  panners.hide_all ();
637  }
638 
642 
643  add_events (Gdk::BUTTON_RELEASE_MASK);
644 
645  processor_box.show ();
646 
647  if (!route()->is_master() && !route()->is_monitor()) {
648  /* we don't allow master or control routes to be hidden */
649  hide_button.show();
650  number_label.show();
651  }
652 
654  gpm.gain_display.show ();
655  gpm.peak_display.show ();
656 
657  width_button.show();
658  width_hide_box.show();
659  global_frame.show();
660  global_vpacker.show();
661  mute_solo_table.show();
662  bottom_button_table.show();
663  gpm.show_all ();
664  meter_point_button.show();
665  input_button_box.show_all();
666  output_button.show();
667  name_button.show();
668  _comment_button.show();
669  group_button.show();
671 
672  parameter_changed ("mixer-element-visibility");
673 
674  show ();
675 }
676 
677 void
679 {
680  /* if width is not set, it will be set by the MixerUI or editor */
681 
682  string str = gui_property ("strip-width");
683  if (!str.empty()) {
684  set_width_enum (Width (string_2_enum (str, _width)), this);
685  }
686 }
687 
688 void
690 {
691  /* always set the gpm width again, things may be hidden */
692 
693  gpm.set_width (w);
694  panners.set_width (w);
695 
696  boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
697 
698  _width_owner = owner;
699 
700  _width = w;
701 
702  if (_width_owner == this) {
703  set_gui_property ("strip-width", enum_2_string (_width));
704  }
705 
706  set_button_names ();
707 
708  const float scale = std::max(1.f, ARDOUR_UI::ui_scale);
709 
710  switch (w) {
711  case Wide:
712 
713  if (show_sends_button) {
714  show_sends_button->set_text (_("Aux"));
715  }
716 
718  gpm.astyle_string(gain_automation->automation_style()));
720  gpm.astate_string(gain_automation->automation_state()));
721 
722  if (_route->panner()) {
723  ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
724  panners.astyle_string(_route->panner()->automation_style()));
725  ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
726  panners.astate_string(_route->panner()->automation_state()));
727  }
728 
729  {
730  // panners expect an even number of horiz. pixels
731  int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
732  width &= ~1;
733  set_size_request (width, -1);
734  }
735  break;
736 
737  case Narrow:
738 
739  if (show_sends_button) {
740  show_sends_button->set_text (_("Snd"));
741  }
742 
744  gpm.short_astyle_string(gain_automation->automation_style()));
746  gpm.short_astate_string(gain_automation->automation_state()));
747  gain_meter().setup_meters (); // recalc meter width
748 
749  if (_route->panner()) {
750  ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
751  panners.short_astyle_string(_route->panner()->automation_style()));
752  ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
753  panners.short_astate_string(_route->panner()->automation_state()));
754  }
755 
756  {
757  // panners expect an even number of horiz. pixels
758  int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
759  width &= ~1;
760  set_size_request (width, -1);
761  }
762  break;
763  }
764 
766 
771  name_changed ();
772  WidthChanged ();
773 }
774 
775 void
777 {
778  _packed = yn;
779 
780  if (_packed) {
781  set_gui_property ("visible", true);
782  } else {
783  set_gui_property ("visible", false);
784  }
785 }
786 
787 
790  return a->name().compare (b->name()) < 0;
791  }
792 };
793 
794 gint
795 MixerStrip::output_release (GdkEventButton *ev)
796 {
797  switch (ev->button) {
798  case 3:
800  break;
801  }
802 
803  return false;
804 }
805 
806 gint
807 MixerStrip::output_press (GdkEventButton *ev)
808 {
809  using namespace Menu_Helpers;
810  if (!_session->engine().connected()) {
811  MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
812  msg.run ();
813  return true;
814  }
815 
816  MenuList& citems = output_menu.items();
817  switch (ev->button) {
818 
819  case 3:
820  return false; //wait for the mouse-up to pop the dialog
821 
822  case 1:
823  {
824  output_menu.set_name ("ArdourContextMenu");
825  citems.clear ();
826  output_menu_bundles.clear ();
827 
828  citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
829 
830  citems.push_back (SeparatorElem());
831  uint32_t const n_with_separator = citems.size ();
832 
833  ARDOUR::BundleList current = _route->output()->bundles_connected ();
834 
836 
837  /* give user bundles first chance at being in the menu */
838 
839  for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
840  if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
841  maybe_add_bundle_to_output_menu (*i, current);
842  }
843  }
844 
845  for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
846  if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
847  maybe_add_bundle_to_output_menu (*i, current);
848  }
849  }
850 
852  RouteList copy = *routes;
853  copy.sort (RouteCompareByName ());
854  for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
855  maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
856  }
857 
858  if (citems.size() == n_with_separator) {
859  /* no routes added; remove the separator */
860  citems.pop_back ();
861  }
862 
863  citems.push_back (SeparatorElem());
864 
865  for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
866  citems.push_back (
867  MenuElem (
868  string_compose (_("Add %1 port"), (*i).to_i18n_string()),
869  sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
870  )
871  );
872  }
873 
874  citems.push_back (SeparatorElem());
875  citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
876 
877  output_menu.popup (1, ev->time);
878  break;
879  }
880 
881  default:
882  break;
883  }
884  return TRUE;
885 }
886 
887 gint
888 MixerStrip::input_release (GdkEventButton *ev)
889 {
890  switch (ev->button) {
891 
892  case 3:
894  break;
895  default:
896  break;
897 
898  }
899 
900  return false;
901 }
902 
903 
904 gint
905 MixerStrip::input_press (GdkEventButton *ev)
906 {
907  using namespace Menu_Helpers;
908 
909  MenuList& citems = input_menu.items();
910  input_menu.set_name ("ArdourContextMenu");
911  citems.clear();
912 
913  if (!_session->engine().connected()) {
914  MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
915  msg.run ();
916  return true;
917  }
918 
920  return true;
921 
922  switch (ev->button) {
923 
924  case 3:
925  return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
926 
927  case 1:
928  {
929  citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
930 
931  citems.push_back (SeparatorElem());
932  uint32_t const n_with_separator = citems.size ();
933 
934  input_menu_bundles.clear ();
935 
936  ARDOUR::BundleList current = _route->input()->bundles_connected ();
937 
939 
940  /* give user bundles first chance at being in the menu */
941 
942  for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
943  if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
944  maybe_add_bundle_to_input_menu (*i, current);
945  }
946  }
947 
948  for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
949  if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
950  maybe_add_bundle_to_input_menu (*i, current);
951  }
952  }
953 
955  RouteList copy = *routes;
956  copy.sort (RouteCompareByName ());
957  for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
958  maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
959  }
960 
961  if (citems.size() == n_with_separator) {
962  /* no routes added; remove the separator */
963  citems.pop_back ();
964  }
965 
966  citems.push_back (SeparatorElem());
967  for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
968  citems.push_back (
969  MenuElem (
970  string_compose (_("Add %1 port"), (*i).to_i18n_string()),
971  sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
972  )
973  );
974  }
975 
976  citems.push_back (SeparatorElem());
977  citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
978 
979  input_menu.popup (1, ev->time);
980 
981  break;
982  }
983  default:
984  break;
985  }
986  return TRUE;
987 }
988 
989 void
991 {
992  if (ignore_toggle) {
993  return;
994  }
995 
996  ARDOUR::BundleList current = _route->input()->bundles_connected ();
997 
998  if (std::find (current.begin(), current.end(), c) == current.end()) {
999  _route->input()->connect_ports_to_bundle (c, true, this);
1000  } else {
1001  _route->input()->disconnect_ports_from_bundle (c, this);
1002  }
1003 }
1004 
1005 void
1007 {
1008  if (ignore_toggle) {
1009  return;
1010  }
1011 
1012  ARDOUR::BundleList current = _route->output()->bundles_connected ();
1013 
1014  if (std::find (current.begin(), current.end(), c) == current.end()) {
1015  _route->output()->connect_ports_to_bundle (c, true, this);
1016  } else {
1017  _route->output()->disconnect_ports_from_bundle (c, this);
1018  }
1019 }
1020 
1021 void
1023 {
1024  using namespace Menu_Helpers;
1025 
1026  if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1027  return;
1028  }
1029 
1030  list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1031  while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1032  ++i;
1033  }
1034 
1035  if (i != input_menu_bundles.end()) {
1036  return;
1037  }
1038 
1039  input_menu_bundles.push_back (b);
1040 
1041  MenuList& citems = input_menu.items();
1042 
1043  std::string n = b->name ();
1044  replace_all (n, "_", " ");
1045 
1046  citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1047 }
1048 
1049 void
1051 {
1052  using namespace Menu_Helpers;
1053 
1054  if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1055  return;
1056  }
1057 
1058  list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1059  while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1060  ++i;
1061  }
1062 
1063  if (i != output_menu_bundles.end()) {
1064  return;
1065  }
1066 
1067  output_menu_bundles.push_back (b);
1068 
1069  MenuList& citems = output_menu.items();
1070 
1071  std::string n = b->name ();
1072  replace_all (n, "_", " ");
1073 
1074  citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1075 }
1076 
1077 void
1079 {
1080  if (is_track() && input_selector) {
1081  input_selector->hide_all ();
1082  }
1083 
1085 }
1086 
1087 void
1089 {
1091 
1094 
1095  if (!_route->panner()) {
1096  return;
1097  }
1098 
1100 
1103 
1104  /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1105  * However, that only works a panner was previously set.
1106  *
1107  * PannerUI must remain subscribed to _panshell->Changed() in case
1108  * we switch the panner eg. AUX-Send and back
1109  * _route->panner_shell()->Changed() vs _panshell->Changed
1110  */
1111  if (panners._panner == 0) {
1113  }
1115 }
1116 
1117 void
1119 {
1121  if (!_route->panner_shell()) { return; }
1122 
1123  uint32_t in = _route->output()->n_ports().n_audio();
1124  uint32_t out = in;
1125  if (_route->panner()) {
1126  in = _route->panner()->in().n_audio();
1127  }
1128 
1129  panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1130 }
1131 
1132 /*
1133  * Output port labelling
1134  * =====================
1135  *
1136  * Case 1: Each output has one connection, all connections are to system:playback_%i
1137  * out 1 -> system:playback_1
1138  * out 2 -> system:playback_2
1139  * out 3 -> system:playback_3
1140  * Display as: 1/2/3
1141  *
1142  * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1143  * out 1 -> ardour:track_x/in 1
1144  * out 2 -> ardour:track_x/in 2
1145  * Display as: track_x
1146  *
1147  * Case 3: Each output has one connection, all connections are to Jack client "program x"
1148  * out 1 -> program x:foo
1149  * out 2 -> program x:foo
1150  * Display as: program x
1151  *
1152  * Case 4: No connections (Disconnected)
1153  * Display as: -
1154  *
1155  * Default case (unusual routing):
1156  * Display as: *number of connections*
1157  *
1158  * Tooltips
1159  * ========
1160  * .-----------------------------------------------.
1161  * | Mixdown |
1162  * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1163  * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1164  * '-----------------------------------------------'
1165  * .-----------------------------------------------.
1166  * | Guitar SM58 |
1167  * | Disconnected |
1168  * '-----------------------------------------------'
1169  */
1170 
1171 void
1173 {
1174  uint32_t io_count;
1175  uint32_t io_index;
1177  vector<string> port_connections;
1178 
1179  uint32_t total_connection_count = 0;
1180  uint32_t io_connection_count = 0;
1181  uint32_t ardour_connection_count = 0;
1182  uint32_t system_connection_count = 0;
1183  uint32_t other_connection_count = 0;
1184 
1185  ostringstream label;
1186 
1187  bool have_label = false;
1188  bool each_io_has_one_connection = true;
1189 
1190  string connection_name;
1191  string ardour_track_name;
1192  string other_connection_type;
1193  string system_ports;
1194  string system_port;
1195 
1196  ostringstream tooltip;
1197  char * tooltip_cstr;
1198 
1199  //to avoid confusion, the button caption should only show connections that match the datatype of the track
1200  DataType dt = DataType::AUDIO;
1201  if ( boost::dynamic_pointer_cast<MidiTrack>(route) != 0 )
1202  dt = DataType::MIDI;
1203 
1204  if (for_input) {
1205  io_count = route->n_inputs().n_total();
1206  tooltip << string_compose (_("<b>INPUT</b> to %1"), Glib::Markup::escape_text(route->name()));
1207  } else {
1208  io_count = route->n_outputs().n_total();
1209  tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Glib::Markup::escape_text(route->name()));
1210  }
1211 
1212 
1213  for (io_index = 0; io_index < io_count; ++io_index) {
1214  if (for_input) {
1215  port = route->input()->nth (io_index);
1216  } else {
1217  port = route->output()->nth (io_index);
1218  }
1219 
1220  //ignore any port connections that don't match our DataType
1221  if (port->type() != dt)
1222  continue;
1223 
1224  port_connections.clear ();
1225  port->get_connections(port_connections);
1226  io_connection_count = 0;
1227 
1228  if (!port_connections.empty()) {
1229  for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1230  string pn = "";
1231  string& connection_name (*i);
1232 
1233  if (connection_name.find("system:") == 0) {
1234  pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1235  }
1236 
1237  if (io_connection_count == 0) {
1238  tooltip << endl << Glib::Markup::escape_text(port->name().substr(port->name().find("/") + 1))
1239  << " -> "
1240  << Glib::Markup::escape_text( pn.empty() ? connection_name : pn );
1241  } else {
1242  tooltip << ", "
1243  << Glib::Markup::escape_text( pn.empty() ? connection_name : pn );
1244  }
1245 
1246  if (connection_name.find("ardour:") == 0) {
1247  if (ardour_track_name.empty()) {
1248  // "ardour:Master/in 1" -> "ardour:Master/"
1249  string::size_type slash = connection_name.find("/");
1250  if (slash != string::npos) {
1251  ardour_track_name = connection_name.substr(0, slash + 1);
1252  }
1253  }
1254 
1255  if (connection_name.find(ardour_track_name) == 0) {
1256  ++ardour_connection_count;
1257  }
1258  } else if (!pn.empty()) {
1259  if (system_ports.empty()) {
1260  system_ports += pn;
1261  } else {
1262  system_ports += "/" + pn;
1263  }
1264  if (connection_name.find("system:") == 0) {
1265  ++system_connection_count;
1266  }
1267  } else if (connection_name.find("system:midi_") == 0) {
1268  if (for_input) {
1269  // "system:midi_capture_123" -> "123"
1270  system_port = "M " + connection_name.substr(20);
1271  } else {
1272  // "system:midi_playback_123" -> "123"
1273  system_port = "M " + connection_name.substr(21);
1274  }
1275 
1276  if (system_ports.empty()) {
1277  system_ports += system_port;
1278  } else {
1279  system_ports += "/" + system_port;
1280  }
1281 
1282  ++system_connection_count;
1283 
1284  } else if (connection_name.find("system:") == 0) {
1285  if (for_input) {
1286  // "system:capture_123" -> "123"
1287  system_port = connection_name.substr(15);
1288  } else {
1289  // "system:playback_123" -> "123"
1290  system_port = connection_name.substr(16);
1291  }
1292 
1293  if (system_ports.empty()) {
1294  system_ports += system_port;
1295  } else {
1296  system_ports += "/" + system_port;
1297  }
1298 
1299  ++system_connection_count;
1300  } else {
1301  if (other_connection_type.empty()) {
1302  // "jamin:in 1" -> "jamin:"
1303  other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1304  }
1305 
1306  if (connection_name.find(other_connection_type) == 0) {
1307  ++other_connection_count;
1308  }
1309  }
1310 
1311  ++total_connection_count;
1312  ++io_connection_count;
1313  }
1314  }
1315 
1316  if (io_connection_count != 1) {
1317  each_io_has_one_connection = false;
1318  }
1319  }
1320 
1321  if (total_connection_count == 0) {
1322  tooltip << endl << _("Disconnected");
1323  }
1324 
1325  tooltip_cstr = new char[tooltip.str().size() + 1];
1326  strcpy(tooltip_cstr, tooltip.str().c_str());
1327 
1328  if (for_input) {
1329  ARDOUR_UI::instance()->set_tip (&input_button, tooltip_cstr, "");
1330  } else {
1331  ARDOUR_UI::instance()->set_tip (&output_button, tooltip_cstr, "");
1332  }
1333 
1334  if (each_io_has_one_connection) {
1335  if (total_connection_count == ardour_connection_count) {
1336  // all connections are to the same track in ardour
1337  // "ardour:Master/" -> "Master"
1338  string::size_type slash = ardour_track_name.find("/");
1339  if (slash != string::npos) {
1340  label << ardour_track_name.substr(7, slash - 7);
1341  have_label = true;
1342  }
1343  }
1344  else if (total_connection_count == system_connection_count) {
1345  // all connections are to system ports
1346  label << system_ports;
1347  have_label = true;
1348  }
1349  else if (total_connection_count == other_connection_count) {
1350  // all connections are to the same external program eg jamin
1351  // "jamin:" -> "jamin"
1352  label << other_connection_type.substr(0, other_connection_type.size() - 1);
1353  have_label = true;
1354  }
1355  }
1356 
1357  if (!have_label) {
1358  if (total_connection_count == 0) {
1359  // Disconnected
1360  label << "-";
1361  } else {
1362  // Odd configuration
1363  label << "*" << total_connection_count << "*";
1364  }
1365  }
1366 
1367  if (for_input) {
1368  input_button.set_text (label.str());
1369  } else {
1370  output_button.set_text (label.str());
1371  }
1372 }
1373 
1374 void
1376 {
1377  update_io_button (_route, _width, true);
1378  panners.setup_pan ();
1379 
1380  if (has_audio_outputs ()) {
1381  panners.show_all ();
1382  } else {
1383  panners.hide_all ();
1384  }
1385 
1386 }
1387 
1388 void
1390 {
1391  update_io_button (_route, _width, false);
1392  gpm.setup_meters ();
1393  panners.setup_pan ();
1394 
1395  if (has_audio_outputs ()) {
1396  panners.show_all ();
1397  } else {
1398  panners.hide_all ();
1399  }
1400 }
1401 
1402 void
1404 {
1405  gpm.update_meters ();
1406 }
1407 
1408 void
1410 {
1412 }
1413 
1414 void
1416 {
1417  Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1418 }
1419 
1420 void
1422 {
1423  boost::shared_ptr<Port> a = wa.lock ();
1424  boost::shared_ptr<Port> b = wb.lock ();
1425 
1426  if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1428  set_width_enum (_width, this);
1429  }
1430 
1431  if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1433  set_width_enum (_width, this);
1434  }
1435 }
1436 
1437 void
1439 {
1440  switch (_width) {
1441 
1442  case Wide:
1443  if (_route->comment().empty ()) {
1444  _comment_button.unset_bg (STATE_NORMAL);
1445  _comment_button.set_text (_("Comments"));
1446  } else {
1447  _comment_button.modify_bg (STATE_NORMAL, color ());
1448  _comment_button.set_text (_("*Comments*"));
1449  }
1450  break;
1451 
1452  case Narrow:
1453  if (_route->comment().empty ()) {
1454  _comment_button.unset_bg (STATE_NORMAL);
1455  _comment_button.set_text (_("Cmt"));
1456  } else {
1457  _comment_button.modify_bg (STATE_NORMAL, color ());
1458  _comment_button.set_text (_("*Cmt*"));
1459  }
1460  break;
1461  }
1462 
1464  _comment_button, _route->comment().empty() ? _("Click to Add/Edit Comments") : _route->comment()
1465  );
1466 
1467 }
1468 
1469 bool
1471 {
1472  using namespace Menu_Helpers;
1473 
1474  if (ev->button == 1) {
1475 
1476  if (group_menu == 0) {
1477 
1478  PropertyList* plist = new PropertyList();
1479 
1480  plist->add (Properties::gain, true);
1481  plist->add (Properties::mute, true);
1482  plist->add (Properties::solo, true);
1483 
1484  group_menu = new RouteGroupMenu (_session, plist);
1485  }
1486 
1487  WeakRouteList r;
1488  r.push_back (route ());
1489  group_menu->build (r);
1490  group_menu->menu()->popup (1, ev->time);
1491  }
1492 
1493  return true;
1494 }
1495 
1496 void
1498 {
1500 
1501  RouteGroup *rg = _route->route_group();
1502 
1503  if (rg) {
1505  } else {
1506  switch (_width) {
1507  case Wide:
1508  group_button.set_text (_("Grp"));
1509  break;
1510  case Narrow:
1511  group_button.set_text (_("~G"));
1512  break;
1513  }
1514  }
1515 }
1516 
1517 void
1519 {
1520  name_button.modify_bg (STATE_NORMAL, color());
1522  reset_strip_style ();
1523 }
1524 
1525 void
1527 {
1528  reset_strip_style ();
1529 }
1530 
1531 void
1533 {
1534  using namespace Menu_Helpers;
1535  route_ops_menu = new Menu;
1536  route_ops_menu->set_name ("ArdourContextMenu");
1537 
1538  MenuList& items = route_ops_menu->items();
1539 
1540  items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1541 
1542  items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1543 
1544  items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1545 
1546  items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1547 
1548  items.push_back (SeparatorElem());
1549 
1550  if (!_route->is_master()) {
1551  items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1552  }
1553  items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1554  rename_menu_item = &items.back();
1555 
1556  items.push_back (SeparatorElem());
1557  items.push_back (CheckMenuElem (_("Active")));
1558  Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1559  i->set_active (_route->active());
1560  i->set_sensitive(! _session->transport_rolling());
1561  i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1562 
1563  items.push_back (SeparatorElem());
1564 
1565  items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1566 
1567  items.push_back (SeparatorElem());
1568  items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1569  denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1571 
1572  if (!Profile->get_sae()) {
1573  items.push_back (SeparatorElem());
1574  items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
1575  }
1576 
1577  items.push_back (SeparatorElem());
1578 
1579  if (_route) {
1580  /* note that this relies on selection being shared across editor and
1581  mixer (or global to the backend, in the future), which is the only
1582  sane thing for users anyway.
1583  */
1584 
1586  if (rtav) {
1587  Selection& selection (PublicEditor::instance().get_selection());
1588  if (!selection.selected (rtav)) {
1589  selection.set (rtav);
1590  }
1591 
1592  items.push_front (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1593  }
1594  }
1595 }
1596 
1597 gboolean
1599 {
1600  if (ev->button == 3) {
1602 
1603  /* do not allow rename if the track is record-enabled */
1604  rename_menu_item->set_sensitive (!_route->record_enabled());
1605  route_ops_menu->popup (1, ev->time);
1606 
1607  return true;
1608  }
1609 
1610  return false;
1611 }
1612 
1613 gboolean
1615 {
1616  if (ev->button == 1) {
1618 
1619  /* do not allow rename if the track is record-enabled */
1620  rename_menu_item->set_sensitive (!_route->record_enabled());
1621  route_ops_menu->popup (1, ev->time);
1622  }
1623 
1624  return false;
1625 }
1626 
1627 gboolean
1629 {
1630  if ( ev->button == 3 ) {
1632 
1633  /* do not allow rename if the track is record-enabled */
1634  rename_menu_item->set_sensitive (!_route->record_enabled());
1635  route_ops_menu->popup (1, ev->time);
1636 
1637  return true;
1638  }
1639 
1640  return false;
1641 }
1642 
1643 void
1645 {
1646  delete route_ops_menu;
1648 }
1649 
1650 void
1652 {
1654  if (_selected) {
1655  global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1656  global_frame.set_name ("MixerStripSelectedFrame");
1657  } else {
1658  global_frame.set_shadow_type (Gtk::SHADOW_IN);
1659  global_frame.set_name ("MixerStripFrame");
1660  }
1661  global_frame.queue_draw ();
1662 
1663 // if (!yn)
1664 // processor_box.deselect_all_processors();
1665 }
1666 
1667 void
1669 {
1670  RouteUI::property_changed (what_changed);
1671 
1672  if (what_changed.contains (ARDOUR::Properties::name)) {
1673  name_changed ();
1674  }
1675 }
1676 
1677 void
1679 {
1680  switch (_width) {
1681  case Wide:
1683  break;
1684  case Narrow:
1686  break;
1687  }
1688 
1690 
1691  if (_session->config.get_track_name_number()) {
1692  const int64_t track_number = _route->track_number ();
1693  if (track_number == 0) {
1694  number_label.set_text ("-");
1695  } else {
1696  number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1697  }
1698  } else {
1699  number_label.set_text ("");
1700  }
1701 }
1702 
1703 void
1704 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1705 {
1706  input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1707 }
1708 
1709 void
1710 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1711 {
1712  output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1713 }
1714 
1715 void
1716 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1717 {
1718  name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1719 }
1720 
1721 bool
1723 {
1724  if (ev->button != 1) {
1725  return false;
1726  }
1727 
1728  if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1729  switch (_width) {
1730  case Wide:
1731  _mixer.set_strip_width (Narrow, true);
1732  break;
1733 
1734  case Narrow:
1735  _mixer.set_strip_width (Wide, true);
1736  break;
1737  }
1738  } else {
1739  switch (_width) {
1740  case Wide:
1741  set_width_enum (Narrow, this);
1742  break;
1743  case Narrow:
1744  set_width_enum (Wide, this);
1745  break;
1746  }
1747  }
1748 
1749  return true;
1750 }
1751 
1752 void
1754 {
1755  // LAME fix to reset the button status for when it is redisplayed (part 1)
1756  hide_button.set_sensitive(false);
1757 
1758  if (_embedded) {
1759  Hiding(); /* EMIT_SIGNAL */
1760  } else {
1761  _mixer.hide_strip (this);
1762  }
1763 
1764  // (part 2)
1765  hide_button.set_sensitive(true);
1766 }
1767 
1768 void
1770 {
1771  _embedded = yn;
1772 }
1773 
1774 void
1776 {
1778 
1780 
1781  if (at) {
1782  switch (at->freeze_state()) {
1783  case AudioTrack::Frozen:
1784  processor_box.set_sensitive (false);
1786  break;
1787  default:
1788  processor_box.set_sensitive (true);
1789  // XXX need some way, maybe, to retoggle redirect editors
1790  break;
1791  }
1792  }
1793 }
1794 
1795 void
1797 {
1798  _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1799 }
1800 
1801 void
1803 {
1804  boost::shared_ptr<Processor> processor (p.lock ());
1805  if (!processor) {
1806  return;
1807  }
1808 
1809  Gtk::Window* w = processor_box.get_processor_ui (processor);
1810 
1811  if (w) {
1812  w->hide ();
1813  }
1814 }
1815 
1816 void
1818 {
1819  if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1820 
1821  gpm.set_fader_name ("SendStripBase");
1822 
1823  } else {
1824 
1825  if (is_midi_track()) {
1826  if (_route->active()) {
1827  set_name ("MidiTrackStripBase");
1828  } else {
1829  set_name ("MidiTrackStripBaseInactive");
1830  }
1831  gpm.set_fader_name ("MidiTrackFader");
1832  } else if (is_audio_track()) {
1833  if (_route->active()) {
1834  set_name ("AudioTrackStripBase");
1835  } else {
1836  set_name ("AudioTrackStripBaseInactive");
1837  }
1838  gpm.set_fader_name ("AudioTrackFader");
1839  } else {
1840  if (_route->active()) {
1841  set_name ("AudioBusStripBase");
1842  } else {
1843  set_name ("AudioBusStripBaseInactive");
1844  }
1845  gpm.set_fader_name ("AudioBusFader");
1846 
1847  /* (no MIDI busses yet) */
1848  }
1849  }
1850 }
1851 
1852 
1853 void
1855 {
1856 }
1857 
1858 void
1860 {
1861 }
1862 
1863 string
1865 {
1866  switch (_width) {
1867  case Wide:
1868  switch (mp) {
1869  case MeterInput:
1870  return _("In");
1871  break;
1872 
1873  case MeterPreFader:
1874  return _("Pre");
1875  break;
1876 
1877  case MeterPostFader:
1878  return _("Post");
1879  break;
1880 
1881  case MeterOutput:
1882  return _("Out");
1883  break;
1884 
1885  case MeterCustom:
1886  default:
1887  return _("Custom");
1888  break;
1889  }
1890  break;
1891  case Narrow:
1892  switch (mp) {
1893  case MeterInput:
1894  return S_("Meter|In");
1895  break;
1896 
1897  case MeterPreFader:
1898  return S_("Meter|Pr");
1899  break;
1900 
1901  case MeterPostFader:
1902  return S_("Meter|Po");
1903  break;
1904 
1905  case MeterOutput:
1906  return S_("Meter|O");
1907  break;
1908 
1909  case MeterCustom:
1910  default:
1911  return S_("Meter|C");
1912  break;
1913  }
1914  break;
1915  }
1916 
1917  return string();
1918 }
1919 
1921 void
1923 {
1925  gpm.setup_meters ();
1926  // reset peak when meter point changes
1928 }
1929 
1933 void
1935 {
1937 
1938  if (send_to) {
1940 
1941  if (send) {
1942  show_send (send);
1943  } else {
1945  }
1946  } else {
1948  }
1949 }
1950 
1951 void
1953 {
1954  boost::shared_ptr<Send> current_send;
1955 
1956  if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
1957  current_send->set_metering (false);
1958  }
1959 
1961  input_button.set_sensitive (true);
1962  output_button.set_sensitive (true);
1963  group_button.set_sensitive (true);
1964  set_invert_sensitive (true);
1965  meter_point_button.set_sensitive (true);
1966  mute_button->set_sensitive (true);
1967  solo_button->set_sensitive (true);
1968  rec_enable_button->set_sensitive (true);
1969  solo_isolated_led->set_sensitive (true);
1970  solo_safe_led->set_sensitive (true);
1971  monitor_input_button->set_sensitive (true);
1972  monitor_disk_button->set_sensitive (true);
1973  _comment_button.set_sensitive (true);
1974 }
1975 
1976 void
1978 {
1979  _current_delivery = d;
1981 }
1982 
1983 void
1985 {
1986  assert (send != 0);
1987 
1988  drop_send ();
1989 
1990  set_current_delivery (send);
1991 
1992  send->meter()->set_type(_route->shared_peak_meter()->get_type());
1993  send->set_metering (true);
1995 
1996  gain_meter().set_controls (_route, send->meter(), send->amp());
1997  gain_meter().setup_meters ();
1998 
1999  uint32_t const in = _current_delivery->pans_required();
2000  uint32_t const out = _current_delivery->pan_outs();
2001 
2003  panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2004  panner_ui().setup_pan ();
2006  panner_ui().show_all ();
2007 
2008  input_button.set_sensitive (false);
2009  group_button.set_sensitive (false);
2010  set_invert_sensitive (false);
2011  meter_point_button.set_sensitive (false);
2012  mute_button->set_sensitive (false);
2013  solo_button->set_sensitive (false);
2014  rec_enable_button->set_sensitive (false);
2015  solo_isolated_led->set_sensitive (false);
2016  solo_safe_led->set_sensitive (false);
2017  monitor_input_button->set_sensitive (false);
2018  monitor_disk_button->set_sensitive (false);
2019  _comment_button.set_sensitive (false);
2020 
2021  if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2022  output_button.set_sensitive (false);
2023  }
2024 
2025  reset_strip_style ();
2026 }
2027 
2028 void
2030 {
2031  drop_send ();
2032 
2034 
2036  gain_meter().setup_meters ();
2037 
2038  panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2040  panner_ui().setup_pan ();
2041  panner_ui().set_send_drawing_mode (false);
2042 
2043  if (has_audio_outputs ()) {
2044  panners.show_all ();
2045  } else {
2046  panners.hide_all ();
2047  }
2048 
2049  reset_strip_style ();
2050 }
2051 
2052 void
2054 {
2055  switch (_width) {
2056  case Wide:
2057  mute_button->set_text (_("Mute"));
2058  monitor_input_button->set_text (_("In"));
2059  monitor_disk_button->set_text (_("Disk"));
2060 
2061  if (_route && _route->solo_safe()) {
2063  } else {
2065  }
2066  if (!Config->get_solo_control_is_listen_control()) {
2067  solo_button->set_text (_("Solo"));
2068  } else {
2069  switch (Config->get_listen_position()) {
2070  case AfterFaderListen:
2071  solo_button->set_text (_("AFL"));
2072  break;
2073  case PreFaderListen:
2074  solo_button->set_text (_("PFL"));
2075  break;
2076  }
2077  }
2078  solo_isolated_led->set_text (_("Iso"));
2079  solo_safe_led->set_text (S_("SoloLock|Lock"));
2080  break;
2081 
2082  default:
2083  mute_button->set_text (S_("Mute|M"));
2084  monitor_input_button->set_text (S_("MonitorInput|I"));
2085  monitor_disk_button->set_text (S_("MonitorDisk|D"));
2086 
2087  if (_route && _route->solo_safe()) {
2089  } else {
2091  }
2092  if (!Config->get_solo_control_is_listen_control()) {
2093  solo_button->set_text (S_("Solo|S"));
2094  } else {
2095  switch (Config->get_listen_position()) {
2096  case AfterFaderListen:
2097  solo_button->set_text (S_("AfterFader|A"));
2098  break;
2099  case PreFaderListen:
2100  solo_button->set_text (S_("Prefader|P"));
2101  break;
2102  }
2103  }
2104 
2105  solo_isolated_led->set_text (S_("SoloIso|I"));
2106  solo_safe_led->set_text (S_("SoloLock|L"));
2107  break;
2108  }
2109 
2110  if (_route) {
2112  } else {
2114  }
2115 }
2116 
2119 {
2120  return _mixer.plugin_selector();
2121 }
2122 
2123 void
2125 {
2127 }
2128 
2129 bool
2131 {
2132  /* nothing happens on press */
2133  return true;
2134 }
2135 
2136 bool
2138 {
2140 
2141  if (!mt) {
2142  return true;
2143  }
2144 
2146 
2147  rl->push_back (route());
2148 
2150  Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2151 
2152  return true;
2153 }
2154 
2155 void
2157 {
2160  assert (mt);
2162  }
2163 }
2164 
2165 string
2167 {
2168  return string_compose ("strip %1", _route->id().to_s());
2169 }
2170 
2171 void
2173 {
2174  if (p == _visibility.get_state_name()) {
2175  /* The user has made changes to the mixer strip visibility, so get
2176  our VisibilityGroup to reflect these changes in our widgets.
2177  */
2178  _visibility.set_state (ARDOUR_UI::config()->get_mixer_strip_visibility ());
2179  }
2180  else if (p == "track-name-number") {
2181  name_changed ();
2182  }
2183 }
2184 
2190 boost::optional<bool>
2192 {
2193  if (_route && _route->is_master ()) {
2194  return boost::optional<bool> (false);
2195  }
2196 
2197  return boost::optional<bool> ();
2198 }
2199 
2200 void
2202 {
2203  _route->input()->add_port ("", this, t);
2204 }
2205 
2206 void
2208 {
2209  _route->output()->add_port ("", this, t);
2210 }
2211 
2212 void
2214 {
2215  reset_strip_style ();
2216 }
2217 
2218 void
2220 {
2222 }
2223 
2224 void
2226 {
2228 }
2229 
2230 void
2232 {
2234 }
2235 
2236 void
2238 {
2240 }
2241 
2242 void
2244 {
2246 }
2247 
2248 bool
2250 {
2252 }
2253 
2254 void
2256 {
2258 }
2259 
2260 void
2262 {
2264 }
2265 
2266 bool
2268 {
2269  if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2270  return false;
2271  }
2272  if (ev->button == 3) {
2274  return true;
2275  }
2276 
2277  return false;
2278 }
2279 
2280 void
2282 {
2283  using namespace Gtk::Menu_Helpers;
2284 
2285  Gtk::Menu* m = manage (new Menu);
2286  MenuList& items = m->items ();
2287 
2288  RadioMenuItem::Group group;
2289 
2290  _suspend_menu_callbacks = true;
2291  add_level_meter_item_point (items, group, _("Input"), MeterInput);
2292  add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2293  add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2294  add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2295  add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2296 
2297  if (gpm.meter_channels().n_audio() == 0) {
2298  m->popup (ev->button, ev->time);
2299  _suspend_menu_callbacks = false;
2300  return;
2301  }
2302 
2303  RadioMenuItem::Group tgroup;
2304  items.push_back (SeparatorElem());
2305 
2317 
2318  int _strip_type;
2319  if (_route->is_master()) {
2320  _strip_type = 4;
2321  }
2322  else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2324  /* non-master bus */
2325  _strip_type = 3;
2326  }
2327  else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2328  _strip_type = 2;
2329  }
2330  else {
2331  _strip_type = 1;
2332  }
2333 
2334  MeterType cmt = _route->meter_type();
2335  const std::string cmn = ArdourMeter::meter_type_string(cmt);
2336 
2337  items.push_back (SeparatorElem());
2338  items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2339  sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2340  items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2341  sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2342  items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2343  sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2344 
2345  m->popup (ev->button, ev->time);
2346  _suspend_menu_callbacks = false;
2347 }
2348 
2349 void
2350 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2351  RadioMenuItem::Group& group, string const & name, MeterPoint point)
2352 {
2353  using namespace Menu_Helpers;
2354 
2355  items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2356  RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2357  i->set_active (_route->meter_point() == point);
2358 }
2359 
2360 void
2362 {
2363  if (_suspend_menu_callbacks) return;
2364  _route->set_meter_point (p);
2365 }
2366 
2367 void
2368 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2369  RadioMenuItem::Group& group, string const & name, MeterType type)
2370 {
2371  using namespace Menu_Helpers;
2372 
2373  items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2374  RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2375  i->set_active (_route->meter_type() == type);
2376 }
2377 
2378 void
2380 {
2381  if (_suspend_menu_callbacks) return;
2382  gpm.set_type (t);
2383 }
void set_route_active(bool, bool)
Definition: route_ui.cc:1687
bool transport_rolling() const
Definition: session.h:592
bool level_meter_button_press(GdkEventButton *)
ArdourKnob trim_control
Definition: mixer_strip.h:206
virtual DataType type() const =0
PluginSelector * plugin_selector()
Definition: mixer_ui.cc:1843
Gdk::Color color() const
Definition: route_ui.cc:2138
void open_comment_editor()
Definition: route_ui.cc:1627
bool _suspend_menu_callbacks
Definition: mixer_strip.h:311
void panshell_changed()
Definition: panner_ui.cc:204
void hide_redirect_editors()
void select_all_processors()
GainMeter gpm
Definition: mixer_strip.h:170
Gtkmm2ext::FocusEntry peak_display
Definition: gain_meter.h:116
std::string to_string(T t, std::ios_base &(*f)(std::ios_base &))
Definition: convert.h:53
const ARDOUR::ChanCount meter_channels() const
Definition: gain_meter.cc:884
void set_tooltip_prefix(std::string pfx)
Definition: ardour_knob.h:77
void set_state(XMLNode const &)
std::string short_astyle_string(ARDOUR::AutoStyle)
Definition: panner_ui.cc:626
void update_output_display()
virtual void set_panner(boost::shared_ptr< ARDOUR::PannerShell >, boost::shared_ptr< ARDOUR::Panner >)
Definition: panner_ui.cc:92
std::string short_astyle_string(ARDOUR::AutoStyle)
Definition: gain_meter.cc:818
void * _width_owner
Definition: mixer_strip.h:155
void pan_automation_style_changed()
Definition: panner_ui.cc:537
ArdourButton gain_automation_state_button
Definition: gain_meter.h:126
void update_mute_display()
Definition: route_ui.cc:1228
boost::shared_ptr< ARDOUR::MidiTrack > midi_track() const
Definition: route_ui.cc:1762
bool get_sae() const
Definition: profile.h:48
Gtk::Table bottom_button_table
Definition: mixer_strip.h:178
Gtk::Menu * route_ops_menu
Definition: mixer_strip.h:251
void open_remote_control_id_dialog()
Definition: route_ui.cc:1900
std::string longest_label
Definition: mixer_strip.h:193
PluginSelector * plugin_selector()
PBD::Signal0< void > DropReferences
Definition: destructible.h:34
ArdourButton * show_sends_button
Definition: route_ui.h:103
void set_available_panners(std::map< std::string, std::string >)
Definition: panner_ui.cc:664
sigc::signal< void > signal_clicked
void bundle_input_chosen(boost::shared_ptr< ARDOUR::Bundle >)
Definition: mixer_strip.cc:990
void show_send(boost::shared_ptr< ARDOUR::Send >)
gint output_press(GdkEventButton *)
Definition: mixer_strip.cc:807
MeterPoint meter_point() const
Definition: route.h:187
PBD::Signal1< void, const PropertyChange & > PropertyChanged
Definition: stateful.h:87
boost::shared_ptr< Send > internal_send_for(boost::shared_ptr< const Route > target) const
Definition: route.cc:3934
bool is_midi_track() const
Definition: route_ui.cc:1756
Gtk::Table mute_solo_table
Definition: mixer_strip.h:177
PBD::Signal0< void > automation_style_changed
Definition: pannable.h:62
boost::shared_ptr< Amp > amp() const
Definition: route.h:194
ArdourButton gain_automation_style_button
Definition: gain_meter.h:125
std::string gui_property(const std::string &property_name) const
Definition: axis_view.cc:67
bool processor_operation(ProcessorOperation)
Width _width
Definition: mixer_strip.h:154
void reset_strip_style()
bool writable() const
Definition: session.h:173
void update_io_button(boost::shared_ptr< ARDOUR::Route > route, Width width, bool input_button)
void hide_strip(MixerStrip *)
Definition: mixer_ui.cc:883
Gtk::HBox _invert_button_box
Definition: route_ui.h:99
void name_button_resized(Gtk::Allocation &)
void choose_color()
Definition: route_ui.cc:1479
bool is_audio_track() const
Definition: route_ui.cc:1744
#define enum_2_string(e)
Definition: enumwriter.h:97
uint32_t pans_required() const
Definition: delivery.h:103
ArdourButton _comment_button
Definition: mixer_strip.h:204
PBD::ScopedConnection _level_meter_connection
Definition: mixer_strip.h:318
ArdourButton input_button
Definition: mixer_strip.h:184
void midi_input_status_changed()
ArdourButton number_label
Definition: mixer_strip.h:159
PBD::Signal0< void > FreezeChange
Definition: track.h:164
bool actively_recording() const
Definition: session.h:280
bool has_audio_outputs() const
Definition: route_ui.cc:1768
std::string astate_string(ARDOUR::AutoState)
Definition: panner_ui.cc:585
GainMeter & gain_meter()
Definition: mixer_strip.h:88
void edit_input_configuration()
Definition: route_ui.cc:486
Definition: ardour_ui.h:130
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
void route_rename()
Definition: route_ui.cc:1558
LIBARDOUR_API PBD::PropertyDescriptor< std::string > name
Gtk::ToggleButton pan_automation_state_button
Definition: panner_ui.h:125
Gtk::Table solo_iso_table
Definition: mixer_strip.h:176
PBD::Signal0< void > meter_change
Definition: route.h:315
virtual void bus_send_display_changed(boost::shared_ptr< ARDOUR::Route >)
void set_fader_name(const char *name)
Definition: gain_meter.cc:583
void revert_to_default_display()
boost::shared_ptr< Pannable > pannable() const
Definition: route.cc:4023
void copy_processors()
Lists of selected things.
Definition: selection.h:66
bool solo_safe() const
Definition: route.cc:804
PBD::Signal1< void, void * > comment_changed
Definition: route.h:292
bool ports_are_outputs() const
Definition: bundle.h:115
void set_exclusive_input_active(boost::shared_ptr< RouteList > rt, bool onoff, bool flip_others=false)
Definition: session.cc:3244
boost::shared_ptr< AutomationControl > gain_control() const
Definition: route.cc:4042
PBD::Signal0< void > io_changed
Definition: route.h:320
uint32_t n_audio() const
Definition: chan_count.h:63
bool mixer_strip_leave_event(GdkEventCrossing *)
Definition: mixer_strip.cc:421
gboolean number_button_button_press(GdkEventButton *)
tuple f
Definition: signals.py:35
Gtkmm2ext::FocusEntry gain_display
Definition: gain_meter.h:115
void set(std::list< Selectable * > const &)
Definition: selection.cc:1024
virtual void set_route(boost::shared_ptr< ARDOUR::Route >)
Definition: route_ui.cc:226
Definition: Beats.hpp:239
std::string astyle_string(ARDOUR::AutoStyle)
Definition: panner_ui.cc:620
LIBARDOUR_API PBD::PropertyDescriptor< bool > gain
Definition: route_group.cc:44
sigc::signal< void > WidthChanged
Definition: mixer_strip.h:113
IOSelectorWindow * input_selector
Definition: route_ui.h:250
boost::shared_ptr< Panner > panner() const
Definition: route.cc:4029
void bundle_output_chosen(boost::shared_ptr< ARDOUR::Bundle >)
void set_width(Width)
std::string name() const
Definition: port.h:54
SessionConfiguration config
Definition: session.h:866
Gtk::Table rec_mon_table
Definition: mixer_strip.h:175
boost::shared_ptr< PeakMeter > shared_peak_meter() const
Definition: route.h:198
void route_color_changed()
void fast_update()
void popup_level_meter_menu(GdkEventButton *)
bool self_destruct
Definition: route_ui.h:254
void set_route(boost::shared_ptr< ARDOUR::Route >)
RouteGroupMenu * group_menu
Definition: mixer_strip.h:211
std::string astate_string(ARDOUR::AutoState)
Definition: gain_meter.cc:777
void set_invert_sensitive(bool)
Definition: route_ui.cc:2092
virtual void remove_tracks()=0
LIBPBD_API int replace_all(std::string &str, const std::string &target, const std::string &replacement)
Definition: strreplace.cc:24
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
void adjust_latency()
Definition: route_ui.cc:1799
void parameter_changed(std::string)
#define invalidator(x)
Definition: gui_thread.h:40
void set_elements(Element)
bool width_button_pressed(GdkEventButton *)
bool ignore_toggle
Definition: route_ui.h:94
void disconnect_output()
Definition: route_ui.cc:1726
ArdourButton width_button
Definition: mixer_strip.h:158
static UI * instance()
Definition: gtk_ui.h:119
void build(ARDOUR::WeakRouteList const &)
AutoStyle automation_style() const
gint meter_press(GdkEventButton *)
Definition: gain_meter.cc:625
gint input_press(GdkEventButton *)
Definition: mixer_strip.cc:905
void toggle_processors()
uint32_t n_total() const
Definition: chan_count.h:69
void save_as_template()
Definition: route_ui.cc:1805
boost::optional< bool > override_solo_visibility() const
void init()
Definition: mixer_strip.cc:138
void set_current_delivery(boost::shared_ptr< ARDOUR::Delivery >)
void setup_comment_button()
void property_changed(const PBD::PropertyChange &)
#define _(Text)
Definition: i18n.h:11
void set_button_names()
void deselect_all_processors()
const std::string meter_type_string(ARDOUR::MeterType)
void show_passthru_color()
PBD::Signal1< void, AutoState > automation_state_changed
Definition: pannable.h:58
ArdourButton * rec_enable_button
Definition: route_ui.h:102
int64_t track_number() const
Definition: route.h:302
void set_route(boost::shared_ptr< ARDOUR::Route >)
Definition: mixer_strip.cc:440
boost::shared_ptr< ARDOUR::Route > _route
Definition: route_ui.h:87
void set_meter_point(ARDOUR::MeterPoint)
PBD::ScopedConnection send_gone_connection
Definition: mixer_strip.h:286
void diskstream_changed()
void set_metering(bool yn)
Definition: send.h:50
void connect_to_pan()
std::string comment()
Definition: route.h:100
virtual bool record_enabled() const
Definition: route.h:131
Gtk::Menu output_menu
Definition: mixer_strip.h:223
virtual uint32_t pan_outs() const
Definition: delivery.cc:385
void set_embedded(bool)
bool denormal_protection() const
Definition: route.cc:3996
uint32_t gdk_color_to_rgba(Gdk::Color const &)
Definition: utils.cc:285
ArdourButton * solo_button
Definition: route_ui.h:101
void hide_processor_editor(boost::weak_ptr< ARDOUR::Processor > processor)
#define X_(Text)
Definition: i18n.h:13
ArdourButton meter_point_button
Definition: mixer_strip.h:180
gint meter_release(GdkEventButton *)
Definition: gain_meter.cc:688
PBD::Signal0< void > route_group_changed
PBD::Signal0< void > InputActiveChanged
Definition: midi_track.h:135
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
#define string_2_enum(str, e)
Definition: enumwriter.h:98
void comment_changed(void *src)
Definition: route_ui.cc:1660
void set_icon(Icon)
std::string astyle_string(ARDOUR::AutoStyle)
Definition: gain_meter.cc:812
std::vector< boost::shared_ptr< Bundle > > BundleList
Definition: types.h:535
void add_level_meter_item_point(Gtk::Menu_Helpers::MenuList &, Gtk::RadioMenuItem::Group &, std::string const &, ARDOUR::MeterPoint)
bool input_active_button_release(GdkEventButton *)
void set_controllable(boost::shared_ptr< PBD::Controllable > c)
Definition: ardour_knob.cc:455
boost::shared_ptr< PeakMeter > meter() const
Definition: send.h:47
void meter_changed()
void engine_running()
Gtkmm2ext::VisualState visual_state() const
Definition: cairo_widget.h:41
boost::shared_ptr< ARDOUR::Panner > _panner
Definition: panner_ui.h:92
void setup_pan()
Definition: panner_ui.cc:211
MixerStrip(Mixer_UI &, ARDOUR::Session *, boost::shared_ptr< ARDOUR::Route >, bool in_mixer=true)
Definition: mixer_strip.cc:114
void set_meter_type(ARDOUR::MeterType)
void set_meter_point(MeterPoint, bool force=false)
Definition: route.cc:3436
MeterType
Definition: types.h:182
ArdourButton * monitor_input_button
Definition: route_ui.h:104
AutoState automation_state() const
boost::shared_ptr< Delivery > main_outs() const
Definition: route.h:237
Definition: amp.h:29
void toggle_comment_editor()
Definition: route_ui.cc:1612
bool ports_are_inputs() const
Definition: bundle.h:114
void set_fixed_colors(const uint32_t active_color, const uint32_t inactive_color)
virtual void set_controls(boost::shared_ptr< ARDOUR::Route > route, boost::shared_ptr< ARDOUR::PeakMeter > meter, boost::shared_ptr< ARDOUR::Amp > amp)
Definition: gain_meter.cc:1009
const PBD::ID & id() const
Definition: stateful.h:68
Gtk::Frame global_frame
Definition: mixer_strip.h:166
std::string to_s() const
Definition: id.cc:78
boost::shared_ptr< BundleList > bundles()
Definition: session.h:241
void set_visual_state(Gtkmm2ext::VisualState)
ChanCount n_outputs() const
Definition: route.h:93
#define gui_context()
Definition: gui_thread.h:36
boost::shared_ptr< ARDOUR::Delivery > _current_delivery
Definition: route_ui.h:124
ChanCount nchannels() const
Definition: bundle.cc:68
void route_group_changed()
void input_button_resized(Gtk::Allocation &)
void set_width(Width)
Definition: panner_ui.cc:187
void foreach_processor(boost::function< void(boost::weak_ptr< Processor >)> method)
Definition: route.h:203
ArdourButton output_button
Definition: mixer_strip.h:185
bool delete_processors()
LIBARDOUR_API PBD::PropertyDescriptor< bool > mute
Definition: route_group.cc:45
Glib::RefPtr< Gtk::SizeGroup > button_size_group
Definition: mixer_strip.h:173
bool _embedded
Definition: mixer_strip.h:151
boost::shared_ptr< RouteList > get_routes() const
Definition: session.h:229
void cut_processors()
sigc::signal< void, int, ARDOUR::RouteGroup *, ARDOUR::MeterType > SetMeterTypeMulti
void set_strip_width(Width, bool save=false)
Definition: mixer_ui.cc:1529
void maybe_add_bundle_to_input_menu(boost::shared_ptr< ARDOUR::Bundle >, ARDOUR::BundleList const &)
std::string name() const
Definition: route_ui.cc:1774
void pan_automation_state_changed()
Definition: panner_ui.cc:552
std::string name() const
Definition: bundle.h:110
void add_input_port(ARDOUR::DataType)
std::string state_id() const
void set_layout_ellipsize_width(int w)
void set_packed(bool yn)
Definition: mixer_strip.cc:776
void map_frozen()
VisibilityGroup _visibility
Definition: mixer_strip.h:303
void output_button_resized(Gtk::Allocation &)
boost::shared_ptr< PannerShell > panner_shell() const
Definition: route.cc:4036
bool _packed
Definition: mixer_strip.h:152
PBD::ScopedConnectionList _config_connection
Definition: mixer_strip.h:306
ChanCount n_inputs() const
Definition: route.h:92
virtual RouteTimeAxisView * get_route_view_by_route_id(const PBD::ID &id) const =0
PBD::Signal0< void > Running
Definition: audioengine.h:187
void set_type(ARDOUR::MeterType)
Definition: gain_meter.cc:362
PBD::Signal1< void, std::string > ParameterChanged
Definition: configuration.h:44
LIBARDOUR_API PBD::PropertyDescriptor< bool > active
Definition: route_group.cc:43
void update_diskstream_display()
void build_route_ops_menu()
LIBARDOUR_API RuntimeProfile * Profile
Definition: globals.cc:120
void ab_plugins()
void set_fallthrough_to_parent(bool fall)
bool is_track() const
Definition: route_ui.cc:1732
void drop_send()
bool _selected
Definition: selectable.h:45
ArdourButton hide_button
Definition: mixer_strip.h:157
void show_gain()
Definition: gain_meter.cc:498
PBD::Signal1< bool, GdkEventButton * > LevelMeterButtonPress
Definition: gain_meter.h:97
void set_tip(Gtk::Widget &w, const gchar *tip)
gint input_release(GdkEventButton *)
Definition: mixer_strip.cc:888
bool solo_isolate_button_release(GdkEventButton *)
Definition: route_ui.cc:1412
ProcessorBox processor_box
Definition: mixer_strip.h:169
void call_slot(EventLoop::InvalidationRecord *, const boost::function< void()> &)
Definition: abstract_ui.cc:368
Mixer_UI & _mixer
Definition: mixer_strip.h:147
void add_output_port(ARDOUR::DataType)
Gtk::HBox input_button_box
Definition: mixer_strip.h:191
bool active() const
Definition: route.h:95
PBD::ScopedConnection panstate_connection
Definition: mixer_strip.h:240
bool selected(TimeAxisView *)
Definition: selection.cc:920
Gtk::MenuItem * rename_menu_item
Definition: mixer_strip.h:234
void port_connected_or_disconnected(boost::weak_ptr< ARDOUR::Port >, boost::weak_ptr< ARDOUR::Port >)
static PublicEditor & instance()
Insensitive
Definition: widget_state.h:23
PBD::ScopedConnection panstyle_connection
Definition: mixer_strip.h:241
bool operator()(boost::shared_ptr< Route > a, boost::shared_ptr< Route > b)
Definition: mixer_strip.cc:789
bool select_route_group(GdkEventButton *)
void add_level_meter_item_type(Gtk::Menu_Helpers::MenuList &, Gtk::RadioMenuItem::Group &, std::string const &, ARDOUR::MeterType)
#define PX_SCALE(px)
void toggle_denormal_protection()
Definition: route_ui.cc:1697
void set_text_ellipsize(Pango::EllipsizeMode)
class LIBPBD_API PropertyList
gboolean name_button_button_press(GdkEventButton *)
gboolean name_button_button_release(GdkEventButton *)
void name_changed()
Gtk::Menu * menu()
void setup_meters(int len=0)
Definition: gain_meter.cc:340
Gtk::VBox global_vpacker
Definition: mixer_strip.h:167
LIBARDOUR_API PBD::PropertyDescriptor< bool > solo
Definition: route_group.cc:46
void reset_peak_display()
Definition: gain_meter.cc:397
std::string short_astate_string(ARDOUR::AutoState)
Definition: panner_ui.cc:591
virtual void property_changed(const PBD::PropertyChange &)
Definition: route_ui.cc:1604
boost::shared_ptr< Amp > amp() const
Definition: send.h:46
bool is_master() const
Definition: route.h:111
void set_width_enum(Width, void *owner)
Definition: mixer_strip.cc:689
void update_panner_choices()
int get_connections(std::vector< std::string > &) const
Definition: port.cc:161
void set_active(bool)
void hide_clicked()
ArdourButton * mute_button
Definition: route_ui.h:100
Width
Definition: enums.h:25
RouteGroup * route_group() const
std::string name() const
static UIConfiguration * config()
Definition: ardour_ui.h:188
void add(Gtk::Widget *, std::string const &, std::string const &, bool visible=false, boost::function< boost::optional< bool >()>=0)
void set_text(const std::string &)
Gtk::HBox width_hide_box
Definition: mixer_strip.h:160
MeterType meter_type() const
Definition: route.h:190
PBD::Signal1< void, boost::weak_ptr< ARDOUR::Delivery > > DeliveryChanged
Definition: mixer_strip.h:116
bool mixer_strip_enter_event(GdkEventCrossing *)
Definition: mixer_strip.cc:409
std::list< boost::weak_ptr< Route > > WeakRouteList
Definition: types.h:533
void update_meters()
Definition: gain_meter.cc:890
bool input_active() const
Definition: midi_track.cc:820
Definition: debug.h:30
string short_version(string orig, string::size_type target_length)
Definition: convert.cc:76
void hide_things()
boost::shared_ptr< IO > input() const
Definition: route.h:89
void set_selected(bool yn)
uint32_t ModifierMask
Definition: keyboard.h:53
Gtk::Button pan_automation_style_button
Definition: panner_ui.h:124
void io_changed_proxy()
#define S_(Text)
Definition: i18n.h:18
void maybe_add_bundle_to_output_menu(boost::shared_ptr< ARDOUR::Bundle >, ARDOUR::BundleList const &)
void edit_output_configuration()
Definition: route_ui.cc:456
sigc::signal< void, std::string > ParameterChanged
Definition: ui_config.h:78
static MixerStrip * _entered_mixer_strip
Definition: mixer_strip.h:276
Gtk::EventBox * spacer
Definition: mixer_strip.h:161
FreezeState freeze_state() const
Definition: track.cc:175
bool contains(PropertyDescriptor< T > p) const
void set_gui_property(const std::string &property_name, const T &value)
Definition: axis_view.h:66
Gtk::TextView * comment_area
Definition: route_ui.h:249
boost::shared_ptr< IO > output() const
Definition: route.h:90
void set_alignment(const float, const float)
PBD::Signal0< void > Stopped
Definition: audioengine.h:188
void update_input_display()
void list_route_operations()
std::string meter_point_string(ARDOUR::MeterPoint)
static float ui_scale
Definition: ardour_ui.h:189
bool solo_safe_button_release(GdkEventButton *)
Definition: route_ui.cc:1449
boost::shared_ptr< ARDOUR::AudioTrack > audio_track() const
Definition: route_ui.cc:1750
ArdourButton name_button
Definition: mixer_strip.h:202
void route_active_changed()
ArdourButton * midi_input_enable_button
Definition: mixer_strip.h:190
void set_stuff_from_route()
Definition: mixer_strip.cc:678
virtual void set_selected(bool yn)
Definition: selectable.h:34
void set_width(Width, int len=0)
Definition: gain_meter.cc:915
Definition: enums.h:27
MeterPoint
Definition: types.h:174
PannerUI panners
Definition: mixer_strip.h:171
static Element led_default_elements
Definition: ardour_button.h:64
#define MISSING_INVALIDATOR
Definition: event_loop.h:86
void disconnect_input()
Definition: route_ui.cc:1720
gint output_release(GdkEventButton *)
Definition: mixer_strip.cc:795
int get_gm_width()
Definition: gain_meter.cc:1055
ArdourButton * solo_isolated_led
Definition: route_ui.h:110
std::list< boost::shared_ptr< Route > > RouteList
Definition: types.h:532
void paste_processors()
boost::shared_ptr< PannerShell > panner_shell() const
Definition: delivery.h:95
Gtk::Menu input_menu
Definition: mixer_strip.h:219
std::string short_astate_string(ARDOUR::AutoState)
Definition: gain_meter.cc:783
static PBD::Signal1< void, MixerStrip * > CatchDeletion
Definition: mixer_strip.h:118
Definition: enums.h:26
boost::shared_ptr< Panner > panner() const
Definition: delivery.cc:578
bool connected() const
Definition: audioengine.cc:919
PBD::ScopedConnectionList route_connections
Definition: route_ui.h:253
bool add(PropertyBase *prop)
ARDOUR::Session * _session
boost::shared_ptr< ARDOUR::Route > route() const
Definition: route_ui.h:76
ArdourButton group_button
Definition: mixer_strip.h:210
std::list< boost::shared_ptr< ARDOUR::Bundle > > output_menu_bundles
Definition: mixer_strip.h:224
ArdourButton * solo_safe_led
Definition: route_ui.h:109
bool has_same_ports(boost::shared_ptr< Bundle >) const
Definition: bundle.cc:501
AudioEngine & engine()
Definition: session.h:546
Gtk::CheckMenuItem * denormal_menu_item
Definition: route_ui.h:207
PannerUI & panner_ui()
Definition: mixer_strip.h:89
bool ignore_comment_edit
Definition: route_ui.h:244
bool _mixer_owned
Definition: mixer_strip.h:153
sigc::signal< void > Hiding
Definition: axis_view.h:56
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
std::list< boost::shared_ptr< ARDOUR::Bundle > > input_menu_bundles
Definition: mixer_strip.h:220
void set_send_drawing_mode(bool)
Definition: panner_ui.cc:330
void engine_stopped()
void update_solo_display()
Definition: route_ui.cc:1146
ArdourButton * monitor_disk_button
Definition: route_ui.h:105
Gtk::Window * get_processor_ui(boost::shared_ptr< ARDOUR::Processor >) const
std::string get_state_name() const
virtual void bus_send_display_changed(boost::shared_ptr< ARDOUR::Route >)
Definition: route_ui.cc:2159
bool input_active_button_press(GdkEventButton *)