2 Copyright (C) 2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <sigc++/bind.h>
31 #include "pbd/error.h"
32 #include "pbd/stl_delete.h"
33 #include "pbd/whitespace.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/enumwriter.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm/menu.h>
39 #include <gtkmm/menuitem.h>
40 #include <gtkmm2ext/gtk_ui.h>
41 #include <gtkmm2ext/selector.h>
42 #include <gtkmm2ext/bindable_button.h>
43 #include <gtkmm2ext/utils.h>
45 #include "ardour/amp.h"
46 #include "ardour/meter.h"
47 #include "ardour/event_type_map.h"
48 #include "ardour/pannable.h"
49 #include "ardour/panner.h"
50 #include "ardour/processor.h"
51 #include "ardour/profile.h"
52 #include "ardour/route_group.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
56 #include "evoral/Parameter.hpp"
58 #include "canvas/debug.h"
60 #include "ardour_ui.h"
61 #include "ardour_button.h"
62 #include "audio_streamview.h"
64 #include "route_time_axis.h"
65 #include "automation_time_axis.h"
67 #include "gui_thread.h"
68 #include "item_counts.h"
70 #include "paste_context.h"
71 #include "playlist_selector.h"
72 #include "point_selection.h"
74 #include "public_editor.h"
75 #include "region_view.h"
76 #include "rgb_macros.h"
77 #include "selection.h"
78 #include "streamview.h"
80 #include "ui_config.h"
82 #include "route_group_menu.h"
84 #include "ardour/track.h"
88 using namespace ARDOUR;
89 using namespace ARDOUR_UI_UTILS;
91 using namespace Gtkmm2ext;
93 using namespace Editing;
97 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
99 , TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas)
101 , parent_canvas (canvas)
103 , button_table (3, 3)
104 , route_group_button (S_("RTAV|G"))
105 , playlist_button (S_("RTAV|P"))
106 , automation_button (S_("RTAV|A"))
107 , automation_action_menu (0)
108 , plugins_submenu_item (0)
109 , route_group_menu (0)
110 , playlist_action_menu (0)
112 , color_mode_menu (0)
113 , gm (sess, true, 75, 14)
114 , _ignore_set_layer_display (false)
115 , gain_automation_item(NULL)
116 , trim_automation_item(NULL)
117 , mute_automation_item(NULL)
118 , pan_automation_item(NULL)
120 number_label.set_name("tracknumber label");
121 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
122 number_label.set_alignment(.5, .5);
123 number_label.set_fallthrough_to_parent (true);
125 sess->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::parameter_changed, this, _1), gui_context());
126 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::parameter_changed));
128 parameter_changed ("editor-stereo-only-meters");
132 RouteTimeAxisView::route_property_changed (const PBD::PropertyChange& what_changed)
134 if (what_changed.contains (ARDOUR::Properties::name)) {
140 RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
142 RouteUI::set_route (rt);
144 CANVAS_DEBUG_NAME (_canvas_display, string_compose ("main for %1", rt->name()));
145 CANVAS_DEBUG_NAME (selection_group, string_compose ("selections for %1", rt->name()));
146 CANVAS_DEBUG_NAME (_ghost_group, string_compose ("ghosts for %1", rt->name()));
149 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
152 gm.set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
153 gm.get_level_meter().set_no_show_all();
154 gm.get_level_meter().setup_meters(50, meter_width);
155 gm.update_gain_sensitive ();
157 string str = gui_property ("height");
159 set_height (atoi (str));
161 set_height (preset_height (HeightNormal));
164 if (!_route->is_auditioner()) {
165 if (gui_property ("visible").empty()) {
166 set_gui_property ("visible", true);
169 set_gui_property ("visible", false);
172 timestretch_rect = 0;
175 ignore_toggle = false;
177 route_group_button.set_name ("route button");
178 playlist_button.set_name ("route button");
179 automation_button.set_name ("route button");
181 route_group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
182 playlist_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click), false);
183 automation_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click), false);
187 if (ARDOUR::Profile->get_mixbus()) {
188 controls_table.attach (*rec_enable_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
190 controls_table.attach (*rec_enable_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
193 if (is_midi_track()) {
194 set_tooltip(*rec_enable_button, _("Record (Right-click for Step Edit)"));
195 gm.set_fader_name ("MidiTrackFader");
197 set_tooltip(*rec_enable_button, _("Record"));
198 gm.set_fader_name ("AudioTrackFader");
201 /* set playlist button tip to the current playlist, and make it update when it changes */
202 update_playlist_tip ();
203 track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context());
206 gm.set_fader_name ("AudioBusFader");
207 Gtk::Fixed *blank = manage(new Gtk::Fixed());
208 controls_button_size_group->add_widget(*blank);
209 if (ARDOUR::Profile->get_mixbus() ) {
210 controls_table.attach (*blank, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
212 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
217 top_hbox.pack_end(gm.get_level_meter(), false, false, 2);
219 if (!ARDOUR::Profile->get_mixbus()) {
220 controls_meters_size_group->add_widget (gm.get_level_meter());
223 _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
224 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
225 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
226 _route->track_number_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::label_view, this), gui_context());
228 if (ARDOUR::Profile->get_mixbus()) {
229 controls_table.attach (*mute_button, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
231 controls_table.attach (*mute_button, 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
233 // mute button is always present, it is used to
234 // force the 'blank' placeholders to the proper size
235 controls_button_size_group->add_widget(*mute_button);
237 if (!_route->is_master()) {
238 if (ARDOUR::Profile->get_mixbus()) {
239 controls_table.attach (*solo_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
241 controls_table.attach (*solo_button, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
244 Gtk::Fixed *blank = manage(new Gtk::Fixed());
245 controls_button_size_group->add_widget(*blank);
246 if (ARDOUR::Profile->get_mixbus()) {
247 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
249 controls_table.attach (*blank, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
254 if (ARDOUR::Profile->get_mixbus()) {
255 controls_table.attach (route_group_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
256 controls_table.attach (gm.get_gain_slider(), 3, 5, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
258 else if (!ARDOUR::Profile->get_trx()) {
259 controls_table.attach (route_group_button, 4, 5, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
260 controls_table.attach (gm.get_gain_slider(), 0, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
263 set_tooltip(*solo_button,_("Solo"));
264 set_tooltip(*mute_button,_("Mute"));
265 set_tooltip(route_group_button, _("Route Group"));
267 mute_button->set_tweaks(ArdourButton::TrackHeader);
268 solo_button->set_tweaks(ArdourButton::TrackHeader);
269 rec_enable_button->set_tweaks(ArdourButton::TrackHeader);
270 playlist_button.set_tweaks(ArdourButton::TrackHeader);
271 automation_button.set_tweaks(ArdourButton::TrackHeader);
272 route_group_button.set_tweaks(ArdourButton::TrackHeader);
274 if (is_midi_track()) {
275 set_tooltip(automation_button, _("MIDI Controllers and Automation"));
277 set_tooltip(automation_button, _("Automation"));
280 update_track_number_visibility();
283 if (ARDOUR::Profile->get_mixbus()) {
284 controls_table.attach (automation_button, 1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
286 else if (!ARDOUR::Profile->get_trx()) {
287 controls_table.attach (automation_button, 3, 4, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
290 if (is_track() && track()->mode() == ARDOUR::Normal) {
291 if (ARDOUR::Profile->get_mixbus()) {
292 controls_table.attach (playlist_button, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
294 else if (!ARDOUR::Profile->get_trx()) {
295 controls_table.attach (playlist_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
301 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
305 str = gui_property ("layer-display");
307 set_layer_display (LayerDisplay (string_2_enum (str, _view->layer_display ())));
310 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
311 track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
313 /* pick up the correct freeze state */
318 _editor.ZoomChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_pixel));
319 UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler));
321 PropertyList* plist = new PropertyList();
323 plist->add (ARDOUR::Properties::group_mute, true);
324 plist->add (ARDOUR::Properties::group_solo, true);
326 route_group_menu = new RouteGroupMenu (_session, plist);
328 gm.get_level_meter().signal_scroll_event().connect (sigc::mem_fun (*this, &RouteTimeAxisView::controls_ebox_scroll), false);
331 RouteTimeAxisView::~RouteTimeAxisView ()
333 cleanup_gui_properties ();
335 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
339 delete playlist_action_menu;
340 playlist_action_menu = 0;
345 _automation_tracks.clear ();
347 delete route_group_menu;
348 CatchDeletion (this);
352 RouteTimeAxisView::name() const
355 return _route->name();
361 RouteTimeAxisView::post_construct ()
363 /* map current state of the route */
365 update_diskstream_display ();
366 setup_processor_menu_and_curves ();
367 reset_processor_automation_curves ();
370 /** Set up the processor menu for the current set of processors, and
371 * display automation curves for any parameters which have data.
374 RouteTimeAxisView::setup_processor_menu_and_curves ()
376 _subplugin_menu_map.clear ();
377 subplugin_menu.items().clear ();
378 _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
379 _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
383 RouteTimeAxisView::route_group_click (GdkEventButton *ev)
385 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
386 if (_route->route_group()) {
387 _route->route_group()->remove (_route);
393 r.push_back (route ());
395 route_group_menu->build (r);
396 if (ev->button == 1) {
397 Gtkmm2ext::anchored_menu_popup(route_group_menu->menu(),
401 route_group_menu->menu()->popup (ev->button, ev->time);
408 RouteTimeAxisView::playlist_changed ()
414 RouteTimeAxisView::label_view ()
416 string x = _route->name ();
417 if (x != name_label.get_text ()) {
418 name_label.set_text (x);
420 const int64_t track_number = _route->track_number ();
421 if (track_number == 0) {
422 number_label.set_text ("");
424 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
429 RouteTimeAxisView::update_track_number_visibility ()
432 bool show_label = _session->config.get_track_name_number();
434 if (_route && _route->is_master()) {
438 if (number_label.get_parent()) {
439 controls_table.remove (number_label);
442 if (ARDOUR::Profile->get_mixbus()) {
443 controls_table.attach (number_label, 3, 4, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
445 controls_table.attach (number_label, 0, 1, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
447 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
448 // except the width of the number label is subtracted from the name-hbox, so we
449 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
450 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
452 number_label.set_size_request(tnw, -1);
453 number_label.show ();
455 number_label.hide ();
460 RouteTimeAxisView::parameter_changed (string const & p)
462 if (p == "track-name-number") {
463 update_track_number_visibility();
464 } else if (p == "editor-stereo-only-meters") {
465 if (UIConfiguration::instance().get_editor_stereo_only_meters()) {
466 gm.get_level_meter().set_max_audio_meter_count (2);
468 gm.get_level_meter().set_max_audio_meter_count (0);
474 RouteTimeAxisView::take_name_changed (void *src)
482 RouteTimeAxisView::playlist_click (GdkEventButton *ev)
484 if (ev->button != 1) {
488 build_playlist_menu ();
489 conditionally_add_to_selection ();
490 Gtkmm2ext::anchored_menu_popup(playlist_action_menu, &playlist_button,
496 RouteTimeAxisView::automation_click (GdkEventButton *ev)
498 if (ev->button != 1) {
502 conditionally_add_to_selection ();
503 build_automation_action_menu (false);
504 Gtkmm2ext::anchored_menu_popup(automation_action_menu, &automation_button,
510 RouteTimeAxisView::build_automation_action_menu (bool for_selection)
512 using namespace Menu_Helpers;
514 /* detach subplugin_menu from automation_action_menu before we delete automation_action_menu,
515 otherwise bad things happen (see comment for similar case in MidiTimeAxisView::build_automation_action_menu)
518 detach_menu (subplugin_menu);
520 _main_automation_menu_map.clear ();
521 delete automation_action_menu;
522 automation_action_menu = new Menu;
524 MenuList& items = automation_action_menu->items();
526 automation_action_menu->set_name ("ArdourContextMenu");
528 items.push_back (MenuElem (_("Show All Automation"),
529 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_all_automation), for_selection)));
531 items.push_back (MenuElem (_("Show Existing Automation"),
532 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_existing_automation), for_selection)));
534 items.push_back (MenuElem (_("Hide All Automation"),
535 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::hide_all_automation), for_selection)));
537 /* Attach the plugin submenu. It may have previously been used elsewhere,
538 so it was detached above
541 if (!subplugin_menu.items().empty()) {
542 items.push_back (SeparatorElem ());
543 items.push_back (MenuElem (_("Processor automation"), subplugin_menu));
544 items.back().set_sensitive (!for_selection || _editor.get_selection().tracks.size() == 1);;
547 /* Add any route automation */
550 items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &RouteTimeAxisView::update_gain_track_visibility)));
551 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
552 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
553 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
555 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
559 items.push_back (CheckMenuElem (_("Trim"), sigc::mem_fun (*this, &RouteTimeAxisView::update_trim_track_visibility)));
560 trim_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
561 trim_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
562 (trim_track && string_is_affirmative (trim_track->gui_property ("visible"))));
564 _main_automation_menu_map[Evoral::Parameter(TrimAutomation)] = trim_automation_item;
568 items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &RouteTimeAxisView::update_mute_track_visibility)));
569 mute_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
570 mute_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
571 (mute_track && string_is_affirmative (mute_track->gui_property ("visible"))));
573 _main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item;
576 if (!pan_tracks.empty()) {
577 items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &RouteTimeAxisView::update_pan_track_visibility)));
578 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
579 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
580 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
582 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
583 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
584 _main_automation_menu_map[*p] = pan_automation_item;
590 RouteTimeAxisView::build_display_menu ()
592 using namespace Menu_Helpers;
596 TimeAxisView::build_display_menu ();
598 /* now fill it with our stuff */
600 MenuList& items = display_menu->items();
601 display_menu->set_name ("ArdourContextMenu");
603 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
605 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
607 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
609 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
611 items.push_back (SeparatorElem());
614 detach_menu (*_size_menu);
617 items.push_back (MenuElem (_("Height"), *_size_menu));
618 items.push_back (SeparatorElem());
620 // Hook for derived classes to add type specific stuff
621 append_extra_display_menu_items ();
625 Menu* layers_menu = manage (new Menu);
626 MenuList &layers_items = layers_menu->items();
627 layers_menu->set_name("ArdourContextMenu");
629 RadioMenuItem::Group layers_group;
631 /* Find out how many overlaid/stacked tracks we have in the selection */
635 TrackSelection const & s = _editor.get_selection().tracks;
636 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
637 StreamView* v = (*i)->view ();
642 switch (v->layer_display ()) {
653 /* We're not connecting to signal_toggled() here; in the case where these two items are
654 set to be in the `inconsistent' state, it seems that one or other will end up active
655 as well as inconsistent (presumably due to the RadioMenuItem::Group). Then when you
656 select the active one, no toggled signal is emitted so nothing happens.
659 _ignore_set_layer_display = true;
661 layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid")));
662 RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
663 i->set_active (overlaid != 0 && stacked == 0);
664 i->set_inconsistent (overlaid != 0 && stacked != 0);
665 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true));
667 layers_items.push_back (RadioMenuElem (layers_group, _("Stacked")));
668 i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
669 i->set_active (overlaid == 0 && stacked != 0);
670 i->set_inconsistent (overlaid != 0 && stacked != 0);
671 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
673 _ignore_set_layer_display = false;
675 items.push_back (MenuElem (_("Layers"), *layers_menu));
677 Menu* alignment_menu = manage (new Menu);
678 MenuList& alignment_items = alignment_menu->items();
679 alignment_menu->set_name ("ArdourContextMenu");
681 RadioMenuItem::Group align_group;
683 /* Same verbose hacks as for the layering options above */
689 boost::shared_ptr<Track> first_track;
691 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
692 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
693 if (!r || !r->is_track ()) {
698 first_track = r->track();
701 switch (r->track()->alignment_choice()) {
705 switch (r->track()->alignment_style()) {
706 case ExistingMaterial:
714 case UseExistingMaterial:
730 inconsistent = false;
737 if (!inconsistent && first_track) {
739 alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)")));
740 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
741 i->set_active (automatic != 0 && existing == 0 && capture == 0);
742 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true));
744 switch (first_track->alignment_choice()) {
746 switch (first_track->alignment_style()) {
747 case ExistingMaterial:
748 alignment_items.push_back (MenuElem (_("(Currently: Existing Material)")));
751 alignment_items.push_back (MenuElem (_("(Currently: Capture Time)")));
759 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
760 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
761 i->set_active (existing != 0 && capture == 0 && automatic == 0);
762 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true));
764 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
765 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
766 i->set_active (existing == 0 && capture != 0 && automatic == 0);
767 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true));
769 items.push_back (MenuElem (_("Alignment"), *alignment_menu));
775 Menu* mode_menu = manage (new Menu);
776 MenuList& mode_items = mode_menu->items ();
777 mode_menu->set_name ("ArdourContextMenu");
779 RadioMenuItem::Group mode_group;
785 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
786 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
787 if (!r || !r->is_track ()) {
791 switch (r->track()->mode()) {
804 mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode")));
805 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
806 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal, true));
807 i->set_active (normal != 0 && tape == 0 && non_layered == 0);
808 i->set_inconsistent (normal != 0 && (tape != 0 || non_layered != 0));
810 mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode")));
811 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
812 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive, true));
813 i->set_active (normal == 0 && tape != 0 && non_layered == 0);
814 i->set_inconsistent (tape != 0 && (normal != 0 || non_layered != 0));
816 mode_items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode")));
817 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
818 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered, true));
819 i->set_active (normal == 0 && tape == 0 && non_layered != 0);
820 i->set_inconsistent (non_layered != 0 && (normal != 0 || tape != 0));
822 items.push_back (MenuElem (_("Record Mode"), *mode_menu));
824 items.push_back (SeparatorElem());
826 build_playlist_menu ();
827 items.push_back (MenuElem (_("Playlist"), *playlist_action_menu));
828 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
831 route_group_menu->detach ();
834 for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) {
835 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
837 r.push_back (rtv->route ());
842 r.push_back (route ());
845 route_group_menu->build (r);
846 items.push_back (MenuElem (_("Group"), *route_group_menu->menu ()));
848 build_automation_action_menu (true);
849 items.push_back (MenuElem (_("Automation"), *automation_action_menu));
851 items.push_back (SeparatorElem());
855 TrackSelection const & s = _editor.get_selection().tracks;
856 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
857 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
862 if (r->route()->active()) {
869 items.push_back (CheckMenuElem (_("Active")));
870 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
871 bool click_sets_active = true;
872 if (active > 0 && inactive == 0) {
873 i->set_active (true);
874 click_sets_active = false;
875 } else if (active > 0 && inactive > 0) {
876 i->set_inconsistent (true);
878 i->set_sensitive(! _session->transport_rolling());
879 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), click_sets_active, true));
881 items.push_back (SeparatorElem());
882 items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true)));
883 if (_route && !_route->is_master()) {
884 items.push_back (SeparatorElem());
885 items.push_back (MenuElem (_("Duplicate..."), boost::bind (&ARDOUR_UI::start_duplicate_routes, ARDOUR_UI::instance())));
887 items.push_back (SeparatorElem());
888 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(_editor, &PublicEditor::remove_tracks)));
892 RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection)
894 if (apply_to_selection) {
895 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_track_mode, _1, mode, false));
898 bool needs_bounce = false;
900 if (!track()->can_use_mode (mode, needs_bounce)) {
906 cerr << "would bounce this one\n";
911 track()->set_mode (mode);
916 RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layers, int layer)
918 TimeAxisView::show_timestretch (start, end, layers, layer);
928 /* check that the time selection was made in our route, or our route group.
929 remember that route_group() == 0 implies the route is *not* in a edit group.
932 if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
933 /* this doesn't apply to us */
937 /* ignore it if our edit group is not active */
939 if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
944 if (timestretch_rect == 0) {
945 timestretch_rect = new ArdourCanvas::Rectangle (canvas_display ());
946 timestretch_rect->set_fill_color (ArdourCanvas::HSV (UIConfiguration::instance().color ("time stretch fill")).mod (UIConfiguration::instance().modifier ("time stretch fill")).color());
947 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
950 timestretch_rect->show ();
951 timestretch_rect->raise_to_top ();
953 double const x1 = start / _editor.get_current_zoom();
954 double const x2 = (end - 1) / _editor.get_current_zoom();
956 timestretch_rect->set (ArdourCanvas::Rect (x1, current_height() * (layers - layer - 1) / layers,
957 x2, current_height() * (layers - layer) / layers));
961 RouteTimeAxisView::hide_timestretch ()
963 TimeAxisView::hide_timestretch ();
965 if (timestretch_rect) {
966 timestretch_rect->hide ();
971 RouteTimeAxisView::show_selection (TimeSelection& ts)
975 /* ignore it if our edit group is not active or if the selection was started
976 in some other track or route group (remember that route_group() == 0 means
977 that the track is not in an route group).
980 if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
981 (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
987 TimeAxisView::show_selection (ts);
991 RouteTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
994 bool height_changed = (height == 0) || (h != height);
997 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
1000 gm.get_level_meter().setup_meters (gmlen, meter_width);
1002 TimeAxisView::set_height (h, m);
1005 _view->set_height ((double) current_height());
1008 if (height >= preset_height (HeightNormal)) {
1012 gm.get_gain_slider().show();
1013 mute_button->show();
1014 if (!_route || _route->is_monitor()) {
1015 solo_button->hide();
1017 solo_button->show();
1019 if (rec_enable_button)
1020 rec_enable_button->show();
1022 route_group_button.show();
1023 automation_button.show();
1025 if (is_track() && track()->mode() == ARDOUR::Normal) {
1026 playlist_button.show();
1033 gm.get_gain_slider().hide();
1034 mute_button->show();
1035 if (!_route || _route->is_monitor()) {
1036 solo_button->hide();
1038 solo_button->show();
1040 if (rec_enable_button)
1041 rec_enable_button->show();
1043 route_group_button.hide ();
1044 automation_button.hide ();
1046 if (is_track() && track()->mode() == ARDOUR::Normal) {
1047 playlist_button.hide ();
1052 if (height_changed && !no_redraw) {
1053 /* only emit the signal if the height really changed */
1059 RouteTimeAxisView::route_color_changed ()
1062 _view->apply_color (color(), StreamView::RegionColor);
1065 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1069 RouteTimeAxisView::reset_samples_per_pixel ()
1071 set_samples_per_pixel (_editor.get_current_zoom());
1075 RouteTimeAxisView::set_samples_per_pixel (double fpp)
1080 speed = track()->speed();
1084 _view->set_samples_per_pixel (fpp * speed);
1087 TimeAxisView::set_samples_per_pixel (fpp * speed);
1091 RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
1093 if (!mitem->get_active()) {
1094 /* this is one of the two calls made when these radio menu items change status. this one
1095 is for the item that became inactive, and we want to ignore it.
1100 if (apply_to_selection) {
1101 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
1104 track()->set_align_choice (choice);
1110 RouteTimeAxisView::rename_current_playlist ()
1112 ArdourPrompter prompter (true);
1115 boost::shared_ptr<Track> tr = track();
1116 if (!tr || tr->destructive()) {
1120 boost::shared_ptr<Playlist> pl = tr->playlist();
1125 prompter.set_title (_("Rename Playlist"));
1126 prompter.set_prompt (_("New name for playlist:"));
1127 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1128 prompter.set_initial_text (pl->name());
1129 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1132 if (prompter.run () != Gtk::RESPONSE_ACCEPT) {
1135 prompter.get_result (name);
1136 if (name.length()) {
1137 if (_session->playlists->by_name (name)) {
1138 MessageDialog msg (_("Given playlist name is not unique."));
1140 prompter.set_initial_text (Playlist::bump_name (name, *_session));
1142 pl->set_name (name);
1150 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
1152 std::string ret (basename);
1154 std::string const group_string = "." + route_group()->name() + ".";
1156 // iterate through all playlists
1158 for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1159 std::string tmp = (*i)->name();
1161 std::string::size_type idx = tmp.find(group_string);
1162 // find those which belong to this group
1163 if (idx != string::npos) {
1164 tmp = tmp.substr(idx + group_string.length());
1166 // and find the largest current number
1168 if (x > maxnumber) {
1177 snprintf (buf, sizeof(buf), "%d", maxnumber);
1179 ret = this->name() + "." + route_group()->name () + "." + buf;
1185 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op, bool copy)
1189 boost::shared_ptr<Track> tr = track ();
1190 if (!tr || tr->destructive()) {
1194 boost::shared_ptr<const Playlist> pl = tr->playlist();
1201 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1202 name = resolve_new_group_playlist_name(name,playlists_before_op);
1205 while (_session->playlists->by_name(name)) {
1206 name = Playlist::bump_name (name, *_session);
1210 // TODO: The prompter "new" button should be de-activated if the user
1211 // specifies a playlist name which already exists in the session.
1213 ArdourPrompter prompter (true);
1216 prompter.set_title (_("New Copy Playlist"));
1217 prompter.set_prompt (_("Name for playlist copy:"));
1219 prompter.set_title (_("New Playlist"));
1220 prompter.set_prompt (_("Name for new playlist:"));
1222 prompter.set_initial_text (name);
1223 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1224 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1225 prompter.show_all ();
1228 if (prompter.run () != Gtk::RESPONSE_ACCEPT) {
1231 prompter.get_result (name);
1232 if (name.length()) {
1233 if (_session->playlists->by_name (name)) {
1234 MessageDialog msg (_("Given playlist name is not unique."));
1236 prompter.set_initial_text (Playlist::bump_name (name, *_session));
1244 if (name.length()) {
1246 tr->use_copy_playlist ();
1248 tr->use_new_playlist ();
1250 tr->playlist()->set_name (name);
1255 RouteTimeAxisView::clear_playlist ()
1257 boost::shared_ptr<Track> tr = track ();
1258 if (!tr || tr->destructive()) {
1262 boost::shared_ptr<Playlist> pl = tr->playlist();
1267 _editor.clear_playlist (pl);
1271 RouteTimeAxisView::speed_changed ()
1273 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_pixel, this));
1277 RouteTimeAxisView::update_diskstream_display ()
1287 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1289 if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1291 /* special case: select/deselect all tracks */
1293 _editor.begin_reversible_selection_op (X_("Selection Click"));
1295 if (_editor.get_selection().selected (this)) {
1296 _editor.get_selection().clear_tracks ();
1298 _editor.select_all_tracks ();
1301 _editor.commit_reversible_selection_op ();
1306 _editor.begin_reversible_selection_op (X_("Selection Click"));
1308 switch (ArdourKeyboard::selection_type (ev->state)) {
1309 case Selection::Toggle:
1310 _editor.get_selection().toggle (this);
1313 case Selection::Set:
1314 _editor.get_selection().set (this);
1317 case Selection::Extend:
1318 _editor.extend_selection_to_track (*this);
1321 case Selection::Add:
1322 _editor.get_selection().add (this);
1326 _editor.commit_reversible_selection_op ();
1330 RouteTimeAxisView::set_selected_points (PointSelection& points)
1332 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1333 (*i)->set_selected_points (points);
1335 AudioStreamView* asv = dynamic_cast<AudioStreamView*>(_view);
1337 asv->set_selected_points (points);
1342 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1345 _view->set_selected_regionviews (regions);
1349 /** Add the selectable things that we have to a list.
1350 * @param results List to add things to.
1353 RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results, bool within)
1358 speed = track()->speed();
1361 framepos_t const start_adjusted = session_frame_to_track_frame(start, speed);
1362 framepos_t const end_adjusted = session_frame_to_track_frame(end, speed);
1364 if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1365 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1368 /* pick up visible automation tracks */
1370 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1371 if (!(*i)->hidden()) {
1372 (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1378 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1381 _view->get_inverted_selectables (sel, results);
1384 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1385 if (!(*i)->hidden()) {
1386 (*i)->get_inverted_selectables (sel, results);
1394 RouteTimeAxisView::route_group () const
1396 return _route->route_group();
1399 boost::shared_ptr<Playlist>
1400 RouteTimeAxisView::playlist () const
1402 boost::shared_ptr<Track> tr;
1404 if ((tr = track()) != 0) {
1405 return tr->playlist();
1407 return boost::shared_ptr<Playlist> ();
1412 RouteTimeAxisView::name_entry_changed (string const& str)
1414 if (str == _route->name()) {
1420 strip_whitespace_edges (x);
1426 if (_session->route_name_internal (x)) {
1427 ARDOUR_UI::instance()->popup_error (string_compose (_("The name \"%1\" is reserved for %2"), x, PROGRAM_NAME));
1429 } else if (RouteUI::verify_new_route_name (x)) {
1430 _route->set_name (x);
1437 boost::shared_ptr<Region>
1438 RouteTimeAxisView::find_next_region (framepos_t pos, RegionPoint point, int32_t dir)
1440 boost::shared_ptr<Playlist> pl = playlist ();
1443 return pl->find_next_region (pos, point, dir);
1446 return boost::shared_ptr<Region> ();
1450 RouteTimeAxisView::find_next_region_boundary (framepos_t pos, int32_t dir)
1452 boost::shared_ptr<Playlist> pl = playlist ();
1455 return pl->find_next_region_boundary (pos, dir);
1462 RouteTimeAxisView::fade_range (TimeSelection& selection)
1464 boost::shared_ptr<Playlist> what_we_got;
1465 boost::shared_ptr<Track> tr = track ();
1466 boost::shared_ptr<Playlist> playlist;
1469 /* route is a bus, not a track */
1473 playlist = tr->playlist();
1475 TimeSelection time (selection);
1476 float const speed = tr->speed();
1477 if (speed != 1.0f) {
1478 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1479 (*i).start = session_frame_to_track_frame((*i).start, speed);
1480 (*i).end = session_frame_to_track_frame((*i).end, speed);
1484 playlist->clear_changes ();
1485 playlist->clear_owned_changes ();
1487 playlist->fade_range (time);
1489 vector<Command*> cmds;
1490 playlist->rdiff (cmds);
1491 _session->add_commands (cmds);
1492 _session->add_command (new StatefulDiffCommand (playlist));
1497 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1499 boost::shared_ptr<Playlist> what_we_got;
1500 boost::shared_ptr<Track> tr = track ();
1501 boost::shared_ptr<Playlist> playlist;
1504 /* route is a bus, not a track */
1508 playlist = tr->playlist();
1510 TimeSelection time (selection.time);
1511 float const speed = tr->speed();
1512 if (speed != 1.0f) {
1513 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1514 (*i).start = session_frame_to_track_frame((*i).start, speed);
1515 (*i).end = session_frame_to_track_frame((*i).end, speed);
1519 playlist->clear_changes ();
1520 playlist->clear_owned_changes ();
1524 if (playlist->cut (time) != 0) {
1525 if (Config->get_edit_mode() == Ripple)
1526 playlist->ripple(time.start(), -time.length(), NULL);
1527 // no need to exclude any regions from rippling here
1529 vector<Command*> cmds;
1530 playlist->rdiff (cmds);
1531 _session->add_commands (cmds);
1533 _session->add_command (new StatefulDiffCommand (playlist));
1538 if ((what_we_got = playlist->cut (time)) != 0) {
1539 _editor.get_cut_buffer().add (what_we_got);
1540 if (Config->get_edit_mode() == Ripple)
1541 playlist->ripple(time.start(), -time.length(), NULL);
1542 // no need to exclude any regions from rippling here
1544 vector<Command*> cmds;
1545 playlist->rdiff (cmds);
1546 _session->add_commands (cmds);
1548 _session->add_command (new StatefulDiffCommand (playlist));
1552 if ((what_we_got = playlist->copy (time)) != 0) {
1553 _editor.get_cut_buffer().add (what_we_got);
1558 if ((what_we_got = playlist->cut (time)) != 0) {
1559 if (Config->get_edit_mode() == Ripple)
1560 playlist->ripple(time.start(), -time.length(), NULL);
1561 // no need to exclude any regions from rippling here
1563 vector<Command*> cmds;
1564 playlist->rdiff (cmds);
1565 _session->add_commands (cmds);
1566 _session->add_command (new StatefulDiffCommand (playlist));
1567 what_we_got->release ();
1574 RouteTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1580 boost::shared_ptr<Playlist> pl = playlist ();
1581 const ARDOUR::DataType type = pl->data_type();
1582 PlaylistSelection::const_iterator p = selection.playlists.get_nth(type, ctx.counts.n_playlists(type));
1584 if (p == selection.playlists.end()) {
1587 ctx.counts.increase_n_playlists(type);
1589 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
1591 if (track()->speed() != 1.0f) {
1592 pos = session_frame_to_track_frame (pos, track()->speed());
1593 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
1596 /* add multi-paste offset if applicable */
1597 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent();
1598 const framecnt_t duration = extent.second - extent.first;
1599 pos += _editor.get_paste_offset(pos, ctx.count, duration);
1601 pl->clear_changes ();
1602 pl->clear_owned_changes ();
1603 if (Config->get_edit_mode() == Ripple) {
1604 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
1605 framecnt_t amount = extent.second - extent.first;
1606 pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
1608 pl->paste (*p, pos, ctx.times, sub_num);
1610 vector<Command*> cmds;
1612 _session->add_commands (cmds);
1614 _session->add_command (new StatefulDiffCommand (pl));
1620 struct PlaylistSorter {
1621 bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1622 return a->sort_id() < b->sort_id();
1627 RouteTimeAxisView::build_playlist_menu ()
1629 using namespace Menu_Helpers;
1635 delete playlist_action_menu;
1636 playlist_action_menu = new Menu;
1637 playlist_action_menu->set_name ("ArdourContextMenu");
1639 MenuList& playlist_items = playlist_action_menu->items();
1640 playlist_action_menu->set_name ("ArdourContextMenu");
1641 playlist_items.clear();
1643 RadioMenuItem::Group playlist_group;
1644 boost::shared_ptr<Track> tr = track ();
1646 vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
1648 /* sort the playlists */
1650 sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1652 /* add the playlists to the menu */
1653 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1654 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1655 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1656 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1658 if (tr->playlist()->id() == (*i)->id()) {
1664 playlist_items.push_back (SeparatorElem());
1665 playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1666 playlist_items.push_back (SeparatorElem());
1668 if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1669 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1670 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1673 // Use a label which tells the user what is happening
1674 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1675 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1679 playlist_items.push_back (SeparatorElem());
1680 playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1681 playlist_items.push_back (SeparatorElem());
1683 playlist_items.push_back (MenuElem(_("Select from All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1687 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1689 assert (is_track());
1691 // exit if we were triggered by deactivating the old playlist
1692 if (!item->get_active()) {
1696 boost::shared_ptr<Playlist> pl (wpl.lock());
1702 if (track()->playlist() == pl) {
1703 // exit when use_playlist is called by the creation of the playlist menu
1704 // or the playlist choice is unchanged
1708 track()->use_playlist (pl);
1710 RouteGroup* rg = route_group();
1712 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1713 std::string group_string = "." + rg->name() + ".";
1715 std::string take_name = pl->name();
1716 std::string::size_type idx = take_name.find(group_string);
1718 if (idx == std::string::npos)
1721 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1723 boost::shared_ptr<RouteList> rl (rg->route_list());
1725 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1726 if ((*i) == this->route()) {
1730 std::string playlist_name = (*i)->name()+group_string+take_name;
1732 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1737 if (track->freeze_state() == Track::Frozen) {
1738 /* Don't change playlists of frozen tracks */
1742 boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1744 // No playlist for this track for this take yet, make it
1745 track->use_new_playlist();
1746 track->playlist()->set_name(playlist_name);
1748 track->use_playlist(ipl);
1755 RouteTimeAxisView::update_playlist_tip ()
1757 RouteGroup* rg = route_group ();
1758 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1759 string group_string = "." + rg->name() + ".";
1761 string take_name = track()->playlist()->name();
1762 string::size_type idx = take_name.find(group_string);
1764 if (idx != string::npos) {
1765 /* find the bit containing the take number / name */
1766 take_name = take_name.substr (idx + group_string.length());
1768 /* set the playlist button tooltip to the take name */
1771 string_compose(_("Take: %1.%2"),
1772 Gtkmm2ext::markup_escape_text (rg->name()),
1773 Gtkmm2ext::markup_escape_text (take_name))
1780 /* set the playlist button tooltip to the playlist name */
1781 set_tooltip (playlist_button, _("Playlist") + std::string(": ") + Gtkmm2ext::markup_escape_text (track()->playlist()->name()));
1786 RouteTimeAxisView::show_playlist_selector ()
1788 _editor.playlist_selector().show_for (this);
1792 RouteTimeAxisView::map_frozen ()
1798 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1800 switch (track()->freeze_state()) {
1802 playlist_button.set_sensitive (false);
1805 playlist_button.set_sensitive (true);
1808 RouteUI::map_frozen ();
1812 RouteTimeAxisView::color_handler ()
1814 //case cTimeStretchOutline:
1815 if (timestretch_rect) {
1816 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
1818 //case cTimeStretchFill:
1819 if (timestretch_rect) {
1820 timestretch_rect->set_fill_color (UIConfiguration::instance().color ("time stretch fill"));
1826 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1827 * Will add track if necessary.
1830 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1832 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1833 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1836 /* it doesn't exist yet, so we don't care about the button state: just add it */
1837 create_automation_child (param, true);
1840 bool yn = menu->get_active();
1841 bool changed = false;
1843 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1845 /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1846 will have done that for us.
1849 if (changed && !no_redraw) {
1857 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1859 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1865 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1867 if (menu && !_hidden) {
1868 ignore_toggle = true;
1869 menu->set_active (false);
1870 ignore_toggle = false;
1873 if (_route && !no_redraw) {
1879 RouteTimeAxisView::update_gain_track_visibility ()
1881 bool const showit = gain_automation_item->get_active();
1883 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1884 gain_track->set_marked_for_display (showit);
1886 /* now trigger a redisplay */
1889 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1895 RouteTimeAxisView::update_trim_track_visibility ()
1897 bool const showit = trim_automation_item->get_active();
1899 if (showit != string_is_affirmative (trim_track->gui_property ("visible"))) {
1900 trim_track->set_marked_for_display (showit);
1902 /* now trigger a redisplay */
1905 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1911 RouteTimeAxisView::update_mute_track_visibility ()
1913 bool const showit = mute_automation_item->get_active();
1915 if (showit != string_is_affirmative (mute_track->gui_property ("visible"))) {
1916 mute_track->set_marked_for_display (showit);
1918 /* now trigger a redisplay */
1921 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1927 RouteTimeAxisView::update_pan_track_visibility ()
1929 bool const showit = pan_automation_item->get_active();
1930 bool changed = false;
1932 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1933 if ((*i)->set_marked_for_display (showit)) {
1939 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1944 RouteTimeAxisView::ensure_pan_views (bool show)
1946 bool changed = false;
1947 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1949 (*i)->set_marked_for_display (false);
1952 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1956 if (!_route->panner()) {
1960 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1961 set<Evoral::Parameter>::iterator p;
1963 for (p = params.begin(); p != params.end(); ++p) {
1964 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1966 if (pan_control->parameter().type() == NullAutomation) {
1967 error << "Pan control has NULL automation type!" << endmsg;
1971 if (automation_child (pan_control->parameter ()).get () == 0) {
1973 /* we don't already have an AutomationTimeAxisView for this parameter */
1975 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1977 boost::shared_ptr<AutomationTimeAxisView> t (
1978 new AutomationTimeAxisView (_session,
1982 pan_control->parameter (),
1990 pan_tracks.push_back (t);
1991 add_automation_child (*p, t, show);
1993 pan_tracks.push_back (automation_child (pan_control->parameter ()));
2000 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
2002 if (apply_to_selection) {
2003 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
2007 /* Show our automation */
2009 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2010 i->second->set_marked_for_display (true);
2012 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2015 menu->set_active(true);
2020 /* Show processor automation */
2022 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2023 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2024 if ((*ii)->view == 0) {
2025 add_processor_automation_curve ((*i)->processor, (*ii)->what);
2028 (*ii)->menu_item->set_active (true);
2041 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
2043 if (apply_to_selection) {
2044 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
2048 /* Show our automation */
2050 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2051 if (i->second->has_automation()) {
2052 i->second->set_marked_for_display (true);
2054 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2056 menu->set_active(true);
2061 /* Show processor automation */
2063 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2064 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2065 if ((*i)->processor->control((*ii)->what)->list()->size() > 0) {
2066 (*ii)->menu_item->set_active (true);
2078 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
2080 if (apply_to_selection) {
2081 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
2085 /* Hide our automation */
2087 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2088 i->second->set_marked_for_display (false);
2090 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2093 menu->set_active (false);
2097 /* Hide processor automation */
2099 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2100 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2101 (*ii)->menu_item->set_active (false);
2112 RouteTimeAxisView::region_view_added (RegionView* rv)
2114 /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
2115 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
2116 boost::shared_ptr<AutomationTimeAxisView> atv;
2118 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
2123 for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
2124 (*i)->add_ghost(rv);
2128 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
2130 for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
2136 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
2138 parent.remove_processor_automation_node (this);
2142 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
2145 remove_child (pan->view);
2149 RouteTimeAxisView::ProcessorAutomationNode*
2150 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2152 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2154 if ((*i)->processor == processor) {
2156 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2157 if ((*ii)->what == what) {
2167 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
2169 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2172 ProcessorAutomationNode* pan;
2174 if ((pan = find_processor_automation_node (processor, what)) == 0) {
2175 /* session state may never have been saved with new plugin */
2176 error << _("programming error: ")
2177 << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
2178 processor->name(), what.type(), (int) what.channel(), what.id() )
2180 abort(); /*NOTREACHED*/
2188 boost::shared_ptr<AutomationControl> control
2189 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
2191 pan->view = boost::shared_ptr<AutomationTimeAxisView>(
2192 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
2193 _editor, *this, false, parent_canvas,
2194 processor->describe_parameter (what), processor->name()));
2196 pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
2198 add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
2201 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
2206 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
2209 pan->menu_item->set_active (false);
2218 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
2220 boost::shared_ptr<Processor> processor (p.lock ());
2222 if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
2223 /* The Amp processor is a special case and is dealt with separately */
2227 set<Evoral::Parameter> existing;
2229 processor->what_has_data (existing);
2231 for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
2233 Evoral::Parameter param (*i);
2234 boost::shared_ptr<AutomationLine> al;
2236 if ((al = find_processor_automation_curve (processor, param)) != 0) {
2239 add_processor_automation_curve (processor, param);
2245 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
2247 using namespace Menu_Helpers;
2251 track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
2253 _automation_tracks[param] = track;
2255 /* existing state overrides "show" argument */
2256 string s = track->gui_property ("visible");
2258 show = string_is_affirmative (s);
2261 /* this might or might not change the visibility status, so don't rely on it */
2262 track->set_marked_for_display (show);
2264 if (show && !no_redraw) {
2268 if (!ARDOUR::parameter_is_midi((AutomationType)param.type())) {
2269 /* MIDI-related parameters are always in the menu, there's no
2270 reason to rebuild the menu just because we added a automation
2271 lane for one of them. But if we add a non-MIDI automation
2272 lane, then we need to invalidate the display menu.
2274 delete display_menu;
2280 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2282 boost::shared_ptr<Processor> processor (p.lock ());
2284 if (!processor || !processor->display_to_user ()) {
2288 /* we use this override to veto the Amp processor from the plugin menu,
2289 as its automation lane can be accessed using the special "Fader" menu
2293 if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2297 using namespace Menu_Helpers;
2298 ProcessorAutomationInfo *rai;
2299 list<ProcessorAutomationInfo*>::iterator x;
2301 const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2303 if (automatable.empty()) {
2307 for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2308 if ((*x)->processor == processor) {
2313 if (x == processor_automation.end()) {
2314 rai = new ProcessorAutomationInfo (processor);
2315 processor_automation.push_back (rai);
2320 /* any older menu was deleted at the top of processors_changed()
2321 when we cleared the subplugin menu.
2324 rai->menu = manage (new Menu);
2325 MenuList& items = rai->menu->items();
2326 rai->menu->set_name ("ArdourContextMenu");
2330 std::set<Evoral::Parameter> has_visible_automation;
2331 AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2333 for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2335 ProcessorAutomationNode* pan;
2336 Gtk::CheckMenuItem* mitem;
2338 string name = processor->describe_parameter (*i);
2340 if (name == X_("hidden")) {
2344 items.push_back (CheckMenuElem (name));
2345 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2347 _subplugin_menu_map[*i] = mitem;
2349 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2350 mitem->set_active(true);
2353 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2357 pan = new ProcessorAutomationNode (*i, mitem, *this);
2359 rai->lines.push_back (pan);
2363 pan->menu_item = mitem;
2367 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2370 if (items.size() == 0) {
2374 /* add the menu for this processor, because the subplugin
2375 menu is always cleared at the top of processors_changed().
2376 this is the result of some poor design in gtkmm and/or
2380 subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2385 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2386 RouteTimeAxisView::ProcessorAutomationNode* pan)
2388 bool showit = pan->menu_item->get_active();
2389 bool redraw = false;
2391 if (pan->view == 0 && showit) {
2392 add_processor_automation_curve (rai->processor, pan->what);
2396 if (pan->view && pan->view->set_marked_for_display (showit)) {
2400 if (redraw && !no_redraw) {
2406 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2408 if (c.type == RouteProcessorChange::MeterPointChange) {
2409 /* nothing to do if only the meter point has changed */
2413 using namespace Menu_Helpers;
2415 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2416 (*i)->valid = false;
2419 setup_processor_menu_and_curves ();
2421 bool deleted_processor_automation = false;
2423 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2425 list<ProcessorAutomationInfo*>::iterator tmp;
2433 processor_automation.erase (i);
2434 deleted_processor_automation = true;
2441 if (deleted_processor_automation && !no_redraw) {
2446 boost::shared_ptr<AutomationLine>
2447 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2449 ProcessorAutomationNode* pan;
2451 if ((pan = find_processor_automation_node (processor, what)) != 0) {
2457 return boost::shared_ptr<AutomationLine>();
2461 RouteTimeAxisView::reset_processor_automation_curves ()
2463 for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2469 RouteTimeAxisView::can_edit_name () const
2471 /* we do not allow track name changes if it is record enabled
2473 boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track> (_route));
2477 return !trk->rec_enable_control()->get_value();
2481 RouteTimeAxisView::blink_rec_display (bool onoff)
2483 RouteUI::blink_rec_display (onoff);
2487 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2489 if (_ignore_set_layer_display) {
2493 if (apply_to_selection) {
2494 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2498 _view->set_layer_display (d);
2501 set_gui_property (X_("layer-display"), enum_2_string (d));
2506 RouteTimeAxisView::layer_display () const
2509 return _view->layer_display ();
2512 /* we don't know, since we don't have a _view, so just return something */
2518 boost::shared_ptr<AutomationTimeAxisView>
2519 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2521 AutomationTracks::iterator i = _automation_tracks.find(param);
2522 if (i != _automation_tracks.end()) {
2525 return boost::shared_ptr<AutomationTimeAxisView>();
2530 RouteTimeAxisView::fast_update ()
2532 gm.get_level_meter().update_meters ();
2536 RouteTimeAxisView::hide_meter ()
2539 gm.get_level_meter().hide_meters ();
2543 RouteTimeAxisView::show_meter ()
2549 RouteTimeAxisView::reset_meter ()
2551 if (UIConfiguration::instance().get_show_track_meters()) {
2552 int meter_width = 3;
2553 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2556 gm.get_level_meter().setup_meters (height - 9, meter_width);
2563 RouteTimeAxisView::clear_meter ()
2565 gm.get_level_meter().clear_meters ();
2569 RouteTimeAxisView::meter_changed ()
2571 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2573 if (_route && !no_redraw && UIConfiguration::instance().get_show_track_meters()) {
2576 // reset peak when meter point changes
2577 gm.reset_peak_display();
2581 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2584 if (_route && !no_redraw) {
2590 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2592 using namespace Menu_Helpers;
2594 if (!_underlay_streams.empty()) {
2595 MenuList& parent_items = parent_menu->items();
2596 Menu* gs_menu = manage (new Menu);
2597 gs_menu->set_name ("ArdourContextMenu");
2598 MenuList& gs_items = gs_menu->items();
2600 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2602 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2603 gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2604 sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2610 RouteTimeAxisView::set_underlay_state()
2612 if (!underlay_xml_node) {
2616 XMLNodeList nlist = underlay_xml_node->children();
2617 XMLNodeConstIterator niter;
2618 XMLNode *child_node;
2620 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2621 child_node = *niter;
2623 if (child_node->name() != "Underlay") {
2627 XMLProperty const * prop = child_node->property ("id");
2629 PBD::ID id (prop->value());
2631 RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2634 add_underlay(v->view(), false);
2643 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2649 RouteTimeAxisView& other = v->trackview();
2651 if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2652 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2653 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2654 abort(); /*NOTREACHED*/
2657 _underlay_streams.push_back(v);
2658 other._underlay_mirrors.push_back(this);
2660 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2662 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2664 if (!underlay_xml_node) {
2665 underlay_xml_node = xml_node->add_child("Underlays");
2668 XMLNode* node = underlay_xml_node->add_child("Underlay");
2669 XMLProperty const * prop = node->add_property("id");
2670 prop->set_value(v->trackview().route()->id().to_s());
2677 RouteTimeAxisView::remove_underlay (StreamView* v)
2683 UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2684 RouteTimeAxisView& other = v->trackview();
2686 if (it != _underlay_streams.end()) {
2687 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2689 if (gm == other._underlay_mirrors.end()) {
2690 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2691 abort(); /*NOTREACHED*/
2694 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2696 _underlay_streams.erase(it);
2697 other._underlay_mirrors.erase(gm);
2699 if (underlay_xml_node) {
2700 underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2706 RouteTimeAxisView::set_button_names ()
2708 if (_route && _route->solo_safe_control()->solo_safe()) {
2709 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2711 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2713 if (Config->get_solo_control_is_listen_control()) {
2714 switch (Config->get_listen_position()) {
2715 case AfterFaderListen:
2716 solo_button->set_text (S_("AfterFader|A"));
2717 set_tooltip (*solo_button, _("After-fade listen (AFL)"));
2719 case PreFaderListen:
2720 solo_button->set_text (S_("PreFader|P"));
2721 set_tooltip (*solo_button, _("Pre-fade listen (PFL)"));
2725 solo_button->set_text (S_("Solo|S"));
2726 set_tooltip (*solo_button, _("Solo"));
2728 mute_button->set_text (S_("Mute|M"));
2732 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2734 ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
2735 if (i != _main_automation_menu_map.end()) {
2739 i = _subplugin_menu_map.find (param);
2740 if (i != _subplugin_menu_map.end()) {
2748 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2750 boost::shared_ptr<AutomationControl> c = _route->gain_control();
2752 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2756 gain_track.reset (new AutomationTimeAxisView (_session,
2757 _route, _route->amp(), c, param,
2762 _route->amp()->describe_parameter(param)));
2765 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2768 add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2772 RouteTimeAxisView::create_trim_automation_child (const Evoral::Parameter& param, bool show)
2774 boost::shared_ptr<AutomationControl> c = _route->trim()->gain_control();
2775 if (!c || ! _route->trim()->active()) {
2779 trim_track.reset (new AutomationTimeAxisView (_session,
2780 _route, _route->trim(), c, param,
2785 _route->trim()->describe_parameter(param)));
2788 _view->foreach_regionview (sigc::mem_fun (*trim_track.get(), &TimeAxisView::add_ghost));
2791 add_automation_child (Evoral::Parameter(TrimAutomation), trim_track, show);
2795 RouteTimeAxisView::create_mute_automation_child (const Evoral::Parameter& param, bool show)
2797 boost::shared_ptr<AutomationControl> c = _route->mute_control();
2799 error << "Route has no mute automation, unable to add automation track view." << endmsg;
2803 mute_track.reset (new AutomationTimeAxisView (_session,
2804 _route, _route, c, param,
2809 _route->describe_parameter(param)));
2812 _view->foreach_regionview (sigc::mem_fun (*mute_track.get(), &TimeAxisView::add_ghost));
2815 add_automation_child (Evoral::Parameter(MuteAutomation), mute_track, show);
2819 void add_region_to_list (RegionView* rv, RegionList* l)
2821 l->push_back (rv->region());
2825 RouteTimeAxisView::combine_regions ()
2827 /* as of may 2011, we do not offer uncombine for MIDI tracks
2830 if (!is_audio_track()) {
2838 RegionList selected_regions;
2839 boost::shared_ptr<Playlist> playlist = track()->playlist();
2841 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2843 if (selected_regions.size() < 2) {
2847 playlist->clear_changes ();
2848 boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2850 _session->add_command (new StatefulDiffCommand (playlist));
2851 /* make the new region be selected */
2853 return _view->find_view (compound_region);
2857 RouteTimeAxisView::uncombine_regions ()
2859 /* as of may 2011, we do not offer uncombine for MIDI tracks
2861 if (!is_audio_track()) {
2869 RegionList selected_regions;
2870 boost::shared_ptr<Playlist> playlist = track()->playlist();
2872 /* have to grab selected regions first because the uncombine is going
2873 * to change that in the middle of the list traverse
2876 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2878 playlist->clear_changes ();
2880 for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2881 playlist->uncombine (*i);
2884 _session->add_command (new StatefulDiffCommand (playlist));
2888 RouteTimeAxisView::state_id() const
2890 return string_compose ("rtav %1", _route->id().to_s());
2895 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2897 TimeAxisView::remove_child (c);
2899 boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2901 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2902 if (i->second == a) {
2903 _automation_tracks.erase (i);
2911 RouteTimeAxisView::color () const
2913 return route_color ();
2917 RouteTimeAxisView::marked_for_display () const
2919 return !_route->presentation_info().hidden();
2923 RouteTimeAxisView::set_marked_for_display (bool yn)
2925 return RouteUI::mark_hidden (!yn);