change packing options within mixer window to fix #4271
[ardour2.git] / gtk2_ardour / mixer_ui.cc
blob644a51f880426e85864676d79988ed3288d6c51f
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.pack1(list_vpacker, true, true);
177 list_hpane.pack2(global_hpacker, true, false);
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->route()->is_master() ? true : 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 if (!strip_redisplay_does_not_reset_order_keys) {
751 strip->route()->set_order_key (N_("signal"), order);
754 bool const visible = (*i)[track_columns.visible];
756 if (visible) {
757 strip->set_gui_property ("visible", true);
759 if (strip->packed()) {
761 if (strip->route()->is_master() || strip->route()->is_monitor()) {
762 out_packer.reorder_child (*strip, -1);
763 } else {
764 strip_packer.reorder_child (*strip, -1); /* put at end */
767 } else {
769 if (strip->route()->is_master() || strip->route()->is_monitor()) {
770 out_packer.pack_start (*strip, false, false);
771 } else {
772 strip_packer.pack_start (*strip, false, false);
774 strip->set_packed (true);
777 } else {
779 strip->set_gui_property ("visible", false);
781 if (strip->route()->is_master() || strip->route()->is_monitor()) {
782 /* do nothing, these cannot be hidden */
783 } else {
784 if (strip->packed()) {
785 strip_packer.remove (*strip);
786 strip->set_packed (false);
792 if (!strip_redisplay_does_not_reset_order_keys && !strip_redisplay_does_not_sync_order_keys) {
793 _session->sync_order_keys (N_("signal"));
796 // Resigc::bind all of the midi controls automatically
798 if (auto_rebinding) {
799 auto_rebind_midi_controls ();
802 _group_tabs->set_dirty ();
805 void
806 Mixer_UI::strip_width_changed ()
808 _group_tabs->set_dirty ();
810 #ifdef GTKOSX
811 TreeModel::Children rows = track_model->children();
812 TreeModel::Children::iterator i;
813 long order;
815 for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
816 MixerStrip* strip = (*i)[track_columns.strip];
818 if (strip == 0) {
819 continue;
822 bool visible = (*i)[track_columns.visible];
824 if (visible) {
825 strip->queue_draw();
828 #endif
832 void
833 Mixer_UI::set_auto_rebinding( bool val )
835 if( val == TRUE )
837 auto_rebinding = TRUE;
838 Session::AutoBindingOff();
840 else
842 auto_rebinding = FALSE;
843 Session::AutoBindingOn();
847 void
848 Mixer_UI::toggle_auto_rebinding()
850 if (auto_rebinding)
852 set_auto_rebinding( FALSE );
855 else
857 set_auto_rebinding( TRUE );
860 auto_rebind_midi_controls();
863 void
864 Mixer_UI::auto_rebind_midi_controls ()
866 TreeModel::Children rows = track_model->children();
867 TreeModel::Children::iterator i;
868 int pos;
870 // Create bindings for all visible strips and remove those that are not visible
871 pos = 1; // 0 is reserved for the master strip
872 for (i = rows.begin(); i != rows.end(); ++i) {
873 MixerStrip* strip = (*i)[track_columns.strip];
875 if ( (*i)[track_columns.visible] == true ) { // add bindings for
876 // make the actual binding
877 //cout<<"Auto Binding: Visible Strip Found: "<<strip->name()<<endl;
879 int controlValue = pos;
880 if( strip->route()->is_master() ) {
881 controlValue = 0;
883 else {
884 pos++;
887 PBD::Controllable::CreateBinding ( strip->solo_button->get_controllable().get(), controlValue, 0);
888 PBD::Controllable::CreateBinding ( strip->mute_button->get_controllable().get(), controlValue, 1);
890 if( strip->is_audio_track() ) {
891 PBD::Controllable::CreateBinding ( strip->rec_enable_button->get_controllable().get(), controlValue, 2);
894 PBD::Controllable::CreateBinding ( strip->gpm.get_controllable().get(), controlValue, 3);
895 PBD::Controllable::CreateBinding ( strip->panners.get_controllable().get(), controlValue, 4);
898 else { // Remove any existing binding
899 PBD::Controllable::DeleteBinding ( strip->solo_button->get_controllable().get() );
900 PBD::Controllable::DeleteBinding ( strip->mute_button->get_controllable().get() );
902 if( strip->is_audio_track() ) {
903 PBD::Controllable::DeleteBinding ( strip->rec_enable_button->get_controllable().get() );
906 PBD::Controllable::DeleteBinding ( strip->gpm.get_controllable().get() );
907 PBD::Controllable::DeleteBinding ( strip->panners.get_controllable().get() ); // This only takes the first panner if there are multiples...
910 } // for
914 struct SignalOrderRouteSorter {
915 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
916 /* use of ">" forces the correct sort order */
917 return a->order_key (N_("signal")) < b->order_key (N_("signal"));
921 void
922 Mixer_UI::initial_track_display ()
924 boost::shared_ptr<RouteList> routes = _session->get_routes();
925 RouteList copy (*routes);
926 SignalOrderRouteSorter sorter;
928 copy.sort (sorter);
930 no_track_list_redisplay = true;
932 track_model->clear ();
934 add_strip (copy);
936 no_track_list_redisplay = false;
938 redisplay_track_list ();
941 void
942 Mixer_UI::show_track_list_menu ()
944 if (track_menu == 0) {
945 build_track_menu ();
948 track_menu->popup (1, gtk_get_current_event_time());
951 bool
952 Mixer_UI::track_display_button_press (GdkEventButton* ev)
954 if (Keyboard::is_context_menu_event (ev)) {
955 show_track_list_menu ();
956 return true;
959 TreeIter iter;
960 TreeModel::Path path;
961 TreeViewColumn* column;
962 int cellx;
963 int celly;
965 if (!track_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
966 return false;
969 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
970 case 0:
971 /* allow normal processing to occur */
972 return false;
974 case 1: /* visibility */
976 if ((iter = track_model->get_iter (path))) {
977 MixerStrip* strip = (*iter)[track_columns.strip];
978 if (strip) {
980 if (!strip->route()->is_master() && !strip->route()->is_monitor()) {
981 bool visible = (*iter)[track_columns.visible];
982 (*iter)[track_columns.visible] = !visible;
984 #ifdef GTKOSX
985 track_display.queue_draw();
986 #endif
989 return true;
991 default:
992 break;
995 return false;
999 void
1000 Mixer_UI::build_track_menu ()
1002 using namespace Menu_Helpers;
1003 using namespace Gtk;
1005 track_menu = new Menu;
1006 track_menu->set_name ("ArdourContextMenu");
1007 MenuList& items = track_menu->items();
1009 items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1010 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1011 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1012 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1013 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1014 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1018 void
1019 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1021 if (!what_changed.contains (ARDOUR::Properties::name)) {
1022 return;
1025 ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1027 TreeModel::Children rows = track_model->children();
1028 TreeModel::Children::iterator i;
1030 for (i = rows.begin(); i != rows.end(); ++i) {
1031 if ((*i)[track_columns.strip] == mx) {
1032 (*i)[track_columns.text] = mx->route()->name();
1033 return;
1037 error << _("track display list item for renamed strip not found!") << endmsg;
1040 bool
1041 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1043 TreeModel::Path path;
1044 TreeViewColumn* column;
1045 int cellx;
1046 int celly;
1048 if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1049 return false;
1052 TreeIter iter = group_model->get_iter (path);
1053 if (!iter) {
1054 return false;
1057 RouteGroup* group = (*iter)[group_columns.group];
1059 if (Keyboard::is_context_menu_event (ev)) {
1060 _group_tabs->get_menu(group)->popup (1, ev->time);
1061 return true;
1064 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1065 case 0:
1066 if (Keyboard::is_edit_event (ev)) {
1067 if (group) {
1068 // edit_route_group (group);
1069 #ifdef GTKOSX
1070 group_display.queue_draw();
1071 #endif
1072 return true;
1075 break;
1077 case 1:
1079 bool visible = (*iter)[group_columns.visible];
1080 (*iter)[group_columns.visible] = !visible;
1081 #ifdef GTKOSX
1082 group_display.queue_draw();
1083 #endif
1084 return true;
1087 default:
1088 break;
1091 return false;
1094 void
1095 Mixer_UI::activate_all_route_groups ()
1097 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1100 void
1101 Mixer_UI::disable_all_route_groups ()
1103 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1106 void
1107 Mixer_UI::route_groups_changed ()
1109 ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed);
1111 _in_group_rebuild_or_clear = true;
1113 /* just rebuild the while thing */
1115 group_model->clear ();
1118 TreeModel::Row row;
1119 row = *(group_model->append());
1120 row[group_columns.visible] = true;
1121 row[group_columns.text] = (_("-all-"));
1122 row[group_columns.group] = 0;
1125 _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1127 _group_tabs->set_dirty ();
1128 _in_group_rebuild_or_clear = false;
1131 void
1132 Mixer_UI::new_route_group ()
1134 RouteList rl;
1136 _group_tabs->run_new_group_dialog (rl);
1139 void
1140 Mixer_UI::remove_selected_route_group ()
1142 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1143 TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1145 if (rows.empty()) {
1146 return;
1149 TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1150 TreeIter iter;
1152 /* selection mode is single, so rows.begin() is it */
1154 if ((iter = group_model->get_iter (*i))) {
1156 RouteGroup* rg = (*iter)[group_columns.group];
1158 if (rg) {
1159 _session->remove_route_group (*rg);
1164 void
1165 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1167 if (in_group_row_change) {
1168 return;
1171 /* force an update of any mixer strips that are using this group,
1172 otherwise mix group names don't change in mixer strips
1175 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1176 if ((*i)->route_group() == group) {
1177 (*i)->route_group_changed();
1181 TreeModel::iterator i;
1182 TreeModel::Children rows = group_model->children();
1183 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1185 in_group_row_change = true;
1187 for (i = rows.begin(); i != rows.end(); ++i) {
1188 if ((*i)[group_columns.group] == group) {
1189 (*i)[group_columns.visible] = !group->is_hidden ();
1190 (*i)[group_columns.text] = group->name ();
1191 break;
1195 in_group_row_change = false;
1197 if (change.contains (Properties::name)) {
1198 _group_tabs->set_dirty ();
1201 for (list<MixerStrip*>::iterator j = strips.begin(); j != strips.end(); ++j) {
1202 if ((*j)->route_group() == group) {
1203 if (group->is_hidden ()) {
1204 hide_strip (*j);
1205 } else {
1206 show_strip (*j);
1212 void
1213 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1215 RouteGroup* group;
1216 TreeIter iter;
1218 if ((iter = group_model->get_iter (path))) {
1220 if ((group = (*iter)[group_columns.group]) == 0) {
1221 return;
1224 if (new_text != group->name()) {
1225 group->set_name (new_text);
1230 void
1231 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1233 RouteGroup* group;
1235 if (in_group_row_change) {
1236 return;
1239 if ((group = (*iter)[group_columns.group]) == 0) {
1240 return;
1243 std::string name = (*iter)[group_columns.text];
1245 if (name != group->name()) {
1246 group->set_name (name);
1249 bool hidden = !(*iter)[group_columns.visible];
1251 if (hidden != group->is_hidden ()) {
1252 group->set_hidden (hidden, this);
1256 /** Called when a group model row is deleted, but also when the model is
1257 * reordered by a user drag-and-drop; the latter is what we are
1258 * interested in here.
1260 void
1261 Mixer_UI::route_group_row_deleted (Gtk::TreeModel::Path const &)
1263 if (_in_group_rebuild_or_clear) {
1264 return;
1267 /* Re-write the session's route group list so that the new order is preserved */
1269 list<RouteGroup*> new_list;
1271 Gtk::TreeModel::Children children = group_model->children();
1272 for (Gtk::TreeModel::Children::iterator i = children.begin(); i != children.end(); ++i) {
1273 RouteGroup* g = (*i)[group_columns.group];
1274 if (g) {
1275 new_list.push_back (g);
1279 _session->reorder_route_groups (new_list);
1283 void
1284 Mixer_UI::add_route_group (RouteGroup* group)
1286 ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1287 bool focus = false;
1289 in_group_row_change = true;
1291 TreeModel::Row row = *(group_model->append());
1292 row[group_columns.visible] = !group->is_hidden ();
1293 row[group_columns.group] = group;
1294 if (!group->name().empty()) {
1295 row[group_columns.text] = group->name();
1296 } else {
1297 row[group_columns.text] = _("unnamed");
1298 focus = true;
1301 group->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1303 if (focus) {
1304 TreeViewColumn* col = group_display.get_column (0);
1305 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1306 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1309 _group_tabs->set_dirty ();
1311 in_group_row_change = false;
1314 bool
1315 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1317 using namespace Menu_Helpers;
1319 if (Keyboard::is_context_menu_event (ev)) {
1320 ARDOUR_UI::instance()->add_route (this);
1321 return true;
1324 return false;
1327 void
1328 Mixer_UI::set_strip_width (Width w)
1330 _strip_width = w;
1332 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1333 (*i)->set_width_enum (w, this);
1337 void
1338 Mixer_UI::set_window_pos_and_size ()
1340 resize (m_width, m_height);
1341 move (m_root_x, m_root_y);
1344 void
1345 Mixer_UI::get_window_pos_and_size ()
1347 get_position(m_root_x, m_root_y);
1348 get_size(m_width, m_height);
1352 Mixer_UI::set_state (const XMLNode& node)
1354 const XMLProperty* prop;
1355 XMLNode* geometry;
1357 m_width = default_width;
1358 m_height = default_height;
1359 m_root_x = 1;
1360 m_root_y = 1;
1362 if ((geometry = find_named_node (node, "geometry")) != 0) {
1364 XMLProperty* prop;
1366 if ((prop = geometry->property("x_size")) == 0) {
1367 prop = geometry->property ("x-size");
1369 if (prop) {
1370 m_width = atoi(prop->value());
1372 if ((prop = geometry->property("y_size")) == 0) {
1373 prop = geometry->property ("y-size");
1375 if (prop) {
1376 m_height = atoi(prop->value());
1379 if ((prop = geometry->property ("x_pos")) == 0) {
1380 prop = geometry->property ("x-pos");
1382 if (prop) {
1383 m_root_x = atoi (prop->value());
1386 if ((prop = geometry->property ("y_pos")) == 0) {
1387 prop = geometry->property ("y-pos");
1389 if (prop) {
1390 m_root_y = atoi (prop->value());
1394 set_window_pos_and_size ();
1396 if ((prop = node.property ("narrow-strips"))) {
1397 if (string_is_affirmative (prop->value())) {
1398 set_strip_width (Narrow);
1399 } else {
1400 set_strip_width (Wide);
1404 if ((prop = node.property ("show-mixer"))) {
1405 if (string_is_affirmative (prop->value())) {
1406 _visible = true;
1410 return 0;
1413 XMLNode&
1414 Mixer_UI::get_state (void)
1416 XMLNode* node = new XMLNode ("Mixer");
1418 if (is_realized()) {
1419 Glib::RefPtr<Gdk::Window> win = get_window();
1421 get_window_pos_and_size ();
1423 XMLNode* geometry = new XMLNode ("geometry");
1424 char buf[32];
1425 snprintf(buf, sizeof(buf), "%d", m_width);
1426 geometry->add_property(X_("x_size"), string(buf));
1427 snprintf(buf, sizeof(buf), "%d", m_height);
1428 geometry->add_property(X_("y_size"), string(buf));
1429 snprintf(buf, sizeof(buf), "%d", m_root_x);
1430 geometry->add_property(X_("x_pos"), string(buf));
1431 snprintf(buf, sizeof(buf), "%d", m_root_y);
1432 geometry->add_property(X_("y_pos"), string(buf));
1434 // written only for compatibility, they are not used.
1435 snprintf(buf, sizeof(buf), "%d", 0);
1436 geometry->add_property(X_("x_off"), string(buf));
1437 snprintf(buf, sizeof(buf), "%d", 0);
1438 geometry->add_property(X_("y_off"), string(buf));
1440 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1441 geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1442 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1443 geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1445 node->add_child_nocopy (*geometry);
1448 node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1450 node->add_property ("show-mixer", _visible ? "yes" : "no");
1452 return *node;
1456 void
1457 Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
1459 int pos;
1460 XMLProperty* prop = 0;
1461 char buf[32];
1462 XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1463 XMLNode* geometry;
1464 int height;
1465 static int32_t done[3] = { 0, 0, 0 };
1467 height = default_height;
1469 if ((geometry = find_named_node (*node, "geometry")) != 0) {
1471 if ((prop = geometry->property ("y_size")) == 0) {
1472 prop = geometry->property ("y-size");
1474 if (prop) {
1475 height = atoi (prop->value());
1479 if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1481 if (done[0]) {
1482 return;
1485 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1486 pos = height / 3;
1487 snprintf (buf, sizeof(buf), "%d", pos);
1488 } else {
1489 pos = atoi (prop->value());
1492 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1493 rhs_pane1.set_position (pos);
1496 } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1498 if (done[2]) {
1499 return;
1502 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1503 pos = 75;
1504 snprintf (buf, sizeof(buf), "%d", pos);
1505 } else {
1506 pos = atoi (prop->value());
1509 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1510 list_hpane.set_position (pos);
1514 void
1515 Mixer_UI::scroll_left ()
1517 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1518 /* stupid GTK: can't rely on clamping across versions */
1519 scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
1522 void
1523 Mixer_UI::scroll_right ()
1525 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1526 /* stupid GTK: can't rely on clamping across versions */
1527 scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
1530 bool
1531 Mixer_UI::on_key_press_event (GdkEventKey* ev)
1533 switch (ev->keyval) {
1534 case GDK_Left:
1535 scroll_left ();
1536 return true;
1538 case GDK_Right:
1539 scroll_right ();
1540 return true;
1542 default:
1543 break;
1546 return key_press_focus_accelerator_handler (*this, ev);
1549 bool
1550 Mixer_UI::on_key_release_event (GdkEventKey* ev)
1552 return Gtk::Window::on_key_release_event (ev);
1553 // return key_press_focus_accelerator_handler (*this, ev);
1557 bool
1558 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
1560 switch (ev->direction) {
1561 case GDK_SCROLL_LEFT:
1562 scroll_left ();
1563 return true;
1564 case GDK_SCROLL_UP:
1565 if (ev->state & Keyboard::TertiaryModifier) {
1566 scroll_left ();
1567 return true;
1569 return false;
1571 case GDK_SCROLL_RIGHT:
1572 scroll_right ();
1573 return true;
1575 case GDK_SCROLL_DOWN:
1576 if (ev->state & Keyboard::TertiaryModifier) {
1577 scroll_right ();
1578 return true;
1580 return false;
1583 return false;
1587 void
1588 Mixer_UI::parameter_changed (string const & p)
1590 if (p == "show-group-tabs") {
1591 bool const s = _session->config.get_show_group_tabs ();
1592 if (s) {
1593 _group_tabs->show ();
1594 } else {
1595 _group_tabs->hide ();
1597 } else if (p == "default-narrow_ms") {
1598 bool const s = Config->get_default_narrow_ms ();
1599 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1600 (*i)->set_width_enum (s ? Narrow : Wide, this);
1605 void
1606 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
1608 g->set_active (a, this);
1611 PluginSelector*
1612 Mixer_UI::plugin_selector()
1614 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
1615 if (!_plugin_selector)
1616 _plugin_selector = new PluginSelector (PluginManager::the_manager ());
1617 #endif
1619 return _plugin_selector;
1622 void
1623 Mixer_UI::setup_track_display ()
1625 track_model = ListStore::create (track_columns);
1626 track_display.set_model (track_model);
1627 track_display.append_column (_("Strips"), track_columns.text);
1628 track_display.append_column (_("Show"), track_columns.visible);
1629 track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
1630 track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
1631 track_display.get_column (0)->set_expand(true);
1632 track_display.get_column (1)->set_expand(false);
1633 track_display.set_name (X_("MixerTrackDisplayList"));
1634 track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
1635 track_display.set_reorderable (true);
1636 track_display.set_headers_visible (true);
1638 track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
1639 track_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_change));
1640 track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
1642 CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
1643 track_list_visible_cell->property_activatable() = true;
1644 track_list_visible_cell->property_radio() = false;
1646 track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
1648 track_display_scroller.add (track_display);
1649 track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1651 VBox* v = manage (new VBox);
1652 v->show ();
1653 v->pack_start (track_display_scroller, true, true);
1655 Button* b = manage (new Button);
1656 b->show ();
1657 Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
1658 w->show ();
1659 b->add (*w);
1661 b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
1663 v->pack_start (*b, false, false);
1665 track_display_frame.set_name("BaseFrame");
1666 track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
1667 track_display_frame.add (*v);
1669 track_display_scroller.show();
1670 track_display_frame.show();
1671 track_display.show();
1674 void
1675 Mixer_UI::new_track_or_bus ()
1677 ARDOUR_UI::instance()->add_route (this);