X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Froute_time_axis.cc;h=0669c0471c53d6a7dc6803b94d3d472b7666d010;hb=5fef65538040fbac1b9edd1847a269aa925a49c9;hp=90cb341c6967b3b494a7957f8114af92d93eba32;hpb=c4212fb10b419023ad8c1176793fa3de15d47b35;p=ardour.git diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 90cb341c69..0669c0471c 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -45,6 +45,8 @@ #include "ardour/amp.h" #include "ardour/meter.h" #include "ardour/event_type_map.h" +#include "ardour/pannable.h" +#include "ardour/panner.h" #include "ardour/processor.h" #include "ardour/profile.h" #include "ardour/route_group.h" @@ -63,7 +65,9 @@ #include "automation_time_axis.h" #include "enums.h" #include "gui_thread.h" +#include "item_counts.h" #include "keyboard.h" +#include "paste_context.h" #include "playlist_selector.h" #include "point_selection.h" #include "prompter.h" @@ -107,8 +111,11 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, ArdourCan , color_mode_menu (0) , gm (sess, true, 75, 14) , _ignore_set_layer_display (false) + , gain_automation_item(NULL) + , mute_automation_item(NULL) + , pan_automation_item(NULL) { - number_label.set_name("route button"); + number_label.set_name("tracknumber label"); number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive)); number_label.set_alignment(.5, .5); number_label.set_fallthrough_to_parent (true); @@ -172,7 +179,6 @@ RouteTimeAxisView::set_route (boost::shared_ptr rt) } else { controls_table.attach (*rec_enable_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0); } - controls_button_size_group->add_widget(*rec_enable_button); if (is_midi_track()) { ARDOUR_UI::instance()->set_tip(*rec_enable_button, _("Record (Right-click for Step Edit)")); @@ -200,7 +206,7 @@ RouteTimeAxisView::set_route (boost::shared_ptr rt) blank->show(); } - top_hbox.pack_end(gm.get_level_meter(), false, false, 4); + top_hbox.pack_end(gm.get_level_meter(), false, false, 2); if (!ARDOUR::Profile->get_mixbus()) { controls_meters_size_group->add_widget (gm.get_level_meter()); @@ -216,6 +222,8 @@ RouteTimeAxisView::set_route (boost::shared_ptr rt) } else { controls_table.attach (*mute_button, 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0); } + // mute button is always present, it is used to + // force the 'blank' placeholders to the proper size controls_button_size_group->add_widget(*mute_button); if (!_route->is_master()) { @@ -224,7 +232,6 @@ RouteTimeAxisView::set_route (boost::shared_ptr rt) } else { controls_table.attach (*solo_button, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0); } - controls_button_size_group->add_widget(*solo_button); } else { Gtk::Fixed *blank = manage(new Gtk::Fixed()); controls_button_size_group->add_widget(*blank); @@ -237,12 +244,10 @@ RouteTimeAxisView::set_route (boost::shared_ptr rt) } if (ARDOUR::Profile->get_mixbus()) { - controls_button_size_group->add_widget(route_group_button); controls_table.attach (route_group_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0); controls_table.attach (gm.get_gain_slider(), 3, 5, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0); } else if (!ARDOUR::Profile->get_trx()) { - controls_button_size_group->add_widget(route_group_button); controls_table.attach (route_group_button, 4, 5, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0); controls_table.attach (gm.get_gain_slider(), 0, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0); } @@ -251,6 +256,13 @@ RouteTimeAxisView::set_route (boost::shared_ptr rt) ARDOUR_UI::instance()->set_tip(*mute_button,_("Mute")); ARDOUR_UI::instance()->set_tip(route_group_button, _("Route Group")); + mute_button->set_tweaks(ArdourButton::TrackHeader); + solo_button->set_tweaks(ArdourButton::TrackHeader); + rec_enable_button->set_tweaks(ArdourButton::TrackHeader); + playlist_button.set_tweaks(ArdourButton::TrackHeader); + automation_button.set_tweaks(ArdourButton::TrackHeader); + route_group_button.set_tweaks(ArdourButton::TrackHeader); + if (is_midi_track()) { ARDOUR_UI::instance()->set_tip(automation_button, _("MIDI Controllers and Automation")); } else { @@ -262,21 +274,17 @@ RouteTimeAxisView::set_route (boost::shared_ptr rt) if (ARDOUR::Profile->get_mixbus()) { controls_table.attach (automation_button, 1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK); - controls_button_size_group->add_widget(automation_button); } else if (!ARDOUR::Profile->get_trx()) { controls_table.attach (automation_button, 3, 4, 2, 3, Gtk::SHRINK, Gtk::SHRINK); - controls_button_size_group->add_widget(automation_button); } if (is_track() && track()->mode() == ARDOUR::Normal) { if (ARDOUR::Profile->get_mixbus()) { controls_table.attach (playlist_button, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK); - controls_button_size_group->add_widget(playlist_button); } else if (!ARDOUR::Profile->get_trx()) { controls_table.attach (playlist_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK); - controls_button_size_group->add_widget(playlist_button); } } @@ -310,15 +318,11 @@ RouteTimeAxisView::set_route (boost::shared_ptr rt) route_group_menu = new RouteGroupMenu (_session, plist); - gm.get_gain_slider().signal_scroll_event().connect(sigc::mem_fun(*this, &RouteTimeAxisView::controls_ebox_scroll), false); - gm.get_level_meter().signal_scroll_event().connect (sigc::mem_fun (*this, &RouteTimeAxisView::controls_ebox_scroll), false); } RouteTimeAxisView::~RouteTimeAxisView () { - CatchDeletion (this); - for (list::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) { delete *i; } @@ -411,17 +415,21 @@ RouteTimeAxisView::update_track_number_visibility () } if (show_label) { if (ARDOUR::Profile->get_mixbus()) { - controls_table.attach (number_label, 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 1, 0); + controls_table.attach (number_label, 3, 4, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0); } else { - controls_table.attach (number_label, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 1, 0); + controls_table.attach (number_label, 0, 1, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0); } - const int tnw = 9 + std::max(2u, _session->track_number_decimals()) * number_label.char_pixel_width(); + // see ArdourButton::on_size_request(), we should probably use a global size-group here instead. + // except the width of the number label is subtracted from the name-hbox, so we + // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets. + int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width(); + if (tnw & 1) --tnw; number_label.set_size_request(tnw, -1); number_label.show (); - name_hbox.set_size_request(TimeAxisView::name_width_px - 2 - tnw, 0); // -2 = cellspacing + name_hbox.set_size_request(TimeAxisView::name_width_px - 2 - tnw, -1); // -2 = cellspacing } else { number_label.hide (); - name_hbox.set_size_request(TimeAxisView::name_width_px, 0); + name_hbox.set_size_request(TimeAxisView::name_width_px, -1); } } @@ -502,6 +510,38 @@ RouteTimeAxisView::build_automation_action_menu (bool for_selection) items.push_back (MenuElem (_("Processor automation"), subplugin_menu)); items.back().set_sensitive (!for_selection || _editor.get_selection().tracks.size() == 1);; } + + /* Add any route automation */ + + if (gain_track) { + items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &RouteTimeAxisView::update_gain_track_visibility))); + gain_automation_item = dynamic_cast (&items.back ()); + gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) && + (gain_track && string_is_affirmative (gain_track->gui_property ("visible")))); + + _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item; + } + + if (mute_track) { + items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &RouteTimeAxisView::update_mute_track_visibility))); + mute_automation_item = dynamic_cast (&items.back ()); + mute_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) && + (mute_track && string_is_affirmative (mute_track->gui_property ("visible")))); + + _main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item; + } + + if (!pan_tracks.empty()) { + items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &RouteTimeAxisView::update_pan_track_visibility))); + pan_automation_item = dynamic_cast (&items.back ()); + pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) && + (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible")))); + + set const & params = _route->pannable()->what_can_be_automated (); + for (set::const_iterator p = params.begin(); p != params.end(); ++p) { + _main_automation_menu_map[*p] = pan_automation_item; + } + } } void @@ -875,8 +915,8 @@ RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layer if (timestretch_rect == 0) { timestretch_rect = new ArdourCanvas::Rectangle (canvas_display ()); - timestretch_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TimeStretchFill()); - timestretch_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TimeStretchOutline()); + timestretch_rect->set_fill_color (ARDOUR_UI::config()->color ("time stretch fill")); + timestretch_rect->set_outline_color (ARDOUR_UI::config()->color ("time stretch outline")); } timestretch_rect->show (); @@ -1531,20 +1571,20 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) } bool -RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth) +RouteTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx) { if (!is_track()) { return false; } - boost::shared_ptr pl = playlist (); - PlaylistSelection::iterator p; - - for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth) {} + boost::shared_ptr pl = playlist (); + const ARDOUR::DataType type = pl->data_type(); + PlaylistSelection::const_iterator p = selection.playlists.get_nth(type, ctx.counts.n_playlists(type)); if (p == selection.playlists.end()) { return false; } + ctx.counts.increase_n_playlists(type); DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos)); @@ -1553,13 +1593,18 @@ RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, siz DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos)); } + /* add multi-paste offset if applicable */ + std::pair extent = (*p)->get_extent(); + const framecnt_t duration = extent.second - extent.first; + pos += _editor.get_paste_offset(pos, ctx.count, duration); + pl->clear_changes (); if (Config->get_edit_mode() == Ripple) { std::pair extent = (*p)->get_extent_with_endspace(); framecnt_t amount = extent.second - extent.first; - pl->ripple(pos, amount * times, boost::shared_ptr()); + pl->ripple(pos, amount * ctx.times, boost::shared_ptr()); } - pl->paste (*p, pos, times); + pl->paste (*p, pos, ctx.times); vector cmds; pl->rdiff (cmds); @@ -1768,11 +1813,11 @@ RouteTimeAxisView::color_handler () { //case cTimeStretchOutline: if (timestretch_rect) { - timestretch_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TimeStretchOutline()); + timestretch_rect->set_outline_color (ARDOUR_UI::config()->color ("time stretch outline")); } //case cTimeStretchFill: if (timestretch_rect) { - timestretch_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TimeStretchFill()); + timestretch_rect->set_fill_color (ARDOUR_UI::config()->color ("time stretch fill")); } reset_meter(); @@ -1830,6 +1875,110 @@ RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param) } } +void +RouteTimeAxisView::update_gain_track_visibility () +{ + bool const showit = gain_automation_item->get_active(); + + if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) { + gain_track->set_marked_for_display (showit); + + /* now trigger a redisplay */ + + if (!no_redraw) { + _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */ + } + } +} + +void +RouteTimeAxisView::update_mute_track_visibility () +{ + bool const showit = mute_automation_item->get_active(); + + if (showit != string_is_affirmative (mute_track->gui_property ("visible"))) { + mute_track->set_marked_for_display (showit); + + /* now trigger a redisplay */ + + if (!no_redraw) { + _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */ + } + } +} + +void +RouteTimeAxisView::update_pan_track_visibility () +{ + bool const showit = pan_automation_item->get_active(); + bool changed = false; + + for (list >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) { + if ((*i)->set_marked_for_display (showit)) { + changed = true; + } + } + + if (changed) { + _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */ + } +} + +void +RouteTimeAxisView::ensure_pan_views (bool show) +{ + bool changed = false; + for (list >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) { + changed = true; + (*i)->set_marked_for_display (false); + } + if (changed) { + _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */ + } + pan_tracks.clear(); + + if (!_route->panner()) { + return; + } + + set params = _route->panner()->what_can_be_automated(); + set::iterator p; + + for (p = params.begin(); p != params.end(); ++p) { + boost::shared_ptr pan_control = _route->pannable()->automation_control(*p); + + if (pan_control->parameter().type() == NullAutomation) { + error << "Pan control has NULL automation type!" << endmsg; + continue; + } + + if (automation_child (pan_control->parameter ()).get () == 0) { + + /* we don't already have an AutomationTimeAxisView for this parameter */ + + std::string const name = _route->panner()->describe_parameter (pan_control->parameter ()); + + boost::shared_ptr t ( + new AutomationTimeAxisView (_session, + _route, + _route->pannable(), + pan_control, + pan_control->parameter (), + _editor, + *this, + false, + parent_canvas, + name) + ); + + pan_tracks.push_back (t); + add_automation_child (*p, t, show); + } else { + pan_tracks.push_back (automation_child (pan_control->parameter ())); + } + } +} + void RouteTimeAxisView::show_all_automation (bool apply_to_selection) @@ -2012,7 +2161,7 @@ RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"), processor->name(), what.type(), (int) what.channel(), what.id() ) << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ return; } @@ -2100,7 +2249,7 @@ RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ request_redraw (); } - if (!EventTypeMap::instance().is_midi_parameter(param)) { + if (!ARDOUR::parameter_is_midi((AutomationType)param.type())) { /* MIDI-related parameters are always in the menu, there's no reason to rebuild the menu just because we added a automation lane for one of them. But if we add a non-MIDI automation @@ -2478,7 +2627,7 @@ RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/) if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) { if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) { fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ } _underlay_streams.push_back(v); @@ -2515,7 +2664,7 @@ RouteTimeAxisView::remove_underlay (StreamView* v) if (gm == other._underlay_mirrors.end()) { fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ } v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));