From 106024330230fca331e2f611fec42ec1f4f43e5a Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sat, 11 Jun 2011 15:35:34 +0000 Subject: [PATCH] major, substantive reworking of how we store GUI information (visibility, height) for automation data. old design stored (insufficient) identifying information plus actual data in a GUI-only XML node; new scheme adds GUI data via extra_xml node to each AutomationControl object. reworked public/private methods for showing/hiding TimeAxisView objects; changed labelling of automation tracks to just show the name of the controlled parameter - more info can be viewed in the tooltip for the track headers. NOTE: Session file format ALTERED. No data loss but track visibility may be different than previous ardour3 versions git-svn-id: svn://localhost/ardour2/branches/3.0@9703 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/audio_time_axis.cc | 64 +++++------ gtk2_ardour/audio_time_axis.h | 5 +- gtk2_ardour/automation_time_axis.cc | 160 +++++++++++---------------- gtk2_ardour/automation_time_axis.h | 7 +- gtk2_ardour/editor_routes.cc | 3 +- gtk2_ardour/midi_time_axis.cc | 68 ++++++++---- gtk2_ardour/midi_time_axis.h | 2 +- gtk2_ardour/route_time_axis.cc | 133 ++++++---------------- gtk2_ardour/route_time_axis.h | 4 - gtk2_ardour/route_ui.cc | 44 +------- gtk2_ardour/route_ui.h | 2 - gtk2_ardour/time_axis_view.cc | 10 +- gtk2_ardour/time_axis_view.h | 10 +- gtk2_ardour/ui_config.cc | 6 +- libs/ardour/ardour/automatable.h | 7 +- libs/ardour/automatable.cc | 52 +-------- libs/ardour/event_type_map.cc | 2 +- libs/ardour/pannable.cc | 73 +++--------- libs/ardour/processor.cc | 37 +------ libs/ardour/rc_configuration.cc | 4 +- libs/ardour/region.cc | 10 +- libs/ardour/route.cc | 12 +- libs/ardour/session_state.cc | 4 +- libs/evoral/evoral/Control.hpp | 2 - libs/evoral/src/ControlSet.cpp | 5 +- libs/gtkmm2ext/cairocell.cc | 9 +- libs/gtkmm2ext/gtkmm2ext/cairocell.h | 2 +- libs/pbd/controllable.cc | 6 + libs/pbd/pbd/stateful.h | 3 +- libs/pbd/stateful.cc | 37 +++++-- 30 files changed, 284 insertions(+), 499 deletions(-) diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index 763c9a5575..4cf127042d 100644 --- a/gtk2_ardour/audio_time_axis.cc +++ b/gtk2_ardour/audio_time_axis.cc @@ -190,6 +190,29 @@ AudioTimeAxisView::append_extra_display_menu_items () void AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show) { + if (param.type() == NullAutomation) { + cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl; + return; + } + + AutomationTracks::iterator existing = _automation_tracks.find (param); + + if (existing != _automation_tracks.end()) { + + /* automation track created because we had existing data for + * the processor, but visibility may need to be controlled + * since it will have been set visible by default. + */ + + existing->second->set_visibility (show); + + if (!no_redraw) { + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + } + + return; + } + if (param.type() == GainAutomation) { create_gain_automation_child (param, show); @@ -264,16 +287,7 @@ AudioTimeAxisView::update_gain_track_visibility () bool const showit = gain_automation_item->get_active(); if (showit != gain_track->marked_for_display()) { - if (showit) { - gain_track->set_marked_for_display (true); - gain_track->canvas_display()->show(); - gain_track->canvas_background()->show(); - gain_track->get_state_node()->add_property ("shown", X_("yes")); - } else { - gain_track->set_marked_for_display (false); - gain_track->hide (); - gain_track->get_state_node()->add_property ("shown", X_("no")); - } + gain_track->set_visibility (showit); /* now trigger a redisplay */ @@ -291,17 +305,7 @@ AudioTimeAxisView::update_pan_track_visibility () for (list >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) { if (showit != (*i)->marked_for_display()) { - if (showit) { - (*i)->set_marked_for_display (true); - (*i)->canvas_display()->show(); - (*i)->canvas_background()->show(); - (*i)->get_state_node()->add_property ("shown", X_("yes")); - } else { - (*i)->set_marked_for_display (false); - (*i)->hide (); - (*i)->get_state_node()->add_property ("shown", X_("no")); - } - + (*i)->set_visibility (showit); /* now trigger a redisplay */ if (!no_redraw) { _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */ @@ -472,24 +476,6 @@ AudioTimeAxisView::build_automation_action_menu (bool for_selection) } } -void -AudioTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr wp) -{ - /* we use this override to veto the Amp processor from the plugin menu, - as its automation lane can be accessed using the special "Fader" menu - option - */ - - boost::shared_ptr p = wp.lock (); - if (!p) { - return; - } - - if (boost::dynamic_pointer_cast (p) == 0) { - RouteTimeAxisView::add_processor_to_subplugin_menu (wp); - } -} - void AudioTimeAxisView::enter_internal_edit_mode () { diff --git a/gtk2_ardour/audio_time_axis.h b/gtk2_ardour/audio_time_axis.h index a13ac32f2a..8f9bf92a70 100644 --- a/gtk2_ardour/audio_time_axis.h +++ b/gtk2_ardour/audio_time_axis.h @@ -78,7 +78,6 @@ class AudioTimeAxisView : public RouteTimeAxisView /* Overridden from parent to store display state */ guint32 show_at (double y, int& nth, Gtk::VBox *parent); - void hide (); void enter_internal_edit_mode (); void leave_internal_edit_mode (); @@ -101,6 +100,8 @@ class AudioTimeAxisView : public RouteTimeAxisView void show_existing_automation (bool apply_to_selection = false); void hide_all_automation (bool apply_to_selection = false); + void hide (); + void gain_hidden (); void pan_hidden (); @@ -110,8 +111,6 @@ class AudioTimeAxisView : public RouteTimeAxisView void update_gain_track_visibility (); void update_pan_track_visibility (); - void add_processor_to_subplugin_menu (boost::weak_ptr); - Gtk::CheckMenuItem* gain_automation_item; std::list > pan_tracks; Gtk::CheckMenuItem* pan_automation_item; diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index bd882719be..d12dfa97bd 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -19,7 +19,10 @@ #include #include + #include "pbd/memento_command.h" +#include "pbd/stacktrace.h" + #include "ardour/automation_control.h" #include "ardour/event_type_map.h" #include "ardour/route.h" @@ -147,51 +150,22 @@ AutomationTimeAxisView::AutomationTimeAxisView ( hide_name_entry(); - /* move the name label over a bit */ + /* keep the parameter name short */ string shortpname = _name; - bool shortened = false; - int ignore_width; shortpname = fit_to_pixels (_name, 60, name_font, ignore_width, true); - if (shortpname != _name ){ - shortened = true; - } - name_label.set_text (shortpname); name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); name_label.set_name (X_("TrackParameterName")); - if (nomparent.length()) { - - /* limit the plug name string */ - - string pname = fit_to_pixels (nomparent, 60, name_font, ignore_width, true); - if (pname != nomparent) { - shortened = true; - } - - plugname = new Label (pname); - plugname->set_name (X_("TrackPlugName")); - plugname->show(); - controls_table.remove (name_hbox); - controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - plugname_packed = true; - controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } else { - plugname = 0; - plugname_packed = false; - } - - if (shortened) { - string tipname = nomparent; - if (!tipname.empty()) { - tipname += ": "; - } - tipname += _name; - ARDOUR_UI::instance()->set_tip(controls_ebox, tipname); + string tipname = nomparent; + if (!tipname.empty()) { + tipname += ": "; } + tipname += _name; + ARDOUR_UI::instance()->set_tip(controls_ebox, tipname); /* add the buttons */ controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); @@ -212,7 +186,7 @@ AutomationTimeAxisView::AutomationTimeAxisView ( controls_base_unselected_name = X_("AutomationTrackControlsBase"); controls_ebox.set_name (controls_base_unselected_name); - XMLNode* xml_node = get_parent_with_state()->get_automation_child_xml_node (_parameter); + XMLNode* xml_node = get_state_node (); if (xml_node) { set_state (*xml_node, Stateful::loading_state_version); @@ -435,7 +409,7 @@ AutomationTimeAxisView::set_height (uint32_t h) TimeAxisView* state_parent = get_parent_with_state (); assert(state_parent); - XMLNode* xml_node = state_parent->get_automation_child_xml_node (_parameter); + XMLNode* xml_node = _control->extra_xml ("GUI"); TimeAxisView::set_height (h); _base_rect->property_y2() = h; @@ -460,19 +434,6 @@ AutomationTimeAxisView::set_height (uint32_t h) first_call_to_set_height = false; if (h >= preset_height (HeightNormal)) { - controls_table.remove (name_hbox); - - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - plugname_packed = true; - controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } else { - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } hide_name_entry (); show_name_label (); name_hbox.show_all (); @@ -481,14 +442,6 @@ AutomationTimeAxisView::set_height (uint32_t h) hide_button.show_all(); } else if (h >= preset_height (HeightSmall)) { - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - } - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); controls_table.hide_all (); hide_name_entry (); show_name_label (); @@ -989,24 +942,18 @@ AutomationTimeAxisView::set_state (const XMLNode& node, int version) return set_state_2X (node, version); } - XMLProperty const * type = node.property ("automation-id"); - if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_parameter)) { - XMLProperty const * shown = node.property ("shown"); - if (shown && shown->value () == "yes") { - set_marked_for_display (true); - _canvas_display->show (); /* FIXME: necessary? show_at? */ - } - } + XMLProperty const * prop = node.property ("shown"); - if (!_marked_for_display) { - hide(); + if (prop) { + set_visibility (string_is_affirmative (prop->value())); + } else { + set_visibility (false); } return 0; } int - AutomationTimeAxisView::set_state_2X (const XMLNode& node, int /*version*/) { if (node.name() == X_("gain") && _parameter == Evoral::Parameter (GainAutomation)) { @@ -1027,50 +974,77 @@ AutomationTimeAxisView::set_state_2X (const XMLNode& node, int /*version*/) XMLNode* AutomationTimeAxisView::get_state_node () { - TimeAxisView* state_parent = get_parent_with_state (); + return _control->extra_xml ("GUI", true); +} - if (state_parent) { - return state_parent->get_automation_child_xml_node (_parameter); - } else { - return 0; +void +AutomationTimeAxisView::update_extra_xml_shown (bool shown) +{ + XMLNode* xml_node = get_state_node(); + if (xml_node) { + xml_node->add_property ("shown", shown ? "yes" : "no"); } } void -AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown) +AutomationTimeAxisView::what_has_visible_automation (const boost::shared_ptr& automatable, set& visible) { - XMLNode* xml_node = get_state_node(); - if (xml_node) { - xml_node->add_property ("shown", editor_shown ? "yes" : "no"); + /* this keeps "knowledge" of how we store visibility information + in XML private to this class. + */ + + assert (automatable); + + Automatable::Controls& controls (automatable->controls()); + + for (Automatable::Controls::iterator i = controls.begin(); i != controls.end(); ++i) { + + boost::shared_ptr ac = boost::dynamic_pointer_cast (i->second); + + if (ac) { + + const XMLNode* gui_node = ac->extra_xml ("GUI"); + + if (gui_node) { + const XMLProperty* prop = gui_node->property ("shown"); + if (prop) { + if (string_is_affirmative (prop->value())) { + visible.insert (i->first); + } + } + } + } } } guint32 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent) { - update_extra_xml_shown (true); + if (!canvas_item_visible (_canvas_display)) { + update_extra_xml_shown (true); + } return TimeAxisView::show_at (y, nth, parent); } void -AutomationTimeAxisView::hide () +AutomationTimeAxisView::show () { - update_extra_xml_shown (false); - - TimeAxisView::hide (); -} - -bool -AutomationTimeAxisView::set_visibility (bool yn) -{ - bool changed = TimeAxisView::set_visibility (yn); - - if (changed) { - get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no")); + if (!canvas_item_visible (_canvas_display)) { + update_extra_xml_shown (true); } - return changed; + return TimeAxisView::show (); +} + +void +AutomationTimeAxisView::hide () +{ + if (canvas_item_visible (_canvas_display)) { + update_extra_xml_shown (false); + } + + TimeAxisView::hide (); } /** @return true if this view has any automation data to display */ diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h index 47d1d70d73..3e3fbde35c 100644 --- a/gtk2_ardour/automation_time_axis.h +++ b/gtk2_ardour/automation_time_axis.h @@ -70,7 +70,6 @@ class AutomationTimeAxisView : public TimeAxisView { virtual void set_height (uint32_t); void set_samples_per_unit (double); - bool set_visibility (bool yn); std::string name() const { return _name; } void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, framepos_t, double); @@ -99,7 +98,6 @@ class AutomationTimeAxisView : public TimeAxisView { int set_state (const XMLNode&, int version); guint32 show_at (double y, int& nth, Gtk::VBox *parent); - void hide (); static const std::string state_node_name; XMLNode* get_state_node(); @@ -120,6 +118,8 @@ class AutomationTimeAxisView : public TimeAxisView { return _route; } + static void what_has_visible_automation (const boost::shared_ptr& automatable, std::set& visible); + protected: /** parent route */ boost::shared_ptr _route; @@ -156,6 +156,9 @@ class AutomationTimeAxisView : public TimeAxisView { Gtk::CheckMenuItem* mode_discrete_item; Gtk::CheckMenuItem* mode_line_item; + void hide (); + void show (); + void add_line (boost::shared_ptr); void clear_clicked (); diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc index 0aae18d793..9e27c7725e 100644 --- a/gtk2_ardour/editor_routes.cc +++ b/gtk2_ardour/editor_routes.cc @@ -439,8 +439,7 @@ EditorRoutes::redisplay () position += tv->show_at (position, n, &_editor->edit_controls_vbox); tv->clip_to_viewport (); } else { - tv->set_marked_for_display (false); - tv->hide (); + tv->set_visibility (false); } n++; diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index 9cda418557..9fbddfd241 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -846,41 +846,71 @@ MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool } AutomationTracks::iterator existing = _automation_tracks.find (param); + if (existing != _automation_tracks.end()) { + + /* automation track created because we had existing data for + * the processor, but visibility may need to be controlled + * since it will have been set visible by default. + */ + + existing->second->set_visibility (show); + + if (!no_redraw) { + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + } + return; } - if (param.type() == GainAutomation) { + boost::shared_ptr track; + + switch (param.type()) { + + case GainAutomation: create_gain_automation_child (param, show); - } else { + break; - /* These controllers are region "automation", so we do not create - * an AutomationList/Line for the track */ + case PluginAutomation: + /* handled elsewhere */ + break; - boost::shared_ptr track ( - new AutomationTimeAxisView ( - _session, - _route, - boost::shared_ptr (), - boost::shared_ptr (), - param, - _editor, - *this, - true, - parent_canvas, - _route->describe_parameter(param) - ) - ); + case MidiCCAutomation: + case MidiPgmChangeAutomation: + case MidiPitchBenderAutomation: + case MidiChannelPressureAutomation: + case MidiSystemExclusiveAutomation: + /* These controllers are region "automation" - they are owned + * by regions (and their MidiModels), not by the track. As a + * result we do not create an AutomationList/Line for the track + * ... except here we are doing something!! XXX + */ + + track.reset (new AutomationTimeAxisView ( + _session, + _route, + boost::shared_ptr (), + boost::shared_ptr (), + param, + _editor, + *this, + true, + parent_canvas, + _route->describe_parameter(param) + )); if (_view) { _view->foreach_regionview (sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost)); } add_automation_child (param, track, show); + break; + + default: + error << "MidiTimeAxisView: unknown automation child " << EventTypeMap::instance().to_symbol(param) << endmsg; } } - void MidiTimeAxisView::route_active_changed () { diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h index 485425e966..6a557af568 100644 --- a/gtk2_ardour/midi_time_axis.h +++ b/gtk2_ardour/midi_time_axis.h @@ -67,7 +67,6 @@ class MidiTimeAxisView : public RouteTimeAxisView /* overridden from parent to store display state */ guint32 show_at (double y, int& nth, Gtk::VBox *parent); void set_height (uint32_t); - void hide (); void enter_internal_edit_mode (); void leave_internal_edit_mode (); @@ -110,6 +109,7 @@ class MidiTimeAxisView : public RouteTimeAxisView private: sigc::signal _midi_patch_settings_changed; + void hide (); void model_changed(); void custom_device_mode_changed(); diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 456c60d17b..b4ad4da1f4 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -359,19 +359,6 @@ RouteTimeAxisView::set_state (const XMLNode& node, int version) set_layer_display (LayerDisplay (string_2_enum (prop->value(), _view->layer_display ()))); } - for (iter = kids.begin(); iter != kids.end(); ++iter) { - if ((*iter)->name() == AutomationTimeAxisView::state_node_name) { - if ((prop = (*iter)->property ("automation-id")) != 0) { - - Evoral::Parameter param = ARDOUR::EventTypeMap::instance().new_parameter(prop->value()); - bool show = ((prop = (*iter)->property ("shown")) != 0) && string_is_affirmative (prop->value()); - create_automation_child(param, show); - } else { - warning << "Automation child has no ID" << endmsg; - } - } - } - return 0; } @@ -1664,9 +1651,6 @@ RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param) Gtk::CheckMenuItem* menu = automation_child_menu_item (param); - // if Evoral::Parameter::operator< doesn't obey strict weak ordering, we may crash here.... - track->get_state_node()->add_property (X_("shown"), X_("no")); - if (menu && !_hidden) { ignore_toggle = true; menu->set_active (false); @@ -1690,9 +1674,7 @@ RouteTimeAxisView::show_all_automation (bool apply_to_selection) /* Show our automation */ for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) { - i->second->set_marked_for_display (true); - i->second->canvas_display()->show(); - i->second->get_state_node()->add_property ("shown", X_("yes")); + i->second->set_visibility (true); Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first); @@ -1734,9 +1716,7 @@ RouteTimeAxisView::show_existing_automation (bool apply_to_selection) for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) { if (i->second->has_automation()) { - i->second->set_marked_for_display (true); - i->second->canvas_display()->show(); - i->second->get_state_node()->add_property ("shown", X_("yes")); + i->second->set_visibility (true); Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first); if (menu) { @@ -1745,7 +1725,6 @@ RouteTimeAxisView::show_existing_automation (bool apply_to_selection) } } - /* Show processor automation */ for (list::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) { @@ -1773,9 +1752,7 @@ RouteTimeAxisView::hide_all_automation (bool apply_to_selection) /* Hide our automation */ for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) { - i->second->set_marked_for_display (false); - i->second->hide (); - i->second->get_state_node()->add_property ("shown", X_("no")); + i->second->set_visibility (false); Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first); @@ -1854,25 +1831,6 @@ RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr return 0; } -static string -legalize_for_xml_node (string str) -{ - string::size_type pos; - string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_=:"; - string legal; - - legal = str; - pos = 0; - - while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) { - legal.replace (pos, 1, "_"); - pos += 1; - } - - return legal; -} - - void RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr processor, Evoral::Parameter what) { @@ -1893,37 +1851,21 @@ RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr return; } - name = processor->describe_parameter (what); - - /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */ - - /* FIXME: ew */ - - char state_name[256]; - snprintf (state_name, sizeof (state_name), "%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id()); - boost::shared_ptr control - = boost::dynamic_pointer_cast(processor->control(what, true)); - + = boost::dynamic_pointer_cast(processor->control(what, true)); + pan->view = boost::shared_ptr( new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (), - _editor, *this, false, parent_canvas, name, state_name)); + _editor, *this, false, parent_canvas, + processor->describe_parameter (what), processor->name())); pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor)); - if (!pan->view->marked_for_display()) { - pan->view->hide (); - } else { - pan->menu_item->set_active (true); - } - - add_automation_child (control->parameter(), pan->view, true); + add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ()); if (_view) { _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost)); } - - processor->mark_automation_visible (what, true); } void @@ -1933,8 +1875,6 @@ RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::Process pan->menu_item->set_active (false); } - i->mark_automation_visible (pan->what, false); - if (!no_redraw) { _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ } @@ -1944,21 +1884,24 @@ void RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr p) { boost::shared_ptr processor (p.lock ()); + if (!processor) { return; } - set s; - boost::shared_ptr al; + set existing; - processor->what_has_visible_data (s); + processor->what_has_data (existing); - for (set::iterator i = s.begin(); i != s.end(); ++i) { + for (set::iterator i = existing.begin(); i != existing.end(); ++i) { + + Evoral::Parameter param (*i); + boost::shared_ptr al; - if ((al = find_processor_automation_curve (processor, *i)) != 0) { + if ((al = find_processor_automation_curve (processor, param)) != 0) { al->queue_reset (); } else { - add_processor_automation_curve (processor, (*i)); + add_processor_automation_curve (processor, param); } } } @@ -1975,19 +1918,16 @@ RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param)); - bool hideit = (!show); + _automation_tracks[param] = track; if ((node = track->get_state_node()) != 0) { if ((prop = node->property ("shown")) != 0) { - if (string_is_affirmative (prop->value())) { - hideit = false; - } + /* existing state overrides "show" argument */ + show = string_is_affirmative (prop->value()); } } - _automation_tracks[param] = track; - - track->set_visibility (!hideit); + track->set_visibility (show); if (!no_redraw) { _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ @@ -2013,14 +1953,20 @@ RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr p return; } + /* we use this override to veto the Amp processor from the plugin menu, + as its automation lane can be accessed using the special "Fader" menu + option + */ + + if (boost::dynamic_pointer_cast (processor) != 0) { + return; + } + using namespace Menu_Helpers; ProcessorAutomationInfo *rai; list::iterator x; const std::set& automatable = processor->what_can_be_automated (); - std::set has_visible_automation; - - processor->what_has_visible_data(has_visible_automation); if (automatable.empty()) { return; @@ -2053,6 +1999,9 @@ RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr p items.clear (); + std::set has_visible_automation; + AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation); + for (std::set::const_iterator i = automatable.begin(); i != automatable.end(); ++i) { ProcessorAutomationNode* pan; @@ -2062,7 +2011,7 @@ RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr p items.push_back (CheckMenuElem (name)); mitem = dynamic_cast (&items.back()); - + _subplugin_menu_map[*i] = mitem; if (has_visible_automation.find((*i)) != has_visible_automation.end()) { @@ -2109,24 +2058,12 @@ RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAuto } if (pan->view && showit != pan->view->marked_for_display()) { - - if (showit) { - pan->view->set_marked_for_display (true); - pan->view->canvas_display()->show(); - pan->view->canvas_background()->show(); - } else { - rai->processor->mark_automation_visible (pan->what, true); - pan->view->set_marked_for_display (false); - pan->view->hide (); - } - + pan->view->set_visibility (showit); redraw = true; - } if (redraw && !no_redraw) { _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ - } } diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h index 9f7fbff54d..e087199c87 100644 --- a/gtk2_ardour/route_time_axis.h +++ b/gtk2_ardour/route_time_axis.h @@ -117,10 +117,6 @@ public: virtual void create_automation_child (const Evoral::Parameter& param, bool show) = 0; - /* make sure we get the right version of this */ - - XMLNode* get_automation_child_xml_node (Evoral::Parameter param) { return RouteUI::get_automation_child_xml_node (param); } - typedef std::map > AutomationTracks; AutomationTracks automation_tracks() { return _automation_tracks; } diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index 7750f6c399..525013ecaa 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -1306,18 +1306,10 @@ RouteUI::ensure_xml_node () new_xml_node->add_property ((*i)->name().c_str (), (*i)->value().c_str ()); } - XMLNodeList old_children = xml_node->children (); - for (XMLNodeConstIterator i = old_children.begin(); i != old_children.end(); ++i) { - XMLNode* new_child = new XMLNode (AutomationTimeAxisView::state_node_name); - new_child->add_property (X_("automation-id"), (*i)->name()); - - XMLPropertyList old_props = (*i)->properties (); - for (XMLPropertyIterator j = old_props.begin(); j != old_props.end(); ++j) { - new_child->add_property ((*j)->name().c_str (), (*j)->value().c_str ()); - } - - new_xml_node->add_child_nocopy (*new_child); - } + /* we can't fix up the automation track nodes, + * because the data is no longer stored + * per-route, but per Controllable. + */ _route->add_extra_xml (*new_xml_node); xml_node = new_xml_node; @@ -1326,34 +1318,6 @@ RouteUI::ensure_xml_node () } } -XMLNode* -RouteUI::get_automation_child_xml_node (Evoral::Parameter param) -{ - ensure_xml_node (); - - XMLNodeList kids = xml_node->children(); - XMLNodeConstIterator iter; - - const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param); - - for (iter = kids.begin(); iter != kids.end(); ++iter) { - - if ((*iter)->name() == AutomationTimeAxisView::state_node_name) { - XMLProperty* type = (*iter)->property("automation-id"); - if (type && type->value() == sym) { - return *iter; - } - } - } - - // Didn't find it, make a new one - XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name); - child->add_property("automation-id", sym); - xml_node->add_child_nocopy (*child); - - return child; -} - int RouteUI::set_color_from_route () { diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h index 9435b036e5..0a72ed9966 100644 --- a/gtk2_ardour/route_ui.h +++ b/gtk2_ardour/route_ui.h @@ -111,8 +111,6 @@ class RouteUI : public virtual AxisView XMLNode *xml_node; void ensure_xml_node (); - virtual XMLNode* get_automation_child_xml_node (Evoral::Parameter); - bool mute_press(GdkEventButton*); bool mute_release(GdkEventButton*); bool solo_press(GdkEventButton*); diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc index 925107d9e8..fa216818f4 100644 --- a/gtk2_ardour/time_axis_view.cc +++ b/gtk2_ardour/time_axis_view.cc @@ -349,6 +349,13 @@ TimeAxisView::selection_click (GdkEventButton* ev) _editor.set_selected_track (*this, op, false); } +void +TimeAxisView::show () +{ + canvas_display()->show(); + canvas_background()->show(); +} + void TimeAxisView::hide () { @@ -1287,7 +1294,7 @@ TimeAxisView::set_visibility (bool yn) if (yn != marked_for_display()) { if (yn) { set_marked_for_display (true); - canvas_display()->show(); + show (); } else { set_marked_for_display (false); hide (); @@ -1298,6 +1305,7 @@ TimeAxisView::set_visibility (bool yn) return false; } + uint32_t TimeAxisView::preset_height (Height h) { diff --git a/gtk2_ardour/time_axis_view.h b/gtk2_ardour/time_axis_view.h index fde5bf0b34..8e7d6f394a 100644 --- a/gtk2_ardour/time_axis_view.h +++ b/gtk2_ardour/time_axis_view.h @@ -136,9 +136,6 @@ class TimeAxisView : public virtual AxisView, public PBD::Stateful bool touched (double top, double bot); - /** Hide this TrackView */ - virtual void hide (); - /** @return true if hidden, otherwise false */ bool hidden () const { return _hidden; } @@ -201,10 +198,6 @@ class TimeAxisView : public virtual AxisView, public PBD::Stateful void set_parent (TimeAxisView& p); bool has_state () const; - /* call this on the parent */ - - virtual XMLNode* get_automation_child_xml_node (Evoral::Parameter) { return 0; } - virtual LayerDisplay layer_display () const { return Overlaid; } virtual StreamView* view () const { return 0; } @@ -286,6 +279,9 @@ class TimeAxisView : public virtual AxisView, public PBD::Stateful void remove_child (boost::shared_ptr); void add_child (boost::shared_ptr); + virtual void hide (); + virtual void show (); + /* selection display */ ArdourCanvas::Group *selection_group; diff --git a/gtk2_ardour/ui_config.cc b/gtk2_ardour/ui_config.cc index 8e89884b22..10628334fd 100644 --- a/gtk2_ardour/ui_config.cc +++ b/gtk2_ardour/ui_config.cc @@ -229,6 +229,8 @@ UIConfiguration::set_state (const XMLNode& root, int /*version*/) return -1; } + Stateful::save_extra_xml (root); + XMLNodeList nlist = root.children(); XMLNodeConstIterator niter; XMLNode *node; @@ -236,12 +238,10 @@ UIConfiguration::set_state (const XMLNode& root, int /*version*/) for (niter = nlist.begin(); niter != nlist.end(); ++niter) { node = *niter; + if (node->name() == "Canvas" || node->name() == "UI") { set_variables (*node); - } else if (node->name() == "Extra") { - _extra_xml = new XMLNode (*node); - } } return 0; diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h index 69ef7d3ecb..dc86c0cddd 100644 --- a/libs/ardour/ardour/automatable.h +++ b/libs/ardour/ardour/automatable.h @@ -73,10 +73,8 @@ public: void protect_automation (); - void what_has_visible_data(std::set&) const; const std::set& what_can_be_automated() const { return _can_automate_list; } - - void mark_automation_visible(Evoral::Parameter, bool); + void what_has_existing_automation (std::set&) const; inline bool should_snapshot (framepos_t now) { return (_last_automation_snapshot > now @@ -91,8 +89,6 @@ public: return _automation_interval; } - typedef Evoral::ControlSet::Controls Controls; - static const std::string xml_node_name; int set_automation_xml_state (const XMLNode&, Evoral::Parameter default_param); @@ -108,7 +104,6 @@ public: int load_automation (const std::string& path); int old_set_automation_state(const XMLNode&); - std::set _visible_controls; std::set _can_automate_list; framepos_t _last_automation_snapshot; diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc index 8c17a99bea..6d8114939d 100644 --- a/libs/ardour/automatable.cc +++ b/libs/ardour/automatable.cc @@ -79,22 +79,6 @@ Automatable::old_set_automation_state (const XMLNode& node) warning << _("Automation node has no path property") << endmsg; } - if ((prop = node.property ("visible")) != 0) { - uint32_t what; - stringstream sstr; - - _visible_controls.clear (); - - sstr << prop->value(); - while (1) { - sstr >> what; - if (sstr.fail()) { - break; - } - mark_automation_visible (Evoral::Parameter(PluginAutomation, 0, what), true); - } - } - _last_automation_snapshot = 0; return 0; @@ -167,17 +151,6 @@ Automatable::add_control(boost::shared_ptr ac) automation_list_automation_state_changed (param, al->automation_state ()); // sync everything up } -void -Automatable::what_has_visible_data(set& s) const -{ - Glib::Mutex::Lock lm (control_lock()); - set::const_iterator li; - - for (li = _visible_controls.begin(); li != _visible_controls.end(); ++li) { - s.insert (*li); - } -} - string Automatable::describe_parameter (Evoral::Parameter param) { @@ -205,20 +178,6 @@ Automatable::can_automate (Evoral::Parameter what) _can_automate_list.insert (what); } -void -Automatable::mark_automation_visible (Evoral::Parameter what, bool yn) -{ - if (yn) { - _visible_controls.insert (what); - } else { - set::iterator i; - - if ((i = _visible_controls.find (what)) != _visible_controls.end()) { - _visible_controls.erase (i); - } - } -} - /** \a legacy_param is used for loading legacy sessions where an object (IO, Panner) * had a single automation parameter, with it's type implicit. Derived objects should * pass that type and it will be used for the untyped AutomationList found. @@ -230,8 +189,6 @@ Automatable::set_automation_xml_state (const XMLNode& node, Evoral::Parameter le /* Don't clear controls, since some may be special derived Controllable classes */ - _visible_controls.clear (); - XMLNodeList nlist = node.children(); XMLNodeIterator niter; @@ -292,8 +249,7 @@ Automatable::get_automation_xml_state () } for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) { - boost::shared_ptr l - = boost::dynamic_pointer_cast(li->second->list()); + boost::shared_ptr l = boost::dynamic_pointer_cast(li->second->list()); if (!l->empty()) { node->add_child_nocopy (l->get_state ()); } @@ -364,11 +320,9 @@ void Automatable::protect_automation () { typedef set ParameterSet; - ParameterSet automated_params; + const ParameterSet& automated_params = what_can_be_automated (); - what_has_data(automated_params); - - for (ParameterSet::iterator i = automated_params.begin(); i != automated_params.end(); ++i) { + for (ParameterSet::const_iterator i = automated_params.begin(); i != automated_params.end(); ++i) { boost::shared_ptr c = control(*i); boost::shared_ptr l = boost::dynamic_pointer_cast(c->list()); diff --git a/libs/ardour/event_type_map.cc b/libs/ardour/event_type_map.cc index 2a45ba672c..4b21d32e58 100644 --- a/libs/ardour/event_type_map.cc +++ b/libs/ardour/event_type_map.cc @@ -244,7 +244,7 @@ EventTypeMap::new_parameter(const string& str) const } else { PBD::warning << "Unknown Parameter '" << str << "'" << endmsg; } - + return new_parameter(p_type, p_channel, p_id); } diff --git a/libs/ardour/pannable.cc b/libs/ardour/pannable.cc index 4de47fc62b..e020c19451 100644 --- a/libs/ardour/pannable.cc +++ b/libs/ardour/pannable.cc @@ -185,33 +185,12 @@ XMLNode& Pannable::state (bool full) { XMLNode* node = new XMLNode (X_("Pannable")); - XMLNode* control_node; - char buf[32]; - control_node = new XMLNode (X_("azimuth")); - snprintf (buf, sizeof(buf), "%.12g", pan_azimuth_control->get_value()); - control_node->add_property (X_("value"), buf); - node->add_child_nocopy (*control_node); - - control_node = new XMLNode (X_("width")); - snprintf (buf, sizeof(buf), "%.12g", pan_width_control->get_value()); - control_node->add_property (X_("value"), buf); - node->add_child_nocopy (*control_node); - - control_node = new XMLNode (X_("elevation")); - snprintf (buf, sizeof(buf), "%.12g", pan_elevation_control->get_value()); - control_node->add_property (X_("value"), buf); - node->add_child_nocopy (*control_node); - - control_node = new XMLNode (X_("frontback")); - snprintf (buf, sizeof(buf), "%.12g", pan_frontback_control->get_value()); - control_node->add_property (X_("value"), buf); - node->add_child_nocopy (*control_node); - - control_node = new XMLNode (X_("lfe")); - snprintf (buf, sizeof(buf), "%.12g", pan_lfe_control->get_value()); - control_node->add_property (X_("value"), buf); - node->add_child_nocopy (*control_node); + node->add_child_nocopy (pan_azimuth_control->get_state()); + node->add_child_nocopy (pan_width_control->get_state()); + node->add_child_nocopy (pan_elevation_control->get_state()); + node->add_child_nocopy (pan_frontback_control->get_state()); + node->add_child_nocopy (pan_lfe_control->get_state()); node->add_child_nocopy (get_automation_xml_state ()); @@ -219,45 +198,27 @@ Pannable::state (bool full) } int -Pannable::set_state (const XMLNode& root, int /*version - not used*/) +Pannable::set_state (const XMLNode& root, int version) { if (root.name() != X_("Pannable")) { warning << string_compose (_("Pannable given XML data for %1 - ignored"), root.name()) << endmsg; return -1; } - XMLNodeList nlist; + const XMLNodeList& nlist (root.children()); XMLNodeConstIterator niter; - const XMLProperty *prop; - - nlist = root.children(); for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - if ((*niter)->name() == X_("azimuth")) { - prop = (*niter)->property (X_("value")); - if (prop) { - pan_azimuth_control->set_value (atof (prop->value())); - } - } else if ((*niter)->name() == X_("width")) { - prop = (*niter)->property (X_("value")); - if (prop) { - pan_width_control->set_value (atof (prop->value())); - } - } else if ((*niter)->name() == X_("elevation")) { - prop = (*niter)->property (X_("value")); - if (prop) { - pan_elevation_control->set_value (atof (prop->value())); - } - } else if ((*niter)->name() == X_("azimuth")) { - prop = (*niter)->property (X_("value")); - if (prop) { - pan_frontback_control->set_value (atof (prop->value())); - } - } else if ((*niter)->name() == X_("lfe")) { - prop = (*niter)->property (X_("value")); - if (prop) { - pan_lfe_control->set_value (atof (prop->value())); - } + if ((*niter)->name() == pan_azimuth_control->name()) { + pan_azimuth_control->set_state (**niter, version); + } else if ((*niter)->name() == pan_width_control->name()) { + pan_width_control->set_state (**niter, version); + } else if ((*niter)->name() == pan_elevation_control->name()) { + pan_elevation_control->set_state (**niter, version); + } else if ((*niter)->name() == pan_frontback_control->name()) { + pan_frontback_control->set_state (**niter, version); + } else if ((*niter)->name() == pan_lfe_control->name()) { + pan_lfe_control->set_state (**niter, version); } else if ((*niter)->name() == Automatable::xml_node_name) { set_automation_xml_state (**niter, PanAzimuthAutomation); } diff --git a/libs/ardour/processor.cc b/libs/ardour/processor.cc index bb004c313d..bf4a8ea6cb 100644 --- a/libs/ardour/processor.cc +++ b/libs/ardour/processor.cc @@ -123,21 +123,7 @@ Processor::state (bool full_state) if (full_state) { XMLNode& automation = Automatable::get_automation_xml_state(); - if (!automation.children().empty() - || !automation.properties().empty() - || !_visible_controls.empty()) { - - stringstream sstr; - for (set::iterator x = _visible_controls.begin(); - x != _visible_controls.end(); ++x) { - - if (x != _visible_controls.begin()) { - sstr << ' '; - } - sstr << (*x).id(); - } - - automation.add_property ("visible", sstr.str()); + if (!automation.children().empty() || !automation.properties().empty()) { node->add_child_nocopy (automation); } } @@ -206,6 +192,8 @@ Processor::set_state (const XMLNode& node, int version) XMLNodeList nlist = node.children(); XMLNodeIterator niter; + Stateful::save_extra_xml (node); + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { if ((*niter)->name() == X_("Automation")) { @@ -218,25 +206,6 @@ Processor::set_state (const XMLNode& node, int version) set_automation_xml_state (*(*niter), Evoral::Parameter(PluginAutomation)); } - if ((prop = (*niter)->property ("visible")) != 0) { - uint32_t what; - stringstream sstr; - - _visible_controls.clear (); - - sstr << prop->value(); - while (1) { - sstr >> what; - if (sstr.fail()) { - break; - } - // FIXME: other automation types? - mark_automation_visible (Evoral::Parameter(PluginAutomation, 0, what), true); - } - } - - } else if ((*niter)->name() == "Extra") { - _extra_xml = new XMLNode (*(*niter)); } else if ((*niter)->name() == "Redirect") { if ( !(legacy_active = (*niter)->property("active"))) { error << string_compose(_("No %1 property flag in element %2"), "active", (*niter)->name()) << endl; diff --git a/libs/ardour/rc_configuration.cc b/libs/ardour/rc_configuration.cc index a17fd9f5a5..1dc1ea636b 100644 --- a/libs/ardour/rc_configuration.cc +++ b/libs/ardour/rc_configuration.cc @@ -268,14 +268,14 @@ RCConfiguration::set_state (const XMLNode& root, int /*version*/) _midi_port_states.clear (); + Stateful::save_extra_xml (root); + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { node = *niter; if (node->name() == "Config") { set_variables (*node); - } else if (node->name() == "Extra") { - _extra_xml = new XMLNode (*node); } else if (node->name() == ControlProtocolManager::state_node_name) { _control_protocol_state = new XMLNode (*node); } else if (node->name() == MIDI::Port::state_node_name) { diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 17698d88a7..30a0b6f24a 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -1251,15 +1251,7 @@ Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_c const XMLProperty* prop; const XMLNodeList& nlist = node.children(); - for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) { - - XMLNode *child = (*niter); - - if (child->name () == "Extra") { - delete _extra_xml; - _extra_xml = new XMLNode (*child); - } - } + Stateful::save_extra_xml (node); what_changed = set_values (node); diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 0e8c93d75e..459ea67480 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -1902,6 +1902,8 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) nlist = node.children(); XMLNode processor_state (X_("processor_state")); + Stateful::save_extra_xml (node); + for (niter = nlist.begin(); niter != nlist.end(); ++niter){ child = *niter; @@ -2015,10 +2017,6 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) XMLNode *cmt = *(child->children().begin()); _comment = cmt->content(); - } else if (child->name() == X_("Extra")) { - - _extra_xml = new XMLNode (*child); - } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) { if (prop->value() == "solo") { _solo_control->set_state (*child, version); @@ -2255,6 +2253,8 @@ Route::_set_state_2X (const XMLNode& node, int version) set_processor_state_2X (redirect_nodes, version); + Stateful::save_extra_xml (node); + for (niter = nlist.begin(); niter != nlist.end(); ++niter){ child = *niter; @@ -2265,10 +2265,6 @@ Route::_set_state_2X (const XMLNode& node, int version) XMLNode *cmt = *(child->children().begin()); _comment = cmt->content(); - } else if (child->name() == X_("extra")) { - - _extra_xml = new XMLNode (*child); - } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) { if (prop->value() == X_("solo")) { _solo_control->set_state (*child, version); diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 182b399877..5d9967cc98 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -1250,9 +1250,7 @@ Session::set_state (const XMLNode& node, int version) IO::disable_connecting (); - if ((child = find_named_node (node, "Extra")) != 0) { - _extra_xml = new XMLNode (*child); - } + Stateful::save_extra_xml (node); if (((child = find_named_node (node, "Options")) != 0)) { /* old style */ load_options (*child); diff --git a/libs/evoral/evoral/Control.hpp b/libs/evoral/evoral/Control.hpp index bc525a0e72..5c45823184 100644 --- a/libs/evoral/evoral/Control.hpp +++ b/libs/evoral/evoral/Control.hpp @@ -40,7 +40,6 @@ public: virtual void set_double(double val, bool to_list=false, double frame=0); virtual double get_double(bool from_list=false, double frame=0) const; - /** Get the latest user-set value * (which may not equal get_value() when automation is playing back). * @@ -51,7 +50,6 @@ public: void set_list(boost::shared_ptr); - boost::shared_ptr list() { return _list; } boost::shared_ptr list() const { return _list; } diff --git a/libs/evoral/src/ControlSet.cpp b/libs/evoral/src/ControlSet.cpp index 1dd73c0115..6b793a08ea 100644 --- a/libs/evoral/src/ControlSet.cpp +++ b/libs/evoral/src/ControlSet.cpp @@ -54,8 +54,11 @@ void ControlSet::what_has_data (set& s) const { Glib::Mutex::Lock lm (_control_lock); + for (Controls::const_iterator li = _controls.begin(); li != _controls.end(); ++li) { - s.insert(li->first); + if (li->second->list() && !li->second->list()->empty()) { + s.insert (li->first); + } } } diff --git a/libs/gtkmm2ext/cairocell.cc b/libs/gtkmm2ext/cairocell.cc index f3da7e8cb3..5a7f4309ed 100644 --- a/libs/gtkmm2ext/cairocell.cc +++ b/libs/gtkmm2ext/cairocell.cc @@ -287,7 +287,14 @@ CairoEditableText::set_text (CairoTextCell* cell, const string& text) bool CairoEditableText::on_expose_event (GdkEventExpose* ev) { - Cairo::RefPtr context = get_window()->create_cairo_context(); + Glib::RefPtr win = get_window (); + + if (!win) { + std::cerr << "CET: no window to draw on\n"; + return false; + } + + Cairo::RefPtr context = win->create_cairo_context(); if (cells.empty()) { return true; diff --git a/libs/gtkmm2ext/gtkmm2ext/cairocell.h b/libs/gtkmm2ext/gtkmm2ext/cairocell.h index 8dd6cd8a16..2839d4266b 100644 --- a/libs/gtkmm2ext/gtkmm2ext/cairocell.h +++ b/libs/gtkmm2ext/gtkmm2ext/cairocell.h @@ -27,7 +27,7 @@ #include #include -#include +#include class CairoCell { diff --git a/libs/pbd/controllable.cc b/libs/pbd/controllable.cc index 0112ff2b1c..959abe443d 100644 --- a/libs/pbd/controllable.cc +++ b/libs/pbd/controllable.cc @@ -113,6 +113,10 @@ Controllable::get_state () snprintf (buf, sizeof (buf), "%2.12f", get_value()); node->add_property (X_("value"), buf); + if (_extra_xml) { + node->add_child_copy (*_extra_xml); + } + return *node; } @@ -123,6 +127,8 @@ Controllable::set_state (const XMLNode& node, int /*version*/) LocaleGuard lg (X_("POSIX")); const XMLProperty* prop; + Stateful::save_extra_xml (node); + if ((prop = node.property (X_("id"))) != 0) { _id = prop->value(); } else { diff --git a/libs/pbd/pbd/stateful.h b/libs/pbd/pbd/stateful.h index 80a5a2f75f..dd1659db55 100644 --- a/libs/pbd/pbd/stateful.h +++ b/libs/pbd/pbd/stateful.h @@ -61,7 +61,8 @@ class Stateful { */ void add_extra_xml (XMLNode&); - XMLNode *extra_xml (const std::string& str); + XMLNode *extra_xml (const std::string& str, bool add_if_missing = false); + void save_extra_xml (const XMLNode&); const PBD::ID& id() const { return _id; } diff --git a/libs/pbd/stateful.cc b/libs/pbd/stateful.cc index 4eb8434af2..47d1e66ef4 100644 --- a/libs/pbd/stateful.cc +++ b/libs/pbd/stateful.cc @@ -68,22 +68,37 @@ Stateful::add_extra_xml (XMLNode& node) } XMLNode * -Stateful::extra_xml (const string& str) +Stateful::extra_xml (const string& str, bool add_if_missing) { - if (_extra_xml == 0) { - return 0; + XMLNode* node = 0; + + if (_extra_xml) { + node = _extra_xml->child (str.c_str()); } - const XMLNodeList& nlist = _extra_xml->children(); - XMLNodeConstIterator i; + if (!node && add_if_missing) { + node = new XMLNode (str); + add_extra_xml (*node); + } - for (i = nlist.begin(); i != nlist.end(); ++i) { - if ((*i)->name() == str) { - return (*i); - } + return node; +} + +void +Stateful::save_extra_xml (const XMLNode& node) +{ + /* Looks for the child node called "Extra" and makes _extra_xml + point to a copy of it. Will delete any existing node pointed + to by _extra_xml if a new Extra node is found, but not + otherwise. + */ + + const XMLNode* xtra = node.child ("Extra"); + + if (xtra) { + delete _extra_xml; + _extra_xml = new XMLNode (*xtra); } - - return 0; } void