don't override user naming of send/return/port inserts
[ardour2.git] / gtk2_ardour / mixer_ui.cc
blob618d1bbe36b75a6caa0dc69a2457547e8e22e581
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 #include <algorithm>
21 #include <map>
22 #include <sigc++/bind.h>
24 #include <gtkmm/accelmap.h>
26 #include "pbd/convert.h"
27 #include "pbd/stacktrace.h"
28 #include <glibmm/thread.h>
30 #include <gtkmm2ext/gtk_ui.h>
31 #include <gtkmm2ext/utils.h>
32 #include <gtkmm2ext/stop_signal.h>
33 #include <gtkmm2ext/tearoff.h>
34 #include <gtkmm2ext/window_title.h>
36 #include "ardour/audio_diskstream.h"
37 #include "ardour/audio_track.h"
38 #include "ardour/plugin_manager.h"
39 #include "ardour/route_group.h"
40 #include "ardour/session.h"
41 #include "ardour/session_route.h"
43 #include "keyboard.h"
44 #include "mixer_ui.h"
45 #include "mixer_strip.h"
46 #include "monitor_section.h"
47 #include "plugin_selector.h"
48 #include "ardour_ui.h"
49 #include "prompter.h"
50 #include "utils.h"
51 #include "actions.h"
52 #include "gui_thread.h"
53 #include "mixer_group_tabs.h"
55 #include "i18n.h"
57 using namespace ARDOUR;
58 using namespace PBD;
59 using namespace Gtk;
60 using namespace Glib;
61 using namespace Gtkmm2ext;
62 using namespace std;
64 using PBD::atoi;
66 Mixer_UI::Mixer_UI ()
67 : Window (Gtk::WINDOW_TOPLEVEL)
69 _strip_width = Config->get_default_narrow_ms() ? Narrow : Wide;
70 track_menu = 0;
71 _monitor_section = 0;
72 route_group_context_menu = 0;
73 no_track_list_redisplay = false;
74 in_group_row_change = false;
75 _visible = false;
76 strip_redisplay_does_not_reset_order_keys = false;
77 strip_redisplay_does_not_sync_order_keys = false;
78 ignore_sync = false;
80 Route::SyncOrderKeys.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::sync_order_keys, this, _1), gui_context());
82 scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
83 scroller_base.set_name ("MixerWindow");
84 scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
85 // add as last item of strip packer
86 strip_packer.pack_end (scroller_base, true, true);
88 _group_tabs = new MixerGroupTabs (this);
89 VBox* b = manage (new VBox);
90 b->pack_start (*_group_tabs, PACK_SHRINK);
91 b->pack_start (strip_packer);
92 b->show_all ();
94 scroller.add (*b);
95 scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
97 track_model = ListStore::create (track_columns);
98 track_display.set_model (track_model);
99 track_display.append_column (_("Strips"), track_columns.text);
100 track_display.append_column (_("Show"), track_columns.visible);
101 track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
102 track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
103 track_display.get_column (0)->set_expand(true);
104 track_display.get_column (1)->set_expand(false);
105 track_display.set_name (X_("MixerTrackDisplayList"));
106 track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
107 track_display.set_reorderable (true);
108 track_display.set_headers_visible (true);
110 track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
111 track_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_change));
112 track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
114 CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
115 track_list_visible_cell->property_activatable() = true;
116 track_list_visible_cell->property_radio() = false;
118 track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
120 track_display_scroller.add (track_display);
121 track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
123 group_model = ListStore::create (group_columns);
124 group_display.set_model (group_model);
125 group_display.append_column (_("Group"), group_columns.text);
126 group_display.append_column (_("Show"), group_columns.visible);
127 group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
128 group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
129 group_display.get_column (0)->set_expand(true);
130 group_display.get_column (1)->set_expand(false);
131 group_display.set_name ("MixerGroupList");
132 group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
133 group_display.set_reorderable (true);
134 group_display.set_headers_visible (true);
135 group_display.set_rules_hint (true);
137 /* name is directly editable */
139 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
140 name_cell->property_editable() = true;
141 name_cell->signal_edited().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_name_edit));
143 /* use checkbox for the active column */
145 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (1));
146 active_cell->property_activatable() = true;
147 active_cell->property_radio() = false;
149 group_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_change));
151 group_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::group_display_button_press), false);
153 group_display_scroller.add (group_display);
154 group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
156 HBox* route_group_display_button_box = manage (new HBox());
158 Button* route_group_add_button = manage (new Button ());
159 Button* route_group_remove_button = manage (new Button ());
161 Widget* w;
163 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
164 w->show();
165 route_group_add_button->add (*w);
167 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
168 w->show();
169 route_group_remove_button->add (*w);
171 route_group_display_button_box->set_homogeneous (true);
173 route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
174 route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
176 route_group_display_button_box->add (*route_group_remove_button);
177 route_group_display_button_box->add (*route_group_add_button);
179 group_display_vbox.pack_start (group_display_scroller, true, true);
180 group_display_vbox.pack_start (*route_group_display_button_box, false, false);
182 track_display_frame.set_name("BaseFrame");
183 track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
184 track_display_frame.add(track_display_scroller);
186 group_display_frame.set_name ("BaseFrame");
187 group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
188 group_display_frame.add (group_display_vbox);
190 rhs_pane1.pack1 (track_display_frame);
191 rhs_pane1.pack2 (group_display_frame);
193 list_vpacker.pack_start (rhs_pane1, true, true);
195 global_hpacker.pack_start (scroller, true, true);
196 #ifdef GTKOSX
197 /* current gtk-quartz has dirty updates on borders like this one */
198 global_hpacker.pack_start (out_packer, false, false, 0);
199 #else
200 global_hpacker.pack_start (out_packer, false, false, 12);
201 #endif
202 list_hpane.add1(list_vpacker);
203 list_hpane.add2(global_hpacker);
205 rhs_pane1.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
206 static_cast<Gtk::Paned*> (&rhs_pane1)));
207 list_hpane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
208 static_cast<Gtk::Paned*> (&list_hpane)));
210 global_vpacker.pack_start (list_hpane, true, true);
212 add (global_vpacker);
213 set_name ("MixerWindow");
215 WindowTitle title(Glib::get_application_name());
216 title += _("Mixer");
217 set_title (title.get_string());
219 set_wmclass (X_("ardour_mixer"), "Ardour");
221 add_accel_group (ActionManager::ui_manager->get_accel_group());
223 signal_delete_event().connect (sigc::mem_fun (*this, &Mixer_UI::hide_window));
224 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
226 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
228 _selection.RoutesChanged.connect (sigc::mem_fun(*this, &Mixer_UI::follow_strip_selection));
230 route_group_display_button_box->show();
231 route_group_add_button->show();
232 route_group_remove_button->show();
234 global_hpacker.show();
235 global_vpacker.show();
236 scroller.show();
237 scroller_base.show();
238 scroller_hpacker.show();
239 mixer_scroller_vpacker.show();
240 list_vpacker.show();
241 group_display_button_label.show();
242 group_display_button.show();
243 track_display_scroller.show();
244 group_display_scroller.show();
245 group_display_vbox.show();
246 track_display_frame.show();
247 group_display_frame.show();
248 rhs_pane1.show();
249 strip_packer.show();
250 out_packer.show();
251 list_hpane.show();
252 track_display.show();
253 group_display.show();
255 auto_rebinding = FALSE;
257 MixerStrip::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::remove_strip, this, _1), gui_context());
259 MonitorSection::setup_knob_images ();
261 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
262 _plugin_selector = new PluginSelector (PluginManager::the_manager ());
263 #endif
266 Mixer_UI::~Mixer_UI ()
270 void
271 Mixer_UI::ensure_float (Window& win)
273 win.set_transient_for (*this);
276 void
277 Mixer_UI::show_window ()
279 present ();
280 if (!_visible) {
281 set_window_pos_and_size ();
283 /* now reset each strips width so the right widgets are shown */
284 MixerStrip* ms;
286 TreeModel::Children rows = track_model->children();
287 TreeModel::Children::iterator ri;
289 for (ri = rows.begin(); ri != rows.end(); ++ri) {
290 ms = (*ri)[track_columns.strip];
291 ms->set_width_enum (ms->get_width_enum (), ms->width_owner());
294 _visible = true;
297 bool
298 Mixer_UI::hide_window (GdkEventAny *ev)
300 get_window_pos_and_size ();
302 _visible = false;
303 return just_hide_it(ev, static_cast<Gtk::Window *>(this));
307 void
308 Mixer_UI::add_strip (RouteList& routes)
310 ENSURE_GUI_THREAD (*this, &Mixer_UI::add_strip, routes)
312 MixerStrip* strip;
314 no_track_list_redisplay = true;
315 strip_redisplay_does_not_sync_order_keys = true;
317 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
318 boost::shared_ptr<Route> route = (*x);
320 if (route->is_hidden()) {
321 continue;
324 if (route->is_monitor()) {
325 if (!_monitor_section) {
326 _monitor_section = new MonitorSection (_session);
327 out_packer.pack_end (_monitor_section->tearoff(), false, false);
328 } else {
329 _monitor_section->set_session (_session);
332 _monitor_section->tearoff().show_all ();
334 XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
335 if (mnode) {
336 _monitor_section->tearoff().set_state (*mnode);
339 /* no regular strip shown for control out */
341 continue;
344 strip = new MixerStrip (*this, _session, route);
345 strips.push_back (strip);
347 Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
349 if (strip->width_owner() != strip) {
350 strip->set_width_enum (_strip_width, this);
353 show_strip (strip);
355 TreeModel::Row row = *(track_model->append());
356 row[track_columns.text] = route->name();
357 row[track_columns.visible] = strip->marked_for_display();
358 row[track_columns.route] = route;
359 row[track_columns.strip] = strip;
361 if (route->order_key (N_("signal")) == -1) {
362 route->set_order_key (N_("signal"), track_model->children().size()-1);
365 route->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
367 strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
368 strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
371 no_track_list_redisplay = false;
373 redisplay_track_list ();
375 strip_redisplay_does_not_sync_order_keys = false;
378 void
379 Mixer_UI::remove_strip (MixerStrip* strip)
381 if (_session && _session->deletion_in_progress()) {
382 /* its all being taken care of */
383 return;
386 ENSURE_GUI_THREAD (*this, &Mixer_UI::remove_strip, strip);
388 cerr << "Mixer UI removing strip for " << strip << endl;
390 TreeModel::Children rows = track_model->children();
391 TreeModel::Children::iterator ri;
392 list<MixerStrip *>::iterator i;
394 if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
395 strips.erase (i);
398 strip_redisplay_does_not_sync_order_keys = true;
400 for (ri = rows.begin(); ri != rows.end(); ++ri) {
401 if ((*ri)[track_columns.strip] == strip) {
402 track_model->erase (ri);
403 break;
407 strip_redisplay_does_not_sync_order_keys = false;
410 void
411 Mixer_UI::sync_order_keys (string const & src)
413 TreeModel::Children rows = track_model->children();
414 TreeModel::Children::iterator ri;
416 if (src == N_("signal") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
417 return;
420 std::map<int,int> keys;
422 bool changed = false;
424 unsigned order = 0;
425 for (ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
426 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
427 unsigned int old_key = order;
428 unsigned int new_key = route->order_key (N_("signal"));
430 keys[new_key] = old_key;
432 if (new_key != old_key) {
433 changed = true;
437 if (keys.size() != rows.size()) {
438 PBD::stacktrace (cerr, 20);
440 assert(keys.size() == rows.size());
442 // Remove any gaps in keys caused by automation children tracks
443 vector<int> neworder;
444 for (std::map<int,int>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
445 neworder.push_back(i->second);
447 assert(neworder.size() == rows.size());
449 if (changed) {
450 strip_redisplay_does_not_reset_order_keys = true;
451 track_model->reorder (neworder);
452 strip_redisplay_does_not_reset_order_keys = false;
456 void
457 Mixer_UI::follow_strip_selection ()
459 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
460 (*i)->set_selected (_selection.selected ((*i)->route()));
464 bool
465 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
467 if (ev->button == 1) {
469 /* this allows the user to click on the strip to terminate comment
470 editing. XXX it needs improving so that we don't select the strip
471 at the same time.
474 if (_selection.selected (strip->route())) {
475 _selection.remove (strip->route());
476 } else {
477 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
478 _selection.add (strip->route());
479 } else {
480 _selection.set (strip->route());
485 return true;
488 void
489 Mixer_UI::set_session (Session* sess)
491 SessionHandlePtr::set_session (sess);
493 if (_plugin_selector) {
494 _plugin_selector->set_session (_session);
497 _group_tabs->set_session (sess);
499 if (!_session) {
500 return;
503 XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
504 set_state (*node);
506 WindowTitle title(_session->name());
507 title += _("Mixer");
508 title += Glib::get_application_name();
510 set_title (title.get_string());
512 initial_track_display ();
514 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Mixer_UI::add_strip, this, _1), gui_context());
515 _session->route_group_added.connect (_session_connections, invalidator (*this), ui_bind (&Mixer_UI::add_route_group, this, _1), gui_context());
516 _session->route_group_removed.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
517 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Mixer_UI::parameter_changed, this, _1), gui_context());
519 route_groups_changed ();
521 if (_visible) {
522 show_window();
525 start_updating ();
528 void
529 Mixer_UI::session_going_away ()
531 ENSURE_GUI_THREAD (*this, &Mixer_UI::session_going_away)
533 group_model->clear ();
534 _selection.clear ();
535 track_model->clear ();
537 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
538 delete (*i);
541 if (_monitor_section) {
542 _monitor_section->tearoff().hide_visible ();
545 strips.clear ();
547 WindowTitle title(Glib::get_application_name());
548 title += _("Mixer");
549 set_title (title.get_string());
551 stop_updating ();
553 SessionHandlePtr::session_going_away ();
556 void
557 Mixer_UI::show_strip (MixerStrip* ms)
559 TreeModel::Children rows = track_model->children();
560 TreeModel::Children::iterator i;
562 for (i = rows.begin(); i != rows.end(); ++i) {
564 MixerStrip* strip = (*i)[track_columns.strip];
565 if (strip == ms) {
566 (*i)[track_columns.visible] = true;
567 break;
572 void
573 Mixer_UI::hide_strip (MixerStrip* ms)
575 TreeModel::Children rows = track_model->children();
576 TreeModel::Children::iterator i;
578 for (i = rows.begin(); i != rows.end(); ++i) {
580 MixerStrip* strip = (*i)[track_columns.strip];
581 if (strip == ms) {
582 (*i)[track_columns.visible] = false;
583 break;
588 gint
589 Mixer_UI::start_updating ()
591 fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &Mixer_UI::fast_update_strips));
592 return 0;
595 gint
596 Mixer_UI::stop_updating ()
598 fast_screen_update_connection.disconnect();
599 return 0;
602 void
603 Mixer_UI::fast_update_strips ()
605 if (is_mapped () && _session) {
606 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
607 (*i)->fast_update ();
612 void
613 Mixer_UI::set_all_strips_visibility (bool yn)
615 TreeModel::Children rows = track_model->children();
616 TreeModel::Children::iterator i;
618 no_track_list_redisplay = true;
620 for (i = rows.begin(); i != rows.end(); ++i) {
622 TreeModel::Row row = (*i);
623 MixerStrip* strip = row[track_columns.strip];
625 if (strip == 0) {
626 continue;
629 if (strip->route()->is_master() || strip->route()->is_monitor()) {
630 continue;
633 (*i)[track_columns.visible] = yn;
636 no_track_list_redisplay = false;
637 redisplay_track_list ();
641 void
642 Mixer_UI::set_all_audio_visibility (int tracks, bool yn)
644 TreeModel::Children rows = track_model->children();
645 TreeModel::Children::iterator i;
647 no_track_list_redisplay = true;
649 for (i = rows.begin(); i != rows.end(); ++i) {
650 TreeModel::Row row = (*i);
651 MixerStrip* strip = row[track_columns.strip];
653 if (strip == 0) {
654 continue;
657 if (strip->route()->is_master() || strip->route()->is_monitor()) {
658 continue;
661 boost::shared_ptr<AudioTrack> at = strip->audio_track();
663 switch (tracks) {
664 case 0:
665 (*i)[track_columns.visible] = yn;
666 break;
668 case 1:
669 if (at) { /* track */
670 (*i)[track_columns.visible] = yn;
672 break;
674 case 2:
675 if (!at) { /* bus */
676 (*i)[track_columns.visible] = yn;
678 break;
682 no_track_list_redisplay = false;
683 redisplay_track_list ();
686 void
687 Mixer_UI::hide_all_routes ()
689 set_all_strips_visibility (false);
692 void
693 Mixer_UI::show_all_routes ()
695 set_all_strips_visibility (true);
698 void
699 Mixer_UI::show_all_audiobus ()
701 set_all_audio_visibility (2, true);
703 void
704 Mixer_UI::hide_all_audiobus ()
706 set_all_audio_visibility (2, false);
709 void
710 Mixer_UI::show_all_audiotracks()
712 set_all_audio_visibility (1, true);
714 void
715 Mixer_UI::hide_all_audiotracks ()
717 set_all_audio_visibility (1, false);
720 void
721 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
723 strip_redisplay_does_not_sync_order_keys = true;
724 _session->set_remote_control_ids();
725 redisplay_track_list ();
726 strip_redisplay_does_not_sync_order_keys = false;
729 void
730 Mixer_UI::track_list_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&)
732 // never reset order keys because of a property change
733 strip_redisplay_does_not_reset_order_keys = true;
734 _session->set_remote_control_ids();
735 redisplay_track_list ();
736 strip_redisplay_does_not_reset_order_keys = false;
739 void
740 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
742 /* this could require an order sync */
743 if (_session && !_session->deletion_in_progress()) {
744 _session->set_remote_control_ids();
745 redisplay_track_list ();
749 void
750 Mixer_UI::redisplay_track_list ()
752 TreeModel::Children rows = track_model->children();
753 TreeModel::Children::iterator i;
754 long order;
756 if (no_track_list_redisplay) {
757 return;
760 for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
761 MixerStrip* strip = (*i)[track_columns.strip];
763 if (strip == 0) {
764 /* we're in the middle of changing a row, don't worry */
765 continue;
768 bool visible = (*i)[track_columns.visible];
770 if (visible) {
771 strip->set_marked_for_display (true);
772 strip->route()->set_order_key (N_("signal"), order);
774 if (!strip_redisplay_does_not_reset_order_keys) {
775 strip->route()->set_order_key (N_("signal"), order);
778 if (strip->packed()) {
780 if (strip->route()->is_master() || strip->route()->is_monitor()) {
781 out_packer.reorder_child (*strip, -1);
782 } else {
783 strip_packer.reorder_child (*strip, -1); /* put at end */
786 } else {
788 if (strip->route()->is_master() || strip->route()->is_monitor()) {
789 out_packer.pack_start (*strip, false, false);
790 } else {
791 strip_packer.pack_start (*strip, false, false);
793 strip->set_packed (true);
794 //strip->show();
797 } else {
799 strip->set_marked_for_display (false);
801 if (strip->route()->is_master() || strip->route()->is_monitor()) {
802 /* do nothing, these cannot be hidden */
803 } else {
804 if (strip->packed()) {
805 strip_packer.remove (*strip);
806 strip->set_packed (false);
812 if (!strip_redisplay_does_not_reset_order_keys && !strip_redisplay_does_not_sync_order_keys) {
813 _session->sync_order_keys (N_("signal"));
816 // Resigc::bind all of the midi controls automatically
818 if (auto_rebinding)
819 auto_rebind_midi_controls ();
821 _group_tabs->set_dirty ();
824 void
825 Mixer_UI::strip_width_changed ()
827 _group_tabs->set_dirty ();
829 #ifdef GTKOSX
830 TreeModel::Children rows = track_model->children();
831 TreeModel::Children::iterator i;
832 long order;
834 for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
835 MixerStrip* strip = (*i)[track_columns.strip];
837 if (strip == 0) {
838 continue;
841 bool visible = (*i)[track_columns.visible];
843 if (visible) {
844 strip->queue_draw();
847 #endif
851 void
852 Mixer_UI::set_auto_rebinding( bool val )
854 if( val == TRUE )
856 auto_rebinding = TRUE;
857 Session::AutoBindingOff();
859 else
861 auto_rebinding = FALSE;
862 Session::AutoBindingOn();
866 void
867 Mixer_UI::toggle_auto_rebinding()
869 if (auto_rebinding)
871 set_auto_rebinding( FALSE );
874 else
876 set_auto_rebinding( TRUE );
879 auto_rebind_midi_controls();
882 void
883 Mixer_UI::auto_rebind_midi_controls ()
885 TreeModel::Children rows = track_model->children();
886 TreeModel::Children::iterator i;
887 int pos;
889 // Create bindings for all visible strips and remove those that are not visible
890 pos = 1; // 0 is reserved for the master strip
891 for (i = rows.begin(); i != rows.end(); ++i) {
892 MixerStrip* strip = (*i)[track_columns.strip];
894 if ( (*i)[track_columns.visible] == true ) { // add bindings for
895 // make the actual binding
896 //cout<<"Auto Binding: Visible Strip Found: "<<strip->name()<<endl;
898 int controlValue = pos;
899 if( strip->route()->is_master() ) {
900 controlValue = 0;
902 else {
903 pos++;
906 PBD::Controllable::CreateBinding ( strip->solo_button->get_controllable().get(), controlValue, 0);
907 PBD::Controllable::CreateBinding ( strip->mute_button->get_controllable().get(), controlValue, 1);
909 if( strip->is_audio_track() ) {
910 PBD::Controllable::CreateBinding ( strip->rec_enable_button->get_controllable().get(), controlValue, 2);
913 PBD::Controllable::CreateBinding ( strip->gpm.get_controllable().get(), controlValue, 3);
914 PBD::Controllable::CreateBinding ( strip->panners.get_controllable().get(), controlValue, 4);
917 else { // Remove any existing binding
918 PBD::Controllable::DeleteBinding ( strip->solo_button->get_controllable().get() );
919 PBD::Controllable::DeleteBinding ( strip->mute_button->get_controllable().get() );
921 if( strip->is_audio_track() ) {
922 PBD::Controllable::DeleteBinding ( strip->rec_enable_button->get_controllable().get() );
925 PBD::Controllable::DeleteBinding ( strip->gpm.get_controllable().get() );
926 PBD::Controllable::DeleteBinding ( strip->panners.get_controllable().get() ); // This only takes the first panner if there are multiples...
929 } // for
933 struct SignalOrderRouteSorter {
934 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
935 /* use of ">" forces the correct sort order */
936 return a->order_key (N_("signal")) < b->order_key (N_("signal"));
940 void
941 Mixer_UI::initial_track_display ()
943 boost::shared_ptr<RouteList> routes = _session->get_routes();
944 RouteList copy (*routes);
945 SignalOrderRouteSorter sorter;
947 copy.sort (sorter);
949 no_track_list_redisplay = true;
951 track_model->clear ();
953 add_strip (copy);
955 no_track_list_redisplay = false;
957 redisplay_track_list ();
960 void
961 Mixer_UI::show_track_list_menu ()
963 if (track_menu == 0) {
964 build_track_menu ();
967 track_menu->popup (1, gtk_get_current_event_time());
970 bool
971 Mixer_UI::track_display_button_press (GdkEventButton* ev)
973 if (Keyboard::is_context_menu_event (ev)) {
974 show_track_list_menu ();
975 return true;
978 TreeIter iter;
979 TreeModel::Path path;
980 TreeViewColumn* column;
981 int cellx;
982 int celly;
984 if (!track_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
985 return false;
988 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
989 case 0:
990 /* allow normal processing to occur */
991 return false;
993 case 1: /* visibility */
995 if ((iter = track_model->get_iter (path))) {
996 MixerStrip* strip = (*iter)[track_columns.strip];
997 if (strip) {
999 if (!strip->route()->is_master() && !strip->route()->is_monitor()) {
1000 bool visible = (*iter)[track_columns.visible];
1001 (*iter)[track_columns.visible] = !visible;
1003 #ifdef GTKOSX
1004 track_display.queue_draw();
1005 #endif
1008 return true;
1010 default:
1011 break;
1014 return false;
1018 void
1019 Mixer_UI::build_track_menu ()
1021 using namespace Menu_Helpers;
1022 using namespace Gtk;
1024 track_menu = new Menu;
1025 track_menu->set_name ("ArdourContextMenu");
1026 MenuList& items = track_menu->items();
1028 items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1029 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1030 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1031 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1032 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1033 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1037 void
1038 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1040 if (!what_changed.contains (ARDOUR::Properties::name)) {
1041 return;
1044 ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1046 TreeModel::Children rows = track_model->children();
1047 TreeModel::Children::iterator i;
1049 for (i = rows.begin(); i != rows.end(); ++i) {
1050 if ((*i)[track_columns.strip] == mx) {
1051 (*i)[track_columns.text] = mx->route()->name();
1052 return;
1056 error << _("track display list item for renamed strip not found!") << endmsg;
1060 void
1061 Mixer_UI::build_route_group_context_menu ()
1063 using namespace Gtk::Menu_Helpers;
1065 route_group_context_menu = new Menu;
1066 route_group_context_menu->set_name ("ArdourContextMenu");
1067 MenuList& items = route_group_context_menu->items();
1069 items.push_back (MenuElem (_("Activate All"), sigc::mem_fun(*this, &Mixer_UI::activate_all_route_groups)));
1070 items.push_back (MenuElem (_("Disable All"), sigc::mem_fun(*this, &Mixer_UI::disable_all_route_groups)));
1071 items.push_back (SeparatorElem());
1072 items.push_back (MenuElem (_("Add group"), sigc::mem_fun(*this, &Mixer_UI::new_route_group)));
1076 bool
1077 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1079 if (Keyboard::is_context_menu_event (ev)) {
1080 if (route_group_context_menu == 0) {
1081 build_route_group_context_menu ();
1083 route_group_context_menu->popup (1, ev->time);
1084 return true;
1088 RouteGroup* group;
1089 TreeIter iter;
1090 TreeModel::Path path;
1091 TreeViewColumn* column;
1092 int cellx;
1093 int celly;
1095 if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1096 return false;
1099 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1100 case 0:
1101 if (Keyboard::is_edit_event (ev)) {
1102 if ((iter = group_model->get_iter (path))) {
1103 if ((group = (*iter)[group_columns.group]) != 0) {
1104 // edit_route_group (group);
1105 #ifdef GTKOSX
1106 group_display.queue_draw();
1107 #endif
1108 return true;
1113 break;
1115 case 1:
1116 if ((iter = group_model->get_iter (path))) {
1117 bool visible = (*iter)[group_columns.visible];
1118 (*iter)[group_columns.visible] = !visible;
1119 #ifdef GTKOSX
1120 group_display.queue_draw();
1121 #endif
1122 return true;
1124 break;
1126 default:
1127 break;
1130 return false;
1133 void
1134 Mixer_UI::activate_all_route_groups ()
1136 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1139 void
1140 Mixer_UI::disable_all_route_groups ()
1142 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1145 void
1146 Mixer_UI::route_groups_changed ()
1148 ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed)
1150 /* just rebuild the while thing */
1152 group_model->clear ();
1155 TreeModel::Row row;
1156 row = *(group_model->append());
1157 row[group_columns.visible] = true;
1158 row[group_columns.text] = (_("-all-"));
1159 row[group_columns.group] = 0;
1162 _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1165 void
1166 Mixer_UI::new_route_group ()
1168 PropertyList plist;
1170 plist.add (Properties::active, true);
1171 plist.add (Properties::gain, true);
1172 plist.add (Properties::mute, true);
1173 plist.add (Properties::solo, true);
1175 RouteGroup* g = new RouteGroup (*_session, "");
1176 g->set_properties (plist);
1178 _session->add_route_group (g);
1181 void
1182 Mixer_UI::remove_selected_route_group ()
1184 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1185 TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1187 if (rows.empty()) {
1188 return;
1191 TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1192 TreeIter iter;
1194 /* selection mode is single, so rows.begin() is it */
1196 if ((iter = group_model->get_iter (*i))) {
1198 RouteGroup* rg = (*iter)[group_columns.group];
1200 if (rg) {
1201 _session->remove_route_group (*rg);
1206 void
1207 Mixer_UI::group_flags_changed (void* src, RouteGroup* group)
1209 if (in_group_row_change) {
1210 return;
1213 ENSURE_GUI_THREAD (*this, &Mixer_UI::group_flags_changed, src, group)
1215 /* force an update of any mixer strips that are using this group,
1216 otherwise mix group names don't change in mixer strips
1219 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1220 if ((*i)->route_group() == group) {
1221 (*i)->route_group_changed();
1225 TreeModel::iterator i;
1226 TreeModel::Children rows = group_model->children();
1227 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1229 in_group_row_change = true;
1231 for (i = rows.begin(); i != rows.end(); ++i) {
1232 if ((*i)[group_columns.group] == group) {
1233 (*i)[group_columns.visible] = !group->is_hidden ();
1234 (*i)[group_columns.text] = group->name ();
1235 break;
1239 in_group_row_change = false;
1241 _group_tabs->set_dirty ();
1244 void
1245 Mixer_UI::route_group_name_edit (const Glib::ustring& path, const Glib::ustring& new_text)
1247 RouteGroup* group;
1248 TreeIter iter;
1250 if ((iter = group_model->get_iter (path))) {
1252 if ((group = (*iter)[group_columns.group]) == 0) {
1253 return;
1256 if (new_text != group->name()) {
1257 group->set_name (new_text);
1262 void
1263 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1265 RouteGroup* group;
1267 if (in_group_row_change) {
1268 return;
1271 if ((group = (*iter)[group_columns.group]) == 0) {
1272 return;
1275 if ((*iter)[group_columns.visible]) {
1276 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1277 if ((*i)->route_group() == group) {
1278 show_strip (*i);
1281 } else {
1282 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1283 if ((*i)->route_group() == group) {
1284 hide_strip (*i);
1289 Glib::ustring name = (*iter)[group_columns.text];
1291 if (name != group->name()) {
1292 group->set_name (name);
1297 void
1298 Mixer_UI::add_route_group (RouteGroup* group)
1300 ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1301 bool focus = false;
1303 in_group_row_change = true;
1305 TreeModel::Row row = *(group_model->append());
1306 row[group_columns.visible] = true;
1307 row[group_columns.group] = group;
1308 if (!group->name().empty()) {
1309 row[group_columns.text] = group->name();
1310 } else {
1311 row[group_columns.text] = _("unnamed");
1312 focus = true;
1315 group->FlagsChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::group_flags_changed, this, _1, group), gui_context());
1317 if (focus) {
1318 TreeViewColumn* col = group_display.get_column (0);
1319 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1320 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1323 in_group_row_change = false;
1326 bool
1327 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1329 using namespace Menu_Helpers;
1331 if (Keyboard::is_context_menu_event (ev)) {
1332 ARDOUR_UI::instance()->add_route (this);
1333 return true;
1336 return false;
1339 void
1340 Mixer_UI::set_strip_width (Width w)
1342 _strip_width = w;
1344 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1345 (*i)->set_width_enum (w, this);
1349 void
1350 Mixer_UI::set_window_pos_and_size ()
1352 resize (m_width, m_height);
1353 move (m_root_x, m_root_y);
1356 void
1357 Mixer_UI::get_window_pos_and_size ()
1359 get_position(m_root_x, m_root_y);
1360 get_size(m_width, m_height);
1364 Mixer_UI::set_state (const XMLNode& node)
1366 const XMLProperty* prop;
1367 XMLNode* geometry;
1369 m_width = default_width;
1370 m_height = default_height;
1371 m_root_x = 1;
1372 m_root_y = 1;
1374 if ((geometry = find_named_node (node, "geometry")) != 0) {
1376 XMLProperty* prop;
1378 if ((prop = geometry->property("x_size")) == 0) {
1379 prop = geometry->property ("x-size");
1381 if (prop) {
1382 m_width = atoi(prop->value());
1384 if ((prop = geometry->property("y_size")) == 0) {
1385 prop = geometry->property ("y-size");
1387 if (prop) {
1388 m_height = atoi(prop->value());
1391 if ((prop = geometry->property ("x_pos")) == 0) {
1392 prop = geometry->property ("x-pos");
1394 if (prop) {
1395 m_root_x = atoi (prop->value());
1398 if ((prop = geometry->property ("y_pos")) == 0) {
1399 prop = geometry->property ("y-pos");
1401 if (prop) {
1402 m_root_y = atoi (prop->value());
1406 set_window_pos_and_size ();
1408 if ((prop = node.property ("narrow-strips"))) {
1409 if (string_is_affirmative (prop->value())) {
1410 set_strip_width (Narrow);
1411 } else {
1412 set_strip_width (Wide);
1416 if ((prop = node.property ("show-mixer"))) {
1417 if (string_is_affirmative (prop->value())) {
1418 _visible = true;
1422 return 0;
1425 XMLNode&
1426 Mixer_UI::get_state (void)
1428 XMLNode* node = new XMLNode ("Mixer");
1430 if (is_realized()) {
1431 Glib::RefPtr<Gdk::Window> win = get_window();
1433 get_window_pos_and_size ();
1435 XMLNode* geometry = new XMLNode ("geometry");
1436 char buf[32];
1437 snprintf(buf, sizeof(buf), "%d", m_width);
1438 geometry->add_property(X_("x_size"), string(buf));
1439 snprintf(buf, sizeof(buf), "%d", m_height);
1440 geometry->add_property(X_("y_size"), string(buf));
1441 snprintf(buf, sizeof(buf), "%d", m_root_x);
1442 geometry->add_property(X_("x_pos"), string(buf));
1443 snprintf(buf, sizeof(buf), "%d", m_root_y);
1444 geometry->add_property(X_("y_pos"), string(buf));
1446 // written only for compatibility, they are not used.
1447 snprintf(buf, sizeof(buf), "%d", 0);
1448 geometry->add_property(X_("x_off"), string(buf));
1449 snprintf(buf, sizeof(buf), "%d", 0);
1450 geometry->add_property(X_("y_off"), string(buf));
1452 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1453 geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1454 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1455 geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1457 node->add_child_nocopy (*geometry);
1460 node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1462 node->add_property ("show-mixer", _visible ? "yes" : "no");
1464 return *node;
1468 void
1469 Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
1471 int pos;
1472 XMLProperty* prop = 0;
1473 char buf[32];
1474 XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1475 XMLNode* geometry;
1476 int width, height;
1477 static int32_t done[3] = { 0, 0, 0 };
1479 width = default_width;
1480 height = default_height;
1482 if ((geometry = find_named_node (*node, "geometry")) != 0) {
1485 if ((prop = geometry->property ("x_size")) == 0) {
1486 prop = geometry->property ("x-size");
1488 if (prop) {
1489 width = atoi (prop->value());
1491 if ((prop = geometry->property ("y_size")) == 0) {
1492 prop = geometry->property ("y-size");
1494 if (prop) {
1495 height = atoi (prop->value());
1499 if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1501 if (done[0]) {
1502 return;
1505 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1506 pos = height / 3;
1507 snprintf (buf, sizeof(buf), "%d", pos);
1508 } else {
1509 pos = atoi (prop->value());
1512 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1513 rhs_pane1.set_position (pos);
1516 } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1518 if (done[2]) {
1519 return;
1522 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1523 pos = 75;
1524 snprintf (buf, sizeof(buf), "%d", pos);
1525 } else {
1526 pos = atoi (prop->value());
1529 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1530 list_hpane.set_position (pos);
1534 void
1535 Mixer_UI::scroll_left ()
1537 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1538 /* stupid GTK: can't rely on clamping across versions */
1539 scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
1542 void
1543 Mixer_UI::scroll_right ()
1545 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1546 /* stupid GTK: can't rely on clamping across versions */
1547 scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
1550 bool
1551 Mixer_UI::on_key_press_event (GdkEventKey* ev)
1553 switch (ev->keyval) {
1554 case GDK_Left:
1555 scroll_left ();
1556 return true;
1558 case GDK_Right:
1559 scroll_right ();
1560 return true;
1562 default:
1563 break;
1566 return key_press_focus_accelerator_handler (*this, ev);
1569 bool
1570 Mixer_UI::on_key_release_event (GdkEventKey* ev)
1572 return Gtk::Window::on_key_release_event (ev);
1573 // return key_press_focus_accelerator_handler (*this, ev);
1577 bool
1578 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
1580 switch (ev->direction) {
1581 case GDK_SCROLL_LEFT:
1582 scroll_left ();
1583 return true;
1584 case GDK_SCROLL_UP:
1585 if (ev->state & Keyboard::TertiaryModifier) {
1586 scroll_left ();
1587 return true;
1589 return false;
1591 case GDK_SCROLL_RIGHT:
1592 scroll_right ();
1593 return true;
1595 case GDK_SCROLL_DOWN:
1596 if (ev->state & Keyboard::TertiaryModifier) {
1597 scroll_right ();
1598 return true;
1600 return false;
1603 return false;
1607 void
1608 Mixer_UI::parameter_changed (string const & p)
1610 if (p == "show-group-tabs") {
1611 bool const s = _session->config.get_show_group_tabs ();
1612 if (s) {
1613 _group_tabs->show ();
1614 } else {
1615 _group_tabs->hide ();
1620 void
1621 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
1623 g->set_active (a, this);
1626 PluginSelector*
1627 Mixer_UI::plugin_selector()
1629 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
1630 if (!_plugin_selector)
1631 _plugin_selector = new PluginSelector (PluginManager::the_manager ());
1632 #endif
1634 return _plugin_selector;