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 <gtkmm/menu.h>
32 #include <gtkmm/menuitem.h>
33 #include <gtkmm/stock.h>
35 #include "pbd/error.h"
36 #include "pbd/stl_delete.h"
37 #include "pbd/whitespace.h"
38 #include "pbd/memento_command.h"
39 #include "pbd/enumwriter.h"
40 #include "pbd/stateful_diff_command.h"
42 #include "evoral/Parameter.hpp"
44 #include "ardour/amp.h"
45 #include "ardour/meter.h"
46 #include "ardour/event_type_map.h"
47 #include "ardour/pannable.h"
48 #include "ardour/panner.h"
49 #include "ardour/processor.h"
50 #include "ardour/profile.h"
51 #include "ardour/route_group.h"
52 #include "ardour/session.h"
53 #include "ardour/session_playlists.h"
54 #include "ardour/track.h"
56 #include "canvas/debug.h"
58 #include "gtkmm2ext/gtk_ui.h"
59 #include "gtkmm2ext/utils.h"
61 #include "widgets/ardour_button.h"
62 #include "widgets/prompter.h"
63 #include "widgets/tooltips.h"
65 #include "ardour_ui.h"
66 #include "audio_streamview.h"
68 #include "enums_convert.h"
69 #include "route_time_axis.h"
70 #include "automation_time_axis.h"
72 #include "gui_thread.h"
73 #include "item_counts.h"
75 #include "paste_context.h"
76 #include "playlist_selector.h"
77 #include "point_selection.h"
78 #include "public_editor.h"
79 #include "region_view.h"
80 #include "rgb_macros.h"
81 #include "selection.h"
82 #include "streamview.h"
83 #include "ui_config.h"
85 #include "route_group_menu.h"
89 using namespace ARDOUR;
90 using namespace ArdourWidgets;
92 using namespace Gtkmm2ext;
94 using namespace Editing;
98 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
100 , StripableTimeAxisView(ed, sess, canvas)
102 , button_table (3, 3)
103 , route_group_button (S_("RTAV|G"))
104 , playlist_button (S_("RTAV|P"))
105 , automation_button (S_("RTAV|A"))
106 , automation_action_menu (0)
107 , plugins_submenu_item (0)
108 , route_group_menu (0)
109 , playlist_action_menu (0)
111 , color_mode_menu (0)
112 , gm (sess, true, 75, 14)
113 , _ignore_set_layer_display (false)
114 , pan_automation_item(NULL)
116 number_label.set_name("tracknumber label");
117 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
118 number_label.set_alignment(.5, .5);
119 number_label.set_fallthrough_to_parent (true);
121 sess->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::parameter_changed, this, _1), gui_context());
122 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::parameter_changed));
124 parameter_changed ("editor-stereo-only-meters");
128 RouteTimeAxisView::route_property_changed (const PBD::PropertyChange& what_changed)
130 if (what_changed.contains (ARDOUR::Properties::name)) {
136 RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
138 RouteUI::set_route (rt);
139 StripableTimeAxisView::set_stripable (rt);
141 CANVAS_DEBUG_NAME (_canvas_display, string_compose ("main for %1", rt->name()));
142 CANVAS_DEBUG_NAME (selection_group, string_compose ("selections for %1", rt->name()));
143 CANVAS_DEBUG_NAME (_ghost_group, string_compose ("ghosts for %1", rt->name()));
146 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
149 gm.set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
150 gm.get_level_meter().set_no_show_all();
151 gm.get_level_meter().setup_meters(50, meter_width);
152 gm.update_gain_sensitive ();
155 if (get_gui_property ("height", height)) {
158 set_height (preset_height (HeightNormal));
161 if (!_route->is_auditioner()) {
162 if (gui_property ("visible").empty()) {
163 set_gui_property ("visible", true);
166 set_gui_property ("visible", false);
169 timestretch_rect = 0;
172 ignore_toggle = false;
174 route_group_button.set_name ("route button");
175 playlist_button.set_name ("route button");
176 automation_button.set_name ("route button");
178 route_group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
179 playlist_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click), false);
180 automation_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click), false);
184 if (ARDOUR::Profile->get_mixbus()) {
185 controls_table.attach (*rec_enable_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
187 controls_table.attach (*rec_enable_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
190 if (is_midi_track()) {
191 set_tooltip(*rec_enable_button, _("Record (Right-click for Step Edit)"));
192 gm.set_fader_name ("MidiTrackFader");
194 set_tooltip(*rec_enable_button, _("Record"));
195 gm.set_fader_name ("AudioTrackFader");
198 /* set playlist button tip to the current playlist, and make it update when it changes */
199 update_playlist_tip ();
200 track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context());
203 gm.set_fader_name ("AudioBusFader");
204 Gtk::Fixed *blank = manage(new Gtk::Fixed());
205 controls_button_size_group->add_widget(*blank);
206 if (ARDOUR::Profile->get_mixbus() ) {
207 controls_table.attach (*blank, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
209 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
214 top_hbox.pack_end(gm.get_level_meter(), false, false, 2);
216 if (!ARDOUR::Profile->get_mixbus()) {
217 controls_meters_size_group->add_widget (gm.get_level_meter());
220 if (_route->is_master()) {
221 route_group_button.set_sensitive(false);
224 _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
225 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
226 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
227 _route->track_number_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::label_view, this), gui_context());
229 if (ARDOUR::Profile->get_mixbus()) {
230 controls_table.attach (*mute_button, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
232 controls_table.attach (*mute_button, 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
234 // mute button is always present, it is used to
235 // force the 'blank' placeholders to the proper size
236 controls_button_size_group->add_widget(*mute_button);
238 if (!_route->is_master()) {
239 if (ARDOUR::Profile->get_mixbus()) {
240 controls_table.attach (*solo_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
242 controls_table.attach (*solo_button, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
245 Gtk::Fixed *blank = manage(new Gtk::Fixed());
246 controls_button_size_group->add_widget(*blank);
247 if (ARDOUR::Profile->get_mixbus()) {
248 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
250 controls_table.attach (*blank, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
255 if (ARDOUR::Profile->get_mixbus()) {
256 controls_table.attach (route_group_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
257 controls_table.attach (gm.get_gain_slider(), 3, 5, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
259 else if (!ARDOUR::Profile->get_trx()) {
260 controls_table.attach (route_group_button, 4, 5, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
261 controls_table.attach (gm.get_gain_slider(), 0, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
264 set_tooltip(*solo_button,_("Solo"));
265 set_tooltip(*mute_button,_("Mute"));
266 set_tooltip(route_group_button, _("Route Group"));
268 mute_button->set_tweaks(ArdourButton::TrackHeader);
269 solo_button->set_tweaks(ArdourButton::TrackHeader);
270 rec_enable_button->set_tweaks(ArdourButton::TrackHeader);
271 playlist_button.set_tweaks(ArdourButton::TrackHeader);
272 automation_button.set_tweaks(ArdourButton::TrackHeader);
273 route_group_button.set_tweaks(ArdourButton::TrackHeader);
275 if (is_midi_track()) {
276 set_tooltip(automation_button, _("MIDI Controllers and Automation"));
278 set_tooltip(automation_button, _("Automation"));
281 update_track_number_visibility();
284 if (ARDOUR::Profile->get_mixbus()) {
285 controls_table.attach (automation_button, 1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
287 else if (!ARDOUR::Profile->get_trx()) {
288 controls_table.attach (automation_button, 3, 4, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
291 if (is_track() && track()->mode() == ARDOUR::Normal) {
292 if (ARDOUR::Profile->get_mixbus()) {
293 controls_table.attach (playlist_button, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
295 else if (!ARDOUR::Profile->get_trx()) {
296 controls_table.attach (playlist_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
302 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
306 LayerDisplay layer_display;
307 if (get_gui_property ("layer-display", layer_display)) {
308 set_layer_display (layer_display);
311 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
312 track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
314 /* pick up the correct freeze state */
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 ())));
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 bool single_track_selected = (!for_selection || _editor.get_selection().tracks.size() == 1);
543 if (!subplugin_menu.items().empty()) {
544 items.push_back (SeparatorElem ());
545 items.push_back (MenuElem (_("Processor automation"), subplugin_menu));
546 items.back().set_sensitive (single_track_selected);
549 /* Add any route automation */
552 items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &RouteTimeAxisView::update_gain_track_visibility)));
553 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
554 gain_automation_item->set_active (single_track_selected &&
555 string_to<bool>(gain_track->gui_property ("visible")));
557 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
561 items.push_back (CheckMenuElem (_("Trim"), sigc::mem_fun (*this, &RouteTimeAxisView::update_trim_track_visibility)));
562 trim_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
563 trim_automation_item->set_active (single_track_selected &&
564 string_to<bool>(trim_track->gui_property ("visible")));
566 _main_automation_menu_map[Evoral::Parameter(TrimAutomation)] = trim_automation_item;
570 items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &RouteTimeAxisView::update_mute_track_visibility)));
571 mute_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
572 mute_automation_item->set_active (single_track_selected &&
573 string_to<bool>(mute_track->gui_property ("visible")));
575 _main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item;
578 if (!pan_tracks.empty() && !ARDOUR::Profile->get_mixbus()) {
579 items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &RouteTimeAxisView::update_pan_track_visibility)));
580 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
581 pan_automation_item->set_active (single_track_selected &&
582 string_to<bool>(pan_tracks.front()->gui_property ("visible")));
584 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
585 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
586 _main_automation_menu_map[*p] = pan_automation_item;
592 RouteTimeAxisView::build_display_menu ()
594 using namespace Menu_Helpers;
598 TimeAxisView::build_display_menu ();
600 /* now fill it with our stuff */
602 MenuList& items = display_menu->items();
603 display_menu->set_name ("ArdourContextMenu");
605 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
607 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
609 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
611 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
613 items.push_back (SeparatorElem());
616 detach_menu (*_size_menu);
619 items.push_back (MenuElem (_("Height"), *_size_menu));
620 items.push_back (SeparatorElem());
622 // Hook for derived classes to add type specific stuff
623 append_extra_display_menu_items ();
627 Menu* layers_menu = manage (new Menu);
628 MenuList &layers_items = layers_menu->items();
629 layers_menu->set_name("ArdourContextMenu");
631 RadioMenuItem::Group layers_group;
633 /* Find out how many overlaid/stacked tracks we have in the selection */
637 int unchangeable = 0;
638 TrackSelection const & s = _editor.get_selection().tracks;
640 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
641 StreamView* v = (*i)->view ();
646 if (v->can_change_layer_display()) {
647 switch (v->layer_display ()) {
661 /* We're not connecting to signal_toggled() here; in the case where these two items are
662 set to be in the `inconsistent' state, it seems that one or other will end up active
663 as well as inconsistent (presumably due to the RadioMenuItem::Group). Then when you
664 select the active one, no toggled signal is emitted so nothing happens.
667 _ignore_set_layer_display = true;
669 layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid")));
670 RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
671 i->set_active (overlaid != 0 && stacked == 0);
672 i->set_inconsistent (overlaid != 0 && stacked != 0);
673 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true));
676 i->set_sensitive (false);
679 layers_items.push_back (RadioMenuElem (layers_group, _("Stacked")));
680 i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
681 i->set_active (overlaid == 0 && stacked != 0);
682 i->set_inconsistent (overlaid != 0 && stacked != 0);
683 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
686 i->set_sensitive (false);
689 _ignore_set_layer_display = false;
691 items.push_back (MenuElem (_("Layers"), *layers_menu));
693 Menu* alignment_menu = manage (new Menu);
694 MenuList& alignment_items = alignment_menu->items();
695 alignment_menu->set_name ("ArdourContextMenu");
697 RadioMenuItem::Group align_group;
699 /* Same verbose hacks as for the layering options above */
705 boost::shared_ptr<Track> first_track;
707 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
708 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
709 if (!r || !r->is_track ()) {
714 first_track = r->track();
717 switch (r->track()->alignment_choice()) {
721 switch (r->track()->alignment_style()) {
722 case ExistingMaterial:
730 case UseExistingMaterial:
746 inconsistent = false;
753 if (!inconsistent && first_track) {
755 alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)")));
756 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
757 i->set_active (automatic != 0 && existing == 0 && capture == 0);
758 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true));
760 switch (first_track->alignment_choice()) {
762 switch (first_track->alignment_style()) {
763 case ExistingMaterial:
764 alignment_items.push_back (MenuElem (_("(Currently: Existing Material)")));
767 alignment_items.push_back (MenuElem (_("(Currently: Capture Time)")));
775 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
776 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
777 i->set_active (existing != 0 && capture == 0 && automatic == 0);
778 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true));
780 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
781 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
782 i->set_active (existing == 0 && capture != 0 && automatic == 0);
783 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true));
785 items.push_back (MenuElem (_("Alignment"), *alignment_menu));
791 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
792 Menu* mode_menu = manage (new Menu);
793 MenuList& mode_items = mode_menu->items ();
794 mode_menu->set_name ("ArdourContextMenu");
796 RadioMenuItem::Group mode_group;
802 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
803 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
804 if (!r || !r->is_track ()) {
808 switch (r->track()->mode()) {
821 mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode")));
822 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
823 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal, true));
824 i->set_active (normal != 0 && tape == 0 && non_layered == 0);
825 i->set_inconsistent (normal != 0 && (tape != 0 || non_layered != 0));
827 mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode")));
828 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
829 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive, true));
830 i->set_active (normal == 0 && tape != 0 && non_layered == 0);
831 i->set_inconsistent (tape != 0 && (normal != 0 || non_layered != 0));
833 mode_items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode")));
834 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
835 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered, true));
836 i->set_active (normal == 0 && tape == 0 && non_layered != 0);
837 i->set_inconsistent (non_layered != 0 && (normal != 0 || tape != 0));
839 items.push_back (MenuElem (_("Record Mode"), *mode_menu));
842 items.push_back (SeparatorElem());
844 build_playlist_menu ();
845 items.push_back (MenuElem (_("Playlist"), *playlist_action_menu));
846 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
849 route_group_menu->detach ();
852 for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) {
853 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
855 r.push_back (rtv->route ());
860 r.push_back (route ());
863 if (!_route->is_master()) {
864 route_group_menu->build (r);
865 items.push_back (MenuElem (_("Group"), *route_group_menu->menu ()));
868 build_automation_action_menu (true);
869 items.push_back (MenuElem (_("Automation"), *automation_action_menu));
871 items.push_back (SeparatorElem());
875 TrackSelection const & s = _editor.get_selection().tracks;
876 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
877 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
882 if (r->route()->active()) {
889 items.push_back (CheckMenuElem (_("Active")));
890 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
891 bool click_sets_active = true;
892 if (active > 0 && inactive == 0) {
893 i->set_active (true);
894 click_sets_active = false;
895 } else if (active > 0 && inactive > 0) {
896 i->set_inconsistent (true);
898 i->set_sensitive(! _session->transport_rolling());
899 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), click_sets_active, true));
901 items.push_back (SeparatorElem());
902 items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true)));
903 if (_route && !_route->is_master()) {
904 items.push_back (SeparatorElem());
905 items.push_back (MenuElem (_("Duplicate..."), boost::bind (&ARDOUR_UI::start_duplicate_routes, ARDOUR_UI::instance())));
907 items.push_back (SeparatorElem());
908 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(_editor, &PublicEditor::remove_tracks)));
911 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
913 RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection)
915 if (apply_to_selection) {
916 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_track_mode, _1, mode, false));
919 bool needs_bounce = false;
921 if (!track()->can_use_mode (mode, needs_bounce)) {
927 cerr << "would bounce this one\n";
932 track()->set_mode (mode);
938 RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layers, int layer)
940 TimeAxisView::show_timestretch (start, end, layers, layer);
950 /* check that the time selection was made in our route, or our route group.
951 remember that route_group() == 0 implies the route is *not* in a edit group.
954 if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
955 /* this doesn't apply to us */
959 /* ignore it if our edit group is not active */
961 if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
966 if (timestretch_rect == 0) {
967 timestretch_rect = new ArdourCanvas::Rectangle (canvas_display ());
968 timestretch_rect->set_fill_color (Gtkmm2ext::HSV (UIConfiguration::instance().color ("time stretch fill")).mod (UIConfiguration::instance().modifier ("time stretch fill")).color());
969 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
972 timestretch_rect->show ();
973 timestretch_rect->raise_to_top ();
975 double const x1 = start / _editor.get_current_zoom();
976 double const x2 = (end - 1) / _editor.get_current_zoom();
978 timestretch_rect->set (ArdourCanvas::Rect (x1, current_height() * (layers - layer - 1) / layers,
979 x2, current_height() * (layers - layer) / layers));
983 RouteTimeAxisView::hide_timestretch ()
985 TimeAxisView::hide_timestretch ();
987 if (timestretch_rect) {
988 timestretch_rect->hide ();
993 RouteTimeAxisView::show_selection (TimeSelection& ts)
997 /* ignore it if our edit group is not active or if the selection was started
998 in some other track or route group (remember that route_group() == 0 means
999 that the track is not in an route group).
1002 if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
1003 (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
1009 TimeAxisView::show_selection (ts);
1013 RouteTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
1016 bool height_changed = (height == 0) || (h != height);
1018 int meter_width = 3;
1019 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
1022 gm.get_level_meter().setup_meters (gmlen, meter_width);
1024 TimeAxisView::set_height (h, m);
1027 _view->set_height ((double) current_height());
1030 if (height >= preset_height (HeightNormal)) {
1034 gm.get_gain_slider().show();
1035 mute_button->show();
1036 if (!_route || _route->is_monitor()) {
1037 solo_button->hide();
1039 solo_button->show();
1041 if (rec_enable_button)
1042 rec_enable_button->show();
1044 route_group_button.show();
1045 automation_button.show();
1047 if (is_track() && track()->mode() == ARDOUR::Normal) {
1048 playlist_button.show();
1055 gm.get_gain_slider().hide();
1056 mute_button->show();
1057 if (!_route || _route->is_monitor()) {
1058 solo_button->hide();
1060 solo_button->show();
1062 if (rec_enable_button)
1063 rec_enable_button->show();
1065 route_group_button.hide ();
1066 automation_button.hide ();
1068 if (is_track() && track()->mode() == ARDOUR::Normal) {
1069 playlist_button.hide ();
1074 if (height_changed && !no_redraw) {
1075 /* only emit the signal if the height really changed */
1081 RouteTimeAxisView::route_color_changed ()
1083 using namespace ARDOUR_UI_UTILS;
1085 _view->apply_color (color(), StreamView::RegionColor);
1087 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1091 RouteTimeAxisView::set_samples_per_pixel (double fpp)
1096 speed = track()->speed();
1100 _view->set_samples_per_pixel (fpp * speed);
1103 StripableTimeAxisView::set_samples_per_pixel (fpp * speed);
1107 RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
1109 if (!mitem->get_active()) {
1110 /* this is one of the two calls made when these radio menu items change status. this one
1111 is for the item that became inactive, and we want to ignore it.
1116 if (apply_to_selection) {
1117 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
1120 track()->set_align_choice (choice);
1126 RouteTimeAxisView::rename_current_playlist ()
1128 Prompter prompter (true);
1131 boost::shared_ptr<Track> tr = track();
1132 if (!tr || tr->destructive()) {
1136 boost::shared_ptr<Playlist> pl = tr->playlist();
1141 prompter.set_title (_("Rename Playlist"));
1142 prompter.set_prompt (_("New name for playlist:"));
1143 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1144 prompter.set_initial_text (pl->name());
1145 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1148 if (prompter.run () != Gtk::RESPONSE_ACCEPT) {
1151 prompter.get_result (name);
1152 if (name.length()) {
1153 if (_session->playlists->by_name (name)) {
1154 MessageDialog msg (_("Given playlist name is not unique."));
1156 prompter.set_initial_text (Playlist::bump_name (name, *_session));
1158 pl->set_name (name);
1166 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
1168 std::string ret (basename);
1170 std::string const group_string = "." + route_group()->name() + ".";
1172 // iterate through all playlists
1174 for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1175 std::string tmp = (*i)->name();
1177 std::string::size_type idx = tmp.find(group_string);
1178 // find those which belong to this group
1179 if (idx != string::npos) {
1180 tmp = tmp.substr(idx + group_string.length());
1182 // and find the largest current number
1184 if (x > maxnumber) {
1193 snprintf (buf, sizeof(buf), "%d", maxnumber);
1195 ret = this->name() + "." + route_group()->name () + "." + buf;
1201 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op, bool copy)
1205 boost::shared_ptr<Track> tr = track ();
1206 if (!tr || tr->destructive()) {
1210 boost::shared_ptr<const Playlist> pl = tr->playlist();
1217 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1218 name = resolve_new_group_playlist_name(name,playlists_before_op);
1221 while (_session->playlists->by_name(name)) {
1222 name = Playlist::bump_name (name, *_session);
1226 // TODO: The prompter "new" button should be de-activated if the user
1227 // specifies a playlist name which already exists in the session.
1229 Prompter prompter (true);
1232 prompter.set_title (_("New Copy Playlist"));
1233 prompter.set_prompt (_("Name for playlist copy:"));
1235 prompter.set_title (_("New Playlist"));
1236 prompter.set_prompt (_("Name for new playlist:"));
1238 prompter.set_initial_text (name);
1239 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1240 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1241 prompter.show_all ();
1244 if (prompter.run () != Gtk::RESPONSE_ACCEPT) {
1247 prompter.get_result (name);
1248 if (name.length()) {
1249 if (_session->playlists->by_name (name)) {
1250 MessageDialog msg (_("Given playlist name is not unique."));
1252 prompter.set_initial_text (Playlist::bump_name (name, *_session));
1260 if (name.length()) {
1262 tr->use_copy_playlist ();
1264 tr->use_new_playlist ();
1266 tr->playlist()->set_name (name);
1271 RouteTimeAxisView::clear_playlist ()
1273 boost::shared_ptr<Track> tr = track ();
1274 if (!tr || tr->destructive()) {
1278 boost::shared_ptr<Playlist> pl = tr->playlist();
1283 _editor.clear_playlist (pl);
1287 RouteTimeAxisView::speed_changed ()
1289 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_pixel, this));
1293 RouteTimeAxisView::update_diskstream_display ()
1303 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1305 if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1307 /* special case: select/deselect all tracks */
1309 _editor.begin_reversible_selection_op (X_("Selection Click"));
1311 if (_editor.get_selection().selected (this)) {
1312 _editor.get_selection().clear_tracks ();
1314 _editor.select_all_tracks ();
1317 _editor.commit_reversible_selection_op ();
1322 _editor.begin_reversible_selection_op (X_("Selection Click"));
1324 switch (ArdourKeyboard::selection_type (ev->state)) {
1325 case Selection::Toggle:
1326 _editor.get_selection().toggle (this);
1329 case Selection::Set:
1330 _editor.get_selection().set (this);
1333 case Selection::Extend:
1334 _editor.extend_selection_to_track (*this);
1337 case Selection::Add:
1338 _editor.get_selection().add (this);
1342 _editor.commit_reversible_selection_op ();
1346 RouteTimeAxisView::set_selected_points (PointSelection& points)
1348 StripableTimeAxisView::set_selected_points (points);
1349 AudioStreamView* asv = dynamic_cast<AudioStreamView*>(_view);
1351 asv->set_selected_points (points);
1356 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1359 _view->set_selected_regionviews (regions);
1363 /** Add the selectable things that we have to a list.
1364 * @param results List to add things to.
1367 RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results, bool within)
1372 speed = track()->speed();
1375 framepos_t const start_adjusted = session_frame_to_track_frame(start, speed);
1376 framepos_t const end_adjusted = session_frame_to_track_frame(end, speed);
1378 if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1379 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1382 /* pick up visible automation tracks */
1383 StripableTimeAxisView::get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1387 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1390 _view->get_inverted_selectables (sel, results);
1392 StripableTimeAxisView::get_inverted_selectables (sel, results);
1396 RouteTimeAxisView::route_group () const
1398 return _route->route_group();
1401 boost::shared_ptr<Playlist>
1402 RouteTimeAxisView::playlist () const
1404 boost::shared_ptr<Track> tr;
1406 if ((tr = track()) != 0) {
1407 return tr->playlist();
1409 return boost::shared_ptr<Playlist> ();
1414 RouteTimeAxisView::name_entry_changed (string const& str)
1416 if (str == _route->name()) {
1422 strip_whitespace_edges (x);
1428 if (_session->route_name_internal (x)) {
1429 ARDOUR_UI::instance()->popup_error (string_compose (_("The name \"%1\" is reserved for %2"), x, PROGRAM_NAME));
1431 } else if (RouteUI::verify_new_route_name (x)) {
1432 _route->set_name (x);
1439 boost::shared_ptr<Region>
1440 RouteTimeAxisView::find_next_region (framepos_t pos, RegionPoint point, int32_t dir)
1442 boost::shared_ptr<Playlist> pl = playlist ();
1445 return pl->find_next_region (pos, point, dir);
1448 return boost::shared_ptr<Region> ();
1452 RouteTimeAxisView::find_next_region_boundary (framepos_t pos, int32_t dir)
1454 boost::shared_ptr<Playlist> pl = playlist ();
1457 return pl->find_next_region_boundary (pos, dir);
1464 RouteTimeAxisView::fade_range (TimeSelection& selection)
1466 boost::shared_ptr<Playlist> what_we_got;
1467 boost::shared_ptr<Track> tr = track ();
1468 boost::shared_ptr<Playlist> playlist;
1471 /* route is a bus, not a track */
1475 playlist = tr->playlist();
1477 TimeSelection time (selection);
1478 float const speed = tr->speed();
1479 if (speed != 1.0f) {
1480 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1481 (*i).start = session_frame_to_track_frame((*i).start, speed);
1482 (*i).end = session_frame_to_track_frame((*i).end, speed);
1486 playlist->clear_changes ();
1487 playlist->clear_owned_changes ();
1489 playlist->fade_range (time);
1491 vector<Command*> cmds;
1492 playlist->rdiff (cmds);
1493 _session->add_commands (cmds);
1494 _session->add_command (new StatefulDiffCommand (playlist));
1499 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1501 boost::shared_ptr<Playlist> what_we_got;
1502 boost::shared_ptr<Track> tr = track ();
1503 boost::shared_ptr<Playlist> playlist;
1506 /* route is a bus, not a track */
1510 playlist = tr->playlist();
1512 TimeSelection time (selection.time);
1513 float const speed = tr->speed();
1514 if (speed != 1.0f) {
1515 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1516 (*i).start = session_frame_to_track_frame((*i).start, speed);
1517 (*i).end = session_frame_to_track_frame((*i).end, speed);
1521 playlist->clear_changes ();
1522 playlist->clear_owned_changes ();
1526 if (playlist->cut (time) != 0) {
1527 if (Config->get_edit_mode() == Ripple) {
1528 playlist->ripple(time.start(), -time.length(), NULL);
1530 // no need to exclude any regions from rippling here
1532 vector<Command*> cmds;
1533 playlist->rdiff (cmds);
1534 _session->add_commands (cmds);
1536 _session->add_command (new StatefulDiffCommand (playlist));
1541 if ((what_we_got = playlist->cut (time)) != 0) {
1542 _editor.get_cut_buffer().add (what_we_got);
1543 if (Config->get_edit_mode() == Ripple) {
1544 playlist->ripple(time.start(), -time.length(), NULL);
1546 // no need to exclude any regions from rippling here
1548 vector<Command*> cmds;
1549 playlist->rdiff (cmds);
1550 _session->add_commands (cmds);
1552 _session->add_command (new StatefulDiffCommand (playlist));
1556 if ((what_we_got = playlist->copy (time)) != 0) {
1557 _editor.get_cut_buffer().add (what_we_got);
1562 if ((what_we_got = playlist->cut (time)) != 0) {
1563 if (Config->get_edit_mode() == Ripple) {
1564 playlist->ripple(time.start(), -time.length(), NULL);
1566 // no need to exclude any regions from rippling here
1568 vector<Command*> cmds;
1569 playlist->rdiff (cmds);
1570 _session->add_commands (cmds);
1571 _session->add_command (new StatefulDiffCommand (playlist));
1572 what_we_got->release ();
1579 RouteTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1585 boost::shared_ptr<Playlist> pl = playlist ();
1586 const ARDOUR::DataType type = pl->data_type();
1587 PlaylistSelection::const_iterator p = selection.playlists.get_nth(type, ctx.counts.n_playlists(type));
1589 if (p == selection.playlists.end()) {
1592 ctx.counts.increase_n_playlists(type);
1594 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
1596 if (track()->speed() != 1.0f) {
1597 pos = session_frame_to_track_frame (pos, track()->speed());
1598 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
1601 /* add multi-paste offset if applicable */
1602 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent();
1603 const framecnt_t duration = extent.second - extent.first;
1604 pos += _editor.get_paste_offset(pos, ctx.count, duration);
1606 pl->clear_changes ();
1607 pl->clear_owned_changes ();
1608 if (Config->get_edit_mode() == Ripple) {
1609 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
1610 framecnt_t amount = extent.second - extent.first;
1611 pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
1613 pl->paste (*p, pos, ctx.times, sub_num);
1615 vector<Command*> cmds;
1617 _session->add_commands (cmds);
1619 _session->add_command (new StatefulDiffCommand (pl));
1625 struct PlaylistSorter {
1626 bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1627 return a->sort_id() < b->sort_id();
1632 RouteTimeAxisView::build_playlist_menu ()
1634 using namespace Menu_Helpers;
1640 delete playlist_action_menu;
1641 playlist_action_menu = new Menu;
1642 playlist_action_menu->set_name ("ArdourContextMenu");
1644 MenuList& playlist_items = playlist_action_menu->items();
1645 playlist_action_menu->set_name ("ArdourContextMenu");
1646 playlist_items.clear();
1648 RadioMenuItem::Group playlist_group;
1649 boost::shared_ptr<Track> tr = track ();
1651 vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
1653 /* sort the playlists */
1655 sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1657 /* add the playlists to the menu */
1658 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1659 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1660 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1661 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1663 if (tr->playlist()->id() == (*i)->id()) {
1668 playlist_items.push_back (SeparatorElem());
1669 playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1670 playlist_items.push_back (SeparatorElem());
1672 if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1673 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1674 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1677 // Use a label which tells the user what is happening
1678 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1679 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1683 playlist_items.push_back (SeparatorElem());
1684 playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1685 playlist_items.push_back (SeparatorElem());
1687 playlist_items.push_back (MenuElem(_("Select from All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1691 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1693 assert (is_track());
1695 // exit if we were triggered by deactivating the old playlist
1696 if (!item->get_active()) {
1700 boost::shared_ptr<Playlist> pl (wpl.lock());
1706 if (track()->playlist() == pl) {
1707 // exit when use_playlist is called by the creation of the playlist menu
1708 // or the playlist choice is unchanged
1712 track()->use_playlist (pl);
1714 RouteGroup* rg = route_group();
1716 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1717 std::string group_string = "." + rg->name() + ".";
1719 std::string take_name = pl->name();
1720 std::string::size_type idx = take_name.find(group_string);
1722 if (idx == std::string::npos)
1725 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1727 boost::shared_ptr<RouteList> rl (rg->route_list());
1729 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1730 if ((*i) == this->route()) {
1734 std::string playlist_name = (*i)->name()+group_string+take_name;
1736 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1741 if (track->freeze_state() == Track::Frozen) {
1742 /* Don't change playlists of frozen tracks */
1746 boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1748 // No playlist for this track for this take yet, make it
1749 track->use_new_playlist();
1750 track->playlist()->set_name(playlist_name);
1752 track->use_playlist(ipl);
1759 RouteTimeAxisView::update_playlist_tip ()
1761 RouteGroup* rg = route_group ();
1762 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1763 string group_string = "." + rg->name() + ".";
1765 string take_name = track()->playlist()->name();
1766 string::size_type idx = take_name.find(group_string);
1768 if (idx != string::npos) {
1769 /* find the bit containing the take number / name */
1770 take_name = take_name.substr (idx + group_string.length());
1772 /* set the playlist button tooltip to the take name */
1775 string_compose(_("Take: %1.%2"),
1776 Gtkmm2ext::markup_escape_text (rg->name()),
1777 Gtkmm2ext::markup_escape_text (take_name))
1784 /* set the playlist button tooltip to the playlist name */
1785 set_tooltip (playlist_button, _("Playlist") + std::string(": ") + Gtkmm2ext::markup_escape_text (track()->playlist()->name()));
1790 RouteTimeAxisView::show_playlist_selector ()
1792 _editor.playlist_selector().show_for (this);
1796 RouteTimeAxisView::map_frozen ()
1802 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1804 switch (track()->freeze_state()) {
1806 playlist_button.set_sensitive (false);
1809 playlist_button.set_sensitive (true);
1812 RouteUI::map_frozen ();
1816 RouteTimeAxisView::color_handler ()
1818 //case cTimeStretchOutline:
1819 if (timestretch_rect) {
1820 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
1822 //case cTimeStretchFill:
1823 if (timestretch_rect) {
1824 timestretch_rect->set_fill_color (UIConfiguration::instance().color ("time stretch fill"));
1830 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1831 * Will add track if necessary.
1834 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1836 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1837 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1840 /* it doesn't exist yet, so we don't care about the button state: just add it */
1841 create_automation_child (param, true);
1844 bool yn = menu->get_active();
1845 bool changed = false;
1847 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1849 /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1850 will have done that for us.
1853 if (changed && !no_redraw) {
1861 RouteTimeAxisView::update_pan_track_visibility ()
1863 bool const showit = pan_automation_item->get_active();
1864 bool changed = false;
1866 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1867 if ((*i)->set_marked_for_display (showit)) {
1873 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1878 RouteTimeAxisView::ensure_pan_views (bool show)
1880 bool changed = false;
1881 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1883 (*i)->set_marked_for_display (false);
1886 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1890 if (!_route->panner()) {
1894 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1895 set<Evoral::Parameter>::iterator p;
1897 for (p = params.begin(); p != params.end(); ++p) {
1898 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1900 if (pan_control->parameter().type() == NullAutomation) {
1901 error << "Pan control has NULL automation type!" << endmsg;
1905 if (automation_child (pan_control->parameter ()).get () == 0) {
1907 /* we don't already have an AutomationTimeAxisView for this parameter */
1909 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1911 boost::shared_ptr<AutomationTimeAxisView> t (
1912 new AutomationTimeAxisView (_session,
1916 pan_control->parameter (),
1924 pan_tracks.push_back (t);
1925 add_automation_child (*p, t, show);
1927 pan_tracks.push_back (automation_child (pan_control->parameter ()));
1934 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
1936 if (apply_to_selection) {
1937 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
1941 StripableTimeAxisView::show_all_automation ();
1943 /* Show processor automation */
1945 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1946 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1947 if ((*ii)->view == 0) {
1948 add_processor_automation_curve ((*i)->processor, (*ii)->what);
1951 (*ii)->menu_item->set_active (true);
1964 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
1966 if (apply_to_selection) {
1967 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
1971 StripableTimeAxisView::show_existing_automation ();
1973 /* Show processor automation */
1974 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1975 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1976 if ((*i)->processor->control((*ii)->what)->list()->size() > 0) {
1977 (*ii)->menu_item->set_active (true);
1988 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
1990 if (apply_to_selection) {
1991 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
1994 StripableTimeAxisView::hide_all_automation ();
1996 /* Hide processor automation */
1997 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1998 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1999 (*ii)->menu_item->set_active (false);
2009 RouteTimeAxisView::region_view_added (RegionView* rv)
2011 /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
2012 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
2013 boost::shared_ptr<AutomationTimeAxisView> atv;
2015 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
2020 for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
2021 (*i)->add_ghost(rv);
2025 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
2027 for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
2033 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
2035 parent.remove_processor_automation_node (this);
2039 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
2042 remove_child (pan->view);
2046 RouteTimeAxisView::ProcessorAutomationNode*
2047 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2049 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2051 if ((*i)->processor == processor) {
2053 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2054 if ((*ii)->what == what) {
2064 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
2066 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2069 ProcessorAutomationNode* pan;
2071 if ((pan = find_processor_automation_node (processor, what)) == 0) {
2072 /* session state may never have been saved with new plugin */
2073 error << _("programming error: ")
2074 << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
2075 processor->name(), what.type(), (int) what.channel(), what.id() )
2077 abort(); /*NOTREACHED*/
2085 boost::shared_ptr<AutomationControl> control
2086 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
2088 pan->view = boost::shared_ptr<AutomationTimeAxisView>(
2089 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
2090 _editor, *this, false, parent_canvas,
2091 processor->describe_parameter (what), processor->name()));
2093 pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
2095 add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
2098 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
2103 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
2106 pan->menu_item->set_active (false);
2115 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
2117 boost::shared_ptr<Processor> processor (p.lock ());
2119 if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
2120 /* The Amp processor is a special case and is dealt with separately */
2124 set<Evoral::Parameter> existing;
2126 processor->what_has_data (existing);
2128 for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
2130 Evoral::Parameter param (*i);
2131 boost::shared_ptr<AutomationLine> al;
2133 if ((al = find_processor_automation_curve (processor, param)) != 0) {
2136 add_processor_automation_curve (processor, param);
2142 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2144 boost::shared_ptr<Processor> processor (p.lock ());
2146 if (!processor || !processor->display_to_user ()) {
2150 /* we use this override to veto the Amp processor from the plugin menu,
2151 as its automation lane can be accessed using the special "Fader" menu
2155 if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2159 using namespace Menu_Helpers;
2160 ProcessorAutomationInfo *rai;
2161 list<ProcessorAutomationInfo*>::iterator x;
2163 const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2165 if (automatable.empty()) {
2169 for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2170 if ((*x)->processor == processor) {
2175 if (x == processor_automation.end()) {
2176 rai = new ProcessorAutomationInfo (processor);
2177 processor_automation.push_back (rai);
2182 /* any older menu was deleted at the top of processors_changed()
2183 when we cleared the subplugin menu.
2186 rai->menu = manage (new Menu);
2187 MenuList& items = rai->menu->items();
2188 rai->menu->set_name ("ArdourContextMenu");
2192 std::set<Evoral::Parameter> has_visible_automation;
2193 AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2195 for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2197 ProcessorAutomationNode* pan;
2198 Gtk::CheckMenuItem* mitem;
2200 string name = processor->describe_parameter (*i);
2202 if (name == X_("hidden")) {
2206 items.push_back (CheckMenuElem (name));
2207 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2209 _subplugin_menu_map[*i] = mitem;
2211 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2212 mitem->set_active(true);
2215 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2219 pan = new ProcessorAutomationNode (*i, mitem, *this);
2221 rai->lines.push_back (pan);
2225 pan->menu_item = mitem;
2229 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2232 if (items.size() == 0) {
2236 /* add the menu for this processor, because the subplugin
2237 menu is always cleared at the top of processors_changed().
2238 this is the result of some poor design in gtkmm and/or
2242 subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2247 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2248 RouteTimeAxisView::ProcessorAutomationNode* pan)
2250 bool showit = pan->menu_item->get_active();
2251 bool redraw = false;
2253 if (pan->view == 0 && showit) {
2254 add_processor_automation_curve (rai->processor, pan->what);
2258 if (pan->view && pan->view->set_marked_for_display (showit)) {
2262 if (redraw && !no_redraw) {
2268 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2270 if (c.type == RouteProcessorChange::MeterPointChange) {
2271 /* nothing to do if only the meter point has changed */
2275 using namespace Menu_Helpers;
2277 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2278 (*i)->valid = false;
2281 setup_processor_menu_and_curves ();
2283 bool deleted_processor_automation = false;
2285 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2287 list<ProcessorAutomationInfo*>::iterator tmp;
2295 processor_automation.erase (i);
2296 deleted_processor_automation = true;
2303 if (deleted_processor_automation && !no_redraw) {
2308 boost::shared_ptr<AutomationLine>
2309 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2311 ProcessorAutomationNode* pan;
2313 if ((pan = find_processor_automation_node (processor, what)) != 0) {
2319 return boost::shared_ptr<AutomationLine>();
2323 RouteTimeAxisView::reset_processor_automation_curves ()
2325 for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2331 RouteTimeAxisView::can_edit_name () const
2333 /* we do not allow track name changes if it is record enabled
2335 boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track> (_route));
2339 return !trk->rec_enable_control()->get_value();
2343 RouteTimeAxisView::blink_rec_display (bool onoff)
2345 RouteUI::blink_rec_display (onoff);
2349 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2351 if (_ignore_set_layer_display) {
2355 if (apply_to_selection) {
2356 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2360 _view->set_layer_display (d);
2363 set_gui_property (X_("layer-display"), d);
2368 RouteTimeAxisView::layer_display () const
2371 return _view->layer_display ();
2374 /* we don't know, since we don't have a _view, so just return something */
2379 RouteTimeAxisView::fast_update ()
2381 gm.get_level_meter().update_meters ();
2385 RouteTimeAxisView::hide_meter ()
2388 gm.get_level_meter().hide_meters ();
2392 RouteTimeAxisView::show_meter ()
2398 RouteTimeAxisView::reset_meter ()
2400 if (UIConfiguration::instance().get_show_track_meters()) {
2401 int meter_width = 3;
2402 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2405 gm.get_level_meter().setup_meters (height - 9, meter_width);
2412 RouteTimeAxisView::clear_meter ()
2414 gm.get_level_meter().clear_meters ();
2418 RouteTimeAxisView::meter_changed ()
2420 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2422 if (_route && !no_redraw && UIConfiguration::instance().get_show_track_meters()) {
2425 // reset peak when meter point changes
2426 gm.reset_peak_display();
2430 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2433 if (_route && !no_redraw) {
2439 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2441 using namespace Menu_Helpers;
2443 if (!_underlay_streams.empty()) {
2444 MenuList& parent_items = parent_menu->items();
2445 Menu* gs_menu = manage (new Menu);
2446 gs_menu->set_name ("ArdourContextMenu");
2447 MenuList& gs_items = gs_menu->items();
2449 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2451 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2452 gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2453 sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2459 RouteTimeAxisView::set_underlay_state()
2461 if (!underlay_xml_node) {
2465 XMLNodeList nlist = underlay_xml_node->children();
2466 XMLNodeConstIterator niter;
2467 XMLNode *child_node;
2469 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2470 child_node = *niter;
2472 if (child_node->name() != "Underlay") {
2476 XMLProperty const * prop = child_node->property ("id");
2478 PBD::ID id (prop->value());
2480 RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2483 add_underlay(v->view(), false);
2492 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2498 RouteTimeAxisView& other = v->trackview();
2500 if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2501 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2502 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2503 abort(); /*NOTREACHED*/
2506 _underlay_streams.push_back(v);
2507 other._underlay_mirrors.push_back(this);
2509 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2511 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2513 if (!underlay_xml_node) {
2514 underlay_xml_node = xml_node->add_child("Underlays");
2517 XMLNode* node = underlay_xml_node->add_child("Underlay");
2518 XMLProperty const * prop = node->add_property("id");
2519 prop->set_value(v->trackview().route()->id().to_s());
2526 RouteTimeAxisView::remove_underlay (StreamView* v)
2532 UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2533 RouteTimeAxisView& other = v->trackview();
2535 if (it != _underlay_streams.end()) {
2536 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2538 if (gm == other._underlay_mirrors.end()) {
2539 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2540 abort(); /*NOTREACHED*/
2543 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2545 _underlay_streams.erase(it);
2546 other._underlay_mirrors.erase(gm);
2548 if (underlay_xml_node) {
2549 underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2555 RouteTimeAxisView::set_button_names ()
2557 if (_route && _route->solo_safe_control()->solo_safe()) {
2558 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2560 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2562 if (Config->get_solo_control_is_listen_control()) {
2563 switch (Config->get_listen_position()) {
2564 case AfterFaderListen:
2565 solo_button->set_text (S_("AfterFader|A"));
2566 set_tooltip (*solo_button, _("After-fade listen (AFL)"));
2568 case PreFaderListen:
2569 solo_button->set_text (S_("PreFader|P"));
2570 set_tooltip (*solo_button, _("Pre-fade listen (PFL)"));
2574 solo_button->set_text (S_("Solo|S"));
2575 set_tooltip (*solo_button, _("Solo"));
2577 mute_button->set_text (S_("Mute|M"));
2581 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2583 Gtk::CheckMenuItem* rv = StripableTimeAxisView::automation_child_menu_item (param);
2588 ParameterMenuMap::iterator i = _subplugin_menu_map.find (param);
2589 if (i != _subplugin_menu_map.end()) {
2597 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2599 boost::shared_ptr<AutomationControl> c = _route->gain_control();
2601 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2605 gain_track.reset (new AutomationTimeAxisView (_session,
2606 _route, _route->amp(), c, param,
2611 _route->amp()->describe_parameter(param)));
2614 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2617 add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2621 RouteTimeAxisView::create_trim_automation_child (const Evoral::Parameter& param, bool show)
2623 boost::shared_ptr<AutomationControl> c = _route->trim()->gain_control();
2624 if (!c || ! _route->trim()->active()) {
2628 trim_track.reset (new AutomationTimeAxisView (_session,
2629 _route, _route->trim(), c, param,
2634 _route->trim()->describe_parameter(param)));
2637 _view->foreach_regionview (sigc::mem_fun (*trim_track.get(), &TimeAxisView::add_ghost));
2640 add_automation_child (Evoral::Parameter(TrimAutomation), trim_track, show);
2644 RouteTimeAxisView::create_mute_automation_child (const Evoral::Parameter& param, bool show)
2646 boost::shared_ptr<AutomationControl> c = _route->mute_control();
2648 error << "Route has no mute automation, unable to add automation track view." << endmsg;
2652 mute_track.reset (new AutomationTimeAxisView (_session,
2653 _route, _route, c, param,
2658 _route->describe_parameter(param)));
2661 _view->foreach_regionview (sigc::mem_fun (*mute_track.get(), &TimeAxisView::add_ghost));
2664 add_automation_child (Evoral::Parameter(MuteAutomation), mute_track, show);
2668 void add_region_to_list (RegionView* rv, RegionList* l)
2670 l->push_back (rv->region());
2674 RouteTimeAxisView::combine_regions ()
2676 /* as of may 2011, we do not offer uncombine for MIDI tracks
2679 if (!is_audio_track()) {
2687 RegionList selected_regions;
2688 boost::shared_ptr<Playlist> playlist = track()->playlist();
2690 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2692 if (selected_regions.size() < 2) {
2696 playlist->clear_changes ();
2697 boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2699 _session->add_command (new StatefulDiffCommand (playlist));
2700 /* make the new region be selected */
2702 return _view->find_view (compound_region);
2706 RouteTimeAxisView::uncombine_regions ()
2708 /* as of may 2011, we do not offer uncombine for MIDI tracks
2710 if (!is_audio_track()) {
2718 RegionList selected_regions;
2719 boost::shared_ptr<Playlist> playlist = track()->playlist();
2721 /* have to grab selected regions first because the uncombine is going
2722 * to change that in the middle of the list traverse
2725 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2727 playlist->clear_changes ();
2729 for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2730 playlist->uncombine (*i);
2733 _session->add_command (new StatefulDiffCommand (playlist));
2737 RouteTimeAxisView::state_id() const
2739 return string_compose ("rtav %1", _route->id().to_s());
2744 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2746 TimeAxisView::remove_child (c);
2748 boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2750 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2751 if (i->second == a) {
2752 _automation_tracks.erase (i);
2760 RouteTimeAxisView::color () const
2762 return route_color ();
2766 RouteTimeAxisView::marked_for_display () const
2768 return !_route->presentation_info().hidden();
2772 RouteTimeAxisView::set_marked_for_display (bool yn)
2774 return RouteUI::mark_hidden (!yn);