somewhat illogical and temporary workaround to the problems with consolidate & bounce...
[ardour2.git] / gtk2_ardour / mixer_ui.cc
blob295e956060c63cb11fd3168ba95479c558cdc8da
1 /*
2 Copyright (C) 2000-2004 Paul Davis
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.
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.
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.
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
24 #include <algorithm>
25 #include <map>
26 #include <sigc++/bind.h>
28 #include <gtkmm/accelmap.h>
30 #include "pbd/convert.h"
31 #include "pbd/stacktrace.h"
32 #include <glibmm/thread.h>
34 #include <gtkmm2ext/gtk_ui.h>
35 #include <gtkmm2ext/utils.h>
36 #include <gtkmm2ext/tearoff.h>
37 #include <gtkmm2ext/window_title.h>
39 #include "ardour/audio_track.h"
40 #include "ardour/plugin_manager.h"
41 #include "ardour/route_group.h"
42 #include "ardour/session.h"
43 #include "ardour/session_route.h"
45 #include "keyboard.h"
46 #include "mixer_ui.h"
47 #include "mixer_strip.h"
48 #include "monitor_section.h"
49 #include "plugin_selector.h"
50 #include "ardour_ui.h"
51 #include "prompter.h"
52 #include "utils.h"
53 #include "actions.h"
54 #include "gui_thread.h"
55 #include "mixer_group_tabs.h"
57 #include "i18n.h"
59 using namespace ARDOUR;
60 using namespace PBD;
61 using namespace Gtk;
62 using namespace Glib;
63 using namespace Gtkmm2ext;
64 using namespace std;
66 using PBD::atoi;
68 Mixer_UI::Mixer_UI ()
69 : Window (Gtk::WINDOW_TOPLEVEL)
71 _strip_width = Config->get_default_narrow_ms() ? Narrow : Wide;
72 track_menu = 0;
73 _monitor_section = 0;
74 no_track_list_redisplay = false;
75 in_group_row_change = false;
76 _visible = false;
77 strip_redisplay_does_not_reset_order_keys = false;
78 strip_redisplay_does_not_sync_order_keys = false;
79 ignore_sync = false;
81 Route::SyncOrderKeys.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::sync_order_keys, this, _1), gui_context());
83 scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
84 scroller_base.set_name ("MixerWindow");
85 scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
86 // add as last item of strip packer
87 strip_packer.pack_end (scroller_base, true, true);
89 _group_tabs = new MixerGroupTabs (this);
90 VBox* b = manage (new VBox);
91 b->pack_start (*_group_tabs, PACK_SHRINK);
92 b->pack_start (strip_packer);
93 b->show_all ();
95 scroller.add (*b);
96 scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
98 setup_track_display ();
100 group_model = ListStore::create (group_columns);
101 group_display.set_model (group_model);
102 group_display.append_column (_("Group"), group_columns.text);
103 group_display.append_column (_("Show"), group_columns.visible);
104 group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
105 group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
106 group_display.get_column (0)->set_expand(true);
107 group_display.get_column (1)->set_expand(false);
108 group_display.set_name ("MixerGroupList");
109 group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
110 group_display.set_reorderable (true);
111 group_display.set_headers_visible (true);
112 group_display.set_rules_hint (true);
114 /* name is directly editable */
116 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
117 name_cell->property_editable() = true;
118 name_cell->signal_edited().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_name_edit));
120 /* use checkbox for the active column */
122 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (1));
123 active_cell->property_activatable() = true;
124 active_cell->property_radio() = false;
126 group_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_change));
127 /* We use this to notice drag-and-drop reorders of the group list */
128 group_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_deleted));
129 group_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::group_display_button_press), false);
131 group_display_scroller.add (group_display);
132 group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
134 HBox* route_group_display_button_box = manage (new HBox());
136 Button* route_group_add_button = manage (new Button ());
137 Button* route_group_remove_button = manage (new Button ());
139 Widget* w;
141 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
142 w->show();
143 route_group_add_button->add (*w);
145 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
146 w->show();
147 route_group_remove_button->add (*w);
149 route_group_display_button_box->set_homogeneous (true);
151 route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
152 route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
154 route_group_display_button_box->add (*route_group_add_button);
155 route_group_display_button_box->add (*route_group_remove_button);
157 group_display_vbox.pack_start (group_display_scroller, true, true);
158 group_display_vbox.pack_start (*route_group_display_button_box, false, false);
160 group_display_frame.set_name ("BaseFrame");
161 group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
162 group_display_frame.add (group_display_vbox);
164 rhs_pane1.pack1 (track_display_frame);
165 rhs_pane1.pack2 (group_display_frame);
167 list_vpacker.pack_start (rhs_pane1, true, true);
169 global_hpacker.pack_start (scroller, true, true);
170 #ifdef GTKOSX
171 /* current gtk-quartz has dirty updates on borders like this one */
172 global_hpacker.pack_start (out_packer, false, false, 0);
173 #else
174 global_hpacker.pack_start (out_packer, false, false, 12);
175 #endif
176 list_hpane.add1(list_vpacker);
177 list_hpane.add2(global_hpacker);
179 rhs_pane1.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
180 static_cast<Gtk::Paned*> (&rhs_pane1)));
181 list_hpane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
182 static_cast<Gtk::Paned*> (&list_hpane)));
184 global_vpacker.pack_start (list_hpane, true, true);
186 add (global_vpacker);
187 set_name ("MixerWindow");
189 WindowTitle title(Glib::get_application_name());
190 title += _("Mixer");
191 set_title (title.get_string());
193 set_wmclass (X_("ardour_mixer"), PROGRAM_NAME);
195 add_accel_group (ActionManager::ui_manager->get_accel_group());
197 signal_delete_event().connect (sigc::mem_fun (*this, &Mixer_UI::hide_window));
198 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
200 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
202 _selection.RoutesChanged.connect (sigc::mem_fun(*this, &Mixer_UI::follow_strip_selection));
204 route_group_display_button_box->show();
205 route_group_add_button->show();
206 route_group_remove_button->show();
208 global_hpacker.show();
209 global_vpacker.show();
210 scroller.show();
211 scroller_base.show();
212 scroller_hpacker.show();
213 mixer_scroller_vpacker.show();
214 list_vpacker.show();
215 group_display_button_label.show();
216 group_display_button.show();
217 group_display_scroller.show();
218 group_display_vbox.show();
219 group_display_frame.show();
220 rhs_pane1.show();
221 strip_packer.show();
222 out_packer.show();
223 list_hpane.show();
224 group_display.show();
226 auto_rebinding = FALSE;
228 _in_group_rebuild_or_clear = false;
230 MixerStrip::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::remove_strip, this, _1), gui_context());
232 MonitorSection::setup_knob_images ();
234 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
235 _plugin_selector = new PluginSelector (PluginManager::the_manager ());
236 #endif
239 Mixer_UI::~Mixer_UI ()
243 void
244 Mixer_UI::ensure_float (Window& win)
246 win.set_transient_for (*this);
249 void
250 Mixer_UI::show_window ()
252 present ();
253 if (!_visible) {
254 set_window_pos_and_size ();
256 /* show/hide group tabs as required */
257 parameter_changed ("show-group-tabs");
259 /* now reset each strips width so the right widgets are shown */
260 MixerStrip* ms;
262 TreeModel::Children rows = track_model->children();
263 TreeModel::Children::iterator ri;
265 for (ri = rows.begin(); ri != rows.end(); ++ri) {
266 ms = (*ri)[track_columns.strip];
267 ms->set_width_enum (ms->get_width_enum (), ms->width_owner());
270 _visible = true;
273 bool
274 Mixer_UI::hide_window (GdkEventAny *ev)
276 get_window_pos_and_size ();
278 _visible = false;
279 return just_hide_it(ev, static_cast<Gtk::Window *>(this));
283 void
284 Mixer_UI::add_strip (RouteList& routes)
286 ENSURE_GUI_THREAD (*this, &Mixer_UI::add_strip, routes)
288 MixerStrip* strip;
290 no_track_list_redisplay = true;
291 strip_redisplay_does_not_sync_order_keys = true;
293 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
294 boost::shared_ptr<Route> route = (*x);
296 if (route->is_hidden()) {
297 continue;
300 if (route->is_monitor()) {
301 if (!_monitor_section) {
302 _monitor_section = new MonitorSection (_session);
303 out_packer.pack_end (_monitor_section->tearoff(), false, false);
304 } else {
305 _monitor_section->set_session (_session);
308 _monitor_section->tearoff().show_all ();
310 XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
311 if (mnode) {
312 _monitor_section->tearoff().set_state (*mnode);
315 /* no regular strip shown for control out */
317 continue;
320 strip = new MixerStrip (*this, _session, route);
321 strips.push_back (strip);
323 Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
325 if (strip->width_owner() != strip) {
326 strip->set_width_enum (_strip_width, this);
329 show_strip (strip);
331 TreeModel::Row row = *(track_model->append());
332 row[track_columns.text] = route->name();
333 row[track_columns.visible] = strip->marked_for_display();
334 row[track_columns.route] = route;
335 row[track_columns.strip] = strip;
337 if (route->order_key (N_("signal")) == -1) {
338 route->set_order_key (N_("signal"), track_model->children().size()-1);
341 route->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
343 strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
344 strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
347 no_track_list_redisplay = false;
349 redisplay_track_list ();
351 strip_redisplay_does_not_sync_order_keys = false;
354 void
355 Mixer_UI::remove_strip (MixerStrip* strip)
357 if (_session && _session->deletion_in_progress()) {
358 /* its all being taken care of */
359 return;
362 ENSURE_GUI_THREAD (*this, &Mixer_UI::remove_strip, strip);
364 cerr << "Mixer UI removing strip for " << strip << endl;
366 TreeModel::Children rows = track_model->children();
367 TreeModel::Children::iterator ri;
368 list<MixerStrip *>::iterator i;
370 if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
371 strips.erase (i);
374 strip_redisplay_does_not_sync_order_keys = true;
376 for (ri = rows.begin(); ri != rows.end(); ++ri) {
377 if ((*ri)[track_columns.strip] == strip) {
378 track_model->erase (ri);
379 break;
383 strip_redisplay_does_not_sync_order_keys = false;
386 void
387 Mixer_UI::sync_order_keys (string const & src)
389 TreeModel::Children rows = track_model->children();
390 TreeModel::Children::iterator ri;
392 if (src == N_("signal") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
393 return;
396 std::map<int,int> keys;
398 bool changed = false;
400 unsigned order = 0;
401 for (ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
402 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
403 unsigned int old_key = order;
404 unsigned int new_key = route->order_key (N_("signal"));
406 keys[new_key] = old_key;
408 if (new_key != old_key) {
409 changed = true;
413 if (keys.size() != rows.size()) {
414 PBD::stacktrace (cerr, 20);
416 assert(keys.size() == rows.size());
418 // Remove any gaps in keys caused by automation children tracks
419 vector<int> neworder;
420 for (std::map<int,int>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
421 neworder.push_back(i->second);
423 assert(neworder.size() == rows.size());
425 if (changed) {
426 strip_redisplay_does_not_reset_order_keys = true;
427 track_model->reorder (neworder);
428 strip_redisplay_does_not_reset_order_keys = false;
432 void
433 Mixer_UI::follow_strip_selection ()
435 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
436 (*i)->set_selected (_selection.selected ((*i)->route()));
440 bool
441 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
443 if (ev->button == 1) {
445 /* this allows the user to click on the strip to terminate comment
446 editing. XXX it needs improving so that we don't select the strip
447 at the same time.
450 if (_selection.selected (strip->route())) {
451 _selection.remove (strip->route());
452 } else {
453 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
454 _selection.add (strip->route());
455 } else {
456 _selection.set (strip->route());
461 return true;
464 void
465 Mixer_UI::set_session (Session* sess)
467 SessionHandlePtr::set_session (sess);
469 if (_plugin_selector) {
470 _plugin_selector->set_session (_session);
473 _group_tabs->set_session (sess);
475 if (!_session) {
476 return;
479 XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
480 set_state (*node);
482 WindowTitle title(_session->name());
483 title += _("Mixer");
484 title += Glib::get_application_name();
486 set_title (title.get_string());
488 initial_track_display ();
490 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Mixer_UI::add_strip, this, _1), gui_context());
491 _session->route_group_added.connect (_session_connections, invalidator (*this), ui_bind (&Mixer_UI::add_route_group, this, _1), gui_context());
492 _session->route_group_removed.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
493 _session->route_groups_reordered.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
494 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Mixer_UI::parameter_changed, this, _1), gui_context());
496 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
498 route_groups_changed ();
500 if (_visible) {
501 show_window();
504 start_updating ();
507 void
508 Mixer_UI::session_going_away ()
510 ENSURE_GUI_THREAD (*this, &Mixer_UI::session_going_away);
512 _in_group_rebuild_or_clear = true;
513 group_model->clear ();
514 _in_group_rebuild_or_clear = false;
516 _selection.clear ();
517 track_model->clear ();
519 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
520 delete (*i);
523 if (_monitor_section) {
524 _monitor_section->tearoff().hide_visible ();
527 strips.clear ();
529 WindowTitle title(Glib::get_application_name());
530 title += _("Mixer");
531 set_title (title.get_string());
533 stop_updating ();
535 SessionHandlePtr::session_going_away ();
538 void
539 Mixer_UI::show_strip (MixerStrip* ms)
541 TreeModel::Children rows = track_model->children();
542 TreeModel::Children::iterator i;
544 for (i = rows.begin(); i != rows.end(); ++i) {
546 MixerStrip* strip = (*i)[track_columns.strip];
547 if (strip == ms) {
548 (*i)[track_columns.visible] = true;
549 break;
554 void
555 Mixer_UI::hide_strip (MixerStrip* ms)
557 TreeModel::Children rows = track_model->children();
558 TreeModel::Children::iterator i;
560 for (i = rows.begin(); i != rows.end(); ++i) {
562 MixerStrip* strip = (*i)[track_columns.strip];
563 if (strip == ms) {
564 (*i)[track_columns.visible] = false;
565 break;
570 gint
571 Mixer_UI::start_updating ()
573 fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &Mixer_UI::fast_update_strips));
574 return 0;
577 gint
578 Mixer_UI::stop_updating ()
580 fast_screen_update_connection.disconnect();
581 return 0;
584 void
585 Mixer_UI::fast_update_strips ()
587 if (is_mapped () && _session) {
588 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
589 (*i)->fast_update ();
594 void
595 Mixer_UI::set_all_strips_visibility (bool yn)
597 TreeModel::Children rows = track_model->children();
598 TreeModel::Children::iterator i;
600 no_track_list_redisplay = true;
602 for (i = rows.begin(); i != rows.end(); ++i) {
604 TreeModel::Row row = (*i);
605 MixerStrip* strip = row[track_columns.strip];
607 if (strip == 0) {
608 continue;
611 if (strip->route()->is_master() || strip->route()->is_monitor()) {
612 continue;
615 (*i)[track_columns.visible] = yn;
618 no_track_list_redisplay = false;
619 redisplay_track_list ();
623 void
624 Mixer_UI::set_all_audio_visibility (int tracks, bool yn)
626 TreeModel::Children rows = track_model->children();
627 TreeModel::Children::iterator i;
629 no_track_list_redisplay = true;
631 for (i = rows.begin(); i != rows.end(); ++i) {
632 TreeModel::Row row = (*i);
633 MixerStrip* strip = row[track_columns.strip];
635 if (strip == 0) {
636 continue;
639 if (strip->route()->is_master() || strip->route()->is_monitor()) {
640 continue;
643 boost::shared_ptr<AudioTrack> at = strip->audio_track();
645 switch (tracks) {
646 case 0:
647 (*i)[track_columns.visible] = yn;
648 break;
650 case 1:
651 if (at) { /* track */
652 (*i)[track_columns.visible] = yn;
654 break;
656 case 2:
657 if (!at) { /* bus */
658 (*i)[track_columns.visible] = yn;
660 break;
664 no_track_list_redisplay = false;
665 redisplay_track_list ();
668 void
669 Mixer_UI::hide_all_routes ()
671 set_all_strips_visibility (false);
674 void
675 Mixer_UI::show_all_routes ()
677 set_all_strips_visibility (true);
680 void
681 Mixer_UI::show_all_audiobus ()
683 set_all_audio_visibility (2, true);
685 void
686 Mixer_UI::hide_all_audiobus ()
688 set_all_audio_visibility (2, false);
691 void
692 Mixer_UI::show_all_audiotracks()
694 set_all_audio_visibility (1, true);
696 void
697 Mixer_UI::hide_all_audiotracks ()
699 set_all_audio_visibility (1, false);
702 void
703 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
705 strip_redisplay_does_not_sync_order_keys = true;
706 _session->set_remote_control_ids();
707 redisplay_track_list ();
708 strip_redisplay_does_not_sync_order_keys = false;
711 void
712 Mixer_UI::track_list_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&)
714 // never reset order keys because of a property change
715 strip_redisplay_does_not_reset_order_keys = true;
716 _session->set_remote_control_ids();
717 redisplay_track_list ();
718 strip_redisplay_does_not_reset_order_keys = false;
721 void
722 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
724 /* this could require an order sync */
725 if (_session && !_session->deletion_in_progress()) {
726 _session->set_remote_control_ids();
727 redisplay_track_list ();
731 void
732 Mixer_UI::redisplay_track_list ()
734 TreeModel::Children rows = track_model->children();
735 TreeModel::Children::iterator i;
736 long order;
738 if (no_track_list_redisplay) {
739 return;
742 for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
743 MixerStrip* strip = (*i)[track_columns.strip];
745 if (strip == 0) {
746 /* we're in the middle of changing a row, don't worry */
747 continue;
750 bool visible = (*i)[track_columns.visible];
752 if (visible) {
753 strip->set_marked_for_display (true);
754 strip->route()->set_order_key (N_("signal"), order);
756 if (!strip_redisplay_does_not_reset_order_keys) {
757 strip->route()->set_order_key (N_("signal"), order);
760 if (strip->packed()) {
762 if (strip->route()->is_master() || strip->route()->is_monitor()) {
763 out_packer.reorder_child (*strip, -1);
764 } else {
765 strip_packer.reorder_child (*strip, -1); /* put at end */
768 } else {
770 if (strip->route()->is_master() || strip->route()->is_monitor()) {
771 out_packer.pack_start (*strip, false, false);
772 } else {
773 strip_packer.pack_start (*strip, false, false);
775 strip->set_packed (true);
776 //strip->show();
779 } else {
781 strip->set_marked_for_display (false);
783 if (strip->route()->is_master() || strip->route()->is_monitor()) {
784 /* do nothing, these cannot be hidden */
785 } else {
786 if (strip->packed()) {
787 strip_packer.remove (*strip);
788 strip->set_packed (false);
794 if (!strip_redisplay_does_not_reset_order_keys && !strip_redisplay_does_not_sync_order_keys) {
795 _session->sync_order_keys (N_("signal"));
798 // Resigc::bind all of the midi controls automatically
800 if (auto_rebinding)
801 auto_rebind_midi_controls ();
803 _group_tabs->set_dirty ();
806 void
807 Mixer_UI::strip_width_changed ()
809 _group_tabs->set_dirty ();
811 #ifdef GTKOSX
812 TreeModel::Children rows = track_model->children();
813 TreeModel::Children::iterator i;
814 long order;
816 for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
817 MixerStrip* strip = (*i)[track_columns.strip];
819 if (strip == 0) {
820 continue;
823 bool visible = (*i)[track_columns.visible];
825 if (visible) {
826 strip->queue_draw();
829 #endif
833 void
834 Mixer_UI::set_auto_rebinding( bool val )
836 if( val == TRUE )
838 auto_rebinding = TRUE;
839 Session::AutoBindingOff();
841 else
843 auto_rebinding = FALSE;
844 Session::AutoBindingOn();
848 void
849 Mixer_UI::toggle_auto_rebinding()
851 if (auto_rebinding)
853 set_auto_rebinding( FALSE );
856 else
858 set_auto_rebinding( TRUE );
861 auto_rebind_midi_controls();
864 void
865 Mixer_UI::auto_rebind_midi_controls ()
867 TreeModel::Children rows = track_model->children();
868 TreeModel::Children::iterator i;
869 int pos;
871 // Create bindings for all visible strips and remove those that are not visible
872 pos = 1; // 0 is reserved for the master strip
873 for (i = rows.begin(); i != rows.end(); ++i) {
874 MixerStrip* strip = (*i)[track_columns.strip];
876 if ( (*i)[track_columns.visible] == true ) { // add bindings for
877 // make the actual binding
878 //cout<<"Auto Binding: Visible Strip Found: "<<strip->name()<<endl;
880 int controlValue = pos;
881 if( strip->route()->is_master() ) {
882 controlValue = 0;
884 else {
885 pos++;
888 PBD::Controllable::CreateBinding ( strip->solo_button->get_controllable().get(), controlValue, 0);
889 PBD::Controllable::CreateBinding ( strip->mute_button->get_controllable().get(), controlValue, 1);
891 if( strip->is_audio_track() ) {
892 PBD::Controllable::CreateBinding ( strip->rec_enable_button->get_controllable().get(), controlValue, 2);
895 PBD::Controllable::CreateBinding ( strip->gpm.get_controllable().get(), controlValue, 3);
896 PBD::Controllable::CreateBinding ( strip->panners.get_controllable().get(), controlValue, 4);
899 else { // Remove any existing binding
900 PBD::Controllable::DeleteBinding ( strip->solo_button->get_controllable().get() );
901 PBD::Controllable::DeleteBinding ( strip->mute_button->get_controllable().get() );
903 if( strip->is_audio_track() ) {
904 PBD::Controllable::DeleteBinding ( strip->rec_enable_button->get_controllable().get() );
907 PBD::Controllable::DeleteBinding ( strip->gpm.get_controllable().get() );
908 PBD::Controllable::DeleteBinding ( strip->panners.get_controllable().get() ); // This only takes the first panner if there are multiples...
911 } // for
915 struct SignalOrderRouteSorter {
916 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
917 /* use of ">" forces the correct sort order */
918 return a->order_key (N_("signal")) < b->order_key (N_("signal"));
922 void
923 Mixer_UI::initial_track_display ()
925 boost::shared_ptr<RouteList> routes = _session->get_routes();
926 RouteList copy (*routes);
927 SignalOrderRouteSorter sorter;
929 copy.sort (sorter);
931 no_track_list_redisplay = true;
933 track_model->clear ();
935 add_strip (copy);
937 no_track_list_redisplay = false;
939 redisplay_track_list ();
942 void
943 Mixer_UI::show_track_list_menu ()
945 if (track_menu == 0) {
946 build_track_menu ();
949 track_menu->popup (1, gtk_get_current_event_time());
952 bool
953 Mixer_UI::track_display_button_press (GdkEventButton* ev)
955 if (Keyboard::is_context_menu_event (ev)) {
956 show_track_list_menu ();
957 return true;
960 TreeIter iter;
961 TreeModel::Path path;
962 TreeViewColumn* column;
963 int cellx;
964 int celly;
966 if (!track_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
967 return false;
970 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
971 case 0:
972 /* allow normal processing to occur */
973 return false;
975 case 1: /* visibility */
977 if ((iter = track_model->get_iter (path))) {
978 MixerStrip* strip = (*iter)[track_columns.strip];
979 if (strip) {
981 if (!strip->route()->is_master() && !strip->route()->is_monitor()) {
982 bool visible = (*iter)[track_columns.visible];
983 (*iter)[track_columns.visible] = !visible;
985 #ifdef GTKOSX
986 track_display.queue_draw();
987 #endif
990 return true;
992 default:
993 break;
996 return false;
1000 void
1001 Mixer_UI::build_track_menu ()
1003 using namespace Menu_Helpers;
1004 using namespace Gtk;
1006 track_menu = new Menu;
1007 track_menu->set_name ("ArdourContextMenu");
1008 MenuList& items = track_menu->items();
1010 items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1011 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1012 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1013 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1014 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1015 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1019 void
1020 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1022 if (!what_changed.contains (ARDOUR::Properties::name)) {
1023 return;
1026 ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1028 TreeModel::Children rows = track_model->children();
1029 TreeModel::Children::iterator i;
1031 for (i = rows.begin(); i != rows.end(); ++i) {
1032 if ((*i)[track_columns.strip] == mx) {
1033 (*i)[track_columns.text] = mx->route()->name();
1034 return;
1038 error << _("track display list item for renamed strip not found!") << endmsg;
1041 bool
1042 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1044 TreeModel::Path path;
1045 TreeViewColumn* column;
1046 int cellx;
1047 int celly;
1049 if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1050 return false;
1053 TreeIter iter = group_model->get_iter (path);
1054 if (!iter) {
1055 return false;
1058 RouteGroup* group = (*iter)[group_columns.group];
1060 if (Keyboard::is_context_menu_event (ev)) {
1061 _group_tabs->get_menu(group)->popup (1, ev->time);
1062 return true;
1065 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1066 case 0:
1067 if (Keyboard::is_edit_event (ev)) {
1068 if (group) {
1069 // edit_route_group (group);
1070 #ifdef GTKOSX
1071 group_display.queue_draw();
1072 #endif
1073 return true;
1076 break;
1078 case 1:
1080 bool visible = (*iter)[group_columns.visible];
1081 (*iter)[group_columns.visible] = !visible;
1082 #ifdef GTKOSX
1083 group_display.queue_draw();
1084 #endif
1085 return true;
1088 default:
1089 break;
1092 return false;
1095 void
1096 Mixer_UI::activate_all_route_groups ()
1098 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1101 void
1102 Mixer_UI::disable_all_route_groups ()
1104 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1107 void
1108 Mixer_UI::route_groups_changed ()
1110 ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed);
1112 _in_group_rebuild_or_clear = true;
1114 /* just rebuild the while thing */
1116 group_model->clear ();
1119 TreeModel::Row row;
1120 row = *(group_model->append());
1121 row[group_columns.visible] = true;
1122 row[group_columns.text] = (_("-all-"));
1123 row[group_columns.group] = 0;
1126 _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1128 _group_tabs->set_dirty ();
1129 _in_group_rebuild_or_clear = false;
1132 void
1133 Mixer_UI::new_route_group ()
1135 RouteList rl;
1137 _group_tabs->run_new_group_dialog (rl);
1140 void
1141 Mixer_UI::remove_selected_route_group ()
1143 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1144 TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1146 if (rows.empty()) {
1147 return;
1150 TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1151 TreeIter iter;
1153 /* selection mode is single, so rows.begin() is it */
1155 if ((iter = group_model->get_iter (*i))) {
1157 RouteGroup* rg = (*iter)[group_columns.group];
1159 if (rg) {
1160 _session->remove_route_group (*rg);
1165 void
1166 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1168 if (in_group_row_change) {
1169 return;
1172 /* force an update of any mixer strips that are using this group,
1173 otherwise mix group names don't change in mixer strips
1176 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1177 if ((*i)->route_group() == group) {
1178 (*i)->route_group_changed();
1182 TreeModel::iterator i;
1183 TreeModel::Children rows = group_model->children();
1184 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1186 in_group_row_change = true;
1188 for (i = rows.begin(); i != rows.end(); ++i) {
1189 if ((*i)[group_columns.group] == group) {
1190 (*i)[group_columns.visible] = !group->is_hidden ();
1191 (*i)[group_columns.text] = group->name ();
1192 break;
1196 in_group_row_change = false;
1198 if (change.contains (Properties::name)) {
1199 _group_tabs->set_dirty ();
1202 for (list<MixerStrip*>::iterator j = strips.begin(); j != strips.end(); ++j) {
1203 if ((*j)->route_group() == group) {
1204 if (group->is_hidden ()) {
1205 hide_strip (*j);
1206 } else {
1207 show_strip (*j);
1213 void
1214 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1216 RouteGroup* group;
1217 TreeIter iter;
1219 if ((iter = group_model->get_iter (path))) {
1221 if ((group = (*iter)[group_columns.group]) == 0) {
1222 return;
1225 if (new_text != group->name()) {
1226 group->set_name (new_text);
1231 void
1232 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1234 RouteGroup* group;
1236 if (in_group_row_change) {
1237 return;
1240 if ((group = (*iter)[group_columns.group]) == 0) {
1241 return;
1244 std::string name = (*iter)[group_columns.text];
1246 if (name != group->name()) {
1247 group->set_name (name);
1250 bool hidden = !(*iter)[group_columns.visible];
1252 if (hidden != group->is_hidden ()) {
1253 group->set_hidden (hidden, this);
1257 /** Called when a group model row is deleted, but also when the model is
1258 * reordered by a user drag-and-drop; the latter is what we are
1259 * interested in here.
1261 void
1262 Mixer_UI::route_group_row_deleted (Gtk::TreeModel::Path const &)
1264 if (_in_group_rebuild_or_clear) {
1265 return;
1268 /* Re-write the session's route group list so that the new order is preserved */
1270 list<RouteGroup*> new_list;
1272 Gtk::TreeModel::Children children = group_model->children();
1273 for (Gtk::TreeModel::Children::iterator i = children.begin(); i != children.end(); ++i) {
1274 RouteGroup* g = (*i)[group_columns.group];
1275 if (g) {
1276 new_list.push_back (g);
1280 _session->reorder_route_groups (new_list);
1284 void
1285 Mixer_UI::add_route_group (RouteGroup* group)
1287 ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1288 bool focus = false;
1290 in_group_row_change = true;
1292 TreeModel::Row row = *(group_model->append());
1293 row[group_columns.visible] = !group->is_hidden ();
1294 row[group_columns.group] = group;
1295 if (!group->name().empty()) {
1296 row[group_columns.text] = group->name();
1297 } else {
1298 row[group_columns.text] = _("unnamed");
1299 focus = true;
1302 group->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1304 if (focus) {
1305 TreeViewColumn* col = group_display.get_column (0);
1306 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1307 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1310 _group_tabs->set_dirty ();
1312 in_group_row_change = false;
1315 bool
1316 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1318 using namespace Menu_Helpers;
1320 if (Keyboard::is_context_menu_event (ev)) {
1321 ARDOUR_UI::instance()->add_route (this);
1322 return true;
1325 return false;
1328 void
1329 Mixer_UI::set_strip_width (Width w)
1331 _strip_width = w;
1333 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1334 (*i)->set_width_enum (w, this);
1338 void
1339 Mixer_UI::set_window_pos_and_size ()
1341 resize (m_width, m_height);
1342 move (m_root_x, m_root_y);
1345 void
1346 Mixer_UI::get_window_pos_and_size ()
1348 get_position(m_root_x, m_root_y);
1349 get_size(m_width, m_height);
1353 Mixer_UI::set_state (const XMLNode& node)
1355 const XMLProperty* prop;
1356 XMLNode* geometry;
1358 m_width = default_width;
1359 m_height = default_height;
1360 m_root_x = 1;
1361 m_root_y = 1;
1363 if ((geometry = find_named_node (node, "geometry")) != 0) {
1365 XMLProperty* prop;
1367 if ((prop = geometry->property("x_size")) == 0) {
1368 prop = geometry->property ("x-size");
1370 if (prop) {
1371 m_width = atoi(prop->value());
1373 if ((prop = geometry->property("y_size")) == 0) {
1374 prop = geometry->property ("y-size");
1376 if (prop) {
1377 m_height = atoi(prop->value());
1380 if ((prop = geometry->property ("x_pos")) == 0) {
1381 prop = geometry->property ("x-pos");
1383 if (prop) {
1384 m_root_x = atoi (prop->value());
1387 if ((prop = geometry->property ("y_pos")) == 0) {
1388 prop = geometry->property ("y-pos");
1390 if (prop) {
1391 m_root_y = atoi (prop->value());
1395 set_window_pos_and_size ();
1397 if ((prop = node.property ("narrow-strips"))) {
1398 if (string_is_affirmative (prop->value())) {
1399 set_strip_width (Narrow);
1400 } else {
1401 set_strip_width (Wide);
1405 if ((prop = node.property ("show-mixer"))) {
1406 if (string_is_affirmative (prop->value())) {
1407 _visible = true;
1411 return 0;
1414 XMLNode&
1415 Mixer_UI::get_state (void)
1417 XMLNode* node = new XMLNode ("Mixer");
1419 if (is_realized()) {
1420 Glib::RefPtr<Gdk::Window> win = get_window();
1422 get_window_pos_and_size ();
1424 XMLNode* geometry = new XMLNode ("geometry");
1425 char buf[32];
1426 snprintf(buf, sizeof(buf), "%d", m_width);
1427 geometry->add_property(X_("x_size"), string(buf));
1428 snprintf(buf, sizeof(buf), "%d", m_height);
1429 geometry->add_property(X_("y_size"), string(buf));
1430 snprintf(buf, sizeof(buf), "%d", m_root_x);
1431 geometry->add_property(X_("x_pos"), string(buf));
1432 snprintf(buf, sizeof(buf), "%d", m_root_y);
1433 geometry->add_property(X_("y_pos"), string(buf));
1435 // written only for compatibility, they are not used.
1436 snprintf(buf, sizeof(buf), "%d", 0);
1437 geometry->add_property(X_("x_off"), string(buf));
1438 snprintf(buf, sizeof(buf), "%d", 0);
1439 geometry->add_property(X_("y_off"), string(buf));
1441 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1442 geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1443 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1444 geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1446 node->add_child_nocopy (*geometry);
1449 node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1451 node->add_property ("show-mixer", _visible ? "yes" : "no");
1453 return *node;
1457 void
1458 Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
1460 int pos;
1461 XMLProperty* prop = 0;
1462 char buf[32];
1463 XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1464 XMLNode* geometry;
1465 int width, height;
1466 static int32_t done[3] = { 0, 0, 0 };
1468 width = default_width;
1469 height = default_height;
1471 if ((geometry = find_named_node (*node, "geometry")) != 0) {
1474 if ((prop = geometry->property ("x_size")) == 0) {
1475 prop = geometry->property ("x-size");
1477 if (prop) {
1478 width = atoi (prop->value());
1480 if ((prop = geometry->property ("y_size")) == 0) {
1481 prop = geometry->property ("y-size");
1483 if (prop) {
1484 height = atoi (prop->value());
1488 if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1490 if (done[0]) {
1491 return;
1494 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1495 pos = height / 3;
1496 snprintf (buf, sizeof(buf), "%d", pos);
1497 } else {
1498 pos = atoi (prop->value());
1501 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1502 rhs_pane1.set_position (pos);
1505 } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1507 if (done[2]) {
1508 return;
1511 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1512 pos = 75;
1513 snprintf (buf, sizeof(buf), "%d", pos);
1514 } else {
1515 pos = atoi (prop->value());
1518 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1519 list_hpane.set_position (pos);
1523 void
1524 Mixer_UI::scroll_left ()
1526 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1527 /* stupid GTK: can't rely on clamping across versions */
1528 scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
1531 void
1532 Mixer_UI::scroll_right ()
1534 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1535 /* stupid GTK: can't rely on clamping across versions */
1536 scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
1539 bool
1540 Mixer_UI::on_key_press_event (GdkEventKey* ev)
1542 switch (ev->keyval) {
1543 case GDK_Left:
1544 scroll_left ();
1545 return true;
1547 case GDK_Right:
1548 scroll_right ();
1549 return true;
1551 default:
1552 break;
1555 return key_press_focus_accelerator_handler (*this, ev);
1558 bool
1559 Mixer_UI::on_key_release_event (GdkEventKey* ev)
1561 return Gtk::Window::on_key_release_event (ev);
1562 // return key_press_focus_accelerator_handler (*this, ev);
1566 bool
1567 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
1569 switch (ev->direction) {
1570 case GDK_SCROLL_LEFT:
1571 scroll_left ();
1572 return true;
1573 case GDK_SCROLL_UP:
1574 if (ev->state & Keyboard::TertiaryModifier) {
1575 scroll_left ();
1576 return true;
1578 return false;
1580 case GDK_SCROLL_RIGHT:
1581 scroll_right ();
1582 return true;
1584 case GDK_SCROLL_DOWN:
1585 if (ev->state & Keyboard::TertiaryModifier) {
1586 scroll_right ();
1587 return true;
1589 return false;
1592 return false;
1596 void
1597 Mixer_UI::parameter_changed (string const & p)
1599 if (p == "show-group-tabs") {
1600 bool const s = _session->config.get_show_group_tabs ();
1601 if (s) {
1602 _group_tabs->show ();
1603 } else {
1604 _group_tabs->hide ();
1606 } else if (p == "default-narrow_ms") {
1607 bool const s = Config->get_default_narrow_ms ();
1608 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1609 (*i)->set_width_enum (s ? Narrow : Wide, this);
1614 void
1615 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
1617 g->set_active (a, this);
1620 PluginSelector*
1621 Mixer_UI::plugin_selector()
1623 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
1624 if (!_plugin_selector)
1625 _plugin_selector = new PluginSelector (PluginManager::the_manager ());
1626 #endif
1628 return _plugin_selector;
1631 void
1632 Mixer_UI::setup_track_display ()
1634 track_model = ListStore::create (track_columns);
1635 track_display.set_model (track_model);
1636 track_display.append_column (_("Strips"), track_columns.text);
1637 track_display.append_column (_("Show"), track_columns.visible);
1638 track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
1639 track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
1640 track_display.get_column (0)->set_expand(true);
1641 track_display.get_column (1)->set_expand(false);
1642 track_display.set_name (X_("MixerTrackDisplayList"));
1643 track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
1644 track_display.set_reorderable (true);
1645 track_display.set_headers_visible (true);
1647 track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
1648 track_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_change));
1649 track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
1651 CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
1652 track_list_visible_cell->property_activatable() = true;
1653 track_list_visible_cell->property_radio() = false;
1655 track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
1657 track_display_scroller.add (track_display);
1658 track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1660 VBox* v = manage (new VBox);
1661 v->show ();
1662 v->pack_start (track_display_scroller, true, true);
1664 Button* b = manage (new Button);
1665 b->show ();
1666 Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
1667 w->show ();
1668 b->add (*w);
1670 b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
1672 v->pack_start (*b, false, false);
1674 track_display_frame.set_name("BaseFrame");
1675 track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
1676 track_display_frame.add (*v);
1678 track_display_scroller.show();
1679 track_display_frame.show();
1680 track_display.show();
1683 void
1684 Mixer_UI::new_track_or_bus ()
1686 ARDOUR_UI::instance()->add_route (this);