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)
100 , TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas)
102 , parent_canvas (canvas)
104 , button_table (3, 3)
105 , route_group_button (S_("RTAV|G"))
106 , playlist_button (S_("RTAV|P"))
107 , automation_button (S_("RTAV|A"))
108 , automation_action_menu (0)
109 , plugins_submenu_item (0)
110 , route_group_menu (0)
111 , playlist_action_menu (0)
113 , color_mode_menu (0)
114 , gm (sess, true, 75, 14)
115 , _ignore_set_layer_display (false)
116 , gain_automation_item(NULL)
117 , trim_automation_item(NULL)
118 , mute_automation_item(NULL)
119 , pan_automation_item(NULL)
121 number_label.set_name("tracknumber label");
122 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
123 number_label.set_alignment(.5, .5);
124 number_label.set_fallthrough_to_parent (true);
126 sess->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::parameter_changed, this, _1), gui_context());
130 RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
132 RouteUI::set_route (rt);
134 CANVAS_DEBUG_NAME (_canvas_display, string_compose ("main for %1", rt->name()));
135 CANVAS_DEBUG_NAME (selection_group, string_compose ("selections for %1", rt->name()));
136 CANVAS_DEBUG_NAME (_ghost_group, string_compose ("ghosts for %1", rt->name()));
139 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
142 gm.set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
143 gm.get_level_meter().set_no_show_all();
144 gm.get_level_meter().setup_meters(50, meter_width);
145 gm.update_gain_sensitive ();
147 string str = gui_property ("height");
149 set_height (atoi (str));
151 set_height (preset_height (HeightNormal));
154 if (!_route->is_auditioner()) {
155 if (gui_property ("visible").empty()) {
156 set_gui_property ("visible", true);
159 set_gui_property ("visible", false);
162 timestretch_rect = 0;
165 ignore_toggle = false;
167 route_group_button.set_name ("route button");
168 playlist_button.set_name ("route button");
169 automation_button.set_name ("route button");
171 route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
172 playlist_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click));
173 automation_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click));
177 if (ARDOUR::Profile->get_mixbus()) {
178 controls_table.attach (*rec_enable_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
180 controls_table.attach (*rec_enable_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
183 if (is_midi_track()) {
184 set_tooltip(*rec_enable_button, _("Record (Right-click for Step Edit)"));
185 gm.set_fader_name ("MidiTrackFader");
187 set_tooltip(*rec_enable_button, _("Record"));
188 gm.set_fader_name ("AudioTrackFader");
191 rec_enable_button->set_sensitive (_session->writable());
193 /* set playlist button tip to the current playlist, and make it update when it changes */
194 update_playlist_tip ();
195 track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context());
198 gm.set_fader_name ("AudioBusFader");
199 Gtk::Fixed *blank = manage(new Gtk::Fixed());
200 controls_button_size_group->add_widget(*blank);
201 if (ARDOUR::Profile->get_mixbus() ) {
202 controls_table.attach (*blank, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
204 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
209 top_hbox.pack_end(gm.get_level_meter(), false, false, 2);
211 if (!ARDOUR::Profile->get_mixbus()) {
212 controls_meters_size_group->add_widget (gm.get_level_meter());
215 _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
216 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
217 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
218 _route->track_number_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::label_view, this), gui_context());
220 if (ARDOUR::Profile->get_mixbus()) {
221 controls_table.attach (*mute_button, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
223 controls_table.attach (*mute_button, 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
225 // mute button is always present, it is used to
226 // force the 'blank' placeholders to the proper size
227 controls_button_size_group->add_widget(*mute_button);
229 if (!_route->is_master()) {
230 if (ARDOUR::Profile->get_mixbus()) {
231 controls_table.attach (*solo_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
233 controls_table.attach (*solo_button, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
236 Gtk::Fixed *blank = manage(new Gtk::Fixed());
237 controls_button_size_group->add_widget(*blank);
238 if (ARDOUR::Profile->get_mixbus()) {
239 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
241 controls_table.attach (*blank, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
246 if (ARDOUR::Profile->get_mixbus()) {
247 controls_table.attach (route_group_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
248 controls_table.attach (gm.get_gain_slider(), 3, 5, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
250 else if (!ARDOUR::Profile->get_trx()) {
251 controls_table.attach (route_group_button, 4, 5, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
252 controls_table.attach (gm.get_gain_slider(), 0, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
255 set_tooltip(*solo_button,_("Solo"));
256 set_tooltip(*mute_button,_("Mute"));
257 set_tooltip(route_group_button, _("Route Group"));
259 mute_button->set_tweaks(ArdourButton::TrackHeader);
260 solo_button->set_tweaks(ArdourButton::TrackHeader);
261 rec_enable_button->set_tweaks(ArdourButton::TrackHeader);
262 playlist_button.set_tweaks(ArdourButton::TrackHeader);
263 automation_button.set_tweaks(ArdourButton::TrackHeader);
264 route_group_button.set_tweaks(ArdourButton::TrackHeader);
266 if (is_midi_track()) {
267 set_tooltip(automation_button, _("MIDI Controllers and Automation"));
269 set_tooltip(automation_button, _("Automation"));
272 update_track_number_visibility();
275 if (ARDOUR::Profile->get_mixbus()) {
276 controls_table.attach (automation_button, 1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
278 else if (!ARDOUR::Profile->get_trx()) {
279 controls_table.attach (automation_button, 3, 4, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
282 if (is_track() && track()->mode() == ARDOUR::Normal) {
283 if (ARDOUR::Profile->get_mixbus()) {
284 controls_table.attach (playlist_button, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
286 else if (!ARDOUR::Profile->get_trx()) {
287 controls_table.attach (playlist_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
293 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
294 _route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::route_property_changed, this, _1), gui_context());
298 str = gui_property ("layer-display");
300 set_layer_display (LayerDisplay (string_2_enum (str, _view->layer_display ())));
303 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
304 track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
306 /* pick up the correct freeze state */
311 _editor.ZoomChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_pixel));
312 UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler));
314 PropertyList* plist = new PropertyList();
316 plist->add (ARDOUR::Properties::mute, true);
317 plist->add (ARDOUR::Properties::solo, true);
319 route_group_menu = new RouteGroupMenu (_session, plist);
321 gm.get_level_meter().signal_scroll_event().connect (sigc::mem_fun (*this, &RouteTimeAxisView::controls_ebox_scroll), false);
324 RouteTimeAxisView::~RouteTimeAxisView ()
326 cleanup_gui_properties ();
328 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
332 delete playlist_action_menu;
333 playlist_action_menu = 0;
338 _automation_tracks.clear ();
340 delete route_group_menu;
341 CatchDeletion (this);
345 RouteTimeAxisView::post_construct ()
347 /* map current state of the route */
349 update_diskstream_display ();
350 setup_processor_menu_and_curves ();
351 reset_processor_automation_curves ();
354 /** Set up the processor menu for the current set of processors, and
355 * display automation curves for any parameters which have data.
358 RouteTimeAxisView::setup_processor_menu_and_curves ()
360 _subplugin_menu_map.clear ();
361 subplugin_menu.items().clear ();
362 _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
363 _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
367 RouteTimeAxisView::route_group_click (GdkEventButton *ev)
369 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
370 if (_route->route_group()) {
371 _route->route_group()->remove (_route);
377 r.push_back (route ());
379 route_group_menu->build (r);
380 route_group_menu->menu()->popup (ev->button, ev->time);
386 RouteTimeAxisView::playlist_changed ()
392 RouteTimeAxisView::label_view ()
394 string x = _route->name ();
395 if (x != name_label.get_text ()) {
396 name_label.set_text (x);
398 const int64_t track_number = _route->track_number ();
399 if (track_number == 0) {
400 number_label.set_text ("");
402 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
407 RouteTimeAxisView::update_track_number_visibility ()
410 bool show_label = _session->config.get_track_name_number();
412 if (_route && _route->is_master()) {
416 if (number_label.get_parent()) {
417 controls_table.remove (number_label);
420 if (ARDOUR::Profile->get_mixbus()) {
421 controls_table.attach (number_label, 3, 4, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
423 controls_table.attach (number_label, 0, 1, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
425 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
426 // except the width of the number label is subtracted from the name-hbox, so we
427 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
428 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
430 number_label.set_size_request(tnw, -1);
431 number_label.show ();
432 name_hbox.set_size_request(TimeAxisView::name_width_px - 2 - tnw, -1); // -2 = cellspacing
434 number_label.hide ();
435 name_hbox.set_size_request(TimeAxisView::name_width_px, -1);
440 RouteTimeAxisView::parameter_changed (string const & p)
442 if (p == "track-name-number") {
443 update_track_number_visibility();
448 RouteTimeAxisView::route_property_changed (const PropertyChange& what_changed)
450 if (what_changed.contains (ARDOUR::Properties::name)) {
456 RouteTimeAxisView::take_name_changed (void *src)
464 RouteTimeAxisView::playlist_click ()
466 build_playlist_menu ();
467 conditionally_add_to_selection ();
468 playlist_action_menu->popup (1, gtk_get_current_event_time());
472 RouteTimeAxisView::automation_click ()
474 conditionally_add_to_selection ();
475 build_automation_action_menu (false);
476 automation_action_menu->popup (1, gtk_get_current_event_time());
480 RouteTimeAxisView::build_automation_action_menu (bool for_selection)
482 using namespace Menu_Helpers;
484 /* detach subplugin_menu from automation_action_menu before we delete automation_action_menu,
485 otherwise bad things happen (see comment for similar case in MidiTimeAxisView::build_automation_action_menu)
488 detach_menu (subplugin_menu);
490 _main_automation_menu_map.clear ();
491 delete automation_action_menu;
492 automation_action_menu = new Menu;
494 MenuList& items = automation_action_menu->items();
496 automation_action_menu->set_name ("ArdourContextMenu");
498 items.push_back (MenuElem (_("Show All Automation"),
499 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_all_automation), for_selection)));
501 items.push_back (MenuElem (_("Show Existing Automation"),
502 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_existing_automation), for_selection)));
504 items.push_back (MenuElem (_("Hide All Automation"),
505 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::hide_all_automation), for_selection)));
507 /* Attach the plugin submenu. It may have previously been used elsewhere,
508 so it was detached above
511 if (!subplugin_menu.items().empty()) {
512 items.push_back (SeparatorElem ());
513 items.push_back (MenuElem (_("Processor automation"), subplugin_menu));
514 items.back().set_sensitive (!for_selection || _editor.get_selection().tracks.size() == 1);;
517 /* Add any route automation */
520 items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &RouteTimeAxisView::update_gain_track_visibility)));
521 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
522 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
523 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
525 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
529 items.push_back (CheckMenuElem (_("Trim"), sigc::mem_fun (*this, &RouteTimeAxisView::update_trim_track_visibility)));
530 trim_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
531 trim_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
532 (trim_track && string_is_affirmative (trim_track->gui_property ("visible"))));
534 _main_automation_menu_map[Evoral::Parameter(TrimAutomation)] = trim_automation_item;
538 items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &RouteTimeAxisView::update_mute_track_visibility)));
539 mute_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
540 mute_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
541 (mute_track && string_is_affirmative (mute_track->gui_property ("visible"))));
543 _main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item;
546 if (!pan_tracks.empty()) {
547 items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &RouteTimeAxisView::update_pan_track_visibility)));
548 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
549 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
550 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
552 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
553 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
554 _main_automation_menu_map[*p] = pan_automation_item;
560 RouteTimeAxisView::build_display_menu ()
562 using namespace Menu_Helpers;
566 TimeAxisView::build_display_menu ();
568 /* now fill it with our stuff */
570 MenuList& items = display_menu->items();
571 display_menu->set_name ("ArdourContextMenu");
573 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
575 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
577 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
579 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
581 items.push_back (SeparatorElem());
584 detach_menu (*_size_menu);
587 items.push_back (MenuElem (_("Height"), *_size_menu));
589 items.push_back (SeparatorElem());
591 items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
592 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
593 items.push_back (SeparatorElem());
595 // Hook for derived classes to add type specific stuff
596 append_extra_display_menu_items ();
600 Menu* layers_menu = manage (new Menu);
601 MenuList &layers_items = layers_menu->items();
602 layers_menu->set_name("ArdourContextMenu");
604 RadioMenuItem::Group layers_group;
606 /* Find out how many overlaid/stacked tracks we have in the selection */
610 TrackSelection const & s = _editor.get_selection().tracks;
611 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
612 StreamView* v = (*i)->view ();
617 switch (v->layer_display ()) {
628 /* We're not connecting to signal_toggled() here; in the case where these two items are
629 set to be in the `inconsistent' state, it seems that one or other will end up active
630 as well as inconsistent (presumably due to the RadioMenuItem::Group). Then when you
631 select the active one, no toggled signal is emitted so nothing happens.
634 _ignore_set_layer_display = true;
636 layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid")));
637 RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
638 i->set_active (overlaid != 0 && stacked == 0);
639 i->set_inconsistent (overlaid != 0 && stacked != 0);
640 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true));
642 layers_items.push_back (RadioMenuElem (layers_group, _("Stacked")));
643 i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
644 i->set_active (overlaid == 0 && stacked != 0);
645 i->set_inconsistent (overlaid != 0 && stacked != 0);
646 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
648 _ignore_set_layer_display = false;
650 items.push_back (MenuElem (_("Layers"), *layers_menu));
652 Menu* alignment_menu = manage (new Menu);
653 MenuList& alignment_items = alignment_menu->items();
654 alignment_menu->set_name ("ArdourContextMenu");
656 RadioMenuItem::Group align_group;
658 /* Same verbose hacks as for the layering options above */
664 boost::shared_ptr<Track> first_track;
666 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
667 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
668 if (!r || !r->is_track ()) {
673 first_track = r->track();
676 switch (r->track()->alignment_choice()) {
680 switch (r->track()->alignment_style()) {
681 case ExistingMaterial:
689 case UseExistingMaterial:
705 inconsistent = false;
712 if (!inconsistent && first_track) {
714 alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)")));
715 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
716 i->set_active (automatic != 0 && existing == 0 && capture == 0);
717 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true));
719 switch (first_track->alignment_choice()) {
721 switch (first_track->alignment_style()) {
722 case ExistingMaterial:
723 alignment_items.push_back (MenuElem (_("(Currently: Existing Material)")));
726 alignment_items.push_back (MenuElem (_("(Currently: Capture Time)")));
734 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
735 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
736 i->set_active (existing != 0 && capture == 0 && automatic == 0);
737 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true));
739 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
740 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
741 i->set_active (existing == 0 && capture != 0 && automatic == 0);
742 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true));
744 items.push_back (MenuElem (_("Alignment"), *alignment_menu));
750 Menu* mode_menu = manage (new Menu);
751 MenuList& mode_items = mode_menu->items ();
752 mode_menu->set_name ("ArdourContextMenu");
754 RadioMenuItem::Group mode_group;
760 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
761 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
762 if (!r || !r->is_track ()) {
766 switch (r->track()->mode()) {
779 mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode")));
780 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
781 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal, true));
782 i->set_active (normal != 0 && tape == 0 && non_layered == 0);
783 i->set_inconsistent (normal != 0 && (tape != 0 || non_layered != 0));
785 mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode")));
786 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
787 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive, true));
788 i->set_active (normal == 0 && tape != 0 && non_layered == 0);
789 i->set_inconsistent (tape != 0 && (normal != 0 || non_layered != 0));
791 mode_items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode")));
792 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
793 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered, true));
794 i->set_active (normal == 0 && tape == 0 && non_layered != 0);
795 i->set_inconsistent (non_layered != 0 && (normal != 0 || tape != 0));
797 items.push_back (MenuElem (_("Record Mode"), *mode_menu));
799 items.push_back (SeparatorElem());
801 build_playlist_menu ();
802 items.push_back (MenuElem (_("Playlist"), *playlist_action_menu));
803 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
806 route_group_menu->detach ();
809 for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) {
810 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
812 r.push_back (rtv->route ());
817 r.push_back (route ());
820 route_group_menu->build (r);
821 items.push_back (MenuElem (_("Group"), *route_group_menu->menu ()));
823 build_automation_action_menu (true);
824 items.push_back (MenuElem (_("Automation"), *automation_action_menu));
826 items.push_back (SeparatorElem());
830 TrackSelection const & s = _editor.get_selection().tracks;
831 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
832 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
837 if (r->route()->active()) {
844 items.push_back (CheckMenuElem (_("Active")));
845 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
846 bool click_sets_active = true;
847 if (active > 0 && inactive == 0) {
848 i->set_active (true);
849 click_sets_active = false;
850 } else if (active > 0 && inactive > 0) {
851 i->set_inconsistent (true);
853 i->set_sensitive(! _session->transport_rolling());
854 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), click_sets_active, true));
856 items.push_back (SeparatorElem());
857 items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true)));
858 if (_route && !_route->is_master()) {
859 items.push_back (SeparatorElem());
860 items.push_back (MenuElem (_("Duplicate..."), boost::bind (&ARDOUR_UI::start_duplicate_routes, ARDOUR_UI::instance())));
862 items.push_back (SeparatorElem());
863 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(_editor, &PublicEditor::remove_tracks)));
867 RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection)
869 if (apply_to_selection) {
870 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_track_mode, _1, mode, false));
873 bool needs_bounce = false;
875 if (!track()->can_use_mode (mode, needs_bounce)) {
881 cerr << "would bounce this one\n";
886 track()->set_mode (mode);
891 RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layers, int layer)
893 TimeAxisView::show_timestretch (start, end, layers, layer);
903 /* check that the time selection was made in our route, or our route group.
904 remember that route_group() == 0 implies the route is *not* in a edit group.
907 if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
908 /* this doesn't apply to us */
912 /* ignore it if our edit group is not active */
914 if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
919 if (timestretch_rect == 0) {
920 timestretch_rect = new ArdourCanvas::Rectangle (canvas_display ());
921 timestretch_rect->set_fill_color (ArdourCanvas::HSV (UIConfiguration::instance().color ("time stretch fill")).mod (UIConfiguration::instance().modifier ("time stretch fill")).color());
922 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
925 timestretch_rect->show ();
926 timestretch_rect->raise_to_top ();
928 double const x1 = start / _editor.get_current_zoom();
929 double const x2 = (end - 1) / _editor.get_current_zoom();
931 timestretch_rect->set (ArdourCanvas::Rect (x1, current_height() * (layers - layer - 1) / layers,
932 x2, current_height() * (layers - layer) / layers));
936 RouteTimeAxisView::hide_timestretch ()
938 TimeAxisView::hide_timestretch ();
940 if (timestretch_rect) {
941 timestretch_rect->hide ();
946 RouteTimeAxisView::show_selection (TimeSelection& ts)
950 /* ignore it if our edit group is not active or if the selection was started
951 in some other track or route group (remember that route_group() == 0 means
952 that the track is not in an route group).
955 if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
956 (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
962 TimeAxisView::show_selection (ts);
966 RouteTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
969 bool height_changed = (height == 0) || (h != height);
972 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
975 gm.get_level_meter().setup_meters (gmlen, meter_width);
977 TimeAxisView::set_height (h, m);
980 _view->set_height ((double) current_height());
983 if (height >= preset_height (HeightNormal)) {
987 gm.get_gain_slider().show();
989 if (!_route || _route->is_monitor()) {
994 if (rec_enable_button)
995 rec_enable_button->show();
997 route_group_button.show();
998 automation_button.show();
1000 if (is_track() && track()->mode() == ARDOUR::Normal) {
1001 playlist_button.show();
1008 gm.get_gain_slider().hide();
1009 mute_button->show();
1010 if (!_route || _route->is_monitor()) {
1011 solo_button->hide();
1013 solo_button->show();
1015 if (rec_enable_button)
1016 rec_enable_button->show();
1018 route_group_button.hide ();
1019 automation_button.hide ();
1021 if (is_track() && track()->mode() == ARDOUR::Normal) {
1022 playlist_button.hide ();
1027 if (height_changed && !no_redraw) {
1028 /* only emit the signal if the height really changed */
1034 RouteTimeAxisView::route_color_changed ()
1037 _view->apply_color (color(), StreamView::RegionColor);
1040 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1044 RouteTimeAxisView::reset_samples_per_pixel ()
1046 set_samples_per_pixel (_editor.get_current_zoom());
1050 RouteTimeAxisView::set_samples_per_pixel (double fpp)
1055 speed = track()->speed();
1059 _view->set_samples_per_pixel (fpp * speed);
1062 TimeAxisView::set_samples_per_pixel (fpp * speed);
1066 RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
1068 if (!mitem->get_active()) {
1069 /* this is one of the two calls made when these radio menu items change status. this one
1070 is for the item that became inactive, and we want to ignore it.
1075 if (apply_to_selection) {
1076 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
1079 track()->set_align_choice (choice);
1085 RouteTimeAxisView::rename_current_playlist ()
1087 ArdourPrompter prompter (true);
1090 boost::shared_ptr<Track> tr = track();
1091 if (!tr || tr->destructive()) {
1095 boost::shared_ptr<Playlist> pl = tr->playlist();
1100 prompter.set_title (_("Rename Playlist"));
1101 prompter.set_prompt (_("New name for playlist:"));
1102 prompter.set_initial_text (pl->name());
1103 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1104 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1106 switch (prompter.run ()) {
1107 case Gtk::RESPONSE_ACCEPT:
1108 prompter.get_result (name);
1109 if (name.length()) {
1110 pl->set_name (name);
1120 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
1122 std::string ret (basename);
1124 std::string const group_string = "." + route_group()->name() + ".";
1126 // iterate through all playlists
1128 for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1129 std::string tmp = (*i)->name();
1131 std::string::size_type idx = tmp.find(group_string);
1132 // find those which belong to this group
1133 if (idx != string::npos) {
1134 tmp = tmp.substr(idx + group_string.length());
1136 // and find the largest current number
1138 if (x > maxnumber) {
1147 snprintf (buf, sizeof(buf), "%d", maxnumber);
1149 ret = this->name() + "." + route_group()->name () + "." + buf;
1155 RouteTimeAxisView::use_copy_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1159 boost::shared_ptr<Track> tr = track ();
1160 if (!tr || tr->destructive()) {
1164 boost::shared_ptr<const Playlist> pl = tr->playlist();
1171 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::select.property_id)) {
1172 name = resolve_new_group_playlist_name(name, playlists_before_op);
1175 while (_session->playlists->by_name(name)) {
1176 name = Playlist::bump_name (name, *_session);
1179 // TODO: The prompter "new" button should be de-activated if the user
1180 // specifies a playlist name which already exists in the session.
1184 ArdourPrompter prompter (true);
1186 prompter.set_title (_("New Copy Playlist"));
1187 prompter.set_prompt (_("Name for new playlist:"));
1188 prompter.set_initial_text (name);
1189 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1190 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1191 prompter.show_all ();
1193 switch (prompter.run ()) {
1194 case Gtk::RESPONSE_ACCEPT:
1195 prompter.get_result (name);
1203 if (name.length()) {
1204 tr->use_copy_playlist ();
1205 tr->playlist()->set_name (name);
1210 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1214 boost::shared_ptr<Track> tr = track ();
1215 if (!tr || tr->destructive()) {
1219 boost::shared_ptr<const Playlist> pl = tr->playlist();
1226 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::select.property_id)) {
1227 name = resolve_new_group_playlist_name(name,playlists_before_op);
1230 while (_session->playlists->by_name(name)) {
1231 name = Playlist::bump_name (name, *_session);
1237 ArdourPrompter prompter (true);
1239 prompter.set_title (_("New Playlist"));
1240 prompter.set_prompt (_("Name for new playlist:"));
1241 prompter.set_initial_text (name);
1242 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1243 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1245 switch (prompter.run ()) {
1246 case Gtk::RESPONSE_ACCEPT:
1247 prompter.get_result (name);
1255 if (name.length()) {
1256 tr->use_new_playlist ();
1257 tr->playlist()->set_name (name);
1262 RouteTimeAxisView::clear_playlist ()
1264 boost::shared_ptr<Track> tr = track ();
1265 if (!tr || tr->destructive()) {
1269 boost::shared_ptr<Playlist> pl = tr->playlist();
1274 _editor.clear_playlist (pl);
1278 RouteTimeAxisView::speed_changed ()
1280 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_pixel, this));
1284 RouteTimeAxisView::update_diskstream_display ()
1294 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1296 if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1298 /* special case: select/deselect all tracks */
1300 _editor.begin_reversible_selection_op (X_("Selection Click"));
1302 if (_editor.get_selection().selected (this)) {
1303 _editor.get_selection().clear_tracks ();
1305 _editor.select_all_tracks ();
1308 _editor.commit_reversible_selection_op ();
1313 _editor.begin_reversible_selection_op (X_("Selection Click"));
1315 switch (ArdourKeyboard::selection_type (ev->state)) {
1316 case Selection::Toggle:
1317 _editor.get_selection().toggle (this);
1320 case Selection::Set:
1321 _editor.get_selection().set (this);
1324 case Selection::Extend:
1325 _editor.extend_selection_to_track (*this);
1328 case Selection::Add:
1329 _editor.get_selection().add (this);
1333 _editor.commit_reversible_selection_op ();
1337 RouteTimeAxisView::set_selected_points (PointSelection& points)
1339 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1340 (*i)->set_selected_points (points);
1342 AudioStreamView* asv = dynamic_cast<AudioStreamView*>(_view);
1344 asv->set_selected_points (points);
1349 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1352 _view->set_selected_regionviews (regions);
1356 /** Add the selectable things that we have to a list.
1357 * @param results List to add things to.
1360 RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results, bool within)
1365 speed = track()->speed();
1368 framepos_t const start_adjusted = session_frame_to_track_frame(start, speed);
1369 framepos_t const end_adjusted = session_frame_to_track_frame(end, speed);
1371 if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1372 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1375 /* pick up visible automation tracks */
1377 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1378 if (!(*i)->hidden()) {
1379 (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1385 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1388 _view->get_inverted_selectables (sel, results);
1391 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1392 if (!(*i)->hidden()) {
1393 (*i)->get_inverted_selectables (sel, results);
1401 RouteTimeAxisView::route_group () const
1403 return _route->route_group();
1407 RouteTimeAxisView::name() const
1409 return _route->name();
1412 boost::shared_ptr<Playlist>
1413 RouteTimeAxisView::playlist () const
1415 boost::shared_ptr<Track> tr;
1417 if ((tr = track()) != 0) {
1418 return tr->playlist();
1420 return boost::shared_ptr<Playlist> ();
1425 RouteTimeAxisView::name_entry_changed ()
1427 TimeAxisView::name_entry_changed ();
1429 string x = name_entry->get_text ();
1431 if (x == _route->name()) {
1435 strip_whitespace_edges (x);
1437 if (x.length() == 0) {
1438 name_entry->set_text (_route->name());
1442 if (_session->route_name_internal (x)) {
1443 ARDOUR_UI::instance()->popup_error (string_compose (_("You cannot create a track with that name as it is reserved for %1"),
1445 name_entry->grab_focus ();
1446 } else if (RouteUI::verify_new_route_name (x)) {
1447 _route->set_name (x);
1449 name_entry->grab_focus ();
1453 boost::shared_ptr<Region>
1454 RouteTimeAxisView::find_next_region (framepos_t pos, RegionPoint point, int32_t dir)
1456 boost::shared_ptr<Playlist> pl = playlist ();
1459 return pl->find_next_region (pos, point, dir);
1462 return boost::shared_ptr<Region> ();
1466 RouteTimeAxisView::find_next_region_boundary (framepos_t pos, int32_t dir)
1468 boost::shared_ptr<Playlist> pl = playlist ();
1471 return pl->find_next_region_boundary (pos, dir);
1478 RouteTimeAxisView::fade_range (TimeSelection& selection)
1480 boost::shared_ptr<Playlist> what_we_got;
1481 boost::shared_ptr<Track> tr = track ();
1482 boost::shared_ptr<Playlist> playlist;
1485 /* route is a bus, not a track */
1489 playlist = tr->playlist();
1491 TimeSelection time (selection);
1492 float const speed = tr->speed();
1493 if (speed != 1.0f) {
1494 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1495 (*i).start = session_frame_to_track_frame((*i).start, speed);
1496 (*i).end = session_frame_to_track_frame((*i).end, speed);
1500 playlist->clear_changes ();
1501 playlist->clear_owned_changes ();
1503 playlist->fade_range (time);
1505 vector<Command*> cmds;
1506 playlist->rdiff (cmds);
1507 _session->add_commands (cmds);
1508 _session->add_command (new StatefulDiffCommand (playlist));
1513 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1515 boost::shared_ptr<Playlist> what_we_got;
1516 boost::shared_ptr<Track> tr = track ();
1517 boost::shared_ptr<Playlist> playlist;
1520 /* route is a bus, not a track */
1524 playlist = tr->playlist();
1526 TimeSelection time (selection.time);
1527 float const speed = tr->speed();
1528 if (speed != 1.0f) {
1529 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1530 (*i).start = session_frame_to_track_frame((*i).start, speed);
1531 (*i).end = session_frame_to_track_frame((*i).end, speed);
1535 playlist->clear_changes ();
1536 playlist->clear_owned_changes ();
1540 if (playlist->cut (time) != 0) {
1541 if (Config->get_edit_mode() == Ripple)
1542 playlist->ripple(time.start(), -time.length(), NULL);
1543 // no need to exclude any regions from rippling here
1545 vector<Command*> cmds;
1546 playlist->rdiff (cmds);
1547 _session->add_commands (cmds);
1549 _session->add_command (new StatefulDiffCommand (playlist));
1554 if ((what_we_got = playlist->cut (time)) != 0) {
1555 _editor.get_cut_buffer().add (what_we_got);
1556 if (Config->get_edit_mode() == Ripple)
1557 playlist->ripple(time.start(), -time.length(), NULL);
1558 // no need to exclude any regions from rippling here
1560 vector<Command*> cmds;
1561 playlist->rdiff (cmds);
1562 _session->add_commands (cmds);
1564 _session->add_command (new StatefulDiffCommand (playlist));
1568 if ((what_we_got = playlist->copy (time)) != 0) {
1569 _editor.get_cut_buffer().add (what_we_got);
1574 if ((what_we_got = playlist->cut (time)) != 0) {
1575 if (Config->get_edit_mode() == Ripple)
1576 playlist->ripple(time.start(), -time.length(), NULL);
1577 // no need to exclude any regions from rippling here
1579 vector<Command*> cmds;
1580 playlist->rdiff (cmds);
1581 _session->add_commands (cmds);
1582 _session->add_command (new StatefulDiffCommand (playlist));
1583 what_we_got->release ();
1590 RouteTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx)
1596 boost::shared_ptr<Playlist> pl = playlist ();
1597 const ARDOUR::DataType type = pl->data_type();
1598 PlaylistSelection::const_iterator p = selection.playlists.get_nth(type, ctx.counts.n_playlists(type));
1600 if (p == selection.playlists.end()) {
1603 ctx.counts.increase_n_playlists(type);
1605 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
1607 if (track()->speed() != 1.0f) {
1608 pos = session_frame_to_track_frame (pos, track()->speed());
1609 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
1612 /* add multi-paste offset if applicable */
1613 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent();
1614 const framecnt_t duration = extent.second - extent.first;
1615 pos += _editor.get_paste_offset(pos, ctx.count, duration);
1617 pl->clear_changes ();
1618 pl->clear_owned_changes ();
1619 if (Config->get_edit_mode() == Ripple) {
1620 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
1621 framecnt_t amount = extent.second - extent.first;
1622 pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
1624 pl->paste (*p, pos, ctx.times);
1626 vector<Command*> cmds;
1628 _session->add_commands (cmds);
1630 _session->add_command (new StatefulDiffCommand (pl));
1636 struct PlaylistSorter {
1637 bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1638 return a->sort_id() < b->sort_id();
1643 RouteTimeAxisView::build_playlist_menu ()
1645 using namespace Menu_Helpers;
1651 delete playlist_action_menu;
1652 playlist_action_menu = new Menu;
1653 playlist_action_menu->set_name ("ArdourContextMenu");
1655 MenuList& playlist_items = playlist_action_menu->items();
1656 playlist_action_menu->set_name ("ArdourContextMenu");
1657 playlist_items.clear();
1659 RadioMenuItem::Group playlist_group;
1660 boost::shared_ptr<Track> tr = track ();
1662 vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
1664 /* sort the playlists */
1666 sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1668 /* add the playlists to the menu */
1669 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1670 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1671 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1672 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1674 if (tr->playlist()->id() == (*i)->id()) {
1680 playlist_items.push_back (SeparatorElem());
1681 playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1682 playlist_items.push_back (SeparatorElem());
1684 if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::select.property_id)) {
1685 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1686 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1689 // Use a label which tells the user what is happening
1690 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1691 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1695 playlist_items.push_back (SeparatorElem());
1696 playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1697 playlist_items.push_back (SeparatorElem());
1699 playlist_items.push_back (MenuElem(_("Select from All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1703 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1705 assert (is_track());
1707 // exit if we were triggered by deactivating the old playlist
1708 if (!item->get_active()) {
1712 boost::shared_ptr<Playlist> pl (wpl.lock());
1718 if (track()->playlist() == pl) {
1719 // exit when use_playlist is called by the creation of the playlist menu
1720 // or the playlist choice is unchanged
1724 track()->use_playlist (pl);
1726 RouteGroup* rg = route_group();
1728 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::select.property_id)) {
1729 std::string group_string = "." + rg->name() + ".";
1731 std::string take_name = pl->name();
1732 std::string::size_type idx = take_name.find(group_string);
1734 if (idx == std::string::npos)
1737 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1739 boost::shared_ptr<RouteList> rl (rg->route_list());
1741 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1742 if ((*i) == this->route()) {
1746 std::string playlist_name = (*i)->name()+group_string+take_name;
1748 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1753 if (track->freeze_state() == Track::Frozen) {
1754 /* Don't change playlists of frozen tracks */
1758 boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1760 // No playlist for this track for this take yet, make it
1761 track->use_new_playlist();
1762 track->playlist()->set_name(playlist_name);
1764 track->use_playlist(ipl);
1771 RouteTimeAxisView::update_playlist_tip ()
1773 RouteGroup* rg = route_group ();
1774 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::select.property_id)) {
1775 string group_string = "." + rg->name() + ".";
1777 string take_name = track()->playlist()->name();
1778 string::size_type idx = take_name.find(group_string);
1780 if (idx != string::npos) {
1781 /* find the bit containing the take number / name */
1782 take_name = take_name.substr (idx + group_string.length());
1784 /* set the playlist button tooltip to the take name */
1787 string_compose(_("Take: %1.%2"),
1788 Gtkmm2ext::markup_escape_text (rg->name()),
1789 Gtkmm2ext::markup_escape_text (take_name))
1796 /* set the playlist button tooltip to the playlist name */
1797 set_tooltip (playlist_button, _("Playlist") + std::string(": ") + Gtkmm2ext::markup_escape_text (track()->playlist()->name()));
1802 RouteTimeAxisView::show_playlist_selector ()
1804 _editor.playlist_selector().show_for (this);
1808 RouteTimeAxisView::map_frozen ()
1814 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1816 switch (track()->freeze_state()) {
1818 playlist_button.set_sensitive (false);
1819 rec_enable_button->set_sensitive (false);
1822 playlist_button.set_sensitive (true);
1823 rec_enable_button->set_sensitive (true);
1829 RouteTimeAxisView::color_handler ()
1831 //case cTimeStretchOutline:
1832 if (timestretch_rect) {
1833 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
1835 //case cTimeStretchFill:
1836 if (timestretch_rect) {
1837 timestretch_rect->set_fill_color (UIConfiguration::instance().color ("time stretch fill"));
1843 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1844 * Will add track if necessary.
1847 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1849 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1850 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1853 /* it doesn't exist yet, so we don't care about the button state: just add it */
1854 create_automation_child (param, true);
1857 bool yn = menu->get_active();
1858 bool changed = false;
1860 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1862 /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1863 will have done that for us.
1866 if (changed && !no_redraw) {
1874 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1876 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1882 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1884 if (menu && !_hidden) {
1885 ignore_toggle = true;
1886 menu->set_active (false);
1887 ignore_toggle = false;
1890 if (_route && !no_redraw) {
1896 RouteTimeAxisView::update_gain_track_visibility ()
1898 bool const showit = gain_automation_item->get_active();
1900 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1901 gain_track->set_marked_for_display (showit);
1903 /* now trigger a redisplay */
1906 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1912 RouteTimeAxisView::update_trim_track_visibility ()
1914 bool const showit = trim_automation_item->get_active();
1916 if (showit != string_is_affirmative (trim_track->gui_property ("visible"))) {
1917 trim_track->set_marked_for_display (showit);
1919 /* now trigger a redisplay */
1922 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1928 RouteTimeAxisView::update_mute_track_visibility ()
1930 bool const showit = mute_automation_item->get_active();
1932 if (showit != string_is_affirmative (mute_track->gui_property ("visible"))) {
1933 mute_track->set_marked_for_display (showit);
1935 /* now trigger a redisplay */
1938 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1944 RouteTimeAxisView::update_pan_track_visibility ()
1946 bool const showit = pan_automation_item->get_active();
1947 bool changed = false;
1949 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1950 if ((*i)->set_marked_for_display (showit)) {
1956 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1961 RouteTimeAxisView::ensure_pan_views (bool show)
1963 bool changed = false;
1964 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1966 (*i)->set_marked_for_display (false);
1969 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1973 if (!_route->panner()) {
1977 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1978 set<Evoral::Parameter>::iterator p;
1980 for (p = params.begin(); p != params.end(); ++p) {
1981 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1983 if (pan_control->parameter().type() == NullAutomation) {
1984 error << "Pan control has NULL automation type!" << endmsg;
1988 if (automation_child (pan_control->parameter ()).get () == 0) {
1990 /* we don't already have an AutomationTimeAxisView for this parameter */
1992 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1994 boost::shared_ptr<AutomationTimeAxisView> t (
1995 new AutomationTimeAxisView (_session,
1999 pan_control->parameter (),
2007 pan_tracks.push_back (t);
2008 add_automation_child (*p, t, show);
2010 pan_tracks.push_back (automation_child (pan_control->parameter ()));
2017 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
2019 if (apply_to_selection) {
2020 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
2024 /* Show our automation */
2026 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2027 i->second->set_marked_for_display (true);
2029 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2032 menu->set_active(true);
2037 /* Show processor automation */
2039 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2040 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2041 if ((*ii)->view == 0) {
2042 add_processor_automation_curve ((*i)->processor, (*ii)->what);
2045 (*ii)->menu_item->set_active (true);
2058 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
2060 if (apply_to_selection) {
2061 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
2065 /* Show our automation */
2067 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2068 if (i->second->has_automation()) {
2069 i->second->set_marked_for_display (true);
2071 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2073 menu->set_active(true);
2078 /* Show processor automation */
2080 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2081 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2082 if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
2083 (*ii)->menu_item->set_active (true);
2095 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
2097 if (apply_to_selection) {
2098 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
2102 /* Hide our automation */
2104 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2105 i->second->set_marked_for_display (false);
2107 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2110 menu->set_active (false);
2114 /* Hide processor automation */
2116 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2117 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2118 (*ii)->menu_item->set_active (false);
2129 RouteTimeAxisView::region_view_added (RegionView* rv)
2131 /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
2132 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
2133 boost::shared_ptr<AutomationTimeAxisView> atv;
2135 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
2140 for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
2141 (*i)->add_ghost(rv);
2145 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
2147 for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
2153 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
2155 parent.remove_processor_automation_node (this);
2159 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
2162 remove_child (pan->view);
2166 RouteTimeAxisView::ProcessorAutomationNode*
2167 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2169 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2171 if ((*i)->processor == processor) {
2173 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2174 if ((*ii)->what == what) {
2184 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
2186 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2189 ProcessorAutomationNode* pan;
2191 if ((pan = find_processor_automation_node (processor, what)) == 0) {
2192 /* session state may never have been saved with new plugin */
2193 error << _("programming error: ")
2194 << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
2195 processor->name(), what.type(), (int) what.channel(), what.id() )
2197 abort(); /*NOTREACHED*/
2205 boost::shared_ptr<AutomationControl> control
2206 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
2208 pan->view = boost::shared_ptr<AutomationTimeAxisView>(
2209 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
2210 _editor, *this, false, parent_canvas,
2211 processor->describe_parameter (what), processor->name()));
2213 pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
2215 add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
2218 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
2223 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
2226 pan->menu_item->set_active (false);
2235 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
2237 boost::shared_ptr<Processor> processor (p.lock ());
2239 if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
2240 /* The Amp processor is a special case and is dealt with separately */
2244 set<Evoral::Parameter> existing;
2246 processor->what_has_data (existing);
2248 for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
2250 Evoral::Parameter param (*i);
2251 boost::shared_ptr<AutomationLine> al;
2253 if ((al = find_processor_automation_curve (processor, param)) != 0) {
2256 add_processor_automation_curve (processor, param);
2262 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
2264 using namespace Menu_Helpers;
2268 track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
2270 _automation_tracks[param] = track;
2272 /* existing state overrides "show" argument */
2273 string s = track->gui_property ("visible");
2275 show = string_is_affirmative (s);
2278 /* this might or might not change the visibility status, so don't rely on it */
2279 track->set_marked_for_display (show);
2281 if (show && !no_redraw) {
2285 if (!ARDOUR::parameter_is_midi((AutomationType)param.type())) {
2286 /* MIDI-related parameters are always in the menu, there's no
2287 reason to rebuild the menu just because we added a automation
2288 lane for one of them. But if we add a non-MIDI automation
2289 lane, then we need to invalidate the display menu.
2291 delete display_menu;
2297 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2299 boost::shared_ptr<Processor> processor (p.lock ());
2301 if (!processor || !processor->display_to_user ()) {
2305 /* we use this override to veto the Amp processor from the plugin menu,
2306 as its automation lane can be accessed using the special "Fader" menu
2310 if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2314 using namespace Menu_Helpers;
2315 ProcessorAutomationInfo *rai;
2316 list<ProcessorAutomationInfo*>::iterator x;
2318 const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2320 if (automatable.empty()) {
2324 for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2325 if ((*x)->processor == processor) {
2330 if (x == processor_automation.end()) {
2331 rai = new ProcessorAutomationInfo (processor);
2332 processor_automation.push_back (rai);
2337 /* any older menu was deleted at the top of processors_changed()
2338 when we cleared the subplugin menu.
2341 rai->menu = manage (new Menu);
2342 MenuList& items = rai->menu->items();
2343 rai->menu->set_name ("ArdourContextMenu");
2347 std::set<Evoral::Parameter> has_visible_automation;
2348 AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2350 for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2352 ProcessorAutomationNode* pan;
2353 Gtk::CheckMenuItem* mitem;
2355 string name = processor->describe_parameter (*i);
2357 if (name == X_("hidden")) {
2361 items.push_back (CheckMenuElem (name));
2362 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2364 _subplugin_menu_map[*i] = mitem;
2366 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2367 mitem->set_active(true);
2370 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2374 pan = new ProcessorAutomationNode (*i, mitem, *this);
2376 rai->lines.push_back (pan);
2380 pan->menu_item = mitem;
2384 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2387 if (items.size() == 0) {
2391 /* add the menu for this processor, because the subplugin
2392 menu is always cleared at the top of processors_changed().
2393 this is the result of some poor design in gtkmm and/or
2397 subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2402 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2403 RouteTimeAxisView::ProcessorAutomationNode* pan)
2405 bool showit = pan->menu_item->get_active();
2406 bool redraw = false;
2408 if (pan->view == 0 && showit) {
2409 add_processor_automation_curve (rai->processor, pan->what);
2413 if (pan->view && pan->view->set_marked_for_display (showit)) {
2417 if (redraw && !no_redraw) {
2423 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2425 if (c.type == RouteProcessorChange::MeterPointChange) {
2426 /* nothing to do if only the meter point has changed */
2430 using namespace Menu_Helpers;
2432 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2433 (*i)->valid = false;
2436 setup_processor_menu_and_curves ();
2438 bool deleted_processor_automation = false;
2440 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2442 list<ProcessorAutomationInfo*>::iterator tmp;
2450 processor_automation.erase (i);
2451 deleted_processor_automation = true;
2458 if (deleted_processor_automation && !no_redraw) {
2463 boost::shared_ptr<AutomationLine>
2464 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2466 ProcessorAutomationNode* pan;
2468 if ((pan = find_processor_automation_node (processor, what)) != 0) {
2474 return boost::shared_ptr<AutomationLine>();
2478 RouteTimeAxisView::reset_processor_automation_curves ()
2480 for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2486 RouteTimeAxisView::can_edit_name () const
2488 /* we do not allow track name changes if it is record enabled
2490 return !_route->record_enabled();
2494 RouteTimeAxisView::blink_rec_display (bool onoff)
2496 RouteUI::blink_rec_display (onoff);
2500 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2502 if (_ignore_set_layer_display) {
2506 if (apply_to_selection) {
2507 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2511 _view->set_layer_display (d);
2514 set_gui_property (X_("layer-display"), enum_2_string (d));
2519 RouteTimeAxisView::layer_display () const
2522 return _view->layer_display ();
2525 /* we don't know, since we don't have a _view, so just return something */
2531 boost::shared_ptr<AutomationTimeAxisView>
2532 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2534 AutomationTracks::iterator i = _automation_tracks.find(param);
2535 if (i != _automation_tracks.end()) {
2538 return boost::shared_ptr<AutomationTimeAxisView>();
2543 RouteTimeAxisView::fast_update ()
2545 gm.get_level_meter().update_meters ();
2549 RouteTimeAxisView::hide_meter ()
2552 gm.get_level_meter().hide_meters ();
2556 RouteTimeAxisView::show_meter ()
2562 RouteTimeAxisView::reset_meter ()
2564 if (UIConfiguration::instance().get_show_track_meters()) {
2565 int meter_width = 3;
2566 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2569 gm.get_level_meter().setup_meters (height - 9, meter_width);
2576 RouteTimeAxisView::clear_meter ()
2578 gm.get_level_meter().clear_meters ();
2582 RouteTimeAxisView::meter_changed ()
2584 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2586 if (_route && !no_redraw && UIConfiguration::instance().get_show_track_meters()) {
2589 // reset peak when meter point changes
2590 gm.reset_peak_display();
2594 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2597 if (_route && !no_redraw) {
2603 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2605 using namespace Menu_Helpers;
2607 if (!_underlay_streams.empty()) {
2608 MenuList& parent_items = parent_menu->items();
2609 Menu* gs_menu = manage (new Menu);
2610 gs_menu->set_name ("ArdourContextMenu");
2611 MenuList& gs_items = gs_menu->items();
2613 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2615 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2616 gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2617 sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2623 RouteTimeAxisView::set_underlay_state()
2625 if (!underlay_xml_node) {
2629 XMLNodeList nlist = underlay_xml_node->children();
2630 XMLNodeConstIterator niter;
2631 XMLNode *child_node;
2633 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2634 child_node = *niter;
2636 if (child_node->name() != "Underlay") {
2640 XMLProperty* prop = child_node->property ("id");
2642 PBD::ID id (prop->value());
2644 RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2647 add_underlay(v->view(), false);
2656 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2662 RouteTimeAxisView& other = v->trackview();
2664 if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2665 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2666 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2667 abort(); /*NOTREACHED*/
2670 _underlay_streams.push_back(v);
2671 other._underlay_mirrors.push_back(this);
2673 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2675 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2677 if (!underlay_xml_node) {
2678 underlay_xml_node = xml_node->add_child("Underlays");
2681 XMLNode* node = underlay_xml_node->add_child("Underlay");
2682 XMLProperty* prop = node->add_property("id");
2683 prop->set_value(v->trackview().route()->id().to_s());
2690 RouteTimeAxisView::remove_underlay (StreamView* v)
2696 UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2697 RouteTimeAxisView& other = v->trackview();
2699 if (it != _underlay_streams.end()) {
2700 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2702 if (gm == other._underlay_mirrors.end()) {
2703 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2704 abort(); /*NOTREACHED*/
2707 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2709 _underlay_streams.erase(it);
2710 other._underlay_mirrors.erase(gm);
2712 if (underlay_xml_node) {
2713 underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2719 RouteTimeAxisView::set_button_names ()
2721 if (_route && _route->solo_safe()) {
2722 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2724 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2726 if (Config->get_solo_control_is_listen_control()) {
2727 switch (Config->get_listen_position()) {
2728 case AfterFaderListen:
2729 solo_button->set_text (S_("AfterFader|A"));
2730 set_tooltip (*solo_button, _("After-fade listen (AFL)"));
2732 case PreFaderListen:
2733 solo_button->set_text (S_("PreFader|P"));
2734 set_tooltip (*solo_button, _("Pre-fade listen (PFL)"));
2738 solo_button->set_text (S_("Solo|S"));
2739 set_tooltip (*solo_button, _("Solo"));
2741 mute_button->set_text (S_("Mute|M"));
2745 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2747 ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
2748 if (i != _main_automation_menu_map.end()) {
2752 i = _subplugin_menu_map.find (param);
2753 if (i != _subplugin_menu_map.end()) {
2761 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2763 boost::shared_ptr<AutomationControl> c = _route->gain_control();
2765 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2769 gain_track.reset (new AutomationTimeAxisView (_session,
2770 _route, _route->amp(), c, param,
2775 _route->amp()->describe_parameter(param)));
2778 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2781 add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2785 RouteTimeAxisView::create_trim_automation_child (const Evoral::Parameter& param, bool show)
2787 boost::shared_ptr<AutomationControl> c = _route->trim()->gain_control();
2788 if (!c || ! _route->trim()->active()) {
2792 trim_track.reset (new AutomationTimeAxisView (_session,
2793 _route, _route->trim(), c, param,
2798 _route->trim()->describe_parameter(param)));
2801 _view->foreach_regionview (sigc::mem_fun (*trim_track.get(), &TimeAxisView::add_ghost));
2804 add_automation_child (Evoral::Parameter(TrimAutomation), trim_track, show);
2808 RouteTimeAxisView::create_mute_automation_child (const Evoral::Parameter& param, bool show)
2810 boost::shared_ptr<AutomationControl> c = _route->mute_control();
2812 error << "Route has no mute automation, unable to add automation track view." << endmsg;
2816 mute_track.reset (new AutomationTimeAxisView (_session,
2817 _route, _route, c, param,
2822 _route->describe_parameter(param)));
2825 _view->foreach_regionview (sigc::mem_fun (*mute_track.get(), &TimeAxisView::add_ghost));
2828 add_automation_child (Evoral::Parameter(MuteAutomation), mute_track, show);
2832 void add_region_to_list (RegionView* rv, RegionList* l)
2834 l->push_back (rv->region());
2838 RouteTimeAxisView::combine_regions ()
2840 /* as of may 2011, we do not offer uncombine for MIDI tracks
2843 if (!is_audio_track()) {
2851 RegionList selected_regions;
2852 boost::shared_ptr<Playlist> playlist = track()->playlist();
2854 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2856 if (selected_regions.size() < 2) {
2860 playlist->clear_changes ();
2861 boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2863 _session->add_command (new StatefulDiffCommand (playlist));
2864 /* make the new region be selected */
2866 return _view->find_view (compound_region);
2870 RouteTimeAxisView::uncombine_regions ()
2872 /* as of may 2011, we do not offer uncombine for MIDI tracks
2874 if (!is_audio_track()) {
2882 RegionList selected_regions;
2883 boost::shared_ptr<Playlist> playlist = track()->playlist();
2885 /* have to grab selected regions first because the uncombine is going
2886 * to change that in the middle of the list traverse
2889 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2891 playlist->clear_changes ();
2893 for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2894 playlist->uncombine (*i);
2897 _session->add_command (new StatefulDiffCommand (playlist));
2901 RouteTimeAxisView::state_id() const
2903 return string_compose ("rtav %1", _route->id().to_s());
2908 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2910 TimeAxisView::remove_child (c);
2912 boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2914 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2915 if (i->second == a) {
2916 _automation_tracks.erase (i);