X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmixer_ui.cc;h=c5a2e947e98d556623f6e581fa50c1ec0eb368d2;hb=refs%2Fheads%2Fcarl-master;hp=5232ab32cf6155f6e6fb2d591f81ff8c8201f9df;hpb=30b087ab3d28f1585987fa3f6ae006562ae192e3;p=ardour.git diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index 5232ab32cf..c5a2e947e9 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -1,21 +1,29 @@ /* - Copyright (C) 2000-2004 Paul Davis - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ + * Copyright (C) 2005-2006 Taybin Rutkin + * Copyright (C) 2005-2018 Paul Davis + * Copyright (C) 2006-2007 Doug McLain + * Copyright (C) 2007-2012 Carl Hetherington + * Copyright (C) 2007-2012 David Robillard + * Copyright (C) 2007-2016 Tim Mayberry + * Copyright (C) 2013-2015 Nick Mainsbridge + * Copyright (C) 2013-2019 Robin Gareus + * Copyright (C) 2014-2018 Ben Loftis + * Copyright (C) 2016-2018 Len Ovens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ #ifdef WAF_BUILD #include "gtk2ardour-config.h" @@ -30,6 +38,7 @@ #include #include +#include #include #include "pbd/convert.h" @@ -40,6 +49,7 @@ #include "ardour/debug.h" #include "ardour/audio_track.h" #include "ardour/midi_track.h" +#include "ardour/monitor_control.h" #include "ardour/plugin_manager.h" #include "ardour/route_group.h" #include "ardour/selection.h" @@ -55,6 +65,7 @@ #include "widgets/tearoff.h" +#include "foldback_strip.h" #include "keyboard.h" #include "mixer_ui.h" #include "mixer_strip.h" @@ -103,19 +114,23 @@ Mixer_UI::Mixer_UI () , no_track_list_redisplay (false) , in_group_row_change (false) , track_menu (0) - , _monitor_section (0) , _plugin_selector (0) + , foldback_strip (0) + , _show_foldback_strip (true) , _strip_width (UIConfiguration::instance().get_default_narrow_ms() ? Narrow : Wide) + , _spill_scroll_position (0) , ignore_reorder (false) , _in_group_rebuild_or_clear (false) , _route_deletion_in_progress (false) , _maximised (false) - , _show_mixer_list (true) - , myactions (X_("mixer")) + , _strip_selection_change_without_scroll (false) , _selection (*this, *this) { - register_actions (); load_bindings (); + register_actions (); + Glib::RefPtr fb_act = ActionManager::get_toggle_action ("Mixer", "ToggleFoldbackStrip"); + fb_act->set_sensitive (false); + _content.set_data ("ardour-bindings", bindings); PresentationInfo::Change.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::presentation_info_changed, this, _1), gui_context()); @@ -134,19 +149,41 @@ Mixer_UI::Mixer_UI () scroller_base.drag_dest_set (target_table); scroller_base.signal_drag_data_received().connect (sigc::mem_fun(*this, &Mixer_UI::scroller_drag_data_received)); - // add as last item of strip packer + /* create a button to add VCA strips ... will get packed in redisplay_track_list() */ + Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON)); + w->show (); + add_vca_button.add (*w); + add_vca_button.set_can_focus(false); + add_vca_button.signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus)); + + /* create a button to add mixer strips */ + w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON)); + w->show (); + add_button.add (*w); + add_button.set_can_focus(false); + add_button.signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus)); + + /* add as last item of strip packer */ strip_packer.pack_end (scroller_base, true, true); + strip_packer.pack_end (add_button, false, false); + +#ifdef MIXBUS + /* create a drop-shadow at the end of the mixer strips */ + mb_shadow.set_size_request( 4, -1 ); + mb_shadow.set_name("EditorWindow"); + mb_shadow.show(); + strip_packer.pack_end (mb_shadow, false, false); +#endif _group_tabs = new MixerGroupTabs (this); - VBox* b = manage (new VBox); - b->set_spacing (0); - b->set_border_width (0); - b->pack_start (*_group_tabs, PACK_SHRINK); - b->pack_start (strip_packer); - b->show_all (); - b->signal_scroll_event().connect (sigc::mem_fun (*this, &Mixer_UI::on_scroll_event), false); - - scroller.add (*b); + strip_group_box.set_spacing (0); + strip_group_box.set_border_width (0); + strip_group_box.pack_start (*_group_tabs, PACK_SHRINK); + strip_group_box.pack_start (strip_packer); + strip_group_box.show_all (); + strip_group_box.signal_scroll_event().connect (sigc::mem_fun (*this, &Mixer_UI::on_scroll_event), false); + + scroller.add (strip_group_box); scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC); setup_track_display (); @@ -187,36 +224,12 @@ Mixer_UI::Mixer_UI () group_display_scroller.add (group_display); group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - HBox* route_group_display_button_box = manage (new HBox()); - - Button* route_group_add_button = manage (new Button ()); - Button* route_group_remove_button = manage (new Button ()); - - Widget* w; - - w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON)); - w->show(); - route_group_add_button->add (*w); - - w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON)); - w->show(); - route_group_remove_button->add (*w); - - route_group_display_button_box->set_homogeneous (true); - - route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group)); - route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group)); - - route_group_display_button_box->add (*route_group_add_button); - route_group_display_button_box->add (*route_group_remove_button); group_display_vbox.pack_start (group_display_scroller, true, true); - group_display_vbox.pack_start (*route_group_display_button_box, false, false); - - group_display_sample.set_name ("BaseFrame"); - group_display_sample.set_shadow_type (Gtk::SHADOW_IN); - group_display_sample.add (group_display_vbox); + group_display_frame.set_name ("BaseFrame"); + group_display_frame.set_shadow_type (Gtk::SHADOW_IN); + group_display_frame.add (group_display_vbox); list target_list; target_list.push_back (TargetEntry ("PluginPresetPtr")); @@ -230,7 +243,6 @@ Mixer_UI::Mixer_UI () favorite_plugins_display.set_headers_visible (true); favorite_plugins_display.set_rules_hint (true); favorite_plugins_display.set_can_focus (false); - favorite_plugins_display.set_tooltip_column (0); favorite_plugins_display.add_object_drag (favorite_plugins_columns.plugin.index(), "PluginFavoritePtr"); favorite_plugins_display.set_drag_column (favorite_plugins_columns.name.index()); favorite_plugins_display.add_drop_targets (target_list); @@ -239,20 +251,27 @@ Mixer_UI::Mixer_UI () favorite_plugins_display.signal_drop.connect (sigc::mem_fun (*this, &Mixer_UI::plugin_drop)); favorite_plugins_display.signal_row_expanded().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state)); favorite_plugins_display.signal_row_collapsed().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state)); + if (UIConfiguration::instance().get_use_tooltips()) { + favorite_plugins_display.set_tooltip_column (0); + } favorite_plugins_model->signal_row_has_child_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::sync_treeview_favorite_ui_state)); favorite_plugins_scroller.add (favorite_plugins_display); favorite_plugins_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - favorite_plugins_sample.set_name ("BaseFrame"); - favorite_plugins_sample.set_shadow_type (Gtk::SHADOW_IN); - favorite_plugins_sample.add (favorite_plugins_scroller); + favorite_plugins_frame.set_name ("BaseFrame"); + favorite_plugins_frame.set_shadow_type (Gtk::SHADOW_IN); + favorite_plugins_frame.add (favorite_plugins_vbox); - rhs_pane1.add (favorite_plugins_sample); - rhs_pane1.add (track_display_sample); + favorite_plugins_vbox.pack_start (favorite_plugins_scroller, true, true); + favorite_plugins_vbox.pack_start (favorite_plugins_tag_combo, false, false); + favorite_plugins_tag_combo.signal_changed().connect (sigc::mem_fun (*this, &Mixer_UI::tag_combo_changed)); + + rhs_pane1.add (favorite_plugins_frame); + rhs_pane1.add (track_display_frame); rhs_pane2.add (rhs_pane1); - rhs_pane2.add (group_display_sample); + rhs_pane2.add (group_display_frame); list_vpacker.pack_start (rhs_pane2, true, true); @@ -262,8 +281,8 @@ Mixer_UI::Mixer_UI () vca_scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); vca_scroller_base.set_name (X_("MixerWindow")); vca_scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::masters_scroller_button_release), false); - vca_hpacker.pack_end (vca_scroller_base, true, true); + vca_hpacker.signal_scroll_event().connect (sigc::mem_fun (*this, &Mixer_UI::on_vca_scroll_event), false); vca_scroller.add (vca_hpacker); vca_scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC); vca_scroller.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release)); @@ -279,7 +298,7 @@ Mixer_UI::Mixer_UI () list_hpane.set_check_divider_position (true); list_hpane.add (list_vpacker); list_hpane.add (global_hpacker); - list_hpane.set_child_minsize (list_vpacker, 1); + list_hpane.set_child_minsize (list_vpacker, 30); XMLNode const * settings = ARDOUR_UI::instance()->mixer_settings(); float fract; @@ -313,10 +332,6 @@ Mixer_UI::Mixer_UI () update_title (); - route_group_display_button_box->show(); - route_group_add_button->show(); - route_group_remove_button->show(); - _content.show (); _content.set_name ("MixerWindow"); @@ -327,12 +342,11 @@ Mixer_UI::Mixer_UI () mixer_scroller_vpacker.show(); list_vpacker.show(); group_display_button_label.show(); - group_display_button.show(); group_display_scroller.show(); favorite_plugins_scroller.show(); group_display_vbox.show(); - group_display_sample.show(); - favorite_plugins_sample.show(); + group_display_frame.show(); + favorite_plugins_frame.show(); rhs_pane1.show(); rhs_pane2.show(); strip_packer.show(); @@ -347,9 +361,16 @@ Mixer_UI::Mixer_UI () list_hpane.show(); group_display.show(); favorite_plugins_display.show(); + add_button.show (); + + XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section")); + if (mnode) { + _monitor_section.tearoff().set_state (*mnode); + } MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context()); VCAMasterStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_master, this, _1), gui_context()); + FoldbackStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_foldback, this, _1), gui_context()); /* handle escape */ @@ -360,27 +381,44 @@ Mixer_UI::Mixer_UI () #else #error implement deferred Plugin-Favorite list #endif - PluginManager::instance ().PluginListChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context()); - PluginManager::instance ().PluginStatusesChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context()); + + PluginManager::instance ().PluginListChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::plugin_list_changed, this), gui_context()); + PluginManager::instance ().PluginStatusChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::plugin_list_changed, this), gui_context()); ARDOUR::Plugin::PresetsChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context()); } Mixer_UI::~Mixer_UI () { - if (_monitor_section) { - monitor_section_detached (); - delete _monitor_section; - } + monitor_section_detached (); + + delete foldback_strip; + foldback_strip = 0; delete _plugin_selector; delete track_menu; } +struct MixerStripSorter { + bool operator() (const MixerStrip* ms_a, const MixerStrip* ms_b) + { + boost::shared_ptr const& a = ms_a->stripable (); + boost::shared_ptr const& b = ms_b->stripable (); + return ARDOUR::Stripable::Sorter(true)(a, b); + } +}; + + void Mixer_UI::escape () { select_none (); } +void +Mixer_UI::tag_combo_changed () +{ + refill_favorite_plugins(); +} + Gtk::Window* Mixer_UI::use_own_window (bool and_fill_it) { @@ -464,6 +502,12 @@ Mixer_UI::masters_scroller_button_release (GdkEventButton* ev) return false; } +void +Mixer_UI::new_masters_created () +{ + ActionManager::get_toggle_action ("Mixer", "ToggleVCAPane")->set_active (true); +} + void Mixer_UI::add_masters (VCAList& vlist) { @@ -546,23 +590,14 @@ Mixer_UI::add_stripables (StripableList& slist) if (route->is_monitor()) { - if (!_monitor_section) { - _monitor_section = new MonitorSection (_session); - - XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section")); - if (mnode) { - _monitor_section->tearoff().set_state (*mnode); - } - } + out_packer.pack_end (_monitor_section.tearoff(), false, false); + _monitor_section.set_session (_session); + _monitor_section.tearoff().show_all (); - out_packer.pack_end (_monitor_section->tearoff(), false, false); - _monitor_section->set_session (_session); - _monitor_section->tearoff().show_all (); + _monitor_section.tearoff().Detach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_detached)); + _monitor_section.tearoff().Attach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_attached)); - _monitor_section->tearoff().Detach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_detached)); - _monitor_section->tearoff().Attach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_attached)); - - if (_monitor_section->tearoff().torn_off()) { + if (_monitor_section.tearoff().torn_off()) { monitor_section_detached (); } else { monitor_section_attached (); @@ -574,6 +609,27 @@ Mixer_UI::add_stripables (StripableList& slist) continue; } + if (route->is_foldbackbus ()) { + if (foldback_strip) { + // last strip created is shown + foldback_strip->set_route (route); + } else { + foldback_strip = new FoldbackStrip (*this, _session, route); + out_packer.pack_start (*foldback_strip, false, false); + // change 0 to 1 below for foldback to right of master + out_packer.reorder_child (*foldback_strip, 0); + foldback_strip->set_packed (true); + } + /* config from last run is set before there are any foldback strips + * this takes that setting and applies it after at least one foldback + * strip exists */ + bool yn = _show_foldback_strip; + Glib::RefPtr act = ActionManager::get_toggle_action ("Mixer", "ToggleFoldbackStrip"); + act->set_sensitive (true); + act->set_active(!yn); + act->set_active(yn); + continue; + } strip = new MixerStrip (*this, _session, route); strips.push_back (strip); @@ -586,7 +642,12 @@ Mixer_UI::add_stripables (StripableList& slist) show_strip (strip); - if (!route->is_master()) { + if (route->is_master()) { + + out_packer.pack_start (*strip, false, false); + strip->set_packed (true); + + } else { TreeModel::Row row = *(track_model->insert (insert_iter)); @@ -594,11 +655,6 @@ Mixer_UI::add_stripables (StripableList& slist) row[stripable_columns.visible] = strip->marked_for_display(); row[stripable_columns.stripable] = route; row[stripable_columns.strip] = strip; - - } else { - - out_packer.pack_start (*strip, false, false); - strip->set_packed (true); } strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed)); @@ -634,16 +690,24 @@ Mixer_UI::deselect_all_strip_processors () } void -Mixer_UI::select_all_tracks () +Mixer_UI::select_none () { - PublicEditor::instance().select_all_tracks (); + _selection.clear_routes(); + deselect_all_strip_processors(); } void -Mixer_UI::select_none () +Mixer_UI::select_next_strip () +{ + deselect_all_strip_processors(); + _session->selection().select_next_stripable (true, false); +} + +void +Mixer_UI::select_prev_strip () { - _selection.clear_routes(); deselect_all_strip_processors(); + _session->selection().select_prev_stripable (true, false); } void @@ -682,6 +746,21 @@ Mixer_UI::remove_strip (MixerStrip* strip) } } +void +Mixer_UI::remove_foldback (FoldbackStrip* strip) +{ + if (_session && _session->deletion_in_progress()) { + /* its all being taken care of */ + return; + } + Glib::RefPtr act = ActionManager::get_toggle_action ("Mixer", "ToggleFoldbackStrip"); + act->set_sensitive (false); + if (foldback_strip) { + foldback_strip->destroy_(); + } + foldback_strip = 0; +} + void Mixer_UI::presentation_info_changed (PropertyChange const & what_changed) { @@ -826,7 +905,7 @@ Mixer_UI::sync_treeview_from_presentation_info (PropertyChange const & what_chan } } - if (!_selection.axes.empty() && !PublicEditor::instance().track_selection_change_without_scroll ()) { + if (!_selection.axes.empty() && !PublicEditor::instance().track_selection_change_without_scroll () && !_strip_selection_change_without_scroll) { move_stripable_into_view ((*_selection.axes.begin())->stripable()); } @@ -906,18 +985,20 @@ Mixer_UI::axis_view_by_control (boost::shared_ptr c) const return 0; } -struct MixerStripSorter { - bool operator() (const MixerStrip* ms_a, const MixerStrip* ms_b) - { - boost::shared_ptr const& a = ms_a->stripable (); - boost::shared_ptr const& b = ms_b->stripable (); - return ARDOUR::Stripable::Sorter(true)(a, b); - } -}; - bool Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip) { + /* Selecting a mixer-strip may also select grouped-tracks, and + * presentation_info_changed() being emitted and + * _selection.axes.begin() is being moved into view. This may + * effectively move the track that was clicked-on out of view. + * + * So here only the track that is actually clicked-on is moved into + * view (in case it's partially visible) + */ + PBD::Unwinder uw (_strip_selection_change_without_scroll, true); + move_stripable_into_view (strip->stripable()); + if (ev->button == 1) { if (_selection.selected (strip)) { /* primary-click: toggle selection state of strip */ @@ -1007,6 +1088,7 @@ void Mixer_UI::set_session (Session* sess) { SessionHandlePtr::set_session (sess); + _monitor_section.set_session (sess); if (_plugin_selector) { _plugin_selector->set_session (_session); @@ -1014,16 +1096,13 @@ Mixer_UI::set_session (Session* sess) _group_tabs->set_session (sess); - if (_monitor_section) { - _monitor_section->set_session (_session); - } - if (!_session) { _selection.clear (); return; } refill_favorite_plugins(); + refill_tag_combo(); XMLNode* node = ARDOUR_UI::instance()->mixer_settings(); set_state (*node, 0); @@ -1041,6 +1120,7 @@ Mixer_UI::set_session (Session* sess) _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context()); _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_masters, this, _1), gui_context()); + _session->vca_manager().VCACreated.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::new_masters_created, this), gui_context()); Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context ()); @@ -1075,8 +1155,14 @@ Mixer_UI::session_going_away () delete (*i); } - if (_monitor_section) { - _monitor_section->tearoff().hide_visible (); + _monitor_section.tearoff().hide_visible (); + StripableList fb; + _session->get_stripables (fb, PresentationInfo::FoldbackBus); + if (fb.size()) { + if (foldback_strip) { + delete foldback_strip; + foldback_strip = 0; + } } monitor_section_detached (); @@ -1125,9 +1211,7 @@ Mixer_UI::update_track_visibility () (*i)[stripable_columns.visible] = av->marked_for_display (); } - /* force presentation catch up with visibility changes - */ - + /* force presentation to catch up with visibility changes */ sync_presentation_info_from_treeview (); } @@ -1220,12 +1304,14 @@ Mixer_UI::set_all_strips_visibility (bool yn) (*i)[stripable_columns.visible] = yn; } + + /* force presentation to catch up with visibility changes */ + sync_presentation_info_from_treeview (); } redisplay_track_list (); } - void Mixer_UI::set_all_audio_midi_visibility (int tracks, bool yn) { @@ -1275,6 +1361,9 @@ Mixer_UI::set_all_audio_midi_visibility (int tracks, bool yn) break; } } + + /* force presentation to catch up with visibility changes */ + sync_presentation_info_from_treeview (); } redisplay_track_list (); @@ -1423,6 +1512,9 @@ Mixer_UI::redisplay_track_list () if (ss) { boost::shared_ptr sv = boost::dynamic_pointer_cast (ss); if (sv) { + if (_spill_scroll_position <= 0 && scroller.get_hscrollbar()) { + _spill_scroll_position = scroller.get_hscrollbar()->get_adjustment()->get_value(); + } spill_redisplay (sv); return; } @@ -1433,7 +1525,12 @@ Mixer_UI::redisplay_track_list () uint32_t n_masters = 0; container_clear (vca_hpacker); + vca_hpacker.pack_end (vca_scroller_base, true, true); + vca_hpacker.pack_end (add_vca_button, false, false); + + add_vca_button.show (); + vca_scroller_base.show(); for (i = rows.begin(); i != rows.end(); ++i) { @@ -1488,14 +1585,35 @@ Mixer_UI::redisplay_track_list () /* update visibility of VCA assign buttons */ if (n_masters == 0) { + //show/hide the channelstrip VCA assign buttons on channelstrips: UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::remove_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA"))); + + Glib::RefPtr act = ActionManager::get_action ("Mixer", "ToggleVCAPane"); + if (act) { + act->set_sensitive (false); + } + + //remove the VCA packer, but don't change our prior setting for show/hide: vca_vpacker.hide (); } else { + //show/hide the channelstrip VCA assign buttons on channelstrips: UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::add_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA"))); - vca_vpacker.show (); + + Glib::RefPtr act = ActionManager::get_toggle_action ("Mixer", "ToggleVCAPane"); + act->set_sensitive (true); + + //if we were showing VCAs before, show them now: + showhide_vcas (act->get_active ()); } _group_tabs->set_dirty (); + + if (_spill_scroll_position > 0 && scroller.get_hscrollbar()) { + Adjustment* adj = scroller.get_hscrollbar()->get_adjustment(); + adj->set_value (max (adj->get_lower(), min (adj->get_upper(), _spill_scroll_position))); + } + _spill_scroll_position = 0; + } void @@ -1544,17 +1662,12 @@ void Mixer_UI::initial_track_display () { StripableList sl; - - boost::shared_ptr routes = _session->get_routes(); - - for (RouteList::iterator r = routes->begin(); r != routes->end(); ++r) { - sl.push_back (*r); - } - - VCAList vcas = _session->vca_manager().vcas(); - - for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) { - sl.push_back (boost::dynamic_pointer_cast (*v)); + StripableList fb; + _session->get_stripables (sl); + _session->get_stripables (fb, PresentationInfo::FoldbackBus); + if (fb.size()) { + boost::shared_ptr _current_foldback = *(fb.begin()); + sl.push_back (_current_foldback); } sl.sort (PresentationInfoMixerSorter()); @@ -1599,15 +1712,56 @@ Mixer_UI::track_display_button_press (GdkEventButton* ev) return false; } +void +Mixer_UI::move_vca_into_view (boost::shared_ptr s) +{ + if (!vca_scroller.get_hscrollbar()) { + return; + } + + bool found = false; + int x0 = 0; + Gtk::Allocation alloc; + + TreeModel::Children rows = track_model->children(); + for (TreeModel::Children::const_iterator i = rows.begin(); i != rows.end(); ++i) { + AxisView* av = (*i)[stripable_columns.strip]; + VCAMasterStrip* vms = dynamic_cast (av); + if (vms && vms->stripable () == s) { + int y; + found = true; + vms->translate_coordinates (vca_hpacker, 0, 0, x0, y); + alloc = vms->get_allocation (); + break; + } + } + + if (!found) { + return; + } + + Adjustment* adj = vca_scroller.get_hscrollbar()->get_adjustment(); + + if (x0 < adj->get_value()) { + adj->set_value (max (adj->get_lower(), min (adj->get_upper(), (double) x0))); + } else if (x0 + alloc.get_width() >= adj->get_value() + adj->get_page_size()) { + int x1 = x0 + alloc.get_width() - adj->get_page_size(); + adj->set_value (max (adj->get_lower(), min (adj->get_upper(), (double) x1))); + } +} + void Mixer_UI::move_stripable_into_view (boost::shared_ptr s) { if (!scroller.get_hscrollbar()) { return; } - if (s->presentation_info().special () || s->presentation_info().flag_match (PresentationInfo::VCA)) { + if (s->presentation_info().special ()) { return; } + if (s->presentation_info().flag_match (PresentationInfo::VCA)) { + move_vca_into_view (s); + } #ifdef MIXBUS if (s->mixbus ()) { return; @@ -1653,10 +1807,10 @@ Mixer_UI::build_track_menu () items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes))); items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks))); items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks))); - items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus))); - items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus))); items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::show_all_miditracks))); items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::hide_all_miditracks))); + items.push_back (MenuElem (_("Show All Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus))); + items.push_back (MenuElem (_("Hide All Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus))); } @@ -1887,34 +2041,103 @@ Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& } void -Mixer_UI::show_mixer_list (bool yn) +Mixer_UI::toggle_mixer_list () +{ + Glib::RefPtr act = ActionManager::get_toggle_action ("Mixer", "ToggleMixerList"); + showhide_mixer_list (act->get_active()); +} + +void +Mixer_UI::showhide_mixer_list (bool yn) { if (yn) { list_vpacker.show (); } else { list_vpacker.hide (); } +} - _show_mixer_list = yn; +void +Mixer_UI::toggle_monitor_section () +{ + Glib::RefPtr act = ActionManager::get_toggle_action ("Mixer", "ToggleMonitorSection"); + showhide_monitor_section (act->get_active()); } + void -Mixer_UI::show_monitor_section (bool yn) +Mixer_UI::showhide_monitor_section (bool yn) { - if (!monitor_section()) { + if (monitor_section().tearoff().torn_off()) { return; } - if (monitor_section()->tearoff().torn_off()) { - return; + + if (yn) { + monitor_section().tearoff().show(); + } else { + monitor_section().tearoff().hide(); + } +} + +void +Mixer_UI::toggle_foldback_strip () +{ + Glib::RefPtr act = ActionManager::get_toggle_action ("Mixer", "ToggleFoldbackStrip"); + showhide_foldback_strip (act->get_active()); +} + + +void +Mixer_UI::showhide_foldback_strip (bool yn) +{ + _show_foldback_strip = yn; + + if (foldback_strip) { + if (yn) { + foldback_strip->show(); + } else { + foldback_strip->hide(); + } } +} + +void +Mixer_UI::toggle_vcas () +{ + Glib::RefPtr act = ActionManager::get_toggle_action ("Mixer", "ToggleVCAPane"); + showhide_vcas (act->get_active()); +} +void +Mixer_UI::showhide_vcas (bool yn) +{ if (yn) { - monitor_section()->tearoff().show(); + vca_vpacker.show(); } else { - monitor_section()->tearoff().hide(); + vca_vpacker.hide(); } } +#ifdef MIXBUS +void +Mixer_UI::toggle_mixbuses () +{ + Glib::RefPtr act = ActionManager::get_toggle_action ("Mixer", "ToggleMixbusPane"); + showhide_mixbuses (act->get_active()); +} + +void +Mixer_UI::showhide_mixbuses (bool on) +{ + if (on) { + mb_vpacker.show(); + } else { + mb_vpacker.hide(); + } +} +#endif + + void Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text) { @@ -2111,40 +2334,69 @@ Mixer_UI::set_state (const XMLNode& node, int version) node.get_property ("show-mixer", _visible); - if (node.get_property ("maximised", yn)) { - Glib::RefPtr act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer")); - assert (act); - Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); - bool fs = tact && tact->get_active(); + yn = false; + node.get_property ("maximised", yn); + { + Glib::RefPtr act = ActionManager::get_toggle_action (X_("Common"), X_("ToggleMaximalMixer")); + bool fs = act && act->get_active(); if (yn ^ fs) { ActionManager::do_action ("Common", "ToggleMaximalMixer"); } } - if (node.get_property ("show-mixer-list", yn)) { - Glib::RefPtr act = ActionManager::get_action (X_("Common"), X_("ToggleMixerList")); - assert (act); - Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); + yn = true; + node.get_property ("show-mixer-list", yn); + { + Glib::RefPtr act = ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleMixerList")); + /* do it twice to force the change */ + act->set_active (!yn); + act->set_active (yn); + } + + yn = true; + node.get_property ("monitor-section-visible", yn); + { + Glib::RefPtr act = ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleMonitorSection")); + /* do it twice to force the change */ + act->set_active (!yn); + act->set_active (yn); + } + yn = true; + node.get_property ("foldback-strip-visible", yn); + { + Glib::RefPtr act = ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleFoldbackStrip")); /* do it twice to force the change */ - tact->set_active (!yn); - tact->set_active (yn); + act->set_active (!yn); + act->set_active (yn); } - if (node.get_property ("monitor-section-visible", yn)) { - Glib::RefPtr act = ActionManager::get_action ("Common", "ToggleMonitorSection"); - Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); + yn = true; + node.get_property ("show-vca-pane", yn); + { + Glib::RefPtr act = ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleVCAPane")); /* do it twice to force the change */ - tact->set_active (yn); - show_monitor_section (yn); + act->set_active (!yn); + act->set_active (yn); } +#ifdef MIXBUS + yn = true; + node.get_property ("show-mixbus-pane", yn); + { + Glib::RefPtr act = ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleMixbusPane")); + /* do it twice to force the change */ + act->set_active (!yn); + act->set_active (yn); + } +#endif - XMLNode* plugin_order; - if ((plugin_order = find_named_node (node, "PluginOrder")) != 0) { + //check for the user's plugin_order file + XMLNode plugin_order_new(X_("PO")); + if (PluginManager::instance().load_plugin_order_file(plugin_order_new)) { store_current_favorite_order (); std::list order; - const XMLNodeList& kids = plugin_order->children("PluginInfo"); + const XMLNodeList& kids = plugin_order_new.children("PluginInfo"); XMLNodeConstIterator i; for (i = kids.begin(); i != kids.end(); ++i) { std::string unique_id; @@ -2158,10 +2410,59 @@ Mixer_UI::set_state (const XMLNode& node, int version) PluginStateSorter cmp (order); favorite_order.sort (cmp); sync_treeview_from_favorite_order (); + + } else { + //if there is no user file, then use an existing one from instant.xml + //NOTE: if you are loading an old session, this might come from the session's instant.xml + //Todo: in the next major version, we should probably stop doing the instant.xml check, and just use the new file + XMLNode* plugin_order; + if ((plugin_order = find_named_node (node, "PluginOrder")) != 0) { + store_current_favorite_order (); + std::list order; + const XMLNodeList& kids = plugin_order->children("PluginInfo"); + XMLNodeConstIterator i; + for (i = kids.begin(); i != kids.end(); ++i) { + std::string unique_id; + if ((*i)->get_property ("unique-id", unique_id)) { + order.push_back (unique_id); + if ((*i)->get_property ("expanded", yn)) { + favorite_ui_state[unique_id] = yn; + } + } + } + + PluginStateSorter cmp (order); + favorite_order.sort (cmp); + sync_treeview_from_favorite_order (); + } } + return 0; } +void +Mixer_UI::save_plugin_order_file () +{ + //this writes the plugin order to the user's preference file ( plugin_metadata/plugin_order ) + + //NOTE: this replaces the old code that stores info in instant.xml + //why? because instant.xml prefers the per-session settings, and we want this to be a global pref + + store_current_favorite_order (); + XMLNode plugin_order ("PluginOrder"); + uint32_t cnt = 0; + for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i, ++cnt) { + XMLNode* p = new XMLNode ("PluginInfo"); + p->set_property ("sort", cnt); + p->set_property ("unique-id", (*i)->unique_id); + if (favorite_ui_state.find ((*i)->unique_id) != favorite_ui_state.end ()) { + p->set_property ("expanded", favorite_ui_state[(*i)->unique_id]); + } + plugin_order.add_child_nocopy (*p); + } + PluginManager::instance().save_plugin_order_file( plugin_order ); +} + XMLNode& Mixer_UI::get_state () { @@ -2176,27 +2477,24 @@ Mixer_UI::get_state () node->set_property ("narrow-strips", (_strip_width == Narrow)); node->set_property ("show-mixer", _visible); - node->set_property ("show-mixer-list", _show_mixer_list); node->set_property ("maximised", _maximised); - Glib::RefPtr act = ActionManager::get_action ("Common", "ToggleMonitorSection"); - Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); - assert (tact); - node->set_property ("monitor-section-visible", tact->get_active ()); + Glib::RefPtr act = ActionManager::get_toggle_action ("Mixer", "ToggleMixerList"); + node->set_property ("show-mixer-list", act->get_active ()); - store_current_favorite_order (); - XMLNode* plugin_order = new XMLNode ("PluginOrder"); - uint32_t cnt = 0; - for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i, ++cnt) { - XMLNode* p = new XMLNode ("PluginInfo"); - p->set_property ("sort", cnt); - p->set_property ("unique-id", (*i)->unique_id); - if (favorite_ui_state.find ((*i)->unique_id) != favorite_ui_state.end ()) { - p->set_property ("expanded", favorite_ui_state[(*i)->unique_id]); - } - plugin_order->add_child_nocopy (*p); - } - node->add_child_nocopy (*plugin_order); + act = ActionManager::get_toggle_action ("Mixer", "ToggleMonitorSection"); + node->set_property ("monitor-section-visible", act->get_active ()); + + act = ActionManager::get_toggle_action ("Mixer", "ToggleFoldbackStrip"); + node->set_property ("foldback-strip-visible", act->get_active ()); + + act = ActionManager::get_toggle_action ("Mixer", "ToggleVCAPane"); + node->set_property ("show-vca-pane", act->get_active ()); + +#ifdef MIXBUS + act = ActionManager::get_toggle_action ("Mixer", "ToggleMixbusPane"); + node->set_property ("show-mixbus-pane", act->get_active ()); +#endif return *node; } @@ -2216,6 +2514,14 @@ Mixer_UI::scroll_left () using namespace Gtk::Box_Helpers; const BoxList& strips = strip_packer.children(); for (BoxList::const_iterator i = strips.begin(); i != strips.end(); ++i) { + if (i->get_widget() == & add_button) { + continue; + } +#ifdef MIXBUS + if (i->get_widget() == &mb_shadow) { + continue; + } +#endif lm += i->get_widget()->get_width (); if (lm >= lp) { lm -= i->get_widget()->get_width (); @@ -2240,6 +2546,14 @@ Mixer_UI::scroll_right () using namespace Gtk::Box_Helpers; const BoxList& strips = strip_packer.children(); for (BoxList::const_iterator i = strips.begin(); i != strips.end(); ++i) { + if (i->get_widget() == & add_button) { + continue; + } +#ifdef MIXBUS + if (i->get_widget() == &mb_shadow) { + continue; + } +#endif lm += i->get_widget()->get_width (); if (lm > lp + 1) { break; @@ -2277,6 +2591,87 @@ Mixer_UI::on_scroll_event (GdkEventScroll* ev) return false; } +void +Mixer_UI::vca_scroll_left () +{ + if (!vca_scroller.get_hscrollbar()) return; + Adjustment* adj = vca_scroller.get_hscrollbar()->get_adjustment(); + int sc_w = vca_scroller.get_width(); + int sp_w = strip_packer.get_width(); + if (sp_w <= sc_w) { + return; + } + int lp = adj->get_value(); + int lm = 0; + using namespace Gtk::Box_Helpers; + const BoxList& strips = vca_hpacker.children(); + for (BoxList::const_iterator i = strips.begin(); i != strips.end(); ++i) { + if (i->get_widget() == &add_vca_button) { + continue; + } + lm += i->get_widget()->get_width (); + if (lm >= lp) { + lm -= i->get_widget()->get_width (); + break; + } + } + vca_scroller.get_hscrollbar()->set_value (max (adj->get_lower(), min (adj->get_upper(), lm - 1.0))); +} + +void +Mixer_UI::vca_scroll_right () +{ + if (!vca_scroller.get_hscrollbar()) return; + Adjustment* adj = vca_scroller.get_hscrollbar()->get_adjustment(); + int sc_w = vca_scroller.get_width(); + int sp_w = strip_packer.get_width(); + if (sp_w <= sc_w) { + return; + } + int lp = adj->get_value(); + int lm = 0; + using namespace Gtk::Box_Helpers; + const BoxList& strips = vca_hpacker.children(); + for (BoxList::const_iterator i = strips.begin(); i != strips.end(); ++i) { + if (i->get_widget() == &add_vca_button) { + continue; + } + lm += i->get_widget()->get_width (); + if (lm > lp + 1) { + break; + } + } + vca_scroller.get_hscrollbar()->set_value (max (adj->get_lower(), min (adj->get_upper(), lm - 1.0))); +} + +bool +Mixer_UI::on_vca_scroll_event (GdkEventScroll* ev) +{ + switch (ev->direction) { + case GDK_SCROLL_LEFT: + vca_scroll_left (); + return true; + case GDK_SCROLL_UP: + if (ev->state & Keyboard::TertiaryModifier) { + vca_scroll_left (); + return true; + } + return false; + + case GDK_SCROLL_RIGHT: + vca_scroll_right (); + return true; + + case GDK_SCROLL_DOWN: + if (ev->state & Keyboard::TertiaryModifier) { + vca_scroll_right (); + return true; + } + return false; + } + + return false; +} void Mixer_UI::parameter_changed (string const & p) @@ -2348,22 +2743,12 @@ Mixer_UI::setup_track_display () v->show (); v->pack_start (track_display_scroller, true, true); - Button* b = manage (new Button); - b->show (); - Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON)); - w->show (); - b->add (*w); - - b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus)); - - v->pack_start (*b, false, false); - - track_display_sample.set_name("BaseFrame"); - track_display_sample.set_shadow_type (Gtk::SHADOW_IN); - track_display_sample.add (*v); + track_display_frame.set_name("BaseFrame"); + track_display_frame.set_shadow_type (Gtk::SHADOW_IN); + track_display_frame.add (*v); track_display_scroller.show(); - track_display_sample.show(); + track_display_frame.show(); track_display.show(); } @@ -2440,29 +2825,27 @@ Mixer_UI::set_axis_targets_for_operation () void Mixer_UI::monitor_section_going_away () { - if (_monitor_section) { - XMLNode* ui_node = Config->extra_xml(X_("UI")); - /* immediate state save. - * - * Tearoff settings are otherwise only stored during - * save_ardour_state(). The mon-section may or may not - * exist at that point. - * */ - if (ui_node) { - XMLNode* tearoff_node = ui_node->child (X_("Tearoffs")); - if (tearoff_node) { - tearoff_node->remove_nodes_and_delete (X_("monitor-section")); - XMLNode* t = new XMLNode (X_("monitor-section")); - _monitor_section->tearoff().add_state (*t); - tearoff_node->add_child_nocopy (*t); - } + XMLNode* ui_node = Config->extra_xml(X_("UI")); + + /* immediate state save. + * + * Tearoff settings are otherwise only stored during + * save_ardour_state(). The mon-section may or may not + * exist at that point. + */ + + if (ui_node) { + XMLNode* tearoff_node = ui_node->child (X_("Tearoffs")); + if (tearoff_node) { + tearoff_node->remove_nodes_and_delete (X_("monitor-section")); + XMLNode* t = new XMLNode (X_("monitor-section")); + _monitor_section.tearoff().add_state (*t); + tearoff_node->add_child_nocopy (*t); } - monitor_section_detached (); - out_packer.remove (_monitor_section->tearoff()); - _monitor_section->set_session (0); - delete _monitor_section; - _monitor_section = 0; } + + monitor_section_detached (); + out_packer.remove (_monitor_section.tearoff()); } void @@ -2518,16 +2901,15 @@ Mixer_UI::restore_mixer_space () void Mixer_UI::monitor_section_attached () { - Glib::RefPtr act = ActionManager::get_action ("Common", "ToggleMonitorSection"); - Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); + Glib::RefPtr act = ActionManager::get_toggle_action ("Mixer", "ToggleMonitorSection"); act->set_sensitive (true); - show_monitor_section (tact->get_active ()); + showhide_monitor_section (act->get_active ()); } void Mixer_UI::monitor_section_detached () { - Glib::RefPtr act = ActionManager::get_action ("Common", "ToggleMonitorSection"); + Glib::RefPtr act = ActionManager::get_action ("Mixer", "ToggleMonitorSection"); act->set_sensitive (false); } @@ -2561,9 +2943,24 @@ Mixer_UI::refiller (PluginInfoList& result, const PluginInfoList& plugs) { PluginManager& manager (PluginManager::instance()); for (PluginInfoList::const_iterator i = plugs.begin(); i != plugs.end(); ++i) { + + /* not a Favorite? skip it */ if (manager.get_status (*i) != PluginManager::Favorite) { continue; } + + /* Check the tag combo selection, and skip this plugin if it doesn't match the selected tag(s) */ + string test = favorite_plugins_tag_combo.get_active_text(); + if (test != _("Show All")) { + vector tags = manager.get_tags(*i); + + //does the selected tag match any of the tags in the plugin? + vector::iterator tt = find (tags.begin(), tags.end(), test); + if (tt == tags.end()) { + continue; + } + } + result.push_back (*i); } } @@ -2626,6 +3023,30 @@ Mixer_UI::refill_favorite_plugins () sync_treeview_from_favorite_order (); } +void +Mixer_UI::plugin_list_changed () +{ + refill_favorite_plugins(); + refill_tag_combo(); +} + +void +Mixer_UI::refill_tag_combo () +{ + PluginManager& mgr (PluginManager::instance()); + + std::vector tags = mgr.get_all_tags (PluginManager::OnlyFavorites); + + favorite_plugins_tag_combo.clear(); + favorite_plugins_tag_combo.append_text (_("Show All")); + + for (vector::iterator t = tags.begin (); t != tags.end (); ++t) { + favorite_plugins_tag_combo.append_text (*t); + } + + favorite_plugins_tag_combo.set_active_text (_("Show All")); +} + void Mixer_UI::sync_treeview_favorite_ui_state (const TreeModel::Path& path, const TreeModel::iterator&) { @@ -2661,6 +3082,9 @@ Mixer_UI::sync_treeview_from_favorite_order () vector presets = (*i)->get_presets (true); for (vector::const_iterator j = presets.begin(); j != presets.end(); ++j) { + if (!(*j).user) { + continue; + } Gtk::TreeModel::Row child_row = *(favorite_plugins_model->append (newrow.children())); child_row[favorite_plugins_columns.name] = (*j).label; child_row[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip, &(*j))); @@ -2678,7 +3102,7 @@ Mixer_UI::popup_note_context_menu (GdkEventButton *ev) { using namespace Gtk::Menu_Helpers; - Gtk::Menu* m = manage (new Menu); + Gtk::Menu* m = ARDOUR_UI::instance()->shared_popup_menu (); MenuList& items = m->items (); if (_selection.axes.empty()) { @@ -2712,7 +3136,7 @@ Mixer_UI::popup_note_context_menu (GdkEventButton *ev) bool Mixer_UI::plugin_row_button_press (GdkEventButton *ev) { - if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3) ) { + if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3)) { TreeModel::Path path; TreeViewColumn* column; int cellx, celly; @@ -2937,48 +3361,57 @@ Mixer_UI::showing_spill_for (boost::shared_ptr s) const return s == spilled_strip.lock(); } -void -Mixer_UI::show_editor_window () const -{ - PublicEditor::instance().make_visible (); -} - void Mixer_UI::register_actions () { - Glib::RefPtr group = myactions.create_action_group (X_("Mixer")); + Glib::RefPtr group = ActionManager::create_action_group (bindings, X_("Mixer")); - myactions.register_action (group, "show-editor", _("Show Editor"), sigc::mem_fun (*this, &Mixer_UI::show_editor_window)); + ActionManager::register_action (group, "solo", _("Toggle Solo on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::solo_action)); + ActionManager::register_action (group, "mute", _("Toggle Mute on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::mute_action)); + ActionManager::register_action (group, "recenable", _("Toggle Rec-enable on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::rec_enable_action)); + ActionManager::register_action (group, "increment-gain", _("Decrease Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::step_gain_up_action)); + ActionManager::register_action (group, "decrement-gain", _("Increase Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::step_gain_down_action)); + ActionManager::register_action (group, "unity-gain", _("Set Gain to 0dB on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::unity_gain_action)); - myactions.register_action (group, "solo", _("Toggle Solo on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::solo_action)); - myactions.register_action (group, "mute", _("Toggle Mute on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::mute_action)); - myactions.register_action (group, "recenable", _("Toggle Rec-enable on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::rec_enable_action)); - myactions.register_action (group, "increment-gain", _("Decrease Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::step_gain_up_action)); - myactions.register_action (group, "decrement-gain", _("Increase Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::step_gain_down_action)); - myactions.register_action (group, "unity-gain", _("Set Gain to 0dB on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::unity_gain_action)); + ActionManager::register_action (group, "copy-processors", _("Copy Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::copy_processors)); + ActionManager::register_action (group, "cut-processors", _("Cut Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::cut_processors)); + ActionManager::register_action (group, "paste-processors", _("Paste Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::paste_processors)); + ActionManager::register_action (group, "delete-processors", _("Delete Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::delete_processors)); + ActionManager::register_action (group, "select-all-processors", _("Select All (visible) Processors"), sigc::mem_fun (*this, &Mixer_UI::select_all_processors)); + ActionManager::register_action (group, "toggle-processors", _("Toggle Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::toggle_processors)); + ActionManager::register_action (group, "ab-plugins", _("Toggle Selected Plugins"), sigc::mem_fun (*this, &Mixer_UI::ab_plugins)); + ActionManager::register_action (group, "select-none", _("Deselect all strips and processors"), sigc::mem_fun (*this, &Mixer_UI::select_none)); - myactions.register_action (group, "copy-processors", _("Copy Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::copy_processors)); - myactions.register_action (group, "cut-processors", _("Cut Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::cut_processors)); - myactions.register_action (group, "paste-processors", _("Paste Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::paste_processors)); - myactions.register_action (group, "delete-processors", _("Delete Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::delete_processors)); - myactions.register_action (group, "select-all-processors", _("Select All (visible) Processors"), sigc::mem_fun (*this, &Mixer_UI::select_all_processors)); - myactions.register_action (group, "toggle-processors", _("Toggle Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::toggle_processors)); - myactions.register_action (group, "ab-plugins", _("Toggle Selected Plugins"), sigc::mem_fun (*this, &Mixer_UI::ab_plugins)); - myactions.register_action (group, "select-none", _("Deselect all strips and processors"), sigc::mem_fun (*this, &Mixer_UI::select_none)); - myactions.register_action (group, "select-all-tracks", _("Select All Tracks"), sigc::mem_fun (*this, &Mixer_UI::select_all_tracks)); + ActionManager::register_action (group, "select-next-stripable", _("Select Next Mixer Strip"), sigc::mem_fun (*this, &Mixer_UI::select_next_strip)); + ActionManager::register_action (group, "select-prev-stripable", _("Scroll Previous Mixer Strip"), sigc::mem_fun (*this, &Mixer_UI::select_prev_strip)); - myactions.register_action (group, "scroll-left", _("Scroll Mixer Window to the left"), sigc::mem_fun (*this, &Mixer_UI::scroll_left)); - myactions.register_action (group, "scroll-right", _("Scroll Mixer Window to the right"), sigc::mem_fun (*this, &Mixer_UI::scroll_right)); + ActionManager::register_action (group, "scroll-left", _("Scroll Mixer Window to the left"), sigc::mem_fun (*this, &Mixer_UI::scroll_left)); + ActionManager::register_action (group, "scroll-right", _("Scroll Mixer Window to the right"), sigc::mem_fun (*this, &Mixer_UI::scroll_right)); - myactions.register_action (group, "toggle-midi-input-active", _("Toggle MIDI Input Active for Mixer-Selected Tracks/Busses"), + ActionManager::register_action (group, "toggle-midi-input-active", _("Toggle MIDI Input Active for Mixer-Selected Tracks/Busses"), sigc::bind (sigc::mem_fun (*this, &Mixer_UI::toggle_midi_input_active), false)); + + ActionManager::register_toggle_action (group, X_("ToggleMixerList"), _("Mixer: Show Mixer List"), sigc::mem_fun (*this, &Mixer_UI::toggle_mixer_list)); + + ActionManager::register_toggle_action (group, X_("ToggleVCAPane"), _("Mixer: Show VCAs"), sigc::mem_fun (*this, &Mixer_UI::toggle_vcas)); + +#ifdef MIXBUS + ActionManager::register_toggle_action (group, X_("ToggleMixbusPane"), _("Mixer: Show Mixbusses"), sigc::mem_fun (*this, &Mixer_UI::toggle_mixbuses)); +#endif + + ActionManager::register_toggle_action (group, X_("ToggleMonitorSection"), _("Mixer: Show Monitor Section"), sigc::mem_fun (*this, &Mixer_UI::toggle_monitor_section)); + + ActionManager::register_toggle_action (group, X_("ToggleFoldbackStrip"), _("Mixer: Show Foldback Strip"), sigc::mem_fun (*this, &Mixer_UI::toggle_foldback_strip)); + + ActionManager::register_toggle_action (group, X_("toggle-disk-monitor"), _("Toggle Disk Monitoring"), sigc::bind (sigc::mem_fun (*this, &Mixer_UI::toggle_monitor_action), MonitorDisk, false, false)); + ActionManager::register_toggle_action (group, X_("toggle-input-monitor"), _("Toggle Input Monitoring"), sigc::bind (sigc::mem_fun (*this, &Mixer_UI::toggle_monitor_action), MonitorInput, false, false)); } void Mixer_UI::load_bindings () { - bindings = Bindings::get_bindings (X_("Mixer"), myactions); + bindings = Bindings::get_bindings (X_("Mixer")); } template void @@ -2996,6 +3429,7 @@ Mixer_UI::control_action (boost::shared_ptr (Stripable::*get_control)() const if (s) { ac = (s.get()->*get_control)(); if (ac) { + ac->start_touch (_session->audible_sample ()); cl->push_back (ac); if (!have_val) { val = !ac->get_value(); @@ -3179,3 +3613,115 @@ Mixer_UI::vca_unassign (boost::shared_ptr vca) } } } + +bool +Mixer_UI::screenshot (std::string const& filename) +{ + if (!_session) { + return false; + } + + int height = strip_packer.get_height(); + bool with_vca = vca_vpacker.is_visible (); + MixerStrip* master = strip_by_route (_session->master_out ()); + + Gtk::OffscreenWindow osw; + Gtk::HBox b; + osw.add (b); + b.show (); + + /* unpack widgets, add to OffscreenWindow */ + + strip_group_box.remove (strip_packer); + b.pack_start (strip_packer, false, false); + /* hide extra elements inside strip_packer */ + add_button.hide (); + scroller_base.hide (); +#ifdef MIXBUS + mb_shadow.hide(); +#endif + + if (with_vca) { + /* work around Gtk::ScrolledWindow */ + Gtk::Viewport* viewport = (Gtk::Viewport*) vca_scroller.get_child(); + viewport->remove (); // << vca_hpacker + b.pack_start (vca_hpacker, false, false); + /* hide some growing widgets */ + add_vca_button.hide (); + vca_scroller_base.hide(); + } + + if (master) { + out_packer.remove (*master); + b.pack_start (*master, false, false); + master->hide_master_spacer (true); + } + + /* prepare the OffscreenWindow for rendering */ + osw.set_size_request (-1, height); + osw.show (); + osw.queue_resize (); + osw.queue_draw (); + osw.get_window()->process_updates (true); + + /* create screenshot */ + Glib::RefPtr pb = osw.get_pixbuf (); + pb->save (filename, "png"); + + /* unpack elements before destorying the Box & OffscreenWindow */ + list children = b.get_children(); + for (list::iterator child = children.begin(); child != children.end(); ++child) { + b.remove (**child); + } + osw.remove (); + + /* now re-pack the widgets into the main mixer window */ + add_button.show (); + scroller_base.show (); +#ifdef MIXBUS + mb_shadow.show(); +#endif + strip_group_box.pack_start (strip_packer); + if (with_vca) { + add_vca_button.show (); + vca_scroller_base.show(); + vca_scroller.add (vca_hpacker); + } + if (master) { + master->hide_master_spacer (false); + out_packer.pack_start (*master, false, false); + } + return true; +} + +void +Mixer_UI::toggle_monitor_action (MonitorChoice monitor_choice, bool group_override, bool all) +{ + MonitorChoice mc; + boost::shared_ptr rl; + + for (AxisViewSelection::iterator i = _selection.axes.begin(); i != _selection.axes.end(); ++i) { + boost::shared_ptr rt = boost::dynamic_pointer_cast ((*i)->stripable()); + + if (rt->monitoring_control()->monitoring_choice() & monitor_choice) { + mc = MonitorChoice (rt->monitoring_control()->monitoring_choice() & ~monitor_choice); + } else { + mc = MonitorChoice (rt->monitoring_control()->monitoring_choice() | monitor_choice); + } + + if (all) { + /* Primary-Tertiary-click applies change to all routes */ + rl = _session->get_routes (); + _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup); + } else if (group_override) { + rl.reset (new RouteList); + rl->push_back (rt); + _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup); + } else { + rl.reset (new RouteList); + rl->push_back (rt); + _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup); + } + + } +}