2 Copyright (C) 2000-2007 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.
21 #include <gtkmm2ext/barcontroller.h>
22 #include "pbd/memento_command.h"
23 #include "ardour/automation_control.h"
24 #include "ardour/event_type_map.h"
25 #include "ardour/route.h"
26 #include "ardour/session.h"
28 #include "ardour_ui.h"
29 #include "automation_time_axis.h"
30 #include "automation_streamview.h"
31 #include "gui_thread.h"
32 #include "route_time_axis.h"
33 #include "automation_line.h"
34 #include "public_editor.h"
35 #include "simplerect.h"
36 #include "selection.h"
37 #include "rgb_macros.h"
38 #include "automation_selectable.h"
39 #include "point_selection.h"
40 #include "canvas_impl.h"
46 using namespace ARDOUR;
49 using namespace Gtkmm2ext;
50 using namespace Editing;
52 Pango::FontDescription* AutomationTimeAxisView::name_font = 0;
53 bool AutomationTimeAxisView::have_name_font = false;
54 const string AutomationTimeAxisView::state_node_name = "AutomationChild";
57 /** \a a the automatable object this time axis is to display data for.
58 * For route/track automation (e.g. gain) pass the route for both \r and \a.
59 * For route child (e.g. plugin) automation, pass the child for \a.
60 * For region automation (e.g. MIDI CC), pass null for \a.
62 AutomationTimeAxisView::AutomationTimeAxisView (Session* s, boost::shared_ptr<Route> r,
63 boost::shared_ptr<Automatable> a, boost::shared_ptr<AutomationControl> c,
64 PublicEditor& e, TimeAxisView& parent, bool show_regions,
65 ArdourCanvas::Canvas& canvas, const string & nom, const string & nomparent)
67 TimeAxisView (s, e, &parent, canvas),
71 _controller(AutomationController::create(a, c->parameter(), c)),
73 _view (show_regions ? new AutomationStreamView(*this) : NULL),
75 auto_button (X_("")) /* force addition of a label */
77 if (!have_name_font) {
78 name_font = get_font_for_style (X_("AutomationTrackName"));
79 have_name_font = true;
87 mode_discrete_item = 0;
90 ignore_state_request = false;
91 first_call_to_set_height = true;
93 _base_rect = new SimpleRect(*_canvas_display);
94 _base_rect->property_x1() = 0.0;
95 _base_rect->property_y1() = 0.0;
96 _base_rect->property_x2() = LONG_MAX - 2;
97 _base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get();
99 /* outline ends and bottom */
100 _base_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);
101 _base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get();
103 _base_rect->set_data ("trackview", this);
105 _base_rect->signal_event().connect (sigc::bind (
106 sigc::mem_fun (_editor, &PublicEditor::canvas_automation_track_event),
110 _base_rect->lower_to_bottom();
113 hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
115 auto_button.set_name ("TrackVisualButton");
116 hide_button.set_name ("TrackRemoveButton");
118 auto_button.unset_flags (Gtk::CAN_FOCUS);
119 hide_button.unset_flags (Gtk::CAN_FOCUS);
121 controls_table.set_no_show_all();
123 ARDOUR_UI::instance()->set_tip(auto_button, _("automation state"));
124 ARDOUR_UI::instance()->set_tip(hide_button, _("hide track"));
126 /* rearrange the name display */
128 /* we never show these for automation tracks, so make
129 life easier and remove them.
134 /* move the name label over a bit */
136 string shortpname = _name;
137 bool shortened = false;
140 shortpname = fit_to_pixels (_name, 60, *name_font, ignore_width, true);
142 if (shortpname != _name ){
146 name_label.set_text (shortpname);
147 name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
149 if (nomparent.length()) {
151 /* limit the plug name string */
153 string pname = fit_to_pixels (nomparent, 60, *name_font, ignore_width, true);
154 if (pname != nomparent) {
158 plugname = new Label (pname);
159 plugname->set_name (X_("TrackPlugName"));
161 name_label.set_name (X_("TrackParameterName"));
162 controls_table.remove (name_hbox);
163 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
164 plugname_packed = true;
165 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
168 plugname_packed = false;
172 string tipname = nomparent;
173 if (!tipname.empty()) {
177 ARDOUR_UI::instance()->set_tip(controls_ebox, tipname);
180 /* add the buttons */
181 controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
183 controls_table.attach (auto_button, 5, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
185 /* add bar controller */
186 controls_table.attach (*_controller.get(), 0, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
188 controls_table.show_all ();
190 hide_button.signal_clicked().connect (sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked));
191 auto_button.signal_clicked().connect (sigc::mem_fun(*this, &AutomationTimeAxisView::auto_clicked));
193 controls_base_selected_name = X_("AutomationTrackControlsBaseSelected");
194 controls_base_unselected_name = X_("AutomationTrackControlsBase");
195 controls_ebox.set_name (controls_base_unselected_name);
197 XMLNode* xml_node = get_parent_with_state()->get_automation_child_xml_node (
198 _control->parameter());
201 set_state (*xml_node, Stateful::loading_state_version);
204 /* ask for notifications of any new RegionViews */
210 /* no regions, just a single line for the entire track (e.g. bus gain) */
212 boost::shared_ptr<AutomationLine> line(new AutomationLine (
213 ARDOUR::EventTypeMap::instance().to_symbol(_control->parameter()),
218 line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
219 line->queue_reset ();
223 /* make sure labels etc. are correct */
225 automation_state_changed ();
226 ColorsChanged.connect (sigc::mem_fun (*this, &AutomationTimeAxisView::color_handler));
229 AutomationTimeAxisView::~AutomationTimeAxisView ()
234 AutomationTimeAxisView::auto_clicked ()
236 using namespace Menu_Helpers;
238 if (automation_menu == 0) {
239 automation_menu = manage (new Menu);
240 automation_menu->set_name ("ArdourContextMenu");
241 MenuList& items (automation_menu->items());
243 items.push_back (MenuElem (_("Manual"), sigc::bind (sigc::mem_fun(*this,
244 &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
245 items.push_back (MenuElem (_("Play"), sigc::bind (sigc::mem_fun(*this,
246 &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
247 items.push_back (MenuElem (_("Write"), sigc::bind (sigc::mem_fun(*this,
248 &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
249 items.push_back (MenuElem (_("Touch"), sigc::bind (sigc::mem_fun(*this,
250 &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
253 automation_menu->popup (1, gtk_get_current_event_time());
257 AutomationTimeAxisView::set_automation_state (AutoState state)
259 if (!ignore_state_request) {
261 _automatable->set_parameter_automation_state (_control->parameter(), state);
264 if (_route == _automatable) { // This is a time axis for route (not region) automation
265 _route->set_parameter_automation_state (_control->parameter(), state);
268 if (_control->list())
269 _control->alist()->set_automation_state(state);
274 _view->set_automation_state (state);
276 /* AutomationStreamViews don't signal when their automation state changes, so handle
277 our updates `manually'.
279 automation_state_changed ();
284 AutomationTimeAxisView::automation_state_changed ()
288 /* update button label */
291 state = _control->alist()->automation_state ();
293 state = _view->automation_state ();
298 switch (state & (Off|Play|Touch|Write)) {
300 auto_button.set_label (_("Manual"));
302 ignore_state_request = true;
303 auto_off_item->set_active (true);
304 auto_play_item->set_active (false);
305 auto_touch_item->set_active (false);
306 auto_write_item->set_active (false);
307 ignore_state_request = false;
311 auto_button.set_label (_("Play"));
312 if (auto_play_item) {
313 ignore_state_request = true;
314 auto_play_item->set_active (true);
315 auto_off_item->set_active (false);
316 auto_touch_item->set_active (false);
317 auto_write_item->set_active (false);
318 ignore_state_request = false;
322 auto_button.set_label (_("Write"));
323 if (auto_write_item) {
324 ignore_state_request = true;
325 auto_write_item->set_active (true);
326 auto_off_item->set_active (false);
327 auto_play_item->set_active (false);
328 auto_touch_item->set_active (false);
329 ignore_state_request = false;
333 auto_button.set_label (_("Touch"));
334 if (auto_touch_item) {
335 ignore_state_request = true;
336 auto_touch_item->set_active (true);
337 auto_off_item->set_active (false);
338 auto_play_item->set_active (false);
339 auto_write_item->set_active (false);
340 ignore_state_request = false;
344 auto_button.set_label (_("???"));
350 AutomationTimeAxisView::interpolation_changed ()
352 AutomationList::InterpolationStyle style = _control->list()->interpolation();
354 if (mode_line_item && mode_discrete_item) {
355 if (style == AutomationList::Discrete) {
356 mode_discrete_item->set_active(true);
357 mode_line_item->set_active(false);
359 mode_line_item->set_active(true);
360 mode_discrete_item->set_active(false);
365 _line->set_interpolation(style);
370 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
372 _control->list()->set_interpolation(style);
374 _line->set_interpolation(style);
379 AutomationTimeAxisView::clear_clicked ()
381 _session->begin_reversible_command (_("clear automation"));
385 _session->commit_reversible_command ();
389 AutomationTimeAxisView::set_height (uint32_t h)
391 bool const changed = (height != (uint32_t) h) || first_call_to_set_height;
392 uint32_t const normal = preset_height (HeightNormal);
393 bool const changed_between_small_and_normal = ( (height < normal && h >= normal) || (height >= normal || h < normal) );
395 TimeAxisView* state_parent = get_parent_with_state ();
396 assert(state_parent);
397 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
399 TimeAxisView::set_height (h);
400 _base_rect->property_y2() = h;
403 _line->set_height(h);
406 _view->set_height(h);
407 _view->update_contents_height();
411 snprintf (buf, sizeof (buf), "%u", height);
413 xml_node->add_property ("height", buf);
416 if (changed_between_small_and_normal || first_call_to_set_height) {
418 first_call_to_set_height = false;
420 if (h >= preset_height (HeightNormal)) {
421 controls_table.remove (name_hbox);
424 if (plugname_packed) {
425 controls_table.remove (*plugname);
426 plugname_packed = false;
428 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
429 plugname_packed = true;
430 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
432 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
436 name_hbox.show_all ();
439 hide_button.show_all();
441 } else if (h >= preset_height (HeightSmall)) {
442 controls_table.remove (name_hbox);
444 if (plugname_packed) {
445 controls_table.remove (*plugname);
446 plugname_packed = false;
449 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
450 controls_table.hide_all ();
453 name_hbox.show_all ();
458 } else if (h >= preset_height (HeightNormal)) {
459 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
463 if (canvas_item_visible (_canvas_display)) {
464 /* only emit the signal if the height really changed and we were visible */
465 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
471 AutomationTimeAxisView::set_samples_per_unit (double spu)
473 TimeAxisView::set_samples_per_unit (spu);
479 _view->set_samples_per_unit (spu);
483 AutomationTimeAxisView::hide_clicked ()
485 // LAME fix for refreshing the hide button
486 hide_button.set_sensitive(false);
488 set_marked_for_display (false);
491 hide_button.set_sensitive(true);
495 AutomationTimeAxisView::build_display_menu ()
497 using namespace Menu_Helpers;
501 TimeAxisView::build_display_menu ();
503 /* now fill it with our stuff */
505 MenuList& items = display_menu->items();
507 items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
508 items.push_back (SeparatorElem());
509 items.push_back (MenuElem (_("Clear"), sigc::mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
510 items.push_back (SeparatorElem());
514 Menu* auto_state_menu = manage (new Menu);
515 auto_state_menu->set_name ("ArdourContextMenu");
516 MenuList& as_items = auto_state_menu->items();
518 as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
519 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
521 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
523 as_items.push_back (CheckMenuElem (_("Play"), sigc::bind (
524 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
526 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
528 as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
529 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
530 (AutoState) Write)));
531 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
533 as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
534 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
535 (AutoState) Touch)));
536 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
538 items.push_back (MenuElem (_("State"), *auto_state_menu));
542 if (EventTypeMap::instance().is_midi_parameter(_control->parameter())) {
544 Menu* auto_mode_menu = manage (new Menu);
545 auto_mode_menu->set_name ("ArdourContextMenu");
546 MenuList& am_items = auto_mode_menu->items();
548 RadioMenuItem::Group group;
550 am_items.push_back (RadioMenuElem (group, _("Discrete"), sigc::bind (
551 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
552 AutomationList::Discrete)));
553 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
554 mode_discrete_item->set_active(_control->list()->interpolation() == AutomationList::Discrete);
556 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
557 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
558 AutomationList::Linear)));
559 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
561 // Set default interpolation type to linear if this isn't a (usually) discrete controller
562 if (EventTypeMap::instance().interpolation_of(_control->parameter()) == Evoral::ControlList::Linear) {
563 mode_line_item->set_active(_control->list()->interpolation() == AutomationList::Linear);
566 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
569 /* make sure the automation menu state is correct */
571 automation_state_changed ();
572 interpolation_changed ();
576 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, nframes_t when, double y)
583 _canvas_display->w2i (x, y);
585 /* compute vertical fractional position */
587 y = 1.0 - (y / height);
591 _line->view_to_model_coord (x, y);
593 _session->begin_reversible_command (_("add automation event"));
594 XMLNode& before = _control->alist()->get_state();
596 _control->alist()->add (when, y);
598 XMLNode& after = _control->alist()->get_state();
599 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
601 _session->set_dirty ();
605 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
607 return (_line ? cut_copy_clear_one (*_line, selection, op) : false);
611 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
613 boost::shared_ptr<Evoral::ControlList> what_we_got;
614 boost::shared_ptr<AutomationList> alist (line.the_list());
617 XMLNode &before = alist->get_state();
621 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
622 _editor.get_cut_buffer().add (what_we_got);
623 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
628 if ((what_we_got = alist->copy (selection.time.front().start, selection.time.front().end)) != 0) {
629 _editor.get_cut_buffer().add (what_we_got);
634 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
635 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
642 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
643 double when = (*x)->when;
644 double val = (*x)->value;
645 line.model_to_view_coord (when, val);
655 AutomationTimeAxisView::reset_objects (PointSelection& selection)
657 reset_objects_one (*_line, selection);
661 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
663 boost::shared_ptr<AutomationList> alist(line.the_list());
665 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
667 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
669 if ((*i).track != this) {
673 alist->reset_range ((*i).start, (*i).end);
678 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
680 return cut_copy_clear_objects_one (*_line, selection, op);
684 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
686 boost::shared_ptr<Evoral::ControlList> what_we_got;
687 boost::shared_ptr<AutomationList> alist(line.the_list());
690 XMLNode &before = alist->get_state();
692 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
694 if ((*i).track != this) {
700 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
701 _editor.get_cut_buffer().add (what_we_got);
702 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
707 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
708 _editor.get_cut_buffer().add (what_we_got);
713 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
714 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
724 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
725 double when = (*x)->when;
726 double val = (*x)->value;
727 line.model_to_view_coord (when, val);
737 AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
739 return paste_one (*_line, pos, times, selection, nth);
743 AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
745 AutomationSelection::iterator p;
746 boost::shared_ptr<AutomationList> alist(line.the_list());
748 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
750 if (p == selection.lines.end()) {
754 /* Make a copy of the list because we have to scale the
755 values from view coordinates to model coordinates, and we're
756 not supposed to modify the points in the selection.
759 AutomationList copy (**p);
761 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
762 double when = (*x)->when;
763 double val = (*x)->value;
764 line.view_to_model_coord (when, val);
769 XMLNode &before = alist->get_state();
770 alist->paste (copy, pos, times);
771 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
777 AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
779 if (_line && touched (top, bot)) {
783 /* remember: this is X Window - coordinate space starts in upper left and moves down.
784 _y_position is the "origin" or "top" of the track.
787 double mybot = _y_position + height;
789 if (_y_position >= top && mybot <= bot) {
791 /* _y_position is below top, mybot is above bot, so we're fully
800 /* top and bot are within _y_position .. mybot */
802 topfrac = 1.0 - ((top - _y_position) / height);
803 botfrac = 1.0 - ((bot - _y_position) / height);
807 _line->get_selectables (start, end, botfrac, topfrac, results);
812 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
815 _line->get_inverted_selectables (sel, result);
819 AutomationTimeAxisView::set_selected_points (PointSelection& points)
822 _line->set_selected_points (points);
827 AutomationTimeAxisView::clear_lines ()
830 automation_connection.disconnect ();
834 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
838 assert(line->the_list() == _control->list());
840 _control->alist()->automation_state_changed.connect (automation_connection, invalidator (*this), boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context());
843 //_controller = AutomationController::create(_session, line->the_list(), _control);
845 line->set_height (height);
847 /* pick up the current state */
848 automation_state_changed ();
854 AutomationTimeAxisView::entered()
857 _line->track_entered();
861 AutomationTimeAxisView::exited ()
864 _line->track_exited();
868 AutomationTimeAxisView::color_handler ()
876 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
878 TimeAxisView::set_state (node, version);
880 XMLProperty const * type = node.property ("automation-id");
881 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
882 XMLProperty const * shown = node.property ("shown");
883 if (shown && shown->value () == "yes") {
884 set_marked_for_display (true);
885 _canvas_display->show (); /* FIXME: necessary? show_at? */
889 if (!_marked_for_display) {
897 AutomationTimeAxisView::get_state_node ()
899 TimeAxisView* state_parent = get_parent_with_state ();
902 return state_parent->get_automation_child_xml_node (_control->parameter());
909 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
911 XMLNode* xml_node = get_state_node();
913 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
918 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
920 update_extra_xml_shown (true);
922 return TimeAxisView::show_at (y, nth, parent);
926 AutomationTimeAxisView::hide ()
928 update_extra_xml_shown (false);
930 TimeAxisView::hide ();
934 AutomationTimeAxisView::set_visibility (bool yn)
936 bool changed = TimeAxisView::set_visibility (yn);
939 get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));