ardour
mixer_ui.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000-2004 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23 
24 #include <algorithm>
25 #include <map>
26 #include <sigc++/bind.h>
27 
28 #include <gtkmm/accelmap.h>
29 
30 #include "pbd/convert.h"
31 #include "pbd/unwind.h"
32 
33 #include <glibmm/threads.h>
34 
35 #include <gtkmm2ext/gtk_ui.h>
36 #include <gtkmm2ext/utils.h>
37 #include <gtkmm2ext/tearoff.h>
38 #include <gtkmm2ext/window_title.h>
39 
40 #include "ardour/debug.h"
41 #include "ardour/midi_track.h"
42 #include "ardour/plugin_manager.h"
43 #include "ardour/route_group.h"
44 #include "ardour/route_sorters.h"
45 #include "ardour/session.h"
46 
47 #include "keyboard.h"
48 #include "mixer_ui.h"
49 #include "mixer_strip.h"
50 #include "monitor_section.h"
51 #include "plugin_selector.h"
52 #include "public_editor.h"
53 #include "ardour_ui.h"
54 #include "prompter.h"
55 #include "utils.h"
56 #include "route_sorter.h"
57 #include "actions.h"
58 #include "gui_thread.h"
59 #include "mixer_group_tabs.h"
60 #include "timers.h"
61 
62 #include "i18n.h"
63 
64 using namespace ARDOUR;
65 using namespace ARDOUR_UI_UTILS;
66 using namespace PBD;
67 using namespace Gtk;
68 using namespace Glib;
69 using namespace Gtkmm2ext;
70 using namespace std;
71 
72 using PBD::atoi;
73 using PBD::Unwinder;
74 
76 
77 Mixer_UI*
79 {
80  if (!_instance) {
81  _instance = new Mixer_UI;
82  }
83 
84  return _instance;
85 }
86 
88  : Window (Gtk::WINDOW_TOPLEVEL)
89  , VisibilityTracker (*((Gtk::Window*) this))
90  , _visible (false)
91  , no_track_list_redisplay (false)
92  , in_group_row_change (false)
93  , track_menu (0)
94  , _monitor_section (0)
95  , _strip_width (ARDOUR_UI::config()->get_default_narrow_ms() ? Narrow : Wide)
96  , ignore_reorder (false)
100  , _maximised (false)
101 {
102  /* allow this window to become the key focus window */
103  set_flags (CAN_FOCUS);
104 
105  Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_order_keys, this), gui_context());
106 
107  scroller.set_can_default (true);
108  set_default (scroller);
109 
110  scroller_base.set_flags (Gtk::CAN_FOCUS);
111  scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
112  scroller_base.set_name ("MixerWindow");
113  scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
114  // add as last item of strip packer
115  strip_packer.pack_end (scroller_base, true, true);
116 
117  _group_tabs = new MixerGroupTabs (this);
118  VBox* b = manage (new VBox);
119  b->pack_start (*_group_tabs, PACK_SHRINK);
120  b->pack_start (strip_packer);
121  b->show_all ();
122 
123  scroller.add (*b);
124  scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
125 
127 
128  group_model = ListStore::create (group_columns);
129  group_display.set_model (group_model);
130  group_display.append_column (_("Group"), group_columns.text);
131  group_display.append_column (_("Show"), group_columns.visible);
132  group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
133  group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
134  group_display.get_column (0)->set_expand(true);
135  group_display.get_column (1)->set_expand(false);
136  group_display.set_name ("EditGroupList");
137  group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
138  group_display.set_reorderable (true);
139  group_display.set_headers_visible (true);
140  group_display.set_rules_hint (true);
141 
142  /* name is directly editable */
143 
144  CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
145  name_cell->property_editable() = true;
146  name_cell->signal_edited().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_name_edit));
147 
148  /* use checkbox for the active column */
149 
150  CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (1));
151  active_cell->property_activatable() = true;
152  active_cell->property_radio() = false;
153 
154  group_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_change));
155  /* We use this to notice drag-and-drop reorders of the group list */
156  group_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_deleted));
157  group_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::group_display_button_press), false);
158 
160  group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
161 
162  HBox* route_group_display_button_box = manage (new HBox());
163 
164  Button* route_group_add_button = manage (new Button ());
165  Button* route_group_remove_button = manage (new Button ());
166 
167  Widget* w;
168 
169  w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
170  w->show();
171  route_group_add_button->add (*w);
172 
173  w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
174  w->show();
175  route_group_remove_button->add (*w);
176 
177  route_group_display_button_box->set_homogeneous (true);
178 
179  route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
180  route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
181 
182  route_group_display_button_box->add (*route_group_add_button);
183  route_group_display_button_box->add (*route_group_remove_button);
184 
185  group_display_vbox.pack_start (group_display_scroller, true, true);
186  group_display_vbox.pack_start (*route_group_display_button_box, false, false);
187 
188  group_display_frame.set_name ("BaseFrame");
189  group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
191 
194 
195  list_vpacker.pack_start (rhs_pane1, true, true);
196 
197  global_hpacker.pack_start (scroller, true, true);
198 #ifdef GTKOSX
199  /* current gtk-quartz has dirty updates on borders like this one */
200  global_hpacker.pack_start (out_packer, false, false, 0);
201 #else
202  global_hpacker.pack_start (out_packer, false, false, 12);
203 #endif
204  list_hpane.pack1(list_vpacker, false, false);
205  list_hpane.pack2(global_hpacker, true, false);
206 
207  rhs_pane1.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
208  static_cast<Gtk::Paned*> (&rhs_pane1)));
209  list_hpane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
210  static_cast<Gtk::Paned*> (&list_hpane)));
211 
212  global_vpacker.pack_start (list_hpane, true, true);
213 
214  add (global_vpacker);
215  set_name ("MixerWindow");
216 
217  update_title ();
218 
219  set_wmclass (X_("ardour_mixer"), PROGRAM_NAME);
220 
221  signal_delete_event().connect (sigc::mem_fun (*this, &Mixer_UI::hide_window));
222  add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
223 
224  signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
225 
226  route_group_display_button_box->show();
227  route_group_add_button->show();
228  route_group_remove_button->show();
229 
230  global_hpacker.show();
231  global_vpacker.show();
232  scroller.show();
233  scroller_base.show();
234  scroller_hpacker.show();
235  mixer_scroller_vpacker.show();
236  list_vpacker.show();
238  group_display_button.show();
239  group_display_scroller.show();
240  group_display_vbox.show();
241  group_display_frame.show();
242  rhs_pane1.show();
243  strip_packer.show();
244  out_packer.show();
245  list_hpane.show();
246  group_display.show();
247 
248  MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context());
249 
250 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
251  _plugin_selector = new PluginSelector (PluginManager::instance ());
252 #endif
253 }
254 
256 {
257  if (_monitor_section) {
258  delete _monitor_section;
259  }
260 }
261 
262 void
264 {
266 }
267 
268 
269 void
271 {
272  win.set_transient_for (*this);
273 }
274 
275 void
277 {
278  present ();
279  if (!_visible) {
281 
282  /* show/hide group tabs as required */
283  parameter_changed ("show-group-tabs");
284 
285  /* now reset each strips width so the right widgets are shown */
286  MixerStrip* ms;
287 
288  TreeModel::Children rows = track_model->children();
289  TreeModel::Children::iterator ri;
290 
291  for (ri = rows.begin(); ri != rows.end(); ++ri) {
292  ms = (*ri)[track_columns.strip];
293  ms->set_width_enum (ms->get_width_enum (), ms->width_owner());
294  /* Fix visibility of mixer strip stuff */
295  ms->parameter_changed (X_("mixer-element-visibility"));
296  }
297  }
298 
299  /* force focus into main area */
300  scroller_base.grab_focus ();
301 
302  _visible = true;
303 }
304 
305 bool
306 Mixer_UI::hide_window (GdkEventAny *ev)
307 {
309 
310  _visible = false;
311  return just_hide_it(ev, static_cast<Gtk::Window *>(this));
312 }
313 
314 
315 void
317 {
318  bool from_scratch = track_model->children().size() == 0;
319  Gtk::TreeModel::Children::iterator insert_iter = track_model->children().end();
320 
321  for (Gtk::TreeModel::Children::iterator it = track_model->children().begin(); it != track_model->children().end(); ++it) {
323 
324  if (r->order_key() == (routes.front()->order_key() + routes.size())) {
325  insert_iter = it;
326  break;
327  }
328  }
329 
330  if(!from_scratch) {
332  }
333 
334  MixerStrip* strip;
335 
336  try {
338  track_display.set_model (Glib::RefPtr<ListStore>());
339 
340  for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
341  boost::shared_ptr<Route> route = (*x);
342 
343  if (route->is_auditioner()) {
344  continue;
345  }
346 
347  if (route->is_monitor()) {
348 
349  if (!_monitor_section) {
351 
352  XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
353  if (mnode) {
354  _monitor_section->tearoff().set_state (*mnode);
355  }
356  }
357 
358  out_packer.pack_end (_monitor_section->tearoff(), false, false);
360  _monitor_section->tearoff().show_all ();
361 
362  route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
363 
364  /* no regular strip shown for control out */
365 
366  continue;
367  }
368 
369  strip = new MixerStrip (*this, _session, route);
370  strips.push_back (strip);
371 
372  ARDOUR_UI::config()->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
373 
374  if (strip->width_owner() != strip) {
375  strip->set_width_enum (_strip_width, this);
376  }
377 
378  show_strip (strip);
379 
380  TreeModel::Row row = *(track_model->insert(insert_iter));
381  row[track_columns.text] = route->name();
382  row[track_columns.visible] = strip->route()->is_master() ? true : strip->marked_for_display();
383  row[track_columns.route] = route;
384  row[track_columns.strip] = strip;
385 
386  if (!from_scratch) {
387  _selection.add (strip);
388  }
389 
390  route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
391 
392  strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
393  strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
394  }
395 
396  } catch (...) {
397  }
398 
399  no_track_list_redisplay = false;
400  track_display.set_model (track_model);
401 
404 }
405 
406 void
408 {
409  for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
410  (*i)->deselect_all_processors();
411  }
412 }
413 
414 void
416 {
419 }
420 
421 void
423 {
424  for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
425  (*i)->delete_processors();
426  }
427 }
428 
429 
430 void
432 {
434  /* its all being taken care of */
435  return;
436  }
437 
438  TreeModel::Children rows = track_model->children();
439  TreeModel::Children::iterator ri;
440  list<MixerStrip *>::iterator i;
441 
442  if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
443  strips.erase (i);
444  }
445 
446  for (ri = rows.begin(); ri != rows.end(); ++ri) {
447  if ((*ri)[track_columns.strip] == strip) {
449  track_model->erase (ri);
450  break;
451  }
452  }
453 }
454 
455 void
457 {
458  if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) {
459  return;
460  }
461 
462  TreeModel::Children rows = track_model->children();
463 
464  if (rows.empty()) {
465  return;
466  }
467 
468  DEBUG_TRACE (DEBUG::OrderKeys, "mixer resets remote control ids after remote model change\n");
469 
470  TreeModel::Children::iterator ri;
471  bool rid_change = false;
472  uint32_t rid = 1;
473  uint32_t invisible_key = UINT32_MAX;
474 
475  for (ri = rows.begin(); ri != rows.end(); ++ri) {
476 
477  /* skip two special values */
478 
479  if (rid == Route::MasterBusRemoteControlID) {
480  rid++;
481  }
482 
483  if (rid == Route::MonitorBusRemoteControlID) {
484  rid++;
485  }
486 
488  bool visible = (*ri)[track_columns.visible];
489 
490  if (!route->is_master() && !route->is_monitor()) {
491 
492  uint32_t new_rid = (visible ? rid : invisible_key--);
493 
494  if (new_rid != route->remote_control_id()) {
495  route->set_remote_control_id_explicit (new_rid);
496  rid_change = true;
497  }
498 
499  if (visible) {
500  rid++;
501  }
502  }
503  }
504 
505  if (rid_change) {
506  /* tell the world that we changed the remote control IDs */
508  }
509 }
510 
511 void
513 {
515  return;
516  }
517 
518  TreeModel::Children rows = track_model->children();
519 
520  if (rows.empty()) {
521  return;
522  }
523 
524  DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync order keys from model\n");
525 
526  TreeModel::Children::iterator ri;
527  bool changed = false;
528  bool rid_change = false;
529  uint32_t order = 0;
530  uint32_t rid = 1;
531  uint32_t invisible_key = UINT32_MAX;
532 
533  for (ri = rows.begin(); ri != rows.end(); ++ri) {
535  bool visible = (*ri)[track_columns.visible];
536 
537  uint32_t old_key = route->order_key ();
538 
539  if (order != old_key) {
540  route->set_order_key (order);
541  changed = true;
542  }
543 
544  if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) {
545 
546  uint32_t new_rid = (visible ? rid : invisible_key--);
547 
548  if (new_rid != route->remote_control_id()) {
549  route->set_remote_control_id_explicit (new_rid);
550  rid_change = true;
551  }
552 
553  if (visible) {
554  rid++;
555  }
556 
557  }
558 
559  ++order;
560  }
561 
562  if (changed) {
563  /* tell everyone that we changed the mixer sort keys */
565  }
566 
567  if (rid_change) {
568  /* tell the world that we changed the remote control IDs */
570  }
571 }
572 
573 void
575 {
577  return;
578  }
579 
580  DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync model from order keys.\n");
581 
582  /* we could get here after either a change in the Mixer or Editor sort
583  * order, but either way, the mixer order keys reflect the intended
584  * order for the GUI, so reorder the treeview model to match it.
585  */
586 
587  vector<int> neworder;
588  TreeModel::Children rows = track_model->children();
589  uint32_t old_order = 0;
590  bool changed = false;
591 
592  if (rows.empty()) {
593  return;
594  }
595 
596  OrderKeySortedRoutes sorted_routes;
597 
598  for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
600  sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key ()));
601  }
602 
604 
605  sort (sorted_routes.begin(), sorted_routes.end(), cmp);
606  neworder.assign (sorted_routes.size(), 0);
607 
608  uint32_t n = 0;
609 
610  for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
611 
612  neworder[n] = sr->old_display_order;
613 
614  if (sr->old_display_order != n) {
615  changed = true;
616  }
617 
618  DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("MIXER change order for %1 from %2 to %3\n",
619  sr->route->name(), sr->old_display_order, n));
620  }
621 
622  if (changed) {
623  Unwinder<bool> uw (ignore_reorder, true);
624  track_model->reorder (neworder);
625  }
626 
628 }
629 
630 void
632 {
634  return;
635  }
636 
639 
640  TrackSelection& s (PublicEditor::instance().get_selection().tracks);
641 
643 
644  for (TrackViewList::iterator i = s.begin(); i != s.end(); ++i) {
645  RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
646  if (rtav) {
647  MixerStrip* ms = strip_by_route (rtav->route());
648  if (ms) {
649  _selection.add (ms);
650  }
651  }
652  }
653 
656 }
657 
658 
659 MixerStrip*
661 {
662  for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
663  if ((*i)->route() == r) {
664  return (*i);
665  }
666  }
667 
668  return 0;
669 }
670 
671 bool
673 {
674  if (ev->button == 1) {
675  if (_selection.selected (strip)) {
676  /* primary-click: toggle selection state of strip */
677  if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
678  _selection.remove (strip);
679  } else if (_selection.routes.size() > 1) {
680  /* de-select others */
681  _selection.set (strip);
682  }
683  } else {
684  if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
685  _selection.add (strip);
686  } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) {
687 
688  if (!_selection.selected(strip)) {
689 
690  /* extend selection */
691 
692  vector<MixerStrip*> tmp;
693  bool accumulate = false;
694  bool found_another = false;
695 
696  tmp.push_back (strip);
697 
698  for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
699  if ((*i) == strip) {
700  /* hit clicked strip, start accumulating till we hit the first
701  selected strip
702  */
703  if (accumulate) {
704  /* done */
705  break;
706  } else {
707  accumulate = true;
708  }
709  } else if (_selection.selected (*i)) {
710  /* hit selected strip. if currently accumulating others,
711  we're done. if not accumulating others, start doing so.
712  */
713  found_another = true;
714  if (accumulate) {
715  /* done */
716  break;
717  } else {
718  accumulate = true;
719  }
720  } else {
721  if (accumulate) {
722  tmp.push_back (*i);
723  }
724  }
725  }
726 
727  if (found_another) {
728  for (vector<MixerStrip*>::iterator i = tmp.begin(); i != tmp.end(); ++i) {
729  _selection.add (*i);
730  }
731  } else
732  _selection.set (strip); //user wants to start a range selection, but there aren't any others selected yet
733  }
734 
735  } else {
736  _selection.set (strip);
737  }
738  }
739  }
740 
741  return true;
742 }
743 
744 void
746 {
747  SessionHandlePtr::set_session (sess);
748 
749  if (_plugin_selector) {
751  }
752 
753  _group_tabs->set_session (sess);
754 
755  if (!_session) {
756  return;
757  }
758 
760  set_state (*node);
761 
762  update_title ();
763 
765 
766  _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_strips, this, _1), gui_context());
767  _session->route_group_added.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_route_group, this, _1), gui_context());
771  _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
772  _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
773 
774  Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
775 
777 
778  if (_visible) {
779  show_window();
780 
781  /* Bit of a hack; if we're here, we're opening the mixer because of our
782  instant XML state having a show-mixer property. Fix up the corresponding
783  action state.
784  */
785  ActionManager::check_toggleaction ("<Actions>/Common/toggle-mixer");
786  }
787 
788  start_updating ();
789 }
790 
791 void
793 {
795 
797  group_model->clear ();
799 
800  _selection.clear ();
801  track_model->clear ();
802 
803  for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
804  delete (*i);
805  }
806 
807  if (_monitor_section) {
809  }
810 
811  strips.clear ();
812 
813  stop_updating ();
814 
815  SessionHandlePtr::session_going_away ();
816 
817  _session = 0;
818  update_title ();
819 }
820 
821 void
822 Mixer_UI::track_visibility_changed (std::string const & path)
823 {
825  return;
826  }
827 
828  TreeIter iter;
829 
830  if ((iter = track_model->get_iter (path))) {
831  MixerStrip* strip = (*iter)[track_columns.strip];
832  if (strip) {
833  bool visible = (*iter)[track_columns.visible];
834 
835  if (strip->set_marked_for_display (!visible)) {
837  }
838  }
839  }
840 }
841 
842 void
844 {
845  TreeModel::Children rows = track_model->children();
846  TreeModel::Children::iterator i;
847 
848  {
850 
851  for (i = rows.begin(); i != rows.end(); ++i) {
852  MixerStrip *strip = (*i)[track_columns.strip];
853  (*i)[track_columns.visible] = strip->marked_for_display ();
854  }
855 
856  /* force route order keys catch up with visibility changes
857  */
858 
860  }
861 
863 }
864 
865 void
867 {
868  TreeModel::Children rows = track_model->children();
869  TreeModel::Children::iterator i;
870 
871  for (i = rows.begin(); i != rows.end(); ++i) {
872 
873  MixerStrip* strip = (*i)[track_columns.strip];
874  if (strip == ms) {
875  (*i)[track_columns.visible] = true;
877  break;
878  }
879  }
880 }
881 
882 void
884 {
885  TreeModel::Children rows = track_model->children();
886  TreeModel::Children::iterator i;
887 
888  for (i = rows.begin(); i != rows.end(); ++i) {
889 
890  MixerStrip* strip = (*i)[track_columns.strip];
891  if (strip == ms) {
892  (*i)[track_columns.visible] = false;
894  break;
895  }
896  }
897 }
898 
899 gint
901 {
903  return 0;
904 }
905 
906 gint
908 {
909  fast_screen_update_connection.disconnect();
910  return 0;
911 }
912 
913 void
915 {
916  if (is_mapped () && _session) {
917  for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
918  (*i)->fast_update ();
919  }
920  }
921 }
922 
923 void
925 {
926  TreeModel::Children rows = track_model->children();
927  TreeModel::Children::iterator i;
928 
929  {
931 
932  for (i = rows.begin(); i != rows.end(); ++i) {
933 
934  TreeModel::Row row = (*i);
935  MixerStrip* strip = row[track_columns.strip];
936 
937  if (strip == 0) {
938  continue;
939  }
940 
941  if (strip->route()->is_master() || strip->route()->is_monitor()) {
942  continue;
943  }
944 
945  (*i)[track_columns.visible] = yn;
946  }
947  }
948 
950 }
951 
952 
953 void
955 {
956  TreeModel::Children rows = track_model->children();
957  TreeModel::Children::iterator i;
958 
959  {
961 
962  for (i = rows.begin(); i != rows.end(); ++i) {
963  TreeModel::Row row = (*i);
964  MixerStrip* strip = row[track_columns.strip];
965 
966  if (strip == 0) {
967  continue;
968  }
969 
970  if (strip->route()->is_master() || strip->route()->is_monitor()) {
971  continue;
972  }
973 
975 
976  switch (tracks) {
977  case 0:
978  (*i)[track_columns.visible] = yn;
979  break;
980 
981  case 1:
982  if (at) { /* track */
983  (*i)[track_columns.visible] = yn;
984  }
985  break;
986 
987  case 2:
988  if (!at) { /* bus */
989  (*i)[track_columns.visible] = yn;
990  }
991  break;
992  }
993  }
994  }
995 
997 }
998 
999 void
1001 {
1002  set_all_strips_visibility (false);
1003 }
1004 
1005 void
1007 {
1009 }
1010 
1011 void
1013 {
1014  set_all_audio_visibility (2, true);
1015 }
1016 void
1018 {
1019  set_all_audio_visibility (2, false);
1020 }
1021 
1022 void
1024 {
1025  set_all_audio_visibility (1, true);
1026 }
1027 void
1029 {
1030  set_all_audio_visibility (1, false);
1031 }
1032 
1033 void
1034 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
1035 {
1036  DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview reordered\n");
1038 }
1039 
1040 void
1041 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
1042 {
1043  /* this happens as the second step of a DnD within the treeview as well
1044  as when a row/route is actually deleted.
1045 
1046  if it was a deletion then we have to force a redisplay because
1047  order keys may not have changed.
1048  */
1049 
1050  DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview row deleted\n");
1052 
1055  }
1056 }
1057 
1058 void
1060 {
1061  TreeModel::Children rows = track_model->children();
1062  TreeModel::Children::iterator i;
1063 
1065  return;
1066  }
1067 
1068  for (i = rows.begin(); i != rows.end(); ++i) {
1069 
1070  MixerStrip* strip = (*i)[track_columns.strip];
1071 
1072  if (strip == 0) {
1073  /* we're in the middle of changing a row, don't worry */
1074  continue;
1075  }
1076 
1077  bool const visible = (*i)[track_columns.visible];
1078 
1079  if (visible) {
1080  strip->set_gui_property ("visible", true);
1081 
1082  if (strip->packed()) {
1083 
1084  if (strip->route()->is_master() || strip->route()->is_monitor()) {
1085  out_packer.reorder_child (*strip, -1);
1086 
1087  } else {
1088  strip_packer.reorder_child (*strip, -1); /* put at end */
1089  }
1090 
1091  } else {
1092 
1093  if (strip->route()->is_master() || strip->route()->is_monitor()) {
1094  out_packer.pack_start (*strip, false, false);
1095  } else {
1096  strip_packer.pack_start (*strip, false, false);
1097  }
1098  strip->set_packed (true);
1099  }
1100 
1101  } else {
1102 
1103  strip->set_gui_property ("visible", false);
1104 
1105  if (strip->route()->is_master() || strip->route()->is_monitor()) {
1106  /* do nothing, these cannot be hidden */
1107  } else {
1108  if (strip->packed()) {
1109  strip_packer.remove (*strip);
1110  strip->set_packed (false);
1111  }
1112  }
1113  }
1114  }
1115 
1116  _group_tabs->set_dirty ();
1117 }
1118 
1119 void
1121 {
1122  _group_tabs->set_dirty ();
1123 
1124 #ifdef GTKOSX
1125  TreeModel::Children rows = track_model->children();
1126  TreeModel::Children::iterator i;
1127  long order;
1128 
1129  for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
1130  MixerStrip* strip = (*i)[track_columns.strip];
1131 
1132  if (strip == 0) {
1133  continue;
1134  }
1135 
1136  bool visible = (*i)[track_columns.visible];
1137 
1138  if (visible) {
1139  strip->queue_draw();
1140  }
1141  }
1142 #endif
1143 
1144 }
1145 
1146 void
1148 {
1150  RouteList copy (*routes);
1152 
1153  copy.sort (sorter);
1154 
1155  {
1157  Unwinder<bool> uw2 (ignore_reorder, true);
1158 
1159  track_model->clear ();
1160  add_strips (copy);
1161  }
1162 
1164 
1166 }
1167 
1168 void
1170 {
1171  if (track_menu == 0) {
1172  build_track_menu ();
1173  }
1174 
1175  track_menu->popup (1, gtk_get_current_event_time());
1176 }
1177 
1178 bool
1180 {
1181  if (Keyboard::is_context_menu_event (ev)) {
1183  return true;
1184  }
1185 
1186  return false;
1187 }
1188 
1189 void
1191 {
1192  using namespace Menu_Helpers;
1193  using namespace Gtk;
1194 
1195  track_menu = new Menu;
1196  track_menu->set_name ("ArdourContextMenu");
1197  MenuList& items = track_menu->items();
1198 
1199  items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1200  items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1201  items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1202  items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1203  items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1204  items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1205 
1206 }
1207 
1208 void
1210 {
1211  if (!what_changed.contains (ARDOUR::Properties::name)) {
1212  return;
1213  }
1214 
1215  ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1216 
1217  TreeModel::Children rows = track_model->children();
1218  TreeModel::Children::iterator i;
1219 
1220  for (i = rows.begin(); i != rows.end(); ++i) {
1221  if ((*i)[track_columns.strip] == mx) {
1222  (*i)[track_columns.text] = mx->route()->name();
1223  return;
1224  }
1225  }
1226 
1227  error << _("track display list item for renamed strip not found!") << endmsg;
1228 }
1229 
1230 bool
1232 {
1233  TreeModel::Path path;
1234  TreeViewColumn* column;
1235  int cellx;
1236  int celly;
1237 
1238  if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1239  _group_tabs->get_menu(0)->popup (1, ev->time);
1240  return true;
1241  }
1242 
1243  TreeIter iter = group_model->get_iter (path);
1244  if (!iter) {
1245  _group_tabs->get_menu(0)->popup (1, ev->time);
1246  return true;
1247  }
1248 
1249  RouteGroup* group = (*iter)[group_columns.group];
1250 
1251  if (Keyboard::is_context_menu_event (ev)) {
1252  _group_tabs->get_menu(group)->popup (1, ev->time);
1253  return true;
1254  }
1255 
1256  switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1257  case 0:
1258  if (Keyboard::is_edit_event (ev)) {
1259  if (group) {
1260  // edit_route_group (group);
1261 #ifdef GTKOSX
1262  group_display.queue_draw();
1263 #endif
1264  return true;
1265  }
1266  }
1267  break;
1268 
1269  case 1:
1270  {
1271  bool visible = (*iter)[group_columns.visible];
1272  (*iter)[group_columns.visible] = !visible;
1273 #ifdef GTKOSX
1274  group_display.queue_draw();
1275 #endif
1276  return true;
1277  }
1278 
1279  default:
1280  break;
1281  }
1282 
1283  return false;
1284  }
1285 
1286 void
1288 {
1289  _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1290 }
1291 
1292 void
1294 {
1295  _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1296 }
1297 
1298 void
1300 {
1302 
1304 
1305  /* just rebuild the while thing */
1306 
1307  group_model->clear ();
1308 
1309 #if 0
1310  /* this is currently not used,
1311  * Mixer_UI::group_display_button_press() has a case for it,
1312  * and a commented edit_route_group() but that's n/a since 2011.
1313  *
1314  * This code is left as reminder that
1315  * row[group_columns.group] = 0 has special meaning.
1316  */
1317  {
1318  TreeModel::Row row;
1319  row = *(group_model->append());
1320  row[group_columns.visible] = true;
1321  row[group_columns.text] = (_("-all-"));
1322  row[group_columns.group] = 0;
1323  }
1324 #endif
1325 
1326  _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1327 
1328  _group_tabs->set_dirty ();
1330 }
1331 
1332 void
1334 {
1335  RouteList rl;
1336 
1338 }
1339 
1340 void
1342 {
1343  Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1344  TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1345 
1346  if (rows.empty()) {
1347  return;
1348  }
1349 
1350  TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1351  TreeIter iter;
1352 
1353  /* selection mode is single, so rows.begin() is it */
1354 
1355  if ((iter = group_model->get_iter (*i))) {
1356 
1357  RouteGroup* rg = (*iter)[group_columns.group];
1358 
1359  if (rg) {
1361  }
1362  }
1363 }
1364 
1365 void
1367 {
1368  if (in_group_row_change) {
1369  return;
1370  }
1371 
1372  /* force an update of any mixer strips that are using this group,
1373  otherwise mix group names don't change in mixer strips
1374  */
1375 
1376  for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1377  if ((*i)->route_group() == group) {
1378  (*i)->route_group_changed();
1379  }
1380  }
1381 
1382  TreeModel::iterator i;
1383  TreeModel::Children rows = group_model->children();
1384  Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1385 
1386  in_group_row_change = true;
1387 
1388  for (i = rows.begin(); i != rows.end(); ++i) {
1389  if ((*i)[group_columns.group] == group) {
1390  (*i)[group_columns.visible] = !group->is_hidden ();
1391  (*i)[group_columns.text] = group->name ();
1392  break;
1393  }
1394  }
1395 
1396  in_group_row_change = false;
1397 
1398  if (change.contains (Properties::name)) {
1399  _group_tabs->set_dirty ();
1400  }
1401 
1402  for (list<MixerStrip*>::iterator j = strips.begin(); j != strips.end(); ++j) {
1403  if ((*j)->route_group() == group) {
1404  if (group->is_hidden ()) {
1405  hide_strip (*j);
1406  } else {
1407  show_strip (*j);
1408  }
1409  }
1410  }
1411 }
1412 
1413 void
1414 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1415 {
1416  RouteGroup* group;
1417  TreeIter iter;
1418 
1419  if ((iter = group_model->get_iter (path))) {
1420 
1421  if ((group = (*iter)[group_columns.group]) == 0) {
1422  return;
1423  }
1424 
1425  if (new_text != group->name()) {
1426  group->set_name (new_text);
1427  }
1428  }
1429 }
1430 
1431 void
1432 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1433 {
1434  RouteGroup* group;
1435 
1436  if (in_group_row_change) {
1437  return;
1438  }
1439 
1440  if ((group = (*iter)[group_columns.group]) == 0) {
1441  return;
1442  }
1443 
1444  std::string name = (*iter)[group_columns.text];
1445 
1446  if (name != group->name()) {
1447  group->set_name (name);
1448  }
1449 
1450  bool hidden = !(*iter)[group_columns.visible];
1451 
1452  if (hidden != group->is_hidden ()) {
1453  group->set_hidden (hidden, this);
1454  }
1455 }
1456 
1461 void
1462 Mixer_UI::route_group_row_deleted (Gtk::TreeModel::Path const &)
1463 {
1465  return;
1466  }
1467 
1468  /* Re-write the session's route group list so that the new order is preserved */
1469 
1470  list<RouteGroup*> new_list;
1471 
1472  Gtk::TreeModel::Children children = group_model->children();
1473  for (Gtk::TreeModel::Children::iterator i = children.begin(); i != children.end(); ++i) {
1474  RouteGroup* g = (*i)[group_columns.group];
1475  if (g) {
1476  new_list.push_back (g);
1477  }
1478  }
1479 
1480  _session->reorder_route_groups (new_list);
1481 }
1482 
1483 
1484 void
1486 {
1488  bool focus = false;
1489 
1490  in_group_row_change = true;
1491 
1492  TreeModel::Row row = *(group_model->append());
1493  row[group_columns.visible] = !group->is_hidden ();
1494  row[group_columns.group] = group;
1495  if (!group->name().empty()) {
1496  row[group_columns.text] = group->name();
1497  } else {
1498  row[group_columns.text] = _("unnamed");
1499  focus = true;
1500  }
1501 
1502  group->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1503 
1504  if (focus) {
1505  TreeViewColumn* col = group_display.get_column (0);
1506  CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1507  group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1508  }
1509 
1510  _group_tabs->set_dirty ();
1511 
1512  in_group_row_change = false;
1513 }
1514 
1515 bool
1517 {
1518  using namespace Menu_Helpers;
1519 
1520  if (Keyboard::is_context_menu_event (ev)) {
1521  ARDOUR_UI::instance()->add_route (this);
1522  return true;
1523  }
1524 
1525  return false;
1526 }
1527 
1528 void
1530 {
1531  _strip_width = w;
1532 
1533  for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1534  (*i)->set_width_enum (w, save ? (*i)->width_owner() : this);
1535  }
1536 }
1537 
1538 void
1540 {
1541  resize (m_width, m_height);
1542  move (m_root_x, m_root_y);
1543 }
1544 
1545  void
1547 {
1548  get_position(m_root_x, m_root_y);
1549  get_size(m_width, m_height);
1550 }
1551 
1552 int
1554 {
1555  const XMLProperty* prop;
1556  XMLNode* geometry;
1557 
1560  m_root_x = 1;
1561  m_root_y = 1;
1562 
1563  if ((geometry = find_named_node (node, "geometry")) != 0) {
1564 
1565  XMLProperty* prop;
1566 
1567  if ((prop = geometry->property("x_size")) == 0) {
1568  prop = geometry->property ("x-size");
1569  }
1570  if (prop) {
1571  m_width = atoi(prop->value());
1572  }
1573  if ((prop = geometry->property("y_size")) == 0) {
1574  prop = geometry->property ("y-size");
1575  }
1576  if (prop) {
1577  m_height = atoi(prop->value());
1578  }
1579 
1580  if ((prop = geometry->property ("x_pos")) == 0) {
1581  prop = geometry->property ("x-pos");
1582  }
1583  if (prop) {
1584  m_root_x = atoi (prop->value());
1585 
1586  }
1587  if ((prop = geometry->property ("y_pos")) == 0) {
1588  prop = geometry->property ("y-pos");
1589  }
1590  if (prop) {
1591  m_root_y = atoi (prop->value());
1592  }
1593  }
1594 
1596 
1597  if ((prop = node.property ("narrow-strips"))) {
1598  if (string_is_affirmative (prop->value())) {
1600  } else {
1602  }
1603  }
1604 
1605  if ((prop = node.property ("show-mixer"))) {
1606  if (string_is_affirmative (prop->value())) {
1607  _visible = true;
1608  }
1609  }
1610 
1611  if ((prop = node.property ("maximised"))) {
1612  bool yn = string_is_affirmative (prop->value());
1613  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer"));
1614  assert (act);
1615  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1616  bool fs = tact && tact->get_active();
1617  if (yn ^ fs) {
1618  ActionManager::do_action ("Common",
1619  "ToggleMaximalMixer");
1620  }
1621  }
1622 
1623 
1624  return 0;
1625 }
1626 
1627 XMLNode&
1629 {
1630  XMLNode* node = new XMLNode ("Mixer");
1631 
1632  if (is_realized()) {
1633  Glib::RefPtr<Gdk::Window> win = get_window();
1634 
1636 
1637  XMLNode* geometry = new XMLNode ("geometry");
1638  char buf[32];
1639  snprintf(buf, sizeof(buf), "%d", m_width);
1640  geometry->add_property(X_("x_size"), string(buf));
1641  snprintf(buf, sizeof(buf), "%d", m_height);
1642  geometry->add_property(X_("y_size"), string(buf));
1643  snprintf(buf, sizeof(buf), "%d", m_root_x);
1644  geometry->add_property(X_("x_pos"), string(buf));
1645  snprintf(buf, sizeof(buf), "%d", m_root_y);
1646  geometry->add_property(X_("y_pos"), string(buf));
1647 
1648  // written only for compatibility, they are not used.
1649  snprintf(buf, sizeof(buf), "%d", 0);
1650  geometry->add_property(X_("x_off"), string(buf));
1651  snprintf(buf, sizeof(buf), "%d", 0);
1652  geometry->add_property(X_("y_off"), string(buf));
1653 
1654  snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1655  geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1656  snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1657  geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1658 
1659  node->add_child_nocopy (*geometry);
1660  }
1661 
1662  node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1663 
1664  node->add_property ("show-mixer", _visible ? "yes" : "no");
1665 
1666  node->add_property ("maximised", _maximised ? "yes" : "no");
1667 
1668  return *node;
1669 }
1670 
1671 
1672 void
1673 Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
1674 {
1675  int pos;
1676  XMLProperty* prop = 0;
1677  char buf[32];
1679  XMLNode* geometry;
1680  int height;
1681  static int32_t done[3] = { 0, 0, 0 };
1682 
1683  height = default_height;
1684 
1685  if ((geometry = find_named_node (*node, "geometry")) != 0) {
1686 
1687  if ((prop = geometry->property ("y_size")) == 0) {
1688  prop = geometry->property ("y-size");
1689  }
1690  if (prop) {
1691  height = atoi (prop->value());
1692  }
1693  }
1694 
1695  if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1696 
1697  if (done[0]) {
1698  return;
1699  }
1700 
1701  if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1702  pos = height / 3;
1703  snprintf (buf, sizeof(buf), "%d", pos);
1704  } else {
1705  pos = atoi (prop->value());
1706  }
1707 
1708  if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1709  rhs_pane1.set_position (pos);
1710  }
1711 
1712  } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1713 
1714  if (done[2]) {
1715  return;
1716  }
1717 
1718  if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1719  pos = 75;
1720  snprintf (buf, sizeof(buf), "%d", pos);
1721  } else {
1722  pos = atoi (prop->value());
1723  }
1724 
1725  if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1726  list_hpane.set_position (pos);
1727  }
1728  }
1729 }
1730 void
1732 {
1733  if (!scroller.get_hscrollbar()) return;
1734  Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1735  /* stupid GTK: can't rely on clamping across versions */
1736  scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
1737 }
1738 
1739 void
1741 {
1742  if (!scroller.get_hscrollbar()) return;
1743  Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1744  /* stupid GTK: can't rely on clamping across versions */
1745  scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
1746 }
1747 
1748 bool
1750 {
1751  /* focus widget gets first shot, then bindings, otherwise
1752  forward to main window
1753  */
1754 
1755  if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
1756  return true;
1757  }
1758 
1759  KeyboardKey k (ev->state, ev->keyval);
1760 
1761  if (bindings.activate (k, Bindings::Press)) {
1762  return true;
1763  }
1764 
1765  return forward_key_press (ev);
1766 }
1767 
1768 bool
1770 {
1771  if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
1772  return true;
1773  }
1774 
1775  KeyboardKey k (ev->state, ev->keyval);
1776 
1777  if (bindings.activate (k, Bindings::Release)) {
1778  return true;
1779  }
1780 
1781  /* don't forward releases */
1782 
1783  return true;
1784 }
1785 
1786 bool
1787 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
1788 {
1789  switch (ev->direction) {
1790  case GDK_SCROLL_LEFT:
1791  scroll_left ();
1792  return true;
1793  case GDK_SCROLL_UP:
1794  if (ev->state & Keyboard::TertiaryModifier) {
1795  scroll_left ();
1796  return true;
1797  }
1798  return false;
1799 
1800  case GDK_SCROLL_RIGHT:
1801  scroll_right ();
1802  return true;
1803 
1804  case GDK_SCROLL_DOWN:
1805  if (ev->state & Keyboard::TertiaryModifier) {
1806  scroll_right ();
1807  return true;
1808  }
1809  return false;
1810  }
1811 
1812  return false;
1813 }
1814 
1815 
1816 void
1818 {
1819  if (p == "show-group-tabs") {
1820  bool const s = _session->config.get_show_group_tabs ();
1821  if (s) {
1822  _group_tabs->show ();
1823  } else {
1824  _group_tabs->hide ();
1825  }
1826  } else if (p == "default-narrow_ms") {
1827  bool const s = ARDOUR_UI::config()->get_default_narrow_ms ();
1828  for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1829  (*i)->set_width_enum (s ? Narrow : Wide, this);
1830  }
1831  } else if (p == "remote-model") {
1833  }
1834 }
1835 
1836 void
1838 {
1839  g->set_active (a, this);
1840 }
1841 
1844 {
1845 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
1846  if (!_plugin_selector)
1847  _plugin_selector = new PluginSelector (PluginManager::instance());
1848 #endif
1849 
1850  return _plugin_selector;
1851 }
1852 
1853 void
1855 {
1856  track_model = ListStore::create (track_columns);
1857  track_display.set_model (track_model);
1858  track_display.append_column (_("Strips"), track_columns.text);
1859  track_display.append_column (_("Show"), track_columns.visible);
1860  track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
1861  track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
1862  track_display.get_column (0)->set_expand(true);
1863  track_display.get_column (1)->set_expand(false);
1864  track_display.get_column (0)->set_sizing (Gtk::TREE_VIEW_COLUMN_FIXED);
1865  track_display.set_name (X_("EditGroupList"));
1866  track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
1867  track_display.set_reorderable (true);
1868  track_display.set_headers_visible (true);
1869 
1870  track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
1871  track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
1872 
1873  CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
1874  track_list_visible_cell->property_activatable() = true;
1875  track_list_visible_cell->property_radio() = false;
1876  track_list_visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::track_visibility_changed));
1877 
1878  track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
1879 
1881  track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1882 
1883  VBox* v = manage (new VBox);
1884  v->show ();
1885  v->pack_start (track_display_scroller, true, true);
1886 
1887  Button* b = manage (new Button);
1888  b->show ();
1889  Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
1890  w->show ();
1891  b->add (*w);
1892 
1893  b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
1894 
1895  v->pack_start (*b, false, false);
1896 
1897  track_display_frame.set_name("BaseFrame");
1898  track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
1899  track_display_frame.add (*v);
1900 
1901  track_display_scroller.show();
1902  track_display_frame.show();
1903  track_display.show();
1904 }
1905 
1906 void
1908 {
1909  ARDOUR_UI::instance()->add_route (this);
1910 }
1911 
1912 
1913 void
1915 {
1916  if (_session) {
1917  string n;
1918 
1919  if (_session->snap_name() != _session->name()) {
1920  n = _session->snap_name ();
1921  } else {
1922  n = _session->name ();
1923  }
1924 
1925  if (_session->dirty ()) {
1926  n = "*" + n;
1927  }
1928 
1929  WindowTitle title (n);
1930  title += S_("Window|Mixer");
1931  title += Glib::get_application_name ();
1932  set_title (title.get_string());
1933 
1934  } else {
1935 
1936  WindowTitle title (S_("Window|Mixer"));
1937  title += Glib::get_application_name ();
1938  set_title (title.get_string());
1939  }
1940 }
1941 
1942 MixerStrip*
1944 {
1945  for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1946  int x1, x2, y;
1947 
1948  (*i)->translate_coordinates (*this, 0, 0, x1, y);
1949  x2 = x1 + (*i)->get_width();
1950 
1951  if (x >= x1 && x <= x2) {
1952  return (*i);
1953  }
1954  }
1955 
1956  return 0;
1957 }
1958 
1959 void
1961 {
1962  _route_targets.clear ();
1963 
1964  if (!_selection.empty()) {
1966  return;
1967  }
1968 
1969 // removed "implicit" selections of strips, after discussion on IRC
1970 
1971 }
1972 
1973 void
1975 {
1976  if (_monitor_section) {
1977  out_packer.remove (_monitor_section->tearoff());
1979  }
1980 }
1981 
1982 void
1984 {
1986  bool onoff = false;
1987 
1989 
1990  for (RouteUISelection::iterator r = _route_targets.begin(); r != _route_targets.end(); ++r) {
1991  boost::shared_ptr<MidiTrack> mt = (*r)->midi_track();
1992 
1993  if (mt) {
1994  rl->push_back ((*r)->route());
1995  onoff = !mt->input_active();
1996  }
1997  }
1998 
1999  _session->set_exclusive_input_active (rl, onoff, flip_others);
2000 }
2001 
2002 void
2004 {
2005  if (_maximised) {
2006  return;
2007  }
2008 
2009  fullscreen ();
2010 
2011  _maximised = true;
2012 }
2013 
2014 void
2016 {
2017  if (!_maximised) {
2018  return;
2019  }
2020 
2021  unfullscreen();
2022 
2023  _maximised = false;
2024 }
TrackDisplayModelColumns track_columns
Definition: mixer_ui.h:244
PBD::Signal0< void > route_groups_reordered
Definition: session.h:508
void set_order_key(uint32_t)
Definition: route.cc:336
PluginSelector * plugin_selector()
Definition: mixer_ui.cc:1843
bool no_track_list_redisplay
Definition: mixer_ui.h:171
bool in_group_row_change
Definition: mixer_ui.h:193
bool _following_editor_selection
Definition: mixer_ui.h:288
void get_window_pos_and_size()
Definition: mixer_ui.cc:1546
bool _maximised
true if we are in fullscreen mode
Definition: mixer_ui.h:293
Gtk::TreeModelColumn< bool > visible
Definition: mixer_ui.h:227
void build_track_menu()
Definition: mixer_ui.cc:1190
int atoi(const string &s)
Definition: convert.cc:140
Gtk::TreeModelColumn< bool > visible
Definition: mixer_ui.h:239
Gtk::Menu * track_menu
Definition: mixer_ui.h:208
void reorder_route_groups(std::list< RouteGroup * >)
PBD::Signal1< void, RouteGroup * > route_group_added
Definition: session.h:506
void set_session(ARDOUR::Session *)
Definition: mixer_ui.cc:745
PBD::Signal0< void > DropReferences
Definition: destructible.h:34
sigc::connection super_rapid_connect(const sigc::slot< void > &slot)
Definition: timers.cc:189
Mixer_UI()
Definition: mixer_ui.cc:87
bool _visible
Definition: mixer_ui.h:102
RouteUISelection _route_targets
Definition: mixer_actor.h:46
bool packed()
Definition: mixer_strip.h:142
const std::string & value() const
Definition: xml++.h:159
PBD::Signal1< void, const PropertyChange & > PropertyChanged
Definition: stateful.h:87
static Mixer_UI * _instance
Definition: mixer_ui.h:100
void session_going_away()
Definition: mixer_ui.cc:792
Glib::RefPtr< Gtk::ListStore > track_model
Definition: mixer_ui.h:250
void maximise_mixer_space()
Definition: mixer_ui.cc:2003
Gtk::VBox global_vpacker
Definition: mixer_ui.h:105
void hide_strip(MixerStrip *)
Definition: mixer_ui.cc:883
LIBARDOUR_API PBD::PropertyDescriptor< bool > hidden
Definition: route_group.h:50
void sync_order_keys()
Definition: session.cc:5510
void scroll_left()
Definition: mixer_ui.cc:1731
Gtk::Button group_display_button
Definition: mixer_ui.h:112
RouteProcessorSelection & selection()
Definition: mixer_actor.h:38
void show_all_audiobus()
Definition: mixer_ui.cc:1012
void route_groups_changed()
Definition: mixer_ui.cc:1299
Definition: ardour_ui.h:130
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
XMLNode * tearoff_settings(const char *) const
Definition: ardour_ui2.cc:204
void delete_processors()
Definition: mixer_ui.cc:422
LIBARDOUR_API PBD::PropertyDescriptor< std::string > name
Gtk::VBox list_vpacker
Definition: mixer_ui.h:110
void set_window_pos_and_size()
Definition: mixer_ui.cc:1539
bool forward_key_press(GdkEventKey *ev)
Definition: utils.cc:317
bool activate(KeyboardKey, Operation)
Definition: bindings.cc:239
Gtk::ScrolledWindow scroller
Definition: mixer_ui.h:106
void set_exclusive_input_active(boost::shared_ptr< RouteList > rt, bool onoff, bool flip_others=false)
Definition: session.cc:3244
Gtk::Frame group_display_frame
Definition: mixer_ui.h:117
void hide_visible()
Definition: tearoff.cc:348
LIBGTKMM2EXT_API Glib::RefPtr< Gtk::Action > get_action(const char *group, const char *name)
Definition: actions.cc:406
Glib::RefPtr< Gtk::ListStore > group_model
Definition: mixer_ui.h:251
std::string name() const
Definition: session.h:166
void remove_route_group(RouteGroup &)
gint stop_updating()
Definition: mixer_ui.cc:907
Width _strip_width
Definition: mixer_ui.h:258
friend class MixerGroupTabs
Definition: mixer_ui.h:285
int m_width
Definition: mixer_ui.h:126
LIBGTKMM2EXT_API void do_action(const char *group, const char *name)
Definition: actions.cc:532
LIBARDOUR_API uint64_t OrderKeys
Definition: debug.cc:61
void * width_owner() const
Definition: mixer_strip.h:86
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
sigc::signal< void > WidthChanged
Definition: mixer_strip.h:113
Gtkmm2ext::TearOff & tearoff() const
bool is_hidden() const
Definition: route_group.h:68
void strip_width_changed()
Definition: mixer_ui.cc:1120
bool is_auditioner() const
Definition: route.h:110
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
Gtkmm2ext::Bindings bindings
Definition: mixer_actor.h:42
void ensure_float(Gtk::Window &)
Definition: mixer_ui.cc:270
SessionConfiguration config
Definition: session.h:866
Gtk::ScrolledWindow group_display_scroller
Definition: mixer_ui.h:114
void strip_property_changed(const PBD::PropertyChange &, MixerStrip *)
Definition: mixer_ui.cc:1209
void route_group_name_edit(const std::string &, const std::string &)
Definition: mixer_ui.cc:1414
void follow_editor_selection()
Definition: mixer_ui.cc:631
bool _route_deletion_in_progress
Definition: mixer_ui.h:280
void track_list_delete(const Gtk::TreeModel::Path &)
Definition: mixer_ui.cc:1041
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
void parameter_changed(std::string)
virtual bool set_marked_for_display(bool)
Definition: axis_view.cc:87
#define invalidator(x)
Definition: gui_thread.h:40
void set_session(ARDOUR::Session *)
Definition: group_tabs.cc:58
Gtk::EventBox scroller_base
Definition: mixer_ui.h:107
bool dirty() const
Definition: session.h:176
GroupDisplayModelColumns group_columns
Definition: mixer_ui.h:245
void toggle_midi_input_active(bool flip_others)
Definition: mixer_ui.cc:1983
void set_all_audio_visibility(int tracks, bool yn)
Definition: mixer_ui.cc:954
gint just_hide_it(GdkEventAny *, Gtk::Window *)
Definition: utils.cc:92
const std::string & get_string()
Definition: window_title.h:53
XMLNode * mixer_settings() const
Definition: ardour_ui.cc:4051
void track_editor_selection()
Definition: mixer_ui.cc:263
Gtk::Menu * get_menu(ARDOUR::RouteGroup *g)
Definition: group_tabs.cc:304
void new_track_or_bus()
Definition: mixer_ui.cc:1907
#define _(Text)
Definition: i18n.h:11
void route_group_row_deleted(Gtk::TreeModel::Path const &)
Definition: mixer_ui.cc:1462
void track_list_reorder(const Gtk::TreeModel::Path &path, const Gtk::TreeModel::iterator &iter, int *new_order)
Definition: mixer_ui.cc:1034
Gtk::TreeModelColumn< MixerStrip * > strip
Definition: mixer_ui.h:230
XMLNode & get_state(void)
Definition: mixer_ui.cc:1628
MonitorSection * _monitor_section
Definition: mixer_ui.h:212
void foreach_route_group(boost::function< void(RouteGroup *)> f)
Definition: session.h:510
#define X_(Text)
Definition: i18n.h:13
void disable_all_route_groups()
Definition: mixer_ui.cc:1293
gboolean configure_handler(GdkEventConfigure *conf)
Definition: ardour_ui.cc:630
XMLProperty * property(const char *)
Definition: xml++.cc:413
uint32_t order_key() const
Definition: route.cc:306
void monitor_section_going_away()
Definition: mixer_ui.cc:1974
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
Gtk::TreeView track_display
Definition: mixer_ui.h:247
Gtk::VBox mixer_scroller_vpacker
Definition: mixer_ui.h:109
bool string_is_affirmative(const std::string &str)
Definition: convert.cc:282
Gtk::TreeModelColumn< std::string > text
Definition: mixer_ui.h:228
Definition: amp.h:29
virtual bool set_name(const std::string &str)
int m_root_x
Definition: mixer_ui.h:126
void restore_mixer_space()
Definition: mixer_ui.cc:2015
PBD::Signal0< void > DirtyChanged
Definition: session.h:180
bool on_key_release_event(GdkEventKey *)
Definition: mixer_ui.cc:1769
Gtk::TreeView group_display
Definition: mixer_ui.h:248
Gtk::Frame track_display_frame
Definition: mixer_ui.h:116
#define gui_context()
Definition: gui_thread.h:36
MixerStrip * strip_by_route(boost::shared_ptr< ARDOUR::Route >)
Definition: mixer_ui.cc:660
Gtk::VBox group_display_vbox
Definition: mixer_ui.h:115
int set_state(const XMLNode &)
Definition: mixer_ui.cc:1553
void setup_track_display()
Definition: mixer_ui.cc:1854
bool deletion_in_progress() const
Definition: session.h:179
void remove_selected_route_group()
Definition: mixer_ui.cc:1341
void set_dirty()
void set_all_strips_visibility(bool yn)
Definition: mixer_ui.cc:924
void deselect_all_strip_processors()
Definition: mixer_ui.cc:407
Gtk::TreeModelColumn< ARDOUR::RouteGroup * > group
Definition: mixer_ui.h:241
void set_hidden(bool yn, void *src)
Definition: route_group.cc:415
std::list< MixerStrip * > strips
Definition: mixer_ui.h:137
boost::shared_ptr< RouteList > get_routes() const
Definition: session.h:229
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
void set_strip_width(Width, bool save=false)
Definition: mixer_ui.cc:1529
Gtk::HBox strip_packer
Definition: mixer_ui.h:119
virtual Selection & get_selection() const =0
bool ignore_reorder
Definition: mixer_ui.h:265
void show_track_list_menu()
Definition: mixer_ui.cc:1169
LIBARDOUR_API XMLNode * find_named_node(const XMLNode &node, std::string name)
void set_packed(bool yn)
Definition: mixer_strip.cc:776
void route_group_row_change(const Gtk::TreeModel::Path &path, const Gtk::TreeModel::iterator &iter)
Definition: mixer_ui.cc:1432
PBD::ScopedConnectionList _session_connections
void parameter_changed(std::string const &)
Definition: mixer_ui.cc:1817
void notify_remote_id_change()
Definition: session.cc:5494
Gtk::ScrolledWindow track_display_scroller
Definition: mixer_ui.h:113
PBD::Signal1< void, std::string > ParameterChanged
Definition: configuration.h:44
gint start_updating()
Definition: mixer_ui.cc:900
bool strip_scroller_button_release(GdkEventButton *)
Definition: mixer_ui.cc:1516
LIBGTKMM2EXT_API void check_toggleaction(std::string)
void remove_strip(MixerStrip *)
Definition: mixer_ui.cc:431
bool hide_window(GdkEventAny *ev)
Definition: mixer_ui.cc:306
void route_group_property_changed(ARDOUR::RouteGroup *, const PBD::PropertyChange &)
Definition: mixer_ui.cc:1366
XMLProperty * add_property(const char *name, const std::string &value)
void fast_update_strips()
Definition: mixer_ui.cc:914
void reset_remote_control_ids()
Definition: mixer_ui.cc:456
void activate_all_route_groups()
Definition: mixer_ui.cc:1287
Gtk::HBox global_hpacker
Definition: mixer_ui.h:104
void show_window()
Definition: mixer_ui.cc:276
static PublicEditor & instance()
Gtk::HBox scroller_hpacker
Definition: mixer_ui.h:108
std::vector< RoutePlusOrderKey > OrderKeySortedRoutes
Definition: route_sorter.h:42
void set_route_group_activation(ARDOUR::RouteGroup *, bool)
Definition: mixer_ui.cc:1837
void show_all_audiotracks()
Definition: mixer_ui.cc:1023
std::string snap_name() const
Definition: session.h:167
void redisplay_track_list()
Definition: mixer_ui.cc:1059
void show_strip(MixerStrip *)
Definition: mixer_ui.cc:866
const char * name
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
Gtk::TreeModelColumn< boost::shared_ptr< ARDOUR::Route > > route
Definition: mixer_ui.h:229
Gtk::Label group_display_button_label
Definition: mixer_ui.h:111
Gtk::TreeModelColumn< std::string > text
Definition: mixer_ui.h:240
void hide_all_routes()
Definition: mixer_ui.cc:1000
bool is_master() const
Definition: route.h:111
void set_width_enum(Width, void *owner)
Definition: mixer_strip.cc:689
PBD::Signal1< void, std::string > StateSaved
Definition: session.h:441
static const int32_t default_height
Definition: mixer_ui.h:274
RouteProcessorSelection _selection
Definition: mixer_actor.h:45
Definition: xml++.h:95
Width
Definition: enums.h:25
std::string name() const
static UIConfiguration * config()
Definition: ardour_ui.h:188
MixerGroupTabs * _group_tabs
Definition: mixer_ui.h:123
bool input_active() const
Definition: midi_track.cc:820
Definition: debug.h:30
bool on_scroll_event(GdkEventScroll *)
Definition: mixer_ui.cc:1787
bool group_display_button_press(GdkEventButton *)
Definition: mixer_ui.cc:1231
MixerStrip * strip_by_x(int x)
Definition: mixer_ui.cc:1943
Width get_width_enum() const
Definition: mixer_strip.h:85
bool on_key_press_event(GdkEventKey *)
Definition: mixer_ui.cc:1749
static const int32_t default_width
Definition: mixer_ui.h:273
#define S_(Text)
Definition: i18n.h:18
PluginSelector * _plugin_selector
Definition: mixer_ui.h:213
void set_session(ARDOUR::Session *)
int m_root_y
Definition: mixer_ui.h:126
void sync_treeview_from_order_keys()
Definition: mixer_ui.cc:574
bool contains(PropertyDescriptor< T > p) const
void set_gui_property(const std::string &property_name, const T &value)
Definition: axis_view.h:66
bool _in_group_rebuild_or_clear
Definition: mixer_ui.h:279
sigc::signal< void > TracksChanged
Definition: selection.h:98
void initial_track_display()
Definition: mixer_ui.cc:1147
virtual void set_session(ARDOUR::Session *)
uint32_t remote_control_id() const
Definition: route.cc:286
static Mixer_UI * instance()
Definition: mixer_ui.cc:78
void set_route_targets_for_operation()
Definition: mixer_ui.cc:1960
void update_title()
Definition: mixer_ui.cc:1914
Gtk::HBox out_packer
Definition: mixer_ui.h:120
void show_all_routes()
Definition: mixer_ui.cc:1006
boost::shared_ptr< ARDOUR::AudioTrack > audio_track() const
Definition: route_ui.cc:1750
void hide_all_audiotracks()
Definition: mixer_ui.cc:1028
void set_remote_control_id_explicit(uint32_t order_key)
Definition: route.cc:312
Definition: enums.h:27
Gtk::HPaned list_hpane
Definition: mixer_ui.h:121
int m_height
Definition: mixer_ui.h:126
bool marked_for_display() const
Definition: axis_view.cc:80
void add_route_group(ARDOUR::RouteGroup *)
Definition: mixer_ui.cc:1485
~Mixer_UI()
Definition: mixer_ui.cc:255
bool track_display_button_press(GdkEventButton *)
Definition: mixer_ui.cc:1179
void scroll_right()
Definition: mixer_ui.cc:1740
std::list< boost::shared_ptr< Route > > RouteList
Definition: types.h:532
void set_active(bool yn, void *src)
Definition: route_group.cc:392
void update_track_visibility()
Definition: mixer_ui.cc:843
static PBD::Signal1< void, MixerStrip * > CatchDeletion
Definition: mixer_strip.h:118
Definition: enums.h:26
bool strip_button_release_event(GdkEventButton *, MixerStrip *)
Definition: mixer_ui.cc:672
void track_visibility_changed(std::string const &path)
Definition: mixer_ui.cc:822
void add_route(Gtk::Window *float_window)
Definition: ardour_ui.cc:3660
void run_new_group_dialog(ARDOUR::RouteList const &)
Definition: group_tabs.cc:419
ARDOUR::Session * _session
boost::shared_ptr< ARDOUR::Route > route() const
Definition: route_ui.h:76
void sync_order_keys_from_treeview()
Definition: mixer_ui.cc:512
void add_strips(ARDOUR::RouteList &)
Definition: mixer_ui.cc:316
void pane_allocation_handler(Gtk::Allocation &, Gtk::Paned *)
Definition: mixer_ui.cc:1673
void hide_all_audiobus()
Definition: mixer_ui.cc:1017
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
void new_route_group()
Definition: mixer_ui.cc:1333
Gtk::VPaned rhs_pane1
Definition: mixer_ui.h:118
sigc::connection fast_screen_update_connection
Definition: mixer_ui.h:165
PBD::Signal0< void > route_group_removed
Definition: session.h:507
void set_state(const XMLNode &)
Definition: tearoff.cc:286
bool is_monitor() const
Definition: route.h:112
PBD::Signal1< void, RouteList & > RouteAdded
Definition: session.h:317
void select_none()
Definition: mixer_ui.cc:415